Add the create function to the test pass
diff --git a/dumper/dumper.c b/dumper/dumper.c
index 13a26c2..3770939 100644
--- a/dumper/dumper.c
+++ b/dumper/dumper.c
@@ -343,7 +343,7 @@
 		group = 0;
 		for (i = 0; i < cbor->length; i+=2, cbor2 = cbor2->next->next) {
 			if ((cbor2->type == CN_CBOR_UINT) && (cbor2->v.uint == 1)) {
-				group = cbor2->next->v.uint;
+				group = (int) cbor2->next->v.uint;
 				break;
 			}
 		}
diff --git a/src/MacMessage.c b/src/MacMessage.c
index 83e6a0e..7683c1d 100644
--- a/src/MacMessage.c
+++ b/src/MacMessage.c
@@ -564,6 +564,24 @@
 	return false;
 }
 
+bool COSE_Mac_AddRecipient(HCOSE_MAC hMac, HCOSE_RECIPIENT hRecip, cose_errback * perr)
+{
+	COSE_RecipientInfo * pRecip;
+	COSE_MacMessage * pMac;
+
+	CHECK_CONDITION(IsValidMacHandle(hMac), COSE_ERR_INVALID_PARAMETER);
+	CHECK_CONDITION(IsValidRecipientHandle(hRecip), COSE_ERR_INVALID_PARAMETER);
+
+	pMac = (COSE_MacMessage *)hMac;
+	pRecip = (COSE_RecipientInfo *)hRecip;
+
+	pRecip->m_recipientNext = pMac->m_recipientFirst;
+	pMac->m_recipientFirst = pRecip;
+	return true;
+
+errorReturn:
+	return false;
+}
 
 
 HCOSE_RECIPIENT COSE_Mac_GetRecipient(HCOSE_MAC cose, int iRecipient, cose_errback * perr)
diff --git a/src/Recipient.c b/src/Recipient.c
index 41a965c..2d3d4db 100644
--- a/src/Recipient.c
+++ b/src/Recipient.c
@@ -12,6 +12,34 @@
 	return true;
 }
 
+HCOSE_RECIPIENT COSE_Recipient_Init(CBOR_CONTEXT_COMMA cose_errback * perror)
+{
+	COSE_RecipientInfo * pobj = (COSE_RecipientInfo *)COSE_CALLOC(1, sizeof(COSE_RecipientInfo), context);
+	if (pobj == NULL) {
+		if (perror != NULL) perror->err = COSE_ERR_OUT_OF_MEMORY;
+		return NULL;
+	}
+
+	if (!_COSE_Init(&pobj->m_encrypt.m_message, COSE_recipient_object, CBOR_CONTEXT_PARAM_COMMA perror)) {
+		COSE_Recipient_Free((HCOSE_RECIPIENT)pobj);
+		return NULL;
+	}
+
+	return (HCOSE_RECIPIENT)pobj;
+}
+
+bool COSE_Recipient_Free(HCOSE_RECIPIENT hRecipient)
+{
+	if (IsValidRecipientHandle(hRecipient)) {
+
+		_COSE_Recipient_Free((COSE_RecipientInfo *)hRecipient);
+		return true;
+	}
+
+	return false;
+}
+
+
 HCOSE_RECIPIENT COSE_Encrypt_GetRecipient(HCOSE_ENCRYPT cose, int iRecipient, cose_errback * perr)
 {
 	int i;
@@ -161,17 +189,28 @@
 	int alg;
 	const cn_cbor * cn_Alg = _COSE_map_get_int(&pRecipient->m_encrypt.m_message, COSE_Header_Algorithm, COSE_BOTH, perr);
 
-	if (cn_Alg == NULL) return false;
-	if ((cn_Alg->type != CN_CBOR_UINT) && (cn_Alg->type != CN_CBOR_INT)) return false;
+	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);
 	alg = (int)cn_Alg->v.uint;
 
 	switch (alg) {
 	case COSE_Algorithm_Direct:
 	{
-		if (pRecipient->m_encrypt.cbKey != cbitKeySize / 8) return NULL;
-		byte * pb = (byte *)malloc(cbitKeySize / 8);
-		if (pb == NULL) return NULL;
-		memcpy(pb, pRecipient->m_encrypt.pbKey, cbitKeySize / 8);
+		byte * pb;
+		if (pRecipient->m_pkey != NULL) {
+			const cn_cbor * 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, &pRecipient->m_encrypt.m_message.m_allocContext);
+			CHECK_CONDITION(pb != NULL, COSE_ERR_OUT_OF_MEMORY);
+			memcpy(pb, pK->v.bytes, cbitKeySize / 8);
+		}
+		else {
+			if (pRecipient->m_encrypt.cbKey != cbitKeySize / 8) return NULL;
+			pb = (byte *)malloc(cbitKeySize / 8);
+			if (pb == NULL) return NULL;
+			memcpy(pb, pRecipient->m_encrypt.pbKey, cbitKeySize / 8);
+		}
 		return pb;
 	}
 	break;
