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;
+}
