Native key (#120)

* Forgot to do the formatting.

* Native keys can now be used for ECDSA

No other algoirthms are currently supported and I don't know what the behavior would be.  Probably crash as that is what ECDH did on me. (I think.)

* Fix the error from the unuseful error message

* Is that the compile error - bad version of openssl

* If def with the Openssl version #

* Short cut native keys if openssl version not high enough.

* Is this compiling?

* Correct version number check for openssl

* Get the version checking right
diff --git a/include/cose/cose.h b/include/cose/cose.h
index 647b1b7..0cc424c 100644
--- a/include/cose/cose.h
+++ b/include/cose/cose.h
@@ -2,10 +2,14 @@
 
 #include <stdbool.h>
 #include <cn-cbor/cn-cbor.h>
+
 #include "cose/cose_configure.h"
 #ifdef COSE_C_USE_OPENSSL
 #include <openssl/evp.h>
 #endif
+#ifdef COSE_C_USE_MBEDTLS
+#include <mbedtls/ecp.h>
+#endif
 
 #ifdef __cplusplus
 extern "C" {
@@ -218,6 +222,10 @@
  * Functions dealing with keys
  */
 
+const int COSE_KEY_FL_OWN = 0x1;	// Cede ownership of the key to the libraray
+									// Only neede for MBEDTLS as OpenSSL does reference counts
+	
+
 HCOSE_KEY COSE_KEY_FromCbor(cn_cbor* pcborKey,
 	CBOR_CONTEXT_COMMA cose_errback* perror);
 bool COSE_KEY_Free(HCOSE_KEY h);
@@ -226,6 +234,12 @@
 	cn_cbor* pcborKey,
 	CBOR_CONTEXT_COMMA cose_errback* perror);
 #endif
+#ifdef COSE_C_USE_MBEDTLS
+HCOSE_KEY COSE_KEY_FromMbedKeypair(mbedtls_ecp_keypair *,
+	cn_cbor *  pcborKey,
+	int flags,
+	CBOR_CONTEXT_COMMA cose_errback* perror);
+#endif
 
 /*
  *  messages dealing with the Enveloped message type
diff --git a/src/CoseKey.cpp b/src/CoseKey.cpp
index 717af12..236c05e 100644
--- a/src/CoseKey.cpp
+++ b/src/CoseKey.cpp
@@ -136,3 +136,37 @@
 	return (HCOSE_KEY)pkey;
 }
 #endif
+
+#ifdef COSE_C_USE_MBEDTLS
+HCOSE_KEY COSE_KEY_FromMbedKeypair(mbedtls_ecp_keypair * mbedtls_keypair,
+	cn_cbor *pcborKey,
+	int flags,
+	CBOR_CONTEXT_COMMA cose_errback *perror)
+{
+	COSE_KEY *pkey = nullptr;
+
+	pkey = (COSE_KEY *)COSE_CALLOC(1, sizeof(COSE_KEY), context);
+
+	if (pkey == nullptr) {
+		perror->err = COSE_ERR_OUT_OF_MEMORY;
+		return nullptr;
+	}
+
+#ifdef USE_CBOR_CONTEXT
+	if (context != nullptr) {
+		pkey->m_allocContext = *context;
+	}
+#endif
+
+	pkey->m_refCount = 1;
+	pkey->m_cborKey = pcborKey;
+	pkey->m_mbedtls_keypair = mbedtls_keypair;
+	pkey->m_flags = flags;
+
+	pkey->m_nextKey = KeysRoot;
+	KeysRoot = pkey;
+
+	return (HCOSE_KEY)pkey;
+}
+
+#endif
diff --git a/src/cose_int.h b/src/cose_int.h
index 5209cc9..88d9907 100644
--- a/src/cose_int.h
+++ b/src/cose_int.h
@@ -6,6 +6,10 @@
 #include <stdbool.h>
 #ifdef COSE_C_USE_OPENSSL
 #include <openssl/evp.h>
+#include <openssl/ec.h>
+#endif
+#ifdef COSE_C_USE_MBEDTLS
+#include <mbedtls/ecp.h>
 #endif
 
 // These definitions are here because they aren't required for the public
@@ -26,7 +30,7 @@
 typedef struct _COSE_KEY {
 	int m_refCount;
 	cn_cbor *m_cborKey;
-	int flags;
+	int m_flags;
 	struct _COSE_KEY *m_nextKey;
 #ifdef USE_CBOR_CONTEXT
 	cn_cbor_context m_allocContext;
@@ -34,6 +38,9 @@
 #ifdef COSE_C_USE_OPENSSL
 	EVP_PKEY *m_opensslKey;
 #endif
+#ifdef COSE_C_USE_MBEDTLS
+	mbedtls_ecp_keypair * m_mbedtls_keypair;
+#endif
 } COSE_KEY;
 
 typedef struct _COSE {
@@ -468,3 +475,14 @@
 
 #define COSE_CounterSign_object 1000
 #define COSE_CounterSign1_object 1001
+
+
+#if defined(COSE_C_USE_OPENSSL) && (OPENSSL_VERSION_NUMBER > 0x10100000L)
+EC_KEY *ECKey_From(COSE_KEY *pKey, int *cbGroup, cose_errback *perr);
+#endif
+
+#ifdef COSE_C_USE_MBEDTLS
+mbedtls_ecp_keypair * ECKey_From(COSE_KEY *pKey,
+	mbedtls_ecp_keypair *keypair,
+	cose_errback *perr);
+#endif
diff --git a/src/mbedtls.cpp b/src/mbedtls.cpp
index 4294e86..5626192 100644
--- a/src/mbedtls.cpp
+++ b/src/mbedtls.cpp
@@ -666,10 +666,14 @@
 #define COSE_Key_EC_Y -3
 #define COSE_Key_EC_d -4
 
-bool ECKey_From(COSE_KEY *pKey,
+mbedtls_ecp_keypair * ECKey_From(COSE_KEY *pKey,
 	mbedtls_ecp_keypair *keypair,
 	cose_errback *perr)
 {
+	if (pKey->m_mbedtls_keypair != nullptr) {
+		return pKey->m_mbedtls_keypair;
+	}
+	
 	byte rgbKey[MBEDTLS_ECP_MAX_PT_LEN];
 	int cbKey = 0;
 	int cbGroup = 0;
@@ -755,10 +759,10 @@
 			mbedtls_mpi_read_binary(&keypair->d, p->v.bytes, p->length) == 0,
 			COSE_ERR_CRYPTO_FAIL);
 	}
-	return true;
+	return keypair;
 
 errorReturn:
-	return false;
+	return nullptr;
 }
 
 bool ECDSA_Sign(COSE *pSigner,
@@ -777,6 +781,7 @@
 	mbedtls_md_type_t mdType;
 	const mbedtls_md_info_t *pmdInfo;
 	mbedtls_ecp_keypair keypair;
+	mbedtls_ecp_keypair *useKey = nullptr;
 	mbedtls_mpi r;
 	mbedtls_mpi s;
 #ifdef USE_CBOR_CONTEXT
@@ -789,11 +794,12 @@
 	mbedtls_mpi_init(&r);
 	mbedtls_mpi_init(&s);
 
-	if (!ECKey_From(pKey, &keypair, perr)) {
+	useKey = ECKey_From(pKey, &keypair, perr);
+	if (useKey == nullptr) {
 		goto errorReturn;
 	}
 
-	CHECK_CONDITION(keypair.d.n != 0, COSE_ERR_INVALID_PARAMETER);
+	CHECK_CONDITION(useKey->d.n != 0, COSE_ERR_INVALID_PARAMETER);
 
 	switch (cbitDigest) {
 		case 256:
@@ -816,11 +822,11 @@
 	CHECK_CONDITION(mbedtls_md(pmdInfo, rgbToSign, cbToSign, rgbDigest) == 0,
 		COSE_ERR_INVALID_PARAMETER);
 
-	CHECK_CONDITION(mbedtls_ecdsa_sign_det(&keypair.grp, &r, &s, &keypair.d,
+	CHECK_CONDITION(mbedtls_ecdsa_sign_det(&useKey->grp, &r, &s, &useKey->d,
 						rgbDigest, mbedtls_md_get_size(pmdInfo), mdType) == 0,
 		COSE_ERR_CRYPTO_FAIL);
 
-	cbR = (keypair.grp.nbits + 7) / 8;
+	cbR = (useKey->grp.nbits + 7) / 8;
 
 	pbSig = (byte *)COSE_CALLOC(cbR, 2, context);
 	CHECK_CONDITION(pbSig != nullptr, COSE_ERR_OUT_OF_MEMORY);
@@ -863,6 +869,7 @@
 	cose_errback *perr)
 {
 	mbedtls_ecp_keypair keypair;
+	mbedtls_ecp_keypair* useKey = nullptr;
 	mbedtls_mpi r;
 	mbedtls_mpi s;
 	mbedtls_md_type_t mdType;
@@ -875,7 +882,8 @@
 	mbedtls_mpi_init(&r);
 	mbedtls_mpi_init(&s);
 
-	if (!ECKey_From(pKey, &keypair, perr)) {
+	useKey = ECKey_From(pKey, &keypair, perr);
+	if (useKey == nullptr) {
 		goto errorReturn;
 	}
 
@@ -911,8 +919,8 @@
 		mbedtls_mpi_read_binary(
 			&s, pSig->v.bytes + pSig->length / 2, pSig->length / 2) == 0,
 		COSE_ERR_OUT_OF_MEMORY);
-	CHECK_CONDITION(mbedtls_ecdsa_verify(&keypair.grp, rgbDigest,
-						mbedtls_md_get_size(pmdInfo), &keypair.Q, &r, &s) == 0,
+	CHECK_CONDITION(mbedtls_ecdsa_verify(&useKey->grp, rgbDigest,
+						mbedtls_md_get_size(pmdInfo), &useKey->Q, &r, &s) == 0,
 		COSE_ERR_CRYPTO_FAIL);
 
 	result = true;
diff --git a/src/openssl.cpp b/src/openssl.cpp
index b9e54e0..f376fb4 100644
--- a/src/openssl.cpp
+++ b/src/openssl.cpp
@@ -1084,6 +1084,7 @@
 #define COSE_Key_EC_Y -3
 #define COSE_Key_EC_d -4
 
+
 EC_KEY *ECKey_From(COSE_KEY *pKey, int *cbGroup, cose_errback *perr)
 {
 	EC_KEY *pNewKey = nullptr;
@@ -1099,6 +1100,24 @@
 	if (pKey->m_opensslKey != nullptr) {
 		EC_KEY *pKeyNew = EVP_PKEY_get1_EC_KEY(pKey->m_opensslKey);
 		CHECK_CONDITION(pKeyNew != nullptr, COSE_ERR_INVALID_PARAMETER);
+		int gid = EC_GROUP_get_curve_name(EC_KEY_get0_group(pKeyNew));
+		switch (gid) {
+			case NID_X9_62_prime256v1:
+				*cbGroup = 256 / 8;
+				break;
+
+			case NID_secp384r1:
+				*cbGroup = 384 / 8;
+				break;
+
+			case NID_secp521r1:
+				*cbGroup = (521 + 7) / 8;
+				break;
+
+			default:
+				FAIL_CONDITION(COSE_ERR_INVALID_PARAMETER);
+		}			
+
 		return pKeyNew;
 	}
 
diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt
index aded8c8..85b893b 100644
--- a/test/CMakeLists.txt
+++ b/test/CMakeLists.txt
@@ -66,6 +66,10 @@
   WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}
   COMMAND cose_test --dir Examples/ecdsa-examples)
 add_test(
+  NAME ecdsa-native
+  WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}
+  COMMAND cose_test --dir Examples/ecdsa-examples --keyFormat=native)
+add_test(
   NAME eddsa
   WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}
   COMMAND cose_test --dir Examples/eddsa-examples)
diff --git a/test/test.cpp b/test/test.cpp
index 9998be6..f515018 100644
--- a/test/test.cpp
+++ b/test/test.cpp
@@ -21,7 +21,14 @@
 #include "json.h"
 #include "test.h"
 
+
+#ifdef COSE_C_USE_OPENSSL
+#include <openssl/ec.h>
+#endif
+
 #ifdef COSE_C_USE_MBEDTLS
+#include <mbedtls/ecp.h>
+#include "mbedtls/ecdsa.h"
 #include "mbedtls/entropy.h"
 #endif
 
@@ -30,6 +37,7 @@
 #endif
 
 int CFails = 0;
+int KeyFormat = 1;
 
 typedef struct _NameMap {
 	const char* sz;
@@ -849,18 +857,119 @@
 
 HCOSE_KEY BuildKey(const cn_cbor* pKeyIn, bool fPublicKey)
 {
+	cose_errback coseError;
 	cn_cbor* pKeyOut = BuildCborKey(pKeyIn, fPublicKey);
 	if (pKeyOut == nullptr) {
 		return nullptr;
 	}
 
-	cose_errback coseError;
-	HCOSE_KEY key =
+	Safe_HCOSE_KEY key =
 		COSE_KEY_FromCbor(pKeyOut, CBOR_CONTEXT_PARAM_COMMA & coseError);
 	if (key == nullptr) {
 		CN_CBOR_FREE(pKeyOut, context);
 	}
-	return key;
+	if (KeyFormat == 1) {
+		return key.Release();
+	}
+
+	cn_cbor* keyType = cn_cbor_mapget_int(pKeyOut, COSE_Key_Type);
+	if (keyType == nullptr) {
+		return nullptr;
+	}
+
+#ifdef COSE_C_USE_OPENSSL
+	EVP_PKEY* opensslKey = EVP_PKEY_new();
+#endif
+#ifdef COSE_C_USE_MBEDTLS
+	mbedtls_ecp_keypair* keypair = nullptr;
+#endif
+
+	switch (keyType->v.uint) {
+		case COSE_Key_Type_EC2:
+#if defined(COSE_C_USE_OPENSSL) && (OPENSSL_VERSION_NUMBER > 0x10100000L)
+		{
+			int cbR = 0;
+			EC_KEY* ecKey =
+				ECKey_From((COSE_KEY*)(HCOSE_KEY)key, &cbR, &coseError);
+			if (ecKey == nullptr) {
+				return nullptr;
+			}
+
+			if (EVP_PKEY_set1_EC_KEY(opensslKey, ecKey) == 0) {
+				EC_KEY_free(ecKey);
+				return nullptr;
+			}
+			EC_KEY_free(ecKey);
+		}
+#endif
+#ifdef COSE_C_USE_MBEDTLS
+			{
+				keypair =
+					static_cast<mbedtls_ecp_keypair*>(COSE_CALLOC(sizeof(*keypair), 1, context)
+					);
+				if (keypair == nullptr) {
+					return nullptr;
+				}
+				mbedtls_ecp_keypair_init(keypair);
+				if (!ECKey_From((COSE_KEY *) (HCOSE_KEY) key, keypair, &coseError)) {
+					mbedtls_ecp_keypair_free(keypair);
+					COSE_FREE(keypair, context);
+					return nullptr;
+				}
+			}
+#endif
+			break;
+
+		case COSE_Key_Type_OKP:
+#ifdef COSE_C_USE_OPENSSL
+
+#endif
+			break;
+
+		default:
+			break;
+	}
+
+#if defined(COSE_C_USE_OPENSSL) && (OPENSSL_VERSION_NUMBER > 0x10100000L)
+
+	if (opensslKey == nullptr) {
+		return key.Release();
+	}
+	else {
+		HCOSE_KEY key2 =
+			COSE_KEY_FromEVP(opensslKey, KeyFormat == 2 ? nullptr : pKeyOut,
+				CBOR_CONTEXT_PARAM_COMMA & coseError);
+		if (key2 == nullptr) {
+			EVP_PKEY_free(opensslKey);
+		}
+		else if (KeyFormat == 3) {
+			// M00BUG - figure out how to get it back.  Might be a dup
+			// CN_CBOR_FREE(pKeyOut, context);
+		}
+		return key2;
+	}
+#endif
+#ifdef COSE_C_USE_MBEDTLS
+	if (keypair == nullptr) {
+		return key.Release();
+	}
+	else {
+		HCOSE_KEY k2 = COSE_KEY_FromMbedKeypair(keypair,
+			KeyFormat == 2 ? nullptr : pKeyOut, COSE_KEY_FL_OWN,
+			CBOR_CONTEXT_PARAM_COMMA & coseError);
+		if (k2 == nullptr) {
+			mbedtls_ecp_keypair_free(keypair);
+			COSE_FREE(keypair, context);
+		}
+		else if (KeyFormat == 3) {
+			//  see note above
+			// CN_CBOR_FREE(pKeyOut, context);
+		}
+		return k2;
+	}
+#endif
+
+	return nullptr;
 }
 
 bool Test_cn_cbor_array_replace()
@@ -1418,6 +1527,7 @@
 }
 #endif	// _MSCVER
 
+
 int main(int argc, char** argv)
 {
 	int i;
@@ -1438,6 +1548,21 @@
 			else if (strcmp(argv[i], "--memory") == 0) {
 				fMemory = true;
 			}
+			else if (strcmp(argv[i], "--keyFormat=native") == 0) {
+				KeyFormat = 2;
+#if defined(COSE_C_USE_OPENSSL) && (OPENSSL_VERSION_NUMBER < 0x10100000L)
+#pragma message("OPENSSL VERSION does not support native key ")
+
+				fprintf(stderr,
+					"Native key formats not supported for OpenSSL version "
+					"{%x}\n",
+					OPENSSL_VERSION_NUMBER);
+				exit(0);
+#endif
+			}
+			else if (strcmp(argv[i], "--keyFormat=both") == 0) {
+				KeyFormat = 3;
+			}
 		}
 		else {
 			szWhere = argv[i];
diff --git a/test/test.h b/test/test.h
index a9a4203..36808eb 100644
--- a/test/test.h
+++ b/test/test.h
@@ -148,7 +148,6 @@
 		handleName Release()                           \
 		{                                              \
 			handleName h2 = h;                         \
-			freeFunction(h);                           \
 			h = NULL;                                  \
 			return h2;                                 \
 		}                                              \