Add validate of signatures
diff --git a/src/MacMessage.c b/src/MacMessage.c
index f9abde3..7a36d0c 100644
--- a/src/MacMessage.c
+++ b/src/MacMessage.c
@@ -599,6 +599,10 @@
 #endif
 	cn_cbor_errback cbor_error;
 
+#ifdef USE_CBOR_CONTEXT
+	context = &pMac->m_message.m_allocContext;
+#endif // USE_CBOR_CONTEXT
+
 	CHECK_CONDITION(IsValidMacHandle(hMac), COSE_ERR_INVALID_PARAMETER);
 	CHECK_CONDITION(IsValidRecipientHandle(hRecip), COSE_ERR_INVALID_PARAMETER);
 
@@ -607,9 +611,6 @@
 
 	pRecip->m_recipientNext = pMac->m_recipientFirst;
 	pMac->m_recipientFirst = pRecip;
-#ifdef USE_CBOR_CONTEXT
-	context = &pMac->m_message.m_allocContext;
-#endif // USE_CBOR_CONTEXT
 
 
 	pRecipients = _COSE_arrayget_int(&pMac->m_message, INDEX_MAC_RECIPIENTS);
diff --git a/src/Sign.c b/src/Sign.c
index 5a1f280..8417ee8 100644
--- a/src/Sign.c
+++ b/src/Sign.c
@@ -47,20 +47,21 @@
 		goto errorReturn;
 	}
 
-	pSigners = (cn_cbor *)cn_cbor_mapget_int(cbor, COSE_Header_Recipients);
-	if (pSigners != NULL) {
-		CHECK_CONDITION(pSigners->type == CN_CBOR_ARRAY, COSE_ERR_INVALID_PARAMETER);
+	pSigners = _COSE_arrayget_int(&pobj->m_message, INDEX_SIGNATURES);
+	CHECK_CONDITION(pSigners != NULL, COSE_ERR_INVALID_PARAMETER);
+	CHECK_CONDITION(pSigners->type == CN_CBOR_ARRAY, COSE_ERR_INVALID_PARAMETER);
 
-		pSigners = pSigners->first_child;
-		while (pSigners != NULL) {
-			COSE_SignerInfo * pInfo = _COSE_SignerInfo_Init_From_Object(pSigners, CBOR_CONTEXT_PARAM_COMMA perr);
-			CHECK_CONDITION(pInfo != NULL, COSE_ERR_OUT_OF_MEMORY);
+	pSigners = pSigners->first_child;
+	CHECK_CONDITION(pSigners != NULL, COSE_ERR_INVALID_PARAMETER);  // Must be at least one signer
 
-			pInfo->m_signerNext = pobj->m_signerFirst;
-			pobj->m_signerFirst = pInfo;
-			pSigners = pSigners->next;
-		}
-	}
+	do {
+		COSE_SignerInfo * pInfo = _COSE_SignerInfo_Init_From_Object(pSigners, CBOR_CONTEXT_PARAM_COMMA perr);
+		if (pInfo == NULL) goto errorReturn;
+
+		pInfo->m_signerNext = pobj->m_signerFirst;
+		pobj->m_signerFirst = pInfo;
+		pSigners = pSigners->next;
+	} while (pSigners != NULL);
 
 	return(HCOSE_SIGN)pobj;
 }
@@ -112,7 +113,7 @@
 	context = &pMessage->m_message.m_allocContext;
 #endif
 
-	p = cn_cbor_data_create(rgb, cb, CBOR_CONTEXT_PARAM_COMMA NULL);
+	p = cn_cbor_data_create(rgb, (int) cb, CBOR_CONTEXT_PARAM_COMMA NULL);
 	CHECK_CONDITION(p != NULL, COSE_ERR_OUT_OF_MEMORY);
 
 #ifdef USE_ARRAY
@@ -165,7 +166,7 @@
 	cbor = cn_cbor_mapget_int(pkey, COSE_Key_ID);
 	if (cbor != NULL) {
 		CHECK_CONDITION(cbor->type == CN_CBOR_BYTES, COSE_ERR_INVALID_PARAMETER);
-		cbor2 = cn_cbor_data_create(cbor->v.bytes, cbor->length, CBOR_CONTEXT_PARAM_COMMA NULL);
+		cbor2 = cn_cbor_data_create(cbor->v.bytes, (int) cbor->length, CBOR_CONTEXT_PARAM_COMMA NULL);
 		CHECK_CONDITION(cbor2 != NULL, COSE_ERR_CBOR);
 		CHECK_CONDITION(cn_cbor_mapput_int(pSigner->m_message.m_unprotectMap, COSE_Parameter_KID, cbor2, CBOR_CONTEXT_PARAM_COMMA NULL), COSE_ERR_CBOR);
 		cbor2 = NULL;
@@ -239,3 +240,31 @@
 
 	return true;
 }
