blob: d1f7fb9360d5be009075c397ac6a503ba518b10b [file] [log] [blame]
#include "cose/cose.h"
#include "cose/cose_configure.h"
#include "cose_int.h"
#include "cose_crypto.h"
#include <assert.h>
#ifndef __MBED__
#include <memory.h>
#endif
#include <stdlib.h>
#ifdef COSE_C_USE_MBEDTLS
#include "mbedtls/ccm.h"
#include "mbedtls/md.h"
#include "mbedtls/ctr_drbg.h"
#include "mbedtls/entropy.h"
#include "mbedtls/ecdsa.h"
#include "mbedtls/gcm.h"
#include "mbedtls/ecp.h"
#include "mbedtls/ecdh.h"
#include "mbedtls/nist_kw.h"
#include "mbedtls/hkdf.h"
static bool FUseCompressed = true;
#define MIN(A, B) ((A) < (B) ? (A) : (B))
#ifdef INCLUDE_AES_CCM
bool AES_CCM_Decrypt(COSE_Enveloped *pcose,
int TSize,
int LSize,
const byte *pbKey,
size_t cbKey,
const byte *pbCrypto,
size_t cbCrypto,
const byte *pbAuthData,
size_t cbAuthData,
cose_errback *perr)
{
mbedtls_ccm_context ctx;
int cbOut;
byte *rgbOut = NULL;
int NSize = 15 - (LSize / 8);
byte rgbIV[15] = {0};
const cn_cbor *pIV = NULL;
mbedtls_cipher_id_t cipher;
#ifdef USE_CBOR_CONTEXT
cn_cbor_context *context = &pcose->m_message.m_allocContext;
#endif
mbedtls_ccm_init(&ctx);
// Setup the IV/Nonce and put it into the message
pIV = _COSE_map_get_int(&pcose->m_message, COSE_Header_IV, COSE_BOTH, NULL);
if ((pIV == NULL) || (pIV->type != CN_CBOR_BYTES)) {
if (perr != NULL) {
perr->err = COSE_ERR_INVALID_PARAMETER;
}
errorReturn:
if (rgbOut != NULL) {
COSE_FREE(rgbOut, context);
}
mbedtls_ccm_free(&ctx);
return false;
}
CHECK_CONDITION(pIV->length == NSize, COSE_ERR_INVALID_PARAMETER);
memcpy(rgbIV, pIV->v.str, pIV->length);
// Setup and run the mbedTLS code
cipher = MBEDTLS_CIPHER_ID_AES;
CHECK_CONDITION(!mbedtls_ccm_setkey(&ctx, cipher, pbKey, cbKey * 8),
COSE_ERR_CRYPTO_FAIL);
TSize /= 8; // Comes in in bits not bytes.
cbOut = (int)cbCrypto - TSize;
rgbOut = (byte *)COSE_CALLOC(cbOut, 1, context);
CHECK_CONDITION(rgbOut != NULL, COSE_ERR_OUT_OF_MEMORY);
CHECK_CONDITION(
!mbedtls_ccm_auth_decrypt(&ctx, cbOut, rgbIV, NSize, pbAuthData,
cbAuthData, pbCrypto, rgbOut, &pbCrypto[cbOut], TSize),
COSE_ERR_CRYPTO_FAIL);
mbedtls_ccm_free(&ctx);
pcose->pbContent = rgbOut;
pcose->cbContent = cbOut;
return true;
}
bool AES_CCM_Encrypt(COSE_Enveloped *pcose,
int TSize,
int LSize,
const byte *pbKey,
size_t cbKey,
const byte *pbAuthData,
size_t cbAuthData,
cose_errback *perr)
{
mbedtls_ccm_context ctx;
int cbOut;
byte *rgbOut = NULL;
int NSize = 15 - (LSize / 8);
const cn_cbor *cbor_iv = NULL;
cn_cbor *cbor_iv_t = NULL;
#ifdef USE_CBOR_CONTEXT
cn_cbor_context *context = &pcose->m_message.m_allocContext;
#endif
cn_cbor *cnTmp = NULL;
mbedtls_cipher_id_t cipher;
byte rgbIV[16];
byte *pbIV = NULL;
cn_cbor_errback cbor_error;
mbedtls_ccm_init(&ctx);
cipher = MBEDTLS_CIPHER_ID_AES;
// Setup the IV/Nonce and put it into the message
cbor_iv =
_COSE_map_get_int(&pcose->m_message, COSE_Header_IV, COSE_BOTH, perr);
if (cbor_iv == NULL) {
pbIV = COSE_CALLOC(NSize, 1, context);
CHECK_CONDITION(pbIV != NULL, COSE_ERR_OUT_OF_MEMORY);
rand_bytes(pbIV, NSize);
memcpy(rgbIV, pbIV, NSize);
cbor_iv_t = cn_cbor_data_create(
pbIV, NSize, CBOR_CONTEXT_PARAM_COMMA & cbor_error);
CHECK_CONDITION_CBOR(cbor_iv_t != NULL, cbor_error);
pbIV = NULL;
if (!_COSE_map_put(&pcose->m_message, COSE_Header_IV, cbor_iv_t,
COSE_UNPROTECT_ONLY, perr)) {
goto errorReturn;
}
cbor_iv_t = NULL;
}
else {
CHECK_CONDITION(
cbor_iv->type == CN_CBOR_BYTES, COSE_ERR_INVALID_PARAMETER);
CHECK_CONDITION(cbor_iv->length == NSize, COSE_ERR_INVALID_PARAMETER);
memcpy(rgbIV, cbor_iv->v.str, cbor_iv->length);
}
// Setup and run the mbedTLS code
// cbKey comes in bytes not bits
CHECK_CONDITION(!mbedtls_ccm_setkey(&ctx, cipher, pbKey, cbKey * 8),
COSE_ERR_CRYPTO_FAIL);
TSize /= 8; // Comes in in bits not bytes.
cbOut = pcose->cbContent; // M00BUG - This is a missing call?
rgbOut = (byte *)COSE_CALLOC(cbOut + TSize, 1, context);
CHECK_CONDITION(rgbOut != NULL, COSE_ERR_OUT_OF_MEMORY);
CHECK_CONDITION(!mbedtls_ccm_encrypt_and_tag(&ctx, pcose->cbContent, rgbIV,
NSize, pbAuthData, cbAuthData, pcose->pbContent, rgbOut,
&rgbOut[pcose->cbContent], TSize),
COSE_ERR_CRYPTO_FAIL);
cnTmp = cn_cbor_data_create(
rgbOut, (int)pcose->cbContent + TSize, CBOR_CONTEXT_PARAM_COMMA NULL);
CHECK_CONDITION(cnTmp != NULL, COSE_ERR_CBOR);
rgbOut = NULL;
CHECK_CONDITION(_COSE_array_replace(&pcose->m_message, cnTmp, INDEX_BODY,
CBOR_CONTEXT_PARAM_COMMA NULL),
COSE_ERR_CBOR);
cnTmp = NULL;
mbedtls_ccm_free(&ctx);
return true;
errorReturn:
if (pbIV != NULL) {
COSE_FREE(pbIV, context);
}
if (cbor_iv_t != NULL) {
COSE_FREE(cbor_iv_t, context);
}
if (rgbOut != NULL) {
COSE_FREE(rgbOut, context);
}
if (cnTmp != NULL) {
COSE_FREE(cnTmp, context);
}
mbedtls_ccm_free(&ctx);
return false;
}
#endif
#ifdef USE_AES_GCM
bool AES_GCM_Decrypt(COSE_Enveloped *pcose,
const byte *pbKey,
size_t cbKey,
const byte *pbCrypto,
size_t cbCrypto,
const byte *pbAuthData,
size_t cbAuthData,
cose_errback *perr)
{
mbedtls_gcm_context ctx;
int cbOut;
byte *rgbOut = NULL;
byte rgbIV[15] = {0};
const cn_cbor *pIV = NULL;
#ifdef USE_CBOR_CONTEXT
cn_cbor_context *context = &pcose->m_message.m_allocContext;
#endif
int TSize = 128 / 8;
// Make it first so we can clean it up
mbedtls_gcm_init(&ctx);
// Setup the IV/Nonce and put it into the message
pIV = _COSE_map_get_int(&pcose->m_message, COSE_Header_IV, COSE_BOTH, NULL);
if ((pIV == NULL) || (pIV->type != CN_CBOR_BYTES)) {
if (perr != NULL) {
perr->err = COSE_ERR_INVALID_PARAMETER;
}
errorReturn:
if (rgbOut != NULL) {
COSE_FREE(rgbOut, context);
}
mbedtls_gcm_free(&ctx);
return false;
}
CHECK_CONDITION(pIV->length == 96 / 8, COSE_ERR_INVALID_PARAMETER);
memcpy(rgbIV, pIV->v.str, pIV->length);
// Setup and run the OpenSSL code
switch (cbKey) {
case 128 / 8:
case 192 / 8:
case 256 / 8:
break;
default:
FAIL_CONDITION(COSE_ERR_INVALID_PARAMETER);
break;
}
// Do the setup for OpenSSL
CHECK_CONDITION0(
mbedtls_gcm_setkey(&ctx, MBEDTLS_CIPHER_ID_AES, pbKey, cbKey * 8),
COSE_ERR_CRYPTO_FAIL);
//
cbOut = (int)cbCrypto - TSize;
rgbOut = (byte *)COSE_CALLOC(cbOut, 1, context);
CHECK_CONDITION(rgbOut != NULL, COSE_ERR_OUT_OF_MEMORY);
// Process content
byte tag[128 / 8];
CHECK_CONDITION0(
mbedtls_gcm_crypt_and_tag(&ctx, MBEDTLS_GCM_DECRYPT, cbOut, rgbIV,
96 / 8, pbAuthData, cbAuthData, pbCrypto, rgbOut, TSize, tag),
COSE_ERR_CRYPTO_FAIL);
// CHECK TAG HERE
bool f = false;
const byte *pb = pbCrypto + cbOut;
for (int i = 0; i < (unsigned int)TSize; i++) {
f |= (pb[i] != tag[i]);
}
CHECK_CONDITION(!f, COSE_ERR_CRYPTO_FAIL);
mbedtls_gcm_free(&ctx);
pcose->pbContent = rgbOut;
pcose->cbContent = cbOut;
return true;
}
bool AES_GCM_Encrypt(COSE_Enveloped *pcose,
const byte *pbKey,
size_t cbKey,
const byte *pbAuthData,
size_t cbAuthData,
cose_errback *perr)
{
mbedtls_gcm_context ctx;
byte *rgbOut = NULL;
byte rgbIV[16] = {0};
byte *pbIV = NULL;
const cn_cbor *cbor_iv = NULL;
cn_cbor *cbor_iv_t = NULL;
#ifdef USE_CBOR_CONTEXT
cn_cbor_context *context = &pcose->m_message.m_allocContext;
#endif
cn_cbor_errback cbor_error;
// Make it first so we can clean it up
mbedtls_gcm_init(&ctx);
// Setup the IV/Nonce and put it into the message
cbor_iv =
_COSE_map_get_int(&pcose->m_message, COSE_Header_IV, COSE_BOTH, perr);
if (cbor_iv == NULL) {
pbIV = COSE_CALLOC(96, 1, context);
CHECK_CONDITION(pbIV != NULL, COSE_ERR_OUT_OF_MEMORY);
rand_bytes(pbIV, 96 / 8);
memcpy(rgbIV, pbIV, 96 / 8);
cbor_iv_t = cn_cbor_data_create(
pbIV, 96 / 8, CBOR_CONTEXT_PARAM_COMMA & cbor_error);
CHECK_CONDITION_CBOR(cbor_iv_t != NULL, cbor_error);
pbIV = NULL;
if (!_COSE_map_put(&pcose->m_message, COSE_Header_IV, cbor_iv_t,
COSE_UNPROTECT_ONLY, perr)) {
goto errorReturn;
}
cbor_iv_t = NULL;
}
else {
CHECK_CONDITION(
cbor_iv->type == CN_CBOR_BYTES, COSE_ERR_INVALID_PARAMETER);
CHECK_CONDITION(cbor_iv->length == 96 / 8, COSE_ERR_INVALID_PARAMETER);
memcpy(rgbIV, cbor_iv->v.str, cbor_iv->length);
}
switch (cbKey * 8) {
case 128:
case 192:
case 256:
break;
default:
FAIL_CONDITION(COSE_ERR_INVALID_PARAMETER);
break;
}
// Setup and run the OpenSSL code
CHECK_CONDITION0(
mbedtls_gcm_setkey(&ctx, MBEDTLS_CIPHER_ID_AES, pbKey, cbKey * 8),
COSE_ERR_CRYPTO_FAIL);
CHECK_CONDITION0(mbedtls_gcm_starts(&ctx, MBEDTLS_GCM_ENCRYPT, rgbIV,
96 / 8, pbAuthData, cbAuthData),
COSE_ERR_CRYPTO_FAIL);
rgbOut = (byte *)COSE_CALLOC(pcose->cbContent + 128 / 8, 1, context);
CHECK_CONDITION(rgbOut != NULL, COSE_ERR_OUT_OF_MEMORY);
CHECK_CONDITION0(
mbedtls_gcm_update(&ctx, pcose->cbContent, pcose->pbContent, rgbOut),
COSE_ERR_CRYPTO_FAIL);
CHECK_CONDITION0(
mbedtls_gcm_finish(&ctx, &rgbOut[pcose->cbContent], 128 / 8),
COSE_ERR_CRYPTO_FAIL);
cn_cbor *cnTmp = cn_cbor_data_create(
rgbOut, (int)pcose->cbContent + 128 / 8, CBOR_CONTEXT_PARAM_COMMA NULL);
CHECK_CONDITION(cnTmp != NULL, COSE_ERR_CBOR);
rgbOut = NULL;
CHECK_CONDITION(_COSE_array_replace(&pcose->m_message, cnTmp, INDEX_BODY,
CBOR_CONTEXT_PARAM_COMMA NULL),
COSE_ERR_CBOR);
mbedtls_gcm_free(&ctx);
return true;
errorReturn:
if (pbIV != NULL) {
COSE_FREE(pbIV, context);
}
if (cbor_iv_t != NULL) {
COSE_FREE(cbor_iv_t, context);
}
if (rgbOut != NULL) {
COSE_FREE(rgbOut, context);
}
mbedtls_gcm_free(&ctx);
return false;
}
#endif
#if defined(USE_HKDF_SHA2)
bool HKDF_Extract(COSE *pcose,
const byte *pbKey,
size_t cbKey,
size_t cbitDigest,
byte *rgbDigest,
size_t *pcbDigest,
CBOR_CONTEXT_COMMA cose_errback *perr)
{
mbedtls_md_info_t *pmd;
mbedtls_md_type_t mdType;
int cbSalt;
cn_cbor *cnSalt;
unsigned int cbDigest;
if (0) {
errorReturn:
return false;
}
switch (cbitDigest) {
case 256:
mdType = MBEDTLS_MD_SHA256;
cbDigest = 256 / 8;
break;
case 384:
mdType = MBEDTLS_MD_SHA384;
cbDigest = 384 / 8;
break;
case 512:
mdType = MBEDTLS_MD_SHA512;
cbDigest = 512 / 8;
break;
default:
FAIL_CONDITION(COSE_ERR_INVALID_PARAMETER);
break;
}
pmd = mbedtls_md_info_from_type(mdType);
if (pmd == NULL) {
goto errorReturn;
}
cbSalt = 0;
byte *pbSalt = NULL;
cnSalt = _COSE_map_get_int(pcose, COSE_Header_HKDF_salt, COSE_BOTH, perr);
if (cnSalt != NULL) {
pbSalt = cnSalt->v.bytes;
cbSalt = (int)cnSalt->length;
}
CHECK_CONDITION0(
mbedtls_hkdf_extract(pmd, pbSalt, cbSalt, pbKey, cbKey, rgbDigest), 0);
*pcbDigest = cbDigest;
return true;
}
bool HKDF_Expand(COSE *pcose,
size_t cbitDigest,
const byte *pbPRK,
size_t cbPRK,
const byte *pbInfo,
size_t cbInfo,
byte *pbOutput,
size_t cbOutput,
cose_errback *perr)
{
UNUSED(pcose);
mbedtls_md_type_t mdType;
mbedtls_md_info_t *pmd;
unsigned int cbDigest = 0;
if (0) {
errorReturn:
return false;
}
switch (cbitDigest) {
case 256:
mdType = MBEDTLS_MD_SHA256;
cbDigest = 256 / 8;
break;
case 384:
mdType = MBEDTLS_MD_SHA384;
cbDigest = 384 / 8;
break;
case 512:
mdType = MBEDTLS_MD_SHA512;
cbDigest = 512 / 8;
break;
default:
FAIL_CONDITION(COSE_ERR_INVALID_PARAMETER);
break;
}
pmd = mbedtls_md_info_from_type(mdType);
if (pmd == NULL) {
goto errorReturn;
}
if (mbedtls_hkdf_expand(
pmd, pbPRK, cbPRK, pbInfo, cbInfo, pbOutput, cbOutput) != 0) {
goto errorReturn;
}
return true;
}
#endif
#ifdef USE_HMAC
bool HMAC_Create(COSE_MacMessage *pcose,
int HSize,
int TSize,
const byte *pbKey,
size_t cbKey,
const byte *pbAuthData,
size_t cbAuthData,
cose_errback *perr)
{
byte *rgbOut = NULL;
// unsigned int cbOut;
mbedtls_md_context_t contx;
const char *md_name;
const struct mbedtls_md_info_t *info;
#ifdef USE_CBOR_CONTEXT
cn_cbor_context *context = &pcose->m_message.m_allocContext;
#endif
switch (HSize) {
case 256:
md_name = "SHA256";
break;
case 384:
md_name = "SHA384";
break;
case 512:
md_name = "SHA512";
break;
default:
FAIL_CONDITION(COSE_ERR_INVALID_PARAMETER);
break;
}
if (0) {
errorReturn:
COSE_FREE(rgbOut, context);
mbedtls_md_free(&contx);
return false;
}
mbedtls_md_init(&contx);
info = mbedtls_md_info_from_string(md_name);
mbedtls_md_setup(&contx, info, 1);
rgbOut = COSE_CALLOC(mbedtls_md_get_size(info), 1, context);
CHECK_CONDITION(rgbOut != NULL, COSE_ERR_OUT_OF_MEMORY);
CHECK_CONDITION(
!(mbedtls_md_hmac_starts(&contx, pbKey, cbKey)), COSE_ERR_CRYPTO_FAIL);
CHECK_CONDITION(!(mbedtls_md_hmac_update(&contx, pbAuthData, cbAuthData)),
COSE_ERR_CRYPTO_FAIL);
CHECK_CONDITION(
!(mbedtls_md_hmac_finish(&contx, rgbOut)), COSE_ERR_CRYPTO_FAIL);
CHECK_CONDITION(_COSE_array_replace(&pcose->m_message,
cn_cbor_data_create(
rgbOut, TSize / 8, CBOR_CONTEXT_PARAM_COMMA NULL),
INDEX_MAC_TAG, CBOR_CONTEXT_PARAM_COMMA NULL),
COSE_ERR_CBOR);
mbedtls_md_free(&contx);
return true;
}
bool HMAC_Validate(COSE_MacMessage *pcose,
int HSize,
int TSize,
const byte *pbKey,
size_t cbKey,
const byte *pbAuthData,
size_t cbAuthData,
cose_errback *perr)
{
mbedtls_md_context_t contx;
const char *md_name;
const struct mbedtls_md_info_t *info;
byte *rgbOut = NULL;
unsigned int cbOut;
bool f = false;
unsigned int i;
#ifdef USE_CBOR_CONTEXT
cn_cbor_context *context = &pcose->m_message.m_allocContext;
#endif
switch (HSize) {
case 256:
md_name = "SHA256";
break;
case 384:
md_name = "SHA384";
break;
case 512:
md_name = "SHA512";
break;
default:
FAIL_CONDITION(COSE_ERR_INVALID_PARAMETER);
break;
}
mbedtls_md_init(&contx);
info = mbedtls_md_info_from_string(md_name);
mbedtls_md_setup(&contx, info, 1);
cbOut = mbedtls_md_get_size(info);
rgbOut = COSE_CALLOC(cbOut, 1, context);
CHECK_CONDITION(rgbOut != NULL, COSE_ERR_OUT_OF_MEMORY);
CHECK_CONDITION(
!(mbedtls_md_hmac_starts(&contx, pbKey, cbKey)), COSE_ERR_CRYPTO_FAIL);
CHECK_CONDITION(!(mbedtls_md_hmac_update(&contx, pbAuthData, cbAuthData)),
COSE_ERR_CRYPTO_FAIL);
CHECK_CONDITION(
!(mbedtls_md_hmac_finish(&contx, rgbOut)), COSE_ERR_CRYPTO_FAIL);
cn_cbor *cn = _COSE_arrayget_int(&pcose->m_message, INDEX_MAC_TAG);
CHECK_CONDITION(cn != NULL, COSE_ERR_CBOR);
if (cn->length > (int)cbOut) {
return false;
}
for (i = 0; i < (unsigned int)TSize / 8; i++) {
f |= (cn->v.bytes[i] != rgbOut[i]);
}
mbedtls_md_free(&contx);
return !f;
errorReturn:
COSE_FREE(rgbOut, context);
mbedtls_md_free(&contx);
return false;
}
#endif
#define COSE_Key_EC_Curve -1
#define COSE_Key_EC_X -2
#define COSE_Key_EC_Y -3
#define COSE_Key_EC_d -4
bool ECKey_From(const cn_cbor *pKey,
mbedtls_ecp_keypair *keypair,
cose_errback *perr)
{
byte rgbKey[MBEDTLS_ECP_MAX_PT_LEN];
int cbKey = 0;
int cbGroup = 0;
const cn_cbor *p;
mbedtls_ecp_group_id groupId = 0;
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) && (p->type == CN_CBOR_UINT), COSE_ERR_INVALID_PARAMETER);
switch (p->v.uint) {
case 1: // P-256
groupId = MBEDTLS_ECP_DP_SECP256R1;
break;
case 2: // P-384
groupId = MBEDTLS_ECP_DP_SECP384R1;
break;
case 3: // P-521
groupId = MBEDTLS_ECP_DP_SECP521R1;
break;
default:
FAIL_CONDITION(COSE_ERR_INVALID_PARAMETER);
}
CHECK_CONDITION(mbedtls_ecp_group_load(&keypair->grp, groupId) == 0,
COSE_ERR_INVALID_PARAMETER);
cbGroup = (int) (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);
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] = 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) {
perr->err = COSE_ERR_NO_COMPRESSED_POINTS;
goto errorReturn;
/*
cbKey = cbGroup + 1;
rgbKey[0] = 0x03;
*/
}
else if (p->type == CN_CBOR_FALSE) {
perr->err = COSE_ERR_NO_COMPRESSED_POINTS;
goto errorReturn;
/*
cbKey = cbGroup + 1;
rgbKey[0] = 0x02;
*/
}
else {
FAIL_CONDITION(COSE_ERR_INVALID_PARAMETER);
}
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) {
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 true;
errorReturn:
return false;
}
bool ECDSA_Sign(COSE *pSigner,
int index,
const cn_cbor *pKey,
int cbitDigest,
const byte *rgbToSign,
size_t cbToSign,
cose_errback *perr)
{
#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;
bool result = false;
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);
CHECK_CONDITION(mbedtls_ecdsa_sign_det(&keypair.grp, &r, &s, &keypair.d,
rgbDigest, mbedtls_md_get_size(pmdInfo), mdType) == 0,
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);
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;
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)
{
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;
bool result = false;
mbedtls_ecp_keypair_init(&keypair);
mbedtls_mpi_init(&r);
mbedtls_mpi_init(&s);
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);
}
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) && (pSig->type == CN_CBOR_BYTES),
COSE_ERR_INVALID_PARAMETER);
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);
result = true;
errorReturn:
mbedtls_mpi_free(&r);
mbedtls_mpi_free(&s);
mbedtls_ecp_keypair_free(&keypair);
return result;
}
#if defined(MBEDTLS_NIST_KW_C)
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)
{
mbedtls_nist_kw_context ctx;
size_t cbKeyOut = 0;
mbedtls_nist_kw_init(&ctx);
CHECK_CONDITION0(mbedtls_nist_kw_setkey(
&ctx, MBEDTLS_CIPHER_ID_AES, pbKeyIn, cbitKey, FALSE),
COSE_ERR_CRYPTO_FAIL);
CHECK_CONDITION0(
mbedtls_nist_kw_unwrap(&ctx, MBEDTLS_KW_MODE_KW, pbCipherText,
cbCipherText, pbKeyOut, &cbKeyOut, cbCipherText - 8),
COSE_ERR_CRYPTO_FAIL);
*pcbKeyOut = (int)cbKeyOut;
mbedtls_nist_kw_free(&ctx);
return true;
errorReturn:
mbedtls_nist_kw_free(&ctx);
return false;
}
bool AES_KW_Encrypt(COSE_RecipientInfo *pcose,
const byte *pbKeyIn,
int cbitKey,
const byte *pbContent,
int cbContent,
cose_errback *perr)
{
byte *pbOut = NULL;
#ifdef USE_CBOR_CONTEXT
cn_cbor_context *context = &pcose->m_encrypt.m_message.m_allocContext;
#endif
cn_cbor *cnTmp = NULL;
mbedtls_nist_kw_context ctx;
size_t cbOut;
mbedtls_nist_kw_init(&ctx);
pbOut = COSE_CALLOC(cbContent + 8, 1, context);
CHECK_CONDITION(pbOut != NULL, COSE_ERR_OUT_OF_MEMORY);
CHECK_CONDITION0(mbedtls_nist_kw_setkey(
&ctx, MBEDTLS_CIPHER_ID_AES, pbKeyIn, cbitKey, TRUE),
COSE_ERR_CRYPTO_FAIL);
CHECK_CONDITION0(mbedtls_nist_kw_wrap(&ctx, MBEDTLS_KW_MODE_KW, pbContent,
cbContent, pbOut, &cbOut, cbContent + 8),
COSE_ERR_CRYPTO_FAIL);
cnTmp = cn_cbor_data_create(
pbOut, (int)cbContent + 8, CBOR_CONTEXT_PARAM_COMMA NULL);
CHECK_CONDITION(cnTmp != NULL, COSE_ERR_CBOR);
pbOut = NULL;
CHECK_CONDITION(_COSE_array_replace(&pcose->m_encrypt.m_message, cnTmp,
INDEX_BODY, CBOR_CONTEXT_PARAM_COMMA NULL),
COSE_ERR_CBOR);
cnTmp = NULL;
mbedtls_nist_kw_free(&ctx);
return true;
errorReturn:
COSE_FREE(cnTmp, context);
if (pbOut != NULL) {
COSE_FREE(pbOut, context);
}
mbedtls_nist_kw_free(&ctx);
return false;
}
#endif
/*
//#include <stdio.h> //TODO
void rand_bytes(byte * pb, size_t cb){
// https://tls.mbed.org/kb/how-to/add-a-random-generator
//init random
mbedtls_ctr_drbg_context ctr_drbg;
char *personalization = "my_app_specific_string";
ret = mbedtls_ctr_drbg_init( &ctr_drbg, mbedtls_entropy_func, &entropy,
(const unsigned char *)
personalization, strlen( personalization ) );
if(ret != 0) {
//printf TODO
}
mbedtls_ctr_drbg_random(&ctx,pb, cb);
mbedtls_ctr_drbg_free(&ctx);
printf("rand byute done\n");
}*/
// TODO HOW TO GENERATE GOOD RANDOM BYTES
#if 0
static const unsigned char entropy_source_pr[96] =
{ 0xc1, 0x80, 0x81, 0xa6, 0x5d, 0x44, 0x02, 0x16,
0x19, 0xb3, 0xf1, 0x80, 0xb1, 0xc9, 0x20, 0x02,
0x6a, 0x54, 0x6f, 0x0c, 0x70, 0x81, 0x49, 0x8b,
0x6e, 0xa6, 0x62, 0x52, 0x6d, 0x51, 0xb1, 0xcb,
0x58, 0x3b, 0xfa, 0xd5, 0x37, 0x5f, 0xfb, 0xc9,
0xff, 0x46, 0xd2, 0x19, 0xc7, 0x22, 0x3e, 0x95,
0x45, 0x9d, 0x82, 0xe1, 0xe7, 0x22, 0x9f, 0x63,
0x31, 0x69, 0xd2, 0x6b, 0x57, 0x47, 0x4f, 0xa3,
0x37, 0xc9, 0x98, 0x1c, 0x0b, 0xfb, 0x91, 0x31,
0x4d, 0x55, 0xb9, 0xe9, 0x1c, 0x5a, 0x5e, 0xe4,
0x93, 0x92, 0xcf, 0xc5, 0x23, 0x12, 0xd5, 0x56,
0x2c, 0x4a, 0x6e, 0xff, 0xdc, 0x10, 0xd0, 0x68 };
#endif
static const unsigned char nonce_pers_pr[16] = {0xd2, 0x54, 0xfc, 0xff, 0x02,
0x1e, 0x69, 0xd2, 0x29, 0xc9, 0xcf, 0xad, 0x85, 0xfa, 0x48, 0x6c};
/*
static size_t test_offset;
static int ctr_drbg_self_test_entropy( void *data, unsigned char *buf, size_t
len ) { const unsigned char *p = data; memcpy( buf, p + test_offset, len );
test_offset += len;
return( 0 );
}
*/
mbedtls_ctr_drbg_context ctxRandom;
int ctx_setup = 0;
mbedtls_entropy_context entropy;
void rand_bytes(byte *pb, size_t cb)
{
// unsigned char buf[16];
if (!ctx_setup) {
mbedtls_entropy_init(&entropy);
mbedtls_ctr_drbg_init(&ctxRandom);
mbedtls_ctr_drbg_seed_entropy_len(&ctxRandom, mbedtls_entropy_func,
(void *)&entropy, nonce_pers_pr, 16, 32);
ctx_setup = 1;
}
// mbedtls_ctr_drbg_set_prediction_resistance( &ctx, MBEDTLS_CTR_DRBG_PR_ON
// );
mbedtls_ctr_drbg_random(&ctxRandom, pb, cb);
// mbedtls_ctr_drbg_random( &ctx, buf, MBEDTLS_CTR_DRBG_BLOCKSIZE );
// memcmp( buf, result_pr, MBEDTLS_CTR_DRBG_BLOCKSIZE ) );
// mbedtls_ctr_drbg_free( &ctx );
}
int rand_bytes2(void *pv, unsigned char *pb, size_t cb)
{
UNUSED(pv);
rand_bytes(pb, cb);
return 0;
}
// END OF TODO RANDOM BYTES
#if USE_ECDH
/*!
*
* @param[in] pRecipient Pointer to the message object
* @param[in] ppKeyPrivate Address of key with private portion
* @param[in] pKeyPublic Address of the key w/o a private portion
* @param[in/out] ppbSecret pointer to buffer to hold the computed secret
* @param[in/out] pcbSecret size of the computed secret
* @param[in] context cbor allocation context structure
* @param[out] perr location to return error information
* @returns success of the function
*/
bool ECDH_ComputeSecret(COSE *pRecipient,
cn_cbor **ppKeyPrivate,
const cn_cbor *pKeyPublic,
byte **ppbSecret,
size_t *pcbSecret,
CBOR_CONTEXT_COMMA cose_errback *perr)
{
UNUSED(pRecipient);
int cbGroup = 0;
int cbsecret = 0;
byte *pbsecret = NULL;
bool fRet = false;
mbedtls_ecp_group_id groupId = 0;
mbedtls_ecp_keypair keypair;
mbedtls_ecdh_context ctx;
mbedtls_mpi d;
cn_cbor *p = NULL;
mbedtls_mpi z;
cn_cbor *pkey = NULL;
int cose_group = 0;
mbedtls_mpi_init(&z);
mbedtls_ecdh_init(&ctx);
mbedtls_mpi_init(&d);
mbedtls_ecp_keypair_init(&keypair);
p = cn_cbor_mapget_int(pKeyPublic, COSE_Key_EC_Curve);
CHECK_CONDITION(
(p != NULL) && (p->type == CN_CBOR_UINT), COSE_ERR_INVALID_PARAMETER);
switch (p->v.uint) {
case 1: // P-256
groupId = MBEDTLS_ECP_DP_SECP256R1;
cbGroup = 256 / 8;
cose_group = 1;
break;
case 2: // P-384
groupId = MBEDTLS_ECP_DP_SECP384R1;
cbGroup = 384 / 12;
cose_group = 2;
break;
case 3: // P-521
groupId = MBEDTLS_ECP_DP_SECP521R1;
cbGroup = (521 + 7) / 8;
cose_group = 3;
break;
default:
FAIL_CONDITION(COSE_ERR_INVALID_PARAMETER);
}
p = NULL;
mbedtls_ecp_group group = {0};
CHECK_CONDITION0(
mbedtls_ecp_group_load(&group, groupId), COSE_ERR_INVALID_PARAMETER);
if (!ECKey_From(pKeyPublic, &keypair, perr)) {
goto errorReturn;
}
if (*ppKeyPrivate == NULL) {
mbedtls_ecp_keypair privateKeyPair;
mbedtls_ecp_keypair_init(&privateKeyPair);
CHECK_CONDITION0(
mbedtls_ecp_gen_key(groupId, &privateKeyPair, rand_bytes2, NULL),
COSE_ERR_CRYPTO_FAIL);
CHECK_CONDITION0(
mbedtls_mpi_copy(&d, &privateKeyPair.d), COSE_ERR_CRYPTO_FAIL);
size_t olen = 0;
byte buff[528 * 2 / 8 + 1];
CHECK_CONDITION0(
mbedtls_ecp_point_write_binary(&group, &privateKeyPair.Q,
MBEDTLS_ECP_PF_UNCOMPRESSED, &olen, buff, sizeof(buff)),
COSE_ERR_CRYPTO_FAIL);
cn_cbor_errback cbor_error;
int cbSize = (olen - 1) / 2;
pkey = cn_cbor_map_create(CBOR_CONTEXT_PARAM_COMMA & cbor_error);
CHECK_CONDITION_CBOR(pkey != NULL, cbor_error);
p = cn_cbor_int_create(
cose_group, CBOR_CONTEXT_PARAM_COMMA & cbor_error);
CHECK_CONDITION_CBOR(p != NULL, cbor_error);
CHECK_CONDITION_CBOR(cn_cbor_mapput_int(pkey, COSE_Key_EC_Curve, p,
CBOR_CONTEXT_PARAM_COMMA perr),
cbor_error);
p = NULL;
pbsecret = COSE_CALLOC(cbSize, 1, context);
CHECK_CONDITION(pbsecret != NULL, COSE_ERR_OUT_OF_MEMORY);
memcpy(pbsecret, buff + 1, cbSize);
p = cn_cbor_data_create(
pbsecret, (int)cbSize, CBOR_CONTEXT_PARAM_COMMA & cbor_error);
CHECK_CONDITION_CBOR(p != NULL, cbor_error);
pbsecret = NULL;
CHECK_CONDITION_CBOR(cn_cbor_mapput_int(pkey, COSE_Key_EC_X, p,
CBOR_CONTEXT_PARAM_COMMA & cbor_error),
cbor_error);
p = NULL;
pbsecret = COSE_CALLOC(cbSize, 1, context);
CHECK_CONDITION(pbsecret != NULL, COSE_ERR_OUT_OF_MEMORY);
memcpy(pbsecret, buff + 1 + cbSize, cbSize);
p = cn_cbor_data_create(
pbsecret, cbSize, CBOR_CONTEXT_PARAM_COMMA & cbor_error);
CHECK_CONDITION_CBOR(p != NULL, cbor_error);
CHECK_CONDITION_CBOR(cn_cbor_mapput_int(pkey, COSE_Key_EC_Y, p,
CBOR_CONTEXT_PARAM_COMMA & cbor_error),
cbor_error);
p = NULL;
p = cn_cbor_int_create(
COSE_Key_Type_EC2, CBOR_CONTEXT_PARAM_COMMA & cbor_error);
CHECK_CONDITION_CBOR(p != NULL, cbor_error);
CHECK_CONDITION_CBOR(cn_cbor_mapput_int(pkey, COSE_Key_Type, p,
CBOR_CONTEXT_PARAM_COMMA & cbor_error),
cbor_error);
p = NULL;
*ppKeyPrivate = pkey;
pkey = NULL;
}
else {
p = cn_cbor_mapget_int(*ppKeyPrivate, COSE_Key_EC_d);
CHECK_CONDITION(p != NULL, COSE_ERR_INVALID_PARAMETER);
CHECK_CONDITION(p->type == CN_CBOR_BYTES, COSE_ERR_INVALID_PARAMETER);
CHECK_CONDITION0(mbedtls_mpi_read_binary(&d, p->v.bytes, p->length),
COSE_ERR_CRYPTO_FAIL);
p = NULL;
}
CHECK_CONDITION0(
mbedtls_ecdh_compute_shared(&group, &z, &keypair.Q, &d, NULL, NULL),
COSE_ERR_CRYPTO_FAIL);
cbsecret = cbGroup;
pbsecret = COSE_CALLOC(cbsecret, 1, context);
CHECK_CONDITION(pbsecret != NULL, COSE_ERR_OUT_OF_MEMORY);
CHECK_CONDITION0(
mbedtls_mpi_write_binary(&z, pbsecret, cbsecret), COSE_ERR_CRYPTO_FAIL);
*ppbSecret = pbsecret;
*pcbSecret = cbsecret;
pbsecret = NULL;
fRet = true;
errorReturn:
if (pbsecret != NULL) {
COSE_FREE(pbsecret, context);
}
if (pkey != NULL) {
CN_CBOR_FREE(pkey, context);
}
if (p != NULL) {
CN_CBOR_FREE(p, context);
}
mbedtls_mpi_free(&d);
mbedtls_mpi_free(&z);
mbedtls_ecp_group_free(&group);
mbedtls_ecp_keypair_free(&keypair);
mbedtls_ecdh_free(&ctx);
return fRet;
}
#endif // USE_ECDH
#endif // COSE_C_USE_MBEDTLS