Merge pull request #28 from jimsch/master

Responses to coverity
Add ECDH functionality
diff --git a/Coverity_Model.c b/Coverity_Model.c
new file mode 100644
index 0000000..61e158c
--- /dev/null
+++ b/Coverity_Model.c
@@ -0,0 +1,31 @@
+void cn_cbor_free(void  *cb) {
+    __coverity_free__(cb);
+}
+
+void * cn_cbor_map_create(void * context, void * errp)
+{
+    __coverity_alloc__(10);
+}
+
+void * cn_cbor_data_create(const char * data, int len, void * context, void * errp)
+{
+    __coverity_alloc__(10);
+    __coverity_escape__(data);
+}
+
+void * cn_cbor_string_create(const char * data, void * context, void * errp)
+{
+    __coverity_alloc__(10);
+    __coverity_escape__(data);
+}
+
+void * cn_cbor_array_create(void * context, void * errp)
+{
+    __coverity_alloc__(10);
+}
+
+void * cn_cbor_decode(const char * pbuf, size_t len, void * context, void * errp)
+{
+    __coverity_alloc__(len);
+    __coverity_escape__(pbuf);
+}
diff --git a/dumper/dumper.c b/dumper/dumper.c
index 2f822dd..056a55e 100644
--- a/dumper/dumper.c
+++ b/dumper/dumper.c
@@ -249,6 +249,7 @@
 	vsprintf(buffer, format, args);
 	if (WrapLineAt == 0) {
 		fprintf(fp, "%s", buffer);
+        	va_end(args);
 		return;
 	}
 
diff --git a/src/Cose.c b/src/Cose.c
index 0b91912..33ac49d 100644
--- a/src/Cose.c
+++ b/src/Cose.c
@@ -228,6 +228,15 @@
 	return msg->m_cbor;
 }
 
+bool _COSE_SetExternal(COSE * pcose, const byte * pbExternalData, size_t cbExternalData, cose_errback * perr)
+{
+	pcose->m_pbExternal = pbExternalData;
+	pcose->m_cbExternal = cbExternalData;
+
+	return true;
+}
+
+
 cn_cbor * _COSE_map_get_int(COSE * pcose, int key, int flags, cose_errback * perror)
 {
 	cn_cbor * p = NULL;
diff --git a/src/Encrypt.c b/src/Encrypt.c
index 6e37da6..fbe5a75 100644
--- a/src/Encrypt.c
+++ b/src/Encrypt.c
@@ -127,83 +127,6 @@
 	_COSE_Release(&p->m_message);
 }
 
-HCOSE_RECIPIENT COSE_Enveloped_add_shared_secret(HCOSE_ENVELOPED hcose, COSE_Algorithms alg, byte * rgbKey, int cbKey, byte * rgbKid, int cbKid, cose_errback * perror)
-{
-#ifdef USE_CBOR_CONTEXT
-	cn_cbor_context * context;
-#endif // USE_CBOR_CONTEXT
-	COSE_RecipientInfo * pobj;
-	COSE_Enveloped * pcose = (COSE_Enveloped *)hcose;
-
-	if (!IsValidEnvelopedHandle(hcose) || (rgbKey == NULL)) {
-		if (perror != NULL) perror->err = COSE_ERR_INVALID_PARAMETER;
-		return NULL;
-	}
-
-	switch (alg) {
-	case COSE_Algorithm_Direct:
-		break;
-
-	default:
-		if (perror != NULL) perror->err = COSE_ERR_INVALID_PARAMETER;
-		return NULL;
-	}
-
-
-#ifdef USE_CBOR_CONTEXT
-	context = &pcose->m_message.m_allocContext;
-#endif // USE_CBOR_CONTEXT
-
-	pobj = (COSE_RecipientInfo *) COSE_CALLOC(1, sizeof(COSE_RecipientInfo) , context);
-	if (pobj == NULL) {
-		oom_error:
-		if (perror != NULL) perror->err = COSE_ERR_OUT_OF_MEMORY;
-	error:
-		// M00BUG COSE_Recipient_Free(pobj);
-		return NULL;
-	}
-
-	if (!_COSE_Init(&pobj->m_encrypt.m_message, COSE_unknown_object, CBOR_CONTEXT_PARAM_COMMA perror)) {
-		goto error;
-	}
-
-	if (!cn_cbor_mapput_int(pobj->m_encrypt.m_message.m_unprotectMap, COSE_Header_Algorithm, cn_cbor_int_create(alg, CBOR_CONTEXT_PARAM_COMMA NULL), CBOR_CONTEXT_PARAM_COMMA NULL)) goto error;
-
-	if (cbKid > 0) {
-		byte * pb = (byte *)COSE_CALLOC(cbKid, 1, context);
-		if (pb == NULL) goto oom_error;
-		memcpy(pb, rgbKid, cbKid);
-		if (!cn_cbor_mapput_int(pobj->m_encrypt.m_message.m_unprotectMap, COSE_Header_KID, cn_cbor_data_create(pb, cbKid, CBOR_CONTEXT_PARAM_COMMA NULL), CBOR_CONTEXT_PARAM_COMMA NULL)) {
-			COSE_FREE(pb, context);
-			goto oom_error; // M00BUG - get error from CBOR
-		}
-	}
-
-
-	pobj->m_encrypt.pbKey = (byte *) COSE_CALLOC(cbKey, 1, context);
-	if (pobj->m_encrypt.pbKey == NULL) goto error;
-	memcpy(pobj->m_encrypt.pbKey, rgbKey, cbKey);
-	pobj->m_encrypt.cbKey = cbKey;
-
-	pobj->m_recipientNext = pcose->m_recipientFirst;
-	pcose->m_recipientFirst = pobj;
-
-	cn_cbor * pRecipients = _COSE_arrayget_int(&pcose->m_message, INDEX_RECIPIENTS);
-	if (pRecipients == NULL) {
-		pRecipients = cn_cbor_array_create(CBOR_CONTEXT_PARAM_COMMA NULL);
-		if (pRecipients == NULL) goto error;
-		if (!_COSE_array_replace(&pcose->m_message, pRecipients, INDEX_RECIPIENTS, CBOR_CONTEXT_PARAM_COMMA NULL)) {
-			CN_CBOR_FREE(pRecipients, context);
-			goto error;
-		}
-	}
-
-	cn_cbor_array_append(pRecipients, pobj->m_encrypt.m_message.m_cbor, NULL);
-
-	pobj->m_encrypt.m_message.m_flags |= 1;
-	return (HCOSE_RECIPIENT) pobj;
-}
-
 bool COSE_Enveloped_decrypt(HCOSE_ENVELOPED h, HCOSE_RECIPIENT hRecip, cose_errback * perr)
 {
 	COSE_Enveloped * pcose = (COSE_Enveloped *)h;
@@ -371,7 +294,6 @@
 	COSE_RecipientInfo * pri;
 	const cn_cbor * cn_Alg = NULL;
 	byte * pbAuthData = NULL;
-	cn_cbor * ptmp = NULL;
 	size_t cbitKey;
 #ifdef USE_CBOR_CONTEXT
 	cn_cbor_context * context = NULL;
@@ -496,7 +418,6 @@
 
 errorReturn:
 	if (pbAuthData != NULL) COSE_FREE(pbAuthData, context);
-	if (ptmp != NULL) cn_cbor_free(ptmp CBOR_CONTEXT_PARAM);
 	return fRet;
 }
 
@@ -510,6 +431,17 @@
 	return _COSE_Enveloped_SetContent((COSE_Enveloped *)h, rgb, cb, perror);
 }
 
+bool COSE_Encrypt_SetExternal(HCOSE_ENVELOPED hcose, const byte * pbExternalData, size_t cbExternalData, cose_errback * perr)
+{
+	if (!IsValidEnvelopedHandle(hcose)) {
+		if (perr != NULL) perr->err = COSE_ERR_INVALID_PARAMETER;
+		return false;
+	}
+
+	return _COSE_SetExternal(&((COSE_Enveloped *)hcose)->m_message, pbExternalData, cbExternalData, perr);
+}
+
+
 bool _COSE_Enveloped_SetContent(COSE_Enveloped * cose, const byte * rgb, size_t cb, cose_errback * perror)
 {
 	byte * pb;
@@ -619,7 +551,7 @@
 	CHECK_CONDITION_CBOR(cn_cbor_array_append(pAuthData, ptmp, &cbor_error), cbor_error);
 	ptmp = NULL;
 
-	ptmp = cn_cbor_data_create(NULL, 0, CBOR_CONTEXT_PARAM_COMMA &cbor_error);
+	ptmp = cn_cbor_data_create(pMessage->m_pbExternal, (int) pMessage->m_cbExternal, CBOR_CONTEXT_PARAM_COMMA &cbor_error);
 	CHECK_CONDITION_CBOR(ptmp != NULL, cbor_error);
 	CHECK_CONDITION_CBOR(cn_cbor_array_append(pAuthData, ptmp, &cbor_error), cbor_error);
 	ptmp = NULL;
@@ -627,7 +559,7 @@
 	cbAuthData = cn_cbor_encoder_write(RgbDontUse, 0, sizeof(RgbDontUse), pAuthData);
 	pbAuthData = (byte *)COSE_CALLOC(cbAuthData, 1, context);
 	CHECK_CONDITION(pbAuthData != NULL, COSE_ERR_OUT_OF_MEMORY);
-	CHECK_CONDITION(cn_cbor_encoder_write(pbAuthData, 0, cbAuthData, pAuthData) == cbAuthData, COSE_ERR_CBOR);
+	CHECK_CONDITION((size_t)cn_cbor_encoder_write(pbAuthData, 0, cbAuthData, pAuthData) == cbAuthData, COSE_ERR_CBOR);
 
 	*ppbAAD = pbAuthData;
 	*pcbAAD = cbAuthData;
diff --git a/src/Encrypt0.c b/src/Encrypt0.c
index f305b78..da2bc92 100644
--- a/src/Encrypt0.c
+++ b/src/Encrypt0.c
@@ -122,14 +122,13 @@
 {
 	int alg;
 	const cn_cbor * cn = NULL;
-	int cbitKey;
+	size_t cbitKey;
 
 #ifdef USE_CBOR_CONTEXT
 	cn_cbor_context * context;
 #endif
 	byte * pbAuthData = NULL;
 	size_t cbAuthData;
-	cn_cbor * pAuthData = NULL;
 	byte * pbProtected = NULL;
 	ssize_t cbProtected;
 
@@ -143,7 +142,6 @@
 	errorReturn:
 		if (pbProtected != NULL) COSE_FREE(pbProtected, context);
 		if (pbAuthData != NULL) COSE_FREE(pbAuthData, context);
-		if (pAuthData != NULL) cn_cbor_free(pAuthData CBOR_CONTEXT_PARAM);
 		return false;
 	}
 	CHECK_CONDITION((cn->type == CN_CBOR_UINT) || (cn->type == CN_CBOR_INT), COSE_ERR_INVALID_PARAMETER);
@@ -241,7 +239,6 @@
 
 	if (pbProtected != NULL) COSE_FREE(pbProtected, context);
 	if (pbAuthData != NULL) COSE_FREE(pbAuthData, context);
-	if (pAuthData != NULL) cn_cbor_free(pAuthData CBOR_CONTEXT_PARAM);
 	if (perr != NULL) perr->err = COSE_ERR_NONE;
 
 	return true;
@@ -252,13 +249,12 @@
 	int alg;
 	const cn_cbor * cn_Alg = NULL;
 	byte * pbAuthData = NULL;
-	cn_cbor * pAuthData = NULL;
-	cn_cbor * ptmp = NULL;
 	size_t cbitKey;
 #ifdef USE_CBOR_CONTEXT
 	cn_cbor_context * context = NULL;
 #endif
 	COSE_Encrypt * pcose = (COSE_Encrypt *) h;
+	bool fRet = false;
 
 	CHECK_CONDITION(IsValidEncryptHandle(h), COSE_ERR_INVALID_PARAMETER);
 
@@ -344,16 +340,11 @@
 
 	//  Figure out the clean up
 
-	if (pbAuthData != NULL) COSE_FREE(pbAuthData, context);
-	if (pAuthData != NULL) cn_cbor_free(pAuthData CBOR_CONTEXT_PARAM);
-
-	return true;
+	fRet = true;
 
 errorReturn:
 	if (pbAuthData != NULL) COSE_FREE(pbAuthData, context);
-	if (pAuthData != NULL) cn_cbor_free(pAuthData CBOR_CONTEXT_PARAM);
-	if (ptmp != NULL) cn_cbor_free(ptmp CBOR_CONTEXT_PARAM);
-	return false;
+	return fRet;
 }
 
 bool COSE_Encrypt_SetContent(HCOSE_ENCRYPT h, const byte * rgb, size_t cb, cose_errback * perror)
diff --git a/src/MacMessage.c b/src/MacMessage.c
index 39ab062..efd6b17 100644
--- a/src/MacMessage.c
+++ b/src/MacMessage.c
@@ -131,102 +131,6 @@
 }
 
 