+
+bool COSE_Sign_validate(HCOSE_SIGN hSign, HCOSE_SIGNER hSigner, cose_errback * perr)
+{
+	bool f;
+	COSE_SignMessage * pSign;
+	COSE_SignerInfo * pSigner;
+	const cn_cbor * cnContent;
+	const cn_cbor * cnProtected;
+
+	CHECK_CONDITION(IsValidSignHandle(hSign), COSE_ERR_INVALID_PARAMETER);
+	CHECK_CONDITION(IsValidSignerHandle(hSigner), COSE_ERR_INVALID_PARAMETER);
+
+	pSign = (COSE_SignMessage *)hSign;
+	pSigner = (COSE_SignerInfo *)hSigner;
+
+	cnContent = _COSE_arrayget_int(&pSign->m_message, INDEX_BODY);
+	CHECK_CONDITION(cnContent != NULL && cnContent->type == CN_CBOR_BYTES, COSE_ERR_INVALID_PARAMETER);
+
+	cnProtected = _COSE_arrayget_int(&pSign->m_message, INDEX_PROTECTED);
+	CHECK_CONDITION(cnProtected != NULL && cnContent->type == CN_CBOR_BYTES, COSE_ERR_INVALID_PARAMETER);
+
+	f = _COSE_Signer_validate(pSign, pSigner, cnContent->v.bytes, cnContent->length, cnProtected->v.bytes, cnProtected->length, perr);
+
+	return f;
+
+errorReturn:
+	return false;
+}
diff --git a/src/SignerInfo.c b/src/SignerInfo.c
index 687a783..e8d2e39 100644
--- a/src/SignerInfo.c
+++ b/src/SignerInfo.c
@@ -48,22 +48,20 @@
 	COSE_SignerInfo * pSigner = NULL;
 
 	pSigner = (COSE_SignerInfo *)COSE_CALLOC(1, sizeof(COSE_SignerInfo), context);
-	if (pSigner == NULL) {
-		if (perr != NULL) perr->err = COSE_ERR_OUT_OF_MEMORY;
-		return NULL;
-	}
+	CHECK_CONDITION(pSigner != NULL, COSE_ERR_OUT_OF_MEMORY);
 
-	if (cbor->type != CN_CBOR_MAP) {
-		if (perr != NULL) perr->err = COSE_ERR_INVALID_PARAMETER;
-		COSE_FREE(pSigner, context);
-		return NULL;
-	}
+	CHECK_CONDITION(cbor->type == CN_CBOR_ARRAY, COSE_ERR_INVALID_PARAMETER);
+
 	if (!_COSE_Init_From_Object(&pSigner->m_message, cbor, CBOR_CONTEXT_PARAM_COMMA perr)) {
 		_COSE_Signer_Free(pSigner);
 		return NULL;
 	}
 
 	return pSigner;
+
+errorReturn:
+	if (pSigner != NULL) COSE_FREE(pSigner, context);
+	return NULL;
 }
 
 byte RgbDontUse4[1024];
@@ -96,13 +94,13 @@
 	pcborProtectedSign = _COSE_encode_protected(&pSigner->m_message, perr);
 	if (pcborProtectedSign == NULL) goto errorReturn;
 
-	pcborBody2 = cn_cbor_data_create(pcborBody->v.bytes, pcborBody->length, CBOR_CONTEXT_PARAM_COMMA NULL);
+	pcborBody2 = cn_cbor_data_create(pcborBody->v.bytes, (int) pcborBody->length, CBOR_CONTEXT_PARAM_COMMA NULL);
 	CHECK_CONDITION(pcborBody2 != NULL, COSE_ERR_OUT_OF_MEMORY);
 
-	pcborProtected2 = cn_cbor_data_create(pcborProtected->v.bytes, pcborProtected->length, CBOR_CONTEXT_PARAM_COMMA NULL);
+	pcborProtected2 = cn_cbor_data_create(pcborProtected->v.bytes, (int) pcborProtected->length, CBOR_CONTEXT_PARAM_COMMA NULL);
 	CHECK_CONDITION(pcborProtected2 != NULL, COSE_ERR_OUT_OF_MEMORY);
 
-	pcborProtectedSign2 = cn_cbor_data_create(pcborProtectedSign->v.bytes, pcborProtectedSign->length, CBOR_CONTEXT_PARAM_COMMA NULL);
+	pcborProtectedSign2 = cn_cbor_data_create(pcborProtectedSign->v.bytes, (int) pcborProtectedSign->length, CBOR_CONTEXT_PARAM_COMMA NULL);
 	CHECK_CONDITION(pcborProtectedSign2 != NULL, COSE_ERR_OUT_OF_MEMORY);
 
 	CHECK_CONDITION(cn_cbor_array_append(pArray, pcborProtected2, NULL), COSE_ERR_CBOR);
@@ -123,3 +121,122 @@
 
 	return f;
 }
