Blame SOURCES/coolkey-1.1.0-p15.patch

dab6d7
diff -up ./src/coolkey/coolkey.cpp.p15 ./src/coolkey/coolkey.cpp
dab6d7
--- ./src/coolkey/coolkey.cpp.p15	2015-07-06 10:27:55.769827286 -0700
dab6d7
+++ ./src/coolkey/coolkey.cpp	2015-07-06 10:27:55.784827002 -0700
dab6d7
@@ -599,13 +599,10 @@ C_Login(CK_SESSION_HANDLE hSession, CK_U
dab6d7
     }
dab6d7
     try {
dab6d7
         log->log("C_Login called\n");
dab6d7
-        if( userType != CKU_USER ) {
dab6d7
-            throw PKCS11Exception(CKR_USER_TYPE_INVALID);
dab6d7
-        }
dab6d7
         if( pPin == NULL ) {
dab6d7
             throw PKCS11Exception(CKR_ARGUMENTS_BAD);
dab6d7
         }
dab6d7
-        slotList->login(hSession, pPin, ulPinLen);
dab6d7
+        slotList->login(hSession, userType, pPin, ulPinLen);
dab6d7
         return CKR_OK;
dab6d7
     } catch(PKCS11Exception &e) {
dab6d7
         e.log(log);
dab6d7
diff -up ./src/coolkey/object.cpp.p15 ./src/coolkey/object.cpp
dab6d7
--- ./src/coolkey/object.cpp.p15	2015-07-06 10:27:55.770827267 -0700
dab6d7
+++ ./src/coolkey/object.cpp	2015-07-06 10:27:55.785826984 -0700
dab6d7
@@ -19,9 +19,9 @@
dab6d7
 
dab6d7
 #include "mypkcs11.h"
dab6d7
 #include "PKCS11Exception.h"
dab6d7
-#include "object.h"
dab6d7
 #include <algorithm>
dab6d7
 #include <string.h>
dab6d7
+#include "object.h"
dab6d7
 
dab6d7
 using std::find_if;
dab6d7
 
dab6d7
@@ -29,7 +29,7 @@ const CKYByte rsaOID[] = {0x2A,0x86,0x48
dab6d7
 const CKYByte eccOID[] = {0x2a,0x86,0x48,0xce,0x3d,0x02,0x01};
dab6d7
 
dab6d7
 #ifdef DEBUG
dab6d7
-void dump(CKYBuffer *buf)
dab6d7
+void dump(const char *label, const CKYBuffer *buf)
dab6d7
 {
dab6d7
     CKYSize i;
dab6d7
     CKYSize size = CKYBuffer_Size(buf);
dab6d7
@@ -38,8 +38,10 @@ void dump(CKYBuffer *buf)
dab6d7
     char *bp = &string[0];
dab6d7
     CKYByte c;
dab6d7
 
dab6d7
+    printf("%s size=%d\n", label, (int)size);
dab6d7
+
dab6d7
     for (i=0; i < size; i++) {
dab6d7
-        if (i && ((i % (ROW_LENGTH-1)) == 0) ) {
dab6d7
+        if (i && ((i % (ROW_LENGTH)) == 0) ) {
dab6d7
             *bp = 0;
dab6d7
             printf(" %s\n",string);
dab6d7
             bp = &string[0];
dab6d7
@@ -49,7 +51,35 @@ void dump(CKYBuffer *buf)
dab6d7
         *bp++ =  (c < ' ') ? '.' : ((c & 0x80) ? '*' : c);
dab6d7
     }
dab6d7
     *bp = 0;
dab6d7
-    for (i= (i % (ROW_LENGTH-1)); i && (i < ROW_LENGTH); i++) {
dab6d7
+    for (i= (i % (ROW_LENGTH)); i && (i < ROW_LENGTH); i++) {
dab6d7
+        printf("   ");
dab6d7
+    }
dab6d7
+    printf(" %s\n",string);
dab6d7
+    fflush(stdout);
dab6d7
+}
dab6d7
+
dab6d7
+void dumpData(const char *label, const CKYByte *buf, CKYSize size)
dab6d7
+{
dab6d7
+    CKYSize i;
dab6d7
+#define ROW_LENGTH 16
dab6d7
+    char string[ROW_LENGTH+1];
dab6d7
+    char *bp = &string[0];
dab6d7
+    CKYByte c;
dab6d7
+
dab6d7
+    printf("%s size=%d:\n",label, (int)size);
dab6d7
+
dab6d7
+    for (i=0; i < size; i++) {
dab6d7
+        if (i && ((i % (ROW_LENGTH)) == 0) ) {
dab6d7
+            *bp = 0;
dab6d7
+            printf(" %s\n",string);
dab6d7
+            bp = &string[0];
dab6d7
+        }
dab6d7
+        c = buf[i];
dab6d7
+        printf("%02x ",c);
dab6d7
+        *bp++ =  (c < ' ') ? '.' : ((c & 0x80) ? '*' : c);
dab6d7
+    }
dab6d7
+    *bp = 0;
dab6d7
+    for (i= (i % (ROW_LENGTH)); i && (i < ROW_LENGTH); i++) {
dab6d7
         printf("   ");
dab6d7
     }
dab6d7
     printf(" %s\n",string);
dab6d7
@@ -77,16 +107,23 @@ class AttributeTypeMatch
dab6d7
 };
dab6d7
 
dab6d7
 PKCS11Object::PKCS11Object(unsigned long muscleObjID_,CK_OBJECT_HANDLE handle_)
dab6d7
-    : muscleObjID(muscleObjID_), handle(handle_), label(NULL), name(NULL), keyType(unknown)
dab6d7
+    : muscleObjID(muscleObjID_), handle(handle_), label(NULL), keySize(0),
dab6d7
+                   user(CKU_USER), name(NULL), keyType(unknown),
dab6d7
+		   keyRef(PK15_INVALID_KEY_REF)
dab6d7
 { 
dab6d7
     CKYBuffer_InitEmpty(&pubKey);
dab6d7
+    CKYBuffer_InitEmpty(&authId);
dab6d7
+    CKYBuffer_InitEmpty(&pinAuthId);
dab6d7
 }
dab6d7
 
dab6d7
 PKCS11Object::PKCS11Object(unsigned long muscleObjID_, const CKYBuffer *data,
dab6d7
     CK_OBJECT_HANDLE handle_) :  muscleObjID(muscleObjID_), handle(handle_),
dab6d7
-                        label(NULL), name(NULL), keyType(unknown)
dab6d7
+                   label(NULL), keySize(0), user(CKU_USER), name(NULL), 
dab6d7
+		   keyType(unknown), keyRef(PK15_INVALID_KEY_REF) 
dab6d7
 {
dab6d7
     CKYBuffer_InitEmpty(&pubKey);
dab6d7
+    CKYBuffer_InitEmpty(&authId);
dab6d7
+    CKYBuffer_InitEmpty(&pinAuthId);
dab6d7
 
dab6d7
     CKYByte type = CKYBuffer_GetChar(data,0);
dab6d7
     // verify object ID is what we think it is
dab6d7
@@ -582,6 +619,21 @@ PKCS11Object::setAttribute(CK_ATTRIBUTE_
dab6d7
 }
dab6d7
 
dab6d7
 void
dab6d7
+PKCS11Object::setAttribute(CK_ATTRIBUTE_TYPE type, const CKYByte *data,
dab6d7
+			CKYSize size)
dab6d7
+{
dab6d7
+    AttributeIter iter;  
dab6d7
+
dab6d7
+    iter = find_if(attributes.begin(), attributes.end(),
dab6d7
+        AttributeTypeMatch(type));
dab6d7
+    if( iter != attributes.end() )  {
dab6d7
+        iter->setValue( data, size);
dab6d7
+    } else {
dab6d7
+        attributes.push_back(PKCS11Attribute(type, data, size));
dab6d7
+    }
dab6d7
+}
dab6d7
+
dab6d7
+void
dab6d7
 PKCS11Object::setAttribute(CK_ATTRIBUTE_TYPE type, const char *string)
dab6d7
 {
dab6d7
     CKYBuffer buf;
dab6d7
@@ -613,7 +665,7 @@ PKCS11Object::setAttributeULong(CK_ATTRI
dab6d7
 
dab6d7
 typedef struct {
dab6d7
     const CKYByte*data;
dab6d7
-    unsigned int len;
dab6d7
+    CKYSize len;
dab6d7
 } CCItem;
dab6d7
 
dab6d7
 typedef enum {
dab6d7
@@ -621,9 +673,9 @@ typedef enum {
dab6d7
     SECFailure=1
dab6d7
 } SECStatus;
dab6d7
 
dab6d7
-static const CKYByte*
dab6d7
-dataStart(const CKYByte *buf, unsigned int length,
dab6d7
-                        unsigned int *data_length, bool includeTag) {
dab6d7
+const CKYByte*
dab6d7
+dataStart(const CKYByte *buf, CKYSize length,
dab6d7
+                        CKYSize *data_length, bool includeTag) {
dab6d7
     unsigned char tag;
dab6d7
     unsigned int used_length= 0;
dab6d7
 
dab6d7
@@ -673,7 +725,7 @@ dataStart(const CKYByte *buf, unsigned i
dab6d7
 }
dab6d7
 
dab6d7
 static const CKYByte *
dab6d7
-unwrapBitString(const CKYByte *buf, unsigned int len, unsigned int *retLen)
dab6d7
+unwrapBitString(const CKYByte *buf, CKYSize len, CKYSize *retLen)
dab6d7
 {
dab6d7
     /* for RSA, bit string always has byte number of bits */
dab6d7
     if (buf[0] != 0) {
dab6d7
@@ -687,15 +739,15 @@ unwrapBitString(const CKYByte *buf, unsi
dab6d7
 }
dab6d7
 
dab6d7
 static SECStatus
dab6d7
-GetECKeyFieldItems(const CKYByte *spki_data,unsigned int spki_length,
dab6d7
+GetECKeyFieldItems(const CKYByte *spki_data, CKYSize spki_length,
dab6d7
         CCItem *point, CCItem *params)
dab6d7
 {
dab6d7
     const CKYByte *buf = spki_data;
dab6d7
-    unsigned int buf_length = spki_length;
dab6d7
+    CKYSize buf_length = spki_length;
dab6d7
     const CKYByte *algid;
dab6d7
-    unsigned int algidlen;
dab6d7
+    CKYSize algidlen;
dab6d7
     const CKYByte *dummy;
dab6d7
-    unsigned int dummylen;
dab6d7
+    CKYSize dummylen;
dab6d7
 
dab6d7
     if (!point || !params || !buf)
dab6d7
         return SECFailure;
dab6d7
@@ -756,12 +808,12 @@ GetKeyOIDMatches(const CKYByte *spki_dat
dab6d7
 }
dab6d7
 
dab6d7
 static SECStatus
dab6d7
-GetKeyAlgorithmId(const CKYByte *spki_data, unsigned int spki_length,
dab6d7
+GetKeyAlgorithmId(const CKYByte *spki_data, CKYSize spki_length,
dab6d7
        CCItem *algorithmId)
dab6d7
 {
dab6d7
 
dab6d7
     const CKYByte *buf = spki_data;
dab6d7
-    unsigned int buf_length = spki_length;
dab6d7
+    CKYSize buf_length = spki_length;
dab6d7
 
dab6d7
     if ( algorithmId == NULL) return SECFailure;
dab6d7
 
dab6d7
@@ -786,7 +838,7 @@ GetKeyTypeFromSPKI(const CKYBuffer *key)
dab6d7
             "Failed to decode key algorithm ID.");
dab6d7
     }
dab6d7
 
dab6d7
-    unsigned int length = 0;
dab6d7
+    CKYSize length = 0;
dab6d7
     const CKYByte *keyData = NULL;
dab6d7
 
dab6d7
     /* Get actual oid buffer */
dab6d7
@@ -829,13 +881,13 @@ GetKeyTypeFromSPKI(const CKYBuffer *key)
dab6d7
 }
dab6d7
 
dab6d7
 static SECStatus
dab6d7
-GetKeyFieldItems(const CKYByte *spki_data,unsigned int spki_length,
dab6d7
+GetKeyFieldItems(const CKYByte *spki_data,CKYSize spki_length,
dab6d7
         CCItem *modulus, CCItem *exponent)
dab6d7
 {
dab6d7
     const CKYByte *buf = spki_data;
dab6d7
-    unsigned int buf_length = spki_length;
dab6d7
+    CKYSize buf_length = spki_length;
dab6d7
     const CKYByte*dummy;
dab6d7
-    unsigned int dummylen;
dab6d7
+    CKYSize dummylen;
dab6d7
 
dab6d7
     /* skip past the algorithm id */
dab6d7
     dummy = dataStart(buf,buf_length,&dummylen,false);
dab6d7
@@ -955,7 +1007,7 @@ Key::Key(unsigned long muscleObjID, cons
dab6d7
 }
dab6d7
 
dab6d7
 void
dab6d7
-Key::completeKey(const PKCS11Object &cert)
dab6d7
+PKCS11Object::completeKey(const PKCS11Object &cert)
dab6d7
 {
dab6d7
     // infer key attributes from cert
dab6d7
     bool modulusExists, exponentExists;
dab6d7
@@ -1015,14 +1067,14 @@ Key::completeKey(const PKCS11Object &cer
dab6d7
 }
dab6d7
 
dab6d7
 static SECStatus
dab6d7
-GetCertFieldItems(const CKYByte *dercert,unsigned int cert_length,
dab6d7
+GetCertFieldItems(const CKYByte *dercert, CKYSize cert_length,
dab6d7
         CCItem *issuer, CCItem *serial, CCItem *derSN, CCItem *subject,
dab6d7
         CCItem *valid, CCItem *subjkey)
dab6d7
 {
dab6d7
     const CKYByte *buf;
dab6d7
-    unsigned int buf_length;
dab6d7
+    CKYSize buf_length;
dab6d7
     const CKYByte*dummy;
dab6d7
-    unsigned int dummylen;
dab6d7
+    CKYSize dummylen;
dab6d7
 
dab6d7
     /* get past the signature wrap */
dab6d7
     buf = dataStart(dercert,cert_length,&buf_length, false);
dab6d7
@@ -1330,10 +1382,10 @@ static const unsigned char CN_DATA[] = {
dab6d7
 const unsigned int CN_LENGTH = sizeof(CN_DATA);
dab6d7
 
dab6d7
 static SECStatus
dab6d7
-GetCN(const CKYByte *dn, unsigned int dn_length, CCItem *cn)
dab6d7
+GetCN(const CKYByte *dn, CKYSize dn_length, CCItem *cn)
dab6d7
 {
dab6d7
     const CKYByte *buf;
dab6d7
-    unsigned int buf_length;
dab6d7
+    CKYSize buf_length;
dab6d7
 
dab6d7
     /* unwrap the sequence */
dab6d7
     buf = dataStart(dn,dn_length,&buf_length, false);
dab6d7
@@ -1341,9 +1393,9 @@ GetCN(const CKYByte *dn, unsigned int dn
dab6d7
 
dab6d7
     while (buf_length) {
dab6d7
         const CKYByte *name;
dab6d7
-        unsigned int name_length;
dab6d7
+        CKYSize name_length;
dab6d7
         const CKYByte *oid;
dab6d7
-        unsigned int oid_length;
dab6d7
+        CKYSize oid_length;
dab6d7
 
dab6d7
         /* unwrap the set */
dab6d7
         name = dataStart(buf, buf_length, &name_length, false);
dab6d7
@@ -1408,13 +1460,6 @@ CACCert::CACCert(CKYByte instance, const
dab6d7
 {
dab6d7
     CKYBuffer id;
dab6d7
     CKYBuffer empty;
dab6d7
-    CK_BBOOL decrypt = FALSE;
dab6d7
-
dab6d7
-    /* So we know what the key is supposed to be used for based on
dab6d7
-     * the instance */
dab6d7
-    if (instance == 2) {
dab6d7
-        decrypt = TRUE;
dab6d7
-    }
dab6d7
 
dab6d7
     CKYBuffer_InitEmpty(&empty);
dab6d7
     setAttributeULong(CKA_CLASS, CKO_CERTIFICATE);
dab6d7
@@ -1456,6 +1501,1063 @@ CACCert::CACCert(CKYByte instance, const
dab6d7
     CKYBuffer_FreeData(&derIssuer);
dab6d7
 }
dab6d7
 
dab6d7
+static const CKYByte rev[] = {
dab6d7
+    0x00, 0x80, 0x40, 0xc0, 0x20, 0xa0, 0x60, 0xe0,
dab6d7
+    0x10, 0x90, 0x50, 0xd0, 0x30, 0xb0, 0x70, 0xf0,
dab6d7
+    0x08, 0x88, 0x48, 0xc8, 0x28, 0xa8, 0x68, 0xe8,
dab6d7
+    0x18, 0x98, 0x58, 0xd8, 0x38, 0xb8, 0x78, 0xf8,
dab6d7
+    0x04, 0x84, 0x44, 0xc4, 0x24, 0xa4, 0x64, 0xe4,
dab6d7
+    0x14, 0x94, 0x54, 0xd4, 0x34, 0xb4, 0x74, 0xf4,
dab6d7
+    0x0c, 0x8c, 0x4c, 0xcc, 0x2c, 0xac, 0x6c, 0xec,
dab6d7
+    0x1c, 0x9c, 0x5c, 0xdc, 0x3c, 0xbc, 0x7c, 0xfc,
dab6d7
+    0x02, 0x82, 0x42, 0xc2, 0x22, 0xa2, 0x62, 0xe2,
dab6d7
+    0x12, 0x92, 0x52, 0xd2, 0x32, 0xb2, 0x72, 0xf2,
dab6d7
+    0x0a, 0x8a, 0x4a, 0xca, 0x2a, 0xaa, 0x6a, 0xea,
dab6d7
+    0x1a, 0x9a, 0x5a, 0xda, 0x3a, 0xba, 0x7a, 0xfa,
dab6d7
+    0x06, 0x86, 0x46, 0xc6, 0x26, 0xa6, 0x66, 0xe6,
dab6d7
+    0x16, 0x96, 0x56, 0xd6, 0x36, 0xb6, 0x76, 0xf6,
dab6d7
+    0x0e, 0x8e, 0x4e, 0xce, 0x2e, 0xae, 0x6e, 0xee,
dab6d7
+    0x1e, 0x9e, 0x5e, 0xde, 0x3e, 0xbe, 0x7e, 0xfe,
dab6d7
+    0x01, 0x81, 0x41, 0xc1, 0x21, 0xa1, 0x61, 0xe1,
dab6d7
+    0x11, 0x91, 0x51, 0xd1, 0x31, 0xb1, 0x71, 0xf1,
dab6d7
+    0x09, 0x89, 0x49, 0xc9, 0x29, 0xa9, 0x69, 0xe9,
dab6d7
+    0x19, 0x99, 0x59, 0xd9, 0x39, 0xb9, 0x79, 0xf9,
dab6d7
+    0x05, 0x85, 0x45, 0xc5, 0x25, 0xa5, 0x65, 0xe5,
dab6d7
+    0x15, 0x95, 0x55, 0xd5, 0x35, 0xb5, 0x75, 0xf5,
dab6d7
+    0x0d, 0x8d, 0x4d, 0xcd, 0x2d, 0xad, 0x6d, 0xed,
dab6d7
+    0x1d, 0x9d, 0x5d, 0xdd, 0x3d, 0xbd, 0x7d, 0xfd,
dab6d7
+    0x03, 0x83, 0x43, 0xc3, 0x23, 0xa3, 0x63, 0xe3,
dab6d7
+    0x13, 0x93, 0x53, 0xd3, 0x33, 0xb3, 0x73, 0xf3,
dab6d7
+    0x0b, 0x8b, 0x4b, 0xcb, 0x2b, 0xab, 0x6b, 0xeb,
dab6d7
+    0x1b, 0x9b, 0x5b, 0xdb, 0x3b, 0xbb, 0x7b, 0xfb,
dab6d7
+    0x07, 0x87, 0x47, 0xc7, 0x27, 0xa7, 0x67, 0xe7,
dab6d7
+    0x17, 0x97, 0x57, 0xd7, 0x37, 0xb7, 0x77, 0xf7,
dab6d7
+    0x0f, 0x8f, 0x4f, 0xcf, 0x2f, 0xaf, 0x6f, 0xef,
dab6d7
+    0x1f, 0x9f, 0x5f, 0xdf, 0x3f, 0xbf, 0x7f, 0xff
dab6d7
+};
dab6d7
+
dab6d7
+unsigned long GetBits(const CKYByte *entry, CKYSize entrySize,
dab6d7
+				unsigned int numBits, unsigned int numBytes)
dab6d7
+{
dab6d7
+   unsigned long bits = 0;
dab6d7
+   unsigned long bitFlag = 0;
dab6d7
+   unsigned int i;
dab6d7
+
dab6d7
+   /* size of zero is valid for no bits */
dab6d7
+   if (entrySize <= 1) {
dab6d7
+	return 0;
dab6d7
+   }
dab6d7
+   entrySize--;
dab6d7
+   entry++;
dab6d7
+
dab6d7
+   /* if we are longer than and unsigned, just bail now */
dab6d7
+   if (entrySize > sizeof (unsigned long)) {
dab6d7
+	bitFlag = BROKEN_FLAG;
dab6d7
+	entrySize = sizeof(unsigned long);
dab6d7
+   }
dab6d7
+   /* turn the flags into an int */
dab6d7
+   for (i=0; i < entrySize; i++) {
dab6d7
+	CKYByte c = rev[entry[i]];
dab6d7
+	bits  = bits | (c << i*8);
dab6d7
+   }
dab6d7
+   return bits | bitFlag;
dab6d7
+}
dab6d7
+
dab6d7
+
dab6d7
+/*
dab6d7
+ * parse the path object.
dab6d7
+ * Caller has already unwrapped the outer ASN1Sequence
dab6d7
+ */
dab6d7
+CKYStatus PK15ObjectPath::setObjectPath(const CKYByte *current, CKYSize size)
dab6d7
+{
dab6d7
+    const CKYByte *entry;
dab6d7
+    CKYSize entrySize;
dab6d7
+    CKYSize tagSize;
dab6d7
+    unsigned int i;
dab6d7
+    CKYStatus status;
dab6d7
+
dab6d7
+
dab6d7
+    if ((current == NULL) || (current[0] != ASN1_OCTET_STRING)) {
dab6d7
+	return CKYINVALIDDATA;
dab6d7
+    }
dab6d7
+    /* entry */
dab6d7
+    entry = dataStart(current, size, &entrySize, false);
dab6d7
+    if (entry == NULL) { return CKYINVALIDDATA; }
dab6d7
+    tagSize = entry - current;
dab6d7
+    current += entrySize + tagSize;
dab6d7
+    size -= (entrySize +tagSize);
dab6d7
+    if (size < 0) { return CKYINVALIDDATA; }
dab6d7
+    status = CKYBuffer_Replace(&path, 0, entry, entrySize);
dab6d7
+    if (status != CKYSUCCESS) {
dab6d7
+	return status;
dab6d7
+    }
dab6d7
+
dab6d7
+    /* index */
dab6d7
+    if ((size != 0) && current[0] ==  ASN1_INTEGER) { 
dab6d7
+	entry = dataStart(current, size, &entrySize, false);
dab6d7
+	if (entry == NULL) { return CKYINVALIDDATA; }
dab6d7
+	tagSize = entry - current;
dab6d7
+	current += entrySize + tagSize;
dab6d7
+	size -= (entrySize +tagSize);
dab6d7
+	if (size < 0) { return CKYINVALIDDATA; }
dab6d7
+	if (entrySize > 5) { return CKYINVALIDDATA; }
dab6d7
+	for (index = 0, i=0; i < entrySize; i++) {
dab6d7
+	    index = (index << 8) + (unsigned int) entry[i];
dab6d7
+	}
dab6d7
+    }
dab6d7
+
dab6d7
+    /* length */
dab6d7
+    if ((size != 0) && ((current[0]|ASN1_CONSTRUCTED) ==  ASN1_CHOICE_0)) { 
dab6d7
+	entry = dataStart(current, size, &entrySize, false);
dab6d7
+	if (entry == NULL) { return CKYINVALIDDATA; }
dab6d7
+	tagSize = entry - current;
dab6d7
+	current += entrySize + tagSize;
dab6d7
+	size -= (entrySize +tagSize);
dab6d7
+	if (size < 0) { return CKYINVALIDDATA; }
dab6d7
+	if (entrySize > 5) { return CKYINVALIDDATA; }
dab6d7
+	for (length = 0, i=0; i < entrySize; i++) {
dab6d7
+	    length = (length << 8) + (unsigned int) entry[i];
dab6d7
+	}
dab6d7
+    }
dab6d7
+    return CKYSUCCESS;
dab6d7
+}
dab6d7
+
dab6d7
+static unsigned int pK15GetTag(PK15ObjectType type) {
dab6d7
+     switch (type) { case PK15PvKey: case PK15PuKey: return 'k'<<24;
dab6d7
+		     case PK15Cert: return 'c' << 24; default: break; }
dab6d7
+     return 'v';
dab6d7
+}
dab6d7
+
dab6d7
+
dab6d7
+PK15Object::PK15Object(CKYByte inst, PK15ObjectType type, 
dab6d7
+	const CKYByte *der, CKYSize derSize) 
dab6d7
+	: PKCS11Object(pK15GetTag(type) | ((inst+'0') << 16), 0xa000 | inst)
dab6d7
+{
dab6d7
+    CKYStatus status;
dab6d7
+
dab6d7
+    instance = inst;
dab6d7
+    p15Type =  type;
dab6d7
+    CKYBuffer_InitEmpty(&authId);
dab6d7
+    CKYBuffer_InitEmpty(&pinAuthId);
dab6d7
+    state = PK15StateInit;
dab6d7
+    pinInfo.pinFlags = 0;
dab6d7
+    pinInfo.pinType = P15PinUTF8;
dab6d7
+    pinInfo.minLength = 4;
dab6d7
+    pinInfo.storedLength = 0;
dab6d7
+    pinInfo.maxLength = 0;
dab6d7
+    pinInfo.pinRef = 0;
dab6d7
+    pinInfo.padChar = 0xff;
dab6d7
+
dab6d7
+    status = completeObject(der, derSize);
dab6d7
+    if (status != CKYSUCCESS) {
dab6d7
+	state = PK15StateInit; /* don't try to fetch any more if we failed */
dab6d7
+    }
dab6d7
+}
dab6d7
+
dab6d7
+/* returns true if there is more work to do... */
dab6d7
+CKYStatus 
dab6d7
+PK15Object::completeObject(const CKYByte *current, CKYSize currentSize)
dab6d7
+{
dab6d7
+    const CKYByte *commonAttributes;
dab6d7
+    CKYSize commonSize;
dab6d7
+    const CKYByte *entry;
dab6d7
+    CKYSize entrySize;
dab6d7
+    CKYSize tagSize;
dab6d7
+    CKYByte objectTag;
dab6d7
+    CKYStatus status;
dab6d7
+    CKYBitFlags bits;
dab6d7
+
dab6d7
+    switch (state) {
dab6d7
+    case PK15StateInit:
dab6d7
+    case PK15StateNeedObject:
dab6d7
+	break;
dab6d7
+    case PK15StateNeedRawPublicKey:
dab6d7
+	return  completeRawPublicKey(current, currentSize);
dab6d7
+    case PK15StateNeedRawCertificate:
dab6d7
+	return  completeRawCertificate(current, currentSize);
dab6d7
+    case PK15StateComplete:
dab6d7
+	return CKYSUCCESS;
dab6d7
+    }
dab6d7
+
dab6d7
+    if (current == NULL) { return CKYINVALIDARGS; }
dab6d7
+
dab6d7
+    objectTag = current[0];
dab6d7
+
dab6d7
+    setAttributeBool(CKA_TOKEN, TRUE);
dab6d7
+
dab6d7
+    /* set type specific attributes */
dab6d7
+    switch (p15Type) {
dab6d7
+    case PK15Cert:
dab6d7
+	setAttributeULong(CKA_CLASS, CKO_CERTIFICATE);
dab6d7
+    	setAttributeULong(CKA_CERTIFICATE_TYPE, CKC_X_509);
dab6d7
+	if (objectTag != PK15X509CertType) {
dab6d7
+	    return CKYUNSUPPORTED;
dab6d7
+	}
dab6d7
+	break;
dab6d7
+    case PK15PvKey:
dab6d7
+	setAttributeULong(CKA_CLASS, CKO_PRIVATE_KEY);
dab6d7
+	goto set_key_type;
dab6d7
+    case PK15PuKey:
dab6d7
+	setAttributeULong(CKA_CLASS, CKO_PUBLIC_KEY);
dab6d7
+set_key_type:
dab6d7
+	switch (objectTag) {
dab6d7
+	case PK15RSAKeyType:
dab6d7
+	    keyType = rsa;
dab6d7
+	    setAttributeULong(CKA_KEY_TYPE, CKK_RSA);
dab6d7
+	    break;
dab6d7
+	case PK15ECCKeyType:
dab6d7
+	    keyType = ecc;
dab6d7
+	    setAttributeULong(CKA_KEY_TYPE, CKK_EC);
dab6d7
+	    break;
dab6d7
+	case PK15DSAKeyType:
dab6d7
+	case PK15DHKeyType:
dab6d7
+	default:
dab6d7
+	    return CKYUNSUPPORTED;
dab6d7
+	}
dab6d7
+	break;
dab6d7
+    case PK15AuthObj:
dab6d7
+	setAttributeULong(CKA_CLASS, CKO_DATA);
dab6d7
+	break;
dab6d7
+    default:
dab6d7
+	return CKYUNSUPPORTED;
dab6d7
+    }
dab6d7
+
dab6d7
+    /* unwrap the object */	
dab6d7
+    current = dataStart(current, currentSize, &currentSize, false);
dab6d7
+    if (current == NULL) { return CKYINVALIDDATA; }
dab6d7
+
dab6d7
+    /*
dab6d7
+     * parse the Common Attributes 
dab6d7
+     *     label UTF8_STRING
dab6d7
+     *     flags BIT_STRING (optional)
dab6d7
+     *     authid OCTET_STRING (optional)
dab6d7
+     */
dab6d7
+    if ((current == NULL) || (current[0] != ASN1_SEQUENCE)) 
dab6d7
+	{ return CKYINVALIDDATA; }
dab6d7
+    /* unwrap */
dab6d7
+    commonAttributes = dataStart(current, currentSize, &commonSize, false);
dab6d7
+    if (commonAttributes == NULL) { return CKYINVALIDDATA; }
dab6d7
+
dab6d7
+    /* point current to the next section (cass attributes)  */
dab6d7
+    tagSize = commonAttributes - current;
dab6d7
+    current += commonSize + tagSize;
dab6d7
+    currentSize -= (commonSize +tagSize);
dab6d7
+    if (currentSize < 0) { return CKYINVALIDDATA; }
dab6d7
+
dab6d7
+    /* get the CKA_LABEL */
dab6d7
+    if (commonAttributes[0] != ASN1_UTF8_STRING) { return CKYINVALIDDATA; }
dab6d7
+    entry = dataStart(commonAttributes, commonSize, &entrySize, false);
dab6d7
+    if (entry == NULL) { return CKYINVALIDARGS; }
dab6d7
+    tagSize = entry - commonAttributes;
dab6d7
+    commonAttributes += entrySize + tagSize;
dab6d7
+    commonSize -= (entrySize +tagSize);
dab6d7
+    setAttribute(CKA_LABEL, entry, entrySize);
dab6d7
+
dab6d7
+    /* parse optional flags */
dab6d7
+    bits = BROKEN_FLAG;
dab6d7
+    if (commonAttributes[0] == ASN1_BIT_STRING) {
dab6d7
+	entry = dataStart(commonAttributes, commonSize, &entrySize, false);
dab6d7
+	if (entry == NULL) { return CKYINVALIDARGS; }
dab6d7
+	tagSize = entry - commonAttributes;
dab6d7
+	commonAttributes += entrySize + tagSize;
dab6d7
+	commonSize -= (entrySize +tagSize);
dab6d7
+	bits = GetBits(entry,entrySize,2,1);
dab6d7
+    }
dab6d7
+
dab6d7
+    if (commonAttributes[0] == ASN1_OCTET_STRING) {
dab6d7
+	entry = dataStart(commonAttributes, commonSize, &entrySize, false);
dab6d7
+	if (entry == NULL) { return CKYINVALIDARGS; }
dab6d7
+	tagSize = entry - commonAttributes;
dab6d7
+	commonAttributes += entrySize + tagSize;
dab6d7
+	commonSize -= (entrySize +tagSize);
dab6d7
+	status = CKYBuffer_Replace(&authId, 0, entry, entrySize);
dab6d7
+	if (status != CKYSUCCESS) {
dab6d7
+	   return status;
dab6d7
+	}
dab6d7
+    }
dab6d7
+
dab6d7
+    if (bits & BROKEN_FLAG) {
dab6d7
+	bits = defaultCommonBits();
dab6d7
+    }
dab6d7
+    setAttributeBool(CKA_PRIVATE, 
dab6d7
+		(bits & P15FlagsPrivate) ? TRUE: FALSE);
dab6d7
+    setAttributeBool(CKA_MODIFIABLE, FALSE); /* our token is ReadOnly, so the
dab6d7
+					      * object is never modifiable for
dab6d7
+					      * us */
dab6d7
+    /* future common attributes here */
dab6d7
+
dab6d7
+    /*
dab6d7
+     *  Parse Class variables
dab6d7
+     *
dab6d7
+     */
dab6d7
+    switch (p15Type) {
dab6d7
+    case PK15Cert:
dab6d7
+	status = completeCertObject(current,currentSize);
dab6d7
+	break;
dab6d7
+    case PK15PuKey:
dab6d7
+    case PK15PvKey:
dab6d7
+	status = completeKeyObject(current,currentSize);
dab6d7
+	break;
dab6d7
+    case PK15AuthObj:
dab6d7
+	status = completeAuthObject(current, currentSize);
dab6d7
+	break;
dab6d7
+    }
dab6d7
+    return status;
dab6d7
+}
dab6d7
+
dab6d7
+
dab6d7
+CKYStatus 
dab6d7
+PK15Object::completeCertObject(const CKYByte *current, CKYSize currentSize)
dab6d7
+{
dab6d7
+    const CKYByte *commonCertAttributes;
dab6d7
+    CKYSize commonSize;
dab6d7
+    const CKYByte *entry;
dab6d7
+    CKYSize entrySize;
dab6d7
+    CKYSize tagSize;
dab6d7
+    CKYBuffer empty;
dab6d7
+    CKYStatus status;
dab6d7
+    CKYByte valueTag;
dab6d7
+
dab6d7
+    CKYBuffer_InitEmpty(&empty);
dab6d7
+
dab6d7
+    /*
dab6d7
+     * parse the Common Cert Attributes 
dab6d7
+     *     id OCTET_STRING
dab6d7
+     *     authority BOOLEAN DEFAULT FALSE
dab6d7
+     *     requestId BIT_STRING (optional)
dab6d7
+     *     thumbprint [0] PKS15OOBCertHash (optional)
dab6d7
+     */
dab6d7
+    if ((current == NULL) || (current[0] != ASN1_SEQUENCE)) 
dab6d7
+		{ return CKYINVALIDARGS; }
dab6d7
+    /* unwrap */
dab6d7
+    commonCertAttributes = dataStart(current, currentSize, &commonSize, false);
dab6d7
+    if (commonCertAttributes == NULL) { return CKYINVALIDDATA; }
dab6d7
+    /* point current to the next section (type attributes)  */
dab6d7
+    tagSize = commonCertAttributes - current;
dab6d7
+    current += commonSize + tagSize;
dab6d7
+    currentSize -= (commonSize +tagSize);
dab6d7
+    if (currentSize < 0) { return CKYINVALIDDATA; }
dab6d7
+
dab6d7
+    /* get the id */
dab6d7
+    if (commonCertAttributes[0] != ASN1_OCTET_STRING) { return CKYINVALIDDATA; }
dab6d7
+    entry = dataStart(commonCertAttributes, commonSize, &entrySize, false);
dab6d7
+    if (entry == NULL) { return CKYINVALIDARGS; }
dab6d7
+    tagSize = entry - commonCertAttributes;
dab6d7
+    commonCertAttributes += entrySize + tagSize;
dab6d7
+    commonSize -= (entrySize +tagSize);
dab6d7
+    setAttribute(CKA_ID, entry, entrySize);
dab6d7
+
dab6d7
+
dab6d7
+    /* skip authority (currently unused) */
dab6d7
+    /* skip requestID */
dab6d7
+    /* skip thumbprint */
dab6d7
+    /* future common cert attributes here */
dab6d7
+
dab6d7
+    /* certs have not subclass attributes  ASN1_CHOICE_0 */
dab6d7
+
dab6d7
+    /* handle the X509 type attributes */
dab6d7
+    if (current[0] != ASN1_CHOICE_1) { return CKYINVALIDDATA; }
dab6d7
+    /* unwrap */
dab6d7
+    commonCertAttributes = dataStart(current, currentSize, &commonSize, false);
dab6d7
+    if (commonCertAttributes == NULL) { return CKYINVALIDDATA; }
dab6d7
+   
dab6d7
+    /*
dab6d7
+     * PCKS11X504CertificateAttributes
dab6d7
+     *     value   SEQUENCE or CHOICE_0
dab6d7
+     *     ... don't care about the rest.
dab6d7
+     */
dab6d7
+    valueTag = commonCertAttributes[0];
dab6d7
+    /* unwrapp */
dab6d7
+    entry = dataStart(commonCertAttributes, commonSize, &entrySize, false);
dab6d7
+    if (entry == NULL) { return CKYINVALIDDATA; }
dab6d7
+    if (valueTag == ASN1_SEQUENCE) {
dab6d7
+    	entry = dataStart(entry, entrySize, &entrySize, false);
dab6d7
+    	if (entry == NULL) { return CKYINVALIDDATA; }
dab6d7
+	/* if we have a path, the actual object is in another file,
dab6d7
+	 * tell the caller to get it and come back here */
dab6d7
+	status = objectPath.setObjectPath(entry, entrySize);
dab6d7
+	state = PK15StateNeedRawCertificate;
dab6d7
+        return status;
dab6d7
+    }
dab6d7
+    if (valueTag != ASN1_CHOICE_0) {
dab6d7
+	return CKYINVALIDDATA;
dab6d7
+    }
dab6d7
+    return  completeRawCertificate(entry, entrySize);
dab6d7
+}
dab6d7
+
dab6d7
+CKYStatus 
dab6d7
+PK15Object::completeAuthObject(const CKYByte *current, CKYSize currentSize)
dab6d7
+{
dab6d7
+    const CKYByte *commonAuthAttributes;
dab6d7
+    CKYSize commonSize;
dab6d7
+    const CKYByte *entry;
dab6d7
+    CKYSize entrySize;
dab6d7
+    CKYSize tagSize;
dab6d7
+    CKYBuffer empty;
dab6d7
+    CKYStatus status;
dab6d7
+
dab6d7
+    CKYBuffer_InitEmpty(&empty);
dab6d7
+
dab6d7
+    if (current == NULL) { return CKYINVALIDARGS; }
dab6d7
+    /* common Auth attributes */
dab6d7
+    if (current[0] == ASN1_SEQUENCE) {
dab6d7
+         /* unwrap */
dab6d7
+        commonAuthAttributes = 
dab6d7
+			dataStart(current, currentSize, &commonSize, false);
dab6d7
+	if (commonAuthAttributes == NULL) { return CKYINVALIDDATA; }
dab6d7
+	tagSize = commonAuthAttributes - current;
dab6d7
+	current += commonSize + tagSize;
dab6d7
+	currentSize -= (commonSize + tagSize);
dab6d7
+	if (currentSize < 0) { return CKYINVALIDDATA; }
dab6d7
+	if (commonAuthAttributes[0] != ASN1_OCTET_STRING) {
dab6d7
+	    return CKYINVALIDDATA;
dab6d7
+	}
dab6d7
+	entry = dataStart(commonAuthAttributes, commonSize, &entrySize, false);
dab6d7
+	if (entry == NULL) { return CKYINVALIDARGS; }
dab6d7
+	tagSize = entry - commonAuthAttributes;
dab6d7
+	commonAuthAttributes += entrySize + tagSize;
dab6d7
+	commonSize -= (entrySize +tagSize);
dab6d7
+	status = CKYBuffer_Replace(&pinAuthId, 0, entry, entrySize);
dab6d7
+	if (status != CKYSUCCESS) {
dab6d7
+	   return status;
dab6d7
+	}
dab6d7
+	
dab6d7
+    }
dab6d7
+    /* auth specific values */
dab6d7
+    if (current[0] != ASN1_CHOICE_1) { return CKYINVALIDARGS; }
dab6d7
+    /* unwrap */
dab6d7
+    commonAuthAttributes = dataStart(current, currentSize, &commonSize, false);
dab6d7
+    if (commonAuthAttributes == NULL) { return CKYINVALIDDATA; }
dab6d7
+    tagSize = commonAuthAttributes - current;
dab6d7
+    current += commonSize + tagSize;
dab6d7
+    currentSize -= (commonSize +tagSize);
dab6d7
+    if (currentSize < 0) { return CKYINVALIDDATA; }
dab6d7
+    /*
dab6d7
+     * parse the Pin Auth Attributes 
dab6d7
+     *     pinFlags  BIT_STRING
dab6d7
+     *     pinType   ENUMERATED (bcd, ascii-numeric, utf8)
dab6d7
+     *     minLength INTEGER
dab6d7
+     *     storedLength INTEGER
dab6d7
+     *     maxlength INTEGER (optional)
dab6d7
+     *     pinReference CHOICE_0 (optional)
dab6d7
+     *     padChar OCTET_STRING (optional)
dab6d7
+     *     lastPinChange GENERALIZED_TIME (optional)
dab6d7
+     *     path PKCS15Path (optional)
dab6d7
+     */
dab6d7
+    if (commonAuthAttributes[0] != ASN1_SEQUENCE) { return CKYINVALIDARGS; }
dab6d7
+    commonAuthAttributes = dataStart(commonAuthAttributes, 
dab6d7
+					commonSize, &commonSize, false);
dab6d7
+    if (commonAuthAttributes == NULL) { return CKYINVALIDDATA; }
dab6d7
+
dab6d7
+    /* parse pin flags */
dab6d7
+    if (commonAuthAttributes[0] != ASN1_BIT_STRING) { return CKYINVALIDDATA; }
dab6d7
+
dab6d7
+    entry = dataStart(commonAuthAttributes, commonSize, &entrySize, false);
dab6d7
+    if (entry == NULL) { return CKYINVALIDARGS; }
dab6d7
+    tagSize = entry - commonAuthAttributes;
dab6d7
+    commonAuthAttributes += entrySize + tagSize;
dab6d7
+    commonSize -= (entrySize +tagSize);
dab6d7
+    pinInfo.pinFlags = GetBits(entry,entrySize,9,2);
dab6d7
+
dab6d7
+
dab6d7
+    /* parse PinType */
dab6d7
+    if (commonAuthAttributes[0] != ASN1_ENUMERATED) { return CKYINVALIDDATA; }
dab6d7
+    entry = dataStart(commonAuthAttributes, commonSize, &entrySize, false);
dab6d7
+    if (entry == NULL) { return CKYINVALIDARGS; }
dab6d7
+    tagSize = entry - commonAuthAttributes;
dab6d7
+    commonAuthAttributes += entrySize + tagSize;
dab6d7
+    commonSize -= (entrySize +tagSize);
dab6d7
+    /* turn entry into an int */
dab6d7
+    if (entrySize > 1) { return CKYINVALIDARGS; }
dab6d7
+    pinInfo.pinType = (P15PinType) *entry;
dab6d7
+
dab6d7
+    /* parse minLength */
dab6d7
+    if (commonAuthAttributes[0] != ASN1_INTEGER) { return CKYINVALIDDATA; }
dab6d7
+    entry = dataStart(commonAuthAttributes, commonSize, &entrySize, false);
dab6d7
+    if (entry == NULL) { return CKYINVALIDARGS; }
dab6d7
+    tagSize = entry - commonAuthAttributes;
dab6d7
+    commonAuthAttributes += entrySize + tagSize;
dab6d7
+    commonSize -= (entrySize +tagSize);
dab6d7
+    if (entrySize > 1) { return CKYINVALIDARGS; }
dab6d7
+    pinInfo.minLength = *entry;
dab6d7
+
dab6d7
+    /* parse storedLength */
dab6d7
+    if (commonAuthAttributes[0] != ASN1_INTEGER) { return CKYINVALIDDATA; }
dab6d7
+    entry = dataStart(commonAuthAttributes, commonSize, &entrySize, false);
dab6d7
+    if (entry == NULL) { return CKYINVALIDARGS; }
dab6d7
+    tagSize = entry - commonAuthAttributes;
dab6d7
+    commonAuthAttributes += entrySize + tagSize;
dab6d7
+    commonSize -= (entrySize +tagSize);
dab6d7
+    if (entrySize > 1) { return CKYINVALIDARGS; }
dab6d7
+    pinInfo.storedLength = *entry;
dab6d7
+
dab6d7
+    /* parse maxLength (optional) */
dab6d7
+    if (commonAuthAttributes[0] == ASN1_INTEGER) { 
dab6d7
+	unsigned long maxPin;
dab6d7
+	entry = dataStart(commonAuthAttributes, commonSize, &entrySize, false);
dab6d7
+	if (entry == NULL) { return CKYINVALIDARGS; }
dab6d7
+	tagSize = entry - commonAuthAttributes;
dab6d7
+	commonAuthAttributes += entrySize + tagSize;
dab6d7
+	commonSize -= (entrySize +tagSize);
dab6d7
+	if (entrySize > sizeof (maxPin)) { return CKYINVALIDARGS; }
dab6d7
+	maxPin = 0; 
dab6d7
+	CKYSize i;
dab6d7
+	for (i=0; i < entrySize; i++) {
dab6d7
+	    maxPin = (maxPin << 8) | entry[i];
dab6d7
+	}
dab6d7
+	pinInfo.maxLength = maxPin;
dab6d7
+    }
dab6d7
+
dab6d7
+    /* parse pin ref  (optional) */
dab6d7
+    if ((commonAuthAttributes[0]|ASN1_CONSTRUCTED) == ASN1_CHOICE_0)  {
dab6d7
+	CKYByte pinRef;
dab6d7
+	entry = dataStart(commonAuthAttributes, commonSize, &entrySize, false);
dab6d7
+	if (entry == NULL) { return CKYINVALIDARGS; }
dab6d7
+	tagSize = entry - commonAuthAttributes;
dab6d7
+	commonAuthAttributes += entrySize + tagSize;
dab6d7
+	commonSize -= (entrySize +tagSize);
dab6d7
+	if (entrySize > 2) { return CKYINVALIDARGS; }
dab6d7
+	if (entrySize == 2) {
dab6d7
+	    if (*entry != 0) { return CKYINVALIDARGS; }
dab6d7
+	    pinRef = entry[1];
dab6d7
+	} else pinRef = entry[0];
dab6d7
+	pinInfo.pinRef = pinRef;
dab6d7
+    }
dab6d7
+
dab6d7
+    /* parse padChar */
dab6d7
+    if (commonAuthAttributes[0] == ASN1_OCTET_STRING) { 
dab6d7
+	entry = dataStart(commonAuthAttributes, commonSize, &entrySize, false);
dab6d7
+	if (entry == NULL) { return CKYINVALIDARGS; }
dab6d7
+	tagSize = entry - commonAuthAttributes;
dab6d7
+	commonAuthAttributes += entrySize + tagSize;
dab6d7
+	commonSize -= (entrySize +tagSize);
dab6d7
+	if (entrySize > 1) { return CKYINVALIDARGS; }
dab6d7
+	pinInfo.padChar = *entry;
dab6d7
+    }
dab6d7
+
dab6d7
+    /* skip lastPinChange */
dab6d7
+    if (commonAuthAttributes[0] == ASN1_GENERALIZED_TIME) { 
dab6d7
+	entry = dataStart(commonAuthAttributes, commonSize, &entrySize, false);
dab6d7
+	if (entry == NULL) { return CKYINVALIDARGS; }
dab6d7
+	tagSize = entry - commonAuthAttributes;
dab6d7
+	commonAuthAttributes += entrySize + tagSize;
dab6d7
+	commonSize -= (entrySize +tagSize);
dab6d7
+    }
dab6d7
+    /* parse path */
dab6d7
+    if (commonAuthAttributes[0] == ASN1_SEQUENCE) { 
dab6d7
+	entry = dataStart(commonAuthAttributes, commonSize, 
dab6d7
+							&entrySize, false);
dab6d7
+	if (entry == NULL) { return CKYINVALIDARGS; }
dab6d7
+	tagSize = entry - commonAuthAttributes;
dab6d7
+	commonAuthAttributes += entrySize + tagSize;
dab6d7
+	commonSize -= (entrySize +tagSize);
dab6d7
+	/* if we have a path, the actual object is in another file,
dab6d7
+	 * tell the caller to get it and come back here */
dab6d7
+	status = objectPath.setObjectPath(entry, entrySize);
dab6d7
+	if (status != CKYSUCCESS) { return status; }
dab6d7
+    }
dab6d7
+    state = PK15StateComplete;
dab6d7
+    return CKYSUCCESS;
dab6d7
+}
dab6d7
+
dab6d7
+CKYStatus
dab6d7
+PK15Object::completeKeyObject(const CKYByte *current, CKYSize currentSize)
dab6d7
+{
dab6d7
+    const CKYByte *commonKeyAttributes;
dab6d7
+    CKYSize commonSize;
dab6d7
+    const CKYByte *entry;
dab6d7
+    CKYSize entrySize;
dab6d7
+    CKYSize tagSize;
dab6d7
+    CKYBuffer empty;
dab6d7
+    CKYStatus status;
dab6d7
+    unsigned long bits;
dab6d7
+    /*bool native; */
dab6d7
+
dab6d7
+    CKYBuffer_InitEmpty(&empty);
dab6d7
+    /*
dab6d7
+     * parse the Common Key Attributes 
dab6d7
+     *     id OCTET_STRING
dab6d7
+     *     usageFlags BIT_STRING 
dab6d7
+     *     native BOOLEAN DEFAULT TRUE
dab6d7
+     *     accessFlags BIT_STRING (optional)
dab6d7
+     *     keyReference OCTET_STRING (optional)
dab6d7
+     *     startDate GENERALIZED_TIME (optional)
dab6d7
+     *     endDate [0] GENERALIZED_TYPE (optional)
dab6d7
+     */
dab6d7
+    if ((current == NULL) || (current[0] != ASN1_SEQUENCE)) 
dab6d7
+		{ return CKYINVALIDARGS; }
dab6d7
+    /* unwrap */
dab6d7
+    commonKeyAttributes = dataStart(current, currentSize, &commonSize, false);
dab6d7
+    if (commonKeyAttributes == NULL) { return CKYINVALIDDATA; }
dab6d7
+
dab6d7
+    /* point current to the next section (sublcass attributes)  */
dab6d7
+    tagSize = commonKeyAttributes - current;
dab6d7
+    current += commonSize + tagSize;
dab6d7
+    currentSize -= (commonSize +tagSize);
dab6d7
+    if (currentSize < 0) { return CKYINVALIDDATA; }
dab6d7
+
dab6d7
+    /* get the id */
dab6d7
+    if (commonKeyAttributes[0] != ASN1_OCTET_STRING) { return CKYINVALIDDATA; }
dab6d7
+    entry = dataStart(commonKeyAttributes, commonSize, &entrySize, false);
dab6d7
+    if (entry == NULL) { return CKYINVALIDARGS; }
dab6d7
+    tagSize = entry - commonKeyAttributes;
dab6d7
+    commonKeyAttributes += entrySize + tagSize;
dab6d7
+    commonSize -= (entrySize +tagSize);
dab6d7
+    setAttribute(CKA_ID, entry, entrySize);
dab6d7
+
dab6d7
+    /* parse flags */
dab6d7
+    if (commonKeyAttributes[0] != ASN1_BIT_STRING) { return CKYINVALIDDATA; }
dab6d7
+    entry = dataStart(commonKeyAttributes, commonSize, &entrySize, false);
dab6d7
+    if (entry == NULL) { return CKYINVALIDARGS; }
dab6d7
+    tagSize = entry - commonKeyAttributes;
dab6d7
+    commonKeyAttributes += entrySize + tagSize;
dab6d7
+    commonSize -= (entrySize +tagSize);
dab6d7
+    bits = GetBits(entry,entrySize,10,2);
dab6d7
+    if (bits & BROKEN_FLAG) {
dab6d7
+	bits = defaultUsageBits();
dab6d7
+    }
dab6d7
+    setAttributeBool(CKA_ENCRYPT,
dab6d7
+			(bits & P15UsageEncrypt)          ? TRUE : FALSE);
dab6d7
+    setAttributeBool(CKA_DECRYPT,
dab6d7
+			(bits & P15UsageDecrypt)          ? TRUE : FALSE);
dab6d7
+    setAttributeBool(CKA_SIGN,
dab6d7
+			(bits & P15UsageSign)             ? TRUE : FALSE);
dab6d7
+    setAttributeBool(CKA_SIGN_RECOVER,
dab6d7
+			(bits & P15UsageSignRecover)      ? TRUE : FALSE);
dab6d7
+    setAttributeBool(CKA_WRAP,
dab6d7
+			(bits & P15UsageWrap)             ? TRUE : FALSE);
dab6d7
+    setAttributeBool(CKA_UNWRAP,
dab6d7
+			(bits & P15UsageUnwrap)           ? TRUE : FALSE);
dab6d7
+    setAttributeBool(CKA_VERIFY,
dab6d7
+			(bits & P15UsageVerify)           ? TRUE : FALSE);
dab6d7
+    setAttributeBool(CKA_VERIFY_RECOVER,
dab6d7
+			(bits & P15UsageVerifyRecover)    ? TRUE : FALSE);
dab6d7
+    setAttributeBool(CKA_DERIVE,
dab6d7
+			(bits & P15UsageDerive)           ? TRUE : FALSE);
dab6d7
+    /* no CKA value for P15UsageNonRepudiation */
dab6d7
+    if (bits & P15UsageNonRepudiation) {
dab6d7
+	/* set signing and sign recover. Non-repudiation keys are automatically
dab6d7
+         * signing keys */
dab6d7
+	setAttributeBool(CKA_SIGN, TRUE);
dab6d7
+	if (keyType == rsa) {
dab6d7
+	    setAttributeBool(CKA_SIGN_RECOVER, TRUE);
dab6d7
+	}
dab6d7
+    }
dab6d7
+
dab6d7
+    /* parse native (currently unused) */
dab6d7
+    /*native=true; */
dab6d7
+    if (commonKeyAttributes[0] == ASN1_BOOLEAN) {
dab6d7
+	entry = dataStart(commonKeyAttributes, commonSize, &entrySize, false);
dab6d7
+	if (entry == NULL) { return CKYINVALIDARGS; }
dab6d7
+	tagSize = entry - commonKeyAttributes;
dab6d7
+	commonKeyAttributes += entrySize + tagSize;
dab6d7
+	commonSize -= (entrySize +tagSize);
dab6d7
+	/*if ((entrySize == 1) && (entry[0] == 0)) {
dab6d7
+	    native = false;
dab6d7
+	} */
dab6d7
+    }
dab6d7
+    /* parse access flags */
dab6d7
+    bits = BROKEN_FLAG;
dab6d7
+    if (commonKeyAttributes[0] == ASN1_BIT_STRING) {
dab6d7
+	entry = dataStart(commonKeyAttributes, commonSize, &entrySize, false);
dab6d7
+	if (entry == NULL) { return CKYINVALIDARGS; }
dab6d7
+	tagSize = entry - commonKeyAttributes;
dab6d7
+	commonKeyAttributes += entrySize + tagSize;
dab6d7
+	commonSize -= (entrySize +tagSize);
dab6d7
+	bits = GetBits(entry,entrySize,4,1);
dab6d7
+    }
dab6d7
+    if (bits & BROKEN_FLAG) {
dab6d7
+	bits = defaultAccessBits();
dab6d7
+    }
dab6d7
+    setAttributeBool(CKA_SENSITIVE,  
dab6d7
+			(bits & P15AccessSensitive)       ? TRUE : FALSE);
dab6d7
+    setAttributeBool(CKA_EXTRACTABLE,
dab6d7
+			(bits & P15AccessExtractable)     ? TRUE : FALSE);
dab6d7
+    setAttributeBool(CKA_ALWAYS_SENSITIVE, 
dab6d7
+			(bits & P15AccessAlwaysSenstive)  ? TRUE : FALSE);
dab6d7
+    setAttributeBool(CKA_NEVER_EXTRACTABLE,
dab6d7
+			(bits & P15AccessNeverExtractable)? TRUE : FALSE);
dab6d7
+    setAttributeBool(CKA_LOCAL,      
dab6d7
+			(bits & P15AccessLocal)           ? TRUE : FALSE);
dab6d7
+
dab6d7
+    /* parse the key reference */
dab6d7
+    keyRef = PK15_INVALID_KEY_REF; /* invalid keyRef */
dab6d7
+    if (commonKeyAttributes[0] == ASN1_INTEGER) {
dab6d7
+	entry = dataStart(commonKeyAttributes, commonSize, &entrySize, false);
dab6d7
+	if (entry == NULL) { return CKYINVALIDARGS; }
dab6d7
+	tagSize = entry - commonKeyAttributes;
dab6d7
+	commonKeyAttributes += entrySize + tagSize;
dab6d7
+	commonSize -= (entrySize +tagSize);
dab6d7
+	if (entrySize == 1) {
dab6d7
+	    keyRef = entry[0];
dab6d7
+	} else if ((entrySize == 2) && (entry[0] == 0)) {
dab6d7
+	    keyRef = entry[1];
dab6d7
+	}
dab6d7
+    }
dab6d7
+    setAttribute(CKA_START_DATE, &empty);
dab6d7
+    if (commonKeyAttributes[0] == ASN1_GENERALIZED_TIME) {
dab6d7
+	entry = dataStart(commonKeyAttributes, commonSize, &entrySize, false);
dab6d7
+	if (entry == NULL) { return CKYINVALIDARGS; }
dab6d7
+	tagSize = entry - commonKeyAttributes;
dab6d7
+	commonKeyAttributes += entrySize + tagSize;
dab6d7
+	commonSize -= (entrySize +tagSize);
dab6d7
+	setAttribute(CKA_START_DATE,entry, entrySize);
dab6d7
+    }
dab6d7
+    setAttribute(CKA_END_DATE, &empty);
dab6d7
+    if (commonKeyAttributes[0] == ASN1_CHOICE_0) {
dab6d7
+	entry = dataStart(commonKeyAttributes, commonSize, &entrySize, false);
dab6d7
+	if (entry == NULL) { return CKYINVALIDARGS; }
dab6d7
+	tagSize = entry - commonKeyAttributes;
dab6d7
+	commonKeyAttributes += entrySize + tagSize;
dab6d7
+	commonSize -= (entrySize +tagSize);
dab6d7
+	setAttribute(CKA_END_DATE,entry, entrySize);
dab6d7
+    }
dab6d7
+    /* future common key attributes here */
dab6d7
+
dab6d7
+    /*
dab6d7
+     *  Parse Class variables
dab6d7
+     *
dab6d7
+     */
dab6d7
+    switch (p15Type) {
dab6d7
+    case PK15PuKey:
dab6d7
+	status = completePubKeyObject(current,currentSize);
dab6d7
+	break;
dab6d7
+    case PK15PvKey:
dab6d7
+	status = completePrivKeyObject(current,currentSize);
dab6d7
+	break;
dab6d7
+    default:
dab6d7
+	status=CKYLIBFAIL; /* shouldn't happen */
dab6d7
+	break;
dab6d7
+    }
dab6d7
+    return status;
dab6d7
+}
dab6d7
+
dab6d7
+CKYStatus PK15Object::completePrivKeyObject(const CKYByte *current,
dab6d7
+							CKYSize currentSize)
dab6d7
+{
dab6d7
+    const CKYByte *commonPrivKeyAttributes;
dab6d7
+    CKYSize commonSize;
dab6d7
+    const CKYByte *entry;
dab6d7
+    CKYSize entrySize;
dab6d7
+    CKYSize tagSize;
dab6d7
+    CKYBuffer empty;
dab6d7
+    CKYStatus status;
dab6d7
+    unsigned int modulusSize;
dab6d7
+    unsigned int i;
dab6d7
+
dab6d7
+    CKYBuffer_InitEmpty(&empty);
dab6d7
+    if (current == NULL) { return CKYINVALIDARGS; }
dab6d7
+
dab6d7
+    /* optional subclass = CommonPrivateKeyAttributes */
dab6d7
+    if (current[0] == ASN1_CHOICE_0) {
dab6d7
+	/*
dab6d7
+         * PKCS15CommonPrivateKeyAttributes
dab6d7
+         *
dab6d7
+         * subjectName   SEQUENCE optional
dab6d7
+         * keyIdentifiers CHOICE 0  optional
dab6d7
+         */
dab6d7
+	/* unwrap */
dab6d7
+	commonPrivKeyAttributes = 
dab6d7
+			dataStart(current, currentSize, &commonSize, false);
dab6d7
+	if (commonPrivKeyAttributes == NULL) { return CKYINVALIDDATA; }
dab6d7
+	/* point current to the next section (type attributes)  */
dab6d7
+	tagSize = commonPrivKeyAttributes - current;
dab6d7
+	current += commonSize + tagSize;
dab6d7
+	currentSize -= (commonSize +tagSize);
dab6d7
+	if (currentSize < 0) { return CKYINVALIDDATA; }
dab6d7
+
dab6d7
+ 	/* subjectName */
dab6d7
+	if (commonPrivKeyAttributes[0] == ASN1_SEQUENCE) {
dab6d7
+	    entry = dataStart(commonPrivKeyAttributes, commonSize, 
dab6d7
+							&entrySize, false);
dab6d7
+	    if (entry == NULL) { return CKYINVALIDARGS; }
dab6d7
+	    tagSize = entry - commonPrivKeyAttributes;
dab6d7
+	    commonPrivKeyAttributes += entrySize + tagSize;
dab6d7
+	    commonSize -= (entrySize +tagSize);
dab6d7
+	    setAttribute(CKA_SUBJECT, entry, entrySize);
dab6d7
+	}
dab6d7
+
dab6d7
+	/* keyIdentfiers */
dab6d7
+	/* future CommonPrivateKeyAttributes here */
dab6d7
+    }
dab6d7
+
dab6d7
+    
dab6d7
+    /* Type attributes (either PKCS15RSAPrivateKeyAttributes or 
dab6d7
+     * PKCS15ECCPrivateKeyAttributes) -- Not Optional */
dab6d7
+    if (current[0] != ASN1_CHOICE_1) { return CKYINVALIDDATA; }
dab6d7
+    /*
dab6d7
+     *    PKCS15RSAPrivateKeyAttributes
dab6d7
+     *        value PKCS15ObjectValue
dab6d7
+     *        modulusLength INTEGER
dab6d7
+     *        keyInfo SEQUENCE optional
dab6d7
+     *    PKCS15ECCPrivateKeyAttributes
dab6d7
+     *        value PKCS15ObjectValue
dab6d7
+     *        keyInfo SEQUENCE optional
dab6d7
+     */
dab6d7
+    /* unwrap */
dab6d7
+    commonPrivKeyAttributes = 
dab6d7
+			dataStart(current, currentSize, &commonSize, false);
dab6d7
+    if (commonPrivKeyAttributes == NULL) { return CKYINVALIDDATA; }
dab6d7
+
dab6d7
+    /* value */
dab6d7
+     /* don't support direct private key objects */
dab6d7
+    if (commonPrivKeyAttributes[0] == ASN1_CHOICE_0) { return CKYUNSUPPORTED;  }
dab6d7
+    if (commonPrivKeyAttributes[0] != ASN1_SEQUENCE) { return CKYINVALIDDATA; }
dab6d7
+    commonPrivKeyAttributes = dataStart(commonPrivKeyAttributes, commonSize, &commonSize, false);
dab6d7
+    if (commonPrivKeyAttributes == NULL) { return CKYINVALIDARGS; }
dab6d7
+    entry = dataStart(commonPrivKeyAttributes, commonSize, &entrySize, false);
dab6d7
+    if (entry == NULL) { return CKYINVALIDARGS; }
dab6d7
+    tagSize = entry - commonPrivKeyAttributes;
dab6d7
+    commonPrivKeyAttributes += entrySize + tagSize;
dab6d7
+    commonSize -= (entrySize +tagSize);
dab6d7
+    /* if we have a path, the actual object is in another file,
dab6d7
+     * tell the caller to get it and come back here */
dab6d7
+    status = objectPath.setObjectPath(entry, entrySize);
dab6d7
+    if (status != CKYSUCCESS) { return status; }
dab6d7
+
dab6d7
+    /* parse modulus size */
dab6d7
+    if ((keyType == rsa) && commonPrivKeyAttributes[0] == ASN1_INTEGER) {
dab6d7
+	entry = dataStart(commonPrivKeyAttributes, commonSize, 
dab6d7
+							&entrySize, false);
dab6d7
+	if (entry == NULL) { return CKYINVALIDARGS; }
dab6d7
+	tagSize = entry - commonPrivKeyAttributes;
dab6d7
+	commonPrivKeyAttributes += entrySize + tagSize;
dab6d7
+	commonSize -= (entrySize +tagSize);
dab6d7
+	if (entrySize > 4) {
dab6d7
+	   return CKYINVALIDDATA;
dab6d7
+	}
dab6d7
+	for (modulusSize = 0, i=0; i < entrySize; i++) {
dab6d7
+	   modulusSize = (modulusSize << 8) + entry[i];
dab6d7
+	}
dab6d7
+	setKeySize(modulusSize);
dab6d7
+    }
dab6d7
+
dab6d7
+    if (keyType == rsa) {
dab6d7
+	state = PK15StateComplete;
dab6d7
+	return CKYSUCCESS; /* we're done with RSA */
dab6d7
+    }
dab6d7
+
dab6d7
+    /* parse keyinfo  at this point all we are after is the EC_PARAM*/
dab6d7
+    if (commonPrivKeyAttributes[0] == ASN1_SEQUENCE) {
dab6d7
+	/* unwrap */
dab6d7
+	commonPrivKeyAttributes = dataStart(commonPrivKeyAttributes, 
dab6d7
+					commonSize, &commonSize, true);
dab6d7
+	if (commonPrivKeyAttributes == NULL) { return CKYINVALIDDATA; }
dab6d7
+	if (commonPrivKeyAttributes[0] == ASN1_SEQUENCE) {
dab6d7
+	    entry = dataStart(commonPrivKeyAttributes, commonSize, 
dab6d7
+							&entrySize, true);
dab6d7
+	    if (entry == NULL) { return CKYINVALIDDATA; }
dab6d7
+	    setAttribute(CKA_EC_PARAMS, entry, entrySize);
dab6d7
+	}
dab6d7
+    }
dab6d7
+    state = PK15StateComplete;
dab6d7
+    return CKYSUCCESS;
dab6d7
+}
dab6d7
+
dab6d7
+CKYStatus 
dab6d7
+PK15Object::completePubKeyObject(const CKYByte *current, CKYSize currentSize)
dab6d7
+{
dab6d7
+    const CKYByte *commonPubKeyAttributes;
dab6d7
+    CKYSize commonSize;
dab6d7
+    const CKYByte *entry;
dab6d7
+    CKYSize entrySize;
dab6d7
+    CKYSize tagSize;
dab6d7
+    CKYBuffer empty;
dab6d7
+    CKYStatus status;
dab6d7
+    unsigned int modulusSize;
dab6d7
+    unsigned int i;
dab6d7
+
dab6d7
+    CKYBuffer_InitEmpty(&empty);
dab6d7
+    if (current == NULL) { return CKYINVALIDDATA; }
dab6d7
+
dab6d7
+    /* optional subclass = CommonPublicKeyAttributes */
dab6d7
+    if (current[0] == ASN1_CHOICE_0) {
dab6d7
+	/*
dab6d7
+         * PKCS15CommonPublicKeyAttributes
dab6d7
+         *
dab6d7
+         * subjectName   SEQUENCE optional
dab6d7
+         * keyIdentifiers CHOICE 0  optional
dab6d7
+         */
dab6d7
+	/* unwrap */
dab6d7
+	commonPubKeyAttributes = 
dab6d7
+			dataStart(current, currentSize, &commonSize, false);
dab6d7
+	if (commonPubKeyAttributes == NULL) { return CKYINVALIDDATA; }
dab6d7
+	/* point current to the next section (type attributes)  */
dab6d7
+	tagSize = commonPubKeyAttributes - current;
dab6d7
+	current += commonSize + tagSize;
dab6d7
+	currentSize -= (commonSize +tagSize);
dab6d7
+	if (currentSize < 0) { return CKYINVALIDDATA; }
dab6d7
+
dab6d7
+ 	/* subjectName */
dab6d7
+	if (commonPubKeyAttributes[0] == ASN1_SEQUENCE) {
dab6d7
+	    entry = dataStart(commonPubKeyAttributes, commonSize, 
dab6d7
+							&entrySize, false);
dab6d7
+	    if (entry == NULL) { return CKYINVALIDARGS; }
dab6d7
+	    tagSize = entry - commonPubKeyAttributes;
dab6d7
+	    commonPubKeyAttributes += entrySize + tagSize;
dab6d7
+	    commonSize -= (entrySize +tagSize);
dab6d7
+	    setAttribute(CKA_SUBJECT, entry, entrySize);
dab6d7
+	}
dab6d7
+	/* future CommonPublicKeyAttributes here */
dab6d7
+    }
dab6d7
+
dab6d7
+    
dab6d7
+    /* Type attributes (either PKCS15RSAPublicKeyAttributes or 
dab6d7
+     * PKCS15ECCPublicKeyAttributes) -- Not Optional */
dab6d7
+    if (current[0] != ASN1_CHOICE_1) { return CKYINVALIDDATA; }
dab6d7
+    /*
dab6d7
+     *    PKCS15RSAPublicKeyAttributes
dab6d7
+     *        value PKCS15ObjectValue
dab6d7
+     *        modulusLength INTEGER
dab6d7
+     *        keyInfo SEQUENCE optional
dab6d7
+     *    PKCS15ECCPublicKeyAttributes
dab6d7
+     *        value PKCS15ObjectValue
dab6d7
+     *        keyInfo SEQUENCE optional
dab6d7
+     */
dab6d7
+    /* unwrap */
dab6d7
+    commonPubKeyAttributes = 
dab6d7
+			dataStart(current, currentSize, &commonSize, false);
dab6d7
+    if (commonPubKeyAttributes == NULL) { return CKYINVALIDDATA; }
dab6d7
+
dab6d7
+    /* value */
dab6d7
+    if (commonPubKeyAttributes[0] == ASN1_CHOICE_0) { 
dab6d7
+    	entry = dataStart(commonPubKeyAttributes, commonSize, 
dab6d7
+							&entrySize, false);
dab6d7
+	if (entry == NULL) { return CKYINVALIDARGS; }
dab6d7
+	status = completeRawPublicKey(entry, entrySize);
dab6d7
+	if (status != CKYSUCCESS) { return status; }
dab6d7
+    } else if (commonPubKeyAttributes[0] == ASN1_SEQUENCE) { 
dab6d7
+	entry = dataStart(commonPubKeyAttributes, commonSize, 
dab6d7
+							&entrySize, false);
dab6d7
+	if (entry == NULL) { return CKYINVALIDARGS; }
dab6d7
+	tagSize = entry - commonPubKeyAttributes;
dab6d7
+	commonPubKeyAttributes += entrySize + tagSize;
dab6d7
+	commonSize -= (entrySize +tagSize);
dab6d7
+	/* if we have a path, the actual object is in another file,
dab6d7
+	 * tell the caller to get it and come back here */
dab6d7
+	status = objectPath.setObjectPath(entry, entrySize);
dab6d7
+	if (status != CKYSUCCESS) { return status; }
dab6d7
+	state = PK15StateNeedRawPublicKey;
dab6d7
+    }
dab6d7
+
dab6d7
+    /* parse modulus size */
dab6d7
+    if ((keyType == rsa) && commonPubKeyAttributes[0] == ASN1_INTEGER) {
dab6d7
+	entry = dataStart(commonPubKeyAttributes, commonSize, 
dab6d7
+							&entrySize, false);
dab6d7
+	if (entry == NULL) { return CKYINVALIDARGS; }
dab6d7
+	tagSize = entry - commonPubKeyAttributes;
dab6d7
+	commonPubKeyAttributes += entrySize + tagSize;
dab6d7
+	commonSize -= (entrySize +tagSize);
dab6d7
+	if (entrySize > 4) {
dab6d7
+	   return CKYINVALIDDATA;
dab6d7
+	}
dab6d7
+	for (modulusSize = 0, i=0; i < entrySize; i++) {
dab6d7
+	   modulusSize = (modulusSize << 8) + entry[i];
dab6d7
+	}
dab6d7
+	setKeySize(modulusSize);
dab6d7
+    }
dab6d7
+
dab6d7
+    if (keyType == rsa) {
dab6d7
+	return CKYSUCCESS; /* we're done with RSA */
dab6d7
+    }
dab6d7
+
dab6d7
+    /* parse keyinfo  at this point all we are after is the EC_PARAM*/
dab6d7
+    if (commonPubKeyAttributes[0] == ASN1_SEQUENCE) {
dab6d7
+	/* unwrap */
dab6d7
+	commonPubKeyAttributes = dataStart(commonPubKeyAttributes, 
dab6d7
+					commonSize, &commonSize, true);
dab6d7
+	if (commonPubKeyAttributes == NULL) { return CKYINVALIDDATA; }
dab6d7
+	if (commonPubKeyAttributes[0] == ASN1_SEQUENCE) {
dab6d7
+	    entry = dataStart(commonPubKeyAttributes, commonSize, 
dab6d7
+							&entrySize, true);
dab6d7
+	    if (entry == NULL) { return CKYINVALIDDATA; } 
dab6d7
+	    setAttribute(CKA_EC_PARAMS, entry, entrySize);
dab6d7
+	}
dab6d7
+    }
dab6d7
+    return CKYSUCCESS;
dab6d7
+
dab6d7
+}
dab6d7
+
dab6d7
+CKYStatus 
dab6d7
+PK15Object::completeRawCertificate(const CKYByte *derCert, CKYSize derCertSize)
dab6d7
+{
dab6d7
+    SECStatus rv;
dab6d7
+    CCItem issuerItem, serialItem, derSerialItem, subjectItem,
dab6d7
+        validityItem, subjectKeyItem;
dab6d7
+    const char *certLabel;
dab6d7
+
dab6d7
+    setAttribute(CKA_VALUE, derCert, derCertSize);
dab6d7
+    rv = GetCertFieldItems(derCert, derCertSize, 
dab6d7
+        &issuerItem, &serialItem, &derSerialItem, &subjectItem, &validityItem,
dab6d7
+        &subjectKeyItem);
dab6d7
+    if (rv != SECSuccess) {
dab6d7
+	return CKYINVALIDDATA;
dab6d7
+    }
dab6d7
+    setAttribute(CKA_SERIAL_NUMBER, derSerialItem.data, derSerialItem.len);
dab6d7
+    setAttribute(CKA_SUBJECT, subjectItem.data, subjectItem.len);
dab6d7
+    setAttribute(CKA_ISSUER, issuerItem.data, issuerItem.len);
dab6d7
+    CKYBuffer_Replace(&pubKey, 0, subjectKeyItem.data, subjectKeyItem.len);
dab6d7
+    /* if we didn't get a label, set one based on the CN */
dab6d7
+    certLabel = getLabel();
dab6d7
+    if ((certLabel == NULL) || (*certLabel == 0)) {
dab6d7
+	CKYBuffer subject;
dab6d7
+	char *newLabel;
dab6d7
+	CKYBuffer_InitFromData(&subject, subjectItem.data, subjectItem.len);
dab6d7
+	newLabel = GetUserName(&subject);
dab6d7
+	if (newLabel) {
dab6d7
+	    setAttribute(CKA_LABEL, (CKYByte *)newLabel, 
dab6d7
+					(CKYSize) strlen(newLabel)-1);
dab6d7
+	    delete [] newLabel;
dab6d7
+	}
dab6d7
+	CKYBuffer_FreeData(&subject);
dab6d7
+    }
dab6d7
+    state = PK15StateComplete;
dab6d7
+    return CKYSUCCESS;
dab6d7
+}
dab6d7
+
dab6d7
+CKYStatus 
dab6d7
+PK15Object::completeRawPublicKey(const CKYByte *current, CKYSize size)
dab6d7
+{
dab6d7
+    const CKYByte *entry;
dab6d7
+    CKYSize entrySize;
dab6d7
+    CKYSize tagSize;
dab6d7
+
dab6d7
+    if ((current == NULL) || (current[0] != ASN1_SEQUENCE)) {
dab6d7
+	return CKYINVALIDDATA;
dab6d7
+    }
dab6d7
+    /* unwrap*/
dab6d7
+    current = dataStart(current, size, &size, false);
dab6d7
+    if (current == NULL) { return CKYINVALIDDATA; }
dab6d7
+
dab6d7
+    /* modulus */
dab6d7
+    if (current[0] != ASN1_INTEGER) { return CKYINVALIDDATA; }
dab6d7
+    entry = dataStart(current, size, &entrySize, false);
dab6d7
+    if (entry == NULL) { return CKYINVALIDDATA; }
dab6d7
+    tagSize = entry - current;
dab6d7
+    current += entrySize + tagSize;
dab6d7
+    size -= (entrySize +tagSize);
dab6d7
+    if (size < 0) { return CKYINVALIDDATA; }
dab6d7
+    if ((entry[0] == 0) && (entrySize > 1)) {
dab6d7
+	entry++; entrySize--;
dab6d7
+    }
dab6d7
+    setAttribute(CKA_MODULUS, entry, entrySize);
dab6d7
+
dab6d7
+    /* exponent */
dab6d7
+    if (current[0] != ASN1_INTEGER) { return CKYINVALIDDATA; }
dab6d7
+    entry = dataStart(current, size, &entrySize, false);
dab6d7
+    if (entry == NULL) { return CKYINVALIDDATA; }
dab6d7
+    tagSize = entry - current;
dab6d7
+    current += entrySize + tagSize;
dab6d7
+    size -= (entrySize +tagSize);
dab6d7
+    if (size < 0) { return CKYINVALIDDATA; }
dab6d7
+    if ((entry[0] == 0) && (entrySize > 1)) {
dab6d7
+	entry++; entrySize--;
dab6d7
+    }
dab6d7
+    setAttribute(CKA_PUBLIC_EXPONENT, entry, entrySize);
dab6d7
+    state = PK15StateComplete;
dab6d7
+    return CKYSUCCESS;
dab6d7
+}
dab6d7
+
dab6d7
 DEREncodedSignature::DEREncodedSignature(const CKYBuffer *derSig)
dab6d7
 {
dab6d7
 
dab6d7
@@ -1483,9 +2585,9 @@ int DEREncodedSignature::getRawSignature
dab6d7
 
dab6d7
     CKYBuffer_Zero(rawSig);
dab6d7
 
dab6d7
-    unsigned int seq_length = 0;
dab6d7
-    unsigned int expected_sig_len = ( (keySize + 7) / 8 ) * 2 ;
dab6d7
-    unsigned int expected_piece_size = expected_sig_len / 2 ;
dab6d7
+    CKYSize seq_length = 0;
dab6d7
+    CKYSize expected_sig_len = ( (keySize + 7) / 8 ) * 2 ;
dab6d7
+    CKYSize expected_piece_size = expected_sig_len / 2 ;
dab6d7
 
dab6d7
     /* unwrap the sequence */
dab6d7
     buf = dataStart(CKYBuffer_Data(&derEncodedSignature), CKYBuffer_Size(&derEncodedSignature),&seq_length, false);
dab6d7
@@ -1494,7 +2596,7 @@ int DEREncodedSignature::getRawSignature
dab6d7
 
dab6d7
     // unwrap first multi byte integer
dab6d7
    
dab6d7
-    unsigned int int_length = 0;
dab6d7
+    CKYSize int_length = 0;
dab6d7
     const CKYByte *int1Buf = NULL;
dab6d7
     const CKYByte *int2Buf = NULL;
dab6d7
 
dab6d7
@@ -1525,7 +2627,7 @@ int DEREncodedSignature::getRawSignature
dab6d7
 
dab6d7
     // unwrap second multi byte integer
dab6d7
 
dab6d7
-    unsigned int second_int_length = 0;
dab6d7
+    CKYSize second_int_length = 0;
dab6d7
 
dab6d7
     int2Buf = dataStart(buf, seq_length, &second_int_length, false);
dab6d7
 
dab6d7
@@ -1552,3 +2654,91 @@ int DEREncodedSignature::getRawSignature
dab6d7
 
dab6d7
     return CKYSUCCESS;
dab6d7
 }
dab6d7
+
dab6d7
+DEREncodedTokenInfo::DEREncodedTokenInfo(CKYBuffer *derTokenInfo)
dab6d7
+{
dab6d7
+    const CKYByte *current = CKYBuffer_Data(derTokenInfo);
dab6d7
+    const CKYByte *entry;
dab6d7
+    CKYSize size = CKYBuffer_Size(derTokenInfo);
dab6d7
+    CKYSize entrySize;
dab6d7
+    CKYSize tagSize;
dab6d7
+    /* set token name, etc */
dab6d7
+
dab6d7
+    version = -1;
dab6d7
+    CKYBuffer_InitEmpty(&serialNumber);
dab6d7
+    manufacturer = NULL;
dab6d7
+    tokenName = NULL;
dab6d7
+
dab6d7
+    if (current[0] != ASN1_SEQUENCE) {
dab6d7
+	return; /* just use the defaults */
dab6d7
+    }
dab6d7
+    /* unwrap */
dab6d7
+    current = dataStart(current, size, &size, false);
dab6d7
+    if (current == NULL) return;
dab6d7
+
dab6d7
+    /* parse the version */
dab6d7
+    if (current[0] != ASN1_INTEGER) { return; }
dab6d7
+    entry = dataStart(current, size, &entrySize, false);
dab6d7
+    if (entry == NULL) return;
dab6d7
+    tagSize = entry - current;
dab6d7
+    current += tagSize + entrySize;
dab6d7
+    size -= tagSize + entrySize;
dab6d7
+    if (entrySize < 1) {
dab6d7
+	version = *entry;
dab6d7
+    }
dab6d7
+    if (size < 0) return;
dab6d7
+
dab6d7
+    /* get the serial number */
dab6d7
+    if (current[0] != ASN1_OCTET_STRING) { return ; }
dab6d7
+    entry = dataStart(current, size, &entrySize, false);
dab6d7
+    if (entry == NULL) return;
dab6d7
+    tagSize = entry - current;
dab6d7
+    current += tagSize + entrySize;
dab6d7
+    size -= tagSize + entrySize;
dab6d7
+    CKYBuffer_Replace(&serialNumber, 0, entry, entrySize);
dab6d7
+    /* should we fake the cuid here? */
dab6d7
+
dab6d7
+    /* get the optional manufacture ID */
dab6d7
+    if (current[0] == ASN1_UTF8_STRING) {
dab6d7
+	entry = dataStart(current, size, &entrySize, false);
dab6d7
+	if (entry == NULL) return;
dab6d7
+	tagSize = entry - current;
dab6d7
+	current += tagSize + entrySize;
dab6d7
+	size -= tagSize + entrySize;
dab6d7
+	manufacturer = (char *)malloc(entrySize+1);
dab6d7
+	if (manufacturer) {
dab6d7
+	    memcpy(manufacturer, entry, entrySize);
dab6d7
+	    manufacturer[entrySize] = 0;
dab6d7
+	}
dab6d7
+    }
dab6d7
+
dab6d7
+    /* get the optional token name */
dab6d7
+    /* most choices are constructed, 
dab6d7
+     * but this one isn't explicity add the flag */
dab6d7
+    if ((current[0]|ASN1_CONSTRUCTED) == ASN1_CHOICE_0) {
dab6d7
+	entry = dataStart(current, size, &entrySize, false);
dab6d7
+	if (entry == NULL) return;
dab6d7
+	tagSize = entry - current;
dab6d7
+	current += tagSize + entrySize;
dab6d7
+	size -= tagSize + entrySize;
dab6d7
+	tokenName = (char *)malloc(entrySize+1);
dab6d7
+	if (tokenName) {
dab6d7
+	    memcpy(tokenName, entry, entrySize);
dab6d7
+	    tokenName[entrySize] = 0;
dab6d7
+	}
dab6d7
+    }
dab6d7
+
dab6d7
+    /* parsing flags */
dab6d7
+    if (current[0] == ASN1_BIT_STRING) {
dab6d7
+    /* recordinfo parsing would go here */
dab6d7
+	unsigned long bits;
dab6d7
+	entry = dataStart(current, size, &entrySize, false);
dab6d7
+	if (entry == NULL) return;
dab6d7
+	tagSize = entry - current;
dab6d7
+	current += tagSize + entrySize;
dab6d7
+	size -= tagSize + entrySize;
dab6d7
+	bits = GetBits(entry, entrySize,8,2);
dab6d7
+    }
dab6d7
+    return;
dab6d7
+}
dab6d7
+
dab6d7
diff -up ./src/coolkey/object.h.p15 ./src/coolkey/object.h
dab6d7
--- ./src/coolkey/object.h.p15	2015-07-06 10:27:55.770827267 -0700
dab6d7
+++ ./src/coolkey/object.h	2015-07-06 10:27:55.785826984 -0700
dab6d7
@@ -27,6 +27,33 @@
dab6d7
 
dab6d7
 using std::list;
dab6d7
 
dab6d7
+/*
dab6d7
+ * Sigh PKCS 15 is heavily ASN.1...
dab6d7
+ */
dab6d7
+const CKYByte  ASN1_BOOLEAN           = 0x01;
dab6d7
+const CKYByte  ASN1_INTEGER           = 0x02;
dab6d7
+const CKYByte  ASN1_BIT_STRING        = 0x03;
dab6d7
+const CKYByte  ASN1_OCTET_STRING      = 0x04;
dab6d7
+const CKYByte  ASN1_ENUMERATED        = 0x0a;
dab6d7
+const CKYByte  ASN1_UTF8_STRING       = 0x0c;
dab6d7
+const CKYByte  ASN1_GENERALIZED_TIME  = 0x18;
dab6d7
+const CKYByte  ASN1_CONSTRUCTED       = 0x20;
dab6d7
+const CKYByte  ASN1_SEQUENCE          = 0x30;
dab6d7
+const CKYByte  ASN1_CHOICE_0          = 0xa0;
dab6d7
+const CKYByte  ASN1_CHOICE_1          = 0xa1;
dab6d7
+const CKYByte  ASN1_CHOICE_2          = 0xa2;
dab6d7
+const CKYByte  ASN1_CHOICE_3          = 0xa3;
dab6d7
+
dab6d7
+const CKYBitFlags BROKEN_FLAG = 0x80000000;
dab6d7
+const unsigned int PK11_INVALID_KEY_REF = -1;
dab6d7
+
dab6d7
+const CKYByte PK15X509CertType = ASN1_SEQUENCE;
dab6d7
+const CKYByte PK15RSAKeyType   = ASN1_SEQUENCE;
dab6d7
+const CKYByte PK15ECCKeyType   = ASN1_CHOICE_0;
dab6d7
+const CKYByte PK15DHKeyType    = ASN1_CHOICE_1;
dab6d7
+const CKYByte PK15DSAKeyType   = ASN1_CHOICE_2;
dab6d7
+const CKYByte PK15KEAKeyType   = ASN1_CHOICE_3;
dab6d7
+
dab6d7
 class PKCS11Attribute {
dab6d7
   private:
dab6d7
     CK_ATTRIBUTE_TYPE type;
dab6d7
@@ -52,9 +79,30 @@ class PKCS11Attribute {
dab6d7
     PKCS11Attribute() : type(0){ CKYBuffer_InitEmpty(&value); }
dab6d7
     PKCS11Attribute(CK_ATTRIBUTE_TYPE type_, const CKYBuffer *value_)
dab6d7
         : type(type_) { CKYBuffer_InitFromCopy(&value, value_); }
dab6d7
+    PKCS11Attribute(CK_ATTRIBUTE_TYPE type_, const CKYByte *data_,
dab6d7
+	 CKYSize size_) : type(type_) 
dab6d7
+		{ CKYBuffer_InitFromData(&value, data_, size_); }
dab6d7
     ~PKCS11Attribute() { CKYBuffer_FreeData(&value); }
dab6d7
 };
dab6d7
 
dab6d7
+class PK15ObjectPath {
dab6d7
+  private:
dab6d7
+    CKYBuffer path;
dab6d7
+    CKYOffset index;
dab6d7
+    CKYSize   length;
dab6d7
+   public:
dab6d7
+    PK15ObjectPath() : index(0), length(0) { CKYBuffer_InitEmpty(&path); }
dab6d7
+    PK15ObjectPath(const PK15ObjectPath &cpy) : 
dab6d7
+		index(cpy.index), length(cpy.length) 
dab6d7
+		{ CKYBuffer_InitFromCopy(&path, &cpy.path); }
dab6d7
+    ~PK15ObjectPath() { CKYBuffer_FreeData(&path); }
dab6d7
+    const CKYBuffer *getPath() const { return &pat;; }
dab6d7
+    CKYOffset getIndex() const { return index; }
dab6d7
+    CKYSize getLength() const { return length; }
dab6d7
+    CKYStatus setObjectPath(const CKYByte *entry, CKYSize size);
dab6d7
+};
dab6d7
+
dab6d7
+
dab6d7
 class PKCS11Object {
dab6d7
   public:
dab6d7
     enum KeyType {
dab6d7
@@ -72,6 +120,8 @@ class PKCS11Object {
dab6d7
     unsigned long muscleObjID;
dab6d7
     CK_OBJECT_HANDLE handle;
dab6d7
     char *label;
dab6d7
+    unsigned int keySize;
dab6d7
+    CK_USER_TYPE user;
dab6d7
 
dab6d7
     void parseOldObject(const CKYBuffer *data);
dab6d7
     void parseNewObject(const CKYBuffer *data);
dab6d7
@@ -82,19 +132,37 @@ class PKCS11Object {
dab6d7
   protected :
dab6d7
     char *name;
dab6d7
     KeyType keyType;
dab6d7
+    unsigned int keyRef;
dab6d7
     CKYBuffer pubKey;
dab6d7
+    CKYBuffer authId;
dab6d7
+    CKYBuffer pinAuthId;
dab6d7
+    PK15ObjectPath objectPath;
dab6d7
 
dab6d7
   public:
dab6d7
     PKCS11Object(unsigned long muscleObjID, CK_OBJECT_HANDLE handle);
dab6d7
     PKCS11Object(unsigned long muscleObjID, const CKYBuffer *data,
dab6d7
         CK_OBJECT_HANDLE handle);
dab6d7
-    ~PKCS11Object() { delete label; delete name; CKYBuffer_FreeData(&pubKey);
dab6d7
-			attributes.clear(); }
dab6d7
+    virtual ~PKCS11Object() { delete [] label; delete [] name; 
dab6d7
+		CKYBuffer_FreeData(&pubKey); CKYBuffer_FreeData(&authId);
dab6d7
+		CKYBuffer_FreeData(&pinAuthId); attributes.clear(); }
dab6d7
 
dab6d7
     PKCS11Object(const PKCS11Object& cpy) :
dab6d7
         attributes(cpy.attributes), muscleObjID(cpy.muscleObjID),
dab6d7
-        handle(cpy.handle), label(NULL),  name(NULL), keyType(cpy.keyType) { 
dab6d7
-			CKYBuffer_InitFromCopy(&pubKey,&cpy.pubKey); }
dab6d7
+        handle(cpy.handle), label(NULL),  keySize(cpy.keySize), 
dab6d7
+	user(cpy.user), name(NULL), keyType(cpy.keyType), keyRef(cpy.keyRef),
dab6d7
+	objectPath(cpy.objectPath) { 
dab6d7
+			/* label is just a cached value, don't need 
dab6d7
+  			 * to copy it. */
dab6d7
+			if (cpy.name != NULL) {
dab6d7
+			    int len = strlen(cpy.name);
dab6d7
+			    name= new char [len+1];
dab6d7
+			    if (name) {
dab6d7
+				memcpy(name,cpy.name,len+1);
dab6d7
+			    }
dab6d7
+			}
dab6d7
+			CKYBuffer_InitFromCopy(&pubKey,&cpy.pubKey);
dab6d7
+			CKYBuffer_InitFromCopy(&authId,&cpy.authId);
dab6d7
+			CKYBuffer_InitFromCopy(&pinAuthId,&cpy.pinAuthId); }
dab6d7
 
dab6d7
 
dab6d7
     unsigned long getMuscleObjID() const { return muscleObjID; }
dab6d7
@@ -107,6 +175,8 @@ class PKCS11Object {
dab6d7
 
dab6d7
     void setAttribute(CK_ATTRIBUTE_TYPE type, const CKYBuffer *value);
dab6d7
     void setAttribute(CK_ATTRIBUTE_TYPE type, const char *);
dab6d7
+    void setAttribute(CK_ATTRIBUTE_TYPE type, const CKYByte *data, 
dab6d7
+							CKYSize size);
dab6d7
     /* bools and ulongs are too close, don't abuse function overloading
dab6d7
      * for these cases */
dab6d7
     void setAttributeBool(CK_ATTRIBUTE_TYPE type, CK_BBOOL);
dab6d7
@@ -124,14 +194,21 @@ class PKCS11Object {
dab6d7
 	return &pubKey;
dab6d7
     }
dab6d7
 
dab6d7
-    KeyType getKeyType() const { return keyType;}
dab6d7
+    KeyType getKeyType(void) const { return keyType;}
dab6d7
+    unsigned int getKeySize(void) const { return keySize; }
dab6d7
+    unsigned int getKeyRef(void) const { return keyRef; }
dab6d7
+    CK_USER_TYPE getUser(void) const { return user; }
dab6d7
     void setKeyType(KeyType theType) { keyType = theType; }
dab6d7
+    void setKeySize(unsigned int keySize_) { keySize = keySize_; }
dab6d7
+    const CKYBuffer *getAuthId(void) const { return &authId; }
dab6d7
+    const CKYBuffer *getPinAuthId(void) const { return &pinAuthId; }
dab6d7
+    const PK15ObjectPath &getObjectPath() const { return objectPath; }
dab6d7
+    void completeKey(const PKCS11Object &cert);
dab6d7
 };
dab6d7
 
dab6d7
 class Key : public PKCS11Object {
dab6d7
   public:
dab6d7
     Key(unsigned long muscleObjID, const CKYBuffer *data, CK_OBJECT_HANDLE handle);
dab6d7
-    void completeKey(const PKCS11Object &cert);
dab6d7
 };
dab6d7
 
dab6d7
 class Cert : public PKCS11Object {
dab6d7
@@ -155,6 +232,84 @@ class CACCert : public PKCS11Object {
dab6d7
     CACCert(CKYByte instance, const CKYBuffer *derCert);
dab6d7
 };
dab6d7
 
dab6d7
+typedef enum { PK15StateInit, PK15StateNeedObject, 
dab6d7
+	PK15StateNeedRawPublicKey,PK15StateNeedRawCertificate, 
dab6d7
+	PK15StateComplete } PK15State;
dab6d7
+
dab6d7
+typedef enum {PK15PvKey, PK15PuKey, PK15Cert, PK15AuthObj} PK15ObjectType;
dab6d7
+const unsigned int PK15_INVALID_KEY_REF = -1;
dab6d7
+
dab6d7
+class PK15Object : public PKCS11Object {
dab6d7
+  private:
dab6d7
+    CKYByte	instance;
dab6d7
+    PK15ObjectType p15Type;
dab6d7
+    PK15State state;
dab6d7
+    P15PinInfo pinInfo;
dab6d7
+
dab6d7
+    CKYStatus completeCertObject(const CKYByte *buf, CKYSize size);
dab6d7
+    CKYStatus completeAuthObject(const CKYByte *buf, CKYSize size);
dab6d7
+    CKYStatus completeKeyObject(const CKYByte *buf, CKYSize size);
dab6d7
+    CKYStatus completePrivKeyObject(const CKYByte *buf, CKYSize size);
dab6d7
+    CKYStatus completePubKeyObject(const CKYByte *buf, CKYSize size);
dab6d7
+    CKYStatus completeRawPublicKey(const CKYByte *buf, CKYSize size);
dab6d7
+    CKYStatus completeRawCertificate(const CKYByte *buf, CKYSize size);
dab6d7
+   
dab6d7
+    CKYBitFlags defaultCommonBits() {
dab6d7
+	return ((p15Type == PK15PvKey) && (CKYBuffer_Size(&authId) != 0)) ?
dab6d7
+		P15FlagsPrivate : 0;
dab6d7
+    }
dab6d7
+    CKYBitFlags defaultUsageBits() {
dab6d7
+	CKYBitFlags sign, recover, encrypt;
dab6d7
+	switch (p15Type) {
dab6d7
+	case PK15PuKey:
dab6d7
+	    sign = P15UsageVerify; recover = P15UsageVerifyRecover;
dab6d7
+	    encrypt = P15UsageEncrypt;
dab6d7
+	    break;
dab6d7
+	case PK15PvKey:
dab6d7
+	    sign = P15UsageSign; recover = P15UsageSignRecover;
dab6d7
+	    encrypt = P15UsageDecrypt;
dab6d7
+	    break;
dab6d7
+	default:
dab6d7
+	    sign = 0; recover = 0; encrypt = 0;
dab6d7
+	    break;
dab6d7
+	}
dab6d7
+	switch(keyType) {
dab6d7
+	case rsa:
dab6d7
+	    return sign | recover | encrypt;
dab6d7
+	case ecc:
dab6d7
+	    return sign | P15UsageDerive;
dab6d7
+	default:
dab6d7
+	    break;
dab6d7
+	}
dab6d7
+	return 0;
dab6d7
+    }
dab6d7
+    CKYBitFlags defaultAccessBits() {
dab6d7
+	switch (p15Type) {
dab6d7
+	case PK15PuKey:
dab6d7
+		return P15AccessExtractable | P15AccessLocal;
dab6d7
+	case PK15PvKey:
dab6d7
+		return P15AccessSensitive | P15AccessLocal;
dab6d7
+	default:
dab6d7
+		break;
dab6d7
+	}
dab6d7
+	return 0;
dab6d7
+    }
dab6d7
+    CKYBitFlags defaultPinBits() {
dab6d7
+	return ((p15Type == PK15AuthObj) ?  P15PinInitialized : 0);
dab6d7
+    }
dab6d7
+		
dab6d7
+  public:
dab6d7
+    PK15Object(CKYByte inst, PK15ObjectType type, 
dab6d7
+					const CKYByte *derObject, CKYSize size);
dab6d7
+    CKYStatus completeObject(const CKYByte *data, CKYSize size);
dab6d7
+    PK15State getState(void) const { return state; }
dab6d7
+    bool isSO(void) const { return 
dab6d7
+		(pinInfo.pinFlags & P15PinSOPin) ? true : false; }
dab6d7
+    bool isLocal(void) const { return 
dab6d7
+			(pinInfo.pinFlags & P15PinLocal) ? true : false; }
dab6d7
+    const P15PinInfo *getPinInfo(void) const { return &pinInfo; }
dab6d7
+};
dab6d7
+
dab6d7
 class Reader : public PKCS11Object {
dab6d7
   public:
dab6d7
     Reader(unsigned long muscleObjID, CK_OBJECT_HANDLE handle, 
dab6d7
@@ -180,6 +335,21 @@ class DEREncodedSignature  {
dab6d7
 
dab6d7
 };
dab6d7
 
dab6d7
+class DEREncodedTokenInfo {
dab6d7
+public:
dab6d7
+   int   version;
dab6d7
+   CKYBuffer serialNumber;
dab6d7
+   char *manufacturer;
dab6d7
+   char *tokenName;
dab6d7
+   public :
dab6d7
+   DEREncodedTokenInfo(CKYBuffer *derTokenInfo);
dab6d7
+   ~DEREncodedTokenInfo() { 
dab6d7
+	CKYBuffer_FreeData(&serialNumber);
dab6d7
+	free(manufacturer);
dab6d7
+	free(tokenName);
dab6d7
+    }
dab6d7
+};
dab6d7
+
dab6d7
 class AttributeMatch {
dab6d7
 
dab6d7
   private:
dab6d7
@@ -202,6 +372,9 @@ makeLEUInt(const CKYBuffer *buf, unsigne
dab6d7
             (b[offset+0] <<  0) ;
dab6d7
 }
dab6d7
 
dab6d7
+const CKYByte* dataStart(const CKYByte *buf, CKYSize length,
dab6d7
+                        CKYSize *data_length, bool includeTag);
dab6d7
+
dab6d7
 // fixed object ID constants 
dab6d7
 #define READER_ID 0x72300000 /* 'r0\0\0' */
dab6d7
 #define COMBINED_ID 0x7a300000 /* 'z0\0\0' */
dab6d7
diff -up ./src/coolkey/pkcs11t.h.p15 ./src/coolkey/pkcs11t.h
dab6d7
--- ./src/coolkey/pkcs11t.h.p15	2015-07-06 10:27:55.770827267 -0700
dab6d7
+++ ./src/coolkey/pkcs11t.h	2015-07-06 10:29:32.293005407 -0700
dab6d7
@@ -274,6 +274,7 @@ typedef CK_ULONG          CK_USER_TYPE;
dab6d7
 #define CKU_SO    0
dab6d7
 /* Normal user */
dab6d7
 #define CKU_USER  1
dab6d7
+#define CKU_CONTEXT_SPECIFIC 2
dab6d7
 
dab6d7
 
dab6d7
 /* CK_STATE enumerates the session states */
dab6d7
@@ -492,6 +493,9 @@ typedef CK_ULONG          CK_ATTRIBUTE_T
dab6d7
 #define CKA_RESET_ON_INIT      0x00000301
dab6d7
 #define CKA_HAS_RESET          0x00000302
dab6d7
 
dab6d7
+/* new for v2.20 */
dab6d7
+#define CKA_ALWAYS_AUTHENTICATE  0x00000202
dab6d7
+
dab6d7
 #define CKA_VENDOR_DEFINED     0x80000000
dab6d7
 
dab6d7
 
dab6d7
diff -up ./src/coolkey/slot.cpp.p15 ./src/coolkey/slot.cpp
dab6d7
--- ./src/coolkey/slot.cpp.p15	2015-07-06 10:27:55.782827040 -0700
dab6d7
+++ ./src/coolkey/slot.cpp	2015-07-06 10:27:55.786826965 -0700
dab6d7
@@ -54,6 +54,11 @@ const CKYByte ATR2[] =
dab6d7
 {  0x3B, 0x6F, 0x00, 0xFF, 0x52, 0x53, 0x41, 0x53, 0x65, 0x63, 0x75, 0x72,
dab6d7
    0x49, 0x44, 0x28, 0x52, 0x29, 0x31, 0x30 };
dab6d7
 
dab6d7
+/* PKCS #15 AID */
dab6d7
+const CKYByte P15AID[] =
dab6d7
+{ 0xa0, 0, 0,  0, 0x63, 'P', 'K', 'C', 'S', '-', '1', '5'};
dab6d7
+
dab6d7
+
dab6d7
 
dab6d7
 /* ECC curve information
dab6d7
  *    Provide information for the limited set of curves supported by our smart card(s).
dab6d7
@@ -405,19 +410,29 @@ SlotList::updateReaderList()
dab6d7
 
dab6d7
 Slot::Slot(const char *readerName_, Log *log_, CKYCardContext* context_)
dab6d7
     : log(log_), readerName(NULL), personName(NULL), manufacturer(NULL),
dab6d7
+	tokenManufacturer(NULL),
dab6d7
 	slotInfoFound(false), context(context_), conn(NULL), state(UNKNOWN), 
dab6d7
 	isVersion1Key(false), needLogin(false), fullTokenName(false), 
dab6d7
-	mCoolkey(false), mOldCAC(false),mCACLocalLogin(false),
dab6d7
-	pivContainer(-1), pivKey(-1), mECC(false), 
dab6d7
+	mCoolkey(false), mOldCAC(false), mCACLocalLogin(false),
dab6d7
+	pivContainer(-1), pivKey(-1), mECC(false), p15aid(0), p15odfAddr(0),
dab6d7
+	p15tokenInfoAddr(0), p15Instance(0),
dab6d7
 #ifdef USE_SHMEM
dab6d7
 	shmem(readerName_),
dab6d7
 #endif
dab6d7
 	sessionHandleCounter(1), objectHandleCounter(1)
dab6d7
 {
dab6d7
+  int i; 
dab6d7
+
dab6d7
+  for (i=0; i < MAX_AUTH_USERS; i++) {
dab6d7
+    auth[i]=NULL;
dab6d7
+  }
dab6d7
 
dab6d7
   tokenFWVersion.major = 0;
dab6d7
   tokenFWVersion.minor = 0;
dab6d7
-
dab6d7
+  CKYBuffer_InitFromData(&p15AID, P15AID, sizeof(P15AID));
dab6d7
+  CKYBuffer_InitEmpty(&p15tokenInfo);
dab6d7
+  CKYBuffer_InitEmpty(&p15odf);
dab6d7
+  CKYBuffer_InitEmpty(&p15serialNumber);
dab6d7
 
dab6d7
   try {
dab6d7
     conn = CKYCardConnection_Create(context);
dab6d7
@@ -433,6 +448,8 @@ Slot::Slot(const char *readerName_, Log
dab6d7
     loggedIn = false;
dab6d7
     pinCache.invalidate();
dab6d7
     pinCache.clearPin();
dab6d7
+    contextPinCache.invalidate();
dab6d7
+    contextPinCache.clearPin();
dab6d7
     //readSlotInfo();
dab6d7
     manufacturer = strdup("Unknown");
dab6d7
     if (!manufacturer) {
dab6d7
@@ -515,12 +532,23 @@ Slot::~Slot()
dab6d7
     if (manufacturer) {
dab6d7
 	free(manufacturer);
dab6d7
     }
dab6d7
+    if (tokenManufacturer) {
dab6d7
+	free(tokenManufacturer);
dab6d7
+    }
dab6d7
     CKYBuffer_FreeData(&nonce);
dab6d7
     CKYBuffer_FreeData(&cardATR);
dab6d7
     CKYBuffer_FreeData(&mCUID);
dab6d7
+    CKYBuffer_FreeData(&p15AID);
dab6d7
+    CKYBuffer_FreeData(&p15odf);
dab6d7
+    CKYBuffer_FreeData(&p15tokenInfo);
dab6d7
+    CKYBuffer_FreeData(&p15serialNumber);
dab6d7
     for (int i=0; i < MAX_CERT_SLOTS; i++) {
dab6d7
 	CKYBuffer_FreeData(&cardAID[i]);
dab6d7
     }
dab6d7
+    for (int i=0; i < MAX_AUTH_USERS; i++) {
dab6d7
+	if (auth[i]) delete auth[i];
dab6d7
+	auth[i]=NULL;
dab6d7
+    }
dab6d7
 }
dab6d7
 
dab6d7
 template <class C>
dab6d7
@@ -637,9 +665,10 @@ Slot::getPIVLoginType(void)
dab6d7
     }
dab6d7
 done:
dab6d7
     CKYBuffer_FreeData(&buffer);
dab6d7
-    return true;
dab6d7
+    return local;
dab6d7
 }
dab6d7
 
dab6d7
+
dab6d7
 void
dab6d7
 Slot::connectToToken()
dab6d7
 {
dab6d7
@@ -745,7 +774,7 @@ Slot::connectToToken()
dab6d7
 	 /* CARD is a PIV card */
dab6d7
 	 state |= PIV_CARD | APPLET_SELECTABLE | APPLET_PERSONALIZED;
dab6d7
 	 isVersion1Key = 0;
dab6d7
-	 needLogin = 1;
dab6d7
+	 needLogin = true;
dab6d7
          mCoolkey = 0;
dab6d7
 	 mOldCAC = 0;
dab6d7
 	 mCACLocalLogin = getPIVLoginType();
dab6d7
@@ -757,12 +786,22 @@ Slot::connectToToken()
dab6d7
 	status = getCACAid();
dab6d7
 	if (status != CKYSUCCESS) {
dab6d7
 	    log->log("CAC Select failed 0x%x\n", status);
dab6d7
-	    if (status == CKYSCARDERR) {
dab6d7
+	    status = getP15Params();
dab6d7
+	    if (status != CKYSUCCESS) {
dab6d7
+	    	if (status == CKYSCARDERR) {
dab6d7
 		    log->log("Card Failure 0x%x\n",
dab6d7
 				CKYCardConnection_GetLastError(conn));
dab6d7
 		    disconnect();
dab6d7
-	    }
dab6d7
-	    /* CARD is unknown */
dab6d7
+	    	}
dab6d7
+	        /* CARD is unknown */
dab6d7
+	        return;
dab6d7
+	    } 
dab6d7
+	    /* enable PCKS 15 */
dab6d7
+	    state |= P15_CARD | APPLET_SELECTABLE | APPLET_PERSONALIZED;
dab6d7
+	    isVersion1Key = 0;
dab6d7
+	    needLogin = false; /* get it from token info */
dab6d7
+            mCoolkey = 0;
dab6d7
+	    mCACLocalLogin = false;
dab6d7
 	    return;
dab6d7
 	}
dab6d7
 	state |= CAC_CARD | APPLET_SELECTABLE | APPLET_PERSONALIZED;
dab6d7
@@ -771,7 +810,7 @@ Slot::connectToToken()
dab6d7
          * other apps may be running now, so resetting the cac is a bit
dab6d7
          * unfriendly */
dab6d7
 	isVersion1Key = 0;
dab6d7
-	needLogin = 1;
dab6d7
+	needLogin = true;
dab6d7
         mCoolkey = 0;
dab6d7
 	mCACLocalLogin = false;
dab6d7
 	return;
dab6d7
@@ -841,6 +880,8 @@ Slot::invalidateLogin(bool hard)
dab6d7
     } else {
dab6d7
 	loggedIn = false;
dab6d7
 	pinCache.invalidate();
dab6d7
+	contextPinCache.invalidate();
dab6d7
+	contextPinCache.clearPin();
dab6d7
 	if (hard) {
dab6d7
 	    pinCache.clearPin();
dab6d7
 	}
dab6d7
@@ -951,6 +992,414 @@ done:
dab6d7
     return status;
dab6d7
 }
dab6d7
 
dab6d7
+CKYStatus Slot::getP15Params()
dab6d7
+{
dab6d7
+    CKYStatus status = CKYSCARDERR;
dab6d7
+    int i;
dab6d7
+    CKYISOStatus apduRC;
dab6d7
+
dab6d7
+    /* read the EF(DIR) */  
dab6d7
+    status = CACApplet_SelectFile(conn, 0x2f00, &apduRC);
dab6d7
+    if (status == CKYSUCCESS) {
dab6d7
+	CKYBuffer record;
dab6d7
+
dab6d7
+	CKYBuffer_InitEmpty(&record);
dab6d7
+	/* dump it out */
dab6d7
+        for (i=1; i < 255; i++) {
dab6d7
+	    status = P15Applet_ReadRecord(conn, i, 0, P15_READ_P1, 255,
dab6d7
+			&record, &apduRC);
dab6d7
+	    if (status != CKYSUCCESS) {
dab6d7
+		log->log("EF(DIR) Read Record %d failed 0x%x apduRC=0x%x\n",
dab6d7
+							 i, status, apduRC);
dab6d7
+		break;
dab6d7
+	    }
dab6d7
+	}
dab6d7
+	CKYBuffer_FreeData(&record);
dab6d7
+	return CKYSCARDERR; /* don't yet support EF(DIR)*/
dab6d7
+
dab6d7
+    } else {
dab6d7
+	log->log("EF(DIR) Select failed 0x%x apduRC=0x%0x\n", status, apduRC);
dab6d7
+	p15aid = 0; /* use the default */
dab6d7
+	p15odfAddr=0x5031;
dab6d7
+	p15tokenInfoAddr=0x5032;
dab6d7
+    }
dab6d7
+   
dab6d7
+    status = CKYApplet_SelectFile(conn, &p15AID, &apduRC);
dab6d7
+    if (status != CKYSUCCESS) {
dab6d7
+	log->log("DF(PKCS-15) select failed 0x%x apduRC=0x%0x\n", status,
dab6d7
+				apduRC);
dab6d7
+	return status;
dab6d7
+    }
dab6d7
+    status = P15Applet_SelectFile(conn, p15tokenInfoAddr, &apduRC);
dab6d7
+    if (status != CKYSUCCESS) {
dab6d7
+	log->log("EF(TokenInfo) select failed 0x%x apduRC=0x%0x\n", status, 
dab6d7
+				apduRC);
dab6d7
+	return status;
dab6d7
+    }
dab6d7
+    /* dump it out */
dab6d7
+    CKYBuffer_Resize(&p15tokenInfo, 0);
dab6d7
+    status = P15Applet_ReadBinary(conn, 0, 0, 0, 0, &p15tokenInfo, &apduRC);
dab6d7
+    if (status != CKYSUCCESS) {
dab6d7
+	log->log("EF(TokenInfo) Read binary failed 0x%x apduRC=0x%x\n", status,
dab6d7
+				 apduRC);
dab6d7
+	    return status;
dab6d7
+    }
dab6d7
+    status = P15Applet_SelectFile(conn, p15odfAddr, &apduRC);
dab6d7
+    if (status != CKYSUCCESS) {
dab6d7
+	log->log("EF(ODF) select failed 0x%x apduRC=0x%0x\n", status,
dab6d7
+				apduRC);
dab6d7
+	return status;
dab6d7
+    }
dab6d7
+
dab6d7
+    CKYBuffer_Resize(&p15odf, 0);
dab6d7
+    status = P15Applet_ReadBinary(conn, 0, 0, 0, 0, &p15odf, &apduRC);
dab6d7
+    if (status != CKYSUCCESS) {
dab6d7
+	    log->log("EF(ODF) Read binary failed 0x%x apduRC=0x%x\n", status,
dab6d7
+				 apduRC);
dab6d7
+	    return status; 
dab6d7
+    }
dab6d7
+
dab6d7
+    return CKYSUCCESS;
dab6d7
+}
dab6d7
+
dab6d7
+CKYStatus
dab6d7
+Slot::readFromPath(const PK15ObjectPath &obj, CKYBuffer *file)
dab6d7
+{
dab6d7
+    CKYStatus status;
dab6d7
+    CKYISOStatus apduRC;
dab6d7
+    CKYSize bufSize;
dab6d7
+    CKYOffset index = obj.getIndex();
dab6d7
+    CKYSize length = obj.getLength();
dab6d7
+
dab6d7
+    CKYBuffer_Resize(file, 0);
dab6d7
+    status = selectPath(obj.getPath(), &apduRC);
dab6d7
+    if (status != CKYSUCCESS) {
dab6d7
+	return status;
dab6d7
+    }
dab6d7
+    status = P15Applet_ReadBinary(conn, index, 0, 0, 
dab6d7
+			(length >= 256)?0:length, file, &apduRC);
dab6d7
+    if (status != CKYSUCCESS) {
dab6d7
+	return status;
dab6d7
+    }
dab6d7
+
dab6d7
+    /* if we asked for a specific length and got it, or we asked for 
dab6d7
+     * an indeterminate length and got less than 256 bytes, then we 
dab6d7
+     * got everything. */
dab6d7
+    bufSize = CKYBuffer_Size(file);
dab6d7
+    if ((length && (bufSize >= length)) || ((length == 0) && (bufSize < 256))) {
dab6d7
+	/* we've already got it all */
dab6d7
+	return status;
dab6d7
+    }
dab6d7
+    if (bufSize < 0x82) {
dab6d7
+	/* make sure we have enough bytes to handle the worst case ANS.1
dab6d7
+         * mistake */
dab6d7
+	return CKYINVALIDDATA;
dab6d7
+    }
dab6d7
+    
dab6d7
+    if (length == 0) {
dab6d7
+	/* we don't yet know how long the length is, use the ASN.1 parser to
dab6d7
+         * find out. We lie to dataStart about actual size so that it won't
dab6d7
+         * fail since we know we don't have the whole buffer yet.*/
dab6d7
+	(void) dataStart(CKYBuffer_Data(file), 65535, &length, true);
dab6d7
+    }
dab6d7
+    if (length > 65535) {
dab6d7
+	return CKYINVALIDDATA;
dab6d7
+    }
dab6d7
+    while ((bufSize =CKYBuffer_Size(file)) < length) {
dab6d7
+	CKYSize tmpLength = length - bufSize;
dab6d7
+
dab6d7
+	if (tmpLength >= 256) tmpLength = 0;
dab6d7
+
dab6d7
+	status = P15Applet_ReadBinary(conn, (unsigned short)(index+bufSize),
dab6d7
+			 0, 0, tmpLength, file, &apduRC);
dab6d7
+	if (status != CKYSUCCESS) {
dab6d7
+	    return status;
dab6d7
+	}
dab6d7
+    }
dab6d7
+	
dab6d7
+    return CKYSUCCESS;
dab6d7
+}
dab6d7
+
dab6d7
+void
dab6d7
+Slot::parseEF_TokenInfo(void)
dab6d7
+{
dab6d7
+    DEREncodedTokenInfo derTokenInfo(&p15tokenInfo);
dab6d7
+    const CKYBuffer *serial=&derTokenInfo.serialNumber;
dab6d7
+
dab6d7
+    if (derTokenInfo.version >= 0) {
dab6d7
+	tokenFWVersion.major = derTokenInfo.version;
dab6d7
+	tokenFWVersion.minor = 0;
dab6d7
+    }
dab6d7
+
dab6d7
+    if (CKYSize(serial) != 0) {
dab6d7
+	CKYBuffer_Replace(&p15serialNumber, 0, CKYBuffer_Data(serial),
dab6d7
+						CKYBuffer_Size(serial));
dab6d7
+    }
dab6d7
+
dab6d7
+    if (derTokenInfo.manufacturer) {
dab6d7
+	if (tokenManufacturer) {
dab6d7
+	    free(tokenManufacturer);
dab6d7
+	    tokenManufacturer = NULL;
dab6d7
+	}
dab6d7
+	tokenManufacturer = derTokenInfo.manufacturer;
dab6d7
+	derTokenInfo.manufacturer = NULL; /* adopted */
dab6d7
+    }
dab6d7
+
dab6d7
+    if (derTokenInfo.tokenName) {
dab6d7
+	if (personName) {
dab6d7
+	    free(personName);
dab6d7
+	    personName = NULL;
dab6d7
+	}
dab6d7
+	personName = derTokenInfo.tokenName;
dab6d7
+	derTokenInfo.tokenName = NULL; /* adopted */
dab6d7
+	fullTokenName = true;
dab6d7
+    }
dab6d7
+    return;
dab6d7
+}
dab6d7
+
dab6d7
+void
dab6d7
+Slot::parseEF_ODF(void)
dab6d7
+{
dab6d7
+    const CKYByte *current = CKYBuffer_Data(&p15odf);
dab6d7
+    CKYSize size = CKYBuffer_Size(&p15odf);
dab6d7
+    CKYBuffer files;
dab6d7
+
dab6d7
+    CKYBuffer_InitEmpty(&files);
dab6d7
+
dab6d7
+    while (size > 0) {
dab6d7
+	const CKYByte *entry;
dab6d7
+	CKYSize entrySize;
dab6d7
+	CKYSize tagSize;
dab6d7
+	CKYByte type, type1;
dab6d7
+	PK15ObjectPath objPath;
dab6d7
+	bool skip;
dab6d7
+
dab6d7
+	type = current[0];
dab6d7
+	entry = dataStart(current, size, &entrySize, false);
dab6d7
+	if (entry == NULL) { break; }
dab6d7
+	tagSize = entry-current;
dab6d7
+	current += entrySize + tagSize;
dab6d7
+	size -= (entrySize + tagSize);
dab6d7
+
dab6d7
+	/* skip those entries we aren't going to parse */
dab6d7
+	skip = false;
dab6d7
+	switch (type) {
dab6d7
+	case 0xa2: skip=true; break; /* skip EF(PuKDF-trusted) */
dab6d7
+	case 0xa3: skip=true; break; /* skip EF(SKDF) */
dab6d7
+	case 0xa7: skip=true; break; /* skip EF(DODF) */
dab6d7
+	default: skip=true; break;
dab6d7
+	case 0xa0:        /* EF(PvKDF) */
dab6d7
+	case 0xa1:        /* EF(PuKDF) */
dab6d7
+	case 0xa4:        /* EF(CDF) */
dab6d7
+	case 0xa5:        /* EF(CDF-trusted) */
dab6d7
+	case 0xa6:        /* EF(CDF-useful) */
dab6d7
+	case 0xa8: break; /* EF(AODF) */
dab6d7
+ 	}
dab6d7
+	if (skip) continue;
dab6d7
+
dab6d7
+	type1 = entry[0];
dab6d7
+	/* unwrap */
dab6d7
+	entry = dataStart(entry, entrySize, &entrySize, false);
dab6d7
+	if (entry == NULL) continue;
dab6d7
+	if (type1 == ASN1_SEQUENCE) {
dab6d7
+	    objPath.setObjectPath(entry, entrySize);
dab6d7
+	    CKYBuffer_Resize(&files, 0);
dab6d7
+	    readFromPath(objPath, &files);
dab6d7
+	    entry = CKYBuffer_Data(&files);
dab6d7
+	    entrySize = CKYBuffer_Size(&files);
dab6d7
+	} else if (type1 != ASN1_CHOICE_0) {
dab6d7
+	    continue;
dab6d7
+	}
dab6d7
+	
dab6d7
+	switch (type) {
dab6d7
+	case 0xa0: parseEF_Directory(entry, entrySize, PK15PvKey); break;
dab6d7
+	case 0xa1: parseEF_Directory(entry, entrySize, PK15PuKey); break;
dab6d7
+	case 0xa4: parseEF_Directory(entry, entrySize, PK15Cert); break;
dab6d7
+	case 0xa5: parseEF_Directory(entry, entrySize, PK15Cert); break;
dab6d7
+	case 0xa6: parseEF_Directory(entry, entrySize, PK15Cert); break;
dab6d7
+	case 0xa8: parseEF_Directory(entry, entrySize, PK15AuthObj); break;
dab6d7
+	default: break;
dab6d7
+	}
dab6d7
+    }
dab6d7
+    CKYBuffer_FreeData(&files);
dab6d7
+    return;
dab6d7
+}
dab6d7
+
dab6d7
+
dab6d7
+class ObjectCertCKAIDMatch {
dab6d7
+  private:
dab6d7
+    const CKYBuffer *cka_id;
dab6d7
+  public:
dab6d7
+    ObjectCertCKAIDMatch(const CKYBuffer *cka_id_) : cka_id(cka_id_) {}
dab6d7
+    bool operator()(const PKCS11Object& obj) {
dab6d7
+	const CKYBuffer *id;
dab6d7
+        const CKYBuffer *objClass;
dab6d7
+	CK_OBJECT_CLASS certClass = CKO_CERTIFICATE;
dab6d7
+	objClass = obj.getAttribute(CKA_CLASS);
dab6d7
+        if (objClass == NULL || !CKYBuffer_DataIsEqual(objClass, 
dab6d7
+				(CKYByte *)&certClass, sizeof(certClass))) {
dab6d7
+	    return false;
dab6d7
+        }
dab6d7
+ 	id = obj.getAttribute(CKA_ID);
dab6d7
+        return (id != NULL && CKYBuffer_IsEqual(id,cka_id)) ? true : false;
dab6d7
+    }
dab6d7
+};
dab6d7
+
dab6d7
+class ObjectKeyCKAIDMatch {
dab6d7
+  private:
dab6d7
+    const CKYBuffer *cka_id;
dab6d7
+  public:
dab6d7
+    ObjectKeyCKAIDMatch(const CKYBuffer *cka_id_) : cka_id(cka_id_) {}
dab6d7
+    bool operator()(const PKCS11Object& obj) {
dab6d7
+	const CKYBuffer *id;
dab6d7
+        const CKYBuffer *objClass;
dab6d7
+	CK_OBJECT_CLASS keyClass = CKO_PRIVATE_KEY;
dab6d7
+	objClass = obj.getAttribute(CKA_CLASS);
dab6d7
+        if (objClass == NULL || !CKYBuffer_DataIsEqual(objClass, 
dab6d7
+				(CKYByte *)&keyClass, sizeof(keyClass))) {
dab6d7
+	    return false;
dab6d7
+        }
dab6d7
+ 	id = obj.getAttribute(CKA_ID);
dab6d7
+        return (id != NULL && CKYBuffer_IsEqual(id,cka_id)) ? true : false;
dab6d7
+    }
dab6d7
+};
dab6d7
+
dab6d7
+CKYStatus
dab6d7
+Slot::parseEF_Directory(const CKYByte *current, 
dab6d7
+					CKYSize size, PK15ObjectType type)
dab6d7
+{
dab6d7
+    CKYBuffer file;
dab6d7
+    CKYBuffer_InitEmpty(&file;;
dab6d7
+    CKYStatus status;
dab6d7
+
dab6d7
+
dab6d7
+    while (size > 0) {
dab6d7
+	const CKYByte *entry;
dab6d7
+	CKYSize entrySize;
dab6d7
+
dab6d7
+	if (current[0] != ASN1_SEQUENCE) {
dab6d7
+	    /* no more */
dab6d7
+	    break;
dab6d7
+	}
dab6d7
+
dab6d7
+	entry = dataStart(current, size, &entrySize, true);
dab6d7
+	if (entry == NULL) { break; }
dab6d7
+	current += entrySize;
dab6d7
+	size -= entrySize;
dab6d7
+
dab6d7
+	do {
dab6d7
+	    PK15Object obj(PK15Instance(), type, entry, entrySize);
dab6d7
+
dab6d7
+	    /* if state failed, then there is something wrong with this
dab6d7
+	     * der, skip this object */
dab6d7
+	    if (obj.getState() == PK15StateInit) {
dab6d7
+		break;
dab6d7
+	    }
dab6d7
+	    status = CKYSUCCESS;
dab6d7
+	    while (obj.getState() != PK15StateComplete) {
dab6d7
+	        CKYBuffer_Resize(&file, 0);
dab6d7
+	        readFromPath(obj.getObjectPath(), &file;;
dab6d7
+		status = obj.completeObject(CKYBuffer_Data(&file), 
dab6d7
+						CKYBuffer_Size(&file));
dab6d7
+		if (status != CKYSUCCESS) {
dab6d7
+		    break;
dab6d7
+		}
dab6d7
+	    }
dab6d7
+	    if (status != CKYSUCCESS) {
dab6d7
+		break;
dab6d7
+	    }
dab6d7
+	    assert(obj.getState() == PK15StateComplete);
dab6d7
+	    /* handle type specific per object fixups */
dab6d7
+	    switch (type) {
dab6d7
+	    case PK15AuthObj:
dab6d7
+	    /* if we're an auth object, squirrel us away for future use */
dab6d7
+		if (obj.isSO()) {
dab6d7
+		    if (auth[CKU_SO] != 0) {
dab6d7
+			auth[CKU_SO] = new PK15Object(obj);
dab6d7
+		    }
dab6d7
+		} else if (auth[CKU_USER] == NULL) {
dab6d7
+		    auth[CKU_USER] = new PK15Object(obj);
dab6d7
+		} else if (auth[CKU_CONTEXT_SPECIFIC] == NULL) {
dab6d7
+		    ObjectIter iter;
dab6d7
+		    const CKYBuffer *authid = obj.getPinAuthId();
dab6d7
+
dab6d7
+		    /* these should put on the individual keys */
dab6d7
+		    auth[CKU_CONTEXT_SPECIFIC] = new PK15Object(obj);
dab6d7
+
dab6d7
+		    for( iter = tokenObjects.begin(); 
dab6d7
+			 iter != tokenObjects.end(); ++iter) {
dab6d7
+			if( CKYBuffer_IsEqual(iter->getAuthId(),authid)) {
dab6d7
+			    iter->setAttributeBool(CKA_ALWAYS_AUTHENTICATE,
dab6d7
+						   TRUE);
dab6d7
+			}
dab6d7
+		    }
dab6d7
+		}
dab6d7
+		/* drop unkown */
dab6d7
+		break;
dab6d7
+	    case PK15PvKey:
dab6d7
+		/* does the cert already exist? */
dab6d7
+		{
dab6d7
+		    ObjectConstIter iter;
dab6d7
+		    const CKYBuffer *id;
dab6d7
+
dab6d7
+		    id = obj.getAttribute(CKA_ID);
dab6d7
+		    if ((!id) || (CKYBuffer_Size(id) != 1)) {
dab6d7
+			break;
dab6d7
+		    }
dab6d7
+		    iter = find_if(tokenObjects.begin(), tokenObjects.end(),
dab6d7
+                        ObjectCertCKAIDMatch(id));
dab6d7
+			
dab6d7
+		    if ( iter != tokenObjects.end() ) {
dab6d7
+			obj.completeKey(*iter);
dab6d7
+		    }
dab6d7
+		}
dab6d7
+		break;
dab6d7
+	    case PK15Cert:
dab6d7
+		/* does a corresponding key already exist? */
dab6d7
+		{
dab6d7
+		    ObjectIter iter;
dab6d7
+		    const CKYBuffer *id;
dab6d7
+
dab6d7
+		    id = obj.getAttribute(CKA_ID);
dab6d7
+		    if ((!id) || (CKYBuffer_Size(id) != 1)) {
dab6d7
+			break;
dab6d7
+		    }
dab6d7
+		    iter = find_if(tokenObjects.begin(), tokenObjects.end(),
dab6d7
+                        ObjectKeyCKAIDMatch(id));
dab6d7
+			
dab6d7
+		    if ( iter != tokenObjects.end() ) {
dab6d7
+			iter->completeKey(obj);
dab6d7
+		    }
dab6d7
+		}
dab6d7
+		break;
dab6d7
+	    case PK15PuKey:
dab6d7
+		break;
dab6d7
+	    }
dab6d7
+    	    tokenObjects.push_back(obj);
dab6d7
+  	} while ( false );
dab6d7
+    }
dab6d7
+    CKYBuffer_FreeData(&file;;
dab6d7
+    return CKYSUCCESS;
dab6d7
+}
dab6d7
+
dab6d7
+
dab6d7
+CKYStatus
dab6d7
+Slot::selectPath(const CKYBuffer *path, CKYISOStatus  *apduRC)
dab6d7
+{
dab6d7
+    CKYSize size = CKYBuffer_Size(path);
dab6d7
+    CKYStatus status = CKYINVALIDARGS;
dab6d7
+    CKYOffset pos;
dab6d7
+
dab6d7
+    for (pos=0; pos < size; pos +=2) {
dab6d7
+	unsigned short ef = CKYBuffer_GetShort(path, pos);
dab6d7
+	status = P15Applet_SelectFile(conn, ef, apduRC);
dab6d7
+	if (status != CKYSUCCESS) {
dab6d7
+		break;
dab6d7
+	}
dab6d7
+    }
dab6d7
+    return status;
dab6d7
+}
dab6d7
+
dab6d7
 void
dab6d7
 Slot::refreshTokenState()
dab6d7
 {
dab6d7
@@ -1132,8 +1581,20 @@ void
dab6d7
 Slot::makeSerialString(char *serialNumber, int maxSize,
dab6d7
 						 const unsigned char *cuid)
dab6d7
 {
dab6d7
+    CKYSize ssize = CKYBuffer_Size(&p15serialNumber);
dab6d7
     memset(serialNumber, ' ', maxSize);
dab6d7
 
dab6d7
+    if (ssize != 0) {
dab6d7
+	CKYSize i;
dab6d7
+	ssize = MIN((CKYSize)maxSize/2, ssize);
dab6d7
+	for (i=0; i < ssize; i++) {
dab6d7
+	   CKYByte c = CKYBuffer_GetChar(&p15serialNumber, i);
dab6d7
+	   serialNumber[2*i] = hex((c >> 4) & 0xf);
dab6d7
+	   serialNumber[2*i+1] = hex(c & 0xf);
dab6d7
+	}
dab6d7
+    }
dab6d7
+	    
dab6d7
+
dab6d7
     // otherwise we use the eepromSerialNumber as a hex value 
dab6d7
     if (cuid) {
dab6d7
          makeCUIDString(serialNumber, maxSize, cuid);
dab6d7
@@ -1204,7 +1665,8 @@ struct _manList {
dab6d7
 static const struct _manList  manList[] = {
dab6d7
         { 0x4090, "Axalto" },
dab6d7
         { 0x2050, "Oberthur" },
dab6d7
-        { 0x4780, "RSA" }
dab6d7
+        { 0x4780, "RSA" },
dab6d7
+        { 0x534e, "SafeNet" }
dab6d7
 };
dab6d7
 
dab6d7
 static int manListSize = sizeof(manList)/sizeof(manList[0]);
dab6d7
@@ -1213,8 +1675,15 @@ void
dab6d7
 Slot::makeManufacturerString(char *man, int maxSize, const unsigned char *cuid)
dab6d7
 {
dab6d7
     char *cp = man;
dab6d7
+    int manLen;
dab6d7
     memset(man, ' ', maxSize);
dab6d7
 
dab6d7
+    if (tokenManufacturer) {
dab6d7
+	manLen = strlen(tokenManufacturer);
dab6d7
+	memcpy(man, tokenManufacturer, MIN(manLen, maxSize));
dab6d7
+        // UTF8 Truncate fixup! don't drop halfway through a UTF8 character 
dab6d7
+        return;
dab6d7
+    }
dab6d7
     if (!cuid) {
dab6d7
 	return;
dab6d7
     }
dab6d7
@@ -1633,26 +2102,6 @@ class KeyNumMatch {
dab6d7
     }
dab6d7
 };
dab6d7
 
dab6d7
-class ObjectCertCKAIDMatch {
dab6d7
-  private:
dab6d7
-    CKYByte cka_id;
dab6d7
-  public:
dab6d7
-    ObjectCertCKAIDMatch(CKYByte cka_id_) : cka_id(cka_id_) {}
dab6d7
-    bool operator()(const PKCS11Object& obj) {
dab6d7
-	const CKYBuffer *id;
dab6d7
-        const CKYBuffer *objClass;
dab6d7
-	CK_OBJECT_CLASS certClass = CKO_CERTIFICATE;
dab6d7
-	objClass = obj.getAttribute(CKA_CLASS);
dab6d7
-        if (objClass == NULL || !CKYBuffer_DataIsEqual(objClass, 
dab6d7
-				(CKYByte *)&certClass, sizeof(certClass))) {
dab6d7
-	    return false;
dab6d7
-        }
dab6d7
- 	id = obj.getAttribute(CKA_ID);
dab6d7
-        return (id != NULL && CKYBuffer_DataIsEqual(id,&cka_id, 1))
dab6d7
-						 ? true : false;
dab6d7
-    }
dab6d7
-};
dab6d7
-
dab6d7
 CK_OBJECT_HANDLE
dab6d7
 Slot::generateUnusedObjectHandle()
dab6d7
 {
dab6d7
@@ -1706,7 +2155,7 @@ Slot::addKeyObject(list<PKCS11Object>& o
dab6d7
                         "Missing or invalid CKA_ID value");
dab6d7
         }
dab6d7
         iter = find_if(objectList.begin(), objectList.end(),
dab6d7
-                        ObjectCertCKAIDMatch(CKYBuffer_GetChar(id,0)));
dab6d7
+                        ObjectCertCKAIDMatch(id));
dab6d7
         if ( iter == objectList.end() ) {
dab6d7
             // We failed to find a cert with a matching CKA_ID. This
dab6d7
             // can happen if the cert is not present on the token, or
dab6d7
@@ -1758,6 +2207,11 @@ Slot::unloadObjects()
dab6d7
     free(personName);
dab6d7
     personName = NULL;
dab6d7
     fullTokenName = false;
dab6d7
+    if (tokenManufacturer) {
dab6d7
+	free(tokenManufacturer);
dab6d7
+	tokenManufacturer = NULL;
dab6d7
+    }
dab6d7
+    CKYBuffer_Resize(&p15serialNumber,0);
dab6d7
 }
dab6d7
 
dab6d7
 #ifdef USE_SHMEM
dab6d7
@@ -2956,6 +3410,17 @@ Slot::loadObjects()
dab6d7
 	loadReaderObject();
dab6d7
 	return;
dab6d7
     }
dab6d7
+    if (state & P15_CARD) {
dab6d7
+	parseEF_TokenInfo();
dab6d7
+	parseEF_ODF();
dab6d7
+	if (auth[CKU_USER] != NULL) {
dab6d7
+	    /* set need login */
dab6d7
+	    needLogin = true;
dab6d7
+	}
dab6d7
+	status = trans.end();
dab6d7
+	loadReaderObject();
dab6d7
+	return;
dab6d7
+    }
dab6d7
 
dab6d7
     selectApplet();
dab6d7
     log->log("time load object: Select Applet (again) %d ms\n",
dab6d7
@@ -3123,15 +3588,15 @@ Slot::getSessionInfo(SessionHandleSuffix
dab6d7
 }
dab6d7
 
dab6d7
 void
dab6d7
-SlotList::login(CK_SESSION_HANDLE hSession, CK_UTF8CHAR_PTR pPin,
dab6d7
-    CK_ULONG ulPinLen)
dab6d7
+SlotList::login(CK_SESSION_HANDLE hSession, CK_USER_TYPE user,
dab6d7
+    CK_UTF8CHAR_PTR pPin, CK_ULONG ulPinLen)
dab6d7
 {
dab6d7
     CK_SLOT_ID slotID;
dab6d7
     SessionHandleSuffix suffix;
dab6d7
 
dab6d7
     decomposeSessionHandle(hSession, slotID, suffix);
dab6d7
 
dab6d7
-    slots[slotIDToIndex(slotID)]->login(suffix, pPin, ulPinLen);
dab6d7
+    slots[slotIDToIndex(slotID)]->login(suffix, user, pPin, ulPinLen);
dab6d7
 }
dab6d7
 
dab6d7
 void
dab6d7
@@ -3181,8 +3646,8 @@ Slot::isLoggedIn()
dab6d7
 }
dab6d7
 
dab6d7
 void
dab6d7
-Slot::login(SessionHandleSuffix handleSuffix, CK_UTF8CHAR_PTR pPin,
dab6d7
-    CK_ULONG ulPinLen)
dab6d7
+Slot::login(SessionHandleSuffix handleSuffix, CK_USER_TYPE user,
dab6d7
+    CK_UTF8CHAR_PTR pPin, CK_ULONG ulPinLen)
dab6d7
 {
dab6d7
     refreshTokenState();
dab6d7
 
dab6d7
@@ -3191,10 +3656,23 @@ Slot::login(SessionHandleSuffix handleSu
dab6d7
             "Slot::login\n", (unsigned long) handleSuffix);
dab6d7
         throw PKCS11Exception(CKR_SESSION_HANDLE_INVALID);
dab6d7
     }
dab6d7
+    /* only support CKU_USER for CAC, PIV, and coolkey... CKU_USER and
dab6d7
+     * CKU_CONTEX_SPECIFIC for P15Card */
dab6d7
+    if (user != CKU_USER) {
dab6d7
+	if ((user != CKU_CONTEXT_SPECIFIC) || ((state & P15_CARD) == 0)) {
dab6d7
+	    throw PKCS11Exception(CKR_USER_TYPE_INVALID);
dab6d7
+	}
dab6d7
+    }
dab6d7
+
dab6d7
 
dab6d7
     if (!isVersion1Key) {
dab6d7
-	pinCache.invalidate();
dab6d7
-	pinCache.set((const char *)pPin, ulPinLen);
dab6d7
+	if (user == CKU_USER) {
dab6d7
+	    pinCache.invalidate();
dab6d7
+	    pinCache.set((const char *)pPin, ulPinLen);
dab6d7
+	} else { 
dab6d7
+	    contextPinCache.invalidate();
dab6d7
+	    contextPinCache.set((const char *)pPin, ulPinLen);
dab6d7
+	}
dab6d7
     } else if (nonceValid) {
dab6d7
 	throw PKCS11Exception(CKR_USER_ALREADY_LOGGED_IN);
dab6d7
     }
dab6d7
@@ -3205,17 +3683,85 @@ Slot::login(SessionHandleSuffix handleSu
dab6d7
 
dab6d7
     if (state & GOV_CARD) {
dab6d7
 	selectCACApplet(0, true);
dab6d7
-    } else {
dab6d7
+    } else if ((state & P15_CARD)== 0) {
dab6d7
+	/* p15 does the select in attemptLogin */
dab6d7
 	selectApplet();
dab6d7
     }
dab6d7
 
dab6d7
     if (isVersion1Key) {
dab6d7
-	attemptLogin((const char *)pPin);
dab6d7
-    } else if (state & GOV_CARD) {
dab6d7
+	attemptCoolKeyLogin((const char *)pPin);
dab6d7
+    } else  {
dab6d7
+	attemptLogin(user, false);
dab6d7
+    }
dab6d7
+}
dab6d7
+
dab6d7
+void
dab6d7
+Slot::attemptLogin(CK_USER_TYPE user, bool flushPin) {
dab6d7
+    if (state & GOV_CARD) {
dab6d7
 	attemptCACLogin();
dab6d7
+    } else if (state & P15_CARD) {
dab6d7
+	attemptP15Login(user);
dab6d7
     } else {
dab6d7
 	oldAttemptLogin();
dab6d7
     }
dab6d7
+    if (flushPin && (user == CKU_CONTEXT_SPECIFIC)) {
dab6d7
+	contextPinCache.clearPin();
dab6d7
+    }
dab6d7
+}
dab6d7
+void dump(const char *label, const CKYBuffer *buf);
dab6d7
+
dab6d7
+void
dab6d7
+Slot::attemptP15Login(CK_USER_TYPE user)
dab6d7
+{
dab6d7
+    PinCache *pinCachePtr  = userPinCache(user);
dab6d7
+    const CKYBuffer *path;
dab6d7
+
dab6d7
+    if (user == CKU_USER) {
dab6d7
+	loggedIn = false;
dab6d7
+    }
dab6d7
+    pinCachePtr->invalidate();
dab6d7
+
dab6d7
+    CKYStatus status;
dab6d7
+    CKYISOStatus result;
dab6d7
+
dab6d7
+    if ((user >= MAX_AUTH_USERS) || (auth[user] == NULL)) {
dab6d7
+	throw PKCS11Exception(CKR_USER_TYPE_INVALID,
dab6d7
+			"No PKCS #15 auth object for user %d\n", user);
dab6d7
+    }
dab6d7
+
dab6d7
+    path = auth[user]->getObjectPath().getPath();
dab6d7
+    status = selectPath(auth[user]->getObjectPath().getPath(), &result);
dab6d7
+    if( status == CKYSCARDERR )  {
dab6d7
+	handleConnectionError();
dab6d7
+    }
dab6d7
+    if (status != CKYSUCCESS) {
dab6d7
+	throw PKCS11Exception(CKR_DEVICE_ERROR, "Applet select return 0x%04x",
dab6d7
+								result);
dab6d7
+    }
dab6d7
+
dab6d7
+    status = P15Applet_VerifyPIN(conn, 
dab6d7
+		(const char *)CKYBuffer_Data(pinCachePtr->get()), 
dab6d7
+		auth[user]->getPinInfo(), &result);
dab6d7
+    if( status == CKYSCARDERR ) {
dab6d7
+	handleConnectionError();
dab6d7
+    }
dab6d7
+    switch( result ) {
dab6d7
+      case CKYISO_SUCCESS:
dab6d7
+        break;
dab6d7
+      case 0x6983:
dab6d7
+	pinCachePtr->clearPin();
dab6d7
+        throw PKCS11Exception(CKR_PIN_LOCKED);
dab6d7
+      default:
dab6d7
+	pinCachePtr->clearPin();
dab6d7
+	if ((result & 0xff00) == 0x6300) {
dab6d7
+            throw PKCS11Exception(CKR_PIN_INCORRECT);
dab6d7
+	}
dab6d7
+        throw PKCS11Exception(CKR_DEVICE_ERROR, "Applet returned 0x%04x", 
dab6d7
+								result);
dab6d7
+    }
dab6d7
+    pinCachePtr->validate();
dab6d7
+    if (user == CKU_USER)
dab6d7
+	loggedIn = true;
dab6d7
 }
dab6d7
 
dab6d7
 void
dab6d7
@@ -3252,6 +3798,7 @@ Slot::attemptCACLogin()
dab6d7
     loggedIn = true;
dab6d7
 }
dab6d7
 
dab6d7
+
dab6d7
 void
dab6d7
 Slot::oldAttemptLogin()
dab6d7
 {
dab6d7
@@ -3286,7 +3833,7 @@ Slot::oldAttemptLogin()
dab6d7
 
dab6d7
 // should already be in a transaction, and applet selected
dab6d7
 void
dab6d7
-Slot::attemptLogin(const char *pin)
dab6d7
+Slot::attemptCoolKeyLogin(const char *pin)
dab6d7
 {
dab6d7
     CKYStatus status;
dab6d7
     CKYISOStatus result;
dab6d7
@@ -3362,7 +3909,7 @@ Slot::logout(SessionHandleSuffix suffix)
dab6d7
         throw PKCS11Exception(CKR_SESSION_HANDLE_INVALID);
dab6d7
     }
dab6d7
 
dab6d7
-    if (state & GOV_CARD) {
dab6d7
+    if (state & (GOV_CARD|P15_CARD)) {
dab6d7
 	CACLogout();
dab6d7
 	return;
dab6d7
     }
dab6d7
@@ -3601,31 +4148,26 @@ Slot::ensureValidSession(SessionHandleSu
dab6d7
 // from 0-9.
dab6d7
 //
dab6d7
 CKYByte
dab6d7
-Slot::objectHandleToKeyNum(CK_OBJECT_HANDLE hKey)
dab6d7
+Slot::objectToKeyNum(const PKCS11Object *key)
dab6d7
 {
dab6d7
-    ObjectConstIter iter = find_if(tokenObjects.begin(), tokenObjects.end(),
dab6d7
-        ObjectHandleMatch(hKey));
dab6d7
-
dab6d7
-    if( iter == tokenObjects.end() ) {
dab6d7
-        // no such object
dab6d7
-        throw PKCS11Exception(CKR_KEY_HANDLE_INVALID);
dab6d7
-    }
dab6d7
+    unsigned long id = key->getMuscleObjID();
dab6d7
 
dab6d7
-    if( getObjectClass(iter->getMuscleObjID()) != 'k' ) {
dab6d7
+    if( getObjectClass(id) != 'k' ) {
dab6d7
         throw PKCS11Exception(CKR_KEY_HANDLE_INVALID);
dab6d7
     }
dab6d7
-    unsigned short keyNum = getObjectIndex(iter->getMuscleObjID());
dab6d7
+    unsigned short keyNum = getObjectIndex(id);
dab6d7
     if( keyNum > 9 ) {
dab6d7
         throw PKCS11Exception(CKR_KEY_HANDLE_INVALID);
dab6d7
     }
dab6d7
     return keyNum & 0xFF;
dab6d7
 }
dab6d7
 
dab6d7
-PKCS11Object::KeyType
dab6d7
-Slot::getKeyTypeFromHandle(CK_OBJECT_HANDLE hKey)
dab6d7
+PKCS11Object *
dab6d7
+Slot::getKeyFromHandle(CK_OBJECT_HANDLE hKey)
dab6d7
 {
dab6d7
     ObjectConstIter iter = find_if(tokenObjects.begin(), tokenObjects.end(),
dab6d7
         ObjectHandleMatch(hKey));
dab6d7
+    PKCS11Object &obj = (PKCS11Object &)*iter;
dab6d7
 
dab6d7
     if( iter == tokenObjects.end() ) {
dab6d7
          throw PKCS11Exception(CKR_KEY_HANDLE_INVALID);
dab6d7
@@ -3635,7 +4177,7 @@ Slot::getKeyTypeFromHandle(CK_OBJECT_HAN
dab6d7
         throw PKCS11Exception(CKR_KEY_HANDLE_INVALID);
dab6d7
     }
dab6d7
 
dab6d7
-    return iter->getKeyType();
dab6d7
+    return &ob;;
dab6d7
 }
dab6d7
 
dab6d7
 void
dab6d7
@@ -3648,9 +4190,7 @@ Slot::signInit(SessionHandleSuffix suffi
dab6d7
         throw PKCS11Exception(CKR_SESSION_HANDLE_INVALID);
dab6d7
     }
dab6d7
 
dab6d7
-    PKCS11Object::KeyType  keyType = getKeyTypeFromHandle(hKey);
dab6d7
-
dab6d7
-    session->signatureState.initialize(objectHandleToKeyNum(hKey), keyType);
dab6d7
+    session->signatureState.initialize(getKeyFromHandle(hKey));
dab6d7
 }
dab6d7
 
dab6d7
 void
dab6d7
@@ -3663,9 +4203,7 @@ Slot::decryptInit(SessionHandleSuffix su
dab6d7
         throw PKCS11Exception(CKR_SESSION_HANDLE_INVALID);
dab6d7
     }
dab6d7
 
dab6d7
-    PKCS11Object::KeyType keyType = getKeyTypeFromHandle(hKey);
dab6d7
-
dab6d7
-    session->decryptionState.initialize(objectHandleToKeyNum(hKey), keyType);
dab6d7
+    session->decryptionState.initialize(getKeyFromHandle(hKey));
dab6d7
 }
dab6d7
 
dab6d7
 /**
dab6d7
@@ -3935,7 +4473,7 @@ Slot::sign(SessionHandleSuffix suffix, C
dab6d7
 
dab6d7
     CryptOpState sigState = dummyParams.getOpState(*session);
dab6d7
 
dab6d7
-    PKCS11Object::KeyType keyType = sigState.keyType;
dab6d7
+    PKCS11Object::KeyType keyType = sigState.key->getKeyType();
dab6d7
    
dab6d7
     if ( keyType == PKCS11Object::unknown) {
dab6d7
         throw PKCS11Exception(CKR_DATA_INVALID);
dab6d7
@@ -3982,9 +4520,9 @@ Slot::cryptRSA(SessionHandleSuffix suffi
dab6d7
     }
dab6d7
     CryptOpState& opState = params.getOpState(*session);
dab6d7
     CKYBuffer *result = &opState.result;
dab6d7
-    CKYByte keyNum = opState.keyNum;
dab6d7
+    PKCS11Object  *key = opState.key;
dab6d7
 
dab6d7
-    unsigned int keySize = getRSAKeySize(keyNum);
dab6d7
+    unsigned int keySize = getRSAKeySize(key);
dab6d7
 
dab6d7
     if (keySize != CryptParams::DEFAULT_KEY_SIZE)
dab6d7
         params.setKeySize(keySize);
dab6d7
@@ -4008,8 +4546,8 @@ Slot::cryptRSA(SessionHandleSuffix suffi
dab6d7
   	}
dab6d7
 	try {
dab6d7
 	    params.padInput(&inputPad, &input);
dab6d7
-            performRSAOp(&output, &inputPad, params.getKeySize(), 
dab6d7
-								keyNum, params.getDirection());
dab6d7
+            performRSAOp(&output, &inputPad, params.getKeySize(), key, 
dab6d7
+							params.getDirection());
dab6d7
 	    params.unpadOutput(result, &output);
dab6d7
 	    CKYBuffer_FreeData(&input);
dab6d7
 	    CKYBuffer_FreeData(&inputPad);
dab6d7
@@ -4072,9 +4610,9 @@ void Slot::signECC(SessionHandleSuffix s
dab6d7
     }
dab6d7
     CryptOpState& opState = params.getOpState(*session);
dab6d7
     CKYBuffer *result = &opState.result;
dab6d7
-    CKYByte keyNum = opState.keyNum;
dab6d7
+    PKCS11Object  *key = opState.key;
dab6d7
 
dab6d7
-    unsigned int keySize = getECCKeySize(keyNum);
dab6d7
+    unsigned int keySize = getECCKeySize(key);
dab6d7
 
dab6d7
     if(keySize != CryptParams::ECC_DEFAULT_KEY_SIZE)
dab6d7
         params.setKeySize(keySize);
dab6d7
@@ -4100,7 +4638,7 @@ void Slot::signECC(SessionHandleSuffix s
dab6d7
             throw PKCS11Exception(CKR_HOST_MEMORY);
dab6d7
         }
dab6d7
         try {
dab6d7
-            performECCSignature(&output, &input, params.getKeySize(), keyNum);
dab6d7
+            performECCSignature(&output, &input, params.getKeySize(), key);
dab6d7
             params.unpadOutput(result, &output);
dab6d7
             CKYBuffer_FreeData(&input);
dab6d7
             CKYBuffer_FreeData(&output);
dab6d7
@@ -4122,8 +4660,26 @@ void Slot::signECC(SessionHandleSuffix s
dab6d7
 }
dab6d7
 
dab6d7
 void
dab6d7
+Slot::selectKey(const PKCS11Object *key, bool retry)
dab6d7
+{
dab6d7
+    /* P15 cards need to be reselected on retry because P15 must select
dab6d7
+     * on authentication. PIV, CAC and Coolkeys do not */
dab6d7
+    if (retry && ((state & GOV_CARD) || ((state & P15_CARD) == 0))) {
dab6d7
+	return;
dab6d7
+    }
dab6d7
+    if (state & GOV_CARD) {
dab6d7
+	selectCACApplet(objectToKeyNum(key), true);
dab6d7
+    } else if (state & P15_CARD) {
dab6d7
+	selectPath(key->getObjectPath().getPath(), NULL);
dab6d7
+    } else {
dab6d7
+	selectApplet();
dab6d7
+    }
dab6d7
+    return;
dab6d7
+}
dab6d7
+
dab6d7
+void
dab6d7
 Slot::performECCSignature(CKYBuffer *output, const CKYBuffer *input, 
dab6d7
-						unsigned int keySize, CKYByte keyNum)
dab6d7
+			unsigned int keySize, const PKCS11Object *key)
dab6d7
 {
dab6d7
 
dab6d7
     /* establish a transaction */
dab6d7
@@ -4135,22 +4691,23 @@ Slot::performECCSignature(CKYBuffer *out
dab6d7
         throw PKCS11Exception(CKR_FUNCTION_NOT_SUPPORTED);
dab6d7
     }
dab6d7
 
dab6d7
-    if (state & GOV_CARD) {
dab6d7
-	selectCACApplet(keyNum, true);
dab6d7
-    } else {
dab6d7
-	selectApplet();
dab6d7
-    }
dab6d7
-
dab6d7
     CKYISOStatus result;
dab6d7
-    int loginAttempted = 0;
dab6d7
+    bool loginAttempted = false;
dab6d7
 
dab6d7
 retry:
dab6d7
+    selectKey(key, loginAttempted);
dab6d7
+
dab6d7
     if (state & PIV_CARD) {
dab6d7
-        status = PIVApplet_SignDecrypt(conn, pivKey, keySize/8, 0, input, output, &result);
dab6d7
+        status = PIVApplet_SignDecrypt(conn, pivKey, keySize/8, 0, 
dab6d7
+					input, output, &result);
dab6d7
     } else if (state & CAC_CARD) {
dab6d7
         status = CACApplet_SignDecrypt(conn, input, output, &result);
dab6d7
+    } else if (state & P15_CARD) {
dab6d7
+	status = P15Applet_SignDecrypt(conn, key->getKeyRef(), keySize/8,
dab6d7
+				CKY_DIR_ENCRYPT, input, output, &result); 
dab6d7
+	
dab6d7
     } else {
dab6d7
-        status = CKYApplet_ComputeECCSignature(conn, keyNum, input, NULL, output, getNonce(), &result);
dab6d7
+        status = CKYApplet_ComputeECCSignature(conn, objectToKeyNum(key), 					input, NULL, output, getNonce(), &result);
dab6d7
     }
dab6d7
     /* map the ISO not logged in code to the coolkey one */
dab6d7
     if ((result == CKYISO_CONDITION_NOT_SATISFIED) ||
dab6d7
@@ -4166,19 +4723,16 @@ retry:
dab6d7
         if (result == CKYISO_DATA_INVALID) {
dab6d7
             throw PKCS11Exception(CKR_DATA_INVALID);
dab6d7
         }
dab6d7
-        /* version0 keys could be logged out in the middle by someone else,
dab6d7
-           reauthenticate... This code can go away when we depricate.
dab6d7
-           version0 applets.
dab6d7
-        */
dab6d7
+        /* keys could be logged out in the middle by someone else,
dab6d7
+         *  reauthenticate... coolkey version 1 bypasses this issue by
dab6d7
+         *  allowing multiple applications separate login states at once.
dab6d7
+         */
dab6d7
         if (!isVersion1Key && !loginAttempted  &&
dab6d7
+				userPinCache(key->getUser())->isValid() &&
dab6d7
                     (result == CKYISO_UNAUTHORIZED)) {
dab6d7
             /* try to reauthenticate  */
dab6d7
 	    try {
dab6d7
-		if (state & GOV_CARD) {
dab6d7
-		    attemptCACLogin();
dab6d7
-		} else {
dab6d7
-		    oldAttemptLogin();
dab6d7
-		}
dab6d7
+		attemptLogin(key->getUser(),true);
dab6d7
             } catch(PKCS11Exception& ) {
dab6d7
                 /* attemptLogin can throw things like CKR_PIN_INCORRECT
dab6d7
                   that don't make sense from a crypto operation. This is
dab6d7
@@ -4199,8 +4753,9 @@ retry:
dab6d7
 
dab6d7
 
dab6d7
 void
dab6d7
-Slot::performRSAOp(CKYBuffer *output, const CKYBuffer *input, unsigned int keySize,
dab6d7
-					CKYByte keyNum, CKYByte direction)
dab6d7
+Slot::performRSAOp(CKYBuffer *output, const CKYBuffer *input, 
dab6d7
+		unsigned int keySize, const PKCS11Object *key, 
dab6d7
+		CKYByte direction)
dab6d7
 {
dab6d7
     if ( mECC ) {
dab6d7
         throw PKCS11Exception(CKR_FUNCTION_NOT_SUPPORTED);
dab6d7
@@ -4212,26 +4767,25 @@ Slot::performRSAOp(CKYBuffer *output, co
dab6d7
     Transaction trans;
dab6d7
     CKYStatus status = trans.begin(conn);
dab6d7
     if( status != CKYSUCCESS ) handleConnectionError();
dab6d7
-
dab6d7
-    //
dab6d7
-    // select the applet
dab6d7
-    //
dab6d7
-    if (state & GOV_CARD) {
dab6d7
-	selectCACApplet(keyNum, true);
dab6d7
-    } else {
dab6d7
-	selectApplet();
dab6d7
-    }
dab6d7
-
dab6d7
     CKYISOStatus result;
dab6d7
-    int loginAttempted = 0;
dab6d7
+    bool loginAttempted = false;
dab6d7
+
dab6d7
 retry:
dab6d7
+    selectKey(key, loginAttempted);
dab6d7
+
dab6d7
+
dab6d7
     if (state & PIV_CARD) {
dab6d7
-        status = PIVApplet_SignDecrypt(conn, pivKey, keySize/8, 0, input, output, &result);
dab6d7
+        status = PIVApplet_SignDecrypt(conn, pivKey, keySize/8, 0, 
dab6d7
+				input, output, &result);
dab6d7
     } else if (state & CAC_CARD) {
dab6d7
         status = CACApplet_SignDecrypt(conn, input, output, &result);
dab6d7
+    } else if (state & P15_CARD) {
dab6d7
+	status = P15Applet_SignDecrypt(conn, key->getKeyRef(), keySize/8,
dab6d7
+				direction, input, output, &result);
dab6d7
     } else {
dab6d7
-        status = CKYApplet_ComputeCrypt(conn, keyNum, CKY_RSA_NO_PAD, direction,
dab6d7
-		input, NULL, output, getNonce(), &result);
dab6d7
+        status = CKYApplet_ComputeCrypt(conn, objectToKeyNum(key), 
dab6d7
+		CKY_RSA_NO_PAD, direction, input, NULL, output, 
dab6d7
+		getNonce(), &result);
dab6d7
     } 
dab6d7
 
dab6d7
     /* map the ISO not logged in code to the coolkey one */
dab6d7
@@ -4250,15 +4804,12 @@ retry:
dab6d7
 	// version0 keys could be logged out in the middle by someone else,
dab6d7
 	// reauthenticate... This code can go away when we depricate.
dab6d7
         // version0 applets.
dab6d7
-	if (!isVersion1Key && !loginAttempted  && pinCache.isValid() &&
dab6d7
+	if (!isVersion1Key && !loginAttempted  && 
dab6d7
+				userPinCache(key->getUser())->isValid() &&
dab6d7
 					(result == CKYISO_UNAUTHORIZED)) {
dab6d7
 	    // try to reauthenticate 
dab6d7
 	    try {
dab6d7
-		if (state & GOV_CARD) {
dab6d7
-		    attemptCACLogin();
dab6d7
-		} else {
dab6d7
-		    oldAttemptLogin();
dab6d7
-		}
dab6d7
+		attemptLogin(key->getUser(), true);
dab6d7
 	    } catch(PKCS11Exception& ) {
dab6d7
 		// attemptLogin can throw things like CKR_PIN_INCORRECT
dab6d7
 		// that don't make sense from a crypto operation. This is
dab6d7
@@ -4278,7 +4829,7 @@ void
dab6d7
 Slot::seedRandom(SessionHandleSuffix suffix, CK_BYTE_PTR pData,
dab6d7
         CK_ULONG ulDataLen)
dab6d7
 {
dab6d7
-    if (state & GOV_CARD) {
dab6d7
+    if (state & (GOV_CARD|P15_CARD)) {
dab6d7
 	/* should throw unsupported */
dab6d7
 	throw PKCS11Exception(CKR_DEVICE_ERROR);
dab6d7
     }
dab6d7
@@ -4330,7 +4881,7 @@ void
dab6d7
 Slot::generateRandom(SessionHandleSuffix suffix, const CK_BYTE_PTR pData,
dab6d7
         CK_ULONG ulDataLen)
dab6d7
 {
dab6d7
-    if (state & GOV_CARD) {
dab6d7
+    if (state & (GOV_CARD|P15_CARD)) {
dab6d7
 	/* should throw unsupported */
dab6d7
 	throw PKCS11Exception(CKR_DEVICE_ERROR);
dab6d7
     }
dab6d7
@@ -4364,61 +4915,44 @@ Slot::generateRandom(SessionHandleSuffix
dab6d7
 
dab6d7
 #define MAX_NUM_KEYS 8
dab6d7
 unsigned int
dab6d7
-Slot::getRSAKeySize(CKYByte keyNum)
dab6d7
+Slot::getRSAKeySize(PKCS11Object *key)
dab6d7
 {
dab6d7
     unsigned int keySize = CryptParams::DEFAULT_KEY_SIZE;
dab6d7
     int modSize = 0;
dab6d7
 
dab6d7
-    if(keyNum >= MAX_NUM_KEYS) {
dab6d7
-        return keySize;
dab6d7
-    }
dab6d7
-
dab6d7
-    ObjectConstIter iter;
dab6d7
-    iter = find_if(tokenObjects.begin(), tokenObjects.end(),
dab6d7
-        KeyNumMatch(keyNum,*this));
dab6d7
-
dab6d7
-    if( iter == tokenObjects.end() ) {
dab6d7
-        return keySize;
dab6d7
+    modSize = key->getKeySize();
dab6d7
+    if (modSize != 0) {
dab6d7
+	return modSize;
dab6d7
     }
dab6d7
 
dab6d7
-    CKYBuffer const *modulus = iter->getAttribute(CKA_MODULUS);
dab6d7
+    CKYBuffer const *modulus = key->getAttribute(CKA_MODULUS);
dab6d7
 
dab6d7
     if(modulus) {
dab6d7
         modSize = CKYBuffer_Size(modulus);
dab6d7
         if(CKYBuffer_GetChar(modulus,0) == 0x0) {
dab6d7
             modSize--;
dab6d7
         }
dab6d7
-        if(modSize > 0)
dab6d7
+        if(modSize > 0) {
dab6d7
             keySize = modSize * 8;
dab6d7
+	    key->setKeySize(keySize);
dab6d7
+	}
dab6d7
     }
dab6d7
 
dab6d7
     return keySize;
dab6d7
 }
dab6d7
 
dab6d7
 unsigned int
dab6d7
-Slot::getECCKeySize(CKYByte keyNum)
dab6d7
-{
dab6d7
-    return calcECCKeySize(keyNum);
dab6d7
-} 
dab6d7
-
dab6d7
-unsigned int
dab6d7
-Slot::calcECCKeySize(CKYByte keyNum)
dab6d7
+Slot::getECCKeySize(PKCS11Object *key)
dab6d7
 {
dab6d7
     unsigned int keySize = CryptParams::ECC_DEFAULT_KEY_SIZE;
dab6d7
+    unsigned int objKeySize = 0;
dab6d7
 
dab6d7
-    if(keyNum >= MAX_NUM_KEYS) {
dab6d7
-        return keySize;
dab6d7
-    }
dab6d7
-
dab6d7
-    ObjectConstIter iter;
dab6d7
-    iter = find_if(tokenObjects.begin(), tokenObjects.end(),
dab6d7
-        KeyNumMatch(keyNum,*this));
dab6d7
-
dab6d7
-    if( iter == tokenObjects.end() ) {
dab6d7
-        return keySize;
dab6d7
+    objKeySize = key->getKeySize();
dab6d7
+    if (objKeySize != 0) {
dab6d7
+	return objKeySize;
dab6d7
     }
dab6d7
 
dab6d7
-    CKYBuffer const *eccParams = iter->getAttribute(CKA_EC_PARAMS);
dab6d7
+    CKYBuffer const *eccParams = key->getAttribute(CKA_EC_PARAMS);
dab6d7
 
dab6d7
     if (eccParams == NULL) {
dab6d7
         return keySize;
dab6d7
@@ -4457,6 +4991,7 @@ Slot::calcECCKeySize(CKYByte keyNum)
dab6d7
 
dab6d7
         if ( match == 1 ) {
dab6d7
             keySize =  curveBytesNamePair[i].length;
dab6d7
+	    key->setKeySize(keySize);
dab6d7
             return keySize;
dab6d7
         }
dab6d7
 
dab6d7
@@ -4476,10 +5011,9 @@ Slot::derive(SessionHandleSuffix suffix,
dab6d7
     ECCKeyAgreementParams params(CryptParams::ECC_DEFAULT_KEY_SIZE);
dab6d7
     SessionIter session = findSession(suffix);
dab6d7
 
dab6d7
-    PKCS11Object::KeyType keyType = getKeyTypeFromHandle(hBaseKey);
dab6d7
-
dab6d7
-    session->keyAgreementState.initialize(objectHandleToKeyNum(hBaseKey), keyType);
dab6d7
-    deriveECC(suffix, pMechanism, hBaseKey, pTemplate, ulAttributeCount, phKey, params);
dab6d7
+    session->keyAgreementState.initialize(getKeyFromHandle(hBaseKey));
dab6d7
+    deriveECC(suffix, pMechanism, hBaseKey, pTemplate, ulAttributeCount, 
dab6d7
+		phKey, params);
dab6d7
 
dab6d7
 }
dab6d7
 
dab6d7
@@ -4515,9 +5049,8 @@ void Slot::deriveECC(SessionHandleSuffix
dab6d7
 
dab6d7
     CryptOpState& opState = params.getOpState(*session);
dab6d7
     CKYBuffer *result = &opState.result;
dab6d7
-    CKYByte keyNum = opState.keyNum;
dab6d7
 
dab6d7
-    unsigned int keySize = getECCKeySize(keyNum);
dab6d7
+    unsigned int keySize = getECCKeySize(opState.key);
dab6d7
 
dab6d7
     if(keySize != CryptParams::ECC_DEFAULT_KEY_SIZE)
dab6d7
         params.setKeySize(keySize);
dab6d7
@@ -4542,10 +5075,11 @@ void Slot::deriveECC(SessionHandleSuffix
dab6d7
 
dab6d7
     if( CKYBuffer_Size(result) == 0 ) {
dab6d7
         try {
dab6d7
-            performECCKeyAgreement(deriveMech, &publicDataBuffer, &secretKeyBuffer,
dab6d7
-			 keyNum, params.getKeySize());
dab6d7
+            performECCKeyAgreement(deriveMech, &publicDataBuffer, 
dab6d7
+			&secretKeyBuffer, opState.key, params.getKeySize());
dab6d7
             CK_OBJECT_HANDLE keyObjectHandle = generateUnusedObjectHandle();
dab6d7
-            secret = createSecretKeyObject(keyObjectHandle, &secretKeyBuffer, pTemplate, ulAttributeCount);
dab6d7
+            secret = createSecretKeyObject(keyObjectHandle, &secretKeyBuffer, 
dab6d7
+						pTemplate, ulAttributeCount);
dab6d7
         } catch(PKCS11Exception& e) {
dab6d7
             CKYBuffer_FreeData(&secretKeyBuffer);
dab6d7
             CKYBuffer_FreeData(&publicDataBuffer);
dab6d7
@@ -4557,15 +5091,15 @@ void Slot::deriveECC(SessionHandleSuffix
dab6d7
    CKYBuffer_FreeData(&publicDataBuffer);
dab6d7
 
dab6d7
    if ( secret ) {
dab6d7
-
dab6d7
        *phKey = secret->getHandle();
dab6d7
         delete secret;
dab6d7
    }
dab6d7
 }
dab6d7
 
dab6d7
 void
dab6d7
-Slot::performECCKeyAgreement(CK_MECHANISM_TYPE deriveMech, CKYBuffer *publicDataBuffer, 
dab6d7
-			     CKYBuffer *secretKeyBuffer, CKYByte keyNum, unsigned int keySize)
dab6d7
+Slot::performECCKeyAgreement(CK_MECHANISM_TYPE deriveMech, 
dab6d7
+	CKYBuffer *publicDataBuffer, CKYBuffer *secretKeyBuffer, 
dab6d7
+	const PKCS11Object *key, unsigned int keySize)
dab6d7
 {
dab6d7
     if (!mECC) {
dab6d7
        throw PKCS11Exception(CKR_FUNCTION_NOT_SUPPORTED);
dab6d7
@@ -4575,25 +5109,26 @@ Slot::performECCKeyAgreement(CK_MECHANIS
dab6d7
     CKYStatus status = trans.begin(conn);
dab6d7
     if( status != CKYSUCCESS ) handleConnectionError();
dab6d7
 
dab6d7
-    if (state & GOV_CARD) {
dab6d7
-	selectCACApplet(keyNum, true);
dab6d7
-    } else {
dab6d7
-	selectApplet();
dab6d7
-    }
dab6d7
-
dab6d7
     CKYISOStatus result;
dab6d7
-    int loginAttempted = 0;
dab6d7
+    bool loginAttempted = false;
dab6d7
 
dab6d7
 retry:
dab6d7
+    selectKey(key, loginAttempted);
dab6d7
 
dab6d7
     if (state & PIV_CARD) {
dab6d7
-        status = PIVApplet_SignDecrypt(conn, pivKey, keySize/8, 1, publicDataBuffer, 
dab6d7
-			secretKeyBuffer, &result);
dab6d7
+        status = PIVApplet_SignDecrypt(conn, pivKey, keySize/8, 1, 
dab6d7
+			publicDataBuffer, secretKeyBuffer, &result);
dab6d7
     } else if (state & CAC_CARD) {
dab6d7
-        status = CACApplet_SignDecrypt(conn, publicDataBuffer, secretKeyBuffer, &result);
dab6d7
+        status = CACApplet_SignDecrypt(conn, publicDataBuffer, 
dab6d7
+			secretKeyBuffer, &result);
dab6d7
+    } else if (state & P15_CARD) {
dab6d7
+	/*status = P15Applet_SignDecrypt(conn, key->getKeyRef(), keySize/8,
dab6d7
+				publicDataBuffer, secretKeyBuffer, &result); */
dab6d7
+	throw PKCS11Exception(CKR_FUNCTION_NOT_SUPPORTED);
dab6d7
     } else {
dab6d7
-    	status = CKYApplet_ComputeECCKeyAgreement(conn, keyNum, 
dab6d7
-			publicDataBuffer , NULL, secretKeyBuffer, getNonce(), &result);
dab6d7
+    	status = CKYApplet_ComputeECCKeyAgreement(conn, objectToKeyNum(key), 
dab6d7
+			publicDataBuffer , NULL, secretKeyBuffer, 
dab6d7
+			getNonce(), &result);
dab6d7
     }
dab6d7
     /* map the ISO not logged in code to the coolkey one */
dab6d7
     if ((result == CKYISO_CONDITION_NOT_SATISFIED) ||
dab6d7
@@ -4610,13 +5145,10 @@ retry:
dab6d7
             throw PKCS11Exception(CKR_DATA_INVALID);
dab6d7
         }
dab6d7
         if (!isVersion1Key && !loginAttempted  &&
dab6d7
-            (result == CKYISO_UNAUTHORIZED)) {
dab6d7
+				userPinCache(key->getUser())->isValid() &&
dab6d7
+            				(result == CKYISO_UNAUTHORIZED)) {
dab6d7
 	    try {
dab6d7
-		if (state & GOV_CARD) {
dab6d7
-		    attemptCACLogin();
dab6d7
-		} else {
dab6d7
-		    oldAttemptLogin();
dab6d7
-		}
dab6d7
+		attemptLogin(key->getUser(), true);
dab6d7
 	    } catch(PKCS11Exception& ) {
dab6d7
               throw PKCS11Exception(CKR_DEVICE_ERROR);
dab6d7
 	    }
dab6d7
diff -up ./src/coolkey/slot.h.p15 ./src/coolkey/slot.h
dab6d7
--- ./src/coolkey/slot.h.p15	2015-07-06 10:27:55.772827229 -0700
dab6d7
+++ ./src/coolkey/slot.h	2015-07-06 10:27:55.786826965 -0700
dab6d7
@@ -183,7 +183,7 @@ struct PinCache {
dab6d7
 	CKYBuffer_Replace(&cachedPin, 0, (const CKYByte *)newPin, pinLen);
dab6d7
 	CKYBuffer_AppendChar(&cachedPin, 0);
dab6d7
     }
dab6d7
-    void clearPin() { CKYBuffer_Zero(&cachedPin); }
dab6d7
+    void clearPin() { CKYBuffer_Zero(&cachedPin); valid = false; }
dab6d7
     void invalidate() { valid = false; }
dab6d7
     void validate() { valid = true; }
dab6d7
     const CKYBuffer *get() const { return &cachedPin; }
dab6d7
@@ -209,29 +209,26 @@ class CryptOpState {
dab6d7
   public:
dab6d7
     enum State { NOT_INITIALIZED, IN_PROCESS, FINALIZED };
dab6d7
     State state;
dab6d7
-    CKYByte keyNum;
dab6d7
     CKYBuffer result;
dab6d7
-    PKCS11Object::KeyType keyType;
dab6d7
+    PKCS11Object *key;
dab6d7
 
dab6d7
-    CryptOpState() : state(NOT_INITIALIZED), keyNum(0), keyType(PKCS11Object::unknown)
dab6d7
+    CryptOpState() : state(NOT_INITIALIZED), key(NULL)
dab6d7
 				{ CKYBuffer_InitEmpty(&result); }
dab6d7
     CryptOpState(const CryptOpState &cpy) : 
dab6d7
-				state(cpy.state), keyNum(cpy.keyNum), keyType(cpy.keyType) { 
dab6d7
+				state(cpy.state), key(cpy.key) { 
dab6d7
 	CKYBuffer_InitFromCopy(&result, &cpy.result);
dab6d7
     }
dab6d7
     CryptOpState &operator=(const CryptOpState &cpy) {
dab6d7
 	state = cpy.state,
dab6d7
-	keyNum = cpy.keyNum;
dab6d7
-        keyType = cpy.keyType;
dab6d7
+        key = cpy.key;
dab6d7
 	CKYBuffer_Replace(&result, 0, CKYBuffer_Data(&cpy.result),
dab6d7
 				CKYBuffer_Size(&cpy.result));
dab6d7
 	return *this;
dab6d7
     }
dab6d7
     ~CryptOpState() { CKYBuffer_FreeData(&result); }
dab6d7
-    void initialize(CKYByte keyNum, PKCS11Object::KeyType theKeyType) {
dab6d7
+    void initialize(PKCS11Object *theKey) {
dab6d7
         state = IN_PROCESS;
dab6d7
-        this->keyNum = keyNum;
dab6d7
-        this->keyType = theKeyType;
dab6d7
+        this->key = theKey;
dab6d7
         CKYBuffer_Resize(&result, 0);
dab6d7
     }
dab6d7
 };
dab6d7
@@ -298,6 +295,7 @@ class CryptParams {
dab6d7
 };
dab6d7
 
dab6d7
 #define MAX_CERT_SLOTS 3
dab6d7
+#define MAX_AUTH_USERS 3
dab6d7
 class Slot {
dab6d7
 
dab6d7
   public:
dab6d7
@@ -308,7 +306,8 @@ class Slot {
dab6d7
         APPLET_SELECTABLE = 0x08,
dab6d7
         APPLET_PERSONALIZED = 0x10,
dab6d7
         CAC_CARD = 0x20,
dab6d7
-        PIV_CARD = 0x40
dab6d7
+        PIV_CARD = 0x40,
dab6d7
+	P15_CARD = 0x80
dab6d7
     };
dab6d7
     enum {
dab6d7
 	NONCE_SIZE = 8
dab6d7
@@ -321,6 +320,7 @@ class Slot {
dab6d7
     char *readerName;
dab6d7
     char *personName;
dab6d7
     char *manufacturer;
dab6d7
+    char *tokenManufacturer;
dab6d7
     //char *model;
dab6d7
     CK_VERSION hwVersion;
dab6d7
     CK_VERSION tokenFWVersion;
dab6d7
@@ -329,6 +329,7 @@ class Slot {
dab6d7
     CKYCardConnection* conn;
dab6d7
     unsigned long state; // = UNKNOWN
dab6d7
     PinCache pinCache;
dab6d7
+    PinCache contextPinCache;
dab6d7
     bool loggedIn;
dab6d7
     bool reverify;
dab6d7
     bool nonceValid;
dab6d7
@@ -349,6 +350,14 @@ class Slot {
dab6d7
     int pivContainer;
dab6d7
     int pivKey;
dab6d7
     bool mECC;
dab6d7
+    unsigned short p15aid;
dab6d7
+    unsigned short p15odfAddr;
dab6d7
+    unsigned short p15tokenInfoAddr;
dab6d7
+    unsigned int p15Instance;
dab6d7
+    CKYBuffer p15AID;
dab6d7
+    CKYBuffer p15tokenInfo;
dab6d7
+    CKYBuffer p15odf;
dab6d7
+    CKYBuffer p15serialNumber;
dab6d7
     //enum { RW_SESSION_HANDLE = 1, RO_SESSION_HANDLE = 2 };
dab6d7
 
dab6d7
 #ifdef USE_SHMEM
dab6d7
@@ -367,6 +376,7 @@ class Slot {
dab6d7
 
dab6d7
     void closeAllSessions();
dab6d7
     SessionHandleSuffix generateNewSession(Session::Type type);
dab6d7
+    PK15Object *auth[MAX_AUTH_USERS];
dab6d7
 
dab6d7
     bool cardStateMayHaveChanged();
dab6d7
     void connectToToken();
dab6d7
@@ -418,48 +428,63 @@ class Slot {
dab6d7
                               bool throwException);
dab6d7
     CKYStatus readCACCertificateAppend(CKYBuffer *cert, CKYSize nextSize);
dab6d7
 
dab6d7
+    CKYStatus getP15Params();
dab6d7
     void selectApplet();
dab6d7
     void selectCACApplet(CKYByte instance,bool do_disconnect);
dab6d7
+    void selectKey(const PKCS11Object *key, bool retry);
dab6d7
+    CKYStatus selectPath(const CKYBuffer *path, CKYISOStatus *adpurc);
dab6d7
+    CKYStatus readFromPath(const PK15ObjectPath &obj, CKYBuffer *file);
dab6d7
     void unloadObjects();
dab6d7
     void loadCACObjects();
dab6d7
     void loadCACCert(CKYByte instance);
dab6d7
     void loadObjects();
dab6d7
     void loadReaderObject();
dab6d7
 
dab6d7
-    void attemptLogin(const char *pin);
dab6d7
+    void attemptCoolKeyLogin(const char *pin);
dab6d7
+    void attemptLogin(CK_USER_TYPE user, bool flushPin);
dab6d7
+    void attemptP15Login(CK_USER_TYPE user);
dab6d7
     void attemptCACLogin();
dab6d7
     void oldAttemptLogin();
dab6d7
     void oldLogout(void);
dab6d7
     void CACLogout(void);
dab6d7
+    PinCache *userPinCache(CK_USER_TYPE user) {
dab6d7
+	return ((user == CKU_CONTEXT_SPECIFIC) && (state & P15_CARD)) ?
dab6d7
+		&contextPinCache : &pinCache; }
dab6d7
+
dab6d7
+    void parseEF_ODF(void);
dab6d7
+    void parseEF_TokenInfo(void);
dab6d7
+    CKYStatus parseEF_Directory(const CKYByte *data, CKYSize size, 
dab6d7
+				PK15ObjectType type);
dab6d7
+    unsigned int PK15Instance(void) { return p15Instance++; }
dab6d7
 
dab6d7
     void readMuscleObject(CKYBuffer *obj, unsigned long objID, 
dab6d7
 							unsigned int objSize);
dab6d7
 
dab6d7
     void performSignature(CKYBuffer *sig, const CKYBuffer *unpaddedInput, 
dab6d7
-							CKYByte keyNum);
dab6d7
-    void performDecryption(CKYBuffer *data, const CKYBuffer *input, CKYByte keyNum);
dab6d7
+						const PKCS11Object *key);
dab6d7
+    void performDecryption(CKYBuffer *data, const CKYBuffer *input, 
dab6d7
+						const PKCS11Object *key);
dab6d7
 
dab6d7
     void cryptRSA(SessionHandleSuffix suffix, CK_BYTE_PTR pInput,
dab6d7
         CK_ULONG ulInputLen, CK_BYTE_PTR pOutput,
dab6d7
         CK_ULONG_PTR pulOutputLen, CryptParams& params);
dab6d7
 
dab6d7
-    void performRSAOp(CKYBuffer *out, const CKYBuffer *input, unsigned int keySize,
dab6d7
-						CKYByte keyNum, CKYByte direction);
dab6d7
+    void performRSAOp(CKYBuffer *out, const CKYBuffer *input, 
dab6d7
+	unsigned int keySize, const PKCS11Object *key, CKYByte direction);
dab6d7
 
dab6d7
     void signECC(SessionHandleSuffix suffix, CK_BYTE_PTR pInput,
dab6d7
         CK_ULONG ulInputLen, CK_BYTE_PTR pOutput,
dab6d7
         CK_ULONG_PTR pulOutputLen, CryptParams& params);
dab6d7
 
dab6d7
     void performECCSignature(CKYBuffer *out, const CKYBuffer *input, 
dab6d7
-					unsigned int keySize, CKYByte keyNum);
dab6d7
+				unsigned int keySize, const PKCS11Object *key);
dab6d7
     void performECCKeyAgreement(CK_MECHANISM_TYPE deriveMech, 
dab6d7
-        CKYBuffer *publicDataBuffer, 
dab6d7
-        CKYBuffer *secretKeyBuffer, CKYByte keyNum, unsigned int keySize);
dab6d7
+        CKYBuffer *publicDataBuffer, CKYBuffer *secretKeyBuffer, 
dab6d7
+	const PKCS11Object *key, 	unsigned int keySize);
dab6d7
 
dab6d7
     void processComputeCrypt(CKYBuffer *result, const CKYAPDU *apdu);
dab6d7
 
dab6d7
-    CKYByte objectHandleToKeyNum(CK_OBJECT_HANDLE hKey);
dab6d7
-    unsigned int calcECCKeySize(CKYByte keyNum);
dab6d7
+    CKYByte objectToKeyNum(const PKCS11Object *key);
dab6d7
     Slot(const Slot &cpy)
dab6d7
 #ifdef USE_SHMEM
dab6d7
 	: shmem(readerName)
dab6d7
@@ -491,10 +516,10 @@ class Slot {
dab6d7
     }
dab6d7
 
dab6d7
     // actually get the size of a key in bits from the card
dab6d7
-    unsigned int getRSAKeySize(CKYByte keyNum);
dab6d7
-    unsigned int getECCKeySize(CKYByte keyNum);
dab6d7
+    unsigned int getRSAKeySize(PKCS11Object *key);
dab6d7
+    unsigned int getECCKeySize(PKCS11Object *key);
dab6d7
 
dab6d7
-    PKCS11Object::KeyType  getKeyTypeFromHandle(CK_OBJECT_HANDLE hKey);
dab6d7
+    PKCS11Object *getKeyFromHandle(CK_OBJECT_HANDLE hKey);
dab6d7
 
dab6d7
     SessionHandleSuffix openSession(Session::Type type);
dab6d7
     void closeSession(SessionHandleSuffix handleSuffix);
dab6d7
@@ -504,8 +529,8 @@ class Slot {
dab6d7
     void getSessionInfo(SessionHandleSuffix handleSuffix,
dab6d7
         CK_SESSION_INFO_PTR pInfo);
dab6d7
 
dab6d7
-    void login(SessionHandleSuffix handleSuffix, CK_UTF8CHAR_PTR pPin,
dab6d7
-        CK_ULONG ulPinLen);
dab6d7
+    void login(SessionHandleSuffix handleSuffix, CK_USER_TYPE user,
dab6d7
+	CK_UTF8CHAR_PTR pPin, CK_ULONG ulPinLen);
dab6d7
 
dab6d7
     void logout(SessionHandleSuffix suffix);
dab6d7
 
dab6d7
@@ -604,8 +629,8 @@ class SlotList {
dab6d7
     void getSessionInfo(CK_SESSION_HANDLE sessionHandle,
dab6d7
         CK_SESSION_INFO_PTR pInfo);
dab6d7
 
dab6d7
-    void login(CK_SESSION_HANDLE hSession, CK_UTF8CHAR_PTR pPin,
dab6d7
-        CK_ULONG ulPinLen);
dab6d7
+    void login(CK_SESSION_HANDLE hSession, CK_USER_TYPE user,
dab6d7
+	CK_UTF8CHAR_PTR pPin, CK_ULONG ulPinLen);
dab6d7
 
dab6d7
     void logout(CK_SESSION_HANDLE hSession);
dab6d7
 
dab6d7
diff -up ./src/libckyapplet/cky_applet.c.p15 ./src/libckyapplet/cky_applet.c
dab6d7
--- ./src/libckyapplet/cky_applet.c.p15	2015-07-06 10:27:55.775827172 -0700
dab6d7
+++ ./src/libckyapplet/cky_applet.c	2015-07-06 10:27:55.787826946 -0700
dab6d7
@@ -19,6 +19,7 @@
dab6d7
 
dab6d7
 #include <stdio.h>
dab6d7
 #include "cky_applet.h"
dab6d7
+#include <string.h>
dab6d7
 
dab6d7
 #define MIN(x, y) ((x) < (y) ? (x) : (y))
dab6d7
 
dab6d7
@@ -51,6 +52,12 @@ CACAppletFactory_SelectFile(CKYAPDU *apd
dab6d7
 }
dab6d7
 
dab6d7
 CKYStatus
dab6d7
+P15AppletFactory_SelectFile(CKYAPDU *apdu, const void *param)
dab6d7
+{
dab6d7
+    return CKYAPDUFactory_SelectFile(apdu, 0, 0, (const CKYBuffer *)param);
dab6d7
+}
dab6d7
+
dab6d7
+CKYStatus
dab6d7
 CKYAppletFactory_SelectCardManager(CKYAPDU *apdu, const void *param)
dab6d7
 {
dab6d7
     return CKYAPDUFactory_SelectCardManager(apdu);
dab6d7
@@ -269,17 +276,10 @@ PIVAppletFactory_SignDecrypt(CKYAPDU *ap
dab6d7
 }
dab6d7
 
dab6d7
 CKYStatus
dab6d7
-CACAppletFactory_VerifyPIN(CKYAPDU *apdu, const void *param)
dab6d7
+P15AppletFactory_VerifyPIN(CKYAPDU *apdu, const void *param)
dab6d7
 {
dab6d7
-    const char *pin=(const char *)param;
dab6d7
-    return CACAPDUFactory_VerifyPIN(apdu, CAC_LOGIN_GLOBAL, pin);
dab6d7
-}
dab6d7
-
dab6d7
-CKYStatus
dab6d7
-PIVAppletFactory_VerifyPIN(CKYAPDU *apdu, const void *param)
dab6d7
-{
dab6d7
-    const char *pin=(const char *)param;
dab6d7
-    return CACAPDUFactory_VerifyPIN(apdu, PIV_LOGIN_LOCAL, pin);
dab6d7
+    const P15AppletArgVerifyPIN *vps = (const P15AppletArgVerifyPIN *)param;
dab6d7
+    return P15APDUFactory_VerifyPIN(apdu, vps->pinRef, vps->pinVal);
dab6d7
 }
dab6d7
 
dab6d7
 CKYStatus
dab6d7
@@ -323,6 +323,39 @@ CKYAppletFactory_LogoutAllV0(CKYAPDU *ap
dab6d7
    return CKYAPDU_SetSendData(apdu, data, sizeof(data));
dab6d7
 }
dab6d7
 
dab6d7
+CKYStatus
dab6d7
+P15AppletFactory_ReadRecord(CKYAPDU *apdu, const void *param)
dab6d7
+{
dab6d7
+    const P15AppletArgReadRecord *rrs = (const P15AppletArgReadRecord *)param;
dab6d7
+    return P15APDUFactory_ReadRecord(apdu, rrs->record,
dab6d7
+					rrs->short_ef, rrs->flags, rrs->size);
dab6d7
+}
dab6d7
+
dab6d7
+CKYStatus
dab6d7
+P15AppletFactory_ReadBinary(CKYAPDU *apdu, const void *param)
dab6d7
+{
dab6d7
+    const P15AppletArgReadBinary *res = (const P15AppletArgReadBinary *)param;
dab6d7
+    return P15APDUFactory_ReadBinary(apdu, res->offset,
dab6d7
+					res->short_ef, res->flags, res->size);
dab6d7
+}
dab6d7
+
dab6d7
+CKYStatus
dab6d7
+P15AppletFactory_ManageSecurityEnvironment(CKYAPDU *apdu, const void *param)
dab6d7
+{
dab6d7
+    const P15AppletArgManageSecurityEnvironment *mse = 
dab6d7
+		(const P15AppletArgManageSecurityEnvironment *)param;
dab6d7
+    return P15APDUFactory_ManageSecurityEnvironment(apdu, mse->p1, 
dab6d7
+						mse->p2, mse->keyRef);
dab6d7
+}
dab6d7
+
dab6d7
+CKYStatus
dab6d7
+P15AppletFactory_PerformSecurityOperation(CKYAPDU *apdu, const void *param)
dab6d7
+{
dab6d7
+    const P15AppletArgPerformSecurityOperation *pso = 
dab6d7
+		(const P15AppletArgPerformSecurityOperation *)param;
dab6d7
+    return P15APDUFactory_PerformSecurityOperation(apdu, pso->dir, pso->chain,
dab6d7
+						   pso->retLen, pso->data);
dab6d7
+}
dab6d7
 /*****************************************************************
dab6d7
  *
dab6d7
  * Generic Fill routines used by several calls in common
dab6d7
@@ -975,9 +1008,6 @@ CKYApplet_ComputeECCSignature(CKYCardCon
dab6d7
     const CKYBuffer *data, CKYBuffer *sig,
dab6d7
     CKYBuffer *result, const CKYBuffer *nonce, CKYISOStatus *apduRC)
dab6d7
 {
dab6d7
-    int         use2APDUs = 0;
dab6d7
-    int         use_dl_object =  0; 
dab6d7
-    short       dataSize = 0;
dab6d7
     CKYStatus ret = CKYAPDUFAIL;
dab6d7
     CKYAppletArgComputeECCSignature ccd;
dab6d7
     CKYBuffer    empty;
dab6d7
@@ -1052,6 +1082,11 @@ done:
dab6d7
     return ret;
dab6d7
 }
dab6d7
 
dab6d7
+const P15PinInfo CACPinInfo = 
dab6d7
+   { P15PinInitialized|P15PinNeedsPadding, P15PinUTF8, 0, 8, 8, 0, 0xff };
dab6d7
+const P15PinInfo PIVPinInfo = 
dab6d7
+   { P15PinLocal|P15PinInitialized|P15PinNeedsPadding, 
dab6d7
+					   P15PinUTF8, 0, 8, 8, 0, 0xff };
dab6d7
 /*
dab6d7
  * do a CAC VerifyPIN
dab6d7
  */
dab6d7
@@ -1059,23 +1094,8 @@ CKYStatus
dab6d7
 CACApplet_VerifyPIN(CKYCardConnection *conn, const char *pin, int local,
dab6d7
 		    CKYISOStatus *apduRC)
dab6d7
 {
dab6d7
-    CKYStatus ret;
dab6d7
-    CKYISOStatus status;
dab6d7
-    if (apduRC == NULL) {
dab6d7
-	apduRC = &status;
dab6d7
-    }
dab6d7
-
dab6d7
-    ret = CKYApplet_HandleAPDU(conn, local ? PIVAppletFactory_VerifyPIN :
dab6d7
-			    CACAppletFactory_VerifyPIN, pin, NULL, 
dab6d7
-			    0, CKYAppletFill_Null, 
dab6d7
-			    NULL, apduRC);
dab6d7
-    /* it's unfortunate that the same code that means 'more data to follow' for
dab6d7
-     * GetCertificate also means, auth failure, you only have N more attempts
dab6d7
-     * left in the verify PIN call */
dab6d7
-    if ((*apduRC & CKYISO_MORE_MASK) == CKYISO_MORE) {
dab6d7
-	ret = CKYAPDUFAIL;
dab6d7
-    }
dab6d7
-    return ret;
dab6d7
+    return P15Applet_VerifyPIN(conn, pin, 
dab6d7
+				local ? &PIVPinInfo: &CACPinInfo, apduRC);
dab6d7
 }
dab6d7
 
dab6d7
 
dab6d7
@@ -1165,6 +1185,214 @@ CACApplet_ReadFile(CKYCardConnection *co
dab6d7
     return ret;
dab6d7
 }
dab6d7
 
dab6d7
+/*
dab6d7
+ *  Select a EF
dab6d7
+ */
dab6d7
+CKYStatus
dab6d7
+P15Applet_SelectFile(CKYCardConnection *conn, unsigned short ef,
dab6d7
+						 CKYISOStatus *apduRC)
dab6d7
+{
dab6d7
+    CKYStatus ret;
dab6d7
+    CKYBuffer efBuf;
dab6d7
+    CKYBuffer_InitEmpty(&efBuf);
dab6d7
+    CKYBuffer_AppendShort(&efBuf, ef);
dab6d7
+    ret = CKYApplet_HandleAPDU(conn, P15AppletFactory_SelectFile, &efBuf,
dab6d7
+		 NULL, CKY_SIZE_UNKNOWN, CKYAppletFill_Null, NULL, apduRC);
dab6d7
+    CKYBuffer_FreeData(&efBuf);
dab6d7
+    return ret;
dab6d7
+}
dab6d7
+
dab6d7
+CKYStatus
dab6d7
+P15Applet_SelectRootFile(CKYCardConnection *conn, unsigned short ef,
dab6d7
+						 CKYISOStatus *apduRC)
dab6d7
+{
dab6d7
+    CKYStatus ret;
dab6d7
+    CKYBuffer efBuf;
dab6d7
+    CKYBuffer_InitEmpty(&efBuf);
dab6d7
+    CKYBuffer_AppendShort(&efBuf, ef);
dab6d7
+    ret = CKYApplet_HandleAPDU(conn, CKYAppletFactory_SelectFile, &efBuf,
dab6d7
+		 NULL, CKY_SIZE_UNKNOWN, CKYAppletFill_Null, NULL, apduRC);
dab6d7
+    CKYBuffer_FreeData(&efBuf);
dab6d7
+    return ret;
dab6d7
+}
dab6d7
+
dab6d7
+CKYStatus
dab6d7
+P15Applet_VerifyPIN(CKYCardConnection *conn, const char *pin, 
dab6d7
+			const P15PinInfo *pinInfo, CKYISOStatus *apduRC)
dab6d7
+{
dab6d7
+    CKYStatus ret;
dab6d7
+    CKYISOStatus status;
dab6d7
+    CKYSize size;
dab6d7
+    CKYBuffer encodedPin;
dab6d7
+    P15AppletArgVerifyPIN vps;
dab6d7
+
dab6d7
+    CKYBuffer_InitEmpty(&encodedPin);
dab6d7
+
dab6d7
+    if (apduRC == NULL) {
dab6d7
+	apduRC = &status;
dab6d7
+    }
dab6d7
+
dab6d7
+    size = strlen(pin);
dab6d7
+    if (pinInfo->pinFlags & P15PinNeedsPadding) {
dab6d7
+	if (size > pinInfo->storedLength) {
dab6d7
+	    size = pinInfo->storedLength;
dab6d7
+	}
dab6d7
+	ret=CKYBuffer_Reserve(&encodedPin, pinInfo->storedLength);
dab6d7
+	if (ret != CKYSUCCESS) { goto fail; }
dab6d7
+    }
dab6d7
+    /* This is where we would do upcase processing for the case insensitive 
dab6d7
+     * flag. It's also where we would do mapping for bcd pins */
dab6d7
+    ret = CKYBuffer_Replace(&encodedPin, 0, (const CKYByte *)pin, size);
dab6d7
+    if (ret != CKYSUCCESS) { goto fail; }
dab6d7
+    if (pinInfo->pinFlags & P15PinNeedsPadding) {
dab6d7
+	int i; 
dab6d7
+	int padSize = pinInfo->storedLength - size;
dab6d7
+	for (i=0; i < padSize; i++) {
dab6d7
+	    CKYBuffer_AppendChar(&encodedPin, pinInfo->padChar);
dab6d7
+	}
dab6d7
+    }
dab6d7
+
dab6d7
+    vps.pinRef = pinInfo->pinRef | 
dab6d7
+     ((pinInfo->pinFlags & P15PinLocal) ? ISO_LOGIN_LOCAL : ISO_LOGIN_GLOBAL);
dab6d7
+    vps.pinVal = &encodedPin;
dab6d7
+    ret = CKYApplet_HandleAPDU(conn, P15AppletFactory_VerifyPIN, &vps, NULL, 
dab6d7
+			    0, CKYAppletFill_Null, 
dab6d7
+			    NULL, apduRC);
dab6d7
+    /* it's unfortunate that the same code that means 'more data to follow' for
dab6d7
+     * GetCertificate also means, auth failure, you only have N more attempts
dab6d7
+     * left in the verify PIN call */
dab6d7
+    if ((*apduRC & CKYISO_MORE_MASK) == CKYISO_MORE) {
dab6d7
+	ret = CKYAPDUFAIL;
dab6d7
+    }
dab6d7
+fail:
dab6d7
+    CKYBuffer_FreeData(&encodedPin);
dab6d7
+    return ret;
dab6d7
+}
dab6d7
+
dab6d7
+
dab6d7
+/*
dab6d7
+ * Read Record
dab6d7
+ */
dab6d7
+CKYStatus
dab6d7
+P15Applet_ReadRecord(CKYCardConnection *conn, CKYByte record, CKYByte short_ef,
dab6d7
+		CKYByte flags, CKYByte size, CKYBuffer *data, CKYISOStatus *apduRC)
dab6d7
+{
dab6d7
+    P15AppletArgReadRecord rrd;
dab6d7
+
dab6d7
+    rrd.record = record;
dab6d7
+    rrd.short_ef = short_ef;
dab6d7
+    rrd.flags = flags;
dab6d7
+    rrd.size = size;
dab6d7
+    return CKYApplet_HandleAPDU(conn, P15AppletFactory_ReadRecord, &rrd, NULL,
dab6d7
+	CKY_SIZE_UNKNOWN, CKYAppletFill_ReplaceBuffer, data, apduRC);
dab6d7
+}
dab6d7
+
dab6d7
+static CKYStatus
dab6d7
+P15Applet_ManageSecurityEnvironment(CKYCardConnection *conn, CKYByte key,
dab6d7
+				 CKYByte direction, CKYByte p1, 
dab6d7
+				 CKYISOStatus *apduRC)
dab6d7
+{
dab6d7
+    P15AppletArgManageSecurityEnvironment mse;
dab6d7
+
dab6d7
+    mse.p1 = p1; /* this appears to be where most cards disagree */
dab6d7
+    mse.p2 = (direction == CKY_DIR_DECRYPT) ? ISO_MSE_KEA : ISO_MSE_SIGN;
dab6d7
+    mse.keyRef = key; /* should be CKYBuffer in the future? */
dab6d7
+    return CKYApplet_HandleAPDU(conn, 
dab6d7
+		P15AppletFactory_ManageSecurityEnvironment, &mse, NULL,
dab6d7
+		CKY_SIZE_UNKNOWN, CKYAppletFill_Null, NULL, apduRC);
dab6d7
+}
dab6d7
+
dab6d7
+CKYStatus
dab6d7
+P15Applet_SignDecrypt(CKYCardConnection *conn, CKYByte key, 
dab6d7
+		unsigned int keySize, CKYByte direction, 
dab6d7
+		const CKYBuffer *data, CKYBuffer *result, CKYISOStatus *apduRC)
dab6d7
+{
dab6d7
+    CKYStatus ret;
dab6d7
+    P15AppletArgPerformSecurityOperation pso;
dab6d7
+    CKYSize dataSize = CKYBuffer_Size(data);
dab6d7
+    CKYOffset offset = 0;
dab6d7
+    CKYBuffer tmp;
dab6d7
+    int length = dataSize;
dab6d7
+    int appendLength = length;
dab6d7
+    int hasPad = 0;
dab6d7
+
dab6d7
+    /* Hack, lie and say we are always doing encipherment */
dab6d7
+    direction = CKY_DIR_DECRYPT;
dab6d7
+    CKYBuffer_Resize(result,0);
dab6d7
+    /*
dab6d7
+     * first set the security environment
dab6d7
+     */
dab6d7
+    ret = P15Applet_ManageSecurityEnvironment(conn, key, direction, 
dab6d7
+			ISO_MSE_SET|ISO_MSE_QUAL_COMPUTE, apduRC);
dab6d7
+    if (ret != CKYSUCCESS) {
dab6d7
+	return ret;
dab6d7
+    }
dab6d7
+
dab6d7
+    CKYBuffer_InitEmpty(&tmp);
dab6d7
+
dab6d7
+    pso.data = &tm;;
dab6d7
+    pso.dir = direction;
dab6d7
+    if (direction == CKY_DIR_DECRYPT) {
dab6d7
+	length++;
dab6d7
+	CKYBuffer_AppendChar(&tmp, 0x00); /* pad byte */
dab6d7
+	hasPad = 1;
dab6d7
+    }
dab6d7
+    if (CKYCardConnection_GetProtocol(conn) == SCARD_PROTOCOL_T0) {
dab6d7
+	ret = CKYBuffer_Reserve(&tmp, CKY_MAX_WRITE_CHUNK_SIZE);
dab6d7
+	if (ret != CKYSUCCESS) {
dab6d7
+	    goto done;
dab6d7
+	}
dab6d7
+	for(offset = 0; length > CKY_MAX_WRITE_CHUNK_SIZE; 
dab6d7
+					hasPad = 0,
dab6d7
+					offset += CKY_MAX_WRITE_CHUNK_SIZE, 
dab6d7
+					length -= CKY_MAX_WRITE_CHUNK_SIZE) {
dab6d7
+	    pso.chain = 1;
dab6d7
+	    pso.retLen = 0;
dab6d7
+	    CKYBuffer_AppendBuffer(&tmp, data, offset, 
dab6d7
+	     hasPad ? (CKY_MAX_WRITE_CHUNK_SIZE-1) : CKY_MAX_WRITE_CHUNK_SIZE);
dab6d7
+            ret = CKYApplet_HandleAPDU(conn, 
dab6d7
+			P15AppletFactory_PerformSecurityOperation, &pso, NULL, 
dab6d7
+			CKY_SIZE_UNKNOWN, CKYAppletFill_Null, NULL, apduRC);
dab6d7
+	    if (ret != CKYSUCCESS) {
dab6d7
+		goto done;
dab6d7
+	    }
dab6d7
+	    CKYBuffer_Resize(&tmp, 0);
dab6d7
+	}
dab6d7
+	appendLength = length;
dab6d7
+    } else {
dab6d7
+	ret = CKYBuffer_Reserve(&tmp, length);
dab6d7
+    }
dab6d7
+    CKYBuffer_AppendBuffer(&tmp, data, offset, appendLength);
dab6d7
+    pso.chain = 0;
dab6d7
+    pso.retLen = dataSize;
dab6d7
+
dab6d7
+    ret = CKYApplet_HandleAPDU(conn, 
dab6d7
+		P15AppletFactory_PerformSecurityOperation, &pso, NULL, 
dab6d7
+	CKY_SIZE_UNKNOWN, CKYAppletFill_ReplaceBuffer, result, apduRC);
dab6d7
+
dab6d7
+done:
dab6d7
+    CKYBuffer_FreeData(&tmp);
dab6d7
+    return ret;
dab6d7
+}
dab6d7
+
dab6d7
+/*
dab6d7
+ * Read Binary
dab6d7
+ */
dab6d7
+CKYStatus
dab6d7
+P15Applet_ReadBinary(CKYCardConnection *conn, unsigned short offset,
dab6d7
+			CKYByte short_ef, CKYByte flags, CKYByte size, 
dab6d7
+			CKYBuffer *data, CKYISOStatus *apduRC)
dab6d7
+{
dab6d7
+    P15AppletArgReadBinary red;
dab6d7
+
dab6d7
+    red.offset = offset;
dab6d7
+    red.short_ef = short_ef;
dab6d7
+    red.flags = flags;
dab6d7
+    red.size = size;
dab6d7
+    return CKYApplet_HandleAPDU(conn, P15AppletFactory_ReadBinary, &red, NULL,
dab6d7
+	CKY_SIZE_UNKNOWN, CKYAppletFill_AppendBuffer, data, apduRC);
dab6d7
+}
dab6d7
+
dab6d7
 CKYStatus 
dab6d7
 CACApplet_GetCertificateFirst(CKYCardConnection *conn, CKYBuffer *cert, 
dab6d7
 			CKYSize *nextSize, CKYISOStatus *apduRC)
dab6d7
@@ -1632,6 +1860,7 @@ CKYApplet_ReadObjectFull(CKYCardConnecti
dab6d7
     return ret;
dab6d7
 }
dab6d7
 
dab6d7
+
dab6d7
 /*
dab6d7
  * Write Object
dab6d7
  * This makes multiple APDU calls to write the entire object.
dab6d7
diff -up ./src/libckyapplet/cky_applet.h.p15 ./src/libckyapplet/cky_applet.h
dab6d7
--- ./src/libckyapplet/cky_applet.h.p15	2015-07-06 10:27:55.776827153 -0700
dab6d7
+++ ./src/libckyapplet/cky_applet.h	2015-07-06 10:27:55.788826927 -0700
dab6d7
@@ -204,6 +204,7 @@ typedef struct _CKYAppletArgReadObject {
dab6d7
     CKYByte         size;
dab6d7
 } CKYAppletArgReadObject;
dab6d7
 
dab6d7
+
dab6d7
 typedef struct _CKYAppletArgWriteObject {
dab6d7
     unsigned long objectID;
dab6d7
     CKYOffset     offset;
dab6d7
@@ -262,6 +263,39 @@ typedef struct _PIVAppletRespSignDecrypt
dab6d7
      CKYBuffer  *buf;
dab6d7
 } PIVAppletRespSignDecrypt;
dab6d7
 
dab6d7
+typedef struct _P15AppletArgReadRecord {
dab6d7
+    CKYByte	    record;
dab6d7
+    CKYByte         short_ef;
dab6d7
+    CKYByte         flags;
dab6d7
+    CKYByte         size;
dab6d7
+} P15AppletArgReadRecord;
dab6d7
+
dab6d7
+typedef struct _P15AppletArgReadBinary {
dab6d7
+    unsigned short    offset;
dab6d7
+    CKYByte         short_ef;
dab6d7
+    CKYByte         flags;
dab6d7
+    CKYByte         size;
dab6d7
+} P15AppletArgReadBinary;
dab6d7
+
dab6d7
+typedef struct _P15AppletArgVerifyPIN {
dab6d7
+    const  CKYBuffer *pinVal;
dab6d7
+    CKYByte pinRef;
dab6d7
+} P15AppletArgVerifyPIN;
dab6d7
+
dab6d7
+typedef struct _P15AppletArgManageSecurityEnvironment {
dab6d7
+    CKYByte p1;
dab6d7
+    CKYByte p2;
dab6d7
+    CKYByte keyRef;
dab6d7
+}
dab6d7
+ P15AppletArgManageSecurityEnvironment;
dab6d7
+
dab6d7
+typedef struct _P15AppletArgPerformSecurityOperation {
dab6d7
+    CKYByte dir;
dab6d7
+    int     chain;
dab6d7
+    CKYSize retLen;
dab6d7
+    const CKYBuffer *data;
dab6d7
+} P15AppletArgPerformSecurityOperation;
dab6d7
+
dab6d7
 /* fills in an APDU from a structure -- form of all the generic factories*/
dab6d7
 typedef CKYStatus (*CKYAppletFactory)(CKYAPDU *apdu, const void *param);
dab6d7
 /* fills in an a structure from a response -- form of all the fill structures*/
dab6d7
@@ -514,6 +548,7 @@ CKYStatus CACApplet_ReadFile(CKYCardConn
dab6d7
 CKYStatus CACApplet_SelectFile(CKYCardConnection *conn, unsigned short ef,
dab6d7
 			     CKYISOStatus *apduRC);
dab6d7
 
dab6d7
+
dab6d7
 /* must happen with PKI applet selected */
dab6d7
 CKYStatus CACApplet_SignDecrypt(CKYCardConnection *conn, const CKYBuffer *data,
dab6d7
 		CKYBuffer *result, CKYISOStatus *apduRC);
dab6d7
@@ -539,6 +574,26 @@ CKYStatus PIVApplet_SignDecrypt(CKYCardC
dab6d7
 				   unsigned int keySize, int derive,
dab6d7
                                    const CKYBuffer *data, CKYBuffer *result, 
dab6d7
                                    CKYISOStatus *apduRC);
dab6d7
+
dab6d7
+/* PKCS Commands 15 */
dab6d7
+CKYStatus P15Applet_SelectFile(CKYCardConnection *conn, unsigned short ef,
dab6d7
+			     CKYISOStatus *apduRC);
dab6d7
+CKYStatus P15Applet_SelectRootFile(CKYCardConnection *conn, unsigned short ef,
dab6d7
+			     CKYISOStatus *apduRC);
dab6d7
+CKYStatus P15Applet_ReadRecord(CKYCardConnection *conn, CKYByte record, 
dab6d7
+		CKYByte short_ef, CKYByte flags, CKYByte size, CKYBuffer *data, 
dab6d7
+		CKYISOStatus *apduRC);
dab6d7
+CKYStatus P15Applet_ReadBinary(CKYCardConnection *conn, unsigned short offset, 
dab6d7
+		CKYByte short_ef, CKYByte flags, CKYByte size, CKYBuffer *data, 
dab6d7
+		CKYISOStatus *apduRC);
dab6d7
+CKYStatus P15Applet_VerifyPIN(CKYCardConnection *conn, const char *pin, 
dab6d7
+			const P15PinInfo *pinInfo, CKYISOStatus *apduRC);
dab6d7
+
dab6d7
+CKYStatus P15Applet_SignDecrypt(CKYCardConnection *conn, CKYByte key,
dab6d7
+				   unsigned int keySize, CKYByte direction,
dab6d7
+                                   const CKYBuffer *data, CKYBuffer *result, 
dab6d7
+                                   CKYISOStatus *apduRC);
dab6d7
+
dab6d7
 /*
dab6d7
  * There are 3 read commands:
dab6d7
  *  
dab6d7
diff -up ./src/libckyapplet/cky_base.c.p15 ./src/libckyapplet/cky_base.c
dab6d7
--- ./src/libckyapplet/cky_base.c.p15	2015-07-06 10:27:55.776827153 -0700
dab6d7
+++ ./src/libckyapplet/cky_base.c	2015-07-06 10:27:55.788826927 -0700
dab6d7
@@ -651,21 +651,38 @@ CKYStatus
dab6d7
 CKYAPDU_SetSendData(CKYAPDU *apdu, const CKYByte *data, CKYSize len)
dab6d7
 {
dab6d7
     CKYStatus ret;
dab6d7
+    CKYOffset offset = 0;
dab6d7
 
dab6d7
-    if (len > CKYAPDU_MAX_DATA_LEN) {
dab6d7
-	return CKYDATATOOLONG;
dab6d7
-    }
dab6d7
+    /* Encode with T1 if necessary */
dab6d7
 
dab6d7
-    ret = CKYBuffer_Resize(&apdu->apduBuf, len + CKYAPDU_HEADER_LEN);
dab6d7
-    if (ret != CKYSUCCESS) {
dab6d7
-	return ret;
dab6d7
+    if (len < CKYAPDU_MAX_DATA_LEN) {
dab6d7
+	offset = 0;
dab6d7
+        ret = CKYBuffer_Resize(&apdu->apduBuf, len+offset+CKYAPDU_HEADER_LEN);
dab6d7
+	if (ret != CKYSUCCESS ) {
dab6d7
+	    return ret;
dab6d7
+	}
dab6d7
+    	ret = CKYBuffer_SetChar(&apdu->apduBuf, CKY_LC_OFFSET, (CKYByte) len);
dab6d7
+    } else if (len < CKYAPDU_MAX_T1_DATA_LEN) {
dab6d7
+	offset = 2;
dab6d7
+        ret = CKYBuffer_Resize(&apdu->apduBuf, len+offset+CKYAPDU_HEADER_LEN);
dab6d7
+	if (ret != CKYSUCCESS ) {
dab6d7
+	    return ret;
dab6d7
+	}
dab6d7
+    	ret = CKYBuffer_SetChar(&apdu->apduBuf, CKY_LC_OFFSET, (CKYByte) 0);
dab6d7
+	if (ret != CKYSUCCESS) {
dab6d7
+	    return ret;
dab6d7
+	}
dab6d7
+        ret = CKYBuffer_SetShort(&apdu->apduBuf,CKY_LC_OFFSET+1,
dab6d7
+							(unsigned short)len);
dab6d7
+    } else {
dab6d7
+	return CKYDATATOOLONG;
dab6d7
     }
dab6d7
-    ret = CKYBuffer_SetChar(&apdu->apduBuf, CKY_LC_OFFSET,
dab6d7
-				len == CKYAPDU_MAX_DATA_LEN ? 0: (CKYByte) len);
dab6d7
+	
dab6d7
     if (ret != CKYSUCCESS) {
dab6d7
 	return ret;
dab6d7
     }
dab6d7
-    return CKYBuffer_Replace(&apdu->apduBuf, CKYAPDU_HEADER_LEN, data, len);
dab6d7
+    return CKYBuffer_Replace(&apdu->apduBuf, 
dab6d7
+				CKYAPDU_HEADER_LEN + offset , data, len);
dab6d7
 }
dab6d7
 
dab6d7
 CKYStatus
dab6d7
@@ -685,15 +702,15 @@ CKYAPDU_AppendSendData(CKYAPDU *apdu, co
dab6d7
     }
dab6d7
 
dab6d7
     dataLen = CKYBuffer_Size(&apdu->apduBuf) + len - CKYAPDU_HEADER_LEN;
dab6d7
-    if (dataLen > CKYAPDU_MAX_DATA_LEN) {
dab6d7
+    /* only handles T0 encoding, not T1 encoding */
dab6d7
+    if (dataLen >= CKYAPDU_MAX_DATA_LEN) {
dab6d7
 	return CKYDATATOOLONG;
dab6d7
     }
dab6d7
     ret = CKYBuffer_AppendData(&apdu->apduBuf, data, len);
dab6d7
     if (ret != CKYSUCCESS) {
dab6d7
 	return ret;
dab6d7
     }
dab6d7
-    return CKYBuffer_SetChar(&apdu->apduBuf, CKY_LC_OFFSET,
dab6d7
-			dataLen == CKYAPDU_MAX_DATA_LEN ? 0 : (CKYByte) dataLen);
dab6d7
+    return CKYBuffer_SetChar(&apdu->apduBuf, CKY_LC_OFFSET, (CKYByte) dataLen);
dab6d7
 }
dab6d7
 
dab6d7
 CKYStatus
dab6d7
@@ -714,11 +731,100 @@ CKYAPDU_SetReceiveLen(CKYAPDU *apdu, CKY
dab6d7
 }
dab6d7
 
dab6d7
 CKYStatus
dab6d7
+CKYAPDU_SetShortReceiveLen(CKYAPDU *apdu, unsigned short recvlen)
dab6d7
+{
dab6d7
+    CKYStatus ret;
dab6d7
+
dab6d7
+    if (recvlen <= CKYAPDU_MAX_DATA_LEN) {
dab6d7
+	return APDU_SetReceiveLen(apdu, (CKYByte)(recvlen & 0xff));
dab6d7
+    }
dab6d7
+    ret = CKYBuffer_Resize(&apdu->apduBuf, CKYAPDU_HEADER_LEN+2);
dab6d7
+    if (ret != CKYSUCCESS) {
dab6d7
+	return ret;
dab6d7
+    }
dab6d7
+    ret = CKYBuffer_SetChar(&apdu->apduBuf, CKY_LE_OFFSET, 0);
dab6d7
+    if (ret != CKYSUCCESS) {
dab6d7
+	return ret;
dab6d7
+    }
dab6d7
+    return CKYBuffer_SetShort(&apdu->apduBuf, CKY_LE_OFFSET+1, recvlen);
dab6d7
+}
dab6d7
+
dab6d7
+CKYStatus
dab6d7
+CKYAPDU_SetReceiveLength(CKYAPDU *apdu, CKYSize recvlen)
dab6d7
+{
dab6d7
+    if (recvlen <= CKYAPDU_MAX_T1_DATA_LEN) {
dab6d7
+	return CKYAPDU_SetShortReceiveLen(apdu, (unsigned short) 
dab6d7
+						(recvlen & 0xffff));
dab6d7
+    }
dab6d7
+    return CKYDATATOOLONG;
dab6d7
+}
dab6d7
+
dab6d7
+/*
dab6d7
+ *  Append Le, If Le=0, treat it as 256 (CKYAPD_MAX_DATA_LEN)
dab6d7
+ */
dab6d7
+CKYStatus
dab6d7
 CKYAPDU_AppendReceiveLen(CKYAPDU *apdu, CKYByte recvlen)
dab6d7
 {
dab6d7
+    /* If we already have a data buffer, make sure that we aren't already
dab6d7
+     * using T1 encoding */
dab6d7
+    if (CKYBuffer_Size(&apdu->apduBuf) > CKYAPDU_MIN_LEN) {
dab6d7
+	if (CKYBuffer_GetChar(&apdu->apduBuf, CKY_LC_OFFSET) == 0) {
dab6d7
+	    /* we are using T1 encoding, use AppendShort*/
dab6d7
+	    return CKYBuffer_AppendShort(&apdu->apduBuf, 
dab6d7
+		recvlen ? (unsigned short) recvlen: CKYAPDU_MAX_DATA_LEN);
dab6d7
+	}
dab6d7
+    }
dab6d7
     return CKYBuffer_AppendChar(&apdu->apduBuf, recvlen);
dab6d7
 }
dab6d7
 
dab6d7
+/*
dab6d7
+ * Append a short Le. If Le be encoded with just T0, do so. If Le=0 treat
dab6d7
+ * it as 65536 (CKYAPDU_MAX_T1_DATA_LEN)
dab6d7
+ */
dab6d7
+CKYStatus
dab6d7
+CKYAPDU_AppendShortReceiveLen(CKYAPDU *apdu, unsigned short recvlen)
dab6d7
+{
dab6d7
+    CKYStatus ret;
dab6d7
+    /* If we already have a data buffer, it's encoding affects ours */
dab6d7
+    if (CKYBuffer_Size(&apdu->apduBuf) > CKYAPDU_MIN_LEN) {
dab6d7
+	/* CKY_LC_OFFSET == 0 means T1, otherwise it's T0 */
dab6d7
+	if (CKYBuffer_GetChar(&apdu->apduBuf, CKY_LC_OFFSET) != 0) {
dab6d7
+	    /* remember 0 is 65536 here */
dab6d7
+	    if ((recvlen == 0) || (recvlen > CKYAPDU_MAX_DATA_LEN)) {
dab6d7
+		/* we can't a encode T1 receive length if we already have a
dab6d7
+ 		 * T0 encoded buffer data */
dab6d7
+		return CKYDATATOOLONG;
dab6d7
+	    }
dab6d7
+	    /* T0 encoding */
dab6d7
+	    return CKYBuffer_AppendChar(&apdu->apduBuf, (CKYByte)recvlen&0xff);
dab6d7
+	}
dab6d7
+	/* T1 encoding */
dab6d7
+	return CKYBuffer_AppendShort(&apdu->apduBuf, recvlen);
dab6d7
+    }
dab6d7
+    /* if length fits in a bit and we aren't forced into T1 encoding, use
dab6d7
+     * T0 */
dab6d7
+    if ((recvlen != 0) && (recvlen <= CKYAPDU_MAX_DATA_LEN)) {
dab6d7
+	return CKYBuffer_AppendChar(&apdu->apduBuf, (CKYByte)recvlen&0xff);
dab6d7
+    }
dab6d7
+    /* write the T1 encoding marker */
dab6d7
+    ret = CKYBuffer_AppendChar(&apdu->apduBuf, (CKYByte)0);
dab6d7
+    if (ret != CKYSUCCESS) {
dab6d7
+	return ret;
dab6d7
+    }
dab6d7
+    /* T1 encoded length */
dab6d7
+    return CKYBuffer_AppendShort(&apdu->apduBuf, recvlen);
dab6d7
+}
dab6d7
+
dab6d7
+CKYStatus
dab6d7
+CKYAPDU_AppendReceiveLength(CKYAPDU *apdu, CKYSize recvlen)
dab6d7
+{
dab6d7
+    if (recvlen > CKYAPDU_MAX_T1_DATA_LEN) {
dab6d7
+	return CKYDATATOOLONG;
dab6d7
+    }
dab6d7
+    return CKYAPDU_AppendShortReceiveLen(apdu, 
dab6d7
+					(unsigned short)(recvlen & 0xffff));
dab6d7
+}
dab6d7
+
dab6d7
 
dab6d7
 void
dab6d7
 CKY_SetName(const char *p)
dab6d7
diff -up ./src/libckyapplet/cky_base.h.p15 ./src/libckyapplet/cky_base.h
dab6d7
--- ./src/libckyapplet/cky_base.h.p15	2015-07-06 10:27:55.777827135 -0700
dab6d7
+++ ./src/libckyapplet/cky_base.h	2015-07-06 10:27:55.789826908 -0700
dab6d7
@@ -32,6 +32,8 @@ typedef unsigned char CKYByte;
dab6d7
 /* Bool type */
dab6d7
 typedef unsigned char CKYBool;
dab6d7
 
dab6d7
+typedef unsigned long CKYBitFlags;
dab6d7
+
dab6d7
 #define CKYBUFFER_PUBLIC \
dab6d7
     unsigned long reserved1;\
dab6d7
     unsigned long reserved2;\
dab6d7
@@ -93,6 +95,8 @@ typedef enum {
dab6d7
 			 * (command) sent. ADPUIOStatus has more info on
dab6d7
 			 * why the APDU failed */
dab6d7
     CKYINVALIDARGS,      /* Caller passed in bad args */
dab6d7
+    CKYINVALIDDATA,	/* Data supplied was invalid */
dab6d7
+    CKYUNSUPPORTED,	/* Requested Operation or feature is not supported */
dab6d7
 } CKYStatus;
dab6d7
 
dab6d7
 /*
dab6d7
@@ -107,12 +111,56 @@ typedef enum {
dab6d7
 #define CKY_LE_OFFSET	4
dab6d7
 
dab6d7
 #define CKYAPDU_MAX_DATA_LEN	256
dab6d7
+#define CKYAPDU_MAX_T1_DATA_LEN	65536
dab6d7
 #define CKYAPDU_MIN_LEN		4
dab6d7
 #define CKYAPDU_HEADER_LEN	5
dab6d7
 #define CKYAPDU_MAX_LEN		(CKYAPDU_HEADER_LEN+CKYAPDU_MAX_DATA_LEN)
dab6d7
 #define CKY_MAX_ATR_LEN		32
dab6d7
 #define CKY_OUTRAGEOUS_MALLOC_SIZE (1024*1024)
dab6d7
 
dab6d7
+#define P15FlagsPrivate           0x00000001
dab6d7
+#define P15FlagsModifiable        0x00000002
dab6d7
+
dab6d7
+#define P15UsageEncrypt           0x00000001
dab6d7
+#define P15UsageDecrypt           0x00000002
dab6d7
+#define P15UsageSign              0x00000004
dab6d7
+#define P15UsageSignRecover       0x00000008
dab6d7
+#define P15UsageWrap              0x00000010
dab6d7
+#define P15UsageUnwrap            0x00000020
dab6d7
+#define P15UsageVerify            0x00000040
dab6d7
+#define P15UsageVerifyRecover     0x00000080
dab6d7
+#define P15UsageDerive            0x00000100
dab6d7
+#define P15UsageNonRepudiation    0x00000200
dab6d7
+
dab6d7
+#define P15AccessSensitive        0x00000001
dab6d7
+#define P15AccessExtractable      0x00000002
dab6d7
+#define P15AccessAlwaysSenstive   0x00000004
dab6d7
+#define P15AccessNeverExtractable 0x00000008
dab6d7
+#define P15AccessLocal            0x00000010
dab6d7
+
dab6d7
+#define P15PinCaseSensitive       0x00000001
dab6d7
+#define P15PinLocal               0x00000002
dab6d7
+#define P15PinChangeDisabled      0x00000004
dab6d7
+#define P15PinUnblockDisabled     0x00000008
dab6d7
+#define P15PinInitialized         0x00000010
dab6d7
+#define P15PinNeedsPadding        0x00000020
dab6d7
+#define P15PinUnblockingPin       0x00000040
dab6d7
+#define P15PinSOPin               0x00000080
dab6d7
+#define P15PinDisableAllowed      0x00000100
dab6d7
+
dab6d7
+typedef enum {P15PinBCD=0, P15PinASCIINum=1, P15PinUTF8=2} P15PinType;
dab6d7
+
dab6d7
+typedef struct _P15PinInfo {
dab6d7
+    CKYBitFlags   pinFlags;
dab6d7
+    P15PinType    pinType;
dab6d7
+    CKYByte       minLength;
dab6d7
+    CKYByte       storedLength;
dab6d7
+    unsigned long maxLength;
dab6d7
+    CKYByte       pinRef;
dab6d7
+    CKYByte       padChar;
dab6d7
+} P15PinInfo;
dab6d7
+     
dab6d7
+
dab6d7
 /*
dab6d7
  * allow direct inclusion in C++ files 
dab6d7
  */
dab6d7
@@ -278,7 +326,11 @@ CKYStatus CKYAPDU_AppendSendDataBuffer(C
dab6d7
 /* set Le in the APDU header to the amount of bytes expected to be
dab6d7
  * returned. */
dab6d7
 CKYStatus CKYAPDU_SetReceiveLen(CKYAPDU *apdu, CKYByte recvlen);
dab6d7
+CKYStatus CKYAPDU_SetShortReceiveLen(CKYAPDU *apdu, unsigned short recvlen);
dab6d7
+CKYStatus CKYAPDU_SetReceiveLength(CKYAPDU *apdu, CKYSize recvlen);
dab6d7
 CKYStatus CKYAPDU_AppendReceiveLen(CKYAPDU *apdu, CKYByte recvlen);
dab6d7
+CKYStatus CKYAPDU_AppendShortReceiveLen(CKYAPDU *apdu, unsigned short recvlen);
dab6d7
+CKYStatus CKYAPDU_AppendReceiveLength(CKYAPDU *apdu, CKYSize recvlen);
dab6d7
 
dab6d7
 /* set the parent loadmodule name */
dab6d7
 void CKY_SetName(const char *name);
dab6d7
diff -up ./src/libckyapplet/cky_card.c.p15 ./src/libckyapplet/cky_card.c
dab6d7
--- ./src/libckyapplet/cky_card.c.p15	2015-07-06 10:27:55.778827116 -0700
dab6d7
+++ ./src/libckyapplet/cky_card.c	2015-07-06 10:27:55.790826889 -0700
dab6d7
@@ -910,6 +910,7 @@ ckyCardConnection_init(CKYCardConnection
dab6d7
     conn->protocol = SCARD_PROTOCOL_T0;
dab6d7
 }
dab6d7
 
dab6d7
+
dab6d7
 CKYCardConnection *
dab6d7
 CKYCardConnection_Create(const CKYCardContext *ctx)
dab6d7
 {
dab6d7
@@ -984,6 +985,12 @@ CKYCardConnection_IsConnected(const CKYC
dab6d7
     return (conn->cardHandle != 0);
dab6d7
 }
dab6d7
 
dab6d7
+unsigned long
dab6d7
+CKYCardConnection_GetProtocol(const CKYCardConnection *conn)
dab6d7
+{
dab6d7
+    return conn->protocol;
dab6d7
+}
dab6d7
+
dab6d7
 CKYStatus 
dab6d7
 ckyCardConnection_reconnectRaw(CKYCardConnection *conn, unsigned long init)
dab6d7
 {
dab6d7
@@ -996,6 +1003,7 @@ ckyCardConnection_reconnectRaw(CKYCardCo
dab6d7
 	conn->lastError = rv;
dab6d7
 	return CKYSCARDERR;
dab6d7
     }
dab6d7
+    conn->protocol = protocol;
dab6d7
     return CKYSUCCESS;
dab6d7
 }
dab6d7
 
dab6d7
diff -up ./src/libckyapplet/cky_card.h.p15 ./src/libckyapplet/cky_card.h
dab6d7
--- ./src/libckyapplet/cky_card.h.p15	2015-07-06 10:27:55.766827342 -0700
dab6d7
+++ ./src/libckyapplet/cky_card.h	2015-07-06 10:27:55.790826889 -0700
dab6d7
@@ -116,6 +116,7 @@ CKYStatus CKYCardConnection_ExchangeAPDU
dab6d7
 CKYStatus CKYCardConnection_Connect(CKYCardConnection *connection, 
dab6d7
 					const char *readerName);
dab6d7
 CKYStatus CKYCardConnection_Disconnect(CKYCardConnection *connection);
dab6d7
+unsigned long CKYCardConnection_GetProtocol(const CKYCardConnection *conn);
dab6d7
 CKYBool CKYCardConnection_IsConnected(const CKYCardConnection *connection);
dab6d7
 CKYStatus CKYCardConnection_Reconnect(CKYCardConnection *connection);
dab6d7
 CKYStatus CKYCardConnection_GetStatus(CKYCardConnection *connection,
dab6d7
diff -up ./src/libckyapplet/cky_factory.c.p15 ./src/libckyapplet/cky_factory.c
dab6d7
--- ./src/libckyapplet/cky_factory.c.p15	2015-07-06 10:27:55.778827116 -0700
dab6d7
+++ ./src/libckyapplet/cky_factory.c	2015-07-06 10:27:55.791826870 -0700
dab6d7
@@ -29,7 +29,7 @@ CKYAPDUFactory_SelectFile(CKYAPDU *apdu,
dab6d7
 			  const CKYBuffer *AID)
dab6d7
 {
dab6d7
     CKYAPDU_SetCLA(apdu, CKY_CLASS_ISO7816);
dab6d7
-    CKYAPDU_SetINS(apdu, CKY_INS_SELECT_FILE);
dab6d7
+    CKYAPDU_SetINS(apdu, ISO_INS_SELECT_FILE);
dab6d7
     CKYAPDU_SetP1(apdu, p1);
dab6d7
     CKYAPDU_SetP2(apdu, p2);
dab6d7
     return CKYAPDU_SetSendDataBuffer(apdu, AID);
dab6d7
@@ -40,7 +40,7 @@ CKYAPDUFactory_SelectCardManager(CKYAPDU
dab6d7
 {
dab6d7
     CKYByte c = 0;
dab6d7
     CKYAPDU_SetCLA(apdu, CKY_CLASS_ISO7816);
dab6d7
-    CKYAPDU_SetINS(apdu, CKY_INS_SELECT_FILE);
dab6d7
+    CKYAPDU_SetINS(apdu, ISO_INS_SELECT_FILE);
dab6d7
     CKYAPDU_SetP1(apdu, 0x04);
dab6d7
     CKYAPDU_SetP2(apdu, 0x00);
dab6d7
     /* I can't find the documentation for this, but if you pass an empty
dab6d7
@@ -57,7 +57,7 @@ CKYStatus
dab6d7
 CKYAPDUFactory_GetCPLCData(CKYAPDU *apdu)
dab6d7
 {
dab6d7
     CKYAPDU_SetCLA(apdu, CKY_CLASS_GLOBAL_PLATFORM);
dab6d7
-    CKYAPDU_SetINS(apdu, CKY_INS_GET_DATA);
dab6d7
+    CKYAPDU_SetINS(apdu, ISO_INS_GET_DATA);
dab6d7
     CKYAPDU_SetP1(apdu, 0x9f);
dab6d7
     CKYAPDU_SetP2(apdu, 0x7f);
dab6d7
     return CKYAPDU_SetReceiveLen(apdu, CKY_SIZE_GET_CPLCDATA);
dab6d7
@@ -707,6 +707,7 @@ fail:
dab6d7
     CKYBuffer_FreeData(&buf;;
dab6d7
     return ret;
dab6d7
 }
dab6d7
+
dab6d7
 CKYStatus
dab6d7
 CACAPDUFactory_GetProperties(CKYAPDU *apdu)
dab6d7
 {
dab6d7
@@ -718,37 +719,6 @@ CACAPDUFactory_GetProperties(CKYAPDU *ap
dab6d7
 }
dab6d7
 
dab6d7
 CKYStatus
dab6d7
-CACAPDUFactory_VerifyPIN(CKYAPDU *apdu, CKYByte keyRef, const char *pin)
dab6d7
-{
dab6d7
-    CKYStatus ret;
dab6d7
-    CKYSize size;
dab6d7
-
dab6d7
-    CKYAPDU_SetCLA(apdu, CKY_CLASS_ISO7816);
dab6d7
-    CKYAPDU_SetINS(apdu, CAC_INS_VERIFY_PIN);
dab6d7
-    CKYAPDU_SetP1(apdu, 0x00);
dab6d7
-    CKYAPDU_SetP2(apdu, keyRef);
dab6d7
-    /* no pin, send an empty buffer */
dab6d7
-    if (!pin) {
dab6d7
-    	return CKYAPDU_SetReceiveLen(apdu, 0);
dab6d7
-    }
dab6d7
-
dab6d7
-    /* all CAC pins are 8 bytes exactly. If to long, truncate it */
dab6d7
-    size = strlen(pin);
dab6d7
-    if (size > 8) {
dab6d7
-	size = 8;
dab6d7
-    }
dab6d7
-    ret = CKYAPDU_SetSendData(apdu, (unsigned char *) pin, size);
dab6d7
-    /* if too short, pad it */
dab6d7
-    if ((ret == CKYSUCCESS) && (size < 8)) {
dab6d7
-	static const unsigned char pad[]= { 0xff , 0xff, 0xff ,0xff, 
dab6d7
-				   0xff, 0xff, 0xff, 0xff };
dab6d7
-	return CKYAPDU_AppendSendData(apdu, pad, 8-size);
dab6d7
-    }
dab6d7
-    return ret;
dab6d7
-
dab6d7
-}
dab6d7
-
dab6d7
-CKYStatus
dab6d7
 PIVAPDUFactory_SignDecrypt(CKYAPDU *apdu, CKYByte chain, CKYByte alg, 
dab6d7
 			   CKYByte key, int len, const CKYBuffer *data)
dab6d7
 {
dab6d7
@@ -807,3 +777,109 @@ fail:
dab6d7
     return ret;
dab6d7
 }
dab6d7
 
dab6d7
+CKYStatus
dab6d7
+P15APDUFactory_VerifyPIN(CKYAPDU *apdu, CKYByte keyRef, const CKYBuffer *pin)
dab6d7
+{
dab6d7
+    CKYStatus ret;
dab6d7
+
dab6d7
+    CKYAPDU_SetCLA(apdu, CKY_CLASS_ISO7816);
dab6d7
+    CKYAPDU_SetINS(apdu, CAC_INS_VERIFY_PIN);
dab6d7
+    CKYAPDU_SetP1(apdu, 0x00);
dab6d7
+    CKYAPDU_SetP2(apdu, keyRef);
dab6d7
+    /* no pin, send an empty buffer */
dab6d7
+    if (CKYBuffer_Size(pin) == 0) {
dab6d7
+    	return CKYAPDU_SetReceiveLen(apdu, 0);
dab6d7
+    }
dab6d7
+
dab6d7
+    /* all CAC pins are 8 bytes exactly. If to long, truncate it */
dab6d7
+    ret = CKYAPDU_SetSendDataBuffer(apdu, pin);
dab6d7
+    return ret;
dab6d7
+
dab6d7
+}
dab6d7
+
dab6d7
+CKYStatus
dab6d7
+P15APDUFactory_ReadRecord(CKYAPDU *apdu, CKYByte record, CKYByte short_ef, 
dab6d7
+					CKYByte flags, CKYByte count)
dab6d7
+{
dab6d7
+    CKYByte control;
dab6d7
+
dab6d7
+    control = (short_ef << 3) & 0xf8;
dab6d7
+    control |= flags & 0x07;
dab6d7
+
dab6d7
+    CKYAPDU_SetCLA(apdu, CKY_CLASS_ISO7816);
dab6d7
+    CKYAPDU_SetINS(apdu, ISO_INS_READ_RECORD);
dab6d7
+    CKYAPDU_SetP1(apdu, record);
dab6d7
+    CKYAPDU_SetP2(apdu, control);
dab6d7
+    return CKYAPDU_SetReceiveLen(apdu, count);
dab6d7
+}
dab6d7
+
dab6d7
+CKYStatus
dab6d7
+P15APDUFactory_ReadBinary(CKYAPDU *apdu, unsigned short offset, 
dab6d7
+			CKYByte short_ef, CKYByte flags, CKYByte count)
dab6d7
+{
dab6d7
+    CKYByte p1 = 0,p2 = 0;
dab6d7
+    unsigned short max_offset = 0;
dab6d7
+
dab6d7
+    if (flags & P15_USE_SHORT_EF) {
dab6d7
+	max_offset = 0xff;
dab6d7
+	p1 = P15_USE_SHORT_EF | (short_ef & 0x7);
dab6d7
+	p2 = offset & 0xff;
dab6d7
+    } else {
dab6d7
+	max_offset = 0x7fff;
dab6d7
+	p1 = (offset >> 8) & 0x7f;
dab6d7
+	p2 = offset & 0xff;
dab6d7
+    }
dab6d7
+    if (offset > max_offset) {
dab6d7
+	return CKYINVALIDARGS;
dab6d7
+    }
dab6d7
+
dab6d7
+    CKYAPDU_SetCLA(apdu, CKY_CLASS_ISO7816);
dab6d7
+    CKYAPDU_SetINS(apdu, ISO_INS_READ_BINARY);
dab6d7
+    CKYAPDU_SetP1(apdu, p1);
dab6d7
+    CKYAPDU_SetP2(apdu, p2);
dab6d7
+    return CKYAPDU_SetReceiveLen(apdu, count);
dab6d7
+}
dab6d7
+
dab6d7
+CKYStatus
dab6d7
+P15APDUFactory_ManageSecurityEnvironment(CKYAPDU *apdu, CKYByte p1, CKYByte p2,
dab6d7
+					CKYByte keyRef)
dab6d7
+{
dab6d7
+    CKYByte param[3];
dab6d7
+
dab6d7
+    CKYAPDU_SetCLA(apdu, CKY_CLASS_ISO7816);
dab6d7
+    CKYAPDU_SetINS(apdu, ISO_INS_MANAGE_SECURITY_ENVIRONMENT);
dab6d7
+    CKYAPDU_SetP1(apdu, p1);
dab6d7
+    CKYAPDU_SetP2(apdu, p2);
dab6d7
+    param[0] = 0x83;
dab6d7
+    param[1] = 1;
dab6d7
+    param[2] = keyRef;
dab6d7
+    return CKYAPDU_SetSendData(apdu, param, sizeof param);
dab6d7
+}
dab6d7
+
dab6d7
+CKYStatus
dab6d7
+P15APDUFactory_PerformSecurityOperation(CKYAPDU *apdu, CKYByte dir,
dab6d7
+			int chain, CKYSize retLen, const CKYBuffer *data)
dab6d7
+{
dab6d7
+    CKYByte p1,p2;
dab6d7
+    CKYStatus ret;
dab6d7
+
dab6d7
+    CKYAPDU_SetCLA(apdu, chain ? CKY_CLASS_ISO7816_CHAIN :
dab6d7
+				  CKY_CLASS_ISO7816);
dab6d7
+    CKYAPDU_SetINS(apdu, ISO_INS_PERFORM_SECURITY_OPERATION);
dab6d7
+    if (dir == CKY_DIR_DECRYPT) {
dab6d7
+	p1 = ISO_PSO_DECRYPT_P1;
dab6d7
+	p2 = ISO_PSO_DECRYPT_P2;
dab6d7
+    } else {
dab6d7
+	p1 = ISO_PSO_SIGN_P1;
dab6d7
+	p2 = ISO_PSO_SIGN_P2;
dab6d7
+    }
dab6d7
+    CKYAPDU_SetP1(apdu, p1);
dab6d7
+    CKYAPDU_SetP2(apdu, p2);
dab6d7
+    ret =  CKYAPDU_SetSendDataBuffer(apdu, data);
dab6d7
+    if (ret == CKYSUCCESS && (chain == 0) && retLen != 0) {
dab6d7
+	ret = CKYAPDU_AppendReceiveLength(apdu, retLen);
dab6d7
+    }
dab6d7
+    return ret;
dab6d7
+}
dab6d7
+
dab6d7
+
dab6d7
diff -up ./src/libckyapplet/cky_factory.h.p15 ./src/libckyapplet/cky_factory.h
dab6d7
--- ./src/libckyapplet/cky_factory.h.p15	2015-07-06 10:27:55.779827097 -0700
dab6d7
+++ ./src/libckyapplet/cky_factory.h	2015-07-06 10:27:55.791826870 -0700
dab6d7
@@ -35,8 +35,31 @@
dab6d7
  * Applet Instruction Bytes
dab6d7
  */
dab6d7
 /* Card Manager */
dab6d7
-#define CKY_INS_SELECT_FILE	0xa4
dab6d7
-#define CKY_INS_GET_DATA 	0xca
dab6d7
+#define ISO_INS_SELECT_FILE	0xa4
dab6d7
+#define ISO_INS_GET_DATA 	0xca
dab6d7
+#define ISO_INS_READ_BINARY 	0xb0
dab6d7
+#define ISO_INS_READ_RECORD 	0xb2
dab6d7
+#define ISO_INS_MANAGE_SECURITY_ENVIRONMENT 0x22
dab6d7
+#define ISO_INS_PERFORM_SECURITY_OPERATION 0x2a
dab6d7
+
dab6d7
+/* ISO Parameters: */
dab6d7
+#define ISO_LOGIN_LOCAL		0x80
dab6d7
+#define ISO_LOGIN_GLOBAL	0x00
dab6d7
+#define ISO_MSE_SET		0x01
dab6d7
+#define ISO_MSE_STORE		0xf2
dab6d7
+#define ISO_MSE_RESTORE		0xf3
dab6d7
+#define ISO_MSE_ERASE		0xf4
dab6d7
+#define ISO_MSE_QUAL_VERIFY	0x80
dab6d7
+#define ISO_MSE_QUAL_COMPUTE	0x40
dab6d7
+#define ISO_MSE_AUTH		0xa4
dab6d7
+#define ISO_MSE_SIGN		0xb6
dab6d7
+#define ISO_MSE_KEA		0xb8
dab6d7
+#define ISO_PSO_SIGN_P1		0x9e
dab6d7
+#define ISO_PSO_SIGN_P2		0x9a
dab6d7
+#define ISO_PSO_ENCRYPT_P1	0x86
dab6d7
+#define ISO_PSO_ENCRYPT_P2	0x80
dab6d7
+#define ISO_PSO_DECRYPT_P1	0x80
dab6d7
+#define ISO_PSO_DECRYPT_P2	0x86
dab6d7
 
dab6d7
 /* deprecated */
dab6d7
 #define CKY_INS_SETUP    	0x2A
dab6d7
@@ -84,6 +107,7 @@
dab6d7
 #define CKY_INS_SEC_READ_IOBUF	0x08
dab6d7
 #define CKY_INS_SEC_START_ENROLLMENT	0x0C
dab6d7
 
dab6d7
+
dab6d7
 /* CAC */
dab6d7
 #define CAC_INS_GET_CERTIFICATE 0x36
dab6d7
 #define CAC_INS_SIGN_DECRYPT	0x42
dab6d7
@@ -94,11 +118,8 @@
dab6d7
 #define CAC_SIZE_GET_PROPERTIES	48
dab6d7
 #define CAC_P1_STEP		0x80
dab6d7
 #define CAC_P1_FINAL		0x00
dab6d7
-#define CAC_LOGIN_GLOBAL	0x00
dab6d7
 
dab6d7
 /* PIV */
dab6d7
-#define PIV_LOGIN_LOCAL		0x80
dab6d7
-#define PIV_LOGIN_GLOBAL	CAC_LOGIN_GLOBAL
dab6d7
 #define PIV_INS_GEN_AUTHENTICATE 0x87
dab6d7
 
dab6d7
 /*
dab6d7
@@ -121,7 +142,7 @@
dab6d7
 /* functions */
dab6d7
 #define CKY_CIPHER_INIT		1
dab6d7
 #define CKY_CIPHER_PROCESS	2
dab6d7
-#define CKY_CIPHER_FINAL		3
dab6d7
+#define CKY_CIPHER_FINAL	3
dab6d7
 #define CKY_CIPHER_ONE_STEP	4  /* init and final in one APDU */
dab6d7
 
dab6d7
 /* modes */
dab6d7
@@ -173,6 +194,18 @@
dab6d7
 #define CKY_CARDM_MANAGER_LOCKED          0x7f
dab6d7
 #define CKY_CARDM_MANAGER_TERMINATED      0xff
dab6d7
 
dab6d7
+/* Read Record Flags */
dab6d7
+#define P15_READ_P1          0x4
dab6d7
+#define P15_READ_P1_TO_LAST  0x5
dab6d7
+#define P15_READ_LAST_TO_P1  0x6
dab6d7
+#define P15_READ_FIRST       0x0
dab6d7
+#define P15_READ_LAST        0x1
dab6d7
+#define P15_READ_NEXT        0x2
dab6d7
+#define P15_READ_PREV        0x3
dab6d7
+
dab6d7
+/* Read Binary Flags */
dab6d7
+#define P15_USE_SHORT_EF    0x80
dab6d7
+
dab6d7
 /*
dab6d7
  * The following factories 'Fill in' APDUs for each of the
dab6d7
  * functions described below. Nonces are not automatically added.
dab6d7
@@ -234,17 +267,28 @@ CKYStatus CKYAPDUFactory_GetBuiltinACL(C
dab6d7
 
dab6d7
 CKYStatus CACAPDUFactory_SignDecrypt(CKYAPDU *apdu, CKYByte type, 
dab6d7
 				     const CKYBuffer *data);
dab6d7
-CKYStatus CACAPDUFactory_VerifyPIN(CKYAPDU *apdu, CKYByte keyRef,
dab6d7
-				   const char *pin);
dab6d7
 CKYStatus CACAPDUFactory_GetCertificate(CKYAPDU *apdu, CKYSize size);
dab6d7
 CKYStatus CACAPDUFactory_ReadFile(CKYAPDU *apdu, unsigned short offset, 
dab6d7
 				  CKYByte type, CKYByte count);
dab6d7
 CKYStatus CACAPDUFactory_GetProperties(CKYAPDU *apdu);
dab6d7
+
dab6d7
 CKYStatus PIVAPDUFactory_GetData(CKYAPDU *apdu, const CKYBuffer *object, 
dab6d7
 				CKYByte count);
dab6d7
 CKYStatus PIVAPDUFactory_SignDecrypt(CKYAPDU *apdu, CKYByte chain, CKYByte alg, 
dab6d7
                            CKYByte key, int len, const CKYBuffer *data);
dab6d7
 
dab6d7
+CKYStatus P15APDUFactory_VerifyPIN(CKYAPDU *apdu, CKYByte keyRef,
dab6d7
+			   const CKYBuffer *pin);
dab6d7
+CKYStatus P15APDUFactory_ReadRecord(CKYAPDU *apdu, CKYByte record, 
dab6d7
+			   CKYByte short_ef, CKYByte flags, CKYByte count);
dab6d7
+CKYStatus P15APDUFactory_ReadBinary(CKYAPDU *apdu, unsigned short offset, 
dab6d7
+			   CKYByte short_ef, CKYByte flags, CKYByte count);
dab6d7
+CKYStatus P15APDUFactory_ManageSecurityEnvironment(CKYAPDU *apdu, 
dab6d7
+			   CKYByte p1, CKYByte p2, CKYByte key);
dab6d7
+CKYStatus P15APDUFactory_PerformSecurityOperation(CKYAPDU *apdu, CKYByte dir,
dab6d7
+			   int chain, CKYSize retLen, const CKYBuffer *data);
dab6d7
+
dab6d7
+
dab6d7
 CKY_END_PROTOS
dab6d7
 
dab6d7
 #endif /* CKY_FACTORY_H */