-HCOSE_RECIPIENT COSE_Mac_add_shared_secret(HCOSE_MAC hcose, COSE_Algorithms alg, byte * rgbKey, int cbKey, byte * rgbKid, int cbKid, cose_errback * perr)
-{
-#ifdef USE_CBOR_CONTEXT
-	cn_cbor_context * context = NULL;
-#endif // USE_CBOR_CONTEXT
-
-	COSE_MacMessage * pcose = (COSE_MacMessage *)hcose;
-	cn_cbor * cn_Temp = NULL;
-	cn_cbor * pRecipients = NULL;
-	cn_cbor * pRecipientsNew = NULL;
-	byte * pbKey = NULL;
-	byte * pbTemp = NULL;
-	cn_cbor * cnTemp = NULL;
-	cn_cbor_errback cbor_error;
-	HCOSE_RECIPIENT hRecipient = NULL;
-
-	CHECK_CONDITION(IsValidMacHandle(hcose) && (rgbKey != NULL), COSE_ERR_INVALID_PARAMETER);
-
-#ifdef USE_CBOR_CONTEXT
-	context = &pcose->m_message.m_allocContext;
-#endif // USE_CBOR_CONTEXT
-
-	switch (alg) {
-	case COSE_Algorithm_Direct:
-		break;
-
-	default:
-		FAIL_CONDITION(COSE_ERR_INVALID_PARAMETER);
-	}
-
-	hRecipient = COSE_Recipient_Init(CBOR_CONTEXT_PARAM_COMMA perr);
-	if (hRecipient == NULL) goto errorReturn;
-
-	cn_Temp = cn_cbor_int_create(alg, CBOR_CONTEXT_PARAM_COMMA &cbor_error);
-	CHECK_CONDITION_CBOR(cn_Temp != NULL, cbor_error);
-	if (!COSE_Recipient_map_put(hRecipient, COSE_Header_Algorithm, cn_Temp, COSE_UNPROTECT_ONLY, perr)) goto errorReturn;
-	cn_Temp = NULL;
-
-	if (cbKid > 0) {
-		pbTemp = (byte *)COSE_CALLOC(cbKid, 1, context);
-		CHECK_CONDITION(pbTemp != NULL, COSE_ERR_OUT_OF_MEMORY);
-
-		memcpy(pbTemp, rgbKid, cbKid);
-		cnTemp = cn_cbor_data_create(pbTemp, cbKid, CBOR_CONTEXT_PARAM_COMMA &cbor_error);
-		CHECK_CONDITION_CBOR(cnTemp != NULL, cbor_error);
-		pbTemp = NULL;
-
-		if (!COSE_Recipient_map_put(hRecipient, COSE_Header_KID, cnTemp, COSE_UNPROTECT_ONLY, perr)) goto errorReturn;
-	}
-
-
-	 pbKey = (byte *)COSE_CALLOC(cbKey, 1, context);
-	CHECK_CONDITION(pbKey != NULL, COSE_ERR_OUT_OF_MEMORY);
-
-	memcpy(pbKey, rgbKey, cbKey);
-
-	cn_Temp = cn_cbor_map_create(CBOR_CONTEXT_PARAM_COMMA &cbor_error);
-	CHECK_CONDITION_CBOR(cn_Temp != NULL, cbor_error);
-
-	cnTemp = cn_cbor_int_create(4, CBOR_CONTEXT_PARAM_COMMA &cbor_error);
-	CHECK_CONDITION_CBOR(cnTemp != NULL, cbor_error);
-	CHECK_CONDITION_CBOR(cn_cbor_mapput_int(cn_Temp, COSE_Key_Type, cnTemp, CBOR_CONTEXT_PARAM_COMMA &cbor_error), cbor_error);
-	cnTemp = NULL;
-
-	cnTemp = cn_cbor_data_create(pbKey, cbKey, CBOR_CONTEXT_PARAM_COMMA &cbor_error);
-	CHECK_CONDITION_CBOR(cnTemp != NULL, cbor_error);
-	CHECK_CONDITION_CBOR(cn_cbor_mapput_int(cn_Temp, -1, cnTemp, CBOR_CONTEXT_PARAM_COMMA &cbor_error), cbor_error);
-	cnTemp = NULL;
-
-	if (!COSE_Recipient_SetKey(hRecipient, cn_Temp, perr)) goto errorReturn;
-	cn_Temp = NULL;
-
-	pRecipients = _COSE_arrayget_int(&pcose->m_message, INDEX_MAC_RECIPIENTS);
-	if (pRecipients == NULL) {
-		pRecipients = pRecipientsNew = cn_cbor_array_create(CBOR_CONTEXT_PARAM_COMMA &cbor_error);
-		CHECK_CONDITION_CBOR(pRecipients != NULL, cbor_error);
-
-		CHECK_CONDITION_CBOR(_COSE_array_replace(&pcose->m_message, pRecipients, INDEX_MAC_RECIPIENTS, CBOR_CONTEXT_PARAM_COMMA &cbor_error), cbor_error);
-		pRecipientsNew = NULL;
-	}
-
-	CHECK_CONDITION(pcose->m_recipientFirst == NULL, COSE_ERR_INVALID_PARAMETER);
-	pcose->m_recipientFirst = (COSE_RecipientInfo *)hRecipient;
-	pcose->m_recipientFirst->m_encrypt.m_message.m_refCount++;
-	CHECK_CONDITION_CBOR(cn_cbor_array_append(pRecipients, ((COSE_RecipientInfo *) hRecipient)->m_encrypt.m_message.m_cbor, &cbor_error), cbor_error);
-
-	return hRecipient;
-
-errorReturn:
-	if (cn_Temp != NULL) CN_CBOR_FREE(cn_Temp, context);
-	if (cnTemp != NULL) CN_CBOR_FREE(cnTemp, context);
-	if (pRecipientsNew != NULL) CN_CBOR_FREE(pRecipientsNew, context);
-	if (hRecipient != NULL) COSE_Recipient_Free(hRecipient);
-	return NULL;
-}
-
 bool COSE_Mac_SetContent(HCOSE_MAC cose, const byte * rgbContent, size_t cbContent, cose_errback * perr)
 {
 	COSE_MacMessage * p = (COSE_MacMessage *)cose;
diff --git a/src/MacMessage0.c b/src/MacMessage0.c
index 1d04e93..af1723f 100644
--- a/src/MacMessage0.c
+++ b/src/MacMessage0.c
@@ -159,14 +159,15 @@
 	int alg;
 	const cn_cbor * cn_Alg = NULL;
 	byte * pbAuthData = NULL;
-	cn_cbor * pAuthData = NULL;
-	cn_cbor * ptmp = NULL;
 	size_t cbitKey;
 #ifdef USE_CBOR_CONTEXT
 	cn_cbor_context * context = NULL;
 #endif
 	COSE_Mac0Message * pcose = (COSE_Mac0Message *)h;
 	cn_cbor_errback cbor_error;
+	bool fRet = false;
+	cn_cbor * pAuthData = NULL;
+	cn_cbor * ptmp = NULL;
 
 	CHECK_CONDITION(IsValidMac0Handle(h), COSE_ERR_INVALID_PARAMETER);
 
@@ -250,7 +251,7 @@
 	CHECK_CONDITION(cbAuthData > 0, COSE_ERR_CBOR);
 	pbAuthData = (byte *)COSE_CALLOC(cbAuthData, 1, context);
 	CHECK_CONDITION(pbAuthData != NULL, COSE_ERR_OUT_OF_MEMORY);
-	CHECK_CONDITION(cn_cbor_encoder_write(pbAuthData, 0, cbAuthData, pAuthData) == cbAuthData, COSE_ERR_CBOR);
+	CHECK_CONDITION((size_t)cn_cbor_encoder_write(pbAuthData, 0, cbAuthData, pAuthData) == cbAuthData, COSE_ERR_CBOR);
 
 	switch (alg) {
 	case COSE_Algorithm_CBC_MAC_128_64:
@@ -285,16 +286,13 @@
 
 	//  Figure out the clean up
 
-	if (pbAuthData != NULL) COSE_FREE(pbAuthData, context);
-	if (pAuthData != NULL) cn_cbor_free(pAuthData CBOR_CONTEXT_PARAM);
-	if (ptmp != NULL) cn_cbor_free(ptmp CBOR_CONTEXT_PARAM);
-	return true;
+	fRet = true;
 
 errorReturn:
 	if (pbAuthData != NULL) COSE_FREE(pbAuthData, context);
 	if (pAuthData != NULL) cn_cbor_free(pAuthData CBOR_CONTEXT_PARAM);
 	if (ptmp != NULL) cn_cbor_free(ptmp CBOR_CONTEXT_PARAM);
-	return false;
+	return fRet;
 }
 
 byte RgbDontUseMac[1024];
diff --git a/src/Recipient.c b/src/Recipient.c
index 71e594e..1a1afb9 100644
--- a/src/Recipient.c
+++ b/src/Recipient.c
@@ -46,10 +46,75 @@
 		return true;
 	}
 
-
 	return false;
 }
 
+HCOSE_RECIPIENT COSE_Recipient_from_shared_secret(byte * rgbKey, int cbKey, byte * rgbKid, int cbKid, CBOR_CONTEXT_COMMA cose_errback * perr)
+{
+	cn_cbor * cn_Temp = NULL;
+	cn_cbor * pRecipientsNew = NULL;
+	byte * pbKey = NULL;
+	byte * pbTemp = NULL;
+	cn_cbor * cnTemp = NULL;
+	cn_cbor_errback cbor_error;
+	HCOSE_RECIPIENT hRecipient = NULL;
+
+	int alg = COSE_Algorithm_Direct;
+
+	hRecipient = COSE_Recipient_Init(CBOR_CONTEXT_PARAM_COMMA perr);
+	if (hRecipient == NULL) goto errorReturn;
+
+	cn_Temp = cn_cbor_int_create(alg, CBOR_CONTEXT_PARAM_COMMA &cbor_error);
+	CHECK_CONDITION_CBOR(cn_Temp != NULL, cbor_error);
+	if (!COSE_Recipient_map_put(hRecipient, COSE_Header_Algorithm, cn_Temp, COSE_UNPROTECT_ONLY, perr)) goto errorReturn;
+	cn_Temp = NULL;
+
+	if (cbKid > 0) {
+		pbTemp = (byte *)COSE_CALLOC(cbKid, 1, context);
+		CHECK_CONDITION(pbTemp != NULL, COSE_ERR_OUT_OF_MEMORY);
+
+		memcpy(pbTemp, rgbKid, cbKid);
+		cnTemp = cn_cbor_data_create(pbTemp, cbKid, CBOR_CONTEXT_PARAM_COMMA &cbor_error);
+		CHECK_CONDITION_CBOR(cnTemp != NULL, cbor_error);
+		pbTemp = NULL;
+
+		if (!COSE_Recipient_map_put(hRecipient, COSE_Header_KID, cnTemp, COSE_UNPROTECT_ONLY, perr)) goto errorReturn;
+	}
+
+
+	pbKey = (byte *)COSE_CALLOC(cbKey, 1, context);
+	CHECK_CONDITION(pbKey != NULL, COSE_ERR_OUT_OF_MEMORY);
+
+	memcpy(pbKey, rgbKey, cbKey);
+
+	cn_Temp = cn_cbor_map_create(CBOR_CONTEXT_PARAM_COMMA &cbor_error);
+	CHECK_CONDITION_CBOR(cn_Temp != NULL, cbor_error);
+
+	cnTemp = cn_cbor_int_create(4, CBOR_CONTEXT_PARAM_COMMA &cbor_error);
+	CHECK_CONDITION_CBOR(cnTemp != NULL, cbor_error);
+	CHECK_CONDITION_CBOR(cn_cbor_mapput_int(cn_Temp, COSE_Key_Type, cnTemp, CBOR_CONTEXT_PARAM_COMMA &cbor_error), cbor_error);
+	cnTemp = NULL;
+
+	cnTemp = cn_cbor_data_create(pbKey, cbKey, CBOR_CONTEXT_PARAM_COMMA &cbor_error);
+	CHECK_CONDITION_CBOR(cnTemp != NULL, cbor_error);
+	pbKey = NULL;
+	CHECK_CONDITION_CBOR(cn_cbor_mapput_int(cn_Temp, -1, cnTemp, CBOR_CONTEXT_PARAM_COMMA &cbor_error), cbor_error);
+	cnTemp = NULL;
+
+	if (!COSE_Recipient_SetKey(hRecipient, cn_Temp, perr)) goto errorReturn;
+	cn_Temp = NULL;
+
+	return hRecipient;
+
+errorReturn:
+	if (cn_Temp != NULL) CN_CBOR_FREE(cn_Temp, context);
+	if (cnTemp != NULL) CN_CBOR_FREE(cnTemp, context);
+	if (pRecipientsNew != NULL) CN_CBOR_FREE(pRecipientsNew, context);
+	if (hRecipient != NULL) COSE_Recipient_Free(hRecipient);
+	if (pbKey != NULL) COSE_FREE(pbKey, context);
+	return NULL;
+}
+
 
 HCOSE_RECIPIENT COSE_Enveloped_GetRecipient(HCOSE_ENVELOPED cose, int iRecipient, cose_errback * perr)
 {
@@ -115,6 +180,82 @@
 	return;
 }
 
+/**
+* Perform an AES-CCM Decryption operation
+*
+* @param[in]	COSE *		Pointer to COSE Encryption context object
+* @param[in]	int			Alorithm key is being generated for
+* @param[in]	cn_cbor *	Key used for operation
+* @param[out]	byte *		Buffer to return new key in	
+* @param[in]	size_t       Size of key to create in bits
+* @param[in]    size_t		Size of digest function
+* @param[in]	cbor_context * Allocation context
+* @param[out]	cose_errback * Returned error information
+* @return                   Did the function succeed?
+*/
+
+static bool HKDF_X(COSE * pCose, bool fHMAC, bool fECDH, bool fStatic, bool fSend, int algResult, const cn_cbor * pKey, byte * pbKey, size_t cbitKey, size_t cbitHash, CBOR_CONTEXT_COMMA cose_errback * perr)
+{
+	byte * pbContext = NULL;
+	size_t cbContext;
+	bool fRet = false;
+	const cn_cbor * cn;
+	byte rgbDigest[512 / 8];
+	size_t cbDigest;
+	byte * pbSecret = NULL;
+	size_t cbSecret = 0;
+
+	if (!BuildContextBytes(pCose, algResult, cbitKey, &pbContext, &cbContext, CBOR_CONTEXT_PARAM_COMMA perr)) goto errorReturn;
+
+	cn = cn_cbor_mapget_int(pKey, COSE_Key_Type);
+	CHECK_CONDITION((cn != NULL) && (cn->type == CN_CBOR_UINT), COSE_ERR_INVALID_PARAMETER);
+
+	if (fECDH) {
+		cn_cbor * pkeyMessage;
+
+		pkeyMessage = _COSE_map_get_int(pCose, fStatic ? COSE_Header_ECDH_STATIC : COSE_Header_ECDH_EPHEMERAL, COSE_BOTH, perr);
+
+		CHECK_CONDITION(pKey != NULL, COSE_ERR_INVALID_PARAMETER);
+		if (fSend) {
+			if (!ECDH_ComputeSecret(pCose, &pkeyMessage, pKey, &pbSecret, &cbSecret, CBOR_CONTEXT_PARAM_COMMA perr)) goto errorReturn;
+			if (pkeyMessage->parent == NULL) {
+				if (!_COSE_map_put(pCose, COSE_Header_ECDH_EPHEMERAL, pkeyMessage, COSE_UNPROTECT_ONLY, perr)) goto errorReturn;
+			}
+		}
+		else {
+			CHECK_CONDITION(pkeyMessage != NULL, COSE_ERR_INVALID_PARAMETER);
+			if (!ECDH_ComputeSecret(pCose, (cn_cbor **)&pKey, pkeyMessage, &pbSecret, &cbSecret, CBOR_CONTEXT_PARAM_COMMA perr)) goto errorReturn;
+		}
+	}
+	else {
+		CHECK_CONDITION(cn->v.sint == 4, COSE_ERR_INVALID_PARAMETER);
+
+		cn = cn_cbor_mapget_int(pKey, -1);
+		CHECK_CONDITION((cn != NULL) && (cn->type == CN_CBOR_BYTES), COSE_ERR_INVALID_PARAMETER);
+		pbSecret = (byte *) cn->v.bytes;
+		cbSecret = cn->length;
+	}
+
+	if (fHMAC) {
+		if (!HKDF_Extract(pCose, pbSecret, cbSecret, cbitHash, rgbDigest, &cbDigest, CBOR_CONTEXT_PARAM_COMMA perr)) goto errorReturn;
+
+		if (!HKDF_Expand(pCose, cbitHash, rgbDigest, cbDigest, pbContext, cbContext, pbKey, cbitKey / 8, perr)) goto errorReturn;
+	}
+	else {
+		if (!HKDF_AES_Expand(pCose, cbitHash, pbSecret, cbSecret, pbContext, cbContext, pbKey, cbitKey / 8, perr)) goto errorReturn;
+	}
+	fRet = true;
+
+errorReturn:
+	if (fECDH && pbSecret != NULL) {
+		memset(pbSecret, 0, cbSecret);
+		COSE_FREE(pbSecret, context);
+	}
+	memset(rgbDigest, 0, sizeof(rgbDigest));
+	if (pbContext != NULL) COSE_FREE(pbContext, context);
+	return fRet;
+}
+
 bool _COSE_Recipient_decrypt(COSE_RecipientInfo * pRecip, int algIn, int cbitKey, byte * pbKeyIn, cose_errback * perr)
 {
 	int alg;
@@ -125,17 +266,13 @@
 	cn_cbor_context * context;
 #endif
 	byte * pbAuthData = NULL;
-	cn_cbor * pAuthData = NULL;
 	byte * pbProtected = NULL;
 	COSE_Enveloped * pcose = &pRecip->m_encrypt;
 	cn_cbor * cnBody = NULL;
 	byte * pbContext = NULL;
-	size_t cbContext;
-	byte rgbDigest[512 / 8];
-	size_t cbDigest;
-	cn_cbor * pkey = NULL;
+	byte rgbKey[256 / 8];
 	byte * pbSecret = NULL;
-	size_t cbSecret;
+	int cbKey2;
 
 #ifdef USE_CBOR_CONTEXT
 	context = &pcose->m_message.m_allocContext;
@@ -147,7 +284,6 @@
 		if (pbContext != NULL) COSE_FREE(pbContext, context);
 		if (pbProtected != NULL) COSE_FREE(pbProtected, context);
 		if (pbAuthData != NULL) COSE_FREE(pbAuthData, context);
-		if (pAuthData != NULL) cn_cbor_free(pAuthData CBOR_CONTEXT_PARAM);
 		if (pbSecret != NULL) COSE_FREE(pbSecret, context);
 		return false;
 	}