@@ -185,6 +224,9 @@
 	default:
 		return NULL;
 	}
+
+errorReturn:
+	return NULL;
 }
 
 bool COSE_Recipient_SetKey_secret(HCOSE_RECIPIENT h, const byte * pbKey, int cbKey, cose_errback * perror)
@@ -219,8 +261,42 @@
 		return false;
 	}
 
+
+
 	p = (COSE_RecipientInfo *)h;
 	p->m_pkey = pKey;
 
 	return true;
 }
+
+bool COSE_Recipient_map_put(HCOSE_RECIPIENT h, int key, cn_cbor * value, int flags, cose_errback * perror)
+{
+	if (!IsValidRecipientHandle(h) || (value == NULL)) {
+		if (perror != NULL) perror->err = COSE_ERR_INVALID_PARAMETER;
+		return false;
+	}
+
+	if (!_COSE_map_put(&((COSE_RecipientInfo *)h)->m_encrypt.m_message, key, value, flags, perror)) return false;
+
+	if (key == COSE_Header_Algorithm) {
+		if (value->type == CN_CBOR_INT) {
+			switch (value->v.uint) {
+			case COSE_Algorithm_Direct:
+			case COSE_Algorithm_ECDH_ES_HKDF_256:
+			case COSE_Algorithm_ECDH_ES_HKDF_512:
+				((COSE_RecipientInfo *)h)->m_encrypt.m_message.m_flags |= 1;
+				break;
+
+			default:
+				((COSE_RecipientInfo *)h)->m_encrypt.m_message.m_flags &= ~1;
+				break;
+			}
+		}
+		else {
+			((COSE_RecipientInfo *)h)->m_encrypt.m_message.m_flags &= ~1;
+		}
+	}
+
+	return true;
+}
+
diff --git a/src/cose.h b/src/cose.h
index 3259957..969e40c 100644
--- a/src/cose.h
+++ b/src/cose.h
@@ -46,7 +46,8 @@
 	COSE_enveloped_object = 992,
 	COSE_encrypted_object = 993,
 	COSE_mac_object = 994,
-	COSE_mac0_object = 996
+	COSE_mac0_object = 996,
+	COSE_recipient_object = -1
 } COSE_object_type;
 
 //  Generic functions for the COSE library
@@ -135,9 +136,17 @@
 HCOSE_RECIPIENT COSE_Encrypt_add_shared_secret(HCOSE_ENCRYPT cose, COSE_Algorithms algId, byte * rgbKey, int cbKey, byte * rgbKid, int cbKid, cose_errback * perr);
 
 HCOSE_RECIPIENT COSE_Encrypt_GetRecipient(HCOSE_ENCRYPT cose, int iRecipient, cose_errback * perr);
+
+HCOSE_RECIPIENT COSE_Recipient_Init(CBOR_CONTEXT_COMMA cose_errback * perror);
+bool COSE_Recipient_Free(HCOSE_RECIPIENT cose);
 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);
 
+bool COSE_Recipient_map_put(HCOSE_RECIPIENT h, int key, cn_cbor * value, int flags, cose_errback * perror);
+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);
+
+
 //
 //
 
@@ -153,6 +162,7 @@
 
 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/test/json.c b/test/json.c
index bf44aff..c5e3a9f 100644
--- a/test/json.c
+++ b/test/json.c
@@ -56,7 +56,7 @@
 			for (ib2 = ib + 1; ib2 < cch; ib2++) if (rgch[ib2] == '"') break;
 			rgch[ib2] = 0;
 			node = cn_cbor_string_create(&rgch[ib+1], CBOR_CONTEXT_PARAM_COMMA NULL);
-			rgch[ib2] = '"';
+			// rgch[ib2] = '"';
 			ib = ib2;
 			break;
 
@@ -219,7 +219,7 @@
 	decoding_table = malloc(256);
 
 	for (int i = 0; i < 64; i++)
-		decoding_table[(unsigned char)encoding_table[i]] = i;
+		decoding_table[encoding_table[i]] = (char) i;
 }
 
 
diff --git a/test/test.c b/test/test.c
index c6175b0..4af9a6b 100644
--- a/test/test.c
+++ b/test/test.c
@@ -24,6 +24,28 @@
 #define CBOR_CONTEXT_PARAM_COMMA
 #endif
 
+struct {
+	char * sz;
+	int    i;
+} RgAlgorithmNames[5] = {
+	{"HS256", COSE_Algorithm_HMAC_256_256},
+	{"HS256/64", COSE_Algorithm_HMAC_256_64},
+	{"HS384", COSE_Algorithm_HMAC_384_384},
+	{"HS512", COSE_Algorithm_HMAC_512_512},
+	{"direct", COSE_Algorithm_Direct}
+};
+
+int MapAlgorithmName(const cn_cbor * p)
+{
+	int i;
+
+	for (i = 0; i < _countof(RgAlgorithmNames); i++) {
+		if (strcmp(RgAlgorithmNames[i].sz, p->v.str) == 0) return RgAlgorithmNames[i].i;
+	}
+
+	return 0;
+}
+
 cn_cbor * cn_cbor_clone(const cn_cbor * pIn)
 {
 	cn_cbor * pOut = NULL;
@@ -101,6 +123,58 @@
 	{ "k", 4, OPERATION_BASE64, -1}
 };
 
