Make the triple wrap example work
diff --git a/src/Recipient.c b/src/Recipient.c
index c8e524a..da0543e 100644
--- a/src/Recipient.c
+++ b/src/Recipient.c
@@ -220,12 +220,11 @@
 	return fRet;
 }
 
-bool _COSE_Recipient_decrypt(COSE_RecipientInfo * pRecip, int algIn, int cbitKey, byte * pbKeyIn, cose_errback * perr)
+bool _COSE_Recipient_decrypt(COSE_RecipientInfo * pRecip, int algIn, int cbitKeyOut, byte * pbKeyOut, cose_errback * perr)
 {
 	int alg;
 	const cn_cbor * cn = NULL;
 	COSE_RecipientInfo * pRecip2;
-	byte * pbKey = pbKeyIn;
 #ifdef USE_CBOR_CONTEXT
 	cn_cbor_context * context;
 #endif
@@ -237,6 +236,8 @@
 	byte rgbKey[256 / 8];
 	byte * pbSecret = NULL;
 	int cbKey2;
+	byte * pbKeyX = NULL;
+	int cbitKeyX = 0;
 
 #ifdef USE_CBOR_CONTEXT
 	context = &pcose->m_message.m_allocContext;
@@ -251,24 +252,32 @@
 		if (pbSecret != NULL) COSE_FREE(pbSecret, context);
 		return false;
 	}
+	CHECK_CONDITION(cn->type != CN_CBOR_TEXT, COSE_ERR_UNKNOWN_ALGORITHM);
 	CHECK_CONDITION((cn->type == CN_CBOR_UINT) || (cn->type == CN_CBOR_INT), COSE_ERR_INVALID_PARAMETER);
 	alg = (int)cn->v.uint;
 
-	CHECK_CONDITION(pbKey != NULL, COSE_ERR_INVALID_PARAMETER);
+	CHECK_CONDITION(pbKeyOut != NULL, COSE_ERR_INVALID_PARAMETER);
 
 	switch (alg) {
 	case COSE_Algorithm_Direct:
 		CHECK_CONDITION(pRecip->m_pkey != NULL, COSE_ERR_INVALID_PARAMETER);
 		cn = cn_cbor_mapget_int(pRecip->m_pkey, -1);
 		CHECK_CONDITION((cn != NULL) && (cn->type == CN_CBOR_BYTES), COSE_ERR_INVALID_PARAMETER);
-		CHECK_CONDITION((cn->length == (unsigned int)cbitKey / 8), COSE_ERR_INVALID_PARAMETER);
-		memcpy(pbKey, cn->v.bytes, cn->length);
+		CHECK_CONDITION((cn->length == (unsigned int)cbitKeyOut / 8), COSE_ERR_INVALID_PARAMETER);
+		memcpy(pbKeyOut, cn->v.bytes, cn->length);
 
 		return true;
 
 	case COSE_Algorithm_AES_KW_128:
+		cbitKeyX = 128;
+		break;
+
 	case COSE_Algorithm_AES_KW_192:
+		cbitKeyX = 192;
+		break;
+
 	case COSE_Algorithm_AES_KW_256:
+		cbitKeyX = 192;
 		break;
 
 	case COSE_Algorithm_Direct_HKDF_AES_128:
@@ -298,10 +307,15 @@
 		break;
 	}
 