@@ -184,6 +320,18 @@
 
 	case COSE_Algorithm_ECDH_ES_HKDF_256:
 	case COSE_Algorithm_ECDH_ES_HKDF_512:
+	case COSE_Algorithm_ECDH_SS_HKDF_256:
+	case COSE_Algorithm_ECDH_SS_HKDF_512:
+		break;
+
+	case COSE_Algorithm_ECDH_ES_A128KW:
+	case COSE_Algorithm_ECDH_ES_A192KW:
+	case COSE_Algorithm_ECDH_ES_A256KW:
+		break;
+
+	case COSE_Algorithm_ECDH_SS_A128KW:
+	case COSE_Algorithm_ECDH_SS_A192KW:
+	case COSE_Algorithm_ECDH_SS_A256KW:
 		break;
 
 	default:
@@ -219,74 +367,76 @@
 		break;
 
 	case COSE_Algorithm_Direct_HKDF_HMAC_SHA_256:
-		if (!BuildContextBytes(&pcose->m_message, algIn, cbitKey, &pbContext, &cbContext, CBOR_CONTEXT_PARAM_COMMA perr)) goto errorReturn;
-
-		cn = cn_cbor_mapget_int(pRecip->m_pkey, -1);
-		CHECK_CONDITION((cn != NULL) && (cn->type == CN_CBOR_BYTES), COSE_ERR_INVALID_PARAMETER);
-
-		if (!HKDF_Extract(&pcose->m_message, cn->v.bytes, cn->length, 256, rgbDigest, &cbDigest, CBOR_CONTEXT_PARAM_COMMA perr)) goto errorReturn;
-
-		if (!HKDF_Expand(&pcose->m_message, 256, rgbDigest, cbDigest, pbContext, cbContext, pbKey, cbitKey / 8, perr)) goto errorReturn;
-
+		if (!HKDF_X(&pcose->m_message, true, false, false, false, algIn, pRecip->m_pkey, pbKey, cbitKey, 256, CBOR_CONTEXT_PARAM_COMMA perr)) goto errorReturn;
 		break;
 
 	case COSE_Algorithm_Direct_HKDF_HMAC_SHA_512:
-		if (!BuildContextBytes(&pcose->m_message, algIn, cbitKey, &pbContext, &cbContext, CBOR_CONTEXT_PARAM_COMMA perr)) goto errorReturn;
-
-		cn = cn_cbor_mapget_int(pRecip->m_pkey, -1);
-		CHECK_CONDITION((cn != NULL) && (cn->type == CN_CBOR_BYTES), COSE_ERR_INVALID_PARAMETER);
-
-		if (!HKDF_Extract(&pcose->m_message, cn->v.bytes, cn->length, 512, rgbDigest, &cbDigest, CBOR_CONTEXT_PARAM_COMMA perr)) goto errorReturn;
-
-		if (!HKDF_Expand(&pcose->m_message, 512, rgbDigest, cbDigest, pbContext, cbContext, pbKey, cbitKey / 8, perr)) goto errorReturn;
-
+		if (!HKDF_X(&pcose->m_message, true, false, false, false, algIn, pRecip->m_pkey, pbKey, cbitKey, 512, CBOR_CONTEXT_PARAM_COMMA perr)) goto errorReturn;
 		break;
 
 	case COSE_Algorithm_Direct_HKDF_AES_128:
-		if (!BuildContextBytes(&pcose->m_message, algIn, cbitKey, &pbContext, &cbContext, CBOR_CONTEXT_PARAM_COMMA perr)) goto errorReturn;
-
-		cn = cn_cbor_mapget_int(pRecip->m_pkey, -1);
-		CHECK_CONDITION((cn != NULL) && (cn->type == CN_CBOR_BYTES), COSE_ERR_INVALID_PARAMETER);
-
-		if (!HKDF_AES_Expand(&pcose->m_message, 128, cn->v.bytes, cn->length, pbContext, cbContext, pbKey, cbitKey / 8, perr)) goto errorReturn;
+		if (!HKDF_X(&pcose->m_message, false, false, false, false, algIn, pRecip->m_pkey, pbKey, cbitKey, 128, CBOR_CONTEXT_PARAM_COMMA perr)) goto errorReturn;
 		break;
 
 	case COSE_Algorithm_Direct_HKDF_AES_256:
-		if (!BuildContextBytes(&pcose->m_message, algIn, cbitKey, &pbContext, &cbContext, CBOR_CONTEXT_PARAM_COMMA perr)) goto errorReturn;
-
-		cn = cn_cbor_mapget_int(pRecip->m_pkey, -1);
-		CHECK_CONDITION((cn != NULL) && (cn->type == CN_CBOR_BYTES), COSE_ERR_INVALID_PARAMETER);
-
-		if (!HKDF_AES_Expand(&pcose->m_message, 256, cn->v.bytes, cn->length, pbContext, cbContext, pbKey, cbitKey / 8, perr)) goto errorReturn;
+		if (!HKDF_X(&pcose->m_message, false, false, false, false, algIn, pRecip->m_pkey, pbKey, cbitKey, 256, CBOR_CONTEXT_PARAM_COMMA perr)) goto errorReturn;
 		break;
 
 	case COSE_Algorithm_ECDH_ES_HKDF_256:
-		if (!BuildContextBytes(&pcose->m_message, algIn, cbitKey, &pbContext, &cbContext, CBOR_CONTEXT_PARAM_COMMA perr)) goto errorReturn;
-
-		pkey = _COSE_map_get_int(&pcose->m_message, COSE_Header_ECDH_EPHEMERAL, COSE_BOTH, perr);
-		if (pkey == NULL) goto errorReturn;
-
-		CHECK_CONDITION(pRecip->m_pkey != NULL, COSE_ERR_INVALID_PARAMETER);
-		if (!ECDH_ComputeSecret(&pcose->m_message, (cn_cbor **) &pRecip->m_pkey, pkey, &pbSecret, &cbSecret, CBOR_CONTEXT_PARAM_COMMA perr)) goto errorReturn;
-
-		if (!HKDF_Extract(&pcose->m_message, pbSecret, cbSecret, 256, rgbDigest, &cbDigest, CBOR_CONTEXT_PARAM_COMMA perr)) goto errorReturn;
-
-		if (!HKDF_Expand(&pcose->m_message, 256, rgbDigest, cbDigest, pbContext, cbContext, pbKey, cbitKey / 8, perr)) goto errorReturn;
-
+		if (!HKDF_X(&pcose->m_message, true, true, false, false, algIn, pRecip->m_pkey, pbKey, cbitKey, 256, CBOR_CONTEXT_PARAM_COMMA perr)) goto errorReturn;
 		break;
 
 	case COSE_Algorithm_ECDH_ES_HKDF_512:
-		if (!BuildContextBytes(&pcose->m_message, algIn, cbitKey, &pbContext, &cbContext, CBOR_CONTEXT_PARAM_COMMA perr)) goto errorReturn;
+		if (!HKDF_X(&pcose->m_message, true, true, false, false, algIn, pRecip->m_pkey, pbKey, cbitKey, 512, CBOR_CONTEXT_PARAM_COMMA perr)) goto errorReturn;
+		break;
 
-		pkey = _COSE_map_get_int(&pcose->m_message, COSE_Header_ECDH_EPHEMERAL, COSE_BOTH, perr);
-		if (pkey == NULL) goto errorReturn;
+	case COSE_Algorithm_ECDH_SS_HKDF_256:
+		if (!HKDF_X(&pcose->m_message, true, true, true, false, algIn, pRecip->m_pkey, pbKey, cbitKey, 256, CBOR_CONTEXT_PARAM_COMMA perr)) goto errorReturn;
+		break;
 
-		CHECK_CONDITION(pRecip->m_pkey != NULL, COSE_ERR_INVALID_PARAMETER);
-		if (!ECDH_ComputeSecret(&pcose->m_message, (cn_cbor **)&pRecip->m_pkey, pkey, &pbSecret, &cbSecret, CBOR_CONTEXT_PARAM_COMMA perr)) goto errorReturn;
+	case COSE_Algorithm_ECDH_SS_HKDF_512:
+		if (!HKDF_X(&pcose->m_message, true, true, true, false, algIn, pRecip->m_pkey, pbKey, cbitKey, 512, CBOR_CONTEXT_PARAM_COMMA perr)) goto errorReturn;
+		break;
 
-		if (!HKDF_Extract(&pcose->m_message, pbSecret, cbSecret, 512, rgbDigest, &cbDigest, CBOR_CONTEXT_PARAM_COMMA perr)) goto errorReturn;
+	case COSE_Algorithm_ECDH_ES_A128KW:
+		if (!HKDF_X(&pcose->m_message, true, true, false, false, COSE_Algorithm_AES_KW_128, pRecip->m_pkey, rgbKey, 128, 256, CBOR_CONTEXT_PARAM_COMMA perr)) goto errorReturn;
 
-		if (!HKDF_Expand(&pcose->m_message, 512, rgbDigest, cbDigest, pbContext, cbContext, pbKey, cbitKey / 8, perr)) goto errorReturn;
+		if (!AES_KW_Decrypt((COSE_Enveloped *)pcose, rgbKey, 128, cnBody->v.bytes, cnBody->length, pbKey, &cbKey2, perr)) goto errorReturn;
+
+		break;
+
+	case COSE_Algorithm_ECDH_ES_A192KW:
+		if (!HKDF_X(&pcose->m_message, true, true, false, false, COSE_Algorithm_AES_KW_192, pRecip->m_pkey, rgbKey, 192, 256, CBOR_CONTEXT_PARAM_COMMA perr)) goto errorReturn;
+
+		if (!AES_KW_Decrypt((COSE_Enveloped *)pcose, rgbKey, 192, cnBody->v.bytes, cnBody->length, pbKey, &cbKey2, perr)) goto errorReturn;
+
+		break;
+
+	case COSE_Algorithm_ECDH_ES_A256KW:
+		if (!HKDF_X(&pcose->m_message, true, true, false, false, COSE_Algorithm_AES_KW_256, pRecip->m_pkey, rgbKey, 256, 256, CBOR_CONTEXT_PARAM_COMMA perr)) goto errorReturn;
+
+		if (!AES_KW_Decrypt((COSE_Enveloped *)pcose, rgbKey, 256, cnBody->v.bytes, cnBody->length, pbKey, &cbKey2, perr)) goto errorReturn;
+
+		break;
+
+	case COSE_Algorithm_ECDH_SS_A128KW:
+		if (!HKDF_X(&pcose->m_message, true, true, true, false, COSE_Algorithm_AES_KW_128, pRecip->m_pkey, rgbKey, 128, 256, CBOR_CONTEXT_PARAM_COMMA perr)) goto errorReturn;
+
+		if (!AES_KW_Decrypt((COSE_Enveloped *)pcose, rgbKey, 128, cnBody->v.bytes, cnBody->length, pbKey, &cbKey2, perr)) goto errorReturn;
+
+		break;
+
+	case COSE_Algorithm_ECDH_SS_A192KW:
+		if (!HKDF_X(&pcose->m_message, true, true, true, false, COSE_Algorithm_AES_KW_192, pRecip->m_pkey, rgbKey, 192, 256, CBOR_CONTEXT_PARAM_COMMA perr)) goto errorReturn;
+
+		if (!AES_KW_Decrypt((COSE_Enveloped *)pcose, rgbKey, 192, cnBody->v.bytes, cnBody->length, pbKey, &cbKey2, perr)) goto errorReturn;
+
+		break;
+
+	case COSE_Algorithm_ECDH_SS_A256KW:
+		if (!HKDF_X(&pcose->m_message, true, true, true, false, COSE_Algorithm_AES_KW_256, pRecip->m_pkey, rgbKey, 256, 256, CBOR_CONTEXT_PARAM_COMMA perr)) goto errorReturn;
+
+		if (!AES_KW_Decrypt((COSE_Enveloped *)pcose, rgbKey, 256, cnBody->v.bytes, cnBody->length, pbKey, &cbKey2, perr)) goto errorReturn;
 
 		break;
 
@@ -312,6 +462,9 @@
 #endif
 	cn_cbor_errback cbor_error;
 	bool fRet = false;
+	byte * pbContext = NULL;
+	byte rgbKey[256 / 8];
+	byte * pbSecret = NULL;
 
 #ifdef USE_CBOR_CONTEXT
 	context = &pRecipient->m_encrypt.m_message.m_allocContext;
@@ -333,20 +486,28 @@
 	case COSE_Algorithm_Direct_HKDF_AES_256:
 	case COSE_Algorithm_ECDH_ES_HKDF_256:
 	case COSE_Algorithm_ECDH_ES_HKDF_512:
