components/coolkey/patches/04-object.cpp.patch
author Stephen Gaul Jr <steve.gaul@oracle.com>
Tue, 12 Jul 2016 17:34:11 -0700
changeset 6401 8e624b116c1d
permissions -rw-r--r--
PSARC/2016/219 Coolkey PKCS#11 provider for smartcard devices 22017764 Add Coolkey v1.1.0 to Userland consolidation

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