components/coolkey/patches/04-object.cpp.patch
changeset 6401 8e624b116c1d
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/components/coolkey/patches/04-object.cpp.patch	Tue Jul 12 17:34:11 2016 -0700
@@ -0,0 +1,1381 @@
+Upstream fixes already included in the latest community updates to coolkey v1.1.0
+
+Addresses various bugs found in PKCS11 object handling.
+
+--- ORIGINAL/./src/coolkey/object.cpp	2016-06-24 16:07:19.782779440 -0400
++++ ././src/coolkey/object.cpp	2016-06-27 13:43:35.548673450 -0400
+@@ -21,15 +21,48 @@
+ #include "PKCS11Exception.h"
+ #include "object.h"
+ #include <algorithm>
++#include <string.h>
+ 
+ using std::find_if;
+ 
++const CKYByte rsaOID[] = {0x2A,0x86,0x48,0x86,0xF7,0x0D, 0x01, 0x01,0x1};
++const CKYByte eccOID[] = {0x2a,0x86,0x48,0xce,0x3d,0x02,0x01};
++
++#ifdef DEBUG
++void dump(CKYBuffer *buf)
++{
++    CKYSize i;
++    CKYSize size = CKYBuffer_Size(buf);
++#define ROW_LENGTH 60
++    char string[ROW_LENGTH+1];
++    char *bp = &string[0];
++    CKYByte c;
++
++    for (i=0; i < size; i++) {
++        if (i && ((i % (ROW_LENGTH-1)) == 0) ) {
++            *bp = 0;
++            printf(" %s\n",string);
++            bp = &string[0];
++        }
++        c = CKYBuffer_GetChar(buf, i);
++        printf("%02x ",c);
++        *bp++ =  (c < ' ') ? '.' : ((c & 0x80) ? '*' : c);
++    }
++    *bp = 0;
++    for (i= (i % (ROW_LENGTH-1)); i && (i < ROW_LENGTH); i++) {
++        printf("   ");
++    }
++    printf(" %s\n",string);
++    fflush(stdout);
++}
++#endif
++
+ 
+ bool AttributeMatch::operator()(const PKCS11Attribute& cmp) 
+ {
+     return (attr->type == cmp.getType()) &&
+-	CKYBuffer_DataIsEqual(cmp.getValue(), 
+-			(const CKYByte *)attr->pValue, attr->ulValueLen);
++        CKYBuffer_DataIsEqual(cmp.getValue(), 
++                        (const CKYByte *)attr->pValue, attr->ulValueLen);
+ }
+ 
+ class AttributeTypeMatch
+@@ -44,14 +77,14 @@
+ };
+ 
+ PKCS11Object::PKCS11Object(unsigned long muscleObjID_,CK_OBJECT_HANDLE handle_)
+-    : muscleObjID(muscleObjID_), handle(handle_), label(NULL), name(NULL)
++    : muscleObjID(muscleObjID_), handle(handle_), label(NULL), name(NULL), keyType(unknown)
+ { 
+     CKYBuffer_InitEmpty(&pubKey);
+ }
+ 
+ PKCS11Object::PKCS11Object(unsigned long muscleObjID_, const CKYBuffer *data,
+     CK_OBJECT_HANDLE handle_) :  muscleObjID(muscleObjID_), handle(handle_),
+-			label(NULL), name(NULL)
++                        label(NULL), name(NULL), keyType(unknown)
+ {
+     CKYBuffer_InitEmpty(&pubKey);
+ 
+@@ -62,9 +95,98 @@
+             "PKCS #11 actual object id does not match stated id");
+     }
+     if (type == 0) {
+-	parseOldObject(data);
++        parseOldObject(data);
+     } else if (type == 1) {
+-	parseNewObject(data);
++        parseNewObject(data);
++    }
++}
++
++SecretKey::SecretKey(unsigned long muscleObjID_, CK_OBJECT_HANDLE handle_, CKYBuffer *secretKeyBuffer, CK_ATTRIBUTE_PTR pTemplate, CK_ULONG ulAttributeCount)
++     : PKCS11Object(muscleObjID_, handle_)
++{
++    static CK_OBJECT_CLASS objClass = CKO_SECRET_KEY;
++    static CK_KEY_TYPE keyType = CKK_GENERIC_SECRET;
++    static CK_BBOOL value = 0x1;
++
++    if ( secretKeyBuffer == NULL)
++        return;
++
++    /* Rifle through the input template */
++
++    CK_ATTRIBUTE_TYPE type;
++    CK_ATTRIBUTE attr;
++    CK_ULONG valueLength = 0;
++
++    for(int i = 0; i <  (int) ulAttributeCount; i++) {
++       attr = pTemplate[i];
++       type =  attr.type;
++
++       if ( type == CKA_VALUE_LEN) {
++           //CK_ULONG ulValueLen = attr.ulValueLen;
++           valueLength = *((CK_ULONG *)attr.pValue);
++       } else {
++
++           CKYBuffer val;
++           CKYBuffer_InitFromData(&val,(const CK_BYTE *) attr.pValue, attr.ulValueLen);
++           setAttribute( type, &val);
++           CKYBuffer_FreeData(&val);
++       }
++    }
++
++    adjustToKeyValueLength( secretKeyBuffer, valueLength ); 
++
++    /* Fall backs. */
++
++    if(!attributeExists(CKA_CLASS))
++        setAttributeULong(CKA_CLASS, objClass);
++
++    if(!attributeExists(CKA_KEY_TYPE))
++        setAttributeULong(CKA_KEY_TYPE, keyType);
++
++    if(!attributeExists(CKA_TOKEN))
++        setAttributeBool(CKA_TOKEN, value);
++      
++    if(!attributeExists(CKA_DERIVE)) 
++        setAttributeBool(CKA_DERIVE, value);
++
++    /* Actual value */
++    setAttribute(CKA_VALUE, secretKeyBuffer);
++
++}
++
++void SecretKey::adjustToKeyValueLength(CKYBuffer * secretKeyBuffer,CK_ULONG valueLength)
++{
++    const CK_LONG MAX_DIFF = 200; /* Put some bounds on this value */
++
++    if ( !secretKeyBuffer ) {
++        return;
++    }
++
++    CKYBuffer scratch;
++    CK_ULONG actual_length = CKYBuffer_Size(secretKeyBuffer);
++
++    CK_LONG diff = 0;
++    diff = (CK_LONG) valueLength - actual_length;
++
++    if ( diff == 0 ) {
++        return;
++    }
++
++    if ( diff > 0 && diff < MAX_DIFF ) { /*check for silly values */
++        /* prepend with zeroes */
++        CKYBuffer_InitFromLen(&scratch, diff);
++        CKYBuffer_AppendCopy(&scratch, secretKeyBuffer);
++
++        CKYBuffer_FreeData(secretKeyBuffer);
++        CKYBuffer_InitFromCopy(secretKeyBuffer, &scratch);
++        CKYBuffer_FreeData(&scratch);
++
++    } else if (diff < 0 ) {
++        /* truncate most significant bytes */
++        CKYBuffer_InitFromData(&scratch, CKYBuffer_Data(secretKeyBuffer)-diff, valueLength);
++        CKYBuffer_FreeData(secretKeyBuffer);
++        CKYBuffer_InitFromCopy(secretKeyBuffer, &scratch);
++        CKYBuffer_FreeData(&scratch);
+     }
+ }
+ 
+@@ -94,29 +216,29 @@
+         attrib.setType(CKYBuffer_GetLong(data, idx));
+         idx += 4;
+         unsigned int attrLen = CKYBuffer_GetShort(data, idx);
+-		idx += 2;
++                idx += 2;
+         if( attrLen > CKYBuffer_Size(data) 
+-			|| (idx + attrLen > CKYBuffer_Size(data)) ) {
++                        || (idx + attrLen > CKYBuffer_Size(data)) ) {
+             throw PKCS11Exception(CKR_DEVICE_ERROR,
+                 "Invalid attribute length %d\n", attrLen);
+         }
+-	/* these two types are ints, read them back from 
+-	 * the card in host order */
+-	if ((attrib.getType() == CKA_CLASS) || 
+-	    (attrib.getType() == CKA_CERTIFICATE_TYPE) ||
+-	    (attrib.getType() == CKA_KEY_TYPE)) {
+-	    /* ulongs are 4 bytes on the token, even if they are 8 or
+-	     * more in the pkcs11 module */
+-	    if (attrLen != 4) {
++        /* these two types are ints, read them back from 
++         * the card in host order */
++        if ((attrib.getType() == CKA_CLASS) || 
++            (attrib.getType() == CKA_CERTIFICATE_TYPE) ||
++            (attrib.getType() == CKA_KEY_TYPE)) {
++            /* ulongs are 4 bytes on the token, even if they are 8 or
++             * more in the pkcs11 module */
++            if (attrLen != 4) {
+                 throw PKCS11Exception(CKR_DEVICE_ERROR,
+                 "Invalid attribute length %d\n", attrLen);
+-	    }
+-	    CK_ULONG value = makeLEUInt(data,idx);
++            }
++            CK_ULONG value = makeLEUInt(data,idx);
+ 
+-	    attrib.setValue((const CKYByte *)&value, sizeof(CK_ULONG));
+-	} else {
+-	    attrib.setValue(CKYBuffer_Data(data)+idx, attrLen);
+-	}
++            attrib.setValue((const CKYByte *)&value, sizeof(CK_ULONG));
++        } else {
++            attrib.setValue(CKYBuffer_Data(data)+idx, attrLen);
++        }
+         idx += attrLen;
+         attributes.push_back(attrib);
+     }
+@@ -176,33 +298,33 @@
+     unsigned long i;
+ 
+     if (!attributeExists(CKA_ID)) {
+-	PKCS11Attribute attrib;
+-	attrib.setType(CKA_ID);
+-	attrib.setValue(&cka_id, 1);
++        PKCS11Attribute attrib;
++        attrib.setType(CKA_ID);
++        attrib.setValue(&cka_id, 1);
+         attributes.push_back(attrib);
+     }
+     /* unpack the class */
+     if (!attributeExists(CKA_CLASS)) {
+-	PKCS11Attribute attrib;
+-	attrib.setType(CKA_CLASS);
+-	attrib.setValue((CKYByte *)&objectType, sizeof(CK_ULONG));
++        PKCS11Attribute attrib;
++        attrib.setType(CKA_CLASS);
++        attrib.setValue((CKYByte *)&objectType, sizeof(CK_ULONG));
+         attributes.push_back(attrib);
+     }
+ 
+     /* unpack the boolean flags. Note, the default mask is based on
+      * the class specified in fixedAttrs, not on the real class */
+     for (i=1; i < sizeof(unsigned long)*8; i++) {
+-	unsigned long iMask = 1<< i;
+-	if ((mask & iMask) == 0) {
+-	   continue;
+-	}
+-	if (attributeExists(boolType[i])) {
+-	    continue;
+-	}
+-	PKCS11Attribute attrib;
+-	CKYByte bVal = (fixedAttrs & iMask) != 0;
+-	attrib.setType(boolType[i]);
+-	attrib.setValue(&bVal, 1);
++        unsigned long iMask = 1<< i;
++        if ((mask & iMask) == 0) {
++           continue;
++        }
++        if (attributeExists(boolType[i])) {
++            continue;
++        }
++        PKCS11Attribute attrib;
++        CKYByte bVal = (fixedAttrs & iMask) != 0;
++        attrib.setType(boolType[i]);
++        attrib.setValue(&bVal, 1);
+         attributes.push_back(attrib);
+     }
+ }
+@@ -223,40 +345,40 @@
+     // load up the explicit attributes first
+     for (j=0, offset = 11; j < attributeCount && offset < size; j++) {
+         PKCS11Attribute attrib;
+-	CKYByte attributeDataType = CKYBuffer_GetChar(data, offset+4);
+-	unsigned int attrLen = 0;
++        CKYByte attributeDataType = CKYBuffer_GetChar(data, offset+4);
++        unsigned int attrLen = 0;
+         attrib.setType(CKYBuffer_GetLong(data, offset));
+         offset += 5;
+ 
+-	switch(attributeDataType) {
+-	case DATATYPE_STRING:
+-	    attrLen = CKYBuffer_GetShort(data, offset);
+-	    offset += 2;
++        switch(attributeDataType) {
++        case DATATYPE_STRING:
++            attrLen = CKYBuffer_GetShort(data, offset);
++            offset += 2;
+             if (attrLen > CKYBuffer_Size(data) 
+-			|| (offset + attrLen > CKYBuffer_Size(data)) ) {
+-            	throw PKCS11Exception(CKR_DEVICE_ERROR,
+-            	    "Invalid attribute length %d\n", attrLen);
++                        || (offset + attrLen > CKYBuffer_Size(data)) ) {
++                    throw PKCS11Exception(CKR_DEVICE_ERROR,
++                        "Invalid attribute length %d\n", attrLen);
+              }
+-	    attrib.setValue(CKYBuffer_Data(data)+offset, attrLen);
+-	    break;
+-	case DATATYPE_BOOL_FALSE:
+-	case DATATYPE_BOOL_TRUE:
+-	    {
+-		CKYByte bval = attributeDataType & 1;
+-		attrib.setValue(&bval, 1);
+-	    }
+-	    break;
+-	case DATATYPE_INTEGER:
+-	    {
+-		CK_ULONG value = CKYBuffer_GetLong(data, offset);
+-		attrLen = 4;
+-		attrib.setValue((const CKYByte *)&value, sizeof(CK_ULONG));
+-	    }
+-	    break;
+-	default:
+-	    throw PKCS11Exception(CKR_DEVICE_ERROR, 
+-		"Invalid attribute Data Type %d\n", attributeDataType);
+-	}
++            attrib.setValue(CKYBuffer_Data(data)+offset, attrLen);
++            break;
++        case DATATYPE_BOOL_FALSE:
++        case DATATYPE_BOOL_TRUE:
++            {
++                CKYByte bval = attributeDataType & 1;
++                attrib.setValue(&bval, 1);
++            }
++            break;
++        case DATATYPE_INTEGER:
++            {
++                CK_ULONG value = CKYBuffer_GetLong(data, offset);
++                attrLen = 4;
++                attrib.setValue((const CKYByte *)&value, sizeof(CK_ULONG));
++            }
++            break;
++        default:
++            throw PKCS11Exception(CKR_DEVICE_ERROR, 
++                "Invalid attribute Data Type %d\n", attributeDataType);
++        }
+         offset += attrLen;
+         attributes.push_back(attrib);
+     }
+@@ -273,9 +395,10 @@
+ };
+ #endif
+ 
++// XXX - Need to use a correct signature. This is necessary only on SPARC
+ bool
+-PKCS11Object::matchesTemplate(const CK_ATTRIBUTE_PTR pTemplate, 
+-						CK_ULONG ulCount)
++PKCS11Object::matchesTemplate(CK_ATTRIBUTE_PTR pTemplate, 
++                                                CK_ULONG ulCount)
+     const
+ {
+     unsigned int i;
+@@ -284,10 +407,10 @@
+ 
+ #if defined( NSS_HIDE_NONSTANDARD_OBJECTS )
+     if (!ulCount) {
+-	// exclude MOZ reader objects from searches for all objects.
+-	// To find an MOZ reader object, one must search for it by 
+-	// some matching attribute, such as class.
+-	iterator iter = find_if(attributes.begin(), attributes.end(),
++        // exclude MOZ reader objects from searches for all objects.
++        // To find an MOZ reader object, one must search for it by 
++        // some matching attribute, such as class.
++        iterator iter = find_if(attributes.begin(), attributes.end(),
+                                 AttributeMatch(&rdr_template[0]));
+         return (iter == attributes.end()) ? true : false;
+     }
+@@ -324,7 +447,7 @@
+             AttributeTypeMatch(type));
+ 
+     if( iter == attributes.end() ) {
+-	return NULL;
++        return NULL;
+     }
+     return iter->getValue();
+ }
+@@ -348,8 +471,9 @@
+         if( iter == attributes.end() ) {
+             // no attribute of this type
+             attrTypeInvalid = true;
+-            log->log("GetAttributeValue: invalid type 0x%08x on object %x\n",
+-                pTemplate[i].type, muscleObjID);
++            if ( log )
++                log->log("GetAttributeValue: invalid type 0x%08x on object %x\n",
++                    pTemplate[i].type, muscleObjID);
+             pTemplate[i].ulValueLen = (CK_ULONG)-1;
+             continue;
+         }
+@@ -370,7 +494,7 @@
+         // the buffer is large enough. return the value and set the exact
+         // length.
+         memcpy(pTemplate[i].pValue, CKYBuffer_Data(iter->getValue()), 
+-					CKYBuffer_Size(iter->getValue()));
++                                        CKYBuffer_Size(iter->getValue()));
+         pTemplate[i].ulValueLen = CKYBuffer_Size(iter->getValue());
+     }
+ 
+@@ -396,7 +520,7 @@
+ {
+     // clean up old one
+     if (label) {
+-	delete label;
++	delete [] label;
+ 	label = NULL;
+     }
+     // find matching attribute
+@@ -405,14 +529,14 @@
+ 
+     // none found 
+     if( iter == attributes.end() ) {
+-	return "";
++        return "";
+     }
+ 
+     int size = CKYBuffer_Size(iter->getValue());
+ 
+     label = new char [ size + 1 ];
+     if (!label) {
+-	return "";
++        return "";
+     }
+     memcpy(label, CKYBuffer_Data(iter->getValue()), size);
+     label[size] = 0;
+@@ -430,13 +554,13 @@
+ 
+     // none found */
+     if( iter == attributes.end() ) {
+-	return (CK_OBJECT_CLASS) -1;
++        return (CK_OBJECT_CLASS) -1;
+     }
+ 
+     int size = CKYBuffer_Size(iter->getValue());
+ 
+     if (size != sizeof(objClass)) {
+-	return (CK_OBJECT_CLASS) -1;
++        return (CK_OBJECT_CLASS) -1;
+     }
+ 
+     memcpy(&objClass, CKYBuffer_Data(iter->getValue()), size);
+@@ -452,7 +576,7 @@
+     iter = find_if(attributes.begin(), attributes.end(),
+         AttributeTypeMatch(type));
+     if( iter != attributes.end() )  {
+-	iter->setValue( CKYBuffer_Data(value), CKYBuffer_Size(value));
++        iter->setValue( CKYBuffer_Data(value), CKYBuffer_Size(value));
+     } else {
+         attributes.push_back(PKCS11Attribute(type, value));
+     }
+@@ -504,6 +628,16 @@
+     unsigned char tag;
+     unsigned int used_length= 0;
+ 
++    *data_length = 0; /* make sure data_length is zero on failure */
++
++    if(!buf) {
++        return NULL;
++    }
++    /* there must be at least 2 bytes */
++    if (length < 2) {
++	return NULL;
++    }
++
+     tag = buf[used_length++];
+ 
+     /* blow out when we come to the end */
+@@ -516,15 +650,22 @@
+     if (*data_length&0x80) {
+         int  len_count = *data_length & 0x7f;
+ 
++	if (len_count+used_length > length) {
++	    return NULL;
++	}
++
+         *data_length = 0;
+ 
+         while (len_count-- > 0) {
+             *data_length = (*data_length << 8) | buf[used_length++];
+         }
+     }
++    /* paranoia, can't happen */
++    if (length < used_length) {
++	return NULL;
++    }
+ 
+     if (*data_length > (length-used_length) ) {
+-        *data_length = length-used_length;
+         return NULL;
+     }
+     if (includeTag) *data_length += used_length;
+@@ -537,16 +678,158 @@
+ {
+     /* for RSA, bit string always has byte number of bits */
+     if (buf[0] != 0) {
+-	return NULL;
++        return NULL;
+     }
+     if (len < 1) {
+-	return NULL;
++        return NULL;
+     }
+     *retLen = len -1;
+     return buf+1;
+ }
+ 
+ static SECStatus
++GetECKeyFieldItems(const CKYByte *spki_data,unsigned int spki_length,
++        CCItem *point, CCItem *params)
++{
++    const CKYByte *buf = spki_data;
++    unsigned int buf_length = spki_length;
++    const CKYByte *algid;
++    unsigned int algidlen;
++    const CKYByte *dummy;
++    unsigned int dummylen;
++
++    if (!point || !params || !buf)
++        return SECFailure;
++
++    point->data = NULL;
++    point->len = 0;
++    params->data = NULL;
++    params->len = 0;
++
++    /* unwrap the algorithm id */
++    dummy = dataStart(buf,buf_length,&dummylen,false);
++    if (dummy == NULL) return SECFailure;
++    buf_length -= (dummy-buf) + dummylen;
++    buf = dummy + dummylen;
++    /* unwrpped value is in dummy */
++    algid = dummy;
++    algidlen = dummylen;
++    /* skip past algid oid */
++    dummy = dataStart(algid, algidlen, &dummylen, false);
++    if (dummy == NULL) return SECFailure;
++    algidlen -= (dummy-algid) + dummylen;
++    algid = dummy + dummylen;
++    params->data = algid;
++    params->len = algidlen;
++
++       /* unwrap the public key info */
++    buf = dataStart(buf,buf_length,&buf_length,false);
++    if (buf == NULL) return SECFailure;
++    buf = unwrapBitString(buf,buf_length,&buf_length);
++    if (buf == NULL) return SECFailure;
++
++    point->data = buf;
++    point->len = buf_length;
++
++    if(point->data == NULL) return SECFailure;
++
++    return SECSuccess;
++}
++
++static bool
++GetKeyOIDMatches(const CKYByte *spki_data, unsigned int length, const CKYByte *oid_data)
++{
++    bool ret = TRUE;
++
++    if( spki_data == NULL || oid_data == NULL) {
++        return FALSE;
++    }
++
++    for ( int i = 0 ; i < (int) length ; i++) {
++        if (spki_data[i] != oid_data[i]) {
++            ret = FALSE;
++            break;
++        }
++            
++    }
++
++    return ret;
++}
++
++static SECStatus
++GetKeyAlgorithmId(const CKYByte *spki_data, unsigned int spki_length,
++       CCItem *algorithmId)
++{
++
++    const CKYByte *buf = spki_data;
++    unsigned int buf_length = spki_length;
++
++    if ( algorithmId == NULL) return SECFailure;
++
++    /* objtain the algorithm id */
++    algorithmId->data = dataStart(buf,buf_length,&algorithmId->len,false);
++    if (algorithmId->data == NULL) return SECFailure;
++
++    return SECSuccess;
++
++}
++
++static PKCS11Object::KeyType
++GetKeyTypeFromSPKI(const CKYBuffer *key)
++{
++    CCItem algIdItem;
++    SECStatus ret = GetKeyAlgorithmId(CKYBuffer_Data(key), 
++                                      CKYBuffer_Size(key),&algIdItem);
++    PKCS11Object::KeyType foundType = PKCS11Object::unknown;
++
++    if ( ret != SECSuccess ) {
++        throw PKCS11Exception(CKR_FUNCTION_FAILED,
++            "Failed to decode key algorithm ID.");
++    }
++
++    unsigned int length = 0;
++    const CKYByte *keyData = NULL;
++
++    /* Get actual oid buffer */
++
++    keyData = dataStart(algIdItem.data,algIdItem.len,&length, false);
++    if (keyData == NULL) {
++        throw PKCS11Exception(CKR_FUNCTION_FAILED,
++            "Failed to decode key algorithm ID.");
++    }
++
++    bool match = FALSE;
++    
++    /* Check for outrageous length */
++
++    if ( length <= 3 || length >= algIdItem.len) {
++        throw PKCS11Exception(CKR_FUNCTION_FAILED,
++            "Failed to decode key algorithm ID.");
++    }
++    /* check for RSA */
++ 
++    match = GetKeyOIDMatches(keyData, length, rsaOID);
++   
++    if ( match == TRUE ) {
++       foundType = PKCS11Object::rsa;
++    } else { 
++      /* check for ECC */
++       match = GetKeyOIDMatches(keyData, length, eccOID);
++
++       if ( match == TRUE ) {
++         foundType = PKCS11Object::ecc;
++       }
++
++    }
++
++    if ( foundType == PKCS11Object::unknown) {
++        throw PKCS11Exception(CKR_FUNCTION_FAILED,
++            "Failed to decode key algorithm ID.");
++    }
++    return foundType;
++}
++
++static SECStatus
+ GetKeyFieldItems(const CKYByte *spki_data,unsigned int spki_length,
+         CCItem *modulus, CCItem *exponent)
+ {
+@@ -591,7 +874,7 @@
+     CCItem modulusItem, exponentItem;
+ 
+     rv = GetKeyFieldItems(CKYBuffer_Data(spki), CKYBuffer_Size(spki), 
+-	&modulusItem, &exponentItem);
++        &modulusItem, &exponentItem);
+ 
+     if( rv != SECSuccess ) {
+         throw PKCS11Exception(CKR_FUNCTION_FAILED,
+@@ -602,6 +885,29 @@
+     CKYBuffer_Replace(exponent, 0, exponentItem.data, exponentItem.len);
+ }
+ 
++static void
++GetECKeyFields(const CKYBuffer *spki, CKYBuffer *point, CKYBuffer *params)
++{
++    SECStatus rv;
++    CCItem pointItem, paramsItem;
++
++    if (spki == NULL || point == NULL || params == NULL) {
++        throw PKCS11Exception(CKR_FUNCTION_FAILED,
++             "Failed to decode certificate Subject Public KeyInfo!");
++    }
++    
++    rv = GetECKeyFieldItems(CKYBuffer_Data(spki), CKYBuffer_Size(spki),
++        &pointItem, &paramsItem);
++
++    if( rv != SECSuccess ) {
++        throw PKCS11Exception(CKR_FUNCTION_FAILED,
++            "Failed to decode certificate Subject Public Key Info!");
++    }
++
++    CKYBuffer_Replace(point, 0, pointItem.data, pointItem.len);
++    CKYBuffer_Replace(params, 0, paramsItem.data, paramsItem.len);
++}
++
+ Key::Key(unsigned long muscleObjID, const CKYBuffer *data,
+     CK_OBJECT_HANDLE handle) : PKCS11Object(muscleObjID, data, handle)
+ {
+@@ -611,22 +917,41 @@
+     CKYBuffer_InitEmpty(&empty);
+ 
+     if ((objClass == CKO_PUBLIC_KEY) || (objClass == CKO_PRIVATE_KEY)) {
+-	/* only CKK_RSA is supported */
+-	setAttributeULong(CKA_KEY_TYPE, CKK_RSA);
++        //we may know already what type of key this is.
++        if (attributeExists(CKA_KEY_TYPE)) {
++            CK_ULONG type = 0;
++            CK_ATTRIBUTE aTemplate = {CKA_KEY_TYPE, &type, sizeof(CK_ULONG)};
++    
++            getAttributeValue(&aTemplate, 1, NULL);
++
++            if (type == 0x3) {
++                setKeyType(ecc);
++                setAttributeULong(CKA_KEY_TYPE, CKK_EC);
++            } else {  
++                setKeyType(rsa);
++                setAttributeULong(CKA_KEY_TYPE, CKK_RSA);
++            }
++        } else {
++           /* default to rsa */
++           setKeyType(rsa);
++           setAttributeULong(CKA_KEY_TYPE, CKK_RSA); 
++        }
++
++    // Could be RSA or ECC
+     } else if (objClass == CKO_SECRET_KEY) {
+-	if (!attributeExists(CKA_LABEL)) {
+-	    setAttribute(CKA_LABEL, &empty);
+-	}
+-	if (!attributeExists(CKA_KEY_TYPE)) {
+-	    /* default to DES3 */
+-	    setAttributeULong(CKA_KEY_TYPE, CKK_DES3);
+-	}
++        if (!attributeExists(CKA_LABEL)) {
++            setAttribute(CKA_LABEL, &empty);
++        }
++        if (!attributeExists(CKA_KEY_TYPE)) {
++            /* default to DES3 */
++            setAttributeULong(CKA_KEY_TYPE, CKK_DES3);
++        }
+     }
+     if (!attributeExists(CKA_START_DATE)) {
+-	setAttribute(CKA_START_DATE, &empty);
++        setAttribute(CKA_START_DATE, &empty);
+     }
+     if (!attributeExists(CKA_END_DATE)) {
+-	setAttribute(CKA_END_DATE, &empty);
++        setAttribute(CKA_END_DATE, &empty);
+     }
+ }
+ 
+@@ -635,32 +960,59 @@
+ {
+     // infer key attributes from cert
+     bool modulusExists, exponentExists;
+-    CKYBuffer modulus; CKYBuffer_InitEmpty(&modulus);
+-    CKYBuffer exponent; CKYBuffer_InitEmpty(&exponent);
++    bool pointExists, paramsExists;
++
++    PKCS11Object::KeyType keyType;
++    const CKYBuffer *key = cert.getPubKey();
+ 
+     if (!attributeExists(CKA_LABEL)) {
+-	setAttribute(CKA_LABEL, cert.getAttribute(CKA_LABEL));
++        setAttribute(CKA_LABEL, cert.getAttribute(CKA_LABEL));
+     }
++
++    CKYBuffer param1; CKYBuffer_InitEmpty(&param1);
++    CKYBuffer param2; CKYBuffer_InitEmpty(&param2);
+     try {
+- 	modulusExists = attributeExists(CKA_MODULUS);
+-	exponentExists = attributeExists(CKA_PUBLIC_EXPONENT);
+-	if (!modulusExists || !exponentExists) {
+-	    const CKYBuffer *key = cert.getPubKey();
+-	    GetKeyFields(key, &modulus, &exponent);
+-	    if (!modulusExists) {
+-		setAttribute(CKA_MODULUS, &modulus);
+-	    }
+-	    if (!exponentExists) {
+-		setAttribute(CKA_PUBLIC_EXPONENT, &exponent);
+-	    }
+-	}
++        keyType = GetKeyTypeFromSPKI(key);
++        setKeyType(keyType);
++
++        switch (keyType) {
++        case rsa:
++            modulusExists = attributeExists(CKA_MODULUS);
++            exponentExists = attributeExists(CKA_PUBLIC_EXPONENT);
++            if (!modulusExists || !exponentExists) {
++                GetKeyFields(key, &param1, &param2);
++                if (!modulusExists) {
++                        setAttribute(CKA_MODULUS, &param1);
++                }
++                if (!exponentExists) {
++                      setAttribute(CKA_PUBLIC_EXPONENT, &param2);
++                }
++            }
++            break;
++        case ecc:
++            pointExists = attributeExists(CKA_EC_POINT);
++            paramsExists = attributeExists(CKA_EC_PARAMS);
++
++            if (!pointExists || !paramsExists) {
++                GetECKeyFields(key, &param1, &param2);
++                if (!pointExists) {
++                   setAttribute(CKA_EC_POINT, &param1);
++                }
++                if (!paramsExists) {
++                    setAttribute(CKA_EC_PARAMS, &param2);
++                }
++            }
++            break;
++        default:
++            break;
++        }
+     } catch (PKCS11Exception &e) {
+-	CKYBuffer_FreeData(&modulus);
+-	CKYBuffer_FreeData(&exponent);
+-	throw e;
++        CKYBuffer_FreeData(&param1);
++        CKYBuffer_FreeData(&param2);
++        throw e;
+     }
+-    CKYBuffer_FreeData(&modulus);
+-    CKYBuffer_FreeData(&exponent);
++    CKYBuffer_FreeData(&param1);
++    CKYBuffer_FreeData(&param2);
+ }
+ 
+ static SECStatus
+@@ -732,14 +1084,14 @@
+ 
+ static void
+ GetCertFields(const CKYBuffer *derCert, CKYBuffer *derSerial, 
+-	    CKYBuffer *derSubject, CKYBuffer *derIssuer, CKYBuffer *subjectKey)
++            CKYBuffer *derSubject, CKYBuffer *derIssuer, CKYBuffer *subjectKey)
+ {
+     SECStatus rv;
+     CCItem issuerItem, serialItem, derSerialItem, subjectItem,
+         validityItem, subjectKeyItem;
+ 
+     rv = GetCertFieldItems(CKYBuffer_Data(derCert), CKYBuffer_Size(derCert), 
+-	&issuerItem, &serialItem, &derSerialItem, &subjectItem, &validityItem,
++        &issuerItem, &serialItem, &derSerialItem, &subjectItem, &validityItem,
+         &subjectKeyItem);
+ 
+     if( rv != SECSuccess ) {
+@@ -764,50 +1116,50 @@
+     CK_ULONG certTypeValue = CKC_X_509;
+ 
+     CKYBuffer_InitFromData(&certType, (CKYByte *)&certTypeValue, 
+-						sizeof(certTypeValue));
++                                                sizeof(certTypeValue));
+     CKYBuffer_Resize(&pubKey,0);
+ 
+     try {
+- 	setAttribute(CKA_CERTIFICATE_TYPE, &certType);
++         setAttribute(CKA_CERTIFICATE_TYPE, &certType);
+ 
+-	if (!attributeExists(CKA_VALUE)) {
+-	    if (derCert) {
+-		 setAttribute(CKA_VALUE, derCert);
+-	    } else  {
+-		throw PKCS11Exception(CKR_DEVICE_ERROR, 
+-		    "Missing certificate data from token");
+-	    }
+-	}
++        if (!attributeExists(CKA_VALUE)) {
++            if (derCert) {
++                 setAttribute(CKA_VALUE, derCert);
++            } else  {
++                throw PKCS11Exception(CKR_DEVICE_ERROR, 
++                    "Missing certificate data from token");
++            }
++        }
+ 
+-	if (!derCert) {
+-	    derCert = getAttribute(CKA_VALUE);
+-	    if (!derCert) {
+-		// paranoia, should never happen since we verify the
+-		// attribute exists above
+-		throw PKCS11Exception(CKR_DEVICE_ERROR, 
+-		     "Missing certificate data from token");
+-	    }
+-	}
++        if (!derCert) {
++            derCert = getAttribute(CKA_VALUE);
++            if (!derCert) {
++                // paranoia, should never happen since we verify the
++                // attribute exists above
++                throw PKCS11Exception(CKR_DEVICE_ERROR, 
++                     "Missing certificate data from token");
++            }
++        }
+ 
+-	// infer cert attributes
++        // infer cert attributes
+ 
+-	GetCertFields(derCert, &derSerial, &derSubject, &derIssuer, &pubKey);
++        GetCertFields(derCert, &derSerial, &derSubject, &derIssuer, &pubKey);
+ 
+-	if (!attributeExists(CKA_SERIAL_NUMBER)) {
+-	    setAttribute(CKA_SERIAL_NUMBER, &derSerial);
+-	}
+-	if (!attributeExists(CKA_SUBJECT)) {
+-	    setAttribute(CKA_SUBJECT, &derSubject);
+-	}
+-	if (!attributeExists(CKA_ISSUER)) {
+-	    setAttribute(CKA_ISSUER, &derIssuer);
+-	}
++        if (!attributeExists(CKA_SERIAL_NUMBER)) {
++            setAttribute(CKA_SERIAL_NUMBER, &derSerial);
++        }
++        if (!attributeExists(CKA_SUBJECT)) {
++            setAttribute(CKA_SUBJECT, &derSubject);
++        }
++        if (!attributeExists(CKA_ISSUER)) {
++            setAttribute(CKA_ISSUER, &derIssuer);
++        }
+    } catch (PKCS11Exception &e) {
+-	CKYBuffer_FreeData(&certType);
+-	CKYBuffer_FreeData(&derSerial);
+-	CKYBuffer_FreeData(&derSubject);
+-	CKYBuffer_FreeData(&derIssuer);
+-	throw e;
++        CKYBuffer_FreeData(&certType);
++        CKYBuffer_FreeData(&derSerial);
++        CKYBuffer_FreeData(&derSubject);
++        CKYBuffer_FreeData(&derIssuer);
++        throw e;
+     }
+     CKYBuffer_FreeData(&certType);
+     CKYBuffer_FreeData(&derSerial);
+@@ -817,7 +1169,7 @@
+ 
+ Reader::Reader(unsigned long muscleObjID, CK_OBJECT_HANDLE handle, 
+     const char *reader, const CKYBuffer *cardATR, bool isCoolkey) : 
+-	PKCS11Object(muscleObjID, handle)
++        PKCS11Object(muscleObjID, handle)
+ {
+     setAttributeULong(CKA_CLASS, CKO_MOZ_READER);
+     setAttribute(CKA_LABEL, reader);
+@@ -828,9 +1180,10 @@
+     setAttribute(CKA_MOZ_ATR, cardATR);
+ }
+ 
+-CACPrivKey::CACPrivKey(CKYByte instance, const PKCS11Object &cert) : 
+-	PKCS11Object( ((int)'k') << 24 | ((int)instance+'0') << 16,
+-			 instance | 0x400)
++
++CACPrivKey::CACPrivKey(CKYByte instance, const PKCS11Object &cert,bool isPIV) : 
++        PKCS11Object( ((int)'k') << 24 | ((int)instance+'0') << 16,
++                         instance | 0x400)
+ {
+     CKYBuffer id;
+     CKYBuffer empty;
+@@ -838,8 +1191,10 @@
+ 
+     /* So we know what the key is supposed to be used for based on
+      * the instance */
+-    if (instance == 2) {
+-	decrypt = TRUE;
++    /* instance 2 is usually a decryption cert. >2 are usually old decryption 
++     * certs */
++    if (instance == 2 || (instance > (isPIV ? 3 : 2))) {
++        decrypt = TRUE;
+     }
+ 
+     CKYBuffer_InitEmpty(&empty);
+@@ -858,33 +1213,52 @@
+     setAttributeBool(CKA_LOCAL, TRUE);
+     setAttributeULong(CKA_KEY_TYPE, CKK_RSA);
+ 
+-    setAttributeBool(CKA_DECRYPT, decrypt);
+     setAttributeBool(CKA_SIGN, !decrypt);
+     setAttributeBool(CKA_SIGN_RECOVER, !decrypt);
+     setAttributeBool(CKA_UNWRAP, FALSE);
+     setAttributeBool(CKA_SENSITIVE, TRUE);
+     setAttributeBool(CKA_EXTRACTABLE, FALSE);
+ 
+-    CKYBuffer modulus; CKYBuffer_InitEmpty(&modulus);
+-    CKYBuffer exponent; CKYBuffer_InitEmpty(&exponent);
++    CKYBuffer param1; CKYBuffer_InitEmpty(&param1);
++    CKYBuffer param2; CKYBuffer_InitEmpty(&param2);
+ 
+     try {
+-	const CKYBuffer *key = cert.getPubKey();
+-	GetKeyFields(key, &modulus, &exponent);
+-	setAttribute(CKA_MODULUS, &modulus);
+-	setAttribute(CKA_PUBLIC_EXPONENT, &exponent);
+-    } catch (PKCS11Exception &e) {
+-	CKYBuffer_FreeData(&modulus);
+-	CKYBuffer_FreeData(&exponent);
+-	throw e;
+-    }
+-    CKYBuffer_FreeData(&modulus);
+-    CKYBuffer_FreeData(&exponent);
++        const CKYBuffer *key = cert.getPubKey();
++        keyType = GetKeyTypeFromSPKI(key);
++        setKeyType(keyType);
++
++        switch (keyType) {
++        case rsa:
++            GetKeyFields(key, &param1, &param2);
++            setAttribute(CKA_MODULUS, &param1);
++            setAttribute(CKA_PUBLIC_EXPONENT, &param2);
++	    setAttributeULong(CKA_KEY_TYPE, CKK_RSA);
++	    setAttributeBool(CKA_DECRYPT, decrypt);
++	    setAttributeBool(CKA_DERIVE, FALSE);
++            break;
++        case ecc:
++            GetECKeyFields(key, &param1, &param2);
++            setAttribute(CKA_EC_POINT, &param1);
++            setAttribute(CKA_EC_PARAMS, &param2);
++	    setAttributeULong(CKA_KEY_TYPE, CKK_EC);
++	    setAttributeBool(CKA_DECRYPT, FALSE);
++	    setAttributeBool(CKA_DERIVE, decrypt);
++            break;
++        default:
++            break;
++        }
++     } catch (PKCS11Exception &e) {
++        CKYBuffer_FreeData(&param1);
++        CKYBuffer_FreeData(&param2);
++        throw e;
++     }
++     CKYBuffer_FreeData(&param1);
++     CKYBuffer_FreeData(&param2);
+ }
+ 
+-CACPubKey::CACPubKey(CKYByte instance, const PKCS11Object &cert) : 
+-	PKCS11Object( ((int)'k') << 24 | ((int)(instance+'5')) << 16,
+-		       instance | 0x500)
++CACPubKey::CACPubKey(CKYByte instance, const PKCS11Object &cert, bool isPIV) : 
++        PKCS11Object( ((int)'k') << 24 | ((int)(instance+'a')) << 16,
++                       instance | 0x500)
+ {
+     CKYBuffer id;
+     CKYBuffer empty;
+@@ -892,8 +1266,8 @@
+ 
+     /* So we know what the key is supposed to be used for based on
+      * the instance */
+-    if (instance == 2) {
+-	encrypt = TRUE;
++    if (instance == 2 || (instance > (isPIV ? 3 : 2))) {
++        encrypt = TRUE;
+     }
+ 
+     CKYBuffer_InitEmpty(&empty);
+@@ -910,34 +1284,72 @@
+     setAttribute(CKA_END_DATE, &empty);
+     setAttributeBool(CKA_DERIVE, FALSE);
+     setAttributeBool(CKA_LOCAL, TRUE);
+-    setAttributeULong(CKA_KEY_TYPE, CKK_RSA);
+ 
+     setAttributeBool(CKA_ENCRYPT, encrypt);
+     setAttributeBool(CKA_VERIFY, !encrypt);
+     setAttributeBool(CKA_VERIFY_RECOVER, !encrypt);
+     setAttributeBool(CKA_WRAP, FALSE);
+ 
+-    CKYBuffer modulus; CKYBuffer_InitEmpty(&modulus);
+-    CKYBuffer exponent; CKYBuffer_InitEmpty(&exponent);
++    CKYBuffer param1; CKYBuffer_InitEmpty(&param1);
++    CKYBuffer param2; CKYBuffer_InitEmpty(&param2);
+ 
+     try {
+-	const CKYBuffer *key = cert.getPubKey();
+-	GetKeyFields(key, &modulus, &exponent);
+-	setAttribute(CKA_MODULUS, &modulus);
+-	setAttribute(CKA_PUBLIC_EXPONENT, &exponent);
+-    } catch (PKCS11Exception &e) {
+-	CKYBuffer_FreeData(&modulus);
+-	CKYBuffer_FreeData(&exponent);
+-	throw e;
+-    }
+-    CKYBuffer_FreeData(&modulus);
+-    CKYBuffer_FreeData(&exponent);
++        const CKYBuffer *key = cert.getPubKey();
++        keyType = GetKeyTypeFromSPKI(key);
++        setKeyType(keyType);
++
++        switch (keyType) {
++        case rsa:
++            GetKeyFields(key, &param1, &param2);
++            setAttribute(CKA_MODULUS, &param1);
++            setAttribute(CKA_PUBLIC_EXPONENT, &param2);
++	    setAttributeULong(CKA_KEY_TYPE, CKK_RSA);
++            break;
++        case ecc:
++            GetECKeyFields(key, &param1, &param2);
++            setAttribute(CKA_EC_POINT, &param1);
++            setAttribute(CKA_EC_PARAMS, &param2);
++	    setAttributeULong(CKA_KEY_TYPE, CKK_EC);
++    	    setAttributeBool(CKA_VERIFY_RECOVER, FALSE);
++    	    setAttributeBool(CKA_ENCRYPT, FALSE);
++    	    setAttributeBool(CKA_DERIVE, encrypt);
++            break;
++        default:
++            break;
++        }
++     } catch (PKCS11Exception &e) {
++        CKYBuffer_FreeData(&param1);
++        CKYBuffer_FreeData(&param2);
++        throw e;
++     }
++     CKYBuffer_FreeData(&param1);
++     CKYBuffer_FreeData(&param2);
+ }
+ 
+ static const char *CAC_Label[] = {
+-	"CAC ID Certificate",
+-	"CAC Email Signature Certificate",
+-	"CAC Email Encryption Certificate",
++        "CAC ID Certificate",
++        "CAC Email Signature Certificate",
++        "CAC Email Encryption Certificate",
++        "CAC Cert 3",
++        "CAC Cert 4",
++        "CAC Cert 5",
++        "CAC Cert 6",
++        "CAC Cert 7",
++        "CAC Cert 8",
++        "CAC Cert 9",
++};
++
++static const char *PIV_Label[] = {
++        "PIV ID Certificate",
++        "PIV Email Signature Certificate",
++        "PIV Email Encryption Certificate",
++        "PIV Card Authentication Certificate",
++        "PIV Cert 4",
++        "PIV Cert 5",
++        "PIV Cert 6",
++        "PIV Cert 7",
++        "PIV Cert 8",
++        "PIV Cert 9",
+ };
+ 
+ static const unsigned char CN_DATA[] = { 0x55, 0x4, 0x3 };
+@@ -954,39 +1366,43 @@
+     if (buf == NULL) return SECFailure;
+ 
+     while (buf_length) {
+-	const CKYByte *name;
+-	unsigned int name_length;
+-	const CKYByte *oid;
+-	unsigned int oid_length;
+-
+-	/* unwrap the set */
+-	name = dataStart(buf, buf_length, &name_length, false);
++        const CKYByte *name;
++        unsigned int name_length;
++        const CKYByte *oid;
++        unsigned int oid_length;
++
++        /* unwrap the set */
++        name = dataStart(buf, buf_length, &name_length, false);
++	if (name == NULL) return SECFailure;
+ 
+         /* advance to next set */
+-	buf_length -= (name-buf) + name_length;
+-	buf = name + name_length; 
++        buf_length -= (name-buf) + name_length;
++        buf = name + name_length; 
+ 
+-	/* unwrap the Sequence */
+-	name = dataStart(name, name_length, &name_length, false);
++        /* unwrap the Sequence */
++        name = dataStart(name, name_length, &name_length, false);
++	if (name == NULL) return SECFailure;
+ 
+         /* unwrap the oid */
+-	oid = dataStart(name, name_length, &oid_length, false);
++        oid = dataStart(name, name_length, &oid_length, false);
++	if (oid == NULL) return SECFailure;
+ 
+-	/* test the oid */
+-	if (oid_length != CN_LENGTH) {
+-	    continue;
+-	}
+-	if (memcmp(oid, CN_DATA, CN_LENGTH) != 0) {
+-	    continue;
+-	}
++        /* test the oid */
++        if (oid_length != CN_LENGTH) {
++            continue;
++        }
++        if (memcmp(oid, CN_DATA, CN_LENGTH) != 0) {
++            continue;
++        }
+ 
+-	/* advance to CN */
+-	name_length -= (oid-name) + oid_length;
+-	name = oid + oid_length;
+-
+-	/* unwrap the CN */
+-	cn->data = dataStart(name, name_length, &cn->len, false);
+-	return SECSuccess;
++        /* advance to CN */
++        name_length -= (oid-name) + oid_length;
++        name = oid + oid_length;
++
++        /* unwrap the CN */
++        cn->data = dataStart(name, name_length, &cn->len, false);
++	if (cn->data == NULL) return SECFailure;
++        return SECSuccess;
+     }
+     return SECFailure;
+ }
+@@ -1001,30 +1417,23 @@
+     rv = GetCN(CKYBuffer_Data(dn), CKYBuffer_Size(dn) , &cn);
+ 
+     if( rv != SECSuccess ) {
+-	return NULL;
++        return NULL;
+     }
+     string = new char [ cn.len + 1 ];
+     if (string == NULL) {
+-	return NULL;
++        return NULL;
+     }
+     memcpy(string, cn.data, cn.len);
+     string[cn.len] = 0;
+     return string;
+ }
+ 
+-CACCert::CACCert(CKYByte instance, const CKYBuffer *derCert) : 
+-	PKCS11Object( ((int)'c') << 24 | ((int)instance+'0') << 16, 
+-			instance | 0x600)
++CACCert::CACCert(CKYByte instance, const CKYBuffer *derCert, bool isPIV) : 
++        PKCS11Object( ((int)'c') << 24 | ((int)instance+'0') << 16, 
++                        instance | 0x600)
+ {
+     CKYBuffer id;
+     CKYBuffer empty;
+-    CK_BBOOL decrypt = FALSE;
+-
+-    /* So we know what the key is supposed to be used for based on
+-     * the instance */
+-    if (instance == 2) {
+-	decrypt = TRUE;
+-    }
+ 
+     CKYBuffer_InitEmpty(&empty);
+     setAttributeULong(CKA_CLASS, CKO_CERTIFICATE);
+@@ -1036,7 +1445,7 @@
+     setAttribute(CKA_ID, &id);
+     CKYBuffer_FreeData(&id);
+     setAttributeULong(CKA_CERTIFICATE_TYPE, CKC_X_509);
+-    setAttribute(CKA_LABEL, CAC_Label[instance]);
++    setAttribute(CKA_LABEL, isPIV ? PIV_Label[instance] : CAC_Label[instance]);
+ 
+     CKYBuffer derSerial; CKYBuffer_InitEmpty(&derSerial);
+     CKYBuffer derSubject; CKYBuffer_InitEmpty(&derSubject);
+@@ -1045,19 +1454,19 @@
+     CKYBuffer_Resize(&pubKey,0);
+ 
+     try {
+-	setAttribute(CKA_VALUE, derCert);
+-	// infer cert attributes
++        setAttribute(CKA_VALUE, derCert);
++        // infer cert attributes
+ 
+-	GetCertFields(derCert, &derSerial, &derSubject, &derIssuer, &pubKey);
++        GetCertFields(derCert, &derSerial, &derSubject, &derIssuer, &pubKey);
+ 
+-	setAttribute(CKA_SERIAL_NUMBER, &derSerial);
+-	setAttribute(CKA_SUBJECT, &derSubject);
+-	setAttribute(CKA_ISSUER, &derIssuer);
++        setAttribute(CKA_SERIAL_NUMBER, &derSerial);
++        setAttribute(CKA_SUBJECT, &derSubject);
++        setAttribute(CKA_ISSUER, &derIssuer);
+    } catch (PKCS11Exception &e) {
+-	CKYBuffer_FreeData(&derSerial);
+-	CKYBuffer_FreeData(&derSubject);
+-	CKYBuffer_FreeData(&derIssuer);
+-	throw e;
++        CKYBuffer_FreeData(&derSerial);
++        CKYBuffer_FreeData(&derSubject);
++        CKYBuffer_FreeData(&derIssuer);
++        throw e;
+     }
+ 
+     name = GetUserName(&derSubject); /* adopt */
+@@ -1065,3 +1474,100 @@
+     CKYBuffer_FreeData(&derSubject);
+     CKYBuffer_FreeData(&derIssuer);
+ }
++
++DEREncodedSignature::DEREncodedSignature(const CKYBuffer *derSig)
++{
++
++    CKYBuffer_InitEmpty(&derEncodedSignature);
++    CKYBuffer_InitFromCopy(&derEncodedSignature, derSig);
++}
++
++DEREncodedSignature::~DEREncodedSignature()
++{
++    CKYBuffer_FreeData(&derEncodedSignature);
++}
++
++int DEREncodedSignature::getRawSignature(CKYBuffer *rawSig, 
++					  unsigned int keySize)
++{
++    const CKYByte *buf = NULL;
++
++    if (rawSig == NULL) {
++        return -1;
++    }
++
++    if (CKYBuffer_Size(&derEncodedSignature) == 0) {
++        return -1;
++    }
++
++    CKYBuffer_Zero(rawSig);
++
++    unsigned int seq_length = 0;
++    unsigned int expected_sig_len = ( (keySize + 7) / 8 ) * 2 ;
++    unsigned int expected_piece_size = expected_sig_len / 2 ;
++
++    /* unwrap the sequence */
++    buf = dataStart(CKYBuffer_Data(&derEncodedSignature), CKYBuffer_Size(&derEncodedSignature),&seq_length, false);
++
++    if (buf == NULL) return -1;
++
++    // unwrap first multi byte integer
++   
++    unsigned int int_length = 0;
++    const CKYByte *int1Buf = NULL;
++    const CKYByte *int2Buf = NULL;
++
++    int1Buf = dataStart(buf, seq_length, &int_length, false );
++
++    if (int1Buf == NULL) return -1;
++    //advance to next entry
++
++    if (int_length > expected_piece_size) {
++
++      unsigned int diff = int_length - expected_piece_size ;
++
++      /* Make sure we are chopping off zeroes 
++         Otherwise give up. */
++
++      for (int i = 0 ; i < (int) diff ; i++) {
++          if ( int1Buf[i] != 0) 
++              return -1;
++      }
++
++      int_length -= diff;
++      int1Buf += diff;
++
++    }
++
++    seq_length -= (int1Buf -buf) + int_length;
++    buf = int1Buf +  int_length;
++
++    // unwrap second multi byte integer
++
++    unsigned int second_int_length = 0;
++
++    int2Buf = dataStart(buf, seq_length, &second_int_length, false);
++
++    if (int2Buf == NULL) return -1;
++
++
++    if (second_int_length > expected_piece_size) {
++        unsigned int diff = second_int_length - expected_piece_size ;
++
++        /* Make sure we are chopping off zeroes 
++           Otherwise give up. */
++
++        for (int i = 0 ;  i < (int)  diff ; i++) {
++            if ( int2Buf[i] != 0) 
++                return -1;
++        }
++      
++        second_int_length -= diff;
++        int2Buf += diff;
++    }
++
++    CKYBuffer_AppendData(rawSig, int1Buf, int_length);
++    CKYBuffer_AppendData(rawSig, int2Buf, second_int_length);
++
++    return CKYSUCCESS;
++}