blob: 229ba29b21fb29ab9c4fc72226778972d57ecd20 [file] [log] [blame]
#include "cose/cose.h"
#include "cose/cose_configure.h"
#include "cose_int.h"
#include "crypto.h"
#include <assert.h>
#include <memory.h>
#include <stdbool.h>
#ifdef USE_OPEN_SSL
#include <openssl/evp.h>
#include <openssl/aes.h>
#include <openssl/cmac.h>
#include <openssl/hmac.h>
#include <openssl/ecdsa.h>
#include <openssl/ecdh.h>
#include <openssl/rand.h>
bool FUseCompressed = true;
#define MIN(A, B) ((A) < (B) ? (A) : (B))
#if (OPENSSL_VERSION_NUMBER < 0x10100000)
HMAC_CTX * HMAC_CTX_new()
{
HMAC_CTX * foo = malloc(sizeof(HMAC_CTX));
if (foo != NULL) {
HMAC_CTX_init(foo);
}
return foo;
}
void HMAC_CTX_free(HMAC_CTX * foo)
{
if (foo != NULL) free(foo);
}
void ECDSA_SIG_get0(const ECDSA_SIG * sig, const BIGNUM **pr, const BIGNUM **ps)
{
if (pr != NULL) *pr = sig->r;
if (ps != NULL) *ps = sig->s;
}
int ECDSA_SIG_set0(ECDSA_SIG * sig, BIGNUM * r, BIGNUM *s)
{
if (r == NULL || s == NULL) return 0;
BN_clear_free(sig->r);
BN_clear_free(sig->s);
sig->r = r;
sig->s = s;
return 1;
}
#endif
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)
{
EVP_CIPHER_CTX *ctx;
int cbOut;
byte * rgbOut = NULL;
int NSize = 15 - (LSize/8);
int outl = 0;
byte rgbIV[15] = { 0 };
const cn_cbor * pIV = NULL;
const EVP_CIPHER * cipher;
#ifdef USE_CBOR_CONTEXT
cn_cbor_context * context = &pcose->m_message.m_allocContext;
#endif
ctx = EVP_CIPHER_CTX_new();
CHECK_CONDITION(ctx != NULL, COSE_ERR_OUT_OF_MEMORY);
// 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);
EVP_CIPHER_CTX_free(ctx);
return false;
}
CHECK_CONDITION(pIV->length == NSize, COSE_ERR_INVALID_PARAMETER);
memcpy(rgbIV, pIV->v.str, pIV->length);
// Setup and run the OpenSSL code
switch (cbKey) {
case 128/8:
cipher = EVP_aes_128_ccm();
break;
case 192/8:
cipher = EVP_aes_192_ccm();
break;
case 256/8:
cipher = EVP_aes_256_ccm();
break;
default:
FAIL_CONDITION(COSE_ERR_INVALID_PARAMETER);
break;
}
CHECK_CONDITION(EVP_DecryptInit_ex(ctx, cipher, NULL, NULL, NULL), COSE_ERR_DECRYPT_FAILED);
TSize /= 8; // Comes in in bits not bytes.
CHECK_CONDITION(EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_CCM_SET_L, (LSize/8), 0), COSE_ERR_DECRYPT_FAILED);
// CHECK_CONDITION(EVP_CIPHER_CTX_ctrl(&ctx, EVP_CTRL_CCM_SET_IVLEN, NSize, 0), COSE_ERR_DECRYPT_FAILED);
CHECK_CONDITION(EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_CCM_SET_TAG, TSize, (void *) &pbCrypto[cbCrypto - TSize]), COSE_ERR_DECRYPT_FAILED);
CHECK_CONDITION(EVP_DecryptInit_ex(ctx, 0, NULL, pbKey, rgbIV), COSE_ERR_DECRYPT_FAILED);
CHECK_CONDITION(EVP_DecryptUpdate(ctx, NULL, &cbOut, NULL, (int) cbCrypto - TSize), COSE_ERR_DECRYPT_FAILED);
cbOut = (int) cbCrypto - TSize;
rgbOut = (byte *)COSE_CALLOC(cbOut, 1, context);
CHECK_CONDITION(rgbOut != NULL, COSE_ERR_OUT_OF_MEMORY);
CHECK_CONDITION(EVP_DecryptUpdate(ctx, NULL, &outl, pbAuthData, (int) cbAuthData), COSE_ERR_DECRYPT_FAILED);
CHECK_CONDITION(EVP_DecryptUpdate(ctx, rgbOut, &cbOut, pbCrypto, (int) cbCrypto - TSize), COSE_ERR_DECRYPT_FAILED);
EVP_CIPHER_CTX_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)
{
EVP_CIPHER_CTX *ctx;
int cbOut;
byte * rgbOut = NULL;
int NSize = 15 - (LSize/8);
int outl = 0;
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;
const EVP_CIPHER * cipher;
byte rgbIV[16];
byte * pbIV = NULL;
cn_cbor_errback cbor_error;
ctx = EVP_CIPHER_CTX_new();
CHECK_CONDITION(NULL != ctx, COSE_ERR_OUT_OF_MEMORY);
switch (cbKey*8) {
case 128:
cipher = EVP_aes_128_ccm();
break;
case 192:
cipher = EVP_aes_192_ccm();
break;
case 256:
cipher = EVP_aes_256_ccm();
break;
default:
FAIL_CONDITION(COSE_ERR_INVALID_PARAMETER);
}
// 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 OpenSSL code
CHECK_CONDITION(EVP_EncryptInit_ex(ctx, cipher, NULL, NULL, NULL), COSE_ERR_CRYPTO_FAIL);
TSize /= 8; // Comes in in bits not bytes.
CHECK_CONDITION(EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_CCM_SET_L, (LSize/8), 0), COSE_ERR_CRYPTO_FAIL);
// CHECK_CONDITION(EVP_CIPHER_CTX_ctrl(&ctx, EVP_CTRL_CCM_SET_IVLEN, NSize, 0), COSE_ERR_CRYPTO_FAIL);
CHECK_CONDITION(EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_CCM_SET_TAG, TSize, NULL), COSE_ERR_CRYPTO_FAIL); // Say we are doing an 8 byte tag
CHECK_CONDITION(EVP_EncryptInit_ex(ctx, 0, NULL, pbKey, rgbIV), COSE_ERR_CRYPTO_FAIL);
CHECK_CONDITION(EVP_EncryptUpdate(ctx, 0, &cbOut, 0, (int) pcose->cbContent), COSE_ERR_CRYPTO_FAIL);
CHECK_CONDITION(EVP_EncryptUpdate(ctx, NULL, &outl, pbAuthData, (int) cbAuthData), COSE_ERR_CRYPTO_FAIL);
rgbOut = (byte *)COSE_CALLOC(cbOut+TSize, 1, context);
CHECK_CONDITION(rgbOut != NULL, COSE_ERR_OUT_OF_MEMORY);
CHECK_CONDITION(EVP_EncryptUpdate(ctx, rgbOut, &cbOut, pcose->pbContent, (int) pcose->cbContent), COSE_ERR_CRYPTO_FAIL);
CHECK_CONDITION(EVP_EncryptFinal_ex(ctx, &rgbOut[cbOut], &cbOut), COSE_ERR_CRYPTO_FAIL);
CHECK_CONDITION(EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_CCM_GET_TAG, TSize, &rgbOut[pcose->cbContent]), 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;
EVP_CIPHER_CTX_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);
EVP_CIPHER_CTX_free(ctx);
return false;
}
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)
{
EVP_CIPHER_CTX *ctx;
int cbOut;
byte * rgbOut = NULL;
int outl = 0;
byte rgbIV[15] = { 0 };
const cn_cbor * pIV = NULL;
const EVP_CIPHER * cipher;
#ifdef USE_CBOR_CONTEXT
cn_cbor_context * context = &pcose->m_message.m_allocContext;
#endif
int TSize = 128 / 8;
ctx = EVP_CIPHER_CTX_new();
CHECK_CONDITION(NULL != ctx, COSE_ERR_OUT_OF_MEMORY);
// 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);
EVP_CIPHER_CTX_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:
cipher = EVP_aes_128_gcm();
break;
case 192 / 8:
cipher = EVP_aes_192_gcm();
break;
case 256 / 8:
cipher = EVP_aes_256_gcm();
break;
default:
FAIL_CONDITION(COSE_ERR_INVALID_PARAMETER);
break;
}
// Do the setup for OpenSSL
CHECK_CONDITION(EVP_DecryptInit_ex(ctx, cipher, NULL, NULL, NULL), COSE_ERR_DECRYPT_FAILED);
CHECK_CONDITION(EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_CCM_SET_TAG, TSize, (void *)&pbCrypto[cbCrypto - TSize]), COSE_ERR_DECRYPT_FAILED);
CHECK_CONDITION(EVP_DecryptInit_ex(ctx, 0, NULL, pbKey, rgbIV), COSE_ERR_DECRYPT_FAILED);
// Pus in the AAD
CHECK_CONDITION(EVP_DecryptUpdate(ctx, NULL, &outl, pbAuthData, (int) cbAuthData), COSE_ERR_DECRYPT_FAILED);
//
cbOut = (int)cbCrypto - TSize;
rgbOut = (byte *)COSE_CALLOC(cbOut, 1, context);
CHECK_CONDITION(rgbOut != NULL, COSE_ERR_OUT_OF_MEMORY);
// Process content
CHECK_CONDITION(EVP_DecryptUpdate(ctx, rgbOut, &cbOut, pbCrypto, (int)cbCrypto - TSize), COSE_ERR_DECRYPT_FAILED);
// Process Tag
CHECK_CONDITION(EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_GCM_SET_TAG, TSize, (byte *)pbCrypto + cbCrypto - TSize), COSE_ERR_DECRYPT_FAILED);
// Check the result
CHECK_CONDITION(EVP_DecryptFinal(ctx, rgbOut + cbOut, &cbOut), COSE_ERR_DECRYPT_FAILED);
EVP_CIPHER_CTX_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)
{
EVP_CIPHER_CTX *ctx;
int cbOut;
byte * rgbOut = NULL;
int outl = 0;
byte rgbIV[16] = { 0 };
byte * pbIV = NULL;
const cn_cbor * cbor_iv = NULL;
cn_cbor * cbor_iv_t = NULL;
const EVP_CIPHER * cipher;
#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
ctx = EVP_CIPHER_CTX_new();
CHECK_CONDITION(NULL != ctx, COSE_ERR_OUT_OF_MEMORY);
// 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:
cipher = EVP_aes_128_gcm();
break;
case 192:
cipher = EVP_aes_192_gcm();
break;
case 256:
cipher = EVP_aes_256_gcm();
break;
default:
FAIL_CONDITION(COSE_ERR_INVALID_PARAMETER);
break;
}
// Setup and run the OpenSSL code
CHECK_CONDITION(EVP_EncryptInit_ex(ctx, cipher, NULL, NULL, NULL), COSE_ERR_CRYPTO_FAIL);
CHECK_CONDITION(EVP_EncryptInit_ex(ctx, 0, NULL, pbKey, rgbIV), COSE_ERR_CRYPTO_FAIL);
CHECK_CONDITION(EVP_EncryptUpdate(ctx, NULL, &outl, pbAuthData, (int) 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_CONDITION(EVP_EncryptUpdate(ctx, rgbOut, &cbOut, pcose->pbContent, (int)pcose->cbContent), COSE_ERR_CRYPTO_FAIL);
CHECK_CONDITION(EVP_EncryptFinal_ex(ctx, &rgbOut[cbOut], &cbOut), COSE_ERR_CRYPTO_FAIL);
CHECK_CONDITION(EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_GCM_GET_TAG, 128/8, &rgbOut[pcose->cbContent]), 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);
EVP_CIPHER_CTX_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);
EVP_CIPHER_CTX_free(ctx);
return false;
}
bool AES_CBC_MAC_Create(COSE_MacMessage * pcose, int TSize, const byte * pbKey, size_t cbKey, const byte * pbAuthData, size_t cbAuthData, cose_errback * perr)
{
const EVP_CIPHER * pcipher = NULL;
EVP_CIPHER_CTX *ctx;
int cbOut;
byte rgbIV[16] = { 0 };
byte * rgbOut = NULL;
bool f = false;
unsigned int i;
cn_cbor * cn = NULL;
#ifdef USE_CBOR_CONTEXT
cn_cbor_context * context = &pcose->m_message.m_allocContext;
#endif
ctx = EVP_CIPHER_CTX_new();
CHECK_CONDITION(NULL != ctx, COSE_ERR_OUT_OF_MEMORY);
rgbOut = COSE_CALLOC(16, 1, context);
CHECK_CONDITION(rgbOut != NULL, COSE_ERR_OUT_OF_MEMORY);
switch (cbKey*8) {
case 128:
pcipher = EVP_aes_128_cbc();
break;
case 256:
pcipher = EVP_aes_256_cbc();
break;
default:
FAIL_CONDITION(COSE_ERR_INVALID_PARAMETER);
}
// Setup and run the OpenSSL code
CHECK_CONDITION(EVP_EncryptInit_ex(ctx, pcipher, NULL, pbKey, rgbIV), COSE_ERR_CRYPTO_FAIL);
for (i = 0; i < (unsigned int)cbAuthData / 16; i++) {
CHECK_CONDITION(EVP_EncryptUpdate(ctx, rgbOut, &cbOut, pbAuthData + (i * 16), 16), COSE_ERR_CRYPTO_FAIL);
}
if (cbAuthData % 16 != 0) {
CHECK_CONDITION(EVP_EncryptUpdate(ctx, rgbOut, &cbOut, pbAuthData + (i * 16), cbAuthData % 16), COSE_ERR_CRYPTO_FAIL);
CHECK_CONDITION(EVP_EncryptUpdate(ctx, rgbOut, &cbOut, rgbIV, 16 - (cbAuthData % 16)), COSE_ERR_CRYPTO_FAIL);
}
cn = cn_cbor_data_create(rgbOut, TSize / 8, CBOR_CONTEXT_PARAM_COMMA NULL);
CHECK_CONDITION(cn != NULL, COSE_ERR_OUT_OF_MEMORY);
rgbOut = NULL;
CHECK_CONDITION(_COSE_array_replace(&pcose->m_message, cn, INDEX_MAC_TAG, CBOR_CONTEXT_PARAM_COMMA NULL), COSE_ERR_CBOR);
cn = NULL;
EVP_CIPHER_CTX_free(ctx);
return !f;
errorReturn:
if (rgbOut != NULL) COSE_FREE(rgbOut, context);
if (cn != NULL) CN_CBOR_FREE(cn, context);
EVP_CIPHER_CTX_free(ctx);
return false;
}
bool AES_CBC_MAC_Validate(COSE_MacMessage * pcose, int TSize, const byte * pbKey, size_t cbKey, const byte * pbAuthData, size_t cbAuthData, cose_errback * perr)
{
const EVP_CIPHER * pcipher = NULL;
EVP_CIPHER_CTX *ctx = NULL;
int cbOut;
byte rgbIV[16] = { 0 };
byte rgbTag[16] = { 0 };
bool f = false;
unsigned int i;
switch (cbKey*8) {
case 128:
pcipher = EVP_aes_128_cbc();
break;
case 256:
pcipher = EVP_aes_256_cbc();
break;
default:
FAIL_CONDITION(COSE_ERR_INVALID_PARAMETER);
}
// Setup and run the OpenSSL code
ctx = EVP_CIPHER_CTX_new();
CHECK_CONDITION(NULL != ctx, COSE_ERR_OUT_OF_MEMORY);
CHECK_CONDITION(EVP_EncryptInit_ex(ctx, pcipher, NULL, pbKey, rgbIV), COSE_ERR_CRYPTO_FAIL);
TSize /= 8;
for (i = 0; i < (unsigned int) cbAuthData / 16; i++) {
CHECK_CONDITION(EVP_EncryptUpdate(ctx, rgbTag, &cbOut, pbAuthData+(i*16), 16), COSE_ERR_CRYPTO_FAIL);
}
if (cbAuthData % 16 != 0) {
CHECK_CONDITION(EVP_EncryptUpdate(ctx, rgbTag, &cbOut, pbAuthData + (i * 16), cbAuthData % 16), COSE_ERR_CRYPTO_FAIL);
CHECK_CONDITION(EVP_EncryptUpdate(ctx, rgbTag, &cbOut, rgbIV, 16 - (cbAuthData % 16)), COSE_ERR_CRYPTO_FAIL);
}
cn_cbor * cn = _COSE_arrayget_int(&pcose->m_message, INDEX_MAC_TAG);
CHECK_CONDITION(cn != NULL, COSE_ERR_CBOR);
for (i = 0; i < (unsigned int)TSize; i++) f |= (cn->v.bytes[i] != rgbTag[i]);
EVP_CIPHER_CTX_free(ctx);
return !f;
errorReturn:
EVP_CIPHER_CTX_free(ctx);
return false;
}
#if 0
// We are doing CBC-MAC not CMAC at this time
bool AES_CMAC_Validate(COSE_MacMessage * pcose, int KeySize, int TagSize, const byte * pbAuthData, int cbAuthData, cose_errback * perr)
{
CMAC_CTX * pctx = NULL;
const EVP_CIPHER * pcipher = NULL;
byte * rgbOut = NULL;
size_t cbOut;
bool f = false;
unsigned int i;
#ifdef USE_CBOR_CONTEXT
cn_cbor_context * context = &pcose->m_message.m_allocContext;
#endif
pctx = CMAC_CTX_new();
switch (KeySize) {
case 128: pcipher = EVP_aes_128_cbc(); break;
case 256: pcipher = EVP_aes_256_cbc(); break;
default: FAIL_CONDITION(COSE_ERR_INVALID_PARAMETER); break;
}
rgbOut = COSE_CALLOC(128/8, 1, context);
CHECK_CONDITION(rgbOut != NULL, COSE_ERR_OUT_OF_MEMORY);
CHECK_CONDITION(CMAC_Init(pctx, pcose->pbKey, pcose->cbKey, pcipher, NULL /*impl*/) == 1, COSE_ERR_CRYPTO_FAIL);
CHECK_CONDITION(CMAC_Update(pctx, pbAuthData, cbAuthData), COSE_ERR_CRYPTO_FAIL);
CHECK_CONDITION(CMAC_Final(pctx, rgbOut, &cbOut), COSE_ERR_CRYPTO_FAIL);
cn_cbor * cn = _COSE_arrayget_int(&pcose->m_message, INDEX_MAC_TAG);
CHECK_CONDITION(cn != NULL, COSE_ERR_CBOR);
for (i = 0; i < (unsigned int)TagSize / 8; i++) f |= (cn->v.bytes[i] != rgbOut[i]);
COSE_FREE(rgbOut, context);
CMAC_CTX_cleanup(pctx);
CMAC_CTX_free(pctx);
return !f;
errorReturn:
COSE_FREE(rgbOut, context);
CMAC_CTX_cleanup(pctx);
CMAC_CTX_free(pctx);
return false;
}
#endif
bool HKDF_AES_Expand(COSE * pcose, size_t cbitKey, const byte * pbPRK, size_t cbPRK, const byte * pbInfo, size_t cbInfo, byte * pbOutput, size_t cbOutput, cose_errback * perr)
{
const EVP_CIPHER * pcipher = NULL;
EVP_CIPHER_CTX *ctx;
int cbOut;
byte rgbIV[16] = { 0 };
byte bCount = 1;
size_t ib;
byte rgbDigest[128 / 8];
int cbDigest = 0;
byte rgbOut[16];
UNUSED(pcose);
ctx = EVP_CIPHER_CTX_new();
CHECK_CONDITION(NULL != ctx, COSE_ERR_OUT_OF_MEMORY);
switch (cbitKey) {
case 128:
pcipher = EVP_aes_128_cbc();
break;
case 256:
pcipher = EVP_aes_256_cbc();
break;
default:
FAIL_CONDITION(COSE_ERR_INVALID_PARAMETER);
}
CHECK_CONDITION(cbPRK == cbitKey / 8, COSE_ERR_INVALID_PARAMETER);
// Setup and run the OpenSSL code
for (ib = 0; ib < cbOutput; ib += 16, bCount += 1) {
size_t ib2;
CHECK_CONDITION(EVP_EncryptInit_ex(ctx, pcipher, NULL, pbPRK, rgbIV), COSE_ERR_CRYPTO_FAIL);
CHECK_CONDITION(EVP_EncryptUpdate(ctx, rgbOut, &cbOut, rgbDigest, cbDigest), COSE_ERR_CRYPTO_FAIL);
for (ib2 = 0; ib2 < cbInfo; ib2+=16) {
CHECK_CONDITION(EVP_EncryptUpdate(ctx, rgbOut, &cbOut, pbInfo+ib2, (int) MIN(16, cbInfo-ib2)), COSE_ERR_CRYPTO_FAIL);
}
CHECK_CONDITION(EVP_EncryptUpdate(ctx, rgbOut, &cbOut, &bCount, 1), COSE_ERR_CRYPTO_FAIL);
if ((cbInfo + 1) % 16 != 0) {
CHECK_CONDITION(EVP_EncryptUpdate(ctx, rgbOut, &cbOut, rgbIV, (int) 16-(cbInfo+1)%16), COSE_ERR_CRYPTO_FAIL);
}
memcpy(rgbDigest, rgbOut, cbOut);
cbDigest = cbOut;
memcpy(pbOutput + ib, rgbDigest, MIN(16, cbOutput - ib));
}
EVP_CIPHER_CTX_free(ctx);
return true;
errorReturn:
EVP_CIPHER_CTX_free(ctx);
return false;
}
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)
{
byte rgbSalt[EVP_MAX_MD_SIZE] = { 0 };
int cbSalt;
cn_cbor * cnSalt;
HMAC_CTX *ctx;
const EVP_MD * pmd = NULL;
unsigned int cbDigest;
ctx = HMAC_CTX_new();
CHECK_CONDITION(NULL != ctx, COSE_ERR_OUT_OF_MEMORY);
if (0) {
errorReturn:
HMAC_CTX_free(ctx);
return false;
}
switch (cbitDigest) {
case 256: pmd = EVP_sha256(); cbSalt = 256 / 8; break;
case 384: pmd = EVP_sha384(); cbSalt = 384 / 8; break;
case 512: pmd = EVP_sha512(); cbSalt = 512 / 8; break;
default: FAIL_CONDITION(COSE_ERR_INVALID_PARAMETER); break;
}
cnSalt = _COSE_map_get_int(pcose, COSE_Header_HKDF_salt, COSE_BOTH, perr);
if (cnSalt != NULL) {
CHECK_CONDITION(HMAC_Init_ex(ctx, cnSalt->v.bytes, (int) cnSalt->length, pmd, NULL), COSE_ERR_CRYPTO_FAIL);
}
else {
CHECK_CONDITION(HMAC_Init_ex(ctx, rgbSalt, cbSalt, pmd, NULL), COSE_ERR_CRYPTO_FAIL);
}
CHECK_CONDITION(HMAC_Update(ctx, pbKey, (int)cbKey), COSE_ERR_CRYPTO_FAIL);
CHECK_CONDITION(HMAC_Final(ctx, rgbDigest, &cbDigest), COSE_ERR_CRYPTO_FAIL);
*pcbDigest = cbDigest;
HMAC_CTX_free(ctx);
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)
{
HMAC_CTX *ctx;
const EVP_MD * pmd = NULL;
size_t ib;
unsigned int cbDigest = 0;
byte rgbDigest[EVP_MAX_MD_SIZE];
byte bCount = 1;
UNUSED(pcose);
ctx = HMAC_CTX_new();
CHECK_CONDITION(ctx != NULL, COSE_ERR_OUT_OF_MEMORY);
if (0) {
errorReturn:
HMAC_CTX_free(ctx);
return false;
}
switch (cbitDigest) {
case 256: pmd = EVP_sha256(); break;
case 384: pmd = EVP_sha384(); break;
case 512: pmd = EVP_sha512(); break;
default: FAIL_CONDITION(COSE_ERR_INVALID_PARAMETER); break;
}
for (ib = 0; ib < cbOutput; ib += cbDigest, bCount += 1) {
CHECK_CONDITION(HMAC_Init_ex(ctx, pbPRK, (int)cbPRK, pmd, NULL), COSE_ERR_CRYPTO_FAIL);
CHECK_CONDITION(HMAC_Update(ctx, rgbDigest, cbDigest), COSE_ERR_CRYPTO_FAIL);
CHECK_CONDITION(HMAC_Update(ctx, pbInfo, cbInfo), COSE_ERR_CRYPTO_FAIL);
CHECK_CONDITION(HMAC_Update(ctx, &bCount, 1), COSE_ERR_CRYPTO_FAIL);
CHECK_CONDITION(HMAC_Final(ctx, rgbDigest, &cbDigest), COSE_ERR_CRYPTO_FAIL);
memcpy(pbOutput + ib, rgbDigest, MIN(cbDigest, cbOutput - ib));
}
HMAC_CTX_free(ctx);
return true;
}
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)
{
HMAC_CTX *ctx;
const EVP_MD * pmd = NULL;
byte * rgbOut = NULL;
unsigned int cbOut;
#ifdef USE_CBOR_CONTEXT
cn_cbor_context * context = &pcose->m_message.m_allocContext;
#endif
ctx = HMAC_CTX_new();
CHECK_CONDITION(NULL != ctx, COSE_ERR_OUT_OF_MEMORY);
if (0) {
errorReturn:
COSE_FREE(rgbOut, context);
HMAC_CTX_free(ctx);
return false;
}
switch (HSize) {
case 256: pmd = EVP_sha256(); break;
case 384: pmd = EVP_sha384(); break;
case 512: pmd = EVP_sha512(); break;
default: FAIL_CONDITION(COSE_ERR_INVALID_PARAMETER); break;
}
rgbOut = COSE_CALLOC(EVP_MAX_MD_SIZE, 1, context);
CHECK_CONDITION(rgbOut != NULL, COSE_ERR_OUT_OF_MEMORY);
CHECK_CONDITION(HMAC_Init_ex(ctx, pbKey, (int) cbKey, pmd, NULL), COSE_ERR_CRYPTO_FAIL);
CHECK_CONDITION(HMAC_Update(ctx, pbAuthData, cbAuthData), COSE_ERR_CRYPTO_FAIL);
CHECK_CONDITION(HMAC_Final(ctx, rgbOut, &cbOut), 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);
HMAC_CTX_free(ctx);
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)
{
HMAC_CTX *ctx;
const EVP_MD * pmd = NULL;
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
ctx = HMAC_CTX_new();
CHECK_CONDITION(ctx != NULL, COSE_ERR_OUT_OF_MEMORY);
switch (HSize) {
case 256: pmd = EVP_sha256(); break;
case 384: pmd = EVP_sha384(); break;
case 512: pmd = EVP_sha512(); break;
default: FAIL_CONDITION(COSE_ERR_INVALID_PARAMETER); break;
}
rgbOut = COSE_CALLOC(EVP_MAX_MD_SIZE, 1, context);
CHECK_CONDITION(rgbOut != NULL, COSE_ERR_OUT_OF_MEMORY);
CHECK_CONDITION(HMAC_Init_ex(ctx, pbKey, (int) cbKey, pmd, NULL), COSE_ERR_CRYPTO_FAIL);
CHECK_CONDITION(HMAC_Update(ctx, pbAuthData, cbAuthData), COSE_ERR_CRYPTO_FAIL);
CHECK_CONDITION(HMAC_Final(ctx, rgbOut, &cbOut), 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]);
HMAC_CTX_free(ctx);
return !f;
errorReturn:
COSE_FREE(rgbOut, context);
HMAC_CTX_free(ctx);
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)
{
EC_KEY * pNewKey = EC_KEY_new();
byte rgbKey[512+1];
int cbKey;
const cn_cbor * p;
int nidGroup = -1;
EC_POINT * pPoint = NULL;
p = cn_cbor_mapget_int(pKey, COSE_Key_EC_Curve);
CHECK_CONDITION(p != NULL, COSE_ERR_INVALID_PARAMETER);
switch (p->v.sint) {
case 1: // P-256
nidGroup = NID_X9_62_prime256v1;
*cbGroup = 256 / 8;
break;
case 2: // P-384
nidGroup = NID_secp384r1;
*cbGroup = 384 / 8;
break;
case 3: // P-521
nidGroup = NID_secp521r1;
*cbGroup = (521 + 7) / 8;
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);
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] = POINT_CONVERSION_UNCOMPRESSED;
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;
}
else if (p->type == CN_CBOR_FALSE) {
cbKey = (*cbGroup) + 1;
rgbKey[0] = POINT_CONVERSION_COMPRESSED;
}
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);
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);
}
return pNewKey;
errorReturn:
if (pNewKey != NULL) EC_KEY_free(pNewKey);
return NULL;
}
cn_cbor * EC_FromKey(const EC_KEY * pKey, CBOR_CONTEXT_COMMA cose_errback * perr)
{
cn_cbor * pkey = NULL;
const EC_GROUP * pgroup;
int cose_group;
cn_cbor * p = NULL;
cn_cbor_errback cbor_error;
const EC_POINT * pPoint;
size_t cbSize;
byte * pbOut = NULL;
pgroup = EC_KEY_get0_group(pKey);
CHECK_CONDITION(pgroup != NULL, COSE_ERR_INVALID_PARAMETER);
switch (EC_GROUP_get_curve_name(pgroup)) {
case NID_X9_62_prime256v1: cose_group = 1; break;
case NID_secp384r1: cose_group = 2; break;
case NID_secp521r1: cose_group = 3; break;
default:
FAIL_CONDITION(COSE_ERR_INVALID_PARAMETER);
}
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 &cbor_error), cbor_error);
p = NULL;
pPoint = EC_KEY_get0_public_key(pKey);
CHECK_CONDITION(pPoint != NULL, COSE_ERR_INVALID_PARAMETER);
if (FUseCompressed) {
cbSize = EC_POINT_point2oct(pgroup, pPoint, POINT_CONVERSION_COMPRESSED, NULL, 0, NULL);
CHECK_CONDITION(cbSize > 0, COSE_ERR_CRYPTO_FAIL);
pbOut = COSE_CALLOC(cbSize, 1, context);
CHECK_CONDITION(pbOut != NULL, COSE_ERR_OUT_OF_MEMORY);
CHECK_CONDITION(EC_POINT_point2oct(pgroup, pPoint, POINT_CONVERSION_COMPRESSED, pbOut, cbSize, NULL) == cbSize, COSE_ERR_CRYPTO_FAIL);
}
else {
cbSize = EC_POINT_point2oct(pgroup, pPoint, POINT_CONVERSION_UNCOMPRESSED, NULL, 0, NULL);
CHECK_CONDITION(cbSize > 0, COSE_ERR_CRYPTO_FAIL);
pbOut = COSE_CALLOC(cbSize, 1, context);
CHECK_CONDITION(pbOut != NULL, COSE_ERR_OUT_OF_MEMORY);
CHECK_CONDITION(EC_POINT_point2oct(pgroup, pPoint, POINT_CONVERSION_UNCOMPRESSED, pbOut, cbSize, NULL) == cbSize, COSE_ERR_CRYPTO_FAIL);
}
p = cn_cbor_data_create(pbOut+1, (int) (cbSize / 2), CBOR_CONTEXT_PARAM_COMMA &cbor_error);
CHECK_CONDITION_CBOR(p != NULL, cbor_error);
CHECK_CONDITION_CBOR(cn_cbor_mapput_int(pkey, COSE_Key_EC_X, p, CBOR_CONTEXT_PARAM_COMMA &cbor_error), cbor_error);
p = NULL;
if (FUseCompressed) {
p = cn_cbor_bool_create(pbOut[0] & 1, 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;
}
else {
p = cn_cbor_data_create(pbOut + cbSize / 2 + 1, (int)(cbSize / 2), CBOR_CONTEXT_PARAM_COMMA &cbor_error);
pbOut = NULL; // It is already part of the other one.
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;
returnHere:
if (pbOut != NULL) COSE_FREE(pbOut, context);
if (p != NULL) CN_CBOR_FREE(p, context);
return pkey;
errorReturn:
CN_CBOR_FREE(pkey, context);
pkey = NULL;
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;
#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;
}
switch (cbitDigest) {
case 256: digest = EVP_sha256(); break;
case 512: digest = EVP_sha512(); break;
case 384: digest = EVP_sha384(); break;
default:
FAIL_CONDITION(COSE_ERR_INVALID_PARAMETER);
}
EVP_Digest(rgbToSign, cbToSign, rgbDigest, &cbDigest, digest, NULL);
psig = ECDSA_do_sign(rgbDigest, cbDigest, eckey);
CHECK_CONDITION(psig != NULL, COSE_ERR_CRYPTO_FAIL);
pbSig = COSE_CALLOC(cbR, 2, context);
CHECK_CONDITION(pbSig != NULL, COSE_ERR_OUT_OF_MEMORY);
const BIGNUM *r;
const BIGNUM *s;
ECDSA_SIG_get0(psig, &r, &s);
cb = BN_bn2bin(r, rgbSig);
CHECK_CONDITION(cb <= cbR, COSE_ERR_INVALID_PARAMETER);
memcpy(pbSig + cbR - cb, rgbSig, cb);
cb = BN_bn2bin(s, rgbSig);
CHECK_CONDITION(cb <= cbR, COSE_ERR_INVALID_PARAMETER);
memcpy(pbSig + 2*cbR - cb, rgbSig, cb);
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);
pbSig = NULL;
if (eckey != NULL) EC_KEY_free(eckey);
return true;
}
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;
int cbR;
cn_cbor * pSig;
size_t cbSignature;
BIGNUM *r, *s;
eckey = ECKey_From(pKey, &cbR, perr);
if (eckey == NULL) {
errorReturn:
if (p != NULL) CN_CBOR_FREE(p, context);
if (eckey != NULL) EC_KEY_free(eckey);
if (sig != NULL) ECDSA_SIG_free(sig);
return false;
}
switch (cbitDigest) {
case 256: digest = EVP_sha256(); break;
case 512: digest = EVP_sha512(); break;
case 384: digest = EVP_sha384(); break;
default:
FAIL_CONDITION(COSE_ERR_INVALID_PARAMETER);
}
EVP_Digest(rgbToSign, cbToSign, rgbDigest, &cbDigest, digest, NULL);
pSig = _COSE_arrayget_int(pSigner, index);
CHECK_CONDITION(pSig != NULL, COSE_ERR_INVALID_PARAMETER);
cbSignature = pSig->length;
CHECK_CONDITION(cbSignature / 2 == cbR, COSE_ERR_INVALID_PARAMETER);
r = BN_bin2bn(pSig->v.bytes,(int) cbSignature/2, NULL);
CHECK_CONDITION(NULL != r, COSE_ERR_OUT_OF_MEMORY);
s = BN_bin2bn(pSig->v.bytes+cbSignature/2, (int) cbSignature/2, NULL);
CHECK_CONDITION(NULL != s, COSE_ERR_OUT_OF_MEMORY);
sig = ECDSA_SIG_new();
CHECK_CONDITION(sig != NULL, COSE_ERR_OUT_OF_MEMORY);
ECDSA_SIG_set0(sig, r, s);
CHECK_CONDITION(ECDSA_do_verify(rgbDigest, cbDigest, sig, eckey) == 1, COSE_ERR_CRYPTO_FAIL);
if (eckey != NULL) EC_KEY_free(eckey);
if (sig != NULL) ECDSA_SIG_free(sig);
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];
AES_KEY key;
UNUSED(pcose);
CHECK_CONDITION(AES_set_decrypt_key(pbKeyIn, (int)cbitKey, &key) == 0, COSE_ERR_CRYPTO_FAIL);
CHECK_CONDITION(AES_unwrap_key(&key, NULL, rgbOut, pbCipherText, (int) cbCipherText), COSE_ERR_CRYPTO_FAIL);
memcpy(pbKeyOut, rgbOut, cbCipherText - 8);
*pcbKeyOut = (int) (cbCipherText - 8);
return true;
errorReturn:
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;
AES_KEY key;
#ifdef USE_CBOR_CONTEXT
cn_cbor_context * context = &pcose->m_encrypt.m_message.m_allocContext;
#endif
cn_cbor * cnTmp = NULL;
pbOut = COSE_CALLOC(cbContent + 8, 1, context);
CHECK_CONDITION(pbOut != NULL, COSE_ERR_OUT_OF_MEMORY);
CHECK_CONDITION(AES_set_encrypt_key(pbKeyIn, cbitKey, &key) == 0, COSE_ERR_CRYPTO_FAIL);
CHECK_CONDITION(AES_wrap_key(&key, NULL, pbOut, pbContent, cbContent), 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;
return true;
errorReturn:
COSE_FREE(cnTmp, context);
if (pbOut != NULL) COSE_FREE(pbOut, context);
return false;
}
void rand_bytes(byte * pb, size_t cb)
{
RAND_bytes(pb, (int) cb);
}
/*!
*
* @param[in] pRecipent 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)
{
EC_KEY * peckeyPrivate = NULL;
EC_KEY * peckeyPublic = NULL;
int cbGroup;
int cbsecret;
byte * pbsecret = NULL;
bool fRet = false;
peckeyPublic = ECKey_From(pKeyPublic, &cbGroup, perr);
if (peckeyPublic == NULL) goto errorReturn;
if (*ppKeyPrivate == NULL) {
{
cn_cbor * pCompress = _COSE_map_get_int(pRecipient, COSE_Header_UseCompressedECDH, COSE_BOTH, perr);
if (pCompress == NULL) FUseCompressed = false;
else FUseCompressed = (pCompress->type == CN_CBOR_TRUE);
}
peckeyPrivate = EC_KEY_new();
EC_KEY_set_group(peckeyPrivate, EC_KEY_get0_group(peckeyPublic));
CHECK_CONDITION(EC_KEY_generate_key(peckeyPrivate) == 1, COSE_ERR_CRYPTO_FAIL);
*ppKeyPrivate = EC_FromKey(peckeyPrivate, CBOR_CONTEXT_PARAM_COMMA perr);
if (*ppKeyPrivate == NULL) goto errorReturn;
}
else {
peckeyPrivate = ECKey_From(*ppKeyPrivate, &cbGroup, perr);
if (peckeyPrivate == NULL) goto errorReturn;
}
pbsecret = COSE_CALLOC(cbGroup, 1, context);
CHECK_CONDITION(pbsecret != NULL, COSE_ERR_OUT_OF_MEMORY);
cbsecret = ECDH_compute_key(pbsecret, cbGroup, EC_KEY_get0_public_key(peckeyPublic), peckeyPrivate, NULL);
CHECK_CONDITION(cbsecret > 0, COSE_ERR_CRYPTO_FAIL);
*ppbSecret = pbsecret;
*pcbSecret = cbsecret;
pbsecret = NULL;
fRet = true;
errorReturn:
if (pbsecret != NULL) COSE_FREE(pbsecret, context);
if (peckeyPublic != NULL) EC_KEY_free(peckeyPublic);
if (peckeyPrivate != NULL) EC_KEY_free(peckeyPrivate);
return fRet;
}
#endif // USE_OPEN_SSL