blob: dd2c307340678190e10c529f52707d68b6acbc13 [file] [log] [blame]
#include <stdlib.h>
#ifndef __MBED__
#include <memory.h>
#endif
#include "cose/cose.h"
#include "cose_int.h"
#include "cose/cose_configure.h"
#include "cose_crypto.h"
#if INCLUDE_ENCRYPT || INCLUDE_ENCRYPT0 || INCLUDE_MAC || INCLUDE_MAC0
static bool BuildContextBytes(COSE *pcose,
int algID,
size_t cbitKey,
byte **ppbContext,
size_t *pcbContext,
CBOR_CONTEXT_COMMA cose_errback *perr);
#endif
#if INCLUDE_ENCRYPT || INCLUDE_MAC
COSE *RecipientRoot = NULL;
/*! \private
* @brief Test if a HCOSE_RECIPIENT handle is valid
*
* Internal function to test if a recipient handle is valid.
* This will start returning invalid results and cause the code to
* crash if handles are not released before the memory that underlies them
* is deallocated. This is an issue of a block allocator is used since
* in that case it is common to allocate memory but never to de-allocate it
* and just do that in a single big block.
*
* @param h handle to be validated
* @returns result of check
*/
bool IsValidRecipientHandle(HCOSE_RECIPIENT h)
{
COSE_RecipientInfo *p = (COSE_RecipientInfo *)h;
if (p == NULL) {
return false;
}
return _COSE_IsInList(RecipientRoot, &p->m_encrypt.m_message);
}
HCOSE_RECIPIENT COSE_Recipient_Init(COSE_INIT_FLAGS flags,
CBOR_CONTEXT_COMMA cose_errback *perr)
{
CHECK_CONDITION(flags == COSE_INIT_FLAGS_NONE, COSE_ERR_INVALID_PARAMETER);
COSE_RecipientInfo *pobj = (COSE_RecipientInfo *)COSE_CALLOC(
1, sizeof(COSE_RecipientInfo), context);
CHECK_CONDITION(pobj != NULL, COSE_ERR_OUT_OF_MEMORY);
if (!_COSE_Init(flags | COSE_INIT_FLAGS_NO_CBOR_TAG,
&pobj->m_encrypt.m_message, COSE_recipient_object,
CBOR_CONTEXT_PARAM_COMMA perr)) {
_COSE_Recipient_Free(pobj);
return NULL;
}
_COSE_InsertInList(&RecipientRoot, &pobj->m_encrypt.m_message);
return (HCOSE_RECIPIENT)pobj;
errorReturn:
return NULL;
}
bool COSE_Recipient_Free(HCOSE_RECIPIENT hRecipient)
{
if (IsValidRecipientHandle(hRecipient)) {
COSE_RecipientInfo *p = (COSE_RecipientInfo *)hRecipient;
if (p->m_encrypt.m_message.m_refCount > 1) {
p->m_encrypt.m_message.m_refCount--;
return true;
}
_COSE_RemoveFromList(&RecipientRoot, &p->m_encrypt.m_message);
_COSE_Recipient_Free(p);
return true;
}
return false;
}
HCOSE_RECIPIENT COSE_Recipient_from_shared_secret(byte *rgbKey,
int cbKey,
byte *rgbKid,
int cbKid,
CBOR_CONTEXT_COMMA cose_errback *perr)
{
HCOSE_RECIPIENT hRecipient = NULL;
hRecipient = COSE_Recipient_Init(0, CBOR_CONTEXT_PARAM_COMMA perr);
if (hRecipient == NULL) {
goto errorReturn;
}
if (!COSE_Recipient_SetKey_secret(
hRecipient, rgbKey, cbKey, rgbKid, cbKid, perr)) {
goto errorReturn;
}
return hRecipient;
errorReturn:
if (hRecipient != NULL) {
COSE_Recipient_Free(hRecipient);
}
return NULL;
}
COSE_RecipientInfo *_COSE_Recipient_Init_From_Object(cn_cbor *cbor,
CBOR_CONTEXT_COMMA cose_errback *perr)
{
COSE_RecipientInfo *pRecipient = NULL;
pRecipient = (COSE_RecipientInfo *)COSE_CALLOC(
1, sizeof(COSE_RecipientInfo), context);
CHECK_CONDITION(pRecipient != NULL, COSE_ERR_OUT_OF_MEMORY);
CHECK_CONDITION(cbor->type == CN_CBOR_ARRAY, COSE_ERR_INVALID_PARAMETER);
if (_COSE_Enveloped_Init_From_Object(cbor, &pRecipient->m_encrypt,
CBOR_CONTEXT_PARAM_COMMA perr) == NULL) {
goto errorReturn;
}
_COSE_InsertInList(&RecipientRoot, &pRecipient->m_encrypt.m_message);
return pRecipient;
errorReturn:
if (pRecipient != NULL) {
_COSE_Recipient_Free(pRecipient);
}
return NULL;
}
void _COSE_Recipient_Free(COSE_RecipientInfo *pRecipient)
{
if (pRecipient->m_encrypt.m_message.m_refCount > 1) {
pRecipient->m_encrypt.m_message.m_refCount--;
return;
}
_COSE_Enveloped_Release(&pRecipient->m_encrypt);
if (pRecipient->m_pkey != NULL) {
CN_CBOR_FREE((cn_cbor *)pRecipient->m_pkey,
&pRecipient->m_encrypt.m_message.m_allocContext);
}
if (pRecipient->m_pkeyStatic != NULL) {
CN_CBOR_FREE((cn_cbor *) pRecipient->m_pkeyStatic,
&pRecipient->m_encrypt.m_message.m_allocContext);
}
COSE_FREE(pRecipient, &pRecipient->m_encrypt.m_message.m_allocContext);
return;
}
#endif
#if INCLUDE_ENCRYPT || INCLUDE_ENCRYPT0 || INCLUDE_MAC || INCLUDE_MAC0
#if defined(USE_HKDF_SHA2) || defined(USE_HKDF_AES)
/**
* Perform an AES-CCM Decryption operation
*
* @param[in] COSE * Pointer to COSE Encryption context object
* @param[in] int Alorithm key is being generated for
* @param[in] cn_cbor * Private key
* @param[in] cn_cbor * Public Key
* @param[out] byte * Buffer to return new key in
* @param[in] size_t Size of key to create in bits
* @param[in] size_t Size of digest function
* @param[in] cbor_context * Allocation context
* @param[out] cose_errback * Returned error information
* @return Did the function succeed?
*/
static bool HKDF_X(COSE *pCose,
bool fHMAC,
bool fECDH,
bool fStatic,
bool fSend,
int algResult,
const cn_cbor *pKeyPrivate,
const cn_cbor *pKeyPublic,
byte *pbKey,
size_t cbitKey,
size_t cbitHash,
CBOR_CONTEXT_COMMA cose_errback *perr)
{
byte *pbContext = NULL;
size_t cbContext;
bool fRet = false;
const cn_cbor *cn;
byte rgbDigest[512 / 8];
size_t cbDigest;
byte *pbSecret = NULL;
size_t cbSecret = 0;
if (!BuildContextBytes(pCose, algResult, cbitKey, &pbContext, &cbContext,
CBOR_CONTEXT_PARAM_COMMA perr)) {
goto errorReturn;
}
if (fECDH) {
#ifdef USE_ECDH
cn_cbor *pkeyMessage;
if (pKeyPrivate != NULL) {
cn = cn_cbor_mapget_int(pKeyPrivate, COSE_Key_Type);
CHECK_CONDITION((cn != NULL) && (cn->type == CN_CBOR_UINT),
COSE_ERR_INVALID_PARAMETER);
CHECK_CONDITION(
cn->v.uint == COSE_Key_Type_EC2, COSE_ERR_INVALID_PARAMETER);
}
if (pKeyPublic != NULL) {
cn = cn_cbor_mapget_int(pKeyPublic, COSE_Key_Type);
CHECK_CONDITION((cn != NULL) && (cn->type == CN_CBOR_UINT),
COSE_ERR_INVALID_PARAMETER);
CHECK_CONDITION(
cn->v.uint == COSE_Key_Type_EC2, COSE_ERR_INVALID_PARAMETER);
}
if (fSend) {
CHECK_CONDITION(pKeyPublic != NULL, COSE_ERR_INVALID_PARAMETER);
pkeyMessage = (cn_cbor *)pKeyPrivate;
if (!ECDH_ComputeSecret(pCose, &pkeyMessage, pKeyPublic, &pbSecret,
&cbSecret, CBOR_CONTEXT_PARAM_COMMA perr)) {
goto errorReturn;
}
if (!fStatic && pkeyMessage->parent == NULL) {
if (!_COSE_map_put(pCose, COSE_Header_ECDH_EPHEMERAL,
pkeyMessage, COSE_UNPROTECT_ONLY, perr)) {
goto errorReturn;
}
}
}
else {
pkeyMessage = _COSE_map_get_int(pCose,
fStatic ? COSE_Header_ECDH_STATIC : COSE_Header_ECDH_EPHEMERAL,
COSE_BOTH, perr);
CHECK_CONDITION(pkeyMessage != NULL, COSE_ERR_INVALID_PARAMETER);
CHECK_CONDITION(pKeyPrivate != NULL, COSE_ERR_INVALID_PARAMETER);
if (!ECDH_ComputeSecret(pCose, (cn_cbor **)&pKeyPrivate,
pkeyMessage, &pbSecret, &cbSecret,
CBOR_CONTEXT_PARAM_COMMA perr)) {
goto errorReturn;
}
}
#else
goto errorReturn;
#endif
}
else {
CHECK_CONDITION(pKeyPrivate != NULL, COSE_ERR_INVALID_PARAMETER);
cn = cn_cbor_mapget_int(pKeyPrivate, COSE_Key_Type);
CHECK_CONDITION((cn != NULL) && (cn->type == CN_CBOR_UINT),
COSE_ERR_INVALID_PARAMETER);
CHECK_CONDITION(
cn->v.uint == COSE_Key_Type_OCTET, COSE_ERR_INVALID_PARAMETER);
CHECK_CONDITION(cn->v.sint == 4, COSE_ERR_INVALID_PARAMETER);
cn = cn_cbor_mapget_int(pKeyPrivate, -1);
CHECK_CONDITION((cn != NULL) && (cn->type == CN_CBOR_BYTES),
COSE_ERR_INVALID_PARAMETER);
pbSecret = (byte *)cn->v.bytes;
cbSecret = cn->length;
}
if (fHMAC) {
#ifdef USE_HKDF_SHA2
if (!HKDF_Extract(pCose, pbSecret, cbSecret, cbitHash, rgbDigest,
&cbDigest, CBOR_CONTEXT_PARAM_COMMA perr)) {
goto errorReturn;
}
if (!HKDF_Expand(pCose, cbitHash, rgbDigest, cbDigest, pbContext,
cbContext, pbKey, cbitKey / 8, perr)) {
goto errorReturn;
}
#else
goto errorReturn;
#endif
}
else {
#ifdef USE_HKDF_AES
if (!HKDF_AES_Expand(pCose, cbitHash, pbSecret, cbSecret, pbContext,
cbContext, pbKey, cbitKey / 8, perr)) {
goto errorReturn;
}
#else
goto errorReturn;
#endif
}
fRet = true;
errorReturn:
if (fECDH && pbSecret != NULL) {
memset(pbSecret, 0, cbSecret);
COSE_FREE(pbSecret, context);
}
memset(rgbDigest, 0, sizeof(rgbDigest));
if (pbContext != NULL) {
COSE_FREE(pbContext, context);
}
return fRet;
}
#endif // defined(USE_HKDF_SHA2) || defined(USE_HKDF_AES)
bool _COSE_Recipient_decrypt(COSE_RecipientInfo *pRecip,
COSE_RecipientInfo *pRecipUse,
int algIn,
size_t cbitKeyOut,
byte *pbKeyOut,
cose_errback *perr)
{
UNUSED(pRecipUse);
int alg;
const cn_cbor *cn = NULL;
COSE_RecipientInfo *pRecip2;
#ifdef USE_CBOR_CONTEXT
cn_cbor_context *context;
#endif
byte *pbAuthData = NULL;
byte *pbProtected = NULL;
COSE_Enveloped *pcose = &pRecip->m_encrypt;
cn_cbor *cnBody = NULL;
byte *pbContext = NULL;
byte *pbSecret = NULL;
int cbKey2;
byte *pbKeyX = NULL;
int cbitKeyX = 0;
byte rgbKey[256 / 8];
#ifdef USE_CBOR_CONTEXT
context = &pcose->m_message.m_allocContext;
#else
UNUSED(pcose);
#endif
cn = _COSE_map_get_int(
&pRecip->m_encrypt.m_message, COSE_Header_Algorithm, COSE_BOTH, perr);
if (cn == NULL) {
errorReturn:
if (pbContext != NULL) {
COSE_FREE(pbContext, context);
}
if (pbProtected != NULL) {
COSE_FREE(pbProtected, context);
}
if (pbAuthData != NULL) {
COSE_FREE(pbAuthData, context);
}
if (pbSecret != NULL) {
COSE_FREE(pbSecret, context);
}
if (pbKeyX != NULL) {
COSE_FREE(pbKeyX, context);
}
return false;
}
CHECK_CONDITION(cn->type != CN_CBOR_TEXT, COSE_ERR_UNKNOWN_ALGORITHM);
CHECK_CONDITION((cn->type == CN_CBOR_UINT) || (cn->type == CN_CBOR_INT),
COSE_ERR_INVALID_PARAMETER);
alg = (int)cn->v.uint;
CHECK_CONDITION(pbKeyOut != NULL, COSE_ERR_INVALID_PARAMETER);
switch (alg) {
case COSE_Algorithm_Direct:
CHECK_CONDITION(pRecip->m_pkey != NULL, COSE_ERR_INVALID_PARAMETER);
cn = cn_cbor_mapget_int(pRecip->m_pkey, -1);
CHECK_CONDITION((cn != NULL) && (cn->type == CN_CBOR_BYTES),
COSE_ERR_INVALID_PARAMETER);
CHECK_CONDITION(((size_t)cn->length == cbitKeyOut / 8),
COSE_ERR_INVALID_PARAMETER);
memcpy(pbKeyOut, cn->v.bytes, cn->length);
return true;
#ifdef USE_AES_KW_128
case COSE_Algorithm_AES_KW_128:
cbitKeyX = 128;
break;
#endif
#ifdef USE_AES_KW_192
case COSE_Algorithm_AES_KW_192:
cbitKeyX = 192;
break;
#endif
#ifdef USE_AES_KW_256
case COSE_Algorithm_AES_KW_256:
cbitKeyX = 192;
break;
#endif
#ifdef USE_Direct_HKDF_AES_128
case COSE_Algorithm_Direct_HKDF_AES_128:
break;
#endif
#ifdef USE_Direct_HKDF_AES_256
case COSE_Algorithm_Direct_HKDF_AES_256:
break;
#endif
#ifdef USE_Direct_HKDF_HMAC_SHA_256
case COSE_Algorithm_Direct_HKDF_HMAC_SHA_256:
break;
#endif
#ifdef USE_Direct_HKDF_HMAC_SHA_512
case COSE_Algorithm_Direct_HKDF_HMAC_SHA_512:
break;
#endif
#ifdef USE_ECDH_ES_HKDF_256
case COSE_Algorithm_ECDH_ES_HKDF_256:
break;
#endif
#ifdef USE_ECDH_ES_HKDF_512
case COSE_Algorithm_ECDH_ES_HKDF_512:
break;
#endif
#ifdef USE_ECDH_SS_HKDF_256
case COSE_Algorithm_ECDH_SS_HKDF_256:
break;
#endif
#ifdef USE_ECDH_SS_HKDF_512
case COSE_Algorithm_ECDH_SS_HKDF_512:
break;
#endif
#ifdef USE_ECDH_ES_A128KW
case COSE_Algorithm_ECDH_ES_A128KW:
break;
#endif
#ifdef USE_ECDH_ES_A192KW
case COSE_Algorithm_ECDH_ES_A192KW:
break;
#endif
#ifdef USE_ECDH_ES_A256KW
case COSE_Algorithm_ECDH_ES_A256KW:
break;
#endif
#ifdef USE_ECDH_SS_A128KW
case COSE_Algorithm_ECDH_SS_A128KW:
break;
#endif
#ifdef USE_ECDH_SS_A192KW
case COSE_Algorithm_ECDH_SS_A192KW:
break;
#endif
#ifdef USE_ECDH_SS_A256KW
case COSE_Algorithm_ECDH_SS_A256KW:
break;
#endif
default:
FAIL_CONDITION(COSE_ERR_UNKNOWN_ALGORITHM);
break;
}
if (pcose->m_recipientFirst != NULL) {
// If there is a recipient - ask it for the key
CHECK_CONDITION(cbitKeyX != 0, COSE_ERR_INVALID_PARAMETER);
pbKeyX = COSE_CALLOC(cbitKeyX / 8, 1, context);
CHECK_CONDITION(pbKeyX != NULL, COSE_ERR_OUT_OF_MEMORY);
cose_errback error = {COSE_ERR_NONE};
int errorFound = false;
for (pRecip2 = pcose->m_recipientFirst; pRecip2 != NULL;
pRecip2 = pRecip->m_recipientNext) {
if (_COSE_Recipient_decrypt(
pRecip2, NULL, alg, cbitKeyX, pbKeyX, &error)) {
break;
}
if (error.err == COSE_ERR_NO_COMPRESSED_POINTS ||
error.err == COSE_ERR_UNKNOWN_ALGORITHM) {
errorFound = error.err;
}
}
if (errorFound) {
perr->err = errorFound;
goto errorReturn;
}
CHECK_CONDITION(pRecip2 != NULL, COSE_ERR_NO_RECIPIENT_FOUND);
}
cnBody = _COSE_arrayget_int(&pcose->m_message, INDEX_BODY);
CHECK_CONDITION(cnBody != NULL, COSE_ERR_INVALID_PARAMETER);
switch (alg) {
#ifdef USE_AES_KW_128
case COSE_Algorithm_AES_KW_128:
if (pbKeyX != NULL) {
int x = cbitKeyOut / 8;
if (!AES_KW_Decrypt((COSE_Enveloped *)pcose, pbKeyX, cbitKeyX,
cnBody->v.bytes, cnBody->length, pbKeyOut, &x, perr)) {
goto errorReturn;
}
}
else {
CHECK_CONDITION(
pRecip->m_pkey != NULL, COSE_ERR_INVALID_PARAMETER);
int x = cbitKeyOut / 8;
cn = cn_cbor_mapget_int(pRecip->m_pkey, -1);
CHECK_CONDITION((cn != NULL) && (cn->type == CN_CBOR_BYTES),
COSE_ERR_INVALID_PARAMETER);
if (!AES_KW_Decrypt((COSE_Enveloped *)pcose, cn->v.bytes,
cn->length * 8, cnBody->v.bytes, cnBody->length,
pbKeyOut, &x, perr)) {
goto errorReturn;
}
}
break;
#endif
#ifdef USE_AES_KW_192
case COSE_Algorithm_AES_KW_192:
if (pbKeyX != NULL) {
int x = cbitKeyOut / 8;
if (!AES_KW_Decrypt((COSE_Enveloped *)pcose, pbKeyX, cbitKeyX,
cnBody->v.bytes, cnBody->length, pbKeyOut, &x, perr)) {
goto errorReturn;
}
}
else {
CHECK_CONDITION(
pRecip->m_pkey != NULL, COSE_ERR_INVALID_PARAMETER);
int x = cbitKeyOut / 8;
cn = cn_cbor_mapget_int(pRecip->m_pkey, -1);
CHECK_CONDITION((cn != NULL) && (cn->type == CN_CBOR_BYTES),
COSE_ERR_INVALID_PARAMETER);
if (!AES_KW_Decrypt((COSE_Enveloped *)pcose, cn->v.bytes,
cn->length * 8, cnBody->v.bytes, cnBody->length,
pbKeyOut, &x, perr)) {
goto errorReturn;
}
}
break;
#endif
#ifdef USE_AES_KW_256
case COSE_Algorithm_AES_KW_256:
if (pbKeyX != NULL) {
int x = cbitKeyOut / 8;
if (!AES_KW_Decrypt((COSE_Enveloped *)pcose, pbKeyX, cbitKeyX,
cnBody->v.bytes, cnBody->length, pbKeyOut, &x, perr)) {
goto errorReturn;
}
}
else {
CHECK_CONDITION(
pRecip->m_pkey != NULL, COSE_ERR_INVALID_PARAMETER);
int x = cbitKeyOut / 8;
cn = cn_cbor_mapget_int(pRecip->m_pkey, -1);
CHECK_CONDITION((cn != NULL) && (cn->type == CN_CBOR_BYTES),
COSE_ERR_INVALID_PARAMETER);
if (!AES_KW_Decrypt((COSE_Enveloped *)pcose, cn->v.bytes,
cn->length * 8, cnBody->v.bytes, cnBody->length,
pbKeyOut, &x, perr)) {
goto errorReturn;
}
}
break;
#endif
#ifdef USE_Direct_HKDF_HMAC_SHA_256
case COSE_Algorithm_Direct_HKDF_HMAC_SHA_256:
if (!HKDF_X(&pcose->m_message, true, false, false, false, algIn,
pRecip->m_pkey, NULL, pbKeyOut, cbitKeyOut, 256,
CBOR_CONTEXT_PARAM_COMMA perr)) {
goto errorReturn;
}
break;
#endif
#ifdef USE_Direct_HKDF_HMAC_SHA_512
case COSE_Algorithm_Direct_HKDF_HMAC_SHA_512:
if (!HKDF_X(&pcose->m_message, true, false, false, false, algIn,
pRecip->m_pkey, NULL, pbKeyOut, cbitKeyOut, 512,
CBOR_CONTEXT_PARAM_COMMA perr)) {
goto errorReturn;
}
break;
#endif
#ifdef USE_Direct_HKDF_AES_128
case COSE_Algorithm_Direct_HKDF_AES_128:
if (!HKDF_X(&pcose->m_message, false, false, false, false, algIn,
pRecip->m_pkey, NULL, pbKeyOut, cbitKeyOut, 128,
CBOR_CONTEXT_PARAM_COMMA perr)) {
goto errorReturn;
}
break;
#endif
#ifdef USE_Direct_HKDF_AES_256
case COSE_Algorithm_Direct_HKDF_AES_256:
if (!HKDF_X(&pcose->m_message, false, false, false, false, algIn,
pRecip->m_pkey, NULL, pbKeyOut, cbitKeyOut, 256,
CBOR_CONTEXT_PARAM_COMMA perr)) {
goto errorReturn;
}
break;
#endif
#ifdef USE_ECDH_ES_HKDF_256
case COSE_Algorithm_ECDH_ES_HKDF_256:
if (!HKDF_X(&pcose->m_message, true, true, false, false, algIn,
pRecip->m_pkey, NULL, pbKeyOut, cbitKeyOut, 256,
CBOR_CONTEXT_PARAM_COMMA perr)) {
goto errorReturn;
}
break;
#endif
#ifdef USE_ECDH_ES_HKDF_512
case COSE_Algorithm_ECDH_ES_HKDF_512:
if (!HKDF_X(&pcose->m_message, true, true, false, false, algIn,
pRecip->m_pkey, NULL, pbKeyOut, cbitKeyOut, 512,
CBOR_CONTEXT_PARAM_COMMA perr)) {
goto errorReturn;
}
break;
#endif
#ifdef USE_ECDH_SS_HKDF_256
case COSE_Algorithm_ECDH_SS_HKDF_256:
if (!HKDF_X(&pcose->m_message, true, true, true, false, algIn,
pRecip->m_pkey, NULL, pbKeyOut, cbitKeyOut, 256,
CBOR_CONTEXT_PARAM_COMMA perr)) {
goto errorReturn;
}
break;
#endif
#ifdef USE_ECDH_SS_HKDF_512
case COSE_Algorithm_ECDH_SS_HKDF_512:
if (!HKDF_X(&pcose->m_message, true, true, true, false, algIn,
pRecip->m_pkey, NULL, pbKeyOut, cbitKeyOut, 512,
CBOR_CONTEXT_PARAM_COMMA perr)) {
goto errorReturn;
}
break;
#endif
#ifdef USE_ECDH_ES_A128KW
case COSE_Algorithm_ECDH_ES_A128KW:
if (!HKDF_X(&pcose->m_message, true, true, false, false,
COSE_Algorithm_AES_KW_128, pRecip->m_pkey, NULL, rgbKey,
128, 256, CBOR_CONTEXT_PARAM_COMMA perr)) {
goto errorReturn;
}
if (!AES_KW_Decrypt((COSE_Enveloped *)pcose, rgbKey, 128,
cnBody->v.bytes, cnBody->length, pbKeyOut, &cbKey2, perr)) {
goto errorReturn;
}
break;
#endif
#ifdef USE_ECDH_ES_A192KW
case COSE_Algorithm_ECDH_ES_A192KW:
if (!HKDF_X(&pcose->m_message, true, true, false, false,
COSE_Algorithm_AES_KW_192, pRecip->m_pkey, NULL, rgbKey,
192, 256, CBOR_CONTEXT_PARAM_COMMA perr)) {
goto errorReturn;
}
if (!AES_KW_Decrypt((COSE_Enveloped *)pcose, rgbKey, 192,
cnBody->v.bytes, cnBody->length, pbKeyOut, &cbKey2, perr)) {
goto errorReturn;
}
break;
#endif
#ifdef USE_ECDH_ES_A256KW
case COSE_Algorithm_ECDH_ES_A256KW:
if (!HKDF_X(&pcose->m_message, true, true, false, false,
COSE_Algorithm_AES_KW_256, pRecip->m_pkey, NULL, rgbKey,
256, 256, CBOR_CONTEXT_PARAM_COMMA perr)) {
goto errorReturn;
}
if (!AES_KW_Decrypt((COSE_Enveloped *)pcose, rgbKey, 256,
cnBody->v.bytes, cnBody->length, pbKeyOut, &cbKey2, perr)) {
goto errorReturn;
}
break;
#endif
#ifdef USE_ECDH_SS_A128KW
case COSE_Algorithm_ECDH_SS_A128KW:
if (!HKDF_X(&pcose->m_message, true, true, true, false,
COSE_Algorithm_AES_KW_128, pRecip->m_pkey, NULL, rgbKey,
128, 256, CBOR_CONTEXT_PARAM_COMMA perr)) {
goto errorReturn;
}
if (!AES_KW_Decrypt((COSE_Enveloped *)pcose, rgbKey, 128,
cnBody->v.bytes, cnBody->length, pbKeyOut, &cbKey2, perr)) {
goto errorReturn;
}
break;
#endif
#ifdef USE_ECDH_SS_A192KW
case COSE_Algorithm_ECDH_SS_A192KW:
if (!HKDF_X(&pcose->m_message, true, true, true, false,
COSE_Algorithm_AES_KW_192, pRecip->m_pkey, NULL, rgbKey,
192, 256, CBOR_CONTEXT_PARAM_COMMA perr)) {
goto errorReturn;
}
if (!AES_KW_Decrypt((COSE_Enveloped *)pcose, rgbKey, 192,
cnBody->v.bytes, cnBody->length, pbKeyOut, &cbKey2, perr)) {
goto errorReturn;
}
break;
#endif
#ifdef USE_ECDH_SS_A256KW
case COSE_Algorithm_ECDH_SS_A256KW:
if (!HKDF_X(&pcose->m_message, true, true, true, false,
COSE_Algorithm_AES_KW_256, pRecip->m_pkey, NULL, rgbKey,
256, 256, CBOR_CONTEXT_PARAM_COMMA perr)) {
goto errorReturn;
}
if (!AES_KW_Decrypt((COSE_Enveloped *)pcose, rgbKey, 256,
cnBody->v.bytes, cnBody->length, pbKeyOut, &cbKey2, perr)) {
goto errorReturn;
}
break;
#endif
default:
FAIL_CONDITION(COSE_ERR_UNKNOWN_ALGORITHM);
break;
}
if (pbKeyX != NULL) {
COSE_FREE(pbKeyX, context);
}
return true;
}
bool _COSE_Recipient_encrypt(COSE_RecipientInfo *pRecipient,
const byte *pbContent,
size_t cbContent,
cose_errback *perr)
{
int alg;
int t = 0;
COSE_RecipientInfo *pri;
const cn_cbor *cn_Alg = NULL;
byte *pbAuthData = NULL;
cn_cbor *ptmp = NULL;
size_t cbitKey;
#ifdef USE_CBOR_CONTEXT
cn_cbor_context *context = NULL;
#endif
cn_cbor_errback cbor_error;
bool fRet = false;
byte *pbContext = NULL;
byte rgbKey[256 / 8];
byte *pbSecret = NULL;
byte *pbKey = NULL;
size_t cbKey = 0;
#ifdef USE_CBOR_CONTEXT
context = &pRecipient->m_encrypt.m_message.m_allocContext;
#endif // USE_CBOR_CONTEXT
cn_Alg = _COSE_map_get_int(&pRecipient->m_encrypt.m_message,
COSE_Header_Algorithm, COSE_BOTH, perr);
if (cn_Alg == NULL) {
goto errorReturn;
}
CHECK_CONDITION(cn_Alg->type != CN_CBOR_TEXT, COSE_ERR_UNKNOWN_ALGORITHM);
CHECK_CONDITION(
(cn_Alg->type == CN_CBOR_UINT) || (cn_Alg->type == CN_CBOR_INT),
COSE_ERR_INVALID_PARAMETER);
alg = (int)cn_Alg->v.uint;
// Get the key size
switch (alg) {
case COSE_Algorithm_Direct:
#ifdef USE_Direct_HKDF_HMAC_SHA_256
case COSE_Algorithm_Direct_HKDF_HMAC_SHA_256:
#endif
#ifdef USE_Direct_HKDF_HMAC_SHA_512
case COSE_Algorithm_Direct_HKDF_HMAC_SHA_512:
#endif
#ifdef USE_Direct_HKDF_AES_128
case COSE_Algorithm_Direct_HKDF_AES_128:
#endif
#ifdef USE_Direct_HKDF_AES_256
case COSE_Algorithm_Direct_HKDF_AES_256:
#endif
#ifdef USE_ECDH_ES_HKDF_256
case COSE_Algorithm_ECDH_ES_HKDF_256:
#endif
#ifdef USE_ECDH_ES_HKDF_512
case COSE_Algorithm_ECDH_ES_HKDF_512:
#endif
#ifdef USE_ECDH_SS_HKDF_256
case COSE_Algorithm_ECDH_SS_HKDF_256:
#endif
#ifdef USE_ECDH_SS_HKDF_512
case COSE_Algorithm_ECDH_SS_HKDF_512:
#endif
// This is a NOOP
cbitKey = 0;
CHECK_CONDITION(pRecipient->m_encrypt.m_recipientFirst == NULL,
COSE_ERR_INVALID_PARAMETER);
break;
#ifdef USE_AES_KW_128
case COSE_Algorithm_AES_KW_128:
cbitKey = 128;
break;
#endif
#ifdef USE_ECDH_ES_A128KW
case COSE_Algorithm_ECDH_ES_A128KW:
cbitKey = 128;
break;
#endif
#ifdef USE_ECDH_SS_A128KW
case COSE_Algorithm_ECDH_SS_A128KW:
cbitKey = 128;
break;
#endif
#ifdef USE_AES_KW_192
case COSE_Algorithm_AES_KW_192:
cbitKey = 192;
break;
#endif
#ifdef USE_ECDH_ES_A192KW
case COSE_Algorithm_ECDH_ES_A192KW:
cbitKey = 192;
break;
#endif
#ifdef USE_ECDH_SS_A192KW
case COSE_Algorithm_ECDH_SS_A192KW:
cbitKey = 192;
break;
#endif
#ifdef USE_AES_KW_256
case COSE_Algorithm_AES_KW_256:
cbitKey = 256;
break;
#endif
#ifdef USE_ECDH_ES_A256KW
case COSE_Algorithm_ECDH_ES_A256KW:
cbitKey = 256;
break;
#endif
#ifdef USE_ECDH_SS_A256KW
case COSE_Algorithm_ECDH_SS_A256KW:
cbitKey = 256;
break;
#endif
default:
FAIL_CONDITION(COSE_ERR_UNKNOWN_ALGORITHM);
}
// If we are doing direct encryption - then recipient generates the key
if (pRecipient->m_encrypt.m_recipientFirst != NULL) {
t = 0;
for (pri = pRecipient->m_encrypt.m_recipientFirst; pri != NULL;
pri = pri->m_recipientNext) {
if (pri->m_encrypt.m_message.m_flags & 1) {
t |= 1;
pbKey =
_COSE_RecipientInfo_generateKey(pri, alg, cbitKey, perr);
if (pbKey == NULL) {
goto errorReturn;
}
cbKey = cbitKey / 8;
}
else {
t |= 2;
}
}
CHECK_CONDITION(t != 3, COSE_ERR_INVALID_PARAMETER);
// Do we need to generate a random key at this point -
// This is only true if we both haven't done it and and we have a
// recipient to encrypt it.
if (t == 2) {
pbKey = (byte *)COSE_CALLOC(cbitKey / 8, 1, context);
CHECK_CONDITION(pbKey != NULL, COSE_ERR_OUT_OF_MEMORY);
cbKey = cbitKey / 8;
rand_bytes(pbKey, cbKey);
}
}
// Build protected headers
const cn_cbor *cbProtected =
_COSE_encode_protected(&pRecipient->m_encrypt.m_message, perr);
if (cbProtected == NULL) {
goto errorReturn;
}
// Build authenticated data
size_t cbAuthData = 0;
if (!_COSE_Encrypt_Build_AAD(&pRecipient->m_encrypt.m_message, &pbAuthData,
&cbAuthData, "Recipient", perr)) {
goto errorReturn;
}
switch (alg) {
case COSE_Algorithm_Direct:
#ifdef USE_Direct_HKDF_HMAC_SHA_256
case COSE_Algorithm_Direct_HKDF_HMAC_SHA_256:
#endif
#ifdef USE_Direct_HKDF_HMAC_SHA_512
case COSE_Algorithm_Direct_HKDF_HMAC_SHA_512:
#endif
#ifdef USE_Direct_HKDF_AES_128
case COSE_Algorithm_Direct_HKDF_AES_128:
#endif
#ifdef USE_Direct_HKDF_AES_256
case COSE_Algorithm_Direct_HKDF_AES_256:
#endif
#ifdef USE_ECDH_ES_HKDF_256
case COSE_Algorithm_ECDH_ES_HKDF_256:
#endif
#ifdef USE_ECDH_ES_HKDF_512
case COSE_Algorithm_ECDH_ES_HKDF_512:
#endif
#ifdef USE_ECDH_SS_HKDF_256
case COSE_Algorithm_ECDH_SS_HKDF_256:
#endif
#ifdef USE_ECDH_SS_HKDF_512
case COSE_Algorithm_ECDH_SS_HKDF_512:
#endif
ptmp = cn_cbor_data_create(
NULL, 0, CBOR_CONTEXT_PARAM_COMMA & cbor_error);
CHECK_CONDITION_CBOR(ptmp != NULL, cbor_error);
CHECK_CONDITION_CBOR(
_COSE_array_replace(&pRecipient->m_encrypt.m_message, ptmp,
INDEX_BODY, CBOR_CONTEXT_PARAM_COMMA & cbor_error),
cbor_error);
ptmp = NULL;
break;
#ifdef USE_AES_KW_128
case COSE_Algorithm_AES_KW_128:
if (pRecipient->m_pkey != NULL) {
cn_cbor *pK = cn_cbor_mapget_int(pRecipient->m_pkey, -1);
CHECK_CONDITION(pK != NULL, COSE_ERR_INVALID_PARAMETER);
if (!AES_KW_Encrypt(pRecipient, pK->v.bytes,
(int)pK->length * 8, pbContent, (int)cbContent, perr)) {
goto errorReturn;
}
}
else {
if (!AES_KW_Encrypt(pRecipient, pbKey, (int)cbKey * 8,
pbContent, (int)cbContent, perr)) {
goto errorReturn;
}
}
break;
#endif
#ifdef USE_AES_KW_192
case COSE_Algorithm_AES_KW_192:
if (pRecipient->m_pkey != NULL) {
cn_cbor *pK = cn_cbor_mapget_int(pRecipient->m_pkey, -1);
CHECK_CONDITION(pK != NULL, COSE_ERR_INVALID_PARAMETER);
if (!AES_KW_Encrypt(pRecipient, pK->v.bytes,
(int)pK->length * 8, pbContent, (int)cbContent, perr)) {
goto errorReturn;
}
}
else {
if (!AES_KW_Encrypt(pRecipient, pbKey, (int)cbKey * 8,
pbContent, (int)cbContent, perr)) {
goto errorReturn;
}
}
break;
#endif
#ifdef USE_AES_KW_256
case COSE_Algorithm_AES_KW_256:
if (pRecipient->m_pkey != NULL) {
cn_cbor *pK = cn_cbor_mapget_int(pRecipient->m_pkey, -1);
CHECK_CONDITION(pK != NULL, COSE_ERR_INVALID_PARAMETER);
if (!AES_KW_Encrypt(pRecipient, pK->v.bytes,
(int)pK->length * 8, pbContent, (int)cbContent, perr)) {
goto errorReturn;
}
}
else {
if (!AES_KW_Encrypt(pRecipient, pbKey, (int)cbKey * 8,
pbContent, (int)cbContent, perr)) {
goto errorReturn;
}
}
break;
#endif
#ifdef USE_ECDH_ES_A128KW
case COSE_Algorithm_ECDH_ES_A128KW:
if (!HKDF_X(&pRecipient->m_encrypt.m_message, true, true, false,
true, COSE_Algorithm_AES_KW_128, NULL, pRecipient->m_pkey,
rgbKey, 128, 256, CBOR_CONTEXT_PARAM_COMMA perr)) {
goto errorReturn;
}
if (!AES_KW_Encrypt(
pRecipient, rgbKey, 128, pbContent, (int)cbContent, perr)) {
goto errorReturn;
}
break;
#endif
#ifdef USE_ECDH_ES_A192KW
case COSE_Algorithm_ECDH_ES_A192KW:
if (!HKDF_X(&pRecipient->m_encrypt.m_message, true, true, false,
true, COSE_Algorithm_AES_KW_192, NULL, pRecipient->m_pkey,
rgbKey, 192, 256, CBOR_CONTEXT_PARAM_COMMA perr)) {
goto errorReturn;
}
if (!AES_KW_Encrypt(
pRecipient, rgbKey, 192, pbContent, (int)cbContent, perr)) {
goto errorReturn;
}
break;
#endif
#ifdef USE_ECDH_ES_A256KW
case COSE_Algorithm_ECDH_ES_A256KW:
if (!HKDF_X(&pRecipient->m_encrypt.m_message, true, true, false,
true, COSE_Algorithm_AES_KW_256, NULL, pRecipient->m_pkey,
rgbKey, 256, 256, CBOR_CONTEXT_PARAM_COMMA perr)) {
goto errorReturn;
}
if (!AES_KW_Encrypt(
pRecipient, rgbKey, 256, pbContent, (int)cbContent, perr)) {
goto errorReturn;
}
break;
#endif
#ifdef USE_ECDH_SS_A128KW
case COSE_Algorithm_ECDH_SS_A128KW:
if (!HKDF_X(&pRecipient->m_encrypt.m_message, true, true, true,
true, COSE_Algorithm_AES_KW_128, pRecipient->m_pkeyStatic,
pRecipient->m_pkey, rgbKey, 128, 256,
CBOR_CONTEXT_PARAM_COMMA perr)) {
goto errorReturn;
}
if (!AES_KW_Encrypt(
pRecipient, rgbKey, 128, pbContent, (int)cbContent, perr)) {
goto errorReturn;
}
break;
#endif
#ifdef USE_ECDH_SS_A192KW
case COSE_Algorithm_ECDH_SS_A192KW:
if (!HKDF_X(&pRecipient->m_encrypt.m_message, true, true, true,
true, COSE_Algorithm_AES_KW_192, pRecipient->m_pkeyStatic,
pRecipient->m_pkey, rgbKey, 192, 256,
CBOR_CONTEXT_PARAM_COMMA perr)) {
goto errorReturn;
}
if (!AES_KW_Encrypt(
pRecipient, rgbKey, 192, pbContent, (int)cbContent, perr)) {
goto errorReturn;
}
break;
#endif
#ifdef USE_ECDH_SS_A256KW
case COSE_Algorithm_ECDH_SS_A256KW:
if (!HKDF_X(&pRecipient->m_encrypt.m_message, true, true, true,
true, COSE_Algorithm_AES_KW_256, pRecipient->m_pkeyStatic,
pRecipient->m_pkey, rgbKey, 256, 256,
CBOR_CONTEXT_PARAM_COMMA perr)) {
goto errorReturn;
}
if (!AES_KW_Encrypt(
pRecipient, rgbKey, 256, pbContent, (int)cbContent, perr)) {
goto errorReturn;
}
break;
#endif
default:
FAIL_CONDITION(COSE_ERR_INVALID_PARAMETER);
}
for (pri = pRecipient->m_encrypt.m_recipientFirst; pri != NULL;
pri = pri->m_recipientNext) {
if (!_COSE_Recipient_encrypt(pri, pbKey, cbKey, perr)) {
goto errorReturn;
}
}
// Figure out the clean up
fRet = true;
errorReturn:
memset(rgbKey, 0, sizeof(rgbKey));
if (pbKey != NULL) {
memset(pbKey, 0, cbKey);
COSE_FREE(pbKey, context);
}
if (pbSecret != NULL) {
COSE_FREE(pbSecret, context);
}
if (pbContext != NULL) {
COSE_FREE(pbContext, context);
}
if (pbAuthData != NULL) {
COSE_FREE(pbAuthData, context);
}
if (ptmp != NULL) {
cn_cbor_free(ptmp CBOR_CONTEXT_PARAM);
}
return fRet;
}
byte *_COSE_RecipientInfo_generateKey(COSE_RecipientInfo *pRecipient,
int algIn,
size_t cbitKeySize,
cose_errback *perr)
{
int alg;
const cn_cbor *cn_Alg = _COSE_map_get_int(&pRecipient->m_encrypt.m_message,
COSE_Header_Algorithm, COSE_BOTH, perr);
byte *pbContext = NULL;
byte *pb = NULL;
#ifdef USE_CBOR_CONTEXT
cn_cbor_context *context = &pRecipient->m_encrypt.m_message.m_allocContext;
#endif
const cn_cbor *pK;
byte *pbSecret = NULL;
CHECK_CONDITION(cn_Alg != NULL, COSE_ERR_INVALID_PARAMETER);
CHECK_CONDITION(
(cn_Alg->type == CN_CBOR_UINT) || (cn_Alg->type == CN_CBOR_INT),
COSE_ERR_INVALID_PARAMETER);
alg = (int)cn_Alg->v.uint;
_COSE_encode_protected(&pRecipient->m_encrypt.m_message, perr);
pb = COSE_CALLOC(cbitKeySize / 8, 1, context);
CHECK_CONDITION(pb != NULL, COSE_ERR_OUT_OF_MEMORY);
switch (alg) {
case COSE_Algorithm_Direct:
CHECK_CONDITION(
pRecipient->m_pkey != NULL, COSE_ERR_INVALID_PARAMETER);
pK = cn_cbor_mapget_int(pRecipient->m_pkey, -1);
CHECK_CONDITION((pK != NULL) && (pK->type == CN_CBOR_BYTES),
COSE_ERR_INVALID_PARAMETER);
CHECK_CONDITION((size_t)pK->length == cbitKeySize / 8,
COSE_ERR_INVALID_PARAMETER);
memcpy(pb, pK->v.bytes, cbitKeySize / 8);
break;
#ifdef USE_Direct_HKDF_HMAC_SHA_256
case COSE_Algorithm_Direct_HKDF_HMAC_SHA_256:
if (!HKDF_X(&pRecipient->m_encrypt.m_message, true, false, false,
true, algIn, pRecipient->m_pkey, NULL, pb, cbitKeySize, 256,
CBOR_CONTEXT_PARAM_COMMA perr)) {
goto errorReturn;
}
break;
#endif
#ifdef USE_Direct_HKDF_HMAC_SHA_512
case COSE_Algorithm_Direct_HKDF_HMAC_SHA_512:
if (!HKDF_X(&pRecipient->m_encrypt.m_message, true, false, false,
true, algIn, pRecipient->m_pkey, NULL, pb, cbitKeySize, 512,
CBOR_CONTEXT_PARAM_COMMA perr)) {
goto errorReturn;
}
break;
#endif
#ifdef USE_Direct_HKDF_AES_128
case COSE_Algorithm_Direct_HKDF_AES_128:
if (!HKDF_X(&pRecipient->m_encrypt.m_message, false, false, false,
true, algIn, pRecipient->m_pkey, NULL, pb, cbitKeySize, 128,
CBOR_CONTEXT_PARAM_COMMA perr)) {
goto errorReturn;
}
break;
#endif
#ifdef USE_Direct_HKDF_AES_256
case COSE_Algorithm_Direct_HKDF_AES_256:
if (!HKDF_X(&pRecipient->m_encrypt.m_message, false, false, false,
true, algIn, pRecipient->m_pkey, NULL, pb, cbitKeySize, 256,
CBOR_CONTEXT_PARAM_COMMA perr)) {
goto errorReturn;
}
break;
#endif
#ifdef USE_ECDH_ES_HKDF_256
case COSE_Algorithm_ECDH_ES_HKDF_256:
if (!HKDF_X(&pRecipient->m_encrypt.m_message, true, true, false,
true, algIn, NULL, pRecipient->m_pkey, pb, cbitKeySize, 256,
CBOR_CONTEXT_PARAM_COMMA perr)) {
goto errorReturn;
}
break;
#endif
#ifdef USE_ECDH_ES_HKDF_512
case COSE_Algorithm_ECDH_ES_HKDF_512:
if (!HKDF_X(&pRecipient->m_encrypt.m_message, true, true, false,
true, algIn, NULL, pRecipient->m_pkey, pb, cbitKeySize, 512,
CBOR_CONTEXT_PARAM_COMMA perr)) {
goto errorReturn;
}
break;
#endif
#ifdef USE_ECDH_SS_HKDF_256
case COSE_Algorithm_ECDH_SS_HKDF_256:
if (!HKDF_X(&pRecipient->m_encrypt.m_message, true, true, true,
true, algIn, pRecipient->m_pkeyStatic, pRecipient->m_pkey,
pb, cbitKeySize, 256, CBOR_CONTEXT_PARAM_COMMA perr)) {
goto errorReturn;
}
break;
#endif
#ifdef USE_ECDH_SS_HKDF_512
case COSE_Algorithm_ECDH_SS_HKDF_512:
if (!HKDF_X(&pRecipient->m_encrypt.m_message, true, true, true,
true, algIn, pRecipient->m_pkeyStatic, pRecipient->m_pkey,
pb, cbitKeySize, 512, CBOR_CONTEXT_PARAM_COMMA perr)) {
goto errorReturn;
}
break;
#endif
default:
FAIL_CONDITION(COSE_ERR_INVALID_PARAMETER);
}
if (pbSecret != NULL) {
COSE_FREE(pbSecret, context);
}
if (pbContext != NULL) {
COSE_FREE(pbContext, context);
}
return pb;
errorReturn:
if (pbSecret != NULL) {
COSE_FREE(pbSecret, context);
}
if (pbContext != NULL) {
COSE_FREE(pbContext, context);
}
if (pb != NULL) {
COSE_FREE(pb, context);
}
return NULL;
}
#endif
#if INCLUDE_ENCRYPT || INCLUDE_MAC
bool COSE_Recipient_SetKey_secret(HCOSE_RECIPIENT hRecipient,
const byte *rgbKey,
int cbKey,
const byte *rgbKid,
int cbKid,
cose_errback *perr)
{
COSE_RecipientInfo *p;
cn_cbor *cn_Temp = NULL;
cn_cbor *cnTemp = NULL;
cn_cbor_errback cbor_error;
byte *pbTemp = NULL;
byte *pbKey = NULL;
#ifdef USE_CBOR_CONTEXT
cn_cbor_context *context = NULL;
#endif
CHECK_CONDITION(
IsValidRecipientHandle(hRecipient), COSE_ERR_INVALID_HANDLE);
CHECK_CONDITION(rgbKey != NULL, COSE_ERR_INVALID_PARAMETER);
p = (COSE_RecipientInfo *)hRecipient;
#ifdef USE_CBOR_CONTEXT
context = &p->m_encrypt.m_message.m_allocContext;
#endif
cn_cbor *cnAlg = _COSE_map_get_int(
&p->m_encrypt.m_message, COSE_Header_Algorithm, COSE_BOTH, perr);
if (cnAlg != NULL) {
CHECK_CONDITION(cnAlg->type == CN_CBOR_INT &&
cnAlg->v.sint == COSE_Algorithm_Direct,
COSE_ERR_INVALID_PARAMETER);
}
else {
cn_Temp = cn_cbor_int_create(
COSE_Algorithm_Direct, CBOR_CONTEXT_PARAM_COMMA & cbor_error);
CHECK_CONDITION_CBOR(cn_Temp != NULL, cbor_error);
if (!COSE_Recipient_map_put_int(hRecipient, COSE_Header_Algorithm,
cn_Temp, COSE_UNPROTECT_ONLY, perr)) {
goto errorReturn;
}
cn_Temp = NULL;
}
if (cbKid > 0) {
pbTemp = (byte *)COSE_CALLOC(cbKid, 1, context);
CHECK_CONDITION(pbTemp != NULL, COSE_ERR_OUT_OF_MEMORY);
memcpy(pbTemp, rgbKid, cbKid);
cnTemp = cn_cbor_data_create(
pbTemp, cbKid, CBOR_CONTEXT_PARAM_COMMA & cbor_error);
CHECK_CONDITION_CBOR(cnTemp != NULL, cbor_error);
pbTemp = NULL;
if (!COSE_Recipient_map_put_int(hRecipient, COSE_Header_KID, cnTemp,
COSE_UNPROTECT_ONLY, perr)) {
goto errorReturn;
}
}
pbKey = (byte *)COSE_CALLOC(cbKey, 1, context);
CHECK_CONDITION(pbKey != NULL, COSE_ERR_OUT_OF_MEMORY);
memcpy(pbKey, rgbKey, cbKey);
cn_Temp = cn_cbor_map_create(CBOR_CONTEXT_PARAM_COMMA & cbor_error);
CHECK_CONDITION_CBOR(cn_Temp != NULL, cbor_error);
cnTemp = cn_cbor_int_create(4, CBOR_CONTEXT_PARAM_COMMA & cbor_error);
CHECK_CONDITION_CBOR(cnTemp != NULL, cbor_error);
CHECK_CONDITION_CBOR(cn_cbor_mapput_int(cn_Temp, COSE_Key_Type, cnTemp,
CBOR_CONTEXT_PARAM_COMMA & cbor_error),
cbor_error);
cnTemp = NULL;
cnTemp = cn_cbor_data_create(
pbKey, cbKey, CBOR_CONTEXT_PARAM_COMMA & cbor_error);
CHECK_CONDITION_CBOR(cnTemp != NULL, cbor_error);
pbKey = NULL;
CHECK_CONDITION_CBOR(cn_cbor_mapput_int(cn_Temp, -1, cnTemp,
CBOR_CONTEXT_PARAM_COMMA & cbor_error),
cbor_error);
cnTemp = NULL;
if (!COSE_Recipient_SetKey(hRecipient, cn_Temp, perr)) {
goto errorReturn;
}
cn_Temp = NULL;
return true;
errorReturn:
if (cn_Temp != NULL) {
CN_CBOR_FREE(cn_Temp, context);
}
if (cnTemp != NULL) {
CN_CBOR_FREE(cnTemp, context);
}
if (pbTemp != NULL) {
COSE_FREE(pbTemp, context);
}
if (pbKey != NULL) {
COSE_FREE(pbKey, context);
}
return false;
}
bool COSE_Recipient_SetKey(HCOSE_RECIPIENT h,
const cn_cbor *pKey,
cose_errback *perr)
{
COSE_RecipientInfo *p;
CHECK_CONDITION(IsValidRecipientHandle(h), COSE_ERR_INVALID_HANDLE);
CHECK_CONDITION(pKey != NULL, COSE_ERR_INVALID_PARAMETER);
p = (COSE_RecipientInfo *)h;
if (p->m_pkey != NULL) {
CN_CBOR_FREE((cn_cbor *) p->m_pkey, &p->m_encrypt.m_message.m_allocContext);
}
p->m_pkey = pKey;
return true;
errorReturn:
return false;
}
/*!
* @brief Set the senders static key for ECDH key agreement algorithms
*
* Set the Static private key to be used in computing ECDH key agreement
* operation.
*
* Private portion of the key is not zeroed when the recipient object is
* released.
*
* @param h Handle to the recipient object
* @param pKey pointer to COSE key structure contiaing the private key
* @param destination 0 - set nothing, 1 - set spk_kid, 2 - set spk
* @param perr location for return of error code
* @return true on success
*/
bool COSE_Recipient_SetSenderKey(HCOSE_RECIPIENT h,
const cn_cbor *pKey,
int destination,
cose_errback *perr)
{
COSE_RecipientInfo *p;
bool f = false;
cn_cbor *cn;
cn_cbor *cn2 = NULL;
cn_cbor *cn3 = NULL;
cn_cbor_errback cbor_err;
#ifdef USE_CBOR_CONTEXT
cn_cbor_context *context = NULL;
#endif
CHECK_CONDITION(IsValidRecipientHandle(h), COSE_ERR_INVALID_HANDLE);
CHECK_CONDITION(pKey != NULL, COSE_ERR_INVALID_PARAMETER);
p = (COSE_RecipientInfo *)h;
#ifdef USE_CBOR_CONTEXT
context = &p->m_encrypt.m_message.m_allocContext;
#endif
switch (destination) {
case 0:
break;
case 1:
cn = cn_cbor_mapget_int(pKey, COSE_Key_ID);
CHECK_CONDITION(cn != NULL, COSE_ERR_INVALID_PARAMETER);
cn2 = cn_cbor_clone(cn, CBOR_CONTEXT_PARAM_COMMA & cbor_err);
CHECK_CONDITION_CBOR(cn2 != NULL, cbor_err);
CHECK_CONDITION(
_COSE_map_put(&p->m_encrypt.m_message, COSE_Header_ECDH_SPK_KID,
cn2, COSE_UNPROTECT_ONLY, perr),
perr->err);
cn2 = NULL;
break;
case 2:
cn2 = cn_cbor_map_create(CBOR_CONTEXT_PARAM_COMMA & cbor_err);
CHECK_CONDITION_CBOR(cn2 != NULL, cbor_err);
cn = cn_cbor_mapget_int(pKey, COSE_Key_Type);
CHECK_CONDITION(cn != NULL, COSE_ERR_INVALID_PARAMETER);
cn3 = cn_cbor_clone(cn, CBOR_CONTEXT_PARAM_COMMA & cbor_err);
CHECK_CONDITION_CBOR(cn3 != NULL, cbor_err);
CHECK_CONDITION_CBOR(cn_cbor_mapput_int(cn2, COSE_Key_Type, cn3,
CBOR_CONTEXT_PARAM_COMMA & cbor_err),
cbor_err);
cn3 = NULL;
cn = cn_cbor_mapget_int(pKey, COSE_Key_EC2_Curve);
cn3 = cn_cbor_clone(cn, CBOR_CONTEXT_PARAM_COMMA & cbor_err);
CHECK_CONDITION_CBOR(cn3 != NULL, cbor_err);
CHECK_CONDITION_CBOR(cn_cbor_mapput_int(cn2, COSE_Key_EC2_Curve,
cn3, CBOR_CONTEXT_PARAM_COMMA & cbor_err),
cbor_err);
cn3 = NULL;
cn = cn_cbor_mapget_int(pKey, COSE_Key_EC2_X);
cn3 = cn_cbor_clone(cn, CBOR_CONTEXT_PARAM_COMMA & cbor_err);
CHECK_CONDITION_CBOR(cn3 != NULL, cbor_err);
CHECK_CONDITION_CBOR(cn_cbor_mapput_int(cn2, COSE_Key_EC2_X, cn3,
CBOR_CONTEXT_PARAM_COMMA & cbor_err),
cbor_err);
cn3 = NULL;
cn = cn_cbor_mapget_int(pKey, COSE_Key_EC2_Y);
cn3 = cn_cbor_clone(cn, CBOR_CONTEXT_PARAM_COMMA & cbor_err);
CHECK_CONDITION_CBOR(cn3 != NULL, cbor_err);
CHECK_CONDITION_CBOR(cn_cbor_mapput_int(cn2, COSE_Key_EC2_Y, cn3,
CBOR_CONTEXT_PARAM_COMMA & cbor_err),
cbor_err);
cn3 = NULL;
CHECK_CONDITION(
_COSE_map_put(&p->m_encrypt.m_message, COSE_Header_ECDH_SPK,
cn2, COSE_UNPROTECT_ONLY, perr),
perr->err);
cn2 = NULL;
break;
default:
FAIL_CONDITION(COSE_ERR_INVALID_PARAMETER);
}
p->m_pkeyStatic = pKey;
f = true;
errorReturn:
if (cn2 != NULL) {
CN_CBOR_FREE(cn2, context);
}
if (cn3 != NULL) {
CN_CBOR_FREE(cn3, context);
}
return f;
}
/*!
* @brief Set the application external data for authentication
*
* Recipient data objects support the authentication of external application
* supplied data. This function is provided to supply that data to the library.
*
* The external data is not copied, nor will be it freed when the handle is
* released.
*
* @param hcose Handle for the COSE recipient data object
* @param pbEternalData point to the external data
* @param cbExternalData size of the external data
* @param perr location to return errors
* @return result of the operation.
*/
bool COSE_Recipient_SetExternal(HCOSE_RECIPIENT hcose,
const byte *pbExternalData,
size_t cbExternalData,
cose_errback *perr)
{
if (!IsValidRecipientHandle(hcose)) {
if (perr != NULL) {
perr->err = COSE_ERR_INVALID_HANDLE;
}
return false;
}
return _COSE_SetExternal(
&((COSE_RecipientInfo *)hcose)->m_encrypt.m_message, pbExternalData,
cbExternalData, perr);
}
bool COSE_Recipient_map_put_int(HCOSE_RECIPIENT h,
int key,
cn_cbor *value,
int flags,
cose_errback *perr)
{
CHECK_CONDITION(IsValidRecipientHandle(h), COSE_ERR_INVALID_HANDLE);
CHECK_CONDITION(value != NULL, COSE_ERR_INVALID_PARAMETER);
if (!_COSE_map_put(&((COSE_RecipientInfo *)h)->m_encrypt.m_message, key,
value, flags, perr)) {
return false;
}
if (key == COSE_Header_Algorithm) {
if (value->type == CN_CBOR_INT) {
switch (value->v.uint) {
case COSE_Algorithm_Direct:
#ifdef USE_Direct_HKDF_AES_128
case COSE_Algorithm_Direct_HKDF_AES_128:
#endif
#ifdef USE_Direct_HKDF_AES_256
case COSE_Algorithm_Direct_HKDF_AES_256:
#endif
#ifdef USE_Direct_HKDF_HMAC_SHA_256
case COSE_Algorithm_Direct_HKDF_HMAC_SHA_256:
#endif
#ifdef USE_Direct_HKDF_HMAC_SHA_512
case COSE_Algorithm_Direct_HKDF_HMAC_SHA_512:
#endif
#ifdef USE_ECDH_ES_HKDF_256
case COSE_Algorithm_ECDH_ES_HKDF_256:
#endif
#ifdef USE_ECDH_ES_HKDF_512
case COSE_Algorithm_ECDH_ES_HKDF_512:
#endif
#ifdef USE_ECDH_SS_HKDF_256
case COSE_Algorithm_ECDH_SS_HKDF_256:
#endif
#ifdef USE_ECDH_SS_HKDF_512
case COSE_Algorithm_ECDH_SS_HKDF_512:
#endif
((COSE_RecipientInfo *)h)->m_encrypt.m_message.m_flags |= 1;
break;
default:
((COSE_RecipientInfo *)h)->m_encrypt.m_message.m_flags &=
~1;
break;
}
}
else {
((COSE_RecipientInfo *)h)->m_encrypt.m_message.m_flags &= ~1;
}
}
return true;
errorReturn:
return false;
}
#endif
#if INCLUDE_ENCRYPT || INCLUDE_ENCRYPT0 || INCLUDE_MAC || INCLUDE_MAC0
static bool BuildContextBytes(COSE *pcose,
int algID,
size_t cbitKey,
byte **ppbContext,
size_t *pcbContext,
CBOR_CONTEXT_COMMA cose_errback *perr)
{
cn_cbor *pArray;
cn_cbor_errback cbor_error;
bool fReturn = false;
cn_cbor *cnT = NULL;
cn_cbor *cnArrayT = NULL;
cn_cbor *cnParam;
byte *pbContext = NULL;
pArray = cn_cbor_array_create(CBOR_CONTEXT_PARAM_COMMA & cbor_error);
CHECK_CONDITION_CBOR(pArray != NULL, cbor_error);
cnT = cn_cbor_int_create(algID, CBOR_CONTEXT_PARAM_COMMA & cbor_error);
CHECK_CONDITION_CBOR(cnT != NULL, cbor_error);
CHECK_CONDITION_CBOR(
cn_cbor_array_append(pArray, cnT, &cbor_error), cbor_error);
cnT = NULL;
cnArrayT = cn_cbor_array_create(CBOR_CONTEXT_PARAM_COMMA & cbor_error);
CHECK_CONDITION_CBOR(cnArrayT != NULL, cbor_error);
cnParam = _COSE_map_get_int(pcose, COSE_Header_KDF_U_name, COSE_BOTH, perr);
if (cnParam != NULL) {
cnT = cn_cbor_clone(cnParam, CBOR_CONTEXT_PARAM_COMMA & cbor_error);
}
else {
cnT = cn_cbor_null_create(CBOR_CONTEXT_PARAM_COMMA &cbor_error);
}
CHECK_CONDITION_CBOR(cnT != NULL, cbor_error);
CHECK_CONDITION_CBOR(
cn_cbor_array_append(cnArrayT, cnT, &cbor_error), cbor_error);
cnT = NULL;
cnParam = NULL;
cnParam =
_COSE_map_get_int(pcose, COSE_Header_KDF_U_nonce, COSE_BOTH, perr);
if (cnParam != NULL) {
cnT = cn_cbor_clone(cnParam, CBOR_CONTEXT_PARAM_COMMA & cbor_error);
}
else {
cnT = cn_cbor_null_create(CBOR_CONTEXT_PARAM_COMMA & cbor_error);
}
CHECK_CONDITION_CBOR(cnT != NULL, cbor_error);
CHECK_CONDITION_CBOR(
cn_cbor_array_append(cnArrayT, cnT, &cbor_error), cbor_error);
cnT = NULL;
cnParam = NULL;
cnParam =
_COSE_map_get_int(pcose, COSE_Header_KDF_U_other, COSE_BOTH, perr);
if (cnParam != NULL) {
cnT = cn_cbor_clone(cnParam, CBOR_CONTEXT_PARAM_COMMA & cbor_error);
}
else {
cnT = cn_cbor_null_create(CBOR_CONTEXT_PARAM_COMMA & cbor_error);
}
CHECK_CONDITION_CBOR(cnT != NULL, cbor_error);
CHECK_CONDITION_CBOR(
cn_cbor_array_append(cnArrayT, cnT, &cbor_error), cbor_error);
cnT = NULL;
cnParam = NULL;
CHECK_CONDITION_CBOR(
cn_cbor_array_append(pArray, cnArrayT, &cbor_error), cbor_error);
cnArrayT = NULL;
cnArrayT = cn_cbor_array_create(CBOR_CONTEXT_PARAM_COMMA & cbor_error);
CHECK_CONDITION_CBOR(cnArrayT != NULL, cbor_error);
cnParam = _COSE_map_get_int(pcose, COSE_Header_KDF_V_name, COSE_BOTH, perr);
if (cnParam != NULL) {
cnT = cn_cbor_clone(cnParam, CBOR_CONTEXT_PARAM_COMMA & cbor_error);
}
else {
cnT = cn_cbor_null_create(CBOR_CONTEXT_PARAM_COMMA & cbor_error);
}
CHECK_CONDITION_CBOR(cnT != NULL, cbor_error);
CHECK_CONDITION_CBOR(
cn_cbor_array_append(cnArrayT, cnT, &cbor_error), cbor_error);
cnT = NULL;
cnParam = NULL;
cnParam =
_COSE_map_get_int(pcose, COSE_Header_KDF_V_nonce, COSE_BOTH, perr);
if (cnParam != NULL) {
cnT = cn_cbor_clone(cnParam, CBOR_CONTEXT_PARAM_COMMA & cbor_error);
}
else {
cnT = cn_cbor_null_create(CBOR_CONTEXT_PARAM_COMMA & cbor_error);
}
CHECK_CONDITION_CBOR(cnT != NULL, cbor_error);
CHECK_CONDITION_CBOR(
cn_cbor_array_append(cnArrayT, cnT, &cbor_error), cbor_error);
cnT = NULL;
cnParam = NULL;
cnParam =
_COSE_map_get_int(pcose, COSE_Header_KDF_V_other, COSE_BOTH, perr);
if (cnParam != NULL) {
cnT = cn_cbor_clone(cnParam, CBOR_CONTEXT_PARAM_COMMA & cbor_error);
}
else {
cnT = cn_cbor_null_create(CBOR_CONTEXT_PARAM_COMMA & cbor_error);
}
CHECK_CONDITION_CBOR(cnT != NULL, cbor_error);
CHECK_CONDITION_CBOR(
cn_cbor_array_append(cnArrayT, cnT, &cbor_error), cbor_error);
cnT = NULL;
cnParam = NULL;
CHECK_CONDITION_CBOR(
cn_cbor_array_append(pArray, cnArrayT, &cbor_error), cbor_error);
cnArrayT = NULL;
cnArrayT = cn_cbor_array_create(CBOR_CONTEXT_PARAM_COMMA & cbor_error);
CHECK_CONDITION_CBOR(cnArrayT != NULL, cbor_error);
cnT = cn_cbor_int_create(cbitKey, CBOR_CONTEXT_PARAM_COMMA & cbor_error);
CHECK_CONDITION_CBOR(cnT != NULL, cbor_error);
CHECK_CONDITION_CBOR(
cn_cbor_array_append(cnArrayT, cnT, &cbor_error), cbor_error);
cnT = NULL;
cnParam = _COSE_arrayget_int(pcose, INDEX_PROTECTED);
if (cnParam != NULL) {
cnT = cn_cbor_clone(cnParam, CBOR_CONTEXT_PARAM_COMMA & cbor_error);
CHECK_CONDITION_CBOR(cnT != NULL, cbor_error);
CHECK_CONDITION_CBOR(
cn_cbor_array_append(cnArrayT, cnT, &cbor_error), cbor_error);
cnT = NULL;
cnParam = NULL;
}
cnParam =
_COSE_map_get_int(pcose, COSE_Header_KDF_PUB_other, COSE_BOTH, perr);
if (cnParam != NULL) {
cnT = cn_cbor_clone(cnParam, CBOR_CONTEXT_PARAM_COMMA & cbor_error);
CHECK_CONDITION_CBOR(cnT != NULL, cbor_error);
CHECK_CONDITION_CBOR(
cn_cbor_array_append(cnArrayT, cnT, &cbor_error), cbor_error);
cnT = NULL;
cnParam = NULL;
}
CHECK_CONDITION_CBOR(
cn_cbor_array_append(pArray, cnArrayT, &cbor_error), cbor_error);
cnArrayT = NULL;
cnParam = _COSE_map_get_int(pcose, COSE_Header_KDF_PRIV, COSE_BOTH, perr);
if (cnParam != NULL) {
cnT = cn_cbor_clone(cnParam, CBOR_CONTEXT_PARAM_COMMA & cbor_error);
CHECK_CONDITION_CBOR(cnT != NULL, cbor_error);
CHECK_CONDITION_CBOR(
cn_cbor_array_append(pArray, cnT, &cbor_error), cbor_error);
cnT = NULL;
cnParam = NULL;
}
size_t cbContext = cn_cbor_encode_size(pArray);
CHECK_CONDITION(cbContext > 0, COSE_ERR_CBOR);
pbContext = (byte *)COSE_CALLOC(cbContext, 1, context);
CHECK_CONDITION(pbContext != NULL, COSE_ERR_OUT_OF_MEMORY);
CHECK_CONDITION(cn_cbor_encoder_write(pbContext, 0, cbContext, pArray) ==
(ssize_t)cbContext,
COSE_ERR_CBOR);
*ppbContext = pbContext;
*pcbContext = cbContext;
pbContext = NULL;
fReturn = true;
returnHere:
if (pbContext != NULL) {
COSE_FREE(pbContext, context);
}
if (pArray != NULL) {
CN_CBOR_FREE(pArray, context);
}
if (cnArrayT != NULL) {
CN_CBOR_FREE(cnArrayT, context);
}
if (cnT != NULL) {
CN_CBOR_FREE(cnT, context);
}
return fReturn;
errorReturn:
fReturn = false;
goto returnHere;
}
#endif
#if INCLUDE_ENCRYPT || INCLUDE_MAC
/*! brief Retrieve header parameter from a recipient structure
*
* Retrieve a header parameter from the message.
* Retrieved object is the same as the one in the message - do not delete it
*
* @param[in] h Handle of recipient object
* @param[in] key Key to look for
* @param[in] flags What buckets should we look for the message
* @param[out] perror Location to return error codes
* @return Object which is found or NULL
*/
cn_cbor *COSE_Recipient_map_get_int(HCOSE_RECIPIENT h,
int key,
int flags,
cose_errback *perror)
{
if (!IsValidRecipientHandle(h)) {
if (perror != NULL) {
perror->err = COSE_ERR_INVALID_HANDLE;
}
return NULL;
}
return _COSE_map_get_int(
&((COSE_RecipientInfo *)h)->m_encrypt.m_message, key, flags, perror);
}
HCOSE_RECIPIENT COSE_Recipient_GetRecipient(HCOSE_RECIPIENT cose,
int iRecipient,
cose_errback *perr)
{
int i;
COSE_RecipientInfo *p = NULL;
CHECK_CONDITION(IsValidRecipientHandle(cose), COSE_ERR_INVALID_HANDLE);
CHECK_CONDITION(iRecipient >= 0, COSE_ERR_INVALID_PARAMETER);
p = ((COSE_RecipientInfo *)cose)->m_encrypt.m_recipientFirst;
for (i = 0; i < iRecipient; i++) {
CHECK_CONDITION(p != NULL, COSE_ERR_INVALID_PARAMETER);
p = p->m_recipientNext;
}
if (p != NULL) {
p->m_encrypt.m_message.m_refCount++;
}
errorReturn:
return (HCOSE_RECIPIENT)p;
}
bool COSE_Recipient_AddRecipient(HCOSE_RECIPIENT hEnc,
HCOSE_RECIPIENT hRecip,
cose_errback *perr)
{
COSE_RecipientInfo *pRecip;
COSE_Enveloped *pEncrypt;
cn_cbor *pRecipients = NULL;
#ifdef USE_CBOR_CONTEXT
cn_cbor_context *context;
#endif
cn_cbor_errback cbor_error;
CHECK_CONDITION(IsValidRecipientHandle(hEnc), COSE_ERR_INVALID_HANDLE);
CHECK_CONDITION(IsValidRecipientHandle(hRecip), COSE_ERR_INVALID_HANDLE);
pEncrypt = &((COSE_RecipientInfo *)hEnc)->m_encrypt;
pRecip = (COSE_RecipientInfo *)hRecip;
#ifdef USE_CBOR_CONTEXT
context = &pEncrypt->m_message.m_allocContext;
#endif // USE_CBOR_CONTEXT
pRecip->m_recipientNext = pEncrypt->m_recipientFirst;
pEncrypt->m_recipientFirst = pRecip;
pRecipients = _COSE_arrayget_int(&pEncrypt->m_message, INDEX_RECIPIENTS);
if (pRecipients == NULL) {
pRecipients =
cn_cbor_array_create(CBOR_CONTEXT_PARAM_COMMA & cbor_error);
CHECK_CONDITION_CBOR(pRecipients != NULL, cbor_error);
if (!_COSE_array_replace(&pEncrypt->m_message, pRecipients,
INDEX_RECIPIENTS, CBOR_CONTEXT_PARAM_COMMA & cbor_error)) {
CN_CBOR_FREE(pRecipients, context);
if (perr != NULL) {
perr->err = _MapFromCBOR(cbor_error);
}
goto errorReturn;
}
}
CHECK_CONDITION_CBOR(cn_cbor_array_append(pRecipients,
pRecip->m_encrypt.m_message.m_cbor, &cbor_error),
cbor_error);
pRecip->m_encrypt.m_message.m_refCount++;
return true;
errorReturn:
return false;
}
#endif