Add ECDSA support for mbedtls (#53)
* Add ECDSA support for mbedtls
* Fix build with USE_CONTEXT=OFF
* Remove incorrect checks for CN_CBOR_INT
diff --git a/src/configure.h b/src/configure.h
index 309a53a..a92ae9c 100644
--- a/src/configure.h
+++ b/src/configure.h
@@ -128,11 +128,9 @@
// Define which of the signature algorithms are to be used
//
-#if !defined(USE_MBED_TLS)
#define USE_ECDSA_SHA_256
#define USE_ECDSA_SHA_384
#define USE_ECDSA_SHA_512
-#endif // !defined(USE_MBED_TLS)
diff --git a/src/mbedtls.c b/src/mbedtls.c
index 5108c6e..f4a6e0d 100644
--- a/src/mbedtls.c
+++ b/src/mbedtls.c
@@ -5,6 +5,7 @@
#include <assert.h>
#include <memory.h>
+#include <stdlib.h>
#ifdef USE_MBED_TLS
@@ -12,6 +13,7 @@
#include "mbedtls/md.h"
#include "mbedtls/ctr_drbg.h"
#include "mbedtls/entropy.h"
+#include "mbedtls/ecdsa.h"
bool FUseCompressed = true;
@@ -758,94 +760,89 @@
mbedtls_md_free(&contx);
return false;
}
-/*
#define COSE_Key_EC_Curve -1
#define COSE_Key_EC_X -2
#define COSE_Key_EC_Y -3
#define COSE_Key_EC_d -4
-EC_KEY * ECKey_From(const cn_cbor * pKey, int * cbGroup, cose_errback * perr)
+bool ECKey_From(const cn_cbor * pKey, mbedtls_ecp_keypair *keypair, cose_errback * perr)
{
- EC_KEY * pNewKey = EC_KEY_new();
- byte rgbKey[512+1];
+ byte rgbKey[MBEDTLS_ECP_MAX_PT_LEN];
int cbKey;
+ int cbGroup;
const cn_cbor * p;
- int nidGroup = -1;
- EC_POINT * pPoint = NULL;
+ mbedtls_ecp_group_id groupId;
+
+ p = cn_cbor_mapget_int(pKey, COSE_Key_Type);
+ CHECK_CONDITION(p != NULL, COSE_ERR_INVALID_PARAMETER);
+ if(p->type == CN_CBOR_UINT) {
+ CHECK_CONDITION(p->v.uint == COSE_Key_Type_EC2, COSE_ERR_INVALID_PARAMETER);
+ }
+ else {
+ FAIL_CONDITION(COSE_ERR_INVALID_PARAMETER);
+ }
p = cn_cbor_mapget_int(pKey, COSE_Key_EC_Curve);
- CHECK_CONDITION(p != NULL, COSE_ERR_INVALID_PARAMETER);
+ CHECK_CONDITION((p != NULL) && (p->type == CN_CBOR_UINT), COSE_ERR_INVALID_PARAMETER);
- switch (p->v.sint) {
+ switch (p->v.uint) {
case 1: // P-256
- nidGroup = NID_X9_62_prime256v1;
- *cbGroup = 256 / 8;
+ groupId = MBEDTLS_ECP_DP_SECP256R1;
break;
case 2: // P-384
- nidGroup = NID_secp384r1;
- *cbGroup = 384 / 8;
+ groupId = MBEDTLS_ECP_DP_SECP384R1;
break;
case 3: // P-521
- nidGroup = NID_secp521r1;
- *cbGroup = (521 + 7) / 8;
+ groupId = MBEDTLS_ECP_DP_SECP521R1;
break;
default:
FAIL_CONDITION(COSE_ERR_INVALID_PARAMETER);
}
-
- EC_GROUP * ecgroup = EC_GROUP_new_by_curve_name(nidGroup);
- CHECK_CONDITION(ecgroup != NULL, COSE_ERR_INVALID_PARAMETER);
- CHECK_CONDITION(EC_KEY_set_group(pNewKey, ecgroup) == 1, COSE_ERR_CRYPTO_FAIL);
+ CHECK_CONDITION(mbedtls_ecp_group_load(&keypair->grp, groupId) == 0, COSE_ERR_INVALID_PARAMETER);
+ cbGroup = (keypair->grp.nbits + 7) / 8;
p = cn_cbor_mapget_int(pKey, COSE_Key_EC_X);
CHECK_CONDITION((p != NULL) && (p->type == CN_CBOR_BYTES), COSE_ERR_INVALID_PARAMETER);
- CHECK_CONDITION(p->length == *cbGroup, COSE_ERR_INVALID_PARAMETER);
+ CHECK_CONDITION(p->length == cbGroup, COSE_ERR_INVALID_PARAMETER);
memcpy(rgbKey+1, p->v.str, p->length);
p = cn_cbor_mapget_int(pKey, COSE_Key_EC_Y);
CHECK_CONDITION((p != NULL), COSE_ERR_INVALID_PARAMETER);
if (p->type == CN_CBOR_BYTES) {
- rgbKey[0] = POINT_CONVERSION_UNCOMPRESSED;
- cbKey = (*cbGroup * 2) + 1;
- CHECK_CONDITION(p->length == *cbGroup, COSE_ERR_INVALID_PARAMETER);
+ rgbKey[0] = 0x04;
+ cbKey = cbGroup * 2 + 1;
+ CHECK_CONDITION(p->length == cbGroup, COSE_ERR_INVALID_PARAMETER);
memcpy(rgbKey + p->length + 1, p->v.str, p->length);
}
else if (p->type == CN_CBOR_TRUE) {
- cbKey = (*cbGroup) + 1;
- rgbKey[0] = POINT_CONVERSION_COMPRESSED + 1;
+ cbKey = cbGroup + 1;
+ rgbKey[0] = 0x03;
}
else if (p->type == CN_CBOR_FALSE) {
- cbKey = (*cbGroup) + 1;
- rgbKey[0] = POINT_CONVERSION_COMPRESSED;
+ cbKey = cbGroup + 1;
+ rgbKey[0] = 0x02;
}
else FAIL_CONDITION(COSE_ERR_INVALID_PARAMETER);
- pPoint = EC_POINT_new(ecgroup);
- CHECK_CONDITION(pPoint != NULL, COSE_ERR_CRYPTO_FAIL);
- CHECK_CONDITION(EC_POINT_oct2point(ecgroup, pPoint, rgbKey, cbKey, NULL) == 1, COSE_ERR_CRYPTO_FAIL);
- CHECK_CONDITION(EC_KEY_set_public_key(pNewKey, pPoint) == 1, COSE_ERR_CRYPTO_FAIL);
+ CHECK_CONDITION(mbedtls_ecp_point_read_binary(&keypair->grp, &keypair->Q, rgbKey, cbKey) == 0, COSE_ERR_INVALID_PARAMETER);
p = cn_cbor_mapget_int(pKey, COSE_Key_EC_d);
if (p != NULL) {
- BIGNUM * pbn;
-
- pbn = BN_bin2bn(p->v.bytes, (int) p->length, NULL);
- CHECK_CONDITION(pbn != NULL, COSE_ERR_CRYPTO_FAIL);
- CHECK_CONDITION(EC_KEY_set_private_key(pNewKey, pbn) == 1, COSE_ERR_CRYPTO_FAIL);
+ CHECK_CONDITION(p->type == CN_CBOR_BYTES, COSE_ERR_INVALID_PARAMETER);
+ CHECK_CONDITION(mbedtls_mpi_read_binary( &keypair->d, p->v.bytes, p->length) == 0, COSE_ERR_CRYPTO_FAIL);
}
-
- return pNewKey;
+ return true;
errorReturn:
- if (pNewKey != NULL) EC_KEY_free(pNewKey);
- return NULL;
+ return false;
}
+/*
cn_cbor * EC_FromKey(const EC_KEY * pKey, CBOR_CONTEXT_COMMA cose_errback * perr)
{
cn_cbor * pkey = NULL;
@@ -929,134 +926,141 @@
goto returnHere;
}
*/
-/*
-bool ECDSA_Sign(const cn_cbor * pKey)
-{
- byte * digest = NULL;
- int digestLen = 0;
- ECDSA_SIG * sig;
- EC_KEY * eckey = ECKey_From(pKey);
-
- sig = ECDSA_do_sign(digest, digestLen, eckey);
-
- return true;
-}
-*/
-/*
bool ECDSA_Sign(COSE * pSigner, int index, const cn_cbor * pKey, int cbitDigest, const byte * rgbToSign, size_t cbToSign, cose_errback * perr)
{
- EC_KEY * eckey = NULL;
- byte rgbDigest[EVP_MAX_MD_SIZE];
- unsigned int cbDigest = sizeof(rgbDigest);
- byte * pbSig = NULL;
- const EVP_MD * digest;
+#if defined(MBEDTLS_ECDSA_DETERMINISTIC)
+ byte rgbDigest[MBEDTLS_MD_MAX_SIZE];
+ uint8_t * pbSig = NULL;
+ cn_cbor_errback cbor_error;
+ int cbR;
+ mbedtls_md_type_t mdType;
+ const mbedtls_md_info_t *pmdInfo;
+ mbedtls_ecp_keypair keypair;
+ mbedtls_mpi r;
+ mbedtls_mpi s;
#ifdef USE_CBOR_CONTEXT
cn_cbor_context * context = &pSigner->m_allocContext;
#endif
cn_cbor * p = NULL;
- ECDSA_SIG * psig = NULL;
- cn_cbor_errback cbor_error;
- int cbR;
- byte rgbSig[66];
- int cb;
-
- eckey = ECKey_From(pKey, &cbR, perr);
- if (eckey == NULL) {
- errorReturn:
- if (pbSig != NULL) COSE_FREE(pbSig, context);
- if (p != NULL) CN_CBOR_FREE(p, context);
- if (eckey != NULL) EC_KEY_free(eckey);
- return false;
- }
+ bool result = false;
- switch (cbitDigest) {
- case 256: digest = EVP_sha256(); break;
- case 512: digest = EVP_sha512(); break;
- case 384: digest = EVP_sha384(); break;
+ mbedtls_ecp_keypair_init(&keypair);
+ mbedtls_mpi_init(&r);
+ mbedtls_mpi_init(&s);
+
+ if(!ECKey_From(pKey, &keypair, perr)) goto errorReturn;
+
+ CHECK_CONDITION(keypair.d.n != 0, COSE_ERR_INVALID_PARAMETER);
+
+ switch(cbitDigest)
+ {
+ case 256:
+ mdType = MBEDTLS_MD_SHA256;
+ break;
+
+ case 384:
+ mdType = MBEDTLS_MD_SHA384;
+ break;
+
+ case 512:
+ mdType = MBEDTLS_MD_SHA512;
+ break;
+
default:
FAIL_CONDITION(COSE_ERR_INVALID_PARAMETER);
}
+ pmdInfo = mbedtls_md_info_from_type(mdType);
+ CHECK_CONDITION(pmdInfo != NULL, COSE_ERR_INVALID_PARAMETER);
+ CHECK_CONDITION(mbedtls_md(pmdInfo, rgbToSign, cbToSign, rgbDigest) == 0, COSE_ERR_INVALID_PARAMETER);
- EVP_Digest(rgbToSign, cbToSign, rgbDigest, &cbDigest, digest, NULL);
+ CHECK_CONDITION(mbedtls_ecdsa_sign_det(&keypair.grp, &r, &s, &keypair.d, rgbDigest, mbedtls_md_get_size(pmdInfo), mdType) == 0, COSE_ERR_CRYPTO_FAIL);
- psig = ECDSA_do_sign(rgbDigest, cbDigest, eckey);
- CHECK_CONDITION(psig != NULL, COSE_ERR_CRYPTO_FAIL);
+ cbR = (keypair.grp.nbits + 7) / 8;
pbSig = COSE_CALLOC(cbR, 2, context);
CHECK_CONDITION(pbSig != NULL, COSE_ERR_OUT_OF_MEMORY);
- cb = BN_bn2bin(psig->r, rgbSig);
- CHECK_CONDITION(cb <= cbR, COSE_ERR_INVALID_PARAMETER);
- memcpy(pbSig + cbR - cb, rgbSig, cb);
-
- cb = BN_bn2bin(psig->s, rgbSig);
- CHECK_CONDITION(cb <= cbR, COSE_ERR_INVALID_PARAMETER);
- memcpy(pbSig + 2*cbR - cb, rgbSig, cb);
+ CHECK_CONDITION(mbedtls_mpi_write_binary(&r, pbSig, cbR) == 0, COSE_ERR_INTERNAL);
+ CHECK_CONDITION(mbedtls_mpi_write_binary(&s, pbSig + cbR, cbR) == 0, COSE_ERR_INTERNAL);
p = cn_cbor_data_create(pbSig, cbR*2, CBOR_CONTEXT_PARAM_COMMA &cbor_error);
CHECK_CONDITION_CBOR(p != NULL, cbor_error);
CHECK_CONDITION(_COSE_array_replace(pSigner, p, index, CBOR_CONTEXT_PARAM_COMMA NULL), COSE_ERR_CBOR);
-
+
+ p = NULL;
pbSig = NULL;
+ result = true;
- if (eckey != NULL) EC_KEY_free(eckey);
-
- return true;
+errorReturn:
+ cn_cbor_free(p CBOR_CONTEXT_PARAM);
+ COSE_FREE(pbSig, context);
+ mbedtls_mpi_free(&r);
+ mbedtls_mpi_free(&s);
+ mbedtls_ecp_keypair_free(&keypair);
+ return result;
+#else
+ return false;
+#endif
}
+
bool ECDSA_Verify(COSE * pSigner, int index, const cn_cbor * pKey, int cbitDigest, const byte * rgbToSign, size_t cbToSign, cose_errback * perr)
{
- EC_KEY * eckey = NULL;
- byte rgbDigest[EVP_MAX_MD_SIZE];
- unsigned int cbDigest = sizeof(rgbDigest);
- const EVP_MD * digest;
-#ifdef USE_CBOR_CONTEXT
- cn_cbor_context * context = &pSigner->m_allocContext;
-#endif
- cn_cbor * p = NULL;
- ECDSA_SIG sig = { NULL, NULL };
- int cbR;
+ mbedtls_ecp_keypair keypair;
+ mbedtls_mpi r;
+ mbedtls_mpi s;
+ mbedtls_md_type_t mdType;
+ const mbedtls_md_info_t *pmdInfo;
+ byte rgbDigest[MBEDTLS_MD_MAX_SIZE];
cn_cbor * pSig;
- size_t cbSignature;
+ bool result = false;
- eckey = ECKey_From(pKey, &cbR, perr);
- if (eckey == NULL) {
- errorReturn:
- if (sig.r != NULL) BN_free(sig.r);
- if (sig.s != NULL) BN_free(sig.s);
- if (p != NULL) CN_CBOR_FREE(p, context);
- if (eckey != NULL) EC_KEY_free(eckey);
- return false;
- }
+ mbedtls_ecp_keypair_init(&keypair);
+ mbedtls_mpi_init(&r);
+ mbedtls_mpi_init(&s);
- switch (cbitDigest) {
- case 256: digest = EVP_sha256(); break;
- case 512: digest = EVP_sha512(); break;
- case 384: digest = EVP_sha384(); break;
+ if(!ECKey_From(pKey, &keypair, perr)) goto errorReturn;
+
+ switch(cbitDigest)
+ {
+ case 256:
+ mdType = MBEDTLS_MD_SHA256;
+ break;
+
+ case 384:
+ mdType = MBEDTLS_MD_SHA384;
+ break;
+
+ case 512:
+ mdType = MBEDTLS_MD_SHA512;
+ break;
+
default:
FAIL_CONDITION(COSE_ERR_INVALID_PARAMETER);
}
- EVP_Digest(rgbToSign, cbToSign, rgbDigest, &cbDigest, digest, NULL);
+ pmdInfo = mbedtls_md_info_from_type(mdType);
+ CHECK_CONDITION(pmdInfo != NULL, COSE_ERR_INVALID_PARAMETER);
+ CHECK_CONDITION(mbedtls_md(pmdInfo, rgbToSign, cbToSign, rgbDigest) == 0, COSE_ERR_INVALID_PARAMETER);
pSig = _COSE_arrayget_int(pSigner, index);
- CHECK_CONDITION(pSig != NULL, COSE_ERR_INVALID_PARAMETER);
- cbSignature = pSig->length;
+ CHECK_CONDITION((pSig != NULL) && (pSig->type == CN_CBOR_BYTES), COSE_ERR_INVALID_PARAMETER);
- CHECK_CONDITION(cbSignature / 2 == cbR, COSE_ERR_INVALID_PARAMETER);
- sig.r = BN_bin2bn(pSig->v.bytes,(int) cbSignature/2, NULL);
- sig.s = BN_bin2bn(pSig->v.bytes+cbSignature/2, (int) cbSignature/2, NULL);
+ CHECK_CONDITION(mbedtls_mpi_read_binary( &r, pSig->v.bytes, pSig->length / 2 ) == 0, COSE_ERR_OUT_OF_MEMORY);
+ CHECK_CONDITION(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, COSE_ERR_CRYPTO_FAIL);
- CHECK_CONDITION(ECDSA_do_verify(rgbDigest, cbDigest, &sig, eckey) == 1, COSE_ERR_CRYPTO_FAIL);
+ result = true;
- BN_free(sig.r);
- BN_free(sig.s);
- if (eckey != NULL) EC_KEY_free(eckey);
-
- return true;
+errorReturn:
+ mbedtls_mpi_free(&r);
+ mbedtls_mpi_free(&s);
+ mbedtls_ecp_keypair_free(&keypair);
+ return result;
}
+/*
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];