--- /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, ¶msItem);
++
++ if( rv != SECSuccess ) {
++ throw PKCS11Exception(CKR_FUNCTION_FAILED,
++ "Failed to decode certificate Subject Public Key Info!");
++ }
++
++ CKYBuffer_Replace(point, 0, pointItem.data, pointItem.len);
++ CKYBuffer_Replace(params, 0, paramsItem.data, paramsItem.len);
++}
++
+ Key::Key(unsigned long muscleObjID, const CKYBuffer *data,
+ CK_OBJECT_HANDLE handle) : PKCS11Object(muscleObjID, data, handle)
+ {
+@@ -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(¶m1);
++ CKYBuffer param2; CKYBuffer_InitEmpty(¶m2);
+ try {
+- modulusExists = attributeExists(CKA_MODULUS);
+- exponentExists = attributeExists(CKA_PUBLIC_EXPONENT);
+- if (!modulusExists || !exponentExists) {
+- const CKYBuffer *key = cert.getPubKey();
+- GetKeyFields(key, &modulus, &exponent);
+- if (!modulusExists) {
+- setAttribute(CKA_MODULUS, &modulus);
+- }
+- if (!exponentExists) {
+- setAttribute(CKA_PUBLIC_EXPONENT, &exponent);
+- }
+- }
++ keyType = GetKeyTypeFromSPKI(key);
++ setKeyType(keyType);
++
++ switch (keyType) {
++ case rsa:
++ modulusExists = attributeExists(CKA_MODULUS);
++ exponentExists = attributeExists(CKA_PUBLIC_EXPONENT);
++ if (!modulusExists || !exponentExists) {
++ GetKeyFields(key, ¶m1, ¶m2);
++ if (!modulusExists) {
++ setAttribute(CKA_MODULUS, ¶m1);
++ }
++ if (!exponentExists) {
++ setAttribute(CKA_PUBLIC_EXPONENT, ¶m2);
++ }
++ }
++ break;
++ case ecc:
++ pointExists = attributeExists(CKA_EC_POINT);
++ paramsExists = attributeExists(CKA_EC_PARAMS);
++
++ if (!pointExists || !paramsExists) {
++ GetECKeyFields(key, ¶m1, ¶m2);
++ if (!pointExists) {
++ setAttribute(CKA_EC_POINT, ¶m1);
++ }
++ if (!paramsExists) {
++ setAttribute(CKA_EC_PARAMS, ¶m2);
++ }
++ }
++ break;
++ default:
++ break;
++ }
+ } catch (PKCS11Exception &e) {
+- CKYBuffer_FreeData(&modulus);
+- CKYBuffer_FreeData(&exponent);
+- throw e;
++ CKYBuffer_FreeData(¶m1);
++ CKYBuffer_FreeData(¶m2);
++ throw e;
+ }
+- CKYBuffer_FreeData(&modulus);
+- CKYBuffer_FreeData(&exponent);
++ CKYBuffer_FreeData(¶m1);
++ CKYBuffer_FreeData(¶m2);
+ }
+
+ static SECStatus
+@@ -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(¶m1);
++ CKYBuffer param2; CKYBuffer_InitEmpty(¶m2);
+
+ try {
+- const CKYBuffer *key = cert.getPubKey();
+- GetKeyFields(key, &modulus, &exponent);
+- setAttribute(CKA_MODULUS, &modulus);
+- setAttribute(CKA_PUBLIC_EXPONENT, &exponent);
+- } catch (PKCS11Exception &e) {
+- CKYBuffer_FreeData(&modulus);
+- CKYBuffer_FreeData(&exponent);
+- throw e;
+- }
+- CKYBuffer_FreeData(&modulus);
+- CKYBuffer_FreeData(&exponent);
++ const CKYBuffer *key = cert.getPubKey();
++ keyType = GetKeyTypeFromSPKI(key);
++ setKeyType(keyType);
++
++ switch (keyType) {
++ case rsa:
++ GetKeyFields(key, ¶m1, ¶m2);
++ setAttribute(CKA_MODULUS, ¶m1);
++ setAttribute(CKA_PUBLIC_EXPONENT, ¶m2);
++ setAttributeULong(CKA_KEY_TYPE, CKK_RSA);
++ setAttributeBool(CKA_DECRYPT, decrypt);
++ setAttributeBool(CKA_DERIVE, FALSE);
++ break;
++ case ecc:
++ GetECKeyFields(key, ¶m1, ¶m2);
++ setAttribute(CKA_EC_POINT, ¶m1);
++ setAttribute(CKA_EC_PARAMS, ¶m2);
++ setAttributeULong(CKA_KEY_TYPE, CKK_EC);
++ setAttributeBool(CKA_DECRYPT, FALSE);
++ setAttributeBool(CKA_DERIVE, decrypt);
++ break;
++ default:
++ break;
++ }
++ } catch (PKCS11Exception &e) {
++ CKYBuffer_FreeData(¶m1);
++ CKYBuffer_FreeData(¶m2);
++ throw e;
++ }
++ CKYBuffer_FreeData(¶m1);
++ CKYBuffer_FreeData(¶m2);
+ }
+
+-CACPubKey::CACPubKey(CKYByte instance, const PKCS11Object &cert) :
+- PKCS11Object( ((int)'k') << 24 | ((int)(instance+'5')) << 16,
+- instance | 0x500)
++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(¶m1);
++ CKYBuffer param2; CKYBuffer_InitEmpty(¶m2);
+
+ try {
+- const CKYBuffer *key = cert.getPubKey();
+- GetKeyFields(key, &modulus, &exponent);
+- setAttribute(CKA_MODULUS, &modulus);
+- setAttribute(CKA_PUBLIC_EXPONENT, &exponent);
+- } catch (PKCS11Exception &e) {
+- CKYBuffer_FreeData(&modulus);
+- CKYBuffer_FreeData(&exponent);
+- throw e;
+- }
+- CKYBuffer_FreeData(&modulus);
+- CKYBuffer_FreeData(&exponent);
++ const CKYBuffer *key = cert.getPubKey();
++ keyType = GetKeyTypeFromSPKI(key);
++ setKeyType(keyType);
++
++ switch (keyType) {
++ case rsa:
++ GetKeyFields(key, ¶m1, ¶m2);
++ setAttribute(CKA_MODULUS, ¶m1);
++ setAttribute(CKA_PUBLIC_EXPONENT, ¶m2);
++ setAttributeULong(CKA_KEY_TYPE, CKK_RSA);
++ break;
++ case ecc:
++ GetECKeyFields(key, ¶m1, ¶m2);
++ setAttribute(CKA_EC_POINT, ¶m1);
++ setAttribute(CKA_EC_PARAMS, ¶m2);
++ setAttributeULong(CKA_KEY_TYPE, CKK_EC);
++ setAttributeBool(CKA_VERIFY_RECOVER, FALSE);
++ setAttributeBool(CKA_ENCRYPT, FALSE);
++ setAttributeBool(CKA_DERIVE, encrypt);
++ break;
++ default:
++ break;
++ }
++ } catch (PKCS11Exception &e) {
++ CKYBuffer_FreeData(¶m1);
++ CKYBuffer_FreeData(¶m2);
++ throw e;
++ }
++ CKYBuffer_FreeData(¶m1);
++ CKYBuffer_FreeData(¶m2);
+ }
+
+ static const char *CAC_Label[] = {
+- "CAC ID Certificate",
+- "CAC Email Signature Certificate",
+- "CAC Email Encryption Certificate",
++ "CAC ID Certificate",
++ "CAC Email Signature Certificate",
++ "CAC Email Encryption Certificate",
++ "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;
++}