EdDSA support added for openssl (#82)

* Add EDDSA for OpenSSL

* No support for EdDSA in MBEDTLS

* Install OpenSSL v1.1.1f in order to get EdDSA support in OpenSSL
diff --git a/.ci/build-openssl.sh b/.ci/build-openssl.sh
new file mode 100644
index 0000000..e483f77
--- /dev/null
+++ b/.ci/build-openssl.sh
@@ -0,0 +1,24 @@
+#!/bin/bash
+set -eux
+
+download_openssl () {
+    if [[ ! -f "download-cache/openssl-${OPENSSL_VERSION}.tar.gz" ]]; then
+        wget -P download-cache/ \
+            "https://www.openssl.org/source/openssl-${OPENSSL_VERSION}.tar.gz"
+    fi
+}
+
+build_openssl () {
+    if [[ "$(cat ${OPENSSL_INSTALL_DIR}/.openssl-version)" != "${OPENSSL_VERSION}" ]]; then
+        tar zxf "download-cache/openssl-${OPENSSL_VERSION}.tar.gz"
+        cd "openssl-${OPENSSL_VERSION}/"
+        ./config shared no-deprecated --prefix="${OPENSSL_INSTALL_DIR}" --openssldir="${OPENSSL_INSTALL_DIR}" -DPURIFY
+        make -j $(nproc || sysctl -n hw.ncpu || echo 4) all
+        make install_sw
+        echo "${OPENSSL_VERSION}" > "${OPENSSL_INSTALL_DIR}/.openssl-version"
+    fi
+}
+
+
+download_openssl
+build_openssl
diff --git a/.travis.yml b/.travis.yml
index a146184..9a3b1d5 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -3,22 +3,24 @@
   - clang
   - gcc
 sudo: false
-before_install:
-  - pip install cpp-coveralls --user
-  - export LD_LIBRARY_PATH=$PWD/build/dist/lib:$LD_LIBRARY_PATH
 env:
-  - USE_CONTEXT=ON
-    COVERALLS="-DCOSE_C_COVERALLS_SEND=ON"
-  - USE_CONTEXT=OFF
-    COVERALLS="-DCOSE_C_COVERALLS_SEND=ON"
-  - USE_CONTEXT=OFF USE_EMBEDTLS=ON
-    COVERALLS="-DCOSE_C_COVERALLS_SEND=ON"
-  - CMAKE_OPTIONS="-DCOSE_C_INCLUDE_ENCRYPT=ON -DCOSE_C_INCLUDE_encrypt0=OFF -DCOSE_C_INCLUDE_MAC0=OFF -DCOSE_C_INCLUDE_MAC=OFF -DCOSE_C_INCLUDE_SIGN=OFF -DCOSE_C_INCLUDE_SIGN1=OFF"
-  - CMAKE_OPTIONS="-DCOSE_C_INCLUDE_ENCRYPT=OFF -DCOSE_C_INCLUDE_encrypt0=ON -DCOSE_C_INCLUDE_MAC0=OFF -DCOSE_C_INCLUDE_MAC=OFF -DCOSE_C_INCLUDE_SIGN=OFF -DCOSE_C_INCLUDE_SIGN1=OFF"
-  - CMAKE_OPTIONS="-DCOSE_C_INCLUDE_ENCRYPT=OFF -DCOSE_C_INCLUDE_encrypt0=OFF -DCOSE_C_INCLUDE_MAC0=ON -DCOSE_C_INCLUDE_MAC=OFF -DCOSE_C_INCLUDE_SIGN=OFF -DCOSE_C_INCLUDE_SIGN1=OFF"
-  - CMAKE_OPTIONS="-DCOSE_C_INCLUDE_ENCRYPT=OFF -DCOSE_C_INCLUDE_encrypt0=OFF -DCOSE_C_INCLUDE_MAC0=OFF -DCOSE_C_INCLUDE_MAC=ON -DCOSE_C_INCLUDE_SIGN=OFF -DCOSE_C_INCLUDE_SIGN1=OFF"
-  - CMAKE_OPTIONS="-DCOSE_C_INCLUDE_ENCRYPT=OFF -DCOSE_C_INCLUDE_encrypt0=OFF -DCOSE_C_INCLUDE_MAC0=OFF -DCOSE_C_INCLUDE_MAC=OFF -DCOSE_C_INCLUDE_SIGN=ON -DCOSE_C_INCLUDE_SIGN1=OFF"
-  - CMAKE_OPTIONS="-DCOSE_C_INCLUDE_ENCRYPT=OFF -DCOSE_C_INCLUDE_encrypt0=OFF -DCOSE_C_INCLUDE_MAC0=OFF -DCOSE_C_INCLUDE_MAC=OFF -DCOSE_C_INCLUDE_SIGN=OFF -DCOSE_C_INCLUDE_SIGN1=ON"
+  global:
+    - OPENSSL_VERSION="1.1.1f"
+      OPENSSL_INSTALL_DIR="${HOME}/opt"
+  jobs:
+    - USE_CONTEXT=ON
+      COVERALLS="-DCOSE_C_COVERALLS_SEND=ON"
+    - USE_CONTEXT=OFF
+      COVERALLS="-DCOSE_C_COVERALLS_SEND=ON"
+    - USE_CONTEXT=OFF USE_EMBEDTLS=ON
+      COVERALLS="-DCOSE_C_COVERALLS_SEND=ON"
+    - CMAKE_OPTIONS="-DCOSE_C_INCLUDE_ENCRYPT=ON -DCOSE_C_INCLUDE_encrypt0=OFF -DCOSE_C_INCLUDE_MAC0=OFF -DCOSE_C_INCLUDE_MAC=OFF -DCOSE_C_INCLUDE_SIGN=OFF -DCOSE_C_INCLUDE_SIGN1=OFF"
+    - CMAKE_OPTIONS="-DCOSE_C_INCLUDE_ENCRYPT=OFF -DCOSE_C_INCLUDE_encrypt0=ON -DCOSE_C_INCLUDE_MAC0=OFF -DCOSE_C_INCLUDE_MAC=OFF -DCOSE_C_INCLUDE_SIGN=OFF -DCOSE_C_INCLUDE_SIGN1=OFF"
+    - CMAKE_OPTIONS="-DCOSE_C_INCLUDE_ENCRYPT=OFF -DCOSE_C_INCLUDE_encrypt0=OFF -DCOSE_C_INCLUDE_MAC0=ON -DCOSE_C_INCLUDE_MAC=OFF -DCOSE_C_INCLUDE_SIGN=OFF -DCOSE_C_INCLUDE_SIGN1=OFF"
+    - CMAKE_OPTIONS="-DCOSE_C_INCLUDE_ENCRYPT=OFF -DCOSE_C_INCLUDE_encrypt0=OFF -DCOSE_C_INCLUDE_MAC0=OFF -DCOSE_C_INCLUDE_MAC=ON -DCOSE_C_INCLUDE_SIGN=OFF -DCOSE_C_INCLUDE_SIGN1=OFF"
+    - CMAKE_OPTIONS="-DCOSE_C_INCLUDE_ENCRYPT=OFF -DCOSE_C_INCLUDE_encrypt0=OFF -DCOSE_C_INCLUDE_MAC0=OFF -DCOSE_C_INCLUDE_MAC=OFF -DCOSE_C_INCLUDE_SIGN=ON -DCOSE_C_INCLUDE_SIGN1=OFF"
+    - CMAKE_OPTIONS="-DCOSE_C_INCLUDE_ENCRYPT=OFF -DCOSE_C_INCLUDE_encrypt0=OFF -DCOSE_C_INCLUDE_MAC0=OFF -DCOSE_C_INCLUDE_MAC=OFF -DCOSE_C_INCLUDE_SIGN=OFF -DCOSE_C_INCLUDE_SIGN1=ON"
+
 matrix:
   exclude:
     - compiler: clang
@@ -31,12 +33,19 @@
       - llvm-toolchain-precise-3.8
       - george-edison55-precise-backports
     packages:
-    - libssl-dev
-#    - libssl1.1.0
+    # - libssl-dev
+    # - libssl1.1
     - cmake
     - cmake-data
+
+before_install:
+  - pip install cpp-coveralls --user
+  - export LD_LIBRARY_PATH=$PWD/build/dist/lib:$LD_LIBRARY_PATH
+  - bash .ci/build-openssl.sh > build-deps.log 2>&1 || (cat build-deps.log && exit 1)
+
 script:
 #  - apt-get install libssl1.1.0
+  - export OPENSSL_ROOT_DIR=${OPENSSL_INSTALL_DIR}
   - cmake --version
   - git clone --depth 1 git://github.com/cose-wg/Examples Examples
   - mkdir build
diff --git a/include/cose/cose.h b/include/cose/cose.h
index 8b197d4..d767c85 100644
--- a/include/cose/cose.h
+++ b/include/cose/cose.h
@@ -132,6 +132,8 @@
 
 	COSE_Algorithm_Direct = -6,
 
+	COSE_Algorithm_EdDSA = - 8,
+
 	COSE_Algorithm_Direct_HKDF_HMAC_SHA_256 = -10,
 	COSE_Algorithm_Direct_HKDF_HMAC_SHA_512 = -11,
 	COSE_Algorithm_Direct_HKDF_AES_128 = -12,
@@ -177,6 +179,7 @@
 } COSE_Header;
 
 typedef enum {
+	COSE_Key_Type_OKP = 1,
 	COSE_Key_Type_EC2 = 2,
 	COSE_Key_Type_OCTET = 4,
 	COSE_Key_Type = 1,
@@ -184,9 +187,20 @@
 	COSE_Parameter_KID = 4,
 	COSE_Key_EC2_Curve=-1,
 	COSE_Key_EC2_X = -2,
-	COSE_Key_EC2_Y = -3
+	COSE_Key_EC2_Y = -3,
+	COSE_Key_OPK_Curve = -1,
+	COSE_Key_OPK_X = -2,
 } COSE_Constants;
 