+	case COSE_Algorithm_ECDH_SS_HKDF_256:
+	case COSE_Algorithm_ECDH_SS_HKDF_512:
 		//  This is a NOOP
 		cbitKey = 0;
 		CHECK_CONDITION(pRecipient->m_encrypt.m_recipientFirst == NULL, COSE_ERR_INVALID_PARAMETER);
 		break;
 
 	case COSE_Algorithm_AES_KW_128:
+	case COSE_Algorithm_ECDH_ES_A128KW:
+	case COSE_Algorithm_ECDH_SS_A128KW:
 		cbitKey = 128;
 		break;
 
 	case COSE_Algorithm_AES_KW_192:
+	case COSE_Algorithm_ECDH_ES_A192KW:
+	case COSE_Algorithm_ECDH_SS_A192KW:
 		cbitKey = 192;
 		break;
 
 	case COSE_Algorithm_AES_KW_256:
+	case COSE_Algorithm_ECDH_ES_A256KW:
+	case COSE_Algorithm_ECDH_SS_A256KW:
 		cbitKey = 256;
 		break;
 
@@ -400,6 +561,8 @@
 	case COSE_Algorithm_Direct_HKDF_AES_256:
 	case COSE_Algorithm_ECDH_ES_HKDF_256:
 	case COSE_Algorithm_ECDH_ES_HKDF_512:
+	case COSE_Algorithm_ECDH_SS_HKDF_256:
+	case COSE_Algorithm_ECDH_SS_HKDF_512:
 		ptmp = cn_cbor_data_create(NULL, 0, CBOR_CONTEXT_PARAM_COMMA &cbor_error);
 		CHECK_CONDITION_CBOR(ptmp != NULL, cbor_error);
 		CHECK_CONDITION_CBOR(_COSE_array_replace(&pRecipient->m_encrypt.m_message, ptmp, INDEX_BODY, CBOR_CONTEXT_PARAM_COMMA &cbor_error), cbor_error);
@@ -420,6 +583,36 @@
 		}
 		break;
 
+	case COSE_Algorithm_ECDH_ES_A128KW:
+		if (!HKDF_X(&pRecipient->m_encrypt.m_message, true, true, false, true, COSE_Algorithm_AES_KW_128, pRecipient->m_pkey, rgbKey, 128, 256, CBOR_CONTEXT_PARAM_COMMA perr)) goto errorReturn;
+		if (!AES_KW_Encrypt(pRecipient, rgbKey, 128, pbContent, (int)cbContent, perr)) goto errorReturn;
+		break;
+
+	case COSE_Algorithm_ECDH_ES_A192KW:
+		if (!HKDF_X(&pRecipient->m_encrypt.m_message, true, true, false, true, COSE_Algorithm_AES_KW_192, pRecipient->m_pkey, rgbKey, 192, 256, CBOR_CONTEXT_PARAM_COMMA perr)) goto errorReturn;
+		if (!AES_KW_Encrypt(pRecipient, rgbKey, 192, pbContent, (int)cbContent, perr)) goto errorReturn;
+		break;
+
+	case COSE_Algorithm_ECDH_ES_A256KW:
+		if (!HKDF_X(&pRecipient->m_encrypt.m_message, true, true, false, true, COSE_Algorithm_AES_KW_256, pRecipient->m_pkey, rgbKey, 256, 256, CBOR_CONTEXT_PARAM_COMMA perr)) goto errorReturn;
+		if (!AES_KW_Encrypt(pRecipient, rgbKey, 256, pbContent, (int)cbContent, perr)) goto errorReturn;
+		break;
+
+	case COSE_Algorithm_ECDH_SS_A128KW:
+		if (!HKDF_X(&pRecipient->m_encrypt.m_message, true, true, true, true, COSE_Algorithm_AES_KW_128, pRecipient->m_pkey, rgbKey, 128, 256, CBOR_CONTEXT_PARAM_COMMA perr)) goto errorReturn;
+		if (!AES_KW_Encrypt(pRecipient, rgbKey, 128, pbContent, (int)cbContent, perr)) goto errorReturn;
+		break;
+
+	case COSE_Algorithm_ECDH_SS_A192KW:
+		if (!HKDF_X(&pRecipient->m_encrypt.m_message, true, true, true, true, COSE_Algorithm_AES_KW_192, pRecipient->m_pkey, rgbKey, 192, 256, CBOR_CONTEXT_PARAM_COMMA perr)) goto errorReturn;
+		if (!AES_KW_Encrypt(pRecipient, rgbKey, 192, pbContent, (int)cbContent, perr)) goto errorReturn;
+		break;
+
+	case COSE_Algorithm_ECDH_SS_A256KW:
+		if (!HKDF_X(&pRecipient->m_encrypt.m_message, true, true, true, true, COSE_Algorithm_AES_KW_256, pRecipient->m_pkey, rgbKey, 256, 256, CBOR_CONTEXT_PARAM_COMMA perr)) goto errorReturn;
+		if (!AES_KW_Encrypt(pRecipient, rgbKey, 256, pbContent, (int)cbContent, perr)) goto errorReturn;
+		break;
+
 	default:
 		FAIL_CONDITION(COSE_ERR_INVALID_PARAMETER);
 	}
@@ -433,6 +626,9 @@
 	fRet = true;
 
 errorReturn:
+	memset(rgbKey, 0, sizeof(rgbKey));
+	if (pbSecret != NULL) COSE_FREE(pbSecret, context);
+	if (pbContext != NULL) COSE_FREE(pbContext, context);
 	if (pbAuthData != NULL) COSE_FREE(pbAuthData, context);
 	if (ptmp != NULL) cn_cbor_free(ptmp CBOR_CONTEXT_PARAM);
 	return fRet;
@@ -443,17 +639,12 @@
 	int alg;
 	const cn_cbor * cn_Alg = _COSE_map_get_int(&pRecipient->m_encrypt.m_message, COSE_Header_Algorithm, COSE_BOTH, perr);
 	byte * pbContext = NULL;
-	size_t cbContext;
 	byte * pb = NULL;
 #ifdef USE_CBOR_CONTEXT
 	cn_cbor_context * context = &pRecipient->m_encrypt.m_message.m_allocContext;
 #endif
 	const cn_cbor * pK;
-	byte rgbDigest[512 / 8];
-	size_t cbDigest;
-	cn_cbor * pkey;
 	byte *pbSecret = NULL;
-	size_t cbSecret;
 
 	CHECK_CONDITION(cn_Alg != NULL, COSE_ERR_INVALID_PARAMETER);
 	CHECK_CONDITION((cn_Alg->type == CN_CBOR_UINT) || (cn_Alg->type == CN_CBOR_INT), COSE_ERR_INVALID_PARAMETER);
@@ -461,14 +652,15 @@
 
 	_COSE_encode_protected(&pRecipient->m_encrypt.m_message, perr);
 