+
+bool COSE_Signer_SetKey(HCOSE_SIGNER h, const cn_cbor * pKey, cose_errback * perror)
+{
+	COSE_SignerInfo * p;
+
+	if (!IsValidSignerHandle(h) || (pKey == NULL)) {
+		if (perror != NULL) perror->err = COSE_ERR_INVALID_PARAMETER;
+		return false;
+	}
+
+	p = (COSE_SignerInfo *)h;
+	p->m_pkey = pKey;
+
+	return true;
+}
+
+byte RgbDontUseSign[8 * 1024];
+
+bool _COSE_Signer_validate(COSE_SignMessage * pSign, COSE_SignerInfo * pSigner, const byte * pbContent, size_t cbContent, const byte * pbProtected, size_t cbProtected, cose_errback * perr)
+{
+	cn_cbor_errback cbor_error;
+	byte * pbAuthData = NULL;
+	int cbitKey = 0;
+	byte * pbKeyIn = NULL;
+
+	int alg;
+	const cn_cbor * cn = NULL;
+
+	byte * pbKey = pbKeyIn;
+#ifdef USE_CBOR_CONTEXT
+	cn_cbor_context * context = NULL;
+#endif
+	ssize_t cbAuthData;
+	cn_cbor * pAuthData = NULL;
+	cn_cbor * ptmp = NULL;
+
+#ifdef USE_CBOR_CONTEXT
+	context = &pSign->m_message.m_allocContext;
+#endif
+
+	cn = _COSE_map_get_int(&pSigner->m_message, COSE_Header_Algorithm, COSE_BOTH, perr);
+	if (cn == NULL) goto errorReturn;
+
+	if (cn->type == CN_CBOR_TEXT) {
+		FAIL_CONDITION(COSE_ERR_UNKNOWN_ALGORITHM);
+	}
+	else {
+		CHECK_CONDITION((cn->type == CN_CBOR_UINT || cn->type == CN_CBOR_INT), COSE_ERR_INVALID_PARAMETER);
+
+		alg = (int)cn->v.uint;
+	}
+
+	//  Build protected headers
+
+	cn_cbor * cnProtected = _COSE_arrayget_int(&pSigner->m_message, INDEX_PROTECTED);
+	CHECK_CONDITION((cnProtected != NULL) && (cnProtected->type == CN_CBOR_BYTES), COSE_ERR_INVALID_PARAMETER);
+
+	cn_cbor * cnSignature = _COSE_arrayget_int(&pSigner->m_message, INDEX_SIGNATURE);
+	CHECK_CONDITION((cnSignature != NULL) && (cnSignature->type == CN_CBOR_BYTES), COSE_ERR_INVALID_PARAMETER);
+
+	//  Build authenticated data
+	pbAuthData = NULL;
+	pAuthData = cn_cbor_array_create(CBOR_CONTEXT_PARAM_COMMA &cbor_error);
+	CHECK_CONDITION_CBOR(pAuthData != NULL, cbor_error);
+
+	ptmp = cn_cbor_string_create("Signature", 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 = cn_cbor_data_create(pbProtected, (int) cbProtected, 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 = cn_cbor_data_create(cnProtected->v.bytes, (int)cnProtected->length, 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 = cn_cbor_data_create(NULL, 0, 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 = cn_cbor_data_create(pbContent, (int) cbContent, 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);
+
+	cbAuthData = cn_cbor_encoder_write(RgbDontUseSign, 0, sizeof(RgbDontUseSign), 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 + 1, pAuthData) == cbAuthData), COSE_ERR_CBOR); // M00HACK
+
+	switch (alg) {
+	case COSE_Algorithm_ECDSA_SHA_256:
+		if (!ECDSA_Verify(pSigner, pbAuthData, cbAuthData, cnSignature->v.bytes, cnSignature->length, perr)) goto errorReturn;
+		break;
+
+	default:
+		FAIL_CONDITION(COSE_ERR_UNKNOWN_ALGORITHM);
+		break;
+	}
+
+	if (pbAuthData != NULL) COSE_FREE(pbAuthData, context);
+	if (pAuthData != NULL) cn_cbor_free(pAuthData CBOR_CONTEXT_PARAM);
+	if ((pbKey != NULL) && (pbKeyIn == NULL)) {
+		memset(pbKey, 0xff, cbitKey / 8);
+		COSE_FREE(pbKey, context);
+	}
+
+	return true;
+
+errorReturn:
+	if (pbAuthData != NULL) COSE_FREE(pbAuthData, context);
+	if (pAuthData != NULL) cn_cbor_free(pAuthData CBOR_CONTEXT_PARAM);
+	if ((pbKey != NULL) && (pbKeyIn == NULL)) {
+		memset(pbKey, 0xff, cbitKey / 8);
+		COSE_FREE(pbKey, context);
+	}
+
+	return false;
+}
diff --git a/src/cose.h b/src/cose.h
index 8cd2f6d..aafe457 100644
--- a/src/cose.h
+++ b/src/cose.h
@@ -185,3 +185,6 @@
 bool COSE_Sign_SetContent(HCOSE_SIGN cose, const byte * rgbContent, size_t cbContent, cose_errback * errp);
 HCOSE_SIGNER COSE_Sign_add_signer(HCOSE_SIGN cose, const cn_cbor * pkey, int algId, cose_errback * perr);
 bool COSE_Sign_Sign(HCOSE_SIGN h, cose_errback * perr);
+HCOSE_SIGNER COSE_Sign_GetSigner(HCOSE_SIGN cose, int iSigner, cose_errback * perr);
+bool COSE_Sign_validate(HCOSE_SIGN hSign, HCOSE_SIGNER hSigner, cose_errback * perr);
+bool COSE_Signer_SetKey(HCOSE_SIGNER hSigner, const cn_cbor * pkey, cose_errback * perr);
diff --git a/src/cose_int.h b/src/cose_int.h
index 922be3a..1ca34fe 100644
--- a/src/cose_int.h
+++ b/src/cose_int.h
@@ -117,6 +117,7 @@
 
 extern bool IsValidEncryptHandle(HCOSE_ENCRYPT h);
 extern bool IsValidRecipientHandle(HCOSE_RECIPIENT h);
+extern bool IsValidSignerHandle(HCOSE_SIGNER h);
 
 extern bool _COSE_Init(COSE * pcose, int msgType, CBOR_CONTEXT_COMMA cose_errback * errp);
 extern bool _COSE_Init_From_Object(COSE* pobj, cn_cbor * pcbor, CBOR_CONTEXT_COMMA cose_errback * perror);
@@ -145,6 +146,7 @@
 extern bool _COSE_Signer_sign(COSE_SignerInfo * pSigner, const cn_cbor * pcborBody, const cn_cbor * pcborProtected, cose_errback * perr);
 extern COSE_SignerInfo * _COSE_SignerInfo_Init_From_Object(cn_cbor * cbor, CBOR_CONTEXT_COMMA cose_errback * perr);
 extern void _COSE_Signer_Free(COSE_SignerInfo * pSigner);
+extern bool _COSE_Signer_validate(COSE_SignMessage * pSign, COSE_SignerInfo * pSigner, const byte * pbContent, size_t cbContent, const byte * pbProtected, size_t cbProtected, cose_errback * perr);
 
 //  Mac-ed items
 extern HCOSE_MAC _COSE_Mac_Init_From_Object(cn_cbor *, COSE_MacMessage * pIn, CBOR_CONTEXT_COMMA cose_errback * errp);
diff --git a/src/crypto.h b/src/crypto.h
index 9180d62..af46cdc 100644
--- a/src/crypto.h
+++ b/src/crypto.h
@@ -56,6 +56,7 @@
 * @return						Did the function succeed?
 */
 bool ECDSA_Sign(COSE_SignerInfo * pSigner, const byte * rgbToSign, size_t cbToSign, cose_errback * perr);
+bool ECDSA_Verify(COSE_SignerInfo * pSigner, const byte * rgbToSign, size_t cbToSign, const byte * rgbSig, size_t cbSig, cose_errback * perr);
 
 /**
 *  Generate random bytes in a buffer
diff --git a/src/openssl.c b/src/openssl.c
index 7916cef..0bd5ae6 100644
--- a/src/openssl.c
+++ b/src/openssl.c
@@ -650,7 +650,7 @@
 		break;
 
 	default:
-		return NULL;
+		FAIL_CONDITION(COSE_ERR_INVALID_PARAMETER);
 	}
 
 	EC_GROUP * ecgroup = EC_GROUP_new_by_curve_name(nidGroup);
@@ -736,6 +736,37 @@
 	return true;
 }
 
+bool ECDSA_Verify(COSE_SignerInfo * pSigner, const byte * rgbToSign, size_t cbToSign, const byte * rgbSignature, size_t cbSignature, cose_errback * perr)
+{
+	EC_KEY * eckey = NULL;
+	byte rgbDigest[EVP_MAX_MD_SIZE];
+	unsigned int cbDigest = sizeof(rgbDigest);
+#ifdef USE_CBOR_CONTEXT
+	cn_cbor_context * context = &pSigner->m_message.m_allocContext;
+#endif
+	cn_cbor * p = NULL;
+
+	eckey = ECKey_From(pSigner->m_pkey, perr);
+	if (eckey == NULL) {
+	errorReturn:
+		if (p != NULL) CN_CBOR_FREE(p, context);
+		if (eckey != NULL) EC_KEY_free(eckey);
+		return false;
+	}
+
+	EVP_Digest(rgbToSign, cbToSign, rgbDigest, &cbDigest, EVP_sha256(), NULL);
+
+	ECDSA_SIG sig;
+	sig.r = BN_bin2bn(rgbSignature,(int) cbSignature/2, NULL);
+	sig.s = BN_bin2bn(rgbSignature+cbSignature/2, (int) cbSignature/2, NULL);
+
+	CHECK_CONDITION(ECDSA_do_verify(rgbDigest, cbDigest, &sig, eckey) == 1, COSE_ERR_CRYPTO_FAIL);
+
+	//BN_FREE(sig.r);
+	//BN_FREE(sig.s);
+
+	return true;
+}
 
 bool AES_KW_Decrypt(COSE_Encrypt * pcose, const byte * pbKeyIn, size_t cbitKey, byte * pbKeyOut, int * pcbKeyOut, cose_errback * perr)
 {
diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt
index a6523b9..05496f0 100644
--- a/test/CMakeLists.txt
+++ b/test/CMakeLists.txt
@@ -8,7 +8,7 @@
 
 set (CMAKE_RUNTIME_OUTPUT_DIRECTORY ${dist_dir}/test )
 
-add_executable ( cose_test test.c json.c encrypt.c context.c )
+add_executable ( cose_test test.c json.c encrypt.c sign.c context.c )
 
 target_link_libraries (cose_test PRIVATE cose-c )
 
@@ -31,6 +31,9 @@
 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 sig-01 WORKING_DIRECTORY ${CMAKE_SOURCE_DIR} COMMAND cose_test Examples/spec-examples/Sig-01.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 hmac-01 WORKING_DIRECTORY ${CMAKE_SOURCE_DIR} COMMAND cose_test Examples/hmac-examples/HMac-01.json )
 add_test ( NAME hmac-02 WORKING_DIRECTORY ${CMAKE_SOURCE_DIR} COMMAND cose_test Examples/hmac-examples/HMac-02.json )
diff --git a/test/sign.c b/test/sign.c
new file mode 100644
index 0000000..34412d3
--- /dev/null
+++ b/test/sign.c
@@ -0,0 +1,173 @@
+//  encrypt.c
+
+#define _CRT_SECURE_NO_WARNINGS
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <cose.h>
+#include <cn-cbor/cn-cbor.h>
+
+#include "json.h"
+#include "test.h"
+#include "context.h"
+
+int _ValidateSigned(const cn_cbor * pControl, const byte * pbEncoded, int cbEncoded)
+{
+	const cn_cbor * pInput = cn_cbor_mapget_string(pControl, "input");
+	const cn_cbor * pFail;
+	const cn_cbor * pSign;
+	const cn_cbor * pSigners;
+	HCOSE_SIGN	hSig;
+	int type;
+	int iSigner;
+	bool fFail = false;
+	bool fFailBody = false;
+
+#ifdef USE_CBOR_CONTEXT
+        allocator = CreateContext();
+#endif 
+
+	pFail = cn_cbor_mapget_string(pControl, "fail");
+	if ((pFail != NULL) && (pFail->type == CN_CBOR_TRUE)) {
+		fFailBody = true;
+	}
+
+	if ((pInput == NULL) || (pInput->type != CN_CBOR_MAP)) exit(1);
+	pSign = cn_cbor_mapget_string(pInput, "sign");
+	if ((pSign == NULL) || (pSign->type != CN_CBOR_MAP)) exit(1);
+
+	pSigners = cn_cbor_mapget_string(pSign, "signers");
+	if ((pSigners == NULL) || (pSigners->type != CN_CBOR_ARRAY)) exit(1);
+
+	pSigners = pSigners->first_child;
+	for (iSigner = 0; pSigners != NULL; iSigner++, pSigners = pSigners->next) {
+
+		hSig = (HCOSE_SIGN)COSE_Decode(pbEncoded, cbEncoded, &type, COSE_sign_object, CBOR_CONTEXT_PARAM_COMMA NULL);
+		if (hSig == NULL) exit(1);
+
+
+		cn_cbor * pkey = BuildKey(cn_cbor_mapget_string(pSigners, "key"));
+		if (pkey == NULL) {
+			fFail = true;
+			continue;
+		}
+
+		HCOSE_SIGNER hSigner = COSE_Sign_GetSigner(hSig, iSigner, NULL);
+		if (hSigner == NULL) {
+			fFail = true;
+			continue;
+		}
+
+		if (!COSE_Signer_SetKey(hSigner, pkey, NULL)) {
+			fFail = true;
+			continue;
+		}
+
+		pFail = cn_cbor_mapget_string(pSigners, "fail");
+		if (COSE_Sign_validate(hSig, hSigner, NULL)) {
+			if ((pFail != NULL) && (pFail->type != CN_CBOR_TRUE)) fFail = true;
+		}
+		else {
+			if ((pFail == NULL) || (pFail->type == CN_CBOR_FALSE)) fFail = true;
+		}
+
+		// COSE_Encrypt_Free(hSig);
+	}
+
+	if (fFailBody) {
+		if (!fFail) fFail = true;
+		else fFail = false;
+	}
+
+#ifdef USE_CBOR_CONTEXT
+        FreeContext(allocator);
+        allocator = NULL;
+#endif
+
+	if (fFail) CFails += 1;
+	return 0;
+}
+
+int ValidateSigned(const cn_cbor * pControl)
+{
+	int cbEncoded;
+	byte * pbEncoded = GetCBOREncoding(pControl, &cbEncoded);
+
+	return _ValidateSigned(pControl, pbEncoded, cbEncoded);
+}
+
+
+int SignMessage()
+{
+	HCOSE_SIGN hEncObj = COSE_Sign_Init(CBOR_CONTEXT_PARAM_COMMA NULL);
+	char * sz = "This is the content to be used";
+	size_t cb;
+	byte * rgb;
+
+			byte rgbX[] = { 0x65, 0xed, 0xa5, 0xa1, 0x25, 0x77, 0xc2, 0xba, 0xe8, 0x29, 0x43, 0x7f, 0xe3, 0x38, 0x70, 0x1a, 0x10, 0xaa, 0xa3, 0x75, 0xe1, 0xbb, 0x5b, 0x5d, 0xe1, 0x08, 0xde, 0x43, 0x9c, 0x08, 0x55, 0x1d };
+		byte rgbY[] = { 0x1e, 0x52, 0xed, 0x75, 0x70, 0x11, 0x63, 0xf7, 0xf9, 0xe4, 0x0d, 0xdf, 0x9f, 0x34, 0x1b, 0x3d, 0xc9, 0xba, 0x86, 0x0a, 0xf7, 0xe0, 0xca, 0x7c, 0xa7, 0xe9, 0xee, 0xcd, 0x00, 0x84, 0xd1, 0x9c };
+		byte kid[] = { 0x6d, 0x65, 0x72, 0x69, 0x61, 0x64, 0x6f, 0x63, 0x2e, 0x62, 0x72, 0x61, 0x6e, 0x64, 0x79, 0x62, 0x75, 0x63, 0x6, 0xb4, 0x06, 0x27, 0x56, 0x36, 0xb6, 0xc6, 0x16, 0xe6, 0x42, 0xe6, 0x57, 0x86, 0x16, 0xd7, 0x06, 0x65};
+		byte rgbD[] = {0xaf, 0xf9, 0x07, 0xc9, 0x9f, 0x9a, 0xd3, 0xaa, 0xe6, 0xc4, 0xcd, 0xf2, 0x11, 0x22, 0xbc, 0xe2, 0xbd, 0x68, 0xb5, 0x28, 0x3e, 0x69, 0x07, 0x15, 0x4a, 0xd9, 0x11, 0x84, 0x0f, 0xa2, 0x08, 0xcf};
+			
+			cn_cbor * pkey = cn_cbor_map_create(CBOR_CONTEXT_PARAM_COMMA NULL);
+	cn_cbor_mapput_int(pkey, COSE_Key_Type, cn_cbor_int_create(COSE_Key_Type_EC2, CBOR_CONTEXT_PARAM_COMMA NULL), CBOR_CONTEXT_PARAM_COMMA NULL);
+	cn_cbor_mapput_int(pkey, -1, cn_cbor_int_create(1, CBOR_CONTEXT_PARAM_COMMA NULL), CBOR_CONTEXT_PARAM_COMMA NULL);
+	cn_cbor_mapput_int(pkey, -2, cn_cbor_data_create(rgbX, sizeof(rgbX), CBOR_CONTEXT_PARAM_COMMA NULL), CBOR_CONTEXT_PARAM_COMMA NULL);
+	cn_cbor_mapput_int(pkey, -3, cn_cbor_data_create(rgbY, sizeof(rgbY), CBOR_CONTEXT_PARAM_COMMA NULL), CBOR_CONTEXT_PARAM_COMMA NULL);
+	cn_cbor_mapput_int(pkey, COSE_Key_ID, cn_cbor_data_create(kid, sizeof(kid), CBOR_CONTEXT_PARAM_COMMA NULL), CBOR_CONTEXT_PARAM_COMMA NULL);
+	cn_cbor_mapput_int(pkey, -4, cn_cbor_data_create(rgbD, sizeof(rgbD), CBOR_CONTEXT_PARAM_COMMA NULL), CBOR_CONTEXT_PARAM_COMMA NULL);
+
+	COSE_Sign_SetContent(hEncObj, (byte *) sz, strlen(sz), NULL);
+	COSE_Sign_add_signer(hEncObj, pkey, COSE_Algorithm_ECDSA_SHA_256, NULL);
+
+	COSE_Sign_Sign(hEncObj, NULL);
+
+	cb = COSE_Encode((HCOSE)hEncObj, NULL, 0, 0) + 1;
+	rgb = (byte *)malloc(cb);
+	cb = COSE_Encode((HCOSE)hEncObj, rgb, 0, cb);
+
+
+	FILE * fp = fopen("test.mac.cbor", "wb");
+	fwrite(rgb, cb, 1, fp);
+	fclose(fp);
+
+#if 0
+	char * szX;
+	int cbPrint = 0;
+	cn_cbor * cbor = COSE_get_cbor((HCOSE)hEncObj);
+	cbPrint = cn_cbor_printer_write(NULL, 0, cbor, "  ", "\r\n");
+	szX = malloc(cbPrint);
+	cn_cbor_printer_write(szX, cbPrint, cbor, "  ", "\r\n");
+	fprintf(stdout, "%s", szX);
+	fprintf(stdout, "\r\n");
+#endif
+
+	COSE_Sign_Free(hEncObj);
+
+	/* */
+
+	int typ;
+	hEncObj = (HCOSE_SIGN)COSE_Decode(rgb, (int)cb, &typ, COSE_sign_object, NULL, NULL);
+
+#if 0
+	int iSigner = 0;
+	do {
+		HCOSE_RECIPIENT hSigner;
+
+		hSigner = COSE_Encrypt_GetRecipient(hEncObj, iSigner, NULL);
+		if (hSigner == NULL) break;
+
+		COSE_Recipient_SetKey(hSigner, rgbSecret, cbSecret, NULL);
+
+		COSE_Encrypt_decrypt(hEncObj, hSigner, NULL);
+
+		iSigner += 1;
+
+	} while (true);
+#endif
+
+	COSE_Sign_Free(hEncObj);
+
+	return 1;
+}
diff --git a/test/test.c b/test/test.c
index e898733..4f11f60 100644
--- a/test/test.c
+++ b/test/test.c
@@ -20,10 +20,12 @@
 int CFails = 0;
 
 
-struct {
+typedef struct _NameMap {
 	char * sz;
 	int    i;
-} RgAlgorithmNames[23] = {
+} NameMap;
+
+NameMap RgAlgorithmNames[23] = {
 	{"HS256", COSE_Algorithm_HMAC_256_256},
 	{"HS256/64", COSE_Algorithm_HMAC_256_64},
 	{"HS384", COSE_Algorithm_HMAC_384_384},
@@ -49,12 +51,19 @@
 	{"AES-CCM-64-256/128", COSE_Algorithm_AES_CCM_64_128_256}
 };
 
-int MapAlgorithmName(const cn_cbor * p)
+
+NameMap RgCurveNames[3] = {
+	{"P-256", 1},
+	{"P-384", 2},
+	{"P-512", 3}
+};
+
+int MapName(const cn_cbor * p, NameMap * rgMap, int cMap)
 {
 	unsigned int i;
 
-	for (i = 0; i < _countof(RgAlgorithmNames); i++) {
-		if (strcmp(RgAlgorithmNames[i].sz, p->v.str) == 0) return RgAlgorithmNames[i].i;
+	for (i = 0; i < cMap; i++) {
+		if (strcmp(rgMap[i].sz, p->v.str) == 0) return rgMap[i].i;
 	}
 
 	assert(false);
@@ -62,6 +71,11 @@
 	return 0;
 }
 
+int MapAlgorithmName(const cn_cbor * p)
+{
+	return MapName(p, RgAlgorithmNames, _countof(RgAlgorithmNames));
+}
+
 cn_cbor * cn_cbor_clone(const cn_cbor * pIn)
 {
 	cn_cbor * pOut = NULL;
@@ -123,6 +137,7 @@
 #define OPERATION_NONE 0
 #define OPERATION_BASE64 1
 #define OPERATION_IGNORE 2
+#define OPERATION_STRING 3
 
 struct {
 	char * szKey;
@@ -132,7 +147,7 @@
 } RgStringKeys[7] = {
 	{ "kty", 0, OPERATION_IGNORE, 0},
 	{ "kid", 0, OPERATION_NONE, 1},
-	{ "crv", 2, OPERATION_NONE, -1},
+	{ "crv", 2, OPERATION_STRING, -1},
 	{ "x", 2, OPERATION_BASE64, -2},
 	{ "y", 2, OPERATION_BASE64, -3},
 	{ "d", 2, OPERATION_BASE64, -4},
@@ -244,6 +259,10 @@
 						pb = base64_decode(pValue->v.str, pValue->length, &cb);
 						cn_cbor_mapput_int(pKeyOut, RgStringKeys[i].keyNew, cn_cbor_data_create(pb, (int) cb, CBOR_CONTEXT_PARAM_COMMA NULL), CBOR_CONTEXT_PARAM_COMMA NULL);
 						break;
+
+					case OPERATION_STRING:
+						cn_cbor_mapput_int(pKeyOut, RgStringKeys[i].keyNew, cn_cbor_int_create(MapName(pValue, RgCurveNames, _countof(RgCurveNames)), CBOR_CONTEXT_PARAM_COMMA NULL), CBOR_CONTEXT_PARAM_COMMA NULL);
+						break;
 					}
 					i = 99;
 				}
@@ -449,79 +468,6 @@
 	return 1;
 }
 
-int SignMessage()
-{
-	HCOSE_SIGN hEncObj = COSE_Sign_Init(CBOR_CONTEXT_PARAM_COMMA NULL);
-	char * sz = "This is the content to be used";
-	size_t cb;
-	byte * rgb;
-
-			byte rgbX[] = { 0x65, 0xed, 0xa5, 0xa1, 0x25, 0x77, 0xc2, 0xba, 0xe8, 0x29, 0x43, 0x7f, 0xe3, 0x38, 0x70, 0x1a, 0x10, 0xaa, 0xa3, 0x75, 0xe1, 0xbb, 0x5b, 0x5d, 0xe1, 0x08, 0xde, 0x43, 0x9c, 0x08, 0x55, 0x1d };
-		byte rgbY[] = { 0x1e, 0x52, 0xed, 0x75, 0x70, 0x11, 0x63, 0xf7, 0xf9, 0xe4, 0x0d, 0xdf, 0x9f, 0x34, 0x1b, 0x3d, 0xc9, 0xba, 0x86, 0x0a, 0xf7, 0xe0, 0xca, 0x7c, 0xa7, 0xe9, 0xee, 0xcd, 0x00, 0x84, 0xd1, 0x9c };
-		byte kid[] = { 0x6d, 0x65, 0x72, 0x69, 0x61, 0x64, 0x6f, 0x63, 0x2e, 0x62, 0x72, 0x61, 0x6e, 0x64, 0x79, 0x62, 0x75, 0x63, 0x6, 0xb4, 0x06, 0x27, 0x56, 0x36, 0xb6, 0xc6, 0x16, 0xe6, 0x42, 0xe6, 0x57, 0x86, 0x16, 0xd7, 0x06, 0x65};
-		byte rgbD[] = {0xaf, 0xf9, 0x07, 0xc9, 0x9f, 0x9a, 0xd3, 0xaa, 0xe6, 0xc4, 0xcd, 0xf2, 0x11, 0x22, 0xbc, 0xe2, 0xbd, 0x68, 0xb5, 0x28, 0x3e, 0x69, 0x07, 0x15, 0x4a, 0xd9, 0x11, 0x84, 0x0f, 0xa2, 0x08, 0xcf};
-			
-			cn_cbor * pkey = cn_cbor_map_create(CBOR_CONTEXT_PARAM_COMMA NULL);
-	cn_cbor_mapput_int(pkey, COSE_Key_Type, cn_cbor_int_create(COSE_Key_Type_EC2, CBOR_CONTEXT_PARAM_COMMA NULL), CBOR_CONTEXT_PARAM_COMMA NULL);
-	cn_cbor_mapput_int(pkey, -1, cn_cbor_int_create(1, CBOR_CONTEXT_PARAM_COMMA NULL), CBOR_CONTEXT_PARAM_COMMA NULL);
-	cn_cbor_mapput_int(pkey, -2, cn_cbor_data_create(rgbX, sizeof(rgbX), CBOR_CONTEXT_PARAM_COMMA NULL), CBOR_CONTEXT_PARAM_COMMA NULL);
-	cn_cbor_mapput_int(pkey, -3, cn_cbor_data_create(rgbY, sizeof(rgbY), CBOR_CONTEXT_PARAM_COMMA NULL), CBOR_CONTEXT_PARAM_COMMA NULL);
-	cn_cbor_mapput_int(pkey, COSE_Key_ID, cn_cbor_data_create(kid, sizeof(kid), CBOR_CONTEXT_PARAM_COMMA NULL), CBOR_CONTEXT_PARAM_COMMA NULL);
-	cn_cbor_mapput_int(pkey, -4, cn_cbor_data_create(rgbD, sizeof(rgbD), CBOR_CONTEXT_PARAM_COMMA NULL), CBOR_CONTEXT_PARAM_COMMA NULL);
-
-	COSE_Sign_SetContent(hEncObj, (byte *) sz, strlen(sz), NULL);
-	COSE_Sign_add_signer(hEncObj, pkey, COSE_Algorithm_ECDSA_SHA_256, NULL);
-
-	COSE_Sign_Sign(hEncObj, NULL);
-
-	cb = COSE_Encode((HCOSE)hEncObj, NULL, 0, 0) + 1;
-	rgb = (byte *)malloc(cb);
-	cb = COSE_Encode((HCOSE)hEncObj, rgb, 0, cb);
-
-
-	FILE * fp = fopen("test.mac.cbor", "wb");
-	fwrite(rgb, cb, 1, fp);
-	fclose(fp);
-
-#if 0
-	char * szX;
-	int cbPrint = 0;
-	cn_cbor * cbor = COSE_get_cbor((HCOSE)hEncObj);
-	cbPrint = cn_cbor_printer_write(NULL, 0, cbor, "  ", "\r\n");
-	szX = malloc(cbPrint);
-	cn_cbor_printer_write(szX, cbPrint, cbor, "  ", "\r\n");
-	fprintf(stdout, "%s", szX);
-	fprintf(stdout, "\r\n");
-#endif
-
-	COSE_Sign_Free(hEncObj);
-
-	/* */
-
-	int typ;
-	hEncObj = (HCOSE_SIGN)COSE_Decode(rgb, (int)cb, &typ, COSE_sign_object, NULL, NULL);
-
-#if 0
-	int iRecipient = 0;
-	do {
-		HCOSE_RECIPIENT hRecip;
-
-		hRecip = COSE_Encrypt_GetRecipient(hEncObj, iRecipient, NULL);
-		if (hRecip == NULL) break;
-
-		COSE_Recipient_SetKey(hRecip, rgbSecret, cbSecret, NULL);
-
-		COSE_Encrypt_decrypt(hEncObj, hRecip, NULL);
-
-		iRecipient += 1;
-
-	} while (true);
-#endif
-
-	COSE_Sign_Free(hEncObj);
-
-	return 1;
-}
 
 bool cn_cbor_array_replace(cn_cbor * cb_array, cn_cbor * cb_value, int index, CBOR_CONTEXT_COMMA cn_cbor_errback *errp);
 
@@ -588,6 +534,9 @@
 			ValidateEnveloped(pControl);
 			BuildEncryptMessage(pControl);
 		}
+		else if (cn_cbor_mapget_string(pInput, "sign") != NULL) {
+			ValidateSigned(pControl);
+		}
 	}
 	else {
 		MacMessage();
diff --git a/test/test.h b/test/test.h
index fc48d29..5150c75 100644
--- a/test/test.h
+++ b/test/test.h
@@ -17,6 +17,12 @@
 int EncryptMessage();
 int BuildEncryptMessage(const cn_cbor * pControl);
 
+//  sign.c
+
+int ValidateSigned(const cn_cbor * pControl);
+int SignMessage();
+int BuildSignedMessage(const cn_cbor * pControl);
+
 
 //  test.c
 enum {