+enum {
+	Attributes_MAC_protected=1,
+	Attributes_MAC_unprotected,
+	Attributes_Recipient_protected,
+	Attributes_Recipient_unprotected,
+} whichSet;
+
+bool SetAttributes(HCOSE hHandle, const cn_cbor * pAttributes, int which)
+{
+	const cn_cbor * pKey;
+	const cn_cbor * pValue;
+	int keyNew;
+	cn_cbor * pValueNew;
+
+	if (pAttributes == NULL) return true;
+	if (pAttributes->type != CN_CBOR_MAP) return false;
+
+	for (pKey = pAttributes->first_child; pKey != NULL; pKey = pKey->next->next) {
+		pValue = pKey->next;
+
+		if (pKey->type != CN_CBOR_TEXT) return false;
+
+		if (strcmp(pKey->v.str, "alg") == 0) {
+			keyNew = COSE_Header_Algorithm;
+			pValueNew = cn_cbor_int_create(MapAlgorithmName(pValue), CBOR_CONTEXT_PARAM_COMMA NULL);
+		}
+		else {
+			continue;
+		}
+
+		switch (which) {
+		case Attributes_MAC_protected:
+			COSE_Mac_map_put((HCOSE_MAC)hHandle, keyNew, pValueNew, COSE_PROTECT_ONLY, NULL);
+			break;
+
+		case Attributes_MAC_unprotected:
+			COSE_Mac_map_put((HCOSE_MAC)hHandle, keyNew, pValueNew, COSE_UNPROTECT_ONLY, 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;
+		}
+	}
+
+	return true;
+}
+
 cn_cbor * BuildKey(const cn_cbor * pKeyIn)
 {
 	cn_cbor * pKeyOut = cn_cbor_map_create(CBOR_CONTEXT_PARAM_COMMA NULL);
@@ -221,6 +295,63 @@
 	return 0;
 }
 
+
+int BuildMacMessage(const cn_cbor * pControl)
+{
+	int iRecipient;
+
+	//
+	//  We don't run this for all control sequences - skip those marked fail.
+	//
+
+	const cn_cbor * pFail = cn_cbor_mapget_string(pControl, "fail");
+	if ((pFail != NULL) && (pFail->type == CN_CBOR_TRUE)) return 0;
+
+	HCOSE_MAC hMacObj = COSE_Mac_Init(CBOR_CONTEXT_PARAM_COMMA NULL);
+
+	const cn_cbor * pInputs = cn_cbor_mapget_string(pControl, "input");
+	if (pInputs == NULL) exit(1);
+	const cn_cbor * pMac = cn_cbor_mapget_string(pInputs, "mac");
+	if (pMac == NULL) exit(1);
+
+	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;
+
+	const cn_cbor * pRecipients = cn_cbor_mapget_string(pMac, "recipients");
+	if ((pRecipients == NULL) || (pRecipients->type != CN_CBOR_ARRAY)) exit(1);
+
+	pRecipients = pRecipients->first_child;
+	for (iRecipient = 0; pRecipients != NULL; iRecipient++, pRecipients = pRecipients->next) {
+		cn_cbor * pkey = BuildKey(cn_cbor_mapget_string(pRecipients, "key"));
+		if (pkey == NULL) exit(1);
+
+		HCOSE_RECIPIENT hRecip = COSE_Recipient_Init(CBOR_CONTEXT_PARAM_COMMA NULL);
+		if (hRecip == NULL) exit(1);
+
+		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 (!COSE_Recipient_SetKey(hRecip, pkey, NULL)) exit(1);
+
+		if (!COSE_Mac_AddRecipient(hMacObj, hRecip, NULL)) exit(1);
+	}
+
+	COSE_Mac_encrypt(hMacObj, NULL);
+
+	size_t cb = COSE_Encode((HCOSE)hMacObj, NULL, 0, 0) + 1;
+	byte * rgb = (byte *)malloc(cb);
+	cb = COSE_Encode((HCOSE)hMacObj, rgb, 0, cb);
+
+	return 0;
+
+returnError:
+	CFails += 1;
+	return 1;
+}
+
 int MacMessage()
 {
 	HCOSE_MAC hEncObj = COSE_Mac_Init(CBOR_CONTEXT_PARAM_COMMA NULL);
@@ -453,6 +584,7 @@
 
 		if (cn_cbor_mapget_string(pInput, "mac") != NULL) {
 			ValidateMAC(pControl);
+			BuildMacMessage(pControl);
 		}
 	}
 	else {