+	pb = COSE_CALLOC(cbitKeySize / 8, 1, context);
+	CHECK_CONDITION(pb != NULL, COSE_ERR_OUT_OF_MEMORY);
+
 	switch (alg) {
 	case COSE_Algorithm_Direct:
 		if (pRecipient->m_pkey != NULL) {
 			pK = cn_cbor_mapget_int(pRecipient->m_pkey, -1);
 			CHECK_CONDITION((pK != NULL) && (pK->type == CN_CBOR_BYTES), COSE_ERR_INVALID_PARAMETER);
 			CHECK_CONDITION(pK->length == cbitKeySize / 8, COSE_ERR_INVALID_PARAMETER);
-			pb = COSE_CALLOC(cbitKeySize / 8, 1, context);
-			CHECK_CONDITION(pb != NULL, COSE_ERR_OUT_OF_MEMORY);
 			memcpy(pb, pK->v.bytes, cbitKeySize / 8);
 		}
 		else {
@@ -480,106 +672,36 @@
 	break;
 
 	case COSE_Algorithm_Direct_HKDF_HMAC_SHA_256:
-		if (!BuildContextBytes(&pRecipient->m_encrypt.m_message, algIn, cbitKeySize, &pbContext, &cbContext, CBOR_CONTEXT_PARAM_COMMA perr)) goto errorReturn;
-
-		pK = cn_cbor_mapget_int(pRecipient->m_pkey, -1);
-		CHECK_CONDITION((pK != NULL) && (pK->type == CN_CBOR_BYTES), COSE_ERR_INVALID_PARAMETER);
-
-		if (!HKDF_Extract(&pRecipient->m_encrypt.m_message, pK->v.bytes, pK->length, 256, rgbDigest, &cbDigest, CBOR_CONTEXT_PARAM_COMMA perr)) goto errorReturn;
-
-		pb = COSE_CALLOC(cbitKeySize / 8, 1, context);
-		CHECK_CONDITION(pb != NULL, COSE_ERR_OUT_OF_MEMORY);
-
-		if (!HKDF_Expand(&pRecipient->m_encrypt.m_message, 256, rgbDigest, cbDigest, pbContext, cbContext, pb, cbitKeySize / 8, perr)) goto errorReturn;
-
+		if (!HKDF_X(&pRecipient->m_encrypt.m_message, true, false, false, true, algIn, pRecipient->m_pkey, pb, cbitKeySize, 256, CBOR_CONTEXT_PARAM_COMMA perr)) goto errorReturn;
 		break;
 
 	case COSE_Algorithm_Direct_HKDF_HMAC_SHA_512:
-		if (!BuildContextBytes(&pRecipient->m_encrypt.m_message, algIn, cbitKeySize, &pbContext, &cbContext, CBOR_CONTEXT_PARAM_COMMA perr)) goto errorReturn;
-
-		pK = cn_cbor_mapget_int(pRecipient->m_pkey, -1);
-		CHECK_CONDITION((pK != NULL) && (pK->type == CN_CBOR_BYTES), COSE_ERR_INVALID_PARAMETER);
-
-		if (!HKDF_Extract(&pRecipient->m_encrypt.m_message, pK->v.bytes, pK->length, 512, rgbDigest, &cbDigest, CBOR_CONTEXT_PARAM_COMMA perr)) goto errorReturn;
-
-		pb = COSE_CALLOC(cbitKeySize / 8, 1, context);
-		CHECK_CONDITION(pb != NULL, COSE_ERR_OUT_OF_MEMORY);
-
-		if (!HKDF_Expand(&pRecipient->m_encrypt.m_message, 512, rgbDigest, cbDigest, pbContext, cbContext, pb, cbitKeySize / 8, perr)) goto errorReturn;
-
+		if (!HKDF_X(&pRecipient->m_encrypt.m_message, true, false, false, true, algIn, pRecipient->m_pkey, pb, cbitKeySize, 512, CBOR_CONTEXT_PARAM_COMMA perr)) goto errorReturn;
 		break;
 
 	case COSE_Algorithm_Direct_HKDF_AES_128:
-		if (!BuildContextBytes(&pRecipient->m_encrypt.m_message, algIn, cbitKeySize, &pbContext, &cbContext, CBOR_CONTEXT_PARAM_COMMA perr)) goto errorReturn;
-
-		pK = cn_cbor_mapget_int(pRecipient->m_pkey, -1);
-		CHECK_CONDITION((pK != NULL) && (pK->type == CN_CBOR_BYTES), COSE_ERR_INVALID_PARAMETER);
-
-		pb = COSE_CALLOC(cbitKeySize / 8, 1, context);
-		CHECK_CONDITION(pb != NULL, COSE_ERR_OUT_OF_MEMORY);
-
-		if (!HKDF_AES_Expand(&pRecipient->m_encrypt.m_message, 128, pK->v.bytes, pK->length, pbContext, cbContext, pb, cbitKeySize / 8, perr)) goto errorReturn;
-
+		if (!HKDF_X(&pRecipient->m_encrypt.m_message, false, false, false, true, algIn, pRecipient->m_pkey, pb, cbitKeySize, 128, CBOR_CONTEXT_PARAM_COMMA perr)) goto errorReturn;
 		break;
 
 	case COSE_Algorithm_Direct_HKDF_AES_256:
-		if (!BuildContextBytes(&pRecipient->m_encrypt.m_message, algIn, cbitKeySize, &pbContext, &cbContext, CBOR_CONTEXT_PARAM_COMMA perr)) goto errorReturn;
-
-		pK = cn_cbor_mapget_int(pRecipient->m_pkey, -1);
-		CHECK_CONDITION((pK != NULL) && (pK->type == CN_CBOR_BYTES), COSE_ERR_INVALID_PARAMETER);
-
-		pb = COSE_CALLOC(cbitKeySize / 8, 1, context);
-		CHECK_CONDITION(pb != NULL, COSE_ERR_OUT_OF_MEMORY);
-
-		if (!HKDF_AES_Expand(&pRecipient->m_encrypt.m_message, 256, pK->v.bytes, pK->length, pbContext, cbContext, pb, cbitKeySize / 8, perr)) goto errorReturn;
-
+		if (!HKDF_X(&pRecipient->m_encrypt.m_message, false, false, false, true, algIn, pRecipient->m_pkey, pb, cbitKeySize, 256, CBOR_CONTEXT_PARAM_COMMA perr)) goto errorReturn;
 		break;
 
 	case COSE_Algorithm_ECDH_ES_HKDF_256:
-		if (!BuildContextBytes(&pRecipient->m_encrypt.m_message, algIn, cbitKeySize, &pbContext, &cbContext, CBOR_CONTEXT_PARAM_COMMA perr)) goto errorReturn;
-
-		pkey = _COSE_map_get_int(&pRecipient->m_encrypt.m_message, COSE_Header_ECDH_EPHEMERAL, COSE_BOTH, perr);
-
-		if (!ECDH_ComputeSecret(&pRecipient->m_encrypt.m_message, &pkey, pRecipient->m_pkey, &pbSecret, &cbSecret, CBOR_CONTEXT_PARAM_COMMA perr)) goto errorReturn;
-
-		if (pkey->parent == NULL) {
-			if (!_COSE_map_put(&pRecipient->m_encrypt.m_message, COSE_Header_ECDH_EPHEMERAL, pkey, COSE_UNPROTECT_ONLY, perr)) goto errorReturn;
-		}
-
-		pb = COSE_CALLOC(cbitKeySize / 8, 1, context);
-		CHECK_CONDITION(pb != NULL, COSE_ERR_OUT_OF_MEMORY);
-
-		if (!HKDF_Extract(&pRecipient->m_encrypt.m_message, pbSecret, cbSecret, 256, rgbDigest, &cbDigest, CBOR_CONTEXT_PARAM_COMMA perr)) goto errorReturn;
-
-		if (!HKDF_Expand(&pRecipient->m_encrypt.m_message, 256, rgbDigest, cbDigest, pbContext, cbContext, pb, cbitKeySize / 8, perr)) goto errorReturn;
-
+		if (!HKDF_X(&pRecipient->m_encrypt.m_message, true, true, false, true, algIn, pRecipient->m_pkey, pb, cbitKeySize, 256, CBOR_CONTEXT_PARAM_COMMA perr)) goto errorReturn;
 		break;
 
 	case COSE_Algorithm_ECDH_ES_HKDF_512:
-		if (!BuildContextBytes(&pRecipient->m_encrypt.m_message, algIn, cbitKeySize, &pbContext, &cbContext, CBOR_CONTEXT_PARAM_COMMA perr)) goto errorReturn;
-
-		pkey = _COSE_map_get_int(&pRecipient->m_encrypt.m_message, COSE_Header_ECDH_EPHEMERAL, COSE_BOTH, perr);
-
-		if (!ECDH_ComputeSecret(&pRecipient->m_encrypt.m_message, &pkey, pRecipient->m_pkey, &pbSecret, &cbSecret, CBOR_CONTEXT_PARAM_COMMA perr)) goto errorReturn;
-
-		if (pkey->parent == NULL) {
-			if (!_COSE_map_put(&pRecipient->m_encrypt.m_message, COSE_Header_ECDH_EPHEMERAL, pkey, COSE_UNPROTECT_ONLY, perr)) goto errorReturn;
-		}
-
-		pb = COSE_CALLOC(cbitKeySize / 8, 1, context);
-		CHECK_CONDITION(pb != NULL, COSE_ERR_OUT_OF_MEMORY);
-
-		if (!HKDF_Extract(&pRecipient->m_encrypt.m_message, pbSecret, cbSecret, 512, rgbDigest, &cbDigest, CBOR_CONTEXT_PARAM_COMMA perr)) goto errorReturn;
-
-		if (!HKDF_Expand(&pRecipient->m_encrypt.m_message, 512, rgbDigest, cbDigest, pbContext, cbContext, pb, cbitKeySize / 8, perr)) goto errorReturn;
-
+		if (!HKDF_X(&pRecipient->m_encrypt.m_message, true, true, false, true, algIn, pRecipient->m_pkey, pb, cbitKeySize, 512, CBOR_CONTEXT_PARAM_COMMA perr)) goto errorReturn;
 		break;
 
-	case COSE_Algorithm_ECDH_SS_HKDF_256: {
-		//  Need to have a key and it needs to be the correct type of key.
-		if ((pRecipient->m_pkey == NULL) || (cn_cbor_mapget_int(pRecipient->m_pkey, 1)->v.uint != 2)) return NULL;
+	case COSE_Algorithm_ECDH_SS_HKDF_256:
+		if (!HKDF_X(&pRecipient->m_encrypt.m_message, true, true, true, true, algIn, pRecipient->m_pkey, pb, cbitKeySize, 256, CBOR_CONTEXT_PARAM_COMMA perr)) goto errorReturn;
 		break;
-	}
+
+	case COSE_Algorithm_ECDH_SS_HKDF_512:
+		if (!HKDF_X(&pRecipient->m_encrypt.m_message, true, true, true, true, algIn, pRecipient->m_pkey, pb, cbitKeySize, 512, CBOR_CONTEXT_PARAM_COMMA perr)) goto errorReturn;
+		break;
 
 	default:
 		FAIL_CONDITION(COSE_ERR_INVALID_PARAMETER);
@@ -656,6 +778,8 @@
 			case COSE_Algorithm_Direct_HKDF_HMAC_SHA_512:
 			case COSE_Algorithm_ECDH_ES_HKDF_256:
 			case COSE_Algorithm_ECDH_ES_HKDF_512:
+			case COSE_Algorithm_ECDH_SS_HKDF_256:
+			case COSE_Algorithm_ECDH_SS_HKDF_512:
 				((COSE_RecipientInfo *)h)->m_encrypt.m_message.m_flags |= 1;
 				break;
 
diff --git a/src/Sign.c b/src/Sign.c
index d2c3d98..7b4d955 100644
--- a/src/Sign.c
+++ b/src/Sign.c
@@ -148,8 +148,8 @@
 {
 #ifdef USE_CBOR_CONTEXT
 	cn_cbor_context * context = NULL;
-#endif
 	COSE_SignMessage * pMessage = (COSE_SignMessage *)hSign;
+#endif
 	const cn_cbor * cbor;
 	cn_cbor * cbor2 = NULL;
 	HCOSE_SIGNER hSigner = NULL;
diff --git a/src/Sign0.c b/src/Sign0.c
index 109fd25..6f602f4 100644
--- a/src/Sign0.c
+++ b/src/Sign0.c
@@ -220,6 +220,7 @@
 	cn = NULL;
 
 	cn2 = _COSE_arrayget_int(&pMessage->m_message, INDEX_PROTECTED);
+	CHECK_CONDITION(cn2 != NULL, COSE_ERR_INVALID_PARAMETER);
 
 	cn = cn_cbor_data_create(cn2->v.bytes, (int)cn2->length, CBOR_CONTEXT_PARAM_COMMA &cbor_error);
 	CHECK_CONDITION_CBOR(cn != NULL, cbor_error);
diff --git a/src/SignerInfo.c b/src/SignerInfo.c
index 0c3a07b..f2927ef 100644
--- a/src/SignerInfo.c
+++ b/src/SignerInfo.c
@@ -259,7 +259,7 @@
 	cn_cbor_context * context = NULL;
 #endif
 	size_t cbToBeSigned;
-	cn_cbor * pAuthData = NULL;
+	bool fRet = false;
 
 #ifdef USE_CBOR_CONTEXT
 	context = &pSign->m_message.m_allocContext;
@@ -307,16 +307,12 @@
 		break;
 	}
 
-	if (pbToBeSigned != NULL) COSE_FREE(pbToBeSigned, context);
-	if (pAuthData != NULL) cn_cbor_free(pAuthData CBOR_CONTEXT_PARAM);
-
-	return true;
+	fRet = true;
 
 errorReturn:
 	if (pbToBeSigned != NULL) COSE_FREE(pbToBeSigned, context);
-	if (pAuthData != NULL) cn_cbor_free(pAuthData CBOR_CONTEXT_PARAM);
 
-	return false;
+	return fRet;
 }
 
 bool COSE_Signer_map_put(HCOSE_SIGNER h, int key, cn_cbor * value, int flags, cose_errback * perror)
diff --git a/src/cose.h b/src/cose.h
index d7c814e..359909e 100644
--- a/src/cose.h
+++ b/src/cose.h
@@ -176,11 +176,11 @@
 
 bool COSE_Enveloped_SetContent(HCOSE_ENVELOPED cose, const byte * rgbContent, size_t cbContent, cose_errback * errp);
 byte * COSE_Enveloped_GetContent(HCOSE_ENVELOPED cose, size_t * pcbContent, cose_errback * errp);
+bool COSE_Encrypt_SetExternal(HCOSE_ENVELOPED hcose, const byte * pbExternalData, size_t cbExternalData, cose_errback * perr);
 
 bool COSE_Enveloped_encrypt(HCOSE_ENVELOPED cose, cose_errback * perror);
 bool COSE_Enveloped_decrypt(HCOSE_ENVELOPED, HCOSE_RECIPIENT, cose_errback * perr);
 
-HCOSE_RECIPIENT COSE_Enveloped_add_shared_secret(HCOSE_ENVELOPED cose, COSE_Algorithms algId, byte * rgbKey, int cbKey, byte * rgbKid, int cbKid, cose_errback * perr);
 extern bool COSE_Enveloped_AddRecipient(HCOSE_ENVELOPED hMac, HCOSE_RECIPIENT hRecip, cose_errback * perr);
 HCOSE_RECIPIENT COSE_Enveloped_GetRecipient(HCOSE_ENVELOPED cose, int iRecipient, cose_errback * perr);
 
@@ -189,6 +189,8 @@
 
 HCOSE_RECIPIENT COSE_Recipient_Init(CBOR_CONTEXT_COMMA cose_errback * perror);
 bool COSE_Recipient_Free(HCOSE_RECIPIENT cose);
+HCOSE_RECIPIENT COSE_Recipient_from_shared_secret(byte * rgbKey, int cbKey, byte * rgbKid, int cbKid, CBOR_CONTEXT_COMMA cose_errback * perr);
+
 bool COSE_Recipient_SetKey_secret(HCOSE_RECIPIENT h, const byte * rgb, int cb, cose_errback * perr);
 bool COSE_Recipient_SetKey(HCOSE_RECIPIENT h, const cn_cbor * pKey, cose_errback * perror);
 
@@ -228,8 +230,6 @@
 bool COSE_Mac_encrypt(HCOSE_MAC cose, cose_errback * perror);
 bool COSE_Mac_validate(HCOSE_MAC, HCOSE_RECIPIENT, cose_errback * perr);
 
-HCOSE_RECIPIENT COSE_Mac_add_shared_secret(HCOSE_MAC cose, COSE_Algorithms algId, byte * rgbKey, int cbKey, byte * rgbKid, int cbKid, cose_errback * perr);
-
 extern bool COSE_Mac_AddRecipient(HCOSE_MAC hMac, HCOSE_RECIPIENT hRecip, cose_errback * perr);
 HCOSE_RECIPIENT COSE_Mac_GetRecipient(HCOSE_MAC cose, int iRecipient, cose_errback * perr);
 
diff --git a/src/cose_int.h b/src/cose_int.h
index f3a834e..386119f 100644
--- a/src/cose_int.h
+++ b/src/cose_int.h
@@ -14,6 +14,8 @@
 	cn_cbor * m_protectedMap;
 	cn_cbor * m_unprotectMap;
 	cn_cbor * m_dontSendMap;
+	const byte * m_pbExternal;
+	size_t m_cbExternal;
 #ifdef USE_CBOR_CONTEXT
 	cn_cbor_context m_allocContext;
 #endif
@@ -155,6 +157,9 @@
 extern cn_cbor * _COSE_map_get_int(COSE * cose, int key, int flags, cose_errback * errp);
 extern bool _COSE_map_put(COSE * cose, int key, cn_cbor * value, int flags, cose_errback * errp);
 
+bool _COSE_SetExternal(COSE * hcose, const byte * pbExternalData, size_t cbExternalData, cose_errback * perr);
+
+
 extern HCOSE_ENVELOPED _COSE_Enveloped_Init_From_Object(cn_cbor *, COSE_Enveloped * pIn, CBOR_CONTEXT_COMMA cose_errback * errp);
 extern void _COSE_Enveloped_Release(COSE_Enveloped * p);
 extern bool _COSE_Enveloped_decrypt(COSE_Enveloped * pcose, COSE_RecipientInfo * pRecip, int cbitKey, byte *pbKeyIn, cose_errback * perr);
diff --git a/src/crypto.h b/src/crypto.h
index 232a927..894cb44 100644
--- a/src/crypto.h
+++ b/src/crypto.h
@@ -8,8 +8,8 @@
 * @param[in]   int          Size of authenticated data structure
 * @return                   Did the function succeed?
 */
-bool AES_CCM_Decrypt(COSE_Enveloped * pcose, int TSize, int LSize, const byte * pbKey, int cbitKey, const byte * pbCrypto, size_t cbCrypto, const byte * pbAuthData, size_t cbAuthData, cose_errback * perr);
-bool AES_GCM_Decrypt(COSE_Enveloped * pcose, const byte * pbKey, int cbKey, const byte * pbCrypto, size_t cbCrypto, const byte * pbAuthData, size_t cbAuthData, cose_errback * perr);
+bool AES_CCM_Decrypt(COSE_Enveloped * pcose, int TSize, int LSize, const byte * pbKey, size_t cbitKey, const byte * pbCrypto, size_t cbCrypto, const byte * pbAuthData, size_t cbAuthData, cose_errback * perr);
+bool AES_GCM_Decrypt(COSE_Enveloped * pcose, const byte * pbKey, size_t cbKey, const byte * pbCrypto, size_t cbCrypto, const byte * pbAuthData, size_t cbAuthData, cose_errback * perr);
 bool AES_KW_Decrypt(COSE_Enveloped * pcose, const byte * pbKeyIn, size_t cbitKey, const byte * pbCipherText, size_t cbCipherText, byte * pbKeyOut, int * pcbKeyOut, cose_errback * perr);
 
 /**
@@ -47,9 +47,9 @@
 bool HMAC_Validate(COSE_MacMessage * pcose, int HSize, int TSize, const byte * pbKey, size_t cbitKey, const byte * pbAuthData, size_t cbAuthData, cose_errback * perr);
 
 bool HKDF_Extract(COSE * pcose, const byte * pbKey, size_t cbKey, size_t cbitDigest, byte * rgbDigest, size_t * pcbDigest, CBOR_CONTEXT_COMMA cose_errback * perr);
-bool HKDF_Expand(COSE * pcose, int cbitDigest, const byte * pbPRK, size_t cbPRK, const byte * pbInfo, size_t cbInfo, byte * pbOutput, size_t cbOutput, cose_errback * perr);
+bool HKDF_Expand(COSE * pcose, size_t cbitDigest, const byte * pbPRK, size_t cbPRK, const byte * pbInfo, size_t cbInfo, byte * pbOutput, size_t cbOutput, cose_errback * perr);
 
-bool HKDF_AES_Expand(COSE * pcose, int cbitKey, const byte * pbPRK, size_t cbPRK, const byte * pbInfo, size_t cbInfo, byte * pbOutput, size_t cbOutput, cose_errback * perr);
+bool HKDF_AES_Expand(COSE * pcose, size_t cbitKey, const byte * pbPRK, size_t cbPRK, const byte * pbInfo, size_t cbInfo, byte * pbOutput, size_t cbOutput, cose_errback * perr);
 
 /**
 * Perform a signature operation
diff --git a/src/openssl.c b/src/openssl.c
index f48f35f..30299fb 100644
--- a/src/openssl.c
+++ b/src/openssl.c
@@ -18,7 +18,7 @@
 
 #define MIN(A, B) ((A) < (B) ? (A) : (B))
 
-bool AES_CCM_Decrypt(COSE_Enveloped * pcose, int TSize, int LSize, const byte * pbKey, int cbKey, const byte * pbCrypto, size_t cbCrypto, const byte * pbAuthData, size_t cbAuthData, cose_errback * perr)
+bool AES_CCM_Decrypt(COSE_Enveloped * pcose, int TSize, int LSize, const byte * pbKey, size_t cbKey, const byte * pbCrypto, size_t cbCrypto, const byte * pbAuthData, size_t cbAuthData, cose_errback * perr)
 {
 	EVP_CIPHER_CTX ctx;
 	int cbOut;
@@ -39,7 +39,7 @@
 
 	pIV = _COSE_map_get_int(&pcose->m_message, COSE_Header_IV, COSE_BOTH, NULL);
 	if ((pIV == NULL) || (pIV->type!= CN_CBOR_BYTES)) {
-		perr->err = COSE_ERR_INVALID_PARAMETER;
+		if (perr != NULL) perr->err = COSE_ERR_INVALID_PARAMETER;
 
 	errorReturn:
 		if (rgbOut != NULL) COSE_FREE(rgbOut, context);
@@ -197,7 +197,7 @@
 	return false;
 }
 
-bool AES_GCM_Decrypt(COSE_Enveloped * pcose, const byte * pbKey, int cbKey, const byte * pbCrypto, size_t cbCrypto, const byte * pbAuthData, size_t cbAuthData, cose_errback * perr)
+bool AES_GCM_Decrypt(COSE_Enveloped * pcose, const byte * pbKey, size_t cbKey, const byte * pbCrypto, size_t cbCrypto, const byte * pbAuthData, size_t cbAuthData, cose_errback * perr)
 {
 	EVP_CIPHER_CTX ctx;
 	int cbOut;
@@ -218,7 +218,7 @@
 
 	pIV = _COSE_map_get_int(&pcose->m_message, COSE_Header_IV, COSE_BOTH, NULL);
 	if ((pIV == NULL) || (pIV->type != CN_CBOR_BYTES)) {
-		perr->err = COSE_ERR_INVALID_PARAMETER;
+		if (perr != NULL) perr->err = COSE_ERR_INVALID_PARAMETER;
 
 	errorReturn:
 		if (rgbOut != NULL) COSE_FREE(rgbOut, context);
@@ -540,7 +540,7 @@
 }
 #endif
 
-bool HKDF_AES_Expand(COSE * pcose, int cbitKey, const byte * pbPRK, size_t cbPRK, const byte * pbInfo, size_t cbInfo, byte * pbOutput, size_t cbOutput, cose_errback * perr)
+bool HKDF_AES_Expand(COSE * pcose, size_t cbitKey, const byte * pbPRK, size_t cbPRK, const byte * pbInfo, size_t cbInfo, byte * pbOutput, size_t cbOutput, cose_errback * perr)
 {
 	const EVP_CIPHER * pcipher = NULL;
 	EVP_CIPHER_CTX ctx;
@@ -635,7 +635,7 @@
 	return true;
 }
 
-bool HKDF_Expand(COSE * pcose, int cbitDigest, const byte * pbPRK, size_t cbPRK, const byte * pbInfo, size_t cbInfo, byte * pbOutput, size_t cbOutput, cose_errback * perr)
+bool HKDF_Expand(COSE * pcose, size_t cbitDigest, const byte * pbPRK, size_t cbPRK, const byte * pbInfo, size_t cbInfo, byte * pbOutput, size_t cbOutput, cose_errback * perr)
 {
 	HMAC_CTX ctx;
 	const EVP_MD * pmd = NULL;
@@ -1004,7 +1004,7 @@
 	EVP_Digest(rgbToSign, cbToSign, rgbDigest, &cbDigest, digest, NULL);
 
 	pSig = _COSE_arrayget_int(pSigner, index);
-	CHECK_CONDITION(pSig != NULL, CN_CBOR_ERR_INVALID_PARAMETER);
+	CHECK_CONDITION(pSig != NULL, COSE_ERR_INVALID_PARAMETER);
 	cbSignature = pSig->length;
 
 	CHECK_CONDITION(cbSignature / 2 == cbR, COSE_ERR_INVALID_PARAMETER);
diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt
index cdc4063..702f564 100644
--- a/test/CMakeLists.txt
+++ b/test/CMakeLists.txt
@@ -30,21 +30,7 @@
 
 add_test ( NAME cose_test COMMAND cose_test )
 
-add_test ( NAME mac-02 WORKING_DIRECTORY ${CMAKE_SOURCE_DIR} COMMAND cose_test Examples/spec-examples/Mac-02.json )
-add_test ( NAME mac-04 WORKING_DIRECTORY ${CMAKE_SOURCE_DIR} COMMAND cose_test Examples/spec-examples/Mac-04.json )
-add_test ( NAME mac0-01 WORKING_DIRECTORY ${CMAKE_SOURCE_DIR} COMMAND cose_test Examples/spec-examples/Mac0-01.json )
-
-add_test ( NAME sig-01 WORKING_DIRECTORY ${CMAKE_SOURCE_DIR} COMMAND cose_test Examples/spec-examples/Sig-01.json )
-add_test ( NAME sig-02 WORKING_DIRECTORY ${CMAKE_SOURCE_DIR} COMMAND cose_test Examples/spec-examples/Sig-02.json )
-add_test ( NAME sig-03 WORKING_DIRECTORY ${CMAKE_SOURCE_DIR} COMMAND cose_test Examples/spec-examples/Sig-03.json )
-add_test ( NAME sig-04 WORKING_DIRECTORY ${CMAKE_SOURCE_DIR} COMMAND cose_test Examples/spec-examples/Sig-04.json )
-add_test ( NAME sig0-01 WORKING_DIRECTORY ${CMAKE_SOURCE_DIR} COMMAND cose_test Examples/spec-examples/Sig0-01.json )
-
-add_test ( NAME enc-01 WORKING_DIRECTORY ${CMAKE_SOURCE_DIR} COMMAND cose_test Examples/spec-examples/Enc-01.json )
-add_test ( NAME enc-02 WORKING_DIRECTORY ${CMAKE_SOURCE_DIR} COMMAND cose_test Examples/spec-examples/Enc-02.json )
-add_test ( NAME enc-03 WORKING_DIRECTORY ${CMAKE_SOURCE_DIR} COMMAND cose_test Examples/spec-examples/Enc-03.json )
-add_test ( NAME enc-04 WORKING_DIRECTORY ${CMAKE_SOURCE_DIR} COMMAND cose_test Examples/spec-examples/Enc-04.json )
-add_test ( NAME enc-05 WORKING_DIRECTORY ${CMAKE_SOURCE_DIR} COMMAND cose_test Examples/spec-examples/Enc-05.json )
+add_test ( NAME spec-examples WORKING_DIRECTORY ${CMAKE_SOURCE_DIR} COMMAND cose_test --dir Examples/spec-examples )
 
 add_test ( NAME aes-ccm WORKING_DIRECTORY ${CMAKE_SOURCE_DIR} COMMAND cose_test --dir Examples/aes-ccm-examples )
 
@@ -62,6 +48,7 @@
 add_test (NAME aes-wrap WORKING_DIRECTORY ${CMAKE_SOURCE_DIR} COMMAND cose_test --dir Examples/aes-wrap-examples )
 
 add_test (NAME ecdh-direct WORKING_DIRECTORY ${CMAKE_SOURCE_DIR} COMMAND cose_test --dir Examples/ecdh-direct-examples )
+add_test (NAME ecdh-wrap WORKING_DIRECTORY ${CMAKE_SOURCE_DIR} COMMAND cose_test --dir Examples/ecdh-wrap-examples )
 
 
 add_test (NAME corner-cases WORKING_DIRECTORY ${CMAKE_SOURCE_DIR} COMMAND cose_test --corners )
diff --git a/test/context.c b/test/context.c
index 701800a..3546f04 100644
--- a/test/context.c
+++ b/test/context.c
@@ -60,22 +60,24 @@
 
 void * MyCalloc(size_t count, size_t size, void * context)
 {
-	MyItem * pb = (MyItem *) malloc(sizeof(MyItem) + count*size);
+	MyItem * pb;
 	MyContext * myContext = (MyContext *)context;
 
 	CheckMemory(myContext);
 
 	if (myContext->iFailLeft == 0) return NULL;
-		myContext->iFailLeft--;
+	myContext->iFailLeft--;
+
+	pb = (MyItem *)malloc(sizeof(MyItem) + count*size);
 
 	memset(pb, 0xef, sizeof(MyItem) + count*size);
 	memset(&pb->data, 0, count*size);
 
 	pb->pNext = (struct _MyItem *) myContext->pFirst;
-	myContext->pFirst = (byte *) pb;
+	myContext->pFirst = (byte *)pb;
 	pb->size = count*size;
 
-    return &pb->data;
+	return &pb->data;
 }
 
 void MyFree(void * ptr, void * context)
diff --git a/test/encrypt.c b/test/encrypt.c
index 709df7c..b7a298e 100644
--- a/test/encrypt.c
+++ b/test/encrypt.c
@@ -44,19 +44,16 @@
 		hEnc = (HCOSE_ENVELOPED)COSE_Decode(pbEncoded, cbEncoded, &type, COSE_enveloped_object, CBOR_CONTEXT_PARAM_COMMA NULL);
 		if (hEnc == NULL) goto errorReturn;
 
-		if (!SetAttributes((HCOSE)hEnc, cn_cbor_mapget_string(pEnveloped, "unsent"), Attributes_Enveloped_unsent)) {
-			fFail = true;
-			continue;
-		}
+		if (!SetReceivingAttributes((HCOSE)hEnc, pEnveloped, Attributes_Enveloped_protected)) goto errorReturn;
 
-		cn_cbor * pkey = BuildKey(cn_cbor_mapget_string(pRecipients, "key"));
+		cn_cbor * pkey = BuildKey(cn_cbor_mapget_string(pRecipients, "key"), false);
 		if (pkey == NULL) {
 			fFail = true;
 			continue;
 		}
 
 		HCOSE_RECIPIENT hRecip = COSE_Enveloped_GetRecipient(hEnc, iRecipient, NULL);
-		if (hEnc == NULL) {
+		if (hRecip == NULL) {
 			fFail = true;
 			continue;
 		}
@@ -66,10 +63,7 @@
 			continue;
 		}
 
-		if (!SetAttributes((HCOSE)hRecip, cn_cbor_mapget_string(pRecipients, "unsent"), Attributes_Recipient_unsent)) {
-			fFail = true;
-			continue;
-		}
+		if (!SetReceivingAttributes((HCOSE) hRecip, pRecipients, Attributes_Recipient_protected)) goto errorReturn;
 
 		pFail = cn_cbor_mapget_string(pRecipients, "fail");
 		if (COSE_Enveloped_decrypt(hEnc, hRecip, NULL)) {
@@ -125,9 +119,7 @@
 	const cn_cbor * pContent = cn_cbor_mapget_string(pInputs, "plaintext");
 	if (!COSE_Enveloped_SetContent(hEncObj, pContent->v.bytes, pContent->length, NULL)) goto returnError;
 
-	if (!SetAttributes((HCOSE)hEncObj, cn_cbor_mapget_string(pEnveloped, "protected"), Attributes_Enveloped_protected)) goto returnError;
-	if (!SetAttributes((HCOSE)hEncObj, cn_cbor_mapget_string(pEnveloped, "unprotected"), Attributes_Enveloped_unprotected)) goto returnError;
-	if (!SetAttributes((HCOSE)hEncObj, cn_cbor_mapget_string(pEnveloped, "unsent"), Attributes_Enveloped_unsent)) goto returnError;
+	if (!SetSendingAttributes((HCOSE)hEncObj, pEnveloped, Attributes_Enveloped_protected)) goto returnError;
 
 	const cn_cbor * pAlg = COSE_Enveloped_map_get_int(hEncObj, 1, COSE_BOTH, NULL);
 	if (pAlg == NULL) goto returnError;
@@ -137,15 +129,13 @@
 
 	pRecipients = pRecipients->first_child;
 	for (iRecipient = 0; pRecipients != NULL; iRecipient++, pRecipients = pRecipients->next) {
-		cn_cbor * pkey = BuildKey(cn_cbor_mapget_string(pRecipients, "key"));
+		cn_cbor * pkey = BuildKey(cn_cbor_mapget_string(pRecipients, "key"), true);
 		if (pkey == NULL) goto returnError;
 
 		HCOSE_RECIPIENT hRecip = COSE_Recipient_Init(CBOR_CONTEXT_PARAM_COMMA NULL);
 		if (hRecip == NULL) goto returnError;
 
-		if (!SetAttributes((HCOSE)hRecip, cn_cbor_mapget_string(pRecipients, "protected"), Attributes_Recipient_protected)) goto returnError;
-		if (!SetAttributes((HCOSE)hRecip, cn_cbor_mapget_string(pRecipients, "unprotected"), Attributes_Recipient_unprotected)) goto returnError;
-		if (!SetAttributes((HCOSE)hRecip, cn_cbor_mapget_string(pRecipients, "unsent"), Attributes_Recipient_unsent)) goto returnError;
+		if (!SetSendingAttributes((HCOSE)hRecip, pRecipients, Attributes_Recipient_protected)) goto returnError;
 
 		if (!COSE_Recipient_SetKey(hRecip, pkey, NULL)) goto returnError;
 
@@ -187,7 +177,8 @@
 	COSE_Enveloped_SetContent(hEncObj, (byte *) sz, strlen(sz), NULL);
 	COSE_Enveloped_map_put_int(hEncObj, COSE_Header_IV, cn_cbor_data_create(rgbKid, 13, CBOR_CONTEXT_PARAM_COMMA NULL), COSE_UNPROTECT_ONLY, NULL);
 
-	HCOSE_RECIPIENT hRecip = COSE_Enveloped_add_shared_secret(hEncObj, COSE_Algorithm_Direct, rgbSecret, cbSecret, rgbKid, cbKid, NULL);
+	HCOSE_RECIPIENT hRecip = COSE_Recipient_from_shared_secret(rgbSecret, cbSecret, rgbKid, cbKid, CBOR_CONTEXT_PARAM_COMMA NULL);
+	COSE_Enveloped_AddRecipient(hEncObj, hRecip, NULL);
 
 	COSE_Enveloped_encrypt(hEncObj, NULL);
 
@@ -269,12 +260,9 @@
 	hEnc = (HCOSE_ENCRYPT)COSE_Decode(pbEncoded, cbEncoded, &type, COSE_encrypt_object, CBOR_CONTEXT_PARAM_COMMA NULL);
 	if (hEnc == NULL) goto returnError;
 
-	if (!SetAttributes((HCOSE)hEnc, cn_cbor_mapget_string(pEncrypt, "unsent"), Attributes_Encrypt_unsent)) {
-		fFail = true;
-		goto exitHere;
-	}
+	if (!SetReceivingAttributes((HCOSE)hEnc, pEncrypt, Attributes_Encrypt_protected)) goto returnError;
 
-	cn_cbor * pkey = BuildKey(cn_cbor_mapget_string(pRecipients, "key"));
+	cn_cbor * pkey = BuildKey(cn_cbor_mapget_string(pRecipients, "key"), true);
 	if (pkey == NULL) goto returnError;
 
 	cn_cbor * k = cn_cbor_mapget_int(pkey, -1);
@@ -336,9 +324,7 @@
 	const cn_cbor * pContent = cn_cbor_mapget_string(pInputs, "plaintext");
 	if (!COSE_Encrypt_SetContent(hEncObj, pContent->v.bytes, pContent->length, NULL)) goto returnError;
 
-	if (!SetAttributes((HCOSE)hEncObj, cn_cbor_mapget_string(pEncrypt, "protected"), Attributes_Encrypt_protected)) goto returnError;
-	if (!SetAttributes((HCOSE)hEncObj, cn_cbor_mapget_string(pEncrypt, "unprotected"), Attributes_Encrypt_unprotected)) goto returnError;
-	if (!SetAttributes((HCOSE)hEncObj, cn_cbor_mapget_string(pEncrypt, "unsent"), Attributes_Encrypt_unsent)) goto returnError;
+	if (!SetSendingAttributes((HCOSE)hEncObj, pEncrypt, Attributes_Encrypt_protected)) goto returnError;
 
 	const cn_cbor * pAlg = COSE_Encrypt_map_get_int(hEncObj, 1, COSE_BOTH, NULL);
 	if (pAlg == NULL) goto returnError;
@@ -347,7 +333,7 @@
 	if ((pRecipients == NULL) || (pRecipients->type != CN_CBOR_ARRAY)) goto returnError;
 
 	pRecipients = pRecipients->first_child;
-		cn_cbor * pkey = BuildKey(cn_cbor_mapget_string(pRecipients, "key"));
+		cn_cbor * pkey = BuildKey(cn_cbor_mapget_string(pRecipients, "key"), false);
 		if (pkey == NULL) goto returnError;
 
 		cn_cbor * k = cn_cbor_mapget_int(pkey, -1);
diff --git a/test/mac_test.c b/test/mac_test.c
index db13215..b94c692 100644
--- a/test/mac_test.c
+++ b/test/mac_test.c
@@ -40,7 +40,7 @@
 	iRecipient = (int) pRecipients->length - 1;
 	pRecipients = pRecipients->first_child;
 	for (; pRecipients != NULL; iRecipient--, pRecipients=pRecipients->next) {
-		cn_cbor * pkey = BuildKey(cn_cbor_mapget_string(pRecipients, "key"));
+		cn_cbor * pkey = BuildKey(cn_cbor_mapget_string(pRecipients, "key"), false);
 		if (pkey == NULL) {
 			fFail = true;
 			continue;
@@ -52,6 +52,8 @@
 			continue;
 		}
 
+		if (!SetReceivingAttributes((HCOSE)hRecip, pRecipients, Attributes_Recipient_protected)) goto failTest;
+
 		if (!COSE_Recipient_SetKey(hRecip, pkey, NULL)) {
 			fFail = true;
 			continue;
@@ -112,8 +114,7 @@
 	const cn_cbor * pContent = cn_cbor_mapget_string(pInputs, "plaintext");
 	if (!COSE_Mac_SetContent(hMacObj, pContent->v.bytes, pContent->length, NULL)) goto returnError;
 
-	if (!SetAttributes((HCOSE) hMacObj, cn_cbor_mapget_string(pMac, "protected"), Attributes_MAC_protected)) goto returnError;
-	if (!SetAttributes((HCOSE) hMacObj, cn_cbor_mapget_string(pMac, "unprotected"), Attributes_MAC_unprotected)) goto returnError;
+	if (!SetSendingAttributes((HCOSE)hMacObj, pMac, Attributes_MAC_protected)) goto returnError;
 
 	const cn_cbor * pAlg = COSE_Mac_map_get_int(hMacObj, 1, COSE_BOTH, NULL);
 
@@ -122,14 +123,13 @@
 
 	pRecipients = pRecipients->first_child;
 	for (iRecipient = 0; pRecipients != NULL; iRecipient++, pRecipients = pRecipients->next) {
-		cn_cbor * pkey = BuildKey(cn_cbor_mapget_string(pRecipients, "key"));
+		cn_cbor * pkey = BuildKey(cn_cbor_mapget_string(pRecipients, "key"), true);
 		if (pkey == NULL) goto returnError;
 
 		HCOSE_RECIPIENT hRecip = COSE_Recipient_Init(CBOR_CONTEXT_PARAM_COMMA NULL);
 		if (hRecip == NULL) goto returnError;
 
-		if (!SetAttributes((HCOSE) hRecip, cn_cbor_mapget_string(pRecipients, "protected"), Attributes_Recipient_protected)) goto returnError;
-		if (!SetAttributes((HCOSE) hRecip, cn_cbor_mapget_string(pRecipients, "unprotected"), Attributes_Recipient_unprotected)) goto returnError;
+		if (!SetSendingAttributes((HCOSE) hRecip, pRecipients, Attributes_Recipient_protected)) goto returnError;
 
 		if (!COSE_Recipient_SetKey(hRecip, pkey, NULL))goto returnError;
 
@@ -169,7 +169,8 @@
 	COSE_Mac_map_put_int(hEncObj, COSE_Header_Algorithm, cn_cbor_int_create(COSE_Algorithm_HMAC_256_256, CBOR_CONTEXT_PARAM_COMMA NULL), COSE_PROTECT_ONLY, NULL);
 	COSE_Mac_SetContent(hEncObj, (byte *) sz, strlen(sz), NULL);
 
-	COSE_Mac_add_shared_secret(hEncObj, COSE_Algorithm_Direct, rgbSecret, sizeof(rgbSecret), rgbKid, cbKid, NULL);
+	HCOSE_RECIPIENT hRecip = COSE_Recipient_from_shared_secret(rgbSecret, sizeof(rgbSecret), rgbKid, cbKid, CBOR_CONTEXT_PARAM_COMMA NULL);
+	COSE_Mac_AddRecipient(hEncObj, hRecip, NULL);
 
 	COSE_Mac_encrypt(hEncObj, NULL);
 
@@ -201,18 +202,18 @@
 
 	int iRecipient = 0;
 	do {
-		HCOSE_RECIPIENT hRecip;
+		HCOSE_RECIPIENT hRecip2;
 
-		hRecip = COSE_Mac_GetRecipient(hEncObj, iRecipient, NULL);
-		if (hRecip == NULL) break;
+		hRecip2 = COSE_Mac_GetRecipient(hEncObj, iRecipient, NULL);
+		if (hRecip2 == NULL) break;
 
-		COSE_Recipient_SetKey_secret(hRecip, rgbSecret, sizeof(rgbSecret), NULL);
+		COSE_Recipient_SetKey_secret(hRecip2, rgbSecret, sizeof(rgbSecret), NULL);
 
-		COSE_Mac_validate(hEncObj, hRecip, NULL);
+		COSE_Mac_validate(hEncObj, hRecip2, NULL);
 
 		iRecipient += 1;
 
-		COSE_Recipient_Free(hRecip);
+		COSE_Recipient_Free(hRecip2);
 
 	} while (true);
 
@@ -250,7 +251,7 @@
 
 	pRecipients = pRecipients->first_child;
 
-	cn_cbor * pkey = BuildKey(cn_cbor_mapget_string(pRecipients, "key"));
+	cn_cbor * pkey = BuildKey(cn_cbor_mapget_string(pRecipients, "key"), true);
 		if (pkey == NULL) {
 			fFail = true;
 			goto exitHere;
@@ -310,8 +311,7 @@
 	const cn_cbor * pContent = cn_cbor_mapget_string(pInputs, "plaintext");
 	if (!COSE_Mac0_SetContent(hMacObj, pContent->v.bytes, pContent->length, NULL)) goto returnError;
 
-	if (!SetAttributes((HCOSE)hMacObj, cn_cbor_mapget_string(pMac, "protected"), Attributes_MAC0_protected)) goto returnError;
-	if (!SetAttributes((HCOSE)hMacObj, cn_cbor_mapget_string(pMac, "unprotected"), Attributes_MAC0_unprotected)) goto returnError;
+	if (!SetSendingAttributes((HCOSE)hMacObj, pMac, Attributes_MAC0_protected)) goto returnError;
 
 	const cn_cbor * pAlg = COSE_Mac0_map_get_int(hMacObj, 1, COSE_BOTH, NULL);
 
@@ -320,7 +320,7 @@
 
 	pRecipients = pRecipients->first_child;
 
-	cn_cbor * pkey = BuildKey(cn_cbor_mapget_string(pRecipients, "key"));
+	cn_cbor * pkey = BuildKey(cn_cbor_mapget_string(pRecipients, "key"), false);
 		if (pkey == NULL) goto returnError;
 
 		cn_cbor * k = cn_cbor_mapget_int(pkey, -1);
@@ -357,8 +357,6 @@
     
     hMAC = (HCOSE_MAC) COSE_Mac_Init(CBOR_CONTEXT_PARAM_COMMA NULL);
 
-    COSE_Mac_add_shared_secret(hMAC, COSE_Algorithm_Direct_HKDF_HMAC_SHA_256, rgb, 10, rgb, 10, NULL);
-
     //  Invalid Handle checks
 
     COSE_Mac_Free((HCOSE_MAC) hEncrypt);
diff --git a/test/sign.c b/test/sign.c
index e83d430..e746080 100644
--- a/test/sign.c
+++ b/test/sign.c
@@ -44,7 +44,7 @@
 		if (hSig == NULL) goto returnError;
 
 
-		cn_cbor * pkey = BuildKey(cn_cbor_mapget_string(pSigners, "key"));
+		cn_cbor * pkey = BuildKey(cn_cbor_mapget_string(pSigners, "key"), false);
 		if (pkey == NULL) {
 			fFail = true;
 			continue;
@@ -115,9 +115,7 @@
 	const cn_cbor * pContent = cn_cbor_mapget_string(pInputs, "plaintext");
 	if (!COSE_Sign_SetContent(hSignObj, pContent->v.bytes, pContent->length, NULL)) goto returnError;
 
-	if (!SetAttributes((HCOSE)hSignObj, cn_cbor_mapget_string(pSign, "protected"), Attributes_Sign_protected)) goto returnError;
-	if (!SetAttributes((HCOSE)hSignObj, cn_cbor_mapget_string(pSign, "unprotected"), Attributes_Sign_unprotected)) goto returnError;
-	if (!SetAttributes((HCOSE)hSignObj, cn_cbor_mapget_string(pSign, "unsent"), Attributes_Sign_unsent)) goto returnError;
+	if (!SetSendingAttributes((HCOSE)hSignObj, pSign, Attributes_Sign_protected)) goto returnError;
 
 	const cn_cbor * pAlg = COSE_Sign_map_get_int(hSignObj, 1, COSE_BOTH, NULL);
 
@@ -126,15 +124,13 @@
 
 	pSigners = pSigners->first_child;
 	for (iSigner = 0; pSigners != NULL; iSigner++, pSigners = pSigners->next) {
-		cn_cbor * pkey = BuildKey(cn_cbor_mapget_string(pSigners, "key"));
+		cn_cbor * pkey = BuildKey(cn_cbor_mapget_string(pSigners, "key"), false);
 		if (pkey == NULL) goto returnError;
 
 		HCOSE_SIGNER hSigner = COSE_Signer_Init(CBOR_CONTEXT_PARAM_COMMA NULL);
 		if (hSigner == NULL) goto returnError;
 
-		if (!SetAttributes((HCOSE)hSigner, cn_cbor_mapget_string(pSigners, "protected"), Attributes_Signer_protected)) goto returnError;
-		if (!SetAttributes((HCOSE)hSigner, cn_cbor_mapget_string(pSigners, "unprotected"), Attributes_Signer_unprotected)) goto returnError;
-		if (!SetAttributes((HCOSE)hSigner, cn_cbor_mapget_string(pSigners, "unsent"), Attributes_Signer_unsent)) goto returnError;
+		if (!SetSendingAttributes((HCOSE)hSigner, pSigners, Attributes_Signer_protected)) goto returnError;
 
 		if (!COSE_Signer_SetKey(hSigner, pkey, NULL)) goto returnError;
 
@@ -259,7 +255,7 @@
 	if (hSig == NULL) goto returnError;
 
 
-	cn_cbor * pkey = BuildKey(cn_cbor_mapget_string(pSign, "key"));
+	cn_cbor * pkey = BuildKey(cn_cbor_mapget_string(pSign, "key"), false);
 	if (pkey == NULL) {
 		fFail = true;
 		goto exitHere;
@@ -318,13 +314,11 @@
 	const cn_cbor * pContent = cn_cbor_mapget_string(pInputs, "plaintext");
 	if (!COSE_Sign0_SetContent(hSignObj, pContent->v.bytes, pContent->length, NULL)) goto returnError;
 
-	if (!SetAttributes((HCOSE)hSignObj, cn_cbor_mapget_string(pSign, "protected"), Attributes_Sign0_protected)) goto returnError;
-	if (!SetAttributes((HCOSE)hSignObj, cn_cbor_mapget_string(pSign, "unprotected"), Attributes_Sign0_unprotected)) goto returnError;
-	if (!SetAttributes((HCOSE)hSignObj, cn_cbor_mapget_string(pSign, "unsent"), Attributes_Sign0_unsent)) goto returnError;
+	if (!SetSendingAttributes((HCOSE)hSignObj, pSign, Attributes_Sign0_protected)) goto returnError;
 
 	const cn_cbor * pAlg = COSE_Sign0_map_get_int(hSignObj, 1, COSE_BOTH, NULL);
 
-	cn_cbor * pkey = BuildKey(cn_cbor_mapget_string(pSign, "key"));
+	cn_cbor * pkey = BuildKey(cn_cbor_mapget_string(pSign, "key"), false);
 	if (pkey == NULL) goto returnError;
 
 
diff --git a/test/test.c b/test/test.c
index 4e2c0b6..f8fcd61 100644
--- a/test/test.c
+++ b/test/test.c
@@ -28,7 +28,7 @@
 	int    i;
 } NameMap;
 
-NameMap RgAlgorithmNames[32] = {
+NameMap RgAlgorithmNames[46] = {
 	{"HS256", COSE_Algorithm_HMAC_256_256},
 	{"HS256/64", COSE_Algorithm_HMAC_256_64},
 	{"HS384", COSE_Algorithm_HMAC_384_384},
@@ -61,6 +61,20 @@
 	{"HKDF-AES-256", COSE_Algorithm_Direct_HKDF_AES_256},
 	{"ECDH-ES", COSE_Algorithm_ECDH_ES_HKDF_256},
 {"ECDH-ES-512",COSE_Algorithm_ECDH_ES_HKDF_512},
+{ "ECDH-SS", COSE_Algorithm_ECDH_SS_HKDF_256 },
+{ "ECDH-SS-512",COSE_Algorithm_ECDH_SS_HKDF_512 },
+{ "ECDH-ES+A128KW", COSE_Algorithm_ECDH_ES_A128KW },
+{ "ECDH-ES+A192KW", COSE_Algorithm_ECDH_ES_A192KW },
+{ "ECDH-ES+A256KW", COSE_Algorithm_ECDH_ES_A256KW },
+{"ECDH-SS+A128KW", COSE_Algorithm_ECDH_SS_A128KW},
+{ "ECDH-SS+A192KW", COSE_Algorithm_ECDH_SS_A192KW },
+{ "ECDH-SS+A256KW", COSE_Algorithm_ECDH_SS_A256KW },
+{ "ECDH-ES-A128KW", COSE_Algorithm_ECDH_ES_A128KW },
+{ "ECDH-ES-A192KW", COSE_Algorithm_ECDH_ES_A192KW },
+{ "ECDH-ES-A256KW", COSE_Algorithm_ECDH_ES_A256KW },
+{ "ECDH-SS-A128KW", COSE_Algorithm_ECDH_SS_A128KW },
+{ "ECDH-SS-A192KW", COSE_Algorithm_ECDH_SS_A192KW },
+{ "ECDH-SS-A256KW", COSE_Algorithm_ECDH_SS_A256KW },
 };
 
 
@@ -93,6 +107,7 @@
 {
 	if (('0' <= c) && (c <= '9')) return c - '0';
 	if (('A' <= c) && (c <= 'F')) return c - 'A' + 10;
+	if (('a' <= c) && (c <= 'f')) return c - 'a' + 10;
 	fprintf(stderr, "Invalid hex");
 	exit(1);
 }
@@ -161,12 +176,13 @@
 	{ "k", 4, OPERATION_BASE64, -1}
 };
 
-bool SetAttributes(HCOSE hHandle, const cn_cbor * pAttributes, int which)
+bool SetAttributes(HCOSE hHandle, const cn_cbor * pAttributes, int which, int msgType, bool fPublicKey)
 {
 	const cn_cbor * pKey;
 	const cn_cbor * pValue;
 	int keyNew;
 	cn_cbor * pValueNew;
+	bool f = false;
 
 	if (pAttributes == NULL) return true;
 	if (pAttributes->type != CN_CBOR_MAP) return false;
@@ -211,114 +227,94 @@
 			pValueNew = cn_cbor_data_create(pValue->v.bytes, (int)pValue->length, CBOR_CONTEXT_PARAM_COMMA NULL);
 			if (pValueNew == NULL) return false;
 		}
+		else if (strcmp(pKey->v.str, "spk") == 0) {
+			keyNew = COSE_Header_ECDH_STATIC;
+			pValueNew = BuildKey(pValue, fPublicKey);
+			if (pValueNew == NULL) return false;
+		}
 		else {
 			continue;
 		}
 
-		switch (which) {
+		switch (msgType) {
 		case Attributes_MAC_protected:
-			COSE_Mac_map_put_int((HCOSE_MAC)hHandle, keyNew, pValueNew, COSE_PROTECT_ONLY, NULL);
-			break;
-
-		case Attributes_MAC_unprotected:
-			COSE_Mac_map_put_int((HCOSE_MAC)hHandle, keyNew, pValueNew, COSE_UNPROTECT_ONLY, NULL);
-			break;
-
-		case Attributes_MAC_unsent:
-			COSE_Mac_map_put_int((HCOSE_MAC)hHandle, keyNew, pValueNew, COSE_DONT_SEND, NULL);
+			f = COSE_Mac_map_put_int((HCOSE_MAC)hHandle, keyNew, pValueNew, which, NULL);
 			break;
 
 		case Attributes_MAC0_protected:
-			COSE_Mac0_map_put_int((HCOSE_MAC0)hHandle, keyNew, pValueNew, COSE_PROTECT_ONLY, NULL);
-			break;
-
-		case Attributes_MAC0_unprotected:
-			COSE_Mac0_map_put_int((HCOSE_MAC0)hHandle, keyNew, pValueNew, COSE_UNPROTECT_ONLY, NULL);
-			break;
-
-		case Attributes_MAC0_unsent:
-			COSE_Mac0_map_put_int((HCOSE_MAC0)hHandle, keyNew, pValueNew, COSE_DONT_SEND, NULL);
+			f = COSE_Mac0_map_put_int((HCOSE_MAC0)hHandle, keyNew, pValueNew, which, NULL);
 			break;
 
 		case Attributes_Recipient_protected:
-			COSE_Recipient_map_put((HCOSE_RECIPIENT)hHandle, keyNew, pValueNew, COSE_PROTECT_ONLY, NULL);
-			break;
-
-		case Attributes_Recipient_unprotected:
-			COSE_Recipient_map_put((HCOSE_RECIPIENT)hHandle, keyNew, pValueNew, COSE_UNPROTECT_ONLY, NULL);
-			break;
-
-		case Attributes_Recipient_unsent:
-			COSE_Recipient_map_put((HCOSE_RECIPIENT)hHandle, keyNew, pValueNew, COSE_DONT_SEND, NULL);
+			f = COSE_Recipient_map_put((HCOSE_RECIPIENT)hHandle, keyNew, pValueNew, which, NULL);
 			break;
 
 		case Attributes_Enveloped_protected:
-			COSE_Enveloped_map_put_int((HCOSE_ENVELOPED)hHandle, keyNew, pValueNew, COSE_PROTECT_ONLY, NULL);
-			break;
-
-		case Attributes_Enveloped_unprotected:
-			COSE_Enveloped_map_put_int((HCOSE_ENVELOPED)hHandle, keyNew, pValueNew, COSE_UNPROTECT_ONLY, NULL);
-			break;
-
-		case Attributes_Enveloped_unsent:
-			COSE_Enveloped_map_put_int((HCOSE_ENVELOPED)hHandle, keyNew, pValueNew, COSE_DONT_SEND, NULL);
+			f = COSE_Enveloped_map_put_int((HCOSE_ENVELOPED)hHandle, keyNew, pValueNew, which, NULL);
 			break;
 
 		case Attributes_Encrypt_protected:
-			COSE_Encrypt_map_put_int((HCOSE_ENCRYPT)hHandle, keyNew, pValueNew, COSE_PROTECT_ONLY, NULL);
-			break;
-
-		case Attributes_Encrypt_unprotected:
-			COSE_Encrypt_map_put_int((HCOSE_ENCRYPT)hHandle, keyNew, pValueNew, COSE_UNPROTECT_ONLY, NULL);
-			break;
-
-		case Attributes_Encrypt_unsent:
-			COSE_Encrypt_map_put_int((HCOSE_ENCRYPT)hHandle, keyNew, pValueNew, COSE_DONT_SEND, NULL);
+			f = COSE_Encrypt_map_put_int((HCOSE_ENCRYPT)hHandle, keyNew, pValueNew, which, NULL);
 			break;
 
 		case Attributes_Sign_protected:
-			COSE_Sign_map_put((HCOSE_SIGN)hHandle, keyNew, pValueNew, COSE_PROTECT_ONLY, NULL);
-			break;
-
-		case Attributes_Sign_unprotected:
-			COSE_Sign_map_put((HCOSE_SIGN)hHandle, keyNew, pValueNew, COSE_UNPROTECT_ONLY, NULL);
-			break;
-
-		case Attributes_Sign_unsent:
-			COSE_Sign_map_put((HCOSE_SIGN)hHandle, keyNew, pValueNew, COSE_DONT_SEND, NULL);
+			f = COSE_Sign_map_put((HCOSE_SIGN)hHandle, keyNew, pValueNew, which, NULL);
 			break;
 
 		case Attributes_Signer_protected:
-			COSE_Signer_map_put((HCOSE_SIGNER)hHandle, keyNew, pValueNew, COSE_PROTECT_ONLY, NULL);
-			break;
-
-		case Attributes_Signer_unprotected:
-			COSE_Signer_map_put((HCOSE_SIGNER)hHandle, keyNew, pValueNew, COSE_UNPROTECT_ONLY, NULL);
-			break;
-
-		case Attributes_Signer_unsent:
-			COSE_Signer_map_put((HCOSE_SIGNER)hHandle, keyNew, pValueNew, COSE_DONT_SEND, NULL);
+			f = COSE_Signer_map_put((HCOSE_SIGNER)hHandle, keyNew, pValueNew, which, NULL);
 			break;
 
 		case Attributes_Sign0_protected:
-			COSE_Sign0_map_put_int((HCOSE_SIGN0)hHandle, keyNew, pValueNew, COSE_PROTECT_ONLY, NULL);
-			break;
-
-		case Attributes_Sign0_unprotected:
-			COSE_Sign0_map_put_int((HCOSE_SIGN0)hHandle, keyNew, pValueNew, COSE_UNPROTECT_ONLY, NULL);
-			break;
-
-		case Attributes_Sign0_unsent:
-			COSE_Sign0_map_put_int((HCOSE_SIGN0)hHandle, keyNew, pValueNew, COSE_DONT_SEND, NULL);
+			f = COSE_Sign0_map_put_int((HCOSE_SIGN0)hHandle, keyNew, pValueNew, which, NULL);
 			break;
 
 		}
+		assert(f);
 	}
 
 	return true;
 }
 
-cn_cbor * BuildKey(const cn_cbor * pKeyIn)
+bool SetSendingAttributes(HCOSE hMsg, const cn_cbor * pIn, int base)
+{
+	bool f = false;
+
+	if (!SetAttributes(hMsg, cn_cbor_mapget_string(pIn, "protected"), COSE_PROTECT_ONLY, base, true)) goto returnError;
+	if (!SetAttributes(hMsg, cn_cbor_mapget_string(pIn, "unprotected"), COSE_UNPROTECT_ONLY, base, true)) goto returnError;
+	if (!SetAttributes(hMsg, cn_cbor_mapget_string(pIn, "unsent"), COSE_DONT_SEND, base, false)) goto returnError;
+
+	cn_cbor * pExternal = cn_cbor_mapget_string(pIn, "external");
+	if (pExternal != NULL) {
+		cn_cbor * pcn = cn_cbor_clone(pExternal, CBOR_CONTEXT_PARAM_COMMA NULL);
+		if (pcn == NULL) goto returnError;
+		if (!COSE_Encrypt_SetExternal((HCOSE_ENVELOPED) hMsg, FromHex(pcn->v.str, (int)pcn->length), pcn->length / 2, NULL)) goto returnError;
+	}
+
+	f = true;
+returnError:
+	return f;
+}
+
+bool SetReceivingAttributes(HCOSE hMsg, const cn_cbor * pIn, int base)
+{
+	bool f = false;
+
+	if (!SetAttributes(hMsg, cn_cbor_mapget_string(pIn, "unsent"), COSE_DONT_SEND, base, true)) goto returnError;
+
+	cn_cbor * pExternal = cn_cbor_mapget_string(pIn, "external");
+	if (pExternal != NULL) {
+		cn_cbor * pcn = cn_cbor_clone(pExternal, CBOR_CONTEXT_PARAM_COMMA NULL);
+		if (pcn == NULL) goto returnError;
+		if (!COSE_Encrypt_SetExternal((HCOSE_ENVELOPED)hMsg, FromHex(pcn->v.str, (int)pcn->length), pcn->length / 2, NULL)) goto returnError;
+	}
+
+	f = true;
+returnError:
+	return f;
+}
+
+cn_cbor * BuildKey(const cn_cbor * pKeyIn, bool fPublicKey)
 {
 	cn_cbor * pKeyOut = cn_cbor_map_create(CBOR_CONTEXT_PARAM_COMMA NULL);
 	cn_cbor * pKty = cn_cbor_mapget_string(pKeyIn, "kty");
@@ -363,6 +359,8 @@
 						break;
 
 					case OPERATION_BASE64:
+						if ((strcmp(pKey->v.str, "d") == 0) && fPublicKey) continue;
+
 						pb = base64_decode(pValue->v.str, pValue->length, &cb);
 						p = cn_cbor_data_create(pb, (int)cb, CBOR_CONTEXT_PARAM_COMMA NULL);
 						if (p == NULL) return NULL;
@@ -673,6 +671,7 @@
 	while ((dp = readdir(dirp)) != NULL) {
 		int cch = strlen(dp->d_name);
 		if (cch < 4) continue;
+		if (strcmp(dp->d_name, "Triple-01.json") == 0) continue;
 		rgchFullName[ich] = 0;
 		if (ich + strlen(dp->d_name) >= sizeof(rgchFullName) - 2) {
 			fprintf(stderr, "Buffer overflow problem\n");
@@ -723,9 +722,17 @@
 	//
 
 	if (fMemory) {
+		if (szWhere == NULL) {
+			fprintf(stderr, "Must specify a file name\n");
+			exit(1);
+		}
 		RunMemoryTest(szWhere);
 	}
 	else if (szWhere != NULL) {
+		if (szWhere == NULL) {
+			fprintf(stderr, "Must specify a file name\n");
+			exit(1);
+		}
 		if (fDir) RunTestsInDirectory(szWhere);
 		else RunFileTest(szWhere);
 	}
diff --git a/test/test.h b/test/test.h
index 87682b0..12c60ed 100644
--- a/test/test.h
+++ b/test/test.h
@@ -47,34 +47,21 @@
 //  test.c
 enum {
 	Attributes_MAC_protected=1,
-	Attributes_MAC_unprotected,
-	Attributes_MAC_unsent,
 	Attributes_MAC0_protected,
-	Attributes_MAC0_unprotected,
-	Attributes_MAC0_unsent,
 	Attributes_Recipient_protected,
-	Attributes_Recipient_unprotected,
-	Attributes_Recipient_unsent,
 	Attributes_Enveloped_protected,
-	Attributes_Enveloped_unprotected,
-	Attributes_Enveloped_unsent,
 	Attributes_Encrypt_protected,
-	Attributes_Encrypt_unprotected,
-	Attributes_Encrypt_unsent,
 	Attributes_Sign_protected,
-	Attributes_Sign_unprotected,
-	Attributes_Sign_unsent,
 	Attributes_Signer_protected,
-	Attributes_Signer_unprotected,
-	Attributes_Signer_unsent,
 	Attributes_Sign0_protected,
-	Attributes_Sign0_unprotected,
-	Attributes_Sign0_unsent,
 } whichSet;
 
 extern int CFails;
 
 int MapAlgorithmName(const cn_cbor * p);
 byte * GetCBOREncoding(const cn_cbor * pControl, int * pcbEncoded);
-bool SetAttributes(HCOSE hHandle, const cn_cbor * pAttributes, int which);
-cn_cbor * BuildKey(const cn_cbor * pKeyIn);
+//bool SetAttributes(HCOSE hHandle, const cn_cbor * pAttributes, int which, bool fPublicKey);
+cn_cbor * BuildKey(const cn_cbor * pKeyIn, bool fPublicKey);
+byte * FromHex(const char * rgch, int cch);
+bool SetSendingAttributes(HCOSE hMsg, const cn_cbor * pIn, int base);
+bool SetReceivingAttributes(HCOSE hMsg, const cn_cbor * pIn, int base);
diff --git a/test/test.sdf b/test/test.sdf
index d947d7d..4c6a25a 100644
--- a/test/test.sdf
+++ b/test/test.sdf
Binary files differ