| /** \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 = NULL; |
| |
| 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); |
| CN_CBOR_FREE(pSigner->m_pkey, &pSigner->m_message.m_allocContext); |
| |
| 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 == NULL) { |
| if (perror != NULL) { |
| perror->err = COSE_ERR_OUT_OF_MEMORY; |
| } |
| return NULL; |
| } |
| |
| 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 NULL; |
| } |
| |
| _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 == NULL) { |
| pSigner = |
| (COSE_SignerInfo *)COSE_CALLOC(1, sizeof(COSE_SignerInfo), context); |
| CHECK_CONDITION(pSigner != NULL, 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 == NULL) { |
| _COSE_InsertInList(&SignerRoot, &pSigner->m_message); |
| } |
| #endif |
| return pSigner; |
| |
| errorReturn: |
| if (pSigner != NULL && pIn == NULL) { |
| _COSE_SignerInfo_Release(pSigner); |
| COSE_FREE(pSigner, context); |
| } |
| return NULL; |
| } |
| |
| 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 = NULL; |
| cn_cbor_errback cbor_error; |
| size_t cbToSign; |
| byte *pbToSign = NULL; |
| bool f = false; |
| cn_cbor *cn = NULL; |
| |
| pArray = cn_cbor_array_create(CBOR_CONTEXT_PARAM_COMMA & cbor_error); |
| CHECK_CONDITION_CBOR(pArray != NULL, cbor_error); |
| |
| cn = cn_cbor_string_create( |
| contextString, CBOR_CONTEXT_PARAM_COMMA & cbor_error); |
| CHECK_CONDITION_CBOR(cn != NULL, cbor_error); |
| CHECK_CONDITION_CBOR( |
| cn_cbor_array_append(pArray, cn, &cbor_error), cbor_error); |
| cn = NULL; |
| |
| if (pcborProtected->length == 1 && (pcborProtected->v.bytes[0] == 0xa0)) { |
| cn = |
| cn_cbor_data_create(NULL, 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 != NULL, cbor_error); |
| CHECK_CONDITION_CBOR( |
| cn_cbor_array_append(pArray, cn, &cbor_error), cbor_error); |
| cn = NULL; |
| |
| if ((pcborProtectedSign->length == 1) && |
| (pcborProtectedSign->v.bytes[0] == 0xa0)) { |
| cn = |
| cn_cbor_data_create(NULL, 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 != NULL, cbor_error); |
| CHECK_CONDITION_CBOR( |
| cn_cbor_array_append(pArray, cn, &cbor_error), cbor_error); |
| cn = NULL; |
| |
| cn = cn_cbor_data_create( |
| pbExternal, (int)cbExternal, CBOR_CONTEXT_PARAM_COMMA & cbor_error); |
| CHECK_CONDITION_CBOR(cn != NULL, cbor_error); |
| CHECK_CONDITION_CBOR( |
| cn_cbor_array_append(pArray, cn, &cbor_error), cbor_error); |
| cn = NULL; |
| |
| cn = cn_cbor_data_create(pcborBody->v.bytes, (int)pcborBody->length, |
| CBOR_CONTEXT_PARAM_COMMA & cbor_error); |
| CHECK_CONDITION_CBOR(cn != NULL, cbor_error); |
| CHECK_CONDITION_CBOR( |
| cn_cbor_array_append(pArray, cn, &cbor_error), cbor_error); |
| cn = NULL; |
| |
| cbToSign = cn_cbor_encode_size(pArray); |
| CHECK_CONDITION(cbToSign > 0, COSE_ERR_CBOR); |
| pbToSign = (byte *)COSE_CALLOC(cbToSign, 1, context); |
| CHECK_CONDITION(pbToSign != NULL, 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 = NULL; |
| f = true; |
| |
| errorReturn: |
| if (cn != NULL) { |
| CN_CBOR_FREE(cn, context); |
| } |
| if (pArray != NULL) { |
| CN_CBOR_FREE(pArray, context); |
| } |
| if (pbToSign != NULL) { |
| COSE_FREE(pbToSign, context); |
| } |
| return f; |
| } |
| |
| 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 = NULL; |
| cn_cbor *pArray = NULL; |
| cn_cbor *cnAlgorithm = NULL; |
| size_t cbToSign; |
| byte *pbToSign = NULL; |
| int alg; |
| bool fRet = false; |
| |
| pArray = cn_cbor_array_create(CBOR_CONTEXT_PARAM_COMMA NULL); |
| CHECK_CONDITION(pArray != NULL, COSE_ERR_OUT_OF_MEMORY); |
| |
| cnAlgorithm = _COSE_map_get_int( |
| &pSigner->m_message, COSE_Header_Algorithm, COSE_BOTH, perr); |
| if (cnAlgorithm == NULL) { |
| 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 == NULL) { |
| 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 != NULL) { |
| if (!_COSE_CounterSign_Sign( |
| &pSigner->m_message, CBOR_CONTEXT_PARAM_COMMA perr)) { |
| goto errorReturn; |
| } |
| } |
| #endif |
| |
| fRet = true; |
| |
| errorReturn: |
| if (pArray != NULL) { |
| COSE_FREE(pArray, context); |
| } |
| if (pbToSign != NULL) { |
| COSE_FREE(pbToSign, context); |
| } |
| return fRet; |
| } |
| |
| #if INCLUDE_SIGN |
| bool COSE_Signer_SetKey(HCOSE_SIGNER h, const cn_cbor *pKey, cose_errback *perr) |
| { |
| COSE_SignerInfo *p; |
| bool fRet = false; |
| |
| CHECK_CONDITION(IsValidSignerHandle(h), COSE_ERR_INVALID_HANDLE); |
| CHECK_CONDITION(pKey != NULL, COSE_ERR_INVALID_PARAMETER); |
| |
| p = (COSE_SignerInfo *)h; |
| p->m_pkey = pKey; |
| |
| fRet = true; |
| errorReturn: |
| 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 != NULL) { |
| 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 = NULL; |
| 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 == NULL) { |
| goto errorReturn; |
| } |
| |
| 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 != NULL) && (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 != NULL) && (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; |
| |
| errorReturn: |
| if (pbToBeSigned != NULL) { |
| COSE_FREE(pbToBeSigned, context); |
| } |
| |
| return fRet; |
| } |
| |
| #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 != NULL) { |
| perr->err = COSE_ERR_INVALID_HANDLE; |
| } |
| return NULL; |
| } |
| |
| 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 != NULL, COSE_ERR_INVALID_PARAMETER); |
| |
| return _COSE_map_put( |
| &((COSE_SignerInfo *)h)->m_message, key, value, flags, perr); |
| |
| errorReturn: |
| return false; |
| } |
| #endif |
| #endif |