-	//  If there is a recipient - ask it for the key
+	if (pcose->m_recipientFirst != NULL) {
+		//  If there is a recipient - ask it for the key
+		CHECK_CONDITION(cbitKeyX != 0, COSE_ERR_INVALID_PARAMETER);
+		pbKeyX = COSE_CALLOC(cbitKeyX / 8, 1, context);
+		CHECK_CONDITION(pbKeyX != NULL, COSE_ERR_OUT_OF_MEMORY);
 
-	for (pRecip2 = pcose->m_recipientFirst; pRecip2 != NULL; pRecip2 = pRecip->m_recipientNext) {
-		if (_COSE_Recipient_decrypt(pRecip2, alg, cbitKey, pbKey, perr)) break;
+		for (pRecip2 = pcose->m_recipientFirst; pRecip2 != NULL; pRecip2 = pRecip->m_recipientNext) {
+			if (_COSE_Recipient_decrypt(pRecip2, alg, cbitKeyX, pbKeyX, perr)) break;
+		}
 	}
 
 	cnBody = _COSE_arrayget_int(&pcose->m_message, INDEX_BODY);
@@ -311,85 +325,91 @@
 	case COSE_Algorithm_AES_KW_128:
 	case COSE_Algorithm_AES_KW_192:
 	case COSE_Algorithm_AES_KW_256:
-		CHECK_CONDITION(pRecip->m_pkey != NULL, COSE_ERR_INVALID_PARAMETER);
-		int x = cbitKey / 8;
-		cn = cn_cbor_mapget_int(pRecip->m_pkey, -1);
-		CHECK_CONDITION((cn != NULL) && (cn->type == CN_CBOR_BYTES), COSE_ERR_INVALID_PARAMETER);
+		if (pbKeyX != NULL) {
+			int x = cbitKeyOut / 8;
+			if (!AES_KW_Decrypt((COSE_Enveloped *)pcose, pbKeyX, cbitKeyX, cnBody->v.bytes, cnBody->length, pbKeyOut, &x, perr)) goto errorReturn;
+		}
+		else {
+			CHECK_CONDITION(pRecip->m_pkey != NULL, COSE_ERR_INVALID_PARAMETER);
+			int x = cbitKeyOut / 8;
+			cn = cn_cbor_mapget_int(pRecip->m_pkey, -1);
+			CHECK_CONDITION((cn != NULL) && (cn->type == CN_CBOR_BYTES), COSE_ERR_INVALID_PARAMETER);
 
-		if (!AES_KW_Decrypt((COSE_Enveloped *)pcose, cn->v.bytes, cn->length * 8, cnBody->v.bytes, cnBody->length, pbKey, &x, perr)) goto errorReturn;
+			if (!AES_KW_Decrypt((COSE_Enveloped *)pcose, cn->v.bytes, cn->length * 8, cnBody->v.bytes, cnBody->length, pbKeyOut, &x, perr)) goto errorReturn;
+		}
 		break;
 
 	case COSE_Algorithm_Direct_HKDF_HMAC_SHA_256:
-		if (!HKDF_X(&pcose->m_message, true, false, false, false, algIn, pRecip->m_pkey, NULL, pbKey, cbitKey, 256, CBOR_CONTEXT_PARAM_COMMA perr)) goto errorReturn;
+		if (!HKDF_X(&pcose->m_message, true, false, false, false, algIn, pRecip->m_pkey, NULL, pbKeyOut, cbitKeyOut, 256, CBOR_CONTEXT_PARAM_COMMA perr)) goto errorReturn;
 		break;
 
 	case COSE_Algorithm_Direct_HKDF_HMAC_SHA_512:
-		if (!HKDF_X(&pcose->m_message, true, false, false, false, algIn, pRecip->m_pkey, NULL, pbKey, cbitKey, 512, CBOR_CONTEXT_PARAM_COMMA perr)) goto errorReturn;
+		if (!HKDF_X(&pcose->m_message, true, false, false, false, algIn, pRecip->m_pkey, NULL, pbKeyOut, cbitKeyOut, 512, CBOR_CONTEXT_PARAM_COMMA perr)) goto errorReturn;
 		break;
 
 	case COSE_Algorithm_Direct_HKDF_AES_128:
-		if (!HKDF_X(&pcose->m_message, false, false, false, false, algIn, pRecip->m_pkey, NULL, pbKey, cbitKey, 128, CBOR_CONTEXT_PARAM_COMMA perr)) goto errorReturn;
+		if (!HKDF_X(&pcose->m_message, false, false, false, false, algIn, pRecip->m_pkey, NULL, pbKeyOut, cbitKeyOut, 128, CBOR_CONTEXT_PARAM_COMMA perr)) goto errorReturn;
 		break;
 
 	case COSE_Algorithm_Direct_HKDF_AES_256:
-		if (!HKDF_X(&pcose->m_message, false, false, false, false, algIn, pRecip->m_pkey, NULL, pbKey, cbitKey, 256, CBOR_CONTEXT_PARAM_COMMA perr)) goto errorReturn;
+		if (!HKDF_X(&pcose->m_message, false, false, false, false, algIn, pRecip->m_pkey, NULL, pbKeyOut, cbitKeyOut, 256, CBOR_CONTEXT_PARAM_COMMA perr)) goto errorReturn;
 		break;
 
 	case COSE_Algorithm_ECDH_ES_HKDF_256:
-		if (!HKDF_X(&pcose->m_message, true, true, false, false, algIn, pRecip->m_pkey, NULL, pbKey, cbitKey, 256, CBOR_CONTEXT_PARAM_COMMA perr)) goto errorReturn;
+		if (!HKDF_X(&pcose->m_message, true, true, false, false, algIn, pRecip->m_pkey, NULL, pbKeyOut, cbitKeyOut, 256, CBOR_CONTEXT_PARAM_COMMA perr)) goto errorReturn;
 		break;
 
 	case COSE_Algorithm_ECDH_ES_HKDF_512:
-		if (!HKDF_X(&pcose->m_message, true, true, false, false, algIn, pRecip->m_pkey, NULL, pbKey, cbitKey, 512, CBOR_CONTEXT_PARAM_COMMA perr)) goto errorReturn;
+		if (!HKDF_X(&pcose->m_message, true, true, false, false, algIn, pRecip->m_pkey, NULL, pbKeyOut, cbitKeyOut, 512, CBOR_CONTEXT_PARAM_COMMA perr)) goto errorReturn;
 		break;
 
 	case COSE_Algorithm_ECDH_SS_HKDF_256:
-		if (!HKDF_X(&pcose->m_message, true, true, true, false, algIn, pRecip->m_pkey, NULL, pbKey, cbitKey, 256, CBOR_CONTEXT_PARAM_COMMA perr)) goto errorReturn;
+		if (!HKDF_X(&pcose->m_message, true, true, true, false, algIn, pRecip->m_pkey, NULL, pbKeyOut, cbitKeyOut, 256, CBOR_CONTEXT_PARAM_COMMA perr)) goto errorReturn;
 		break;
 
 	case COSE_Algorithm_ECDH_SS_HKDF_512:
-		if (!HKDF_X(&pcose->m_message, true, true, true, false, algIn, pRecip->m_pkey, NULL, pbKey, cbitKey, 512, CBOR_CONTEXT_PARAM_COMMA perr)) goto errorReturn;
+		if (!HKDF_X(&pcose->m_message, true, true, true, false, algIn, pRecip->m_pkey, NULL, pbKeyOut, cbitKeyOut, 512, CBOR_CONTEXT_PARAM_COMMA perr)) goto errorReturn;
 		break;
 
 	case COSE_Algorithm_ECDH_ES_A128KW:
 		if (!HKDF_X(&pcose->m_message, true, true, false, false, COSE_Algorithm_AES_KW_128, pRecip->m_pkey, NULL, 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;
+		if (!AES_KW_Decrypt((COSE_Enveloped *)pcose, rgbKey, 128, cnBody->v.bytes, cnBody->length, pbKeyOut, &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, NULL, 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;
+		if (!AES_KW_Decrypt((COSE_Enveloped *)pcose, rgbKey, 192, cnBody->v.bytes, cnBody->length, pbKeyOut, &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, NULL, 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;
+		if (!AES_KW_Decrypt((COSE_Enveloped *)pcose, rgbKey, 256, cnBody->v.bytes, cnBody->length, pbKeyOut, &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, NULL, 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;
+		if (!AES_KW_Decrypt((COSE_Enveloped *)pcose, rgbKey, 128, cnBody->v.bytes, cnBody->length, pbKeyOut, &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, NULL, 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;
+		if (!AES_KW_Decrypt((COSE_Enveloped *)pcose, rgbKey, 192, cnBody->v.bytes, cnBody->length, pbKeyOut, &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, NULL, 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;
+		if (!AES_KW_Decrypt((COSE_Enveloped *)pcose, rgbKey, 256, cnBody->v.bytes, cnBody->length, pbKeyOut, &cbKey2, perr)) goto errorReturn;
 
 		break;
 
@@ -404,7 +424,7 @@
 bool _COSE_Recipient_encrypt(COSE_RecipientInfo * pRecipient, const byte * pbContent, size_t cbContent, cose_errback * perr)
 {
 	int alg;
-	int t;
+	int t = 0;
 	COSE_RecipientInfo * pri;
 	const cn_cbor * cn_Alg = NULL;
 	byte * pbAuthData = NULL;
@@ -486,16 +506,16 @@
 			}
 		}
 		CHECK_CONDITION(t != 3, COSE_ERR_INVALID_PARAMETER);
-	}
 
-	//   Do we need to generate a random key at this point - 
-	//   This is only true if we both haven't done it and and we have a recipient to encrypt it.
-
-	if ((pRecipient->m_pkey!= NULL)) {
-		pbKey = (byte *)COSE_CALLOC(cbitKey / 8, 1, context);
-		CHECK_CONDITION(pbKey != NULL, COSE_ERR_OUT_OF_MEMORY);
-		cbKey = cbitKey / 8;
-		rand_bytes(pbKey, cbKey);
+		// Do we need to generate a random key at this point -
+			//   This is only true if we both haven't done it and and we have a recipient to encrypt it.
+			
+			if (t == 2) {
+			pbKey = (byte *)COSE_CALLOC(cbitKey / 8, 1, context);
+			CHECK_CONDITION(pbKey != NULL, COSE_ERR_OUT_OF_MEMORY);
+			cbKey = cbitKey / 8;
+			rand_bytes(pbKey, cbKey);
+		}
 	}
 
 	//  Build protected headers
@@ -534,7 +554,7 @@
 			if (!AES_KW_Encrypt(pRecipient, pK->v.bytes, (int) pK->length*8, pbContent, (int) cbContent, perr)) goto errorReturn;
 		}
 		else {
-			if (!AES_KW_Encrypt(pRecipient, NULL, 0, pbContent, (int) cbContent, perr)) goto errorReturn;
+			if (!AES_KW_Encrypt(pRecipient, pbKey, (int) cbKey*8, pbContent, (int) cbContent, perr)) goto errorReturn;
 		}
 		break;
 
@@ -1089,3 +1109,67 @@
 
 	return _COSE_map_get_int(&((COSE_RecipientInfo *)h)->m_encrypt.m_message, key, flags, perror);
 }
+
+HCOSE_RECIPIENT COSE_Recipient_GetRecipient(HCOSE_RECIPIENT cose, int iRecipient, cose_errback * perr)
+{
+	int i;
+	COSE_RecipientInfo * p = NULL;
+
+	CHECK_CONDITION(IsValidRecipientHandle(cose), COSE_ERR_INVALID_HANDLE);
+	CHECK_CONDITION(iRecipient >= 0, COSE_ERR_INVALID_PARAMETER);
+
+	p = ((COSE_RecipientInfo *)cose)->m_encrypt.m_recipientFirst;
+	for (i = 0; i < iRecipient; i++) {
+		CHECK_CONDITION(p != NULL, COSE_ERR_INVALID_PARAMETER);
+		p = p->m_recipientNext;
+	}
+	if (p != NULL) p->m_encrypt.m_message.m_refCount++;
+
+errorReturn:
+	return (HCOSE_RECIPIENT)p;
+}
+
+bool COSE_Recipient_AddRecipient(HCOSE_RECIPIENT hEnc, HCOSE_RECIPIENT hRecip, cose_errback * perr)
+{
+	COSE_RecipientInfo * pRecip;
+	COSE_Enveloped * pEncrypt;
+	cn_cbor * pRecipients = NULL;
+#ifdef USE_CBOR_CONTEXT
+	cn_cbor_context * context;
+#endif
+	cn_cbor_errback cbor_error;
+
+	CHECK_CONDITION(IsValidRecipientHandle(hEnc), COSE_ERR_INVALID_HANDLE);
+	CHECK_CONDITION(IsValidRecipientHandle(hRecip), COSE_ERR_INVALID_HANDLE);
+
+	pEncrypt = &((COSE_RecipientInfo *)hEnc)->m_encrypt;
+	pRecip = (COSE_RecipientInfo *)hRecip;
+
+#ifdef USE_CBOR_CONTEXT
+	context = &pEncrypt->m_message.m_allocContext;
+#endif // USE_CBOR_CONTEXT
+
+	pRecip->m_recipientNext = pEncrypt->m_recipientFirst;
+	pEncrypt->m_recipientFirst = pRecip;
+
+	pRecipients = _COSE_arrayget_int(&pEncrypt->m_message, INDEX_RECIPIENTS);
+	if (pRecipients == NULL) {
+		pRecipients = cn_cbor_array_create(CBOR_CONTEXT_PARAM_COMMA &cbor_error);
+		CHECK_CONDITION_CBOR(pRecipients != NULL, cbor_error);
+
+		if (!_COSE_array_replace(&pEncrypt->m_message, pRecipients, INDEX_RECIPIENTS, CBOR_CONTEXT_PARAM_COMMA &cbor_error)) {
+			CN_CBOR_FREE(pRecipients, context);
+			if (perr != NULL) perr->err = _MapFromCBOR(cbor_error);
+			goto errorReturn;
+		}
+	}
+
+	CHECK_CONDITION_CBOR(cn_cbor_array_append(pRecipients, pRecip->m_encrypt.m_message.m_cbor, &cbor_error), cbor_error);
+
+	pRecip->m_encrypt.m_message.m_refCount++;
+
+	return true;
+
+errorReturn:
+	return false;
+}
diff --git a/src/cose.h b/src/cose.h
index dceed1c..7c13e36 100644
--- a/src/cose.h
+++ b/src/cose.h
@@ -211,6 +211,9 @@
 cn_cbor * COSE_Recipient_map_get_string(HCOSE_RECIPIENT cose, const char * key, int flags, cose_errback * errp);
 cn_cbor * COSE_Recipient_map_get_int(HCOSE_RECIPIENT cose, int key, int flags, cose_errback * errp);
 
+extern bool COSE_Recipient_AddRecipient(HCOSE_RECIPIENT hMac, HCOSE_RECIPIENT hRecip, cose_errback * perr);
+HCOSE_RECIPIENT COSE_Recipient_GetRecipient(HCOSE_RECIPIENT cose, int iRecipient, cose_errback * perr);
+
 
 /*
  *  Encrypt message API
diff --git a/test/encrypt.c b/test/encrypt.c
index a7072ba..ea5b23a 100644
--- a/test/encrypt.c
+++ b/test/encrypt.c
@@ -16,6 +16,85 @@
 #pragma warning (disable: 4127)
 #endif
 
+bool DecryptMessage(const byte * pbEncoded, size_t cbEncoded, bool fFailBody, const cn_cbor * pEnveloped, const cn_cbor * pRecipient1, int iRecipient1, const cn_cbor * pRecipient2, int iRecipient2)
+{
+	HCOSE_ENVELOPED hEnc = NULL;
+	HCOSE_RECIPIENT hRecip = NULL;
+	HCOSE_RECIPIENT hRecip2 = NULL;
+	bool fRet = false;
+	int type;
+	cose_errback cose_err;
+	cn_cbor * pkey;
+
+	hEnc = (HCOSE_ENVELOPED)COSE_Decode(pbEncoded, cbEncoded, &type, COSE_enveloped_object, CBOR_CONTEXT_PARAM_COMMA &cose_err);
+	if (hEnc == NULL) {
+		if (fFailBody && (cose_err.err == COSE_ERR_INVALID_PARAMETER)) return true;
+		goto errorReturn;
+	}
+
+	if (!SetReceivingAttributes((HCOSE)hEnc, pEnveloped, Attributes_Enveloped_protected)) goto errorReturn;
+
+	hRecip = COSE_Enveloped_GetRecipient(hEnc, iRecipient1, NULL);
+	if (hRecip == NULL) goto errorReturn;
+	if (!SetReceivingAttributes((HCOSE)hRecip, pRecipient1, Attributes_Recipient_protected)) goto errorReturn;
+
+	if (pRecipient2 != NULL) {
+		pkey = BuildKey(cn_cbor_mapget_string(pRecipient2, "key"), false);
+		if (pkey == NULL) goto errorReturn;
+
+		hRecip2 = COSE_Recipient_GetRecipient(hRecip, iRecipient2, NULL);
+		if (hRecip2 == NULL) goto errorReturn;
+
+		if (!SetReceivingAttributes((HCOSE)hRecip2, pRecipient2, Attributes_Recipient_protected)) goto errorReturn;
+		if (!COSE_Recipient_SetKey(hRecip2, pkey, NULL)) goto errorReturn;
+	}
+	else {
+		pkey = BuildKey(cn_cbor_mapget_string(pRecipient1, "key"), false);
+		if (pkey == NULL) goto errorReturn;
+		if (!COSE_Recipient_SetKey(hRecip, pkey, NULL)) goto errorReturn;
+	}
+
+
+	cn_cbor * cnStatic = cn_cbor_mapget_string(pRecipient1, "sender_key");
+	if (cnStatic != NULL) {
+		if (COSE_Recipient_map_get_int(hRecip, COSE_Header_ECDH_SPK, COSE_BOTH, NULL) == 0) {
+			COSE_Recipient_map_put_int(hRecip, COSE_Header_ECDH_SPK, BuildKey(cnStatic, true), COSE_DONT_SEND, NULL);
+		}
+	}
+
+	if (pRecipient2 != NULL) {
+		cnStatic = cn_cbor_mapget_string(pRecipient2, "sender_key");
+		if (cnStatic != NULL) {
+			if (COSE_Recipient_map_get_int(hRecip2, COSE_Header_ECDH_SPK, COSE_BOTH, NULL) == 0) {
+				COSE_Recipient_map_put_int(hRecip2, COSE_Header_ECDH_SPK, BuildKey(cnStatic, true), COSE_DONT_SEND, NULL);
+			}
+		}
+	}
+
+	if (!fFailBody) {
+		cn_cbor * cn = cn_cbor_mapget_string(pRecipient1, "fail");
+		if (cn != NULL && (cn->type == CN_CBOR_TRUE)) fFailBody = true;
+		if (fFailBody && (pRecipient2 != NULL)) {
+			cn = cn_cbor_mapget_string(pRecipient2, "fail");
+			if (cn != NULL && (cn->type == CN_CBOR_TRUE)) fFailBody = true;
+		}
+	}
+
+	if (COSE_Enveloped_decrypt(hEnc, hRecip, NULL)) {
+		fRet = !fFailBody;
+	}
+	else {
+		fRet = fFailBody;
+	}
+
+errorReturn:
+	if (hEnc != NULL) COSE_Enveloped_Free(hEnc);
+	if (hRecip != NULL) COSE_Recipient_Free(hRecip);
+	if (hRecip2 != NULL) COSE_Recipient_Free(hRecip2);
+
+
+	return fRet;
+}
 
 int _ValidateEnveloped(const cn_cbor * pControl, const byte * pbEncoded, size_t cbEncoded)
 {
@@ -23,10 +102,7 @@
 	const cn_cbor * pFail;
 	const cn_cbor * pEnveloped;
 	const cn_cbor * pRecipients;
-	HCOSE_ENVELOPED hEnc;
-	int type;
 	int iRecipient;
-	bool fFail = false;
 	bool fFailBody = false;
 
 	pFail = cn_cbor_mapget_string(pControl, "fail");
@@ -44,56 +120,18 @@
 	iRecipient = (int) pRecipients->length - 1;
 	pRecipients = pRecipients->first_child;
 	for (; pRecipients != NULL; iRecipient--, pRecipients = pRecipients->next) {
-
-		hEnc = (HCOSE_ENVELOPED)COSE_Decode(pbEncoded, cbEncoded, &type, COSE_enveloped_object, CBOR_CONTEXT_PARAM_COMMA NULL);
-		if (hEnc == NULL) { if (fFailBody) return 0; else  goto errorReturn; }
-
-		if (!SetReceivingAttributes((HCOSE)hEnc, pEnveloped, Attributes_Enveloped_protected)) goto errorReturn;
-
-		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 (hRecip == NULL) {
-			fFail = true;
-			continue;
-		}
-
-		if (!COSE_Recipient_SetKey(hRecip, pkey, NULL)) {
-			fFail = true;
-			continue;
-		}
-
-		if (!SetReceivingAttributes((HCOSE) hRecip, pRecipients, Attributes_Recipient_protected)) goto errorReturn;
-
-		cn_cbor * cnStatic = cn_cbor_mapget_string(pRecipients, "sender_key");
-		if (cnStatic != NULL) {
-			if (COSE_Recipient_map_get_int(hRecip, COSE_Header_ECDH_SPK, COSE_BOTH, NULL) == 0) {
-				COSE_Recipient_map_put_int(hRecip, COSE_Header_ECDH_SPK, BuildKey(cnStatic, true), COSE_DONT_SEND, NULL);
-			}
-		}
-
-		pFail = cn_cbor_mapget_string(pRecipients, "fail");
-		if (COSE_Enveloped_decrypt(hEnc, hRecip, NULL)) {
-			if ((pFail != NULL) && (pFail->type != CN_CBOR_TRUE)) fFail = true;
+		cn_cbor * pRecip2 = cn_cbor_mapget_string(pRecipients, "recipients");
+		if (pRecip2 == NULL) {
+			if (!DecryptMessage(pbEncoded, cbEncoded, fFailBody, pEnveloped, pRecipients, iRecipient, NULL, 0)) CFails++;
 		}
 		else {
-			if ((pFail == NULL) || (pFail->type == CN_CBOR_FALSE)) fFail = true;
+			int iRecipient2 = (int)(pRecip2->length - 1);
+			pRecip2 = pRecip2->first_child;
+			for (; pRecip2 != NULL; pRecip2 = pRecip2->next, iRecipient2--) {
+				if (!DecryptMessage(pbEncoded, cbEncoded, fFailBody, pEnveloped, pRecipients, iRecipient, pRecip2, iRecipient2)) CFails++;
+			}
 		}
-
-		COSE_Enveloped_Free(hEnc);
-		COSE_Recipient_Free(hRecip);
 	}
-
-	if (fFailBody) {
-		if (!fFail) fFail = true;
-		else fFail = false;
-	}
-
-	if (fFail) CFails += 1;
 	return 0;
 
 errorReturn:
@@ -109,6 +147,45 @@
 	return _ValidateEnveloped(pControl, pbEncoded, cbEncoded);
 }
 
+HCOSE_RECIPIENT BuildRecipient(const cn_cbor * pRecipient)
+{
+	HCOSE_RECIPIENT hRecip = COSE_Recipient_Init(0, CBOR_CONTEXT_PARAM_COMMA NULL);
+	if (hRecip == NULL) goto returnError;
+
+	if (!SetSendingAttributes((HCOSE)hRecip, pRecipient, Attributes_Recipient_protected)) goto returnError;
+
+	cn_cbor * cnKey = cn_cbor_mapget_string(pRecipient, "key");
+	if (cnKey != NULL) {
+		cn_cbor * pkey = BuildKey(cnKey, true);
+		if (pkey == NULL) goto returnError;
+
+		if (!COSE_Recipient_SetKey(hRecip, pkey, NULL)) goto returnError;
+	}
+
+	cnKey = cn_cbor_mapget_string(pRecipient, "recipients");
+	if (cnKey != NULL) {
+		for (cnKey = cnKey->first_child; cnKey != NULL; cnKey = cnKey->next) {
+			HCOSE_RECIPIENT hRecip2 = BuildRecipient(cnKey);
+			if (hRecip2 == NULL) goto returnError;
+			if (!COSE_Recipient_AddRecipient(hRecip, hRecip2, NULL)) goto returnError;
+			COSE_Recipient_Free(hRecip2);
+		}
+	}
+
+
+	cn_cbor * pSenderKey = cn_cbor_mapget_string(pRecipient, "sender_key");
+	if (pSenderKey != NULL) {
+		cn_cbor * pSendKey = BuildKey(pSenderKey, false);
+		if (!COSE_Recipient_SetSenderKey(hRecip, pSendKey, 2, NULL)) goto returnError;
+	}
+
+	return hRecip;
+
+returnError:
+	COSE_Recipient_Free(hRecip);
+	return NULL;
+}
+
 int BuildEnvelopedMessage(const cn_cbor * pControl)
 {
 	int iRecipient;
@@ -140,24 +217,11 @@
 
 	pRecipients = pRecipients->first_child;
 	for (iRecipient = 0; pRecipients != NULL; iRecipient++, pRecipients = pRecipients->next) {
-		cn_cbor * pkey = BuildKey(cn_cbor_mapget_string(pRecipients, "key"), true);
-		if (pkey == NULL) goto returnError;
-
-		HCOSE_RECIPIENT hRecip = COSE_Recipient_Init(0, CBOR_CONTEXT_PARAM_COMMA NULL);
+		HCOSE_RECIPIENT hRecip = BuildRecipient(pRecipients);
 		if (hRecip == NULL) goto returnError;
 
-		if (!SetSendingAttributes((HCOSE)hRecip, pRecipients, Attributes_Recipient_protected)) goto returnError;
-
-		if (!COSE_Recipient_SetKey(hRecip, pkey, NULL)) goto returnError;
-
 		if (!COSE_Enveloped_AddRecipient(hEncObj, hRecip, NULL)) goto returnError;
 
-		cn_cbor * pSenderKey = cn_cbor_mapget_string(pRecipients, "sender_key");
-		if (pSenderKey != NULL) {
-			cn_cbor * pSendKey = BuildKey(pSenderKey, false);
-			if (!COSE_Recipient_SetSenderKey(hRecip, pSendKey, 2, NULL)) goto returnError;
-		}
-
 		COSE_Recipient_Free(hRecip);
 	}
 
diff --git a/test/test.c b/test/test.c
index d288a5c..7be7116 100644
--- a/test/test.c
+++ b/test/test.c
@@ -725,7 +725,6 @@
 	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");