+typedef enum {
+	COSE_Curve_P256 = 1,
+	COSE_Curve_P384 = 2,
+	COSE_Curve_P521 = 3,
+	COSE_Curve_X25519 = 4,
+	COSE_Curve_X448 = 5,
+	COSE_Curve_Ed25519 = 6,
+	COSE_Curve_Ed448 = 7,
+} COSE_Curves;
 
 /*
  *  messages dealing with the Enveloped message type
diff --git a/include/cose/cose_configure.h b/include/cose/cose_configure.h
index 978c36e..dfabc96 100644
--- a/include/cose/cose_configure.h
+++ b/include/cose/cose_configure.h
@@ -13,6 +13,7 @@
 #error Only Define One Crypto Package
 #endif
 #elif !defined(USE_OPEN_SSL)
+#include <openssl/opensslv.h>
 #define USE_OPEN_SSL
 #endif
 
@@ -131,7 +132,16 @@
 #define USE_ECDSA_SHA_256
 #define USE_ECDSA_SHA_384
 #define USE_ECDSA_SHA_512
-
+#if !defined(USE_MBED_TLS)
+//  MBEDTLS currently supports ECDH for X25519 but not EdDSA
+#if OPENSSL_VERSION_NUMBER > 0x10100000L
+// Requires OPEN SSL 1.1.1 to build
+#define USE_EDDSA
+#else
+#pragma message("OPENSSL VERSION IS ")
+#pragma message(OPENSSL_VERISON_NUMBER)
+#endif
+#endif // !defined (USE_MBED_TLS)
 
 
 //#define USE_COUNTER_SIGNATURES
diff --git a/src/Sign1.c b/src/Sign1.c
index ae9c405..93364b8 100644
--- a/src/Sign1.c
+++ b/src/Sign1.c
@@ -369,6 +369,13 @@
 		f = ECDSA_Sign(&pSigner->m_message, INDEX_SIGNATURE+1, pKey, 512, pbToSign, cbToSign, perr);
 		break;
 #endif
+
+#ifdef USE_EDDSA
+	case COSE_Algorithm_EdDSA:
+		f = EdDSA_Sign(&pSigner->m_message, INDEX_SIGNATURE + 1, pKey, pbToSign, cbToSign, perr);
+		break;
+#endif
+
 	default:
 		FAIL_CONDITION(COSE_ERR_UNKNOWN_ALGORITHM);
 	}
@@ -429,6 +436,12 @@
 		break;
 #endif
 
+#ifdef USE_EDDSA
+	case COSE_Algorithm_EdDSA:
+		if (!EdDSA_Verify(&pSign->m_message, INDEX_SIGNATURE + 1, pKey, pbToSign, cbToSign, perr)) goto errorReturn;
+		break;
+#endif
+
 	default:
 		FAIL_CONDITION(COSE_ERR_UNKNOWN_ALGORITHM);
 		break;
diff --git a/src/SignerInfo.c b/src/SignerInfo.c
index 33b01d9..82e3a24 100644
--- a/src/SignerInfo.c
+++ b/src/SignerInfo.c
@@ -179,7 +179,6 @@
 	cn_cbor * cnAlgorithm = NULL;
 	size_t cbToSign;
 	byte * pbToSign = NULL;
-	bool f;
 	int alg;
 	bool fRet = false;
 
@@ -222,6 +221,12 @@
 		break;
 #endif
 
+#ifdef USE_EDDSA
+	case COSE_Algorithm_EdDSA:
+		if (!EdDSA_Sign(&pSigner->m_message, INDEX_SIGNATURE, pSigner->m_pkey, pbToSign, cbToSign, perr)) goto errorReturn;
+		break;
+#endif
+
 	default:
 		FAIL_CONDITION(COSE_ERR_UNKNOWN_ALGORITHM);
 	}
@@ -334,6 +339,12 @@
 		break;
 #endif
 
+#ifdef USE_EDDSA
+	case COSE_Algorithm_EdDSA:
+		if (!EdDSA_Verify(&pSigner->m_message, INDEX_SIGNATURE, pSigner->m_pkey, pbToBeSigned, cbToBeSigned, perr)) goto errorReturn;
+		break;
+#endif
+
 	default:
 		FAIL_CONDITION(COSE_ERR_UNKNOWN_ALGORITHM);
 		break;
diff --git a/src/crypto.h b/src/crypto.h
index 2caebf1..9afb3d6 100644
--- a/src/crypto.h
+++ b/src/crypto.h
@@ -67,6 +67,9 @@
 
 bool ECDH_ComputeSecret(COSE * pReciient, cn_cbor ** ppKeyMe, const cn_cbor * pKeyYou, byte ** ppbSecret, size_t * pcbSecret, CBOR_CONTEXT_COMMA cose_errback *perr);
 
+bool EdDSA_Sign(COSE* pSigner, int index, const cn_cbor* pKey, const byte* rgbToSign, size_t cbToSign, cose_errback* perr);
+bool EdDSA_Verify(COSE* pSigner, int index, const cn_cbor* pKey, const byte* rgbToSign, size_t cbToSign, cose_errback* perr);
+
 /**
 *  Generate random bytes in a buffer
 *
diff --git a/src/openssl.c b/src/openssl.c
index 2ace55c..229ba29 100644
--- a/src/openssl.c
+++ b/src/openssl.c
@@ -1118,6 +1118,137 @@
 	return true;
 }
 
+
+#ifdef USE_EDDSA
+bool EdDSA_Sign(COSE* pSigner, int index, const cn_cbor* pKeyIn, const byte* rgbToSign, size_t cbToSign, cose_errback* perr)
+{
+#ifdef USE_CBOR_CONTEXT
+	cn_cbor_context* context = &pSigner->m_allocContext;
+#endif
+	cn_cbor* p;
+	cn_cbor_errback cbor_error;
+	EVP_PKEY_CTX* keyCtx = NULL;
+	EVP_MD_CTX* mdCtx = NULL;
+	EVP_PKEY* pkey = NULL;
+	byte* pbSig = NULL;
+	int cbSig;
+
+	p = cn_cbor_mapget_int(pKeyIn, COSE_Key_OPK_Curve);
+	if (p == NULL) {
+	errorReturn:
+		if (mdCtx != NULL) EVP_MD_CTX_free(mdCtx);
+		if (keyCtx != NULL) EVP_PKEY_CTX_free(keyCtx);
+		if (pkey != NULL) EVP_PKEY_free(pkey);
+		if (pbSig != NULL) COSE_FREE(pbSig, context);
+		return false;
+	}
+
+	int type;
+
+	switch (p->v.uint) {
+	case COSE_Curve_Ed25519:
+		type = EVP_PKEY_ED25519;
+		cbSig = 32 * 2;
+		break;
+
+	case COSE_Curve_Ed448:
+		type = EVP_PKEY_ED448;
+		cbSig = 64 * 2;
+		break;
+
+	default:
+		FAIL_CONDITION(COSE_ERR_INVALID_PARAMETER);
+	}
+
+	p = cn_cbor_mapget_int(pKeyIn, COSE_Key_EC_d);
+	CHECK_CONDITION(p != NULL, COSE_ERR_INVALID_PARAMETER);
+
+	pkey = EVP_PKEY_new_raw_private_key(type, NULL, p->v.bytes, p->length);
+	CHECK_CONDITION(pkey != NULL, COSE_ERR_CRYPTO_FAIL);
+
+	keyCtx = EVP_PKEY_CTX_new_id(type, NULL);
+	CHECK_CONDITION(keyCtx != NULL, COSE_ERR_OUT_OF_MEMORY);
+
+	mdCtx = EVP_MD_CTX_new();
+	CHECK_CONDITION(mdCtx != NULL, COSE_ERR_OUT_OF_MEMORY);
+
+	CHECK_CONDITION(EVP_DigestSignInit(mdCtx, &keyCtx, NULL, NULL, pkey) == 1, COSE_ERR_CRYPTO_FAIL);
+	keyCtx = NULL;
+
+	pbSig = COSE_CALLOC(cbSig, 1, context);
+	CHECK_CONDITION(pbSig != NULL, COSE_ERR_OUT_OF_MEMORY);
+
+	size_t cb2 = cbSig;
+	CHECK_CONDITION(EVP_DigestSign(mdCtx, pbSig, &cb2, rgbToSign, cbToSign) == 1, COSE_ERR_CRYPTO_FAIL);
+
+	p = cn_cbor_data_create(pbSig, (int)cb2, CBOR_CONTEXT_PARAM_COMMA & cbor_error);
+	CHECK_CONDITION(p != NULL, COSE_ERR_OUT_OF_MEMORY);
+	pbSig = NULL;
+
+	CHECK_CONDITION(_COSE_array_replace(pSigner, p, index, CBOR_CONTEXT_PARAM_COMMA NULL), COSE_ERR_CBOR);
+
+	if (mdCtx != NULL) EVP_MD_CTX_free(mdCtx);
+	if (keyCtx != NULL) EVP_PKEY_CTX_free(keyCtx);
+	if (pkey != NULL) EVP_PKEY_free(pkey);
+	if (pbSig != NULL) COSE_FREE(pbSig, context);
+
+	return true;
+}
+
+bool EdDSA_Verify(COSE* pSigner, int index, const cn_cbor* pKey, const byte* rgbToSign, size_t cbToSign, cose_errback* perr)
+{
+#ifdef USE_CBOR_CONTEXT
+	cn_cbor_context* context = &pSigner->m_allocContext;
+#endif
+	cn_cbor* p = NULL;
+	cn_cbor* pSig;
+	EVP_PKEY* pkey = NULL;
+
+	p = cn_cbor_mapget_int(pKey, COSE_Key_OPK_Curve);
+	if (p == NULL) {
+	errorReturn:
+		if (pkey != NULL) EVP_PKEY_free(pkey);
+		return false;
+	}
+
+	int type;
+
+	switch (p->v.uint) {
+	case COSE_Curve_Ed25519:
+		type = EVP_PKEY_ED25519;
+		break;
+
+	case COSE_Curve_Ed448:
+		type = EVP_PKEY_ED448;
+		break;
+
+	default:
+		FAIL_CONDITION(COSE_ERR_INVALID_PARAMETER);
+	}
+
+	p = cn_cbor_mapget_int(pKey, COSE_Key_OPK_X);
+	CHECK_CONDITION(p != NULL, COSE_ERR_INVALID_PARAMETER);
+
+	pkey = EVP_PKEY_new_raw_public_key(type, NULL, p->v.bytes, p->length);
+	CHECK_CONDITION(pkey != NULL, COSE_ERR_CBOR);
+
+	pSig = _COSE_arrayget_int(pSigner, index);
+	CHECK_CONDITION(pSig != NULL, COSE_ERR_INVALID_PARAMETER);
+
+	EVP_MD_CTX* pmdCtx = EVP_MD_CTX_new();
+	EVP_PKEY_CTX* keyCtx = EVP_PKEY_CTX_new_id(type, NULL);
+
+	CHECK_CONDITION(EVP_DigestVerifyInit(pmdCtx, &keyCtx, NULL, NULL, pkey) == 1, COSE_ERR_CRYPTO_FAIL);
+
+	CHECK_CONDITION(EVP_DigestVerify(pmdCtx, pSig->v.bytes, pSig->length, rgbToSign, cbToSign) == 1, COSE_ERR_CRYPTO_FAIL);
+
+	if (pmdCtx != NULL) EVP_MD_CTX_free(pmdCtx);
+	if (pkey != NULL) EVP_PKEY_free(pkey);
+
+	return true;
+}
+#endif
+
 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)
 {
 	byte rgbOut[512 / 8];
diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt
index d8b48cc..b95743f 100644
--- a/test/CMakeLists.txt
+++ b/test/CMakeLists.txt
@@ -57,6 +57,10 @@
   NAME ecdsa
   WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}
   COMMAND cose_test --dir Examples/ecdsa-examples)
+add_test(
+  NAME eddsa
+  WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}
+  COMMAND cose_test --dir Examples/eddsa-examples)
 
 add_test(
   NAME hmac
@@ -150,3 +154,11 @@
   NAME Memory-sign
   WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}
   COMMAND cose_test --memory Examples/ecdsa-examples/ecdsa-01.json)
+add_test(
+  NAME Memory-sign0-eddsa
+  WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}
+  COMMAND cose_test --memory Examples/eddsa-examples/eddsa-sig-01.json)
+add_test(
+  NAME Memory-sign-eddsa
+  WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}
+  COMMAND cose_test --memory Examples/eddsa-examples/eddsa-01.json)
diff --git a/test/json.c b/test/json.c
index e7931d0..9a99ecd 100644
--- a/test/json.c
+++ b/test/json.c
@@ -249,3 +249,37 @@
 void base64_cleanup() {
 	free(decoding_table);
 }
+
+unsigned char* hex_decode(const char* data,
+	size_t input_length,
+	size_t* output_length) {
+
+    if (input_length % 2 != 0) {
+		return NULL;
+	}
+
+	*output_length = input_length / 2;
+
+	unsigned char* decoded_data = malloc(*output_length);
+	if (decoded_data == NULL) {
+		return NULL;
+	}
+
+	for (unsigned int i = 0, j = 0; i < input_length; i++) {
+		int c;
+
+		if ('0' <= data[i] && data[i] <= '9') c = data[i] - '0';
+		else if ('A' <= data[i] && data[i] <= 'F') c = data[i] - 'A' + 10;
+		else if ('a' <= data[i] && data[i] <= 'f') c = data[i] - 'a' + 10;
+		else return NULL;
+
+		if ((i & 0x1) == 0) {
+			decoded_data[j] = ((unsigned char) c << 4);
+		}
+		else {
+			decoded_data[j++] |= (unsigned char)c;
+		}
+	}
+
+	return decoded_data;
+}
diff --git a/test/json.h b/test/json.h
index 4dbabf3..4e2d60f 100644
--- a/test/json.h
+++ b/test/json.h
@@ -3,3 +3,4 @@
 extern const cn_cbor * ParseJson(const char * fileName);
 
 extern unsigned char *base64_decode(const char *data,	size_t input_length,	size_t *output_length);
+extern unsigned char* hex_decode(const char* data, size_t input_length, size_t* output_length);
diff --git a/test/test.c b/test/test.c
index 209af1b..bc110f1 100644
--- a/test/test.c
+++ b/test/test.c
@@ -33,7 +33,7 @@
 	int    i;
 } NameMap;
 
-NameMap RgAlgorithmNames[47] = {
+NameMap RgAlgorithmNames[48] = {
 	{"HS256", COSE_Algorithm_HMAC_256_256},
 	{"HS256/64", COSE_Algorithm_HMAC_256_64},
 	{"HS384", COSE_Algorithm_HMAC_384_384},
@@ -81,13 +81,18 @@
 { "ECDH-SS-A128KW", COSE_Algorithm_ECDH_SS_A128KW },
 { "ECDH-SS-A192KW", COSE_Algorithm_ECDH_SS_A192KW },
 { "ECDH-SS-A256KW", COSE_Algorithm_ECDH_SS_A256KW },
+	{ "EdDSA", COSE_Algorithm_EdDSA},
 };
 
 
-NameMap RgCurveNames[3] = {
+NameMap RgCurveNames[7] = {
 	{"P-256", 1},
 	{"P-384", 2},
-	{"P-521", 3}
+	{"P-521", 3},
+	{"X25519", 4},
+	{"X448", 5},
+	{"Ed25519", 6},
+	{"Ed448", 7}
 };
 
 int MapName(const cn_cbor * p, NameMap * rgMap, unsigned int cMap)
@@ -259,6 +264,9 @@
 #ifdef USE_HMAC_512_512
 	case COSE_Algorithm_HMAC_512_512:
 #endif
+#ifdef USE_EDDSA
+	case COSE_Algorithm_EdDSA:
+#endif
 	case COSE_Algorithm_Direct:
 	case -999: // Unsupported algorithm for testing.
 		return true;
@@ -300,20 +308,24 @@
 #define OPERATION_BASE64 1
 #define OPERATION_IGNORE 2
 #define OPERATION_STRING 3
+#define OPERATION_HEX 4
 
 struct {
 	char * szKey;
 	int kty;
 	int operation;
 	int keyNew;
-} RgStringKeys[7] = {
+} RgStringKeys[10] = {
 	{ "kty", 0, OPERATION_IGNORE, COSE_Key_Type},
 	{ "kid", 0, OPERATION_NONE, COSE_Key_ID},
 	{ "crv", 2, OPERATION_STRING, COSE_Key_EC2_Curve},
 	{ "x", 2, OPERATION_BASE64, COSE_Key_EC2_X},
 	{ "y", 2, OPERATION_BASE64, COSE_Key_EC2_Y},
 	{ "d", 2, OPERATION_BASE64, -4},
-	{ "k", 4, OPERATION_BASE64, -1}
+	{ "k", 4, OPERATION_BASE64, -1},
+	{ "crv", COSE_Key_Type_OKP, OPERATION_STRING, COSE_Key_OPK_Curve},
+	{ "x_hex", COSE_Key_Type_OKP, OPERATION_HEX, COSE_Key_OPK_X},
+	{ "d_hex", COSE_Key_Type_OKP, OPERATION_HEX, -4}
 };
 
 bool SetAttributes(HCOSE hHandle, const cn_cbor * pAttributes, int which, int msgType, bool fPublicKey)
@@ -563,6 +575,7 @@
 	}
 	else if (pKty->length == 3) {
 		if (strncmp(pKty->v.str, "oct", 3) == 0) kty = 4;
+		else if (strncmp(pKty->v.str, "OKP", 3) == 0) kty = COSE_Key_Type_OKP;
 		else return NULL;
 	}
 	else return NULL;
@@ -575,7 +588,7 @@
 		pValue = pKey->next;
 
 		if (pKey->type == CN_CBOR_TEXT) {
-			for (i = 0; i < 7; i++) {
+			for (i = 0; i < sizeof(RgStringKeys)/sizeof(RgStringKeys[0]); i++) {
 				if ((pKey->length == strlen(RgStringKeys[i].szKey)) &&
 					(strncmp(pKey->v.str, RgStringKeys[i].szKey, strlen(RgStringKeys[i].szKey)) == 0) &&
 					((RgStringKeys[i].kty == 0) || (RgStringKeys[i].kty == kty))) {
@@ -600,6 +613,14 @@
 						if (p == NULL) return NULL;
 						if (!cn_cbor_mapput_int(pKeyOut, RgStringKeys[i].keyNew, p, CBOR_CONTEXT_PARAM_COMMA NULL)) return NULL;
 						break;
+
+					case OPERATION_HEX:
+						if ((strcmp(pKey->v.str, "d_hex") == 0) && fPublicKey) continue;
+						pb = hex_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;
+						if (!cn_cbor_mapput_int(pKeyOut, RgStringKeys[i].keyNew, p, CBOR_CONTEXT_PARAM_COMMA NULL)) return NULL;
+						break;
 					}
 					i = 99;
 				}
@@ -695,9 +716,7 @@
 	bool fValidateDone = false;
 	bool fBuildDone = false;
 
-	for (iFail = 0; !fValidateDone || !fBuildDone; iFail++) {
-		context = CreateContext(iFail);
-
+	for (iFail = 0; (!fValidateDone || !fBuildDone) && (iFail < 3); iFail++) {
 		if (cn_cbor_mapget_string(pInput, "mac") != NULL) {
 #if INCLUDE_MAC
 			if (!fValidateDone) {
@@ -705,6 +724,7 @@
 				CFails = 0;
 				ValidateMAC(pControl);
 				if (CFails == 0) fValidateDone = true;
+				FreeContext(context);
 			}
 
 			if (!fBuildDone) {
@@ -712,6 +732,7 @@
 				CFails = 0;
 				BuildMacMessage(pControl);
 				if (CFails == 0) fBuildDone = true;
+				FreeContext(context);
 			}
 #else
 			fValidateDone = true;
@@ -725,6 +746,7 @@
 				CFails = 0;
 				ValidateMac0(pControl);
 				if (CFails == 0) fValidateDone = true;
+				FreeContext(context);
 			}
 
 			if (!fBuildDone) {
@@ -732,6 +754,7 @@
 				CFails = 0;
 				BuildMac0Message(pControl);
 				if (CFails == 0) fBuildDone = true;
+				FreeContext(context);
 			}
 #else
 			fValidateDone = true;
@@ -745,6 +768,7 @@
 				CFails = 0;
 				ValidateEncrypt(pControl);
 				if (CFails == 0) fValidateDone = true;
+				FreeContext(context);
 			}
 
 			if (!fBuildDone) {
@@ -752,6 +776,7 @@
 				CFails = 0;
 				BuildEncryptMessage(pControl);
 				if (CFails == 0) fBuildDone = true;
+				FreeContext(context);
 			}
 #else
 			fValidateDone = true;
@@ -765,6 +790,7 @@
 				CFails = 0;
 				ValidateEnveloped(pControl);
 				if (CFails == 0) fValidateDone = true;
+				FreeContext(context);
 			}
 
 			if (!fBuildDone) {
@@ -772,6 +798,7 @@
 				CFails = 0;
 				BuildEnvelopedMessage(pControl);
 				if (CFails == 0) fBuildDone = true;
+				FreeContext(context);
 			}
 #else
 			fValidateDone = true;
@@ -785,6 +812,7 @@
 				CFails = 0;
 				ValidateSigned(pControl);
 				if (CFails == 0) fValidateDone = true;
+				FreeContext(context);
 			}
 
 			if (!fBuildDone) {
@@ -792,6 +820,7 @@
 				CFails = 0;
 				BuildSignedMessage(pControl);
 				if (CFails == 0) fBuildDone = true;
+				FreeContext(context);
 			}
 #else
 			fValidateDone = true;
@@ -805,6 +834,7 @@
 				CFails = 0;
 				ValidateSign1(pControl);
 				if (CFails == 0) fValidateDone = true;
+				FreeContext(context);
 			}
 
 			if (!fBuildDone) {
@@ -812,6 +842,7 @@
 				CFails = 0;
 				BuildSign1Message(pControl);
 				if (CFails == 0) fBuildDone = true;
+				FreeContext(context);
 			}
 #else
 			fValidateDone = true;