blob: 0874bc9d74fcd07b4fbc0dcb2081fb41a92d2cde [file] [log] [blame]
/** \file SignerInfo.c
* Contains implementation of the functions related to HCOSE_SIGNER handle
* objects.
*/
#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_SIGN || INCLUDE_COUNTERSIGNATURE
#if INCLUDE_SIGN
COSE *SignerRoot = nullptr;
bool IsValidSignerHandle(HCOSE_SIGNER h)
{
COSE_SignerInfo *p = (COSE_SignerInfo *)h;
return _COSE_IsInList(SignerRoot, (COSE *)p);
}
#endif
bool _COSE_SignerInfo_Release(COSE_SignerInfo *pSigner)
{
// Check ref counting
if (pSigner->m_message.m_refCount > 1) {
pSigner->m_message.m_refCount--;
return true;
}
_COSE_Release(&pSigner->m_message);
if (pSigner->m_pkey != nullptr) {
COSE_KEY_Free((HCOSE_KEY)pSigner->m_pkey);
}
return true;
}
#if INCLUDE_SIGN
bool COSE_Signer_Free(HCOSE_SIGNER hSigner)
{
COSE_SignerInfo *pSigner = (COSE_SignerInfo *)hSigner;
bool fRet = false;
if (!IsValidSignerHandle(hSigner)) {
goto errorReturn;
}
if (pSigner->m_message.m_refCount > 1) {
pSigner->m_message.m_refCount--;
return true;
}
_COSE_SignerInfo_Release(pSigner);
_COSE_RemoveFromList(&SignerRoot, &pSigner->m_message);
COSE_FREE(pSigner, &pSigner->m_message.m_allocContext);
fRet = true;
errorReturn:
return fRet;
}
HCOSE_SIGNER COSE_Signer_Init(CBOR_CONTEXT_COMMA cose_errback *perror)
{
COSE_SignerInfo *pobj =
(COSE_SignerInfo *)COSE_CALLOC(1, sizeof(COSE_SignerInfo), context);
if (pobj == nullptr) {
if (perror != nullptr) {
perror->err = COSE_ERR_OUT_OF_MEMORY;
}
return nullptr;
}
if (!_COSE_SignerInfo_Init(COSE_INIT_FLAGS_NO_CBOR_TAG, pobj,
COSE_recipient_object, CBOR_CONTEXT_PARAM_COMMA perror)) {
_COSE_SignerInfo_Release(pobj);
COSE_FREE(pobj, context);
return nullptr;
}
_COSE_InsertInList(&SignerRoot, &pobj->m_message);
return (HCOSE_SIGNER)pobj;
}
#endif
bool _COSE_SignerInfo_Init(COSE_INIT_FLAGS flags,
COSE_SignerInfo *pobj,
int msgType,
CBOR_CONTEXT_COMMA cose_errback *errp)
{
return _COSE_Init(
flags, &pobj->m_message, msgType, CBOR_CONTEXT_PARAM_COMMA errp);
}
COSE_SignerInfo *_COSE_SignerInfo_Init_From_Object(cn_cbor *cbor,
COSE_SignerInfo *pIn,
CBOR_CONTEXT_COMMA cose_errback *perr)
{
COSE_SignerInfo *pSigner = pIn;
if (pSigner == nullptr) {
pSigner =
(COSE_SignerInfo *)COSE_CALLOC(1, sizeof(COSE_SignerInfo), context);
CHECK_CONDITION(pSigner != nullptr, COSE_ERR_OUT_OF_MEMORY);
}
CHECK_CONDITION(cbor->type == CN_CBOR_ARRAY, COSE_ERR_INVALID_PARAMETER);
if (!_COSE_Init_From_Object(
&pSigner->m_message, cbor, CBOR_CONTEXT_PARAM_COMMA perr)) {
goto errorReturn;
}
#if INCLUDE_SIGN
if (pIn == nullptr) {
_COSE_InsertInList(&SignerRoot, &pSigner->m_message);
}
#endif
return pSigner;
errorReturn:
if (pSigner != nullptr && pIn == nullptr) {
_COSE_SignerInfo_Release(pSigner);
COSE_FREE(pSigner, context);
}
return nullptr;
}
static bool BuildToBeSigned(byte **ppbToSign,
size_t *pcbToSign,
const cn_cbor *pcborBody,
const cn_cbor *pcborProtected,
const cn_cbor *pcborProtectedSign,
const byte *pbExternal,
size_t cbExternal,
const char *const contextString,
CBOR_CONTEXT_COMMA cose_errback *perr)
{
cn_cbor *pArray = nullptr;
cn_cbor_errback cbor_error;
size_t cbToSign;
byte *pbToSign = nullptr;
bool f = false;
cn_cbor *cn = nullptr;
if (false) {
errorReturn:
if (cn != nullptr) {
CN_CBOR_FREE(cn, context);
}
if (pArray != nullptr) {
CN_CBOR_FREE(pArray, context);
}
if (pbToSign != nullptr) {
COSE_FREE(pbToSign, context);
}
return f;
}
pArray = cn_cbor_array_create(CBOR_CONTEXT_PARAM_COMMA & cbor_error);
CHECK_CONDITION_CBOR(pArray != nullptr, cbor_error);
cn = cn_cbor_string_create(
contextString, CBOR_CONTEXT_PARAM_COMMA & cbor_error);
CHECK_CONDITION_CBOR(cn != nullptr, cbor_error);
CHECK_CONDITION_CBOR(
cn_cbor_array_append(pArray, cn, &cbor_error), cbor_error);
cn = nullptr;
if (pcborProtected->length == 1 && (pcborProtected->v.bytes[0] == 0xa0)) {
cn =
cn_cbor_data_create(nullptr, 0, CBOR_CONTEXT_PARAM_COMMA & cbor_error);
}
else {
cn = cn_cbor_data_create(pcborProtected->v.bytes,
(int)pcborProtected->length, CBOR_CONTEXT_PARAM_COMMA & cbor_error);
}
CHECK_CONDITION_CBOR(cn != nullptr, cbor_error);
CHECK_CONDITION_CBOR(
cn_cbor_array_append(pArray, cn, &cbor_error), cbor_error);
cn = nullptr;
if ((pcborProtectedSign->length == 1) &&
(pcborProtectedSign->v.bytes[0] == 0xa0)) {
cn =
cn_cbor_data_create(nullptr, 0, CBOR_CONTEXT_PARAM_COMMA & cbor_error);
}
else {
cn = cn_cbor_data_create(pcborProtectedSign->v.bytes,
(int)pcborProtectedSign->length,
CBOR_CONTEXT_PARAM_COMMA & cbor_error);
}
CHECK_CONDITION_CBOR(cn != nullptr, cbor_error);
CHECK_CONDITION_CBOR(
cn_cbor_array_append(pArray, cn, &cbor_error), cbor_error);
cn = nullptr;
cn = cn_cbor_data_create(
pbExternal, (int)cbExternal, CBOR_CONTEXT_PARAM_COMMA & cbor_error);
CHECK_CONDITION_CBOR(cn != nullptr, cbor_error);
CHECK_CONDITION_CBOR(
cn_cbor_array_append(pArray, cn, &cbor_error), cbor_error);
cn = nullptr;
cn = cn_cbor_data_create(pcborBody->v.bytes, (int)pcborBody->length,
CBOR_CONTEXT_PARAM_COMMA & cbor_error);
CHECK_CONDITION_CBOR(cn != nullptr, cbor_error);
CHECK_CONDITION_CBOR(
cn_cbor_array_append(pArray, cn, &cbor_error), cbor_error);
cn = nullptr;
cbToSign = cn_cbor_encode_size(pArray);
CHECK_CONDITION(cbToSign > 0, COSE_ERR_CBOR);
pbToSign = (byte *)COSE_CALLOC(cbToSign, 1, context);
CHECK_CONDITION(pbToSign != nullptr, COSE_ERR_OUT_OF_MEMORY);
const ssize_t writtenBits =
cn_cbor_encoder_write(pbToSign, 0, cbToSign, pArray);
CHECK_CONDITION(writtenBits >= 0, COSE_ERR_CBOR);
CHECK_CONDITION((size_t)writtenBits == cbToSign, COSE_ERR_CBOR);
*ppbToSign = pbToSign;
*pcbToSign = cbToSign;
pbToSign = nullptr;
f = true;
goto errorReturn;
}
bool _COSE_Signer_sign(COSE_SignerInfo *pSigner,
const cn_cbor *pcborBody,
const cn_cbor *pcborProtected,
const char *const contextString,
cose_errback *perr)
{
#ifdef USE_CBOR_CONTEXT
cn_cbor_context *context = &pSigner->m_message.m_allocContext;
#endif
cn_cbor *pcborProtectedSign = nullptr;
cn_cbor *pArray = nullptr;
cn_cbor *cnAlgorithm = nullptr;
size_t cbToSign;
byte *pbToSign = nullptr;
int alg;
bool fRet = false;
pArray = cn_cbor_array_create(CBOR_CONTEXT_PARAM_COMMA nullptr);
CHECK_CONDITION(pArray != nullptr, COSE_ERR_OUT_OF_MEMORY);
cnAlgorithm = _COSE_map_get_int(
&pSigner->m_message, COSE_Header_Algorithm, COSE_BOTH, perr);
if (cnAlgorithm == nullptr) {
goto errorReturn;
}
if (cnAlgorithm->type == CN_CBOR_TEXT) {
FAIL_CONDITION(COSE_ERR_UNKNOWN_ALGORITHM);
}
else {
CHECK_CONDITION((cnAlgorithm->type == CN_CBOR_UINT ||
cnAlgorithm->type == CN_CBOR_INT),
COSE_ERR_INVALID_PARAMETER);
alg = (int)cnAlgorithm->v.sint;
}
pcborProtectedSign = _COSE_encode_protected(&pSigner->m_message, perr);
if (pcborProtectedSign == nullptr) {
goto errorReturn;
}
if (!BuildToBeSigned(&pbToSign, &cbToSign, pcborBody, pcborProtected,
pcborProtectedSign, pSigner->m_message.m_pbExternal,
pSigner->m_message.m_cbExternal, contextString,
CBOR_CONTEXT_PARAM_COMMA perr)) {
goto errorReturn;
}
switch (alg) {
#ifdef USE_ECDSA_SHA_256
case COSE_Algorithm_ECDSA_SHA_256:
if (!ECDSA_Sign(&pSigner->m_message, INDEX_SIGNATURE,
pSigner->m_pkey, 256, pbToSign, cbToSign, perr)) {
goto errorReturn;
}
break;
#endif
#ifdef USE_ECDSA_SHA_384
case COSE_Algorithm_ECDSA_SHA_384:
if (!ECDSA_Sign(&pSigner->m_message, INDEX_SIGNATURE,
pSigner->m_pkey, 384, pbToSign, cbToSign, perr)) {
goto errorReturn;
}
break;
#endif
#ifdef USE_ECDSA_SHA_512
case COSE_Algorithm_ECDSA_SHA_512:
if (!ECDSA_Sign(&pSigner->m_message, INDEX_SIGNATURE,
pSigner->m_pkey, 512, pbToSign, cbToSign, perr)) {
goto errorReturn;
}
break;
#endif
#ifdef USE_EDDSA
case COSE_Algorithm_EdDSA:
if (!EdDSA_Sign(&pSigner->m_message, INDEX_SIGNATURE,
pSigner->m_pkey, pbToSign, cbToSign, perr)) {
goto errorReturn;
}
break;
#endif
default:
FAIL_CONDITION(COSE_ERR_UNKNOWN_ALGORITHM);
}
#if INCLUDE_COUNTERSIGNATURE
if (pSigner->m_message.m_counterSigners != nullptr) {
if (!_COSE_CounterSign_Sign(
&pSigner->m_message, CBOR_CONTEXT_PARAM_COMMA perr)) {
goto errorReturn;
}
}
#endif
#if INCLUDE_COUNTERSIGNATURE1
if (pSigner->m_message.m_counterSign1 != NULL) {
if (!_COSE_CounterSign1_Sign(
&pSigner->m_message, CBOR_CONTEXT_PARAM_COMMA perr)) {
goto errorReturn;
}
}
#endif
fRet = true;
errorReturn:
if (pArray != nullptr) {
COSE_FREE(pArray, context);
}
if (pbToSign != nullptr) {
COSE_FREE(pbToSign, context);
}
return fRet;
}
#if INCLUDE_SIGN
bool COSE_Signer_SetKey2(HCOSE_SIGNER h, HCOSE_KEY pKey, cose_errback *perr)
{
COSE_SignerInfo *p;
if (false) {
errorReturn:
return false;
}
CHECK_CONDITION(IsValidSignerHandle(h), COSE_ERR_INVALID_HANDLE);
CHECK_CONDITION(IsValidKeyHandle(pKey), COSE_ERR_INVALID_HANDLE);
p = (COSE_SignerInfo *)h;
if (p->m_pkey != nullptr) {
COSE_KEY_Free((HCOSE_KEY)p->m_pkey);
}
COSE_KEY *pcose = (COSE_KEY *)pKey;
p->m_pkey = pcose;
if (pcose != nullptr) {
pcose->m_refCount += 1;
}
return true;
}
bool COSE_Signer_SetKey(HCOSE_SIGNER h, const cn_cbor *pKey, cose_errback *perr)
{
HCOSE_KEY cose = nullptr;
bool fRet = false;
if (false) {
errorReturn:
if (cose != nullptr) {
COSE_KEY_Free(cose);
}
return fRet;
}
CHECK_CONDITION(pKey != nullptr, COSE_ERR_INVALID_PARAMETER);
CHECK_CONDITION(IsValidSignerHandle(h), COSE_ERR_INVALID_HANDLE);
#ifdef USE_CBOR_CONTEXT
COSE_SignerInfo *p = (COSE_SignerInfo *)h;
cn_cbor_context *context = &p->m_message.m_allocContext;
#endif
cose = COSE_KEY_FromCbor((cn_cbor *)pKey, CBOR_CONTEXT_PARAM_COMMA perr);
CHECK_CONDITION(cose != nullptr, COSE_ERR_OUT_OF_MEMORY);
fRet = COSE_Signer_SetKey2(h, cose, perr);
return fRet;
}
/*!
* @brief Set the application external data for authentication
*
* Signer 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 MAC 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_Signer_SetExternal(HCOSE_SIGNER hcose,
const byte *pbExternalData,
size_t cbExternalData,
cose_errback *perr)
{
if (!IsValidSignerHandle(hcose)) {
if (perr != nullptr) {
perr->err = COSE_ERR_INVALID_HANDLE;
}
return false;
}
return _COSE_SetExternal(&((COSE_SignerInfo *)hcose)->m_message,
pbExternalData, cbExternalData, perr);
}
#endif
bool _COSE_Signer_validate(COSE_SignerInfo *pSigner,
const cn_cbor *pcborBody,
const cn_cbor *pcborProtected,
const char *const contextString,
cose_errback *perr)
{
byte *pbToBeSigned = nullptr;
int alg = 0;
#ifdef USE_CBOR_CONTEXT
cn_cbor_context *context = &pSigner->m_message.m_allocContext;
#endif
size_t cbToBeSigned;
bool fRet = false;
const cn_cbor *cn = _COSE_map_get_int(
&pSigner->m_message, COSE_Header_Algorithm, COSE_BOTH, perr);
if (cn == nullptr) {
errorReturn:
if (pbToBeSigned != nullptr) {
COSE_FREE(pbToBeSigned, context);
}
return fRet;
}
if (cn->type == CN_CBOR_TEXT) {
FAIL_CONDITION(COSE_ERR_UNKNOWN_ALGORITHM);
}
else {
CHECK_CONDITION((cn->type == CN_CBOR_UINT || cn->type == CN_CBOR_INT),
COSE_ERR_INVALID_PARAMETER);
alg = (int)cn->v.sint;
}
// Build protected headers
cn_cbor *cnProtected =
_COSE_arrayget_int(&pSigner->m_message, INDEX_PROTECTED);
CHECK_CONDITION(
(cnProtected != nullptr) && (cnProtected->type == CN_CBOR_BYTES),
COSE_ERR_INVALID_PARAMETER);
// Build authenticated data
if (!BuildToBeSigned(&pbToBeSigned, &cbToBeSigned, pcborBody,
pcborProtected, cnProtected, pSigner->m_message.m_pbExternal,
pSigner->m_message.m_cbExternal, contextString,
CBOR_CONTEXT_PARAM_COMMA perr)) {
goto errorReturn;
}
cn_cbor *cnSignature =
_COSE_arrayget_int(&pSigner->m_message, INDEX_SIGNATURE);
CHECK_CONDITION(
(cnSignature != nullptr) && (cnSignature->type == CN_CBOR_BYTES),
COSE_ERR_INVALID_PARAMETER);
switch (alg) {
#ifdef USE_ECDSA_SHA_256
case COSE_Algorithm_ECDSA_SHA_256:
if (!ECDSA_Verify(&pSigner->m_message, INDEX_SIGNATURE,
pSigner->m_pkey, 256, pbToBeSigned, cbToBeSigned, perr)) {
goto errorReturn;
}
break;
#endif
#ifdef USE_ECDSA_SHA_384
case COSE_Algorithm_ECDSA_SHA_384:
if (!ECDSA_Verify(&pSigner->m_message, INDEX_SIGNATURE,
pSigner->m_pkey, 384, pbToBeSigned, cbToBeSigned, perr)) {
goto errorReturn;
}
break;
#endif
#ifdef USE_ECDSA_SHA_512
case COSE_Algorithm_ECDSA_SHA_512:
if (!ECDSA_Verify(&pSigner->m_message, INDEX_SIGNATURE,
pSigner->m_pkey, 512, pbToBeSigned, cbToBeSigned, perr)) {
goto errorReturn;
}
break;
#endif
#ifdef USE_EDDSA
case COSE_Algorithm_EdDSA:
if (!EdDSA_Verify(&pSigner->m_message, INDEX_SIGNATURE,
pSigner->m_pkey, pbToBeSigned, cbToBeSigned, perr)) {
goto errorReturn;
}
break;
#endif
default:
FAIL_CONDITION(COSE_ERR_UNKNOWN_ALGORITHM);
break;
}
fRet = true;
goto errorReturn;
}
#if INCLUDE_SIGN
cn_cbor *COSE_Signer_map_get_int(HCOSE_SIGNER h,
int key,
int flags,
cose_errback *perr)
{
if (!IsValidSignerHandle(h)) {
if (perr != nullptr) {
perr->err = COSE_ERR_INVALID_HANDLE;
}
return nullptr;
}
return _COSE_map_get_int((COSE *)h, key, flags, perr);
}
bool COSE_Signer_map_put_int(HCOSE_SIGNER h,
int key,
cn_cbor *value,
int flags,
cose_errback *perr)
{
CHECK_CONDITION(IsValidSignerHandle(h), COSE_ERR_INVALID_HANDLE);
CHECK_CONDITION(value != nullptr, COSE_ERR_INVALID_PARAMETER);
return _COSE_map_put(
&((COSE_SignerInfo *)h)->m_message, key, value, flags, perr);
errorReturn:
return false;
}
#endif
#endif