Update to last version of TFM-Attesttaion code

-update TFM attestation files
-update attest_crypto.c and psa_attestation_stubs.c file to support TFM
code changes
pull/9668/head
Moran Peker 2019-02-17 16:16:38 +02:00
parent 2117a26cb1
commit 70a14b2f3a
26 changed files with 1908 additions and 960 deletions

View File

@ -35,23 +35,23 @@ extern "C" {
*
*/
enum psa_attest_err_t {
/* Action was performed successfully */
/** Action was performed successfully */
PSA_ATTEST_ERR_SUCCESS = 0,
/* Boot status data is unavailable or malformed */
/** Boot status data is unavailable or malformed */
PSA_ATTEST_ERR_INIT_FAILED,
/* Token buffer is too small to store the created token there */
/** Token buffer is too small to store the created token there */
PSA_ATTEST_ERR_TOKEN_BUFFER_OVERFLOW,
/* Some of the mandatory claims are unavailable*/
/** Some of the mandatory claims are unavailable*/
PSA_ATTEST_ERR_CLAIM_UNAVAILABLE,
/* Some parameter or combination of parameters are recognised as invalid:
/** Some parameter or combination of parameters are recognised as invalid:
* - challenge size is not allowed
* - challenge object is unavailable
* - token buffer is unavailable
*/
PSA_ATTEST_ERR_INVALID_INPUT,
/* Unexpected error happened during operation */
/** Unexpected error happened during operation */
PSA_ATTEST_ERR_GENERAL,
/* Following entry is only to ensure the error code of integer size */
/** Following entry is only to ensure the error code of integer size */
PSA_ATTEST_ERR_FORCE_INT_SIZE = INT_MAX
};
@ -112,8 +112,12 @@ enum psa_attest_err_t {
* Custom claim with a value encoded as byte string.
*
* - Security lifecycle: It represents the current lifecycle state of the
* instance. Custom claim with a value encoded as unsigned
* integer (enum). Possible values:
* instance. Custom claim with a value encoded as integer that
* is divided to convey a major state and a minor state. The
* PSA state and implementation state are encoded as follows:
* - version[15:8] - PSA lifecycle state - major
* - version[7:0] - IMPLEMENTATION DEFINED state - minor
* Possible PSA lifecycle states:
* - Unknown (0x1000u),
* - PSA_RoT_Provisioning (0x2000u),
* - Secured (0x3000u),
@ -144,22 +148,25 @@ enum psa_attest_err_t {
* device. Each map contains multiple claims that describe
* evidence about the details of the software component.
*
* - Type: It represents the role of the software component. Value is
* encoded as short(!) text string.
*
* - Measurement: It represents a hash of the invariant software component
* in memory at start-up time. Value is encoded as byte
* - Measurement type: Optional claim. It represents the role of the
* software component. Value is encoded as short(!) text
* string.
*
* - Security epoch: It represents the security control point of the
* software component. Value is encoded as unsigned integer.
* - Measurement value: It represents a hash of the invariant software
* component in memory at start-up time. The value must be a
* cryptographic hash of 256 bits or stronger.Value is
* encoded as byte string.
*
* - Signer ID: Optional claim. It represents the hash of a signing
* authority public key. Value is encoded as byte string.
* - Security epoch: Optional claim. It represents the security control
* point of the software component. Value is encoded as
* unsigned integer.
*
* - Version: Optional claim. It represents the issued software version.
* Value is encoded as text string.
*
* - Signer ID: It represents the hash of a signing authority public key.
* Value is encoded as byte string.
*
* - Measurement description: Optional claim. It represents the way in which
* the measurement value of the software component is
* computed. Value is encoded as text string containing an

View File

@ -16,7 +16,7 @@
* limitations under the License.
*/
#include "t_cose/src/t_cose_crypto.h"
#include "t_cose_crypto.h"
#include "tfm_plat_defs.h"
#include "crypto.h"
#include "tfm_plat_crypto_keys.h"
@ -24,7 +24,16 @@
#define PSA_ATTESTATION_PRIVATE_KEY_ID 17
static psa_hash_operation_t hash_handle = {0};
/**
* \brief Context for PSA hash adaptation.
*
* Hash context for PSA hash implementation. This is fit into and cast
* to/from struct \ref t_cose_crypto_hash.
*/
struct t_cose_psa_crypto_hash {
psa_status_t status;
psa_hash_operation_t operation;
};
enum t_cose_err_t
t_cose_crypto_pub_key_sign(int32_t cose_alg_id,
@ -34,12 +43,18 @@ t_cose_crypto_pub_key_sign(int32_t cose_alg_id,
struct useful_buf_c *signature) {
enum t_cose_err_t cose_ret = T_COSE_SUCCESS;
psa_status_t crypto_ret;
const size_t sig_size = t_cose_signature_size(cose_alg_id);
(void)key_select;
const psa_key_id_t key_id = PSA_ATTESTATION_PRIVATE_KEY_ID;
psa_key_handle_t handle = 0;
if (sig_size > signature_buffer.len)
{
return T_COSE_ERR_SIG_BUFFER_SIZE;
}
crypto_ret = psa_crypto_init();
if (crypto_ret != PSA_SUCCESS)
{
@ -64,7 +79,7 @@ t_cose_crypto_pub_key_sign(int32_t cose_alg_id,
if (crypto_ret != PSA_SUCCESS)
{
psa_close_key(handle);
cose_ret = T_COSE_ERR_UNKNOWN_SIGNING_ALG;
cose_ret = T_COSE_ERR_UNSUPPORTED_SIGNING_ALG;
} else
{
signature->ptr = signature_buffer.ptr;
@ -76,6 +91,7 @@ t_cose_crypto_pub_key_sign(int32_t cose_alg_id,
enum t_cose_err_t
t_cose_crypto_get_ec_pub_key(int32_t key_select,
struct useful_buf_c kid,
int32_t *cose_curve_id,
struct useful_buf buf_to_hold_x_coord,
struct useful_buf buf_to_hold_y_coord,
@ -139,18 +155,77 @@ t_cose_crypto_get_ec_pub_key(int32_t key_select,
return T_COSE_SUCCESS;
}
/**
* \brief Check some of the sizes for hash implementation.
*
* \return Value from \ref t_cose_err_t error if sizes are not correct.
*
* It makes sure the constants in the header file match the local
* implementation. This gets evaluated at compile time and will
* optimize out to nothing when all checks pass.
*/
static inline enum t_cose_err_t check_hash_sizes()
{
if (T_COSE_CRYPTO_SHA256_SIZE != PSA_HASH_SIZE(PSA_ALG_SHA_256)) {
return T_COSE_ERR_HASH_GENERAL_FAIL;
}
return T_COSE_SUCCESS;
}
/**
* \brief Convert COSE algorithm ID to a PSA algorithm ID
*
* \param[in] cose_hash_alg_id The COSE-based ID for the
*
* \return PSA-based hash algorithm ID, or MD4 in the case of error.
*
*/
static inline psa_algorithm_t cose_hash_alg_id_to_psa(int32_t cose_hash_alg_id)
{
psa_algorithm_t return_value;
switch (cose_hash_alg_id) {
case COSE_ALG_SHA256_PROPRIETARY:
return_value = PSA_ALG_SHA_256;
break;
default:
return_value = PSA_ALG_MD4;
break;
}
return return_value;
}
enum t_cose_err_t
t_cose_crypto_hash_start(struct t_cose_crypto_hash *hash_ctx,
int32_t cose_hash_alg_id) {
enum t_cose_err_t cose_ret = T_COSE_SUCCESS;
psa_status_t crypto_ret;
psa_status_t psa_ret;
struct t_cose_psa_crypto_hash *psa_hash_ctx;
crypto_ret = psa_hash_setup(&hash_handle, PSA_ALG_SHA_256);
/* These next 3 lines optimize to nothing except when there is
* failure.
*/
cose_ret = check_hash_sizes();
if (cose_ret)
{
return cose_ret;
}
if (crypto_ret == PSA_ERROR_NOT_SUPPORTED)
psa_hash_ctx = (struct t_cose_psa_crypto_hash *)hash_ctx;
psa_ret = psa_hash_setup(&psa_hash_ctx->operation,
cose_hash_alg_id_to_psa(cose_hash_alg_id));
if (psa_ret == PSA_SUCCESS)
{
psa_hash_ctx->status = PSA_SUCCESS;
cose_ret = T_COSE_SUCCESS;
} else if (psa_ret == PSA_ERROR_NOT_SUPPORTED)
{
cose_ret = T_COSE_ERR_UNSUPPORTED_HASH;
} else if (crypto_ret != PSA_SUCCESS)
} else
{
cose_ret = T_COSE_ERR_HASH_GENERAL_FAIL;
}
@ -161,10 +236,18 @@ t_cose_crypto_hash_start(struct t_cose_crypto_hash *hash_ctx,
void t_cose_crypto_hash_update(struct t_cose_crypto_hash *hash_ctx,
struct useful_buf_c data_to_hash)
{
if (data_to_hash.ptr != NULL) {
psa_hash_update(&hash_handle, data_to_hash.ptr, data_to_hash.len);
} else {
/* Intentionally do nothing, just computing the size of the token */
struct t_cose_psa_crypto_hash *psa_hash_ctx;
psa_hash_ctx = (struct t_cose_psa_crypto_hash *)hash_ctx;
if (psa_hash_ctx->status == PSA_SUCCESS) {
if (data_to_hash.ptr != NULL) {
psa_hash_ctx->status = psa_hash_update(&psa_hash_ctx->operation,
data_to_hash.ptr,
data_to_hash.len);
} else {
/* Intentionally do nothing, just computing the size of the token */
}
}
}
@ -173,25 +256,30 @@ t_cose_crypto_hash_finish(struct t_cose_crypto_hash *hash_ctx,
struct useful_buf buffer_to_hold_result,
struct useful_buf_c *hash_result) {
enum t_cose_err_t cose_ret = T_COSE_SUCCESS;
psa_status_t crypto_ret;
psa_status_t psa_ret;
struct t_cose_psa_crypto_hash *psa_hash_ctx;
crypto_ret = psa_hash_finish(&hash_handle,
buffer_to_hold_result.ptr,
buffer_to_hold_result.len,
&(hash_result->len));
psa_hash_ctx = (struct t_cose_psa_crypto_hash *)hash_ctx;
if (crypto_ret == PSA_ERROR_BUFFER_TOO_SMALL)
if (psa_hash_ctx->status == PSA_SUCCESS)
{
cose_ret = T_COSE_ERR_HASH_BUFFER_SIZE;
} else if (crypto_ret != PSA_SUCCESS)
psa_ret = psa_hash_finish(&psa_hash_ctx->operation,
buffer_to_hold_result.ptr,
buffer_to_hold_result.len,
&(hash_result->len));
if (psa_ret == PSA_SUCCESS) {
hash_result->ptr = buffer_to_hold_result.ptr;
cose_ret = T_COSE_SUCCESS;
} else if (psa_ret == PSA_ERROR_BUFFER_TOO_SMALL) {
cose_ret = T_COSE_ERR_HASH_BUFFER_SIZE;
} else {
cose_ret = T_COSE_ERR_HASH_GENERAL_FAIL;
}
} else
{
cose_ret = T_COSE_ERR_HASH_GENERAL_FAIL;
}
if (cose_ret == T_COSE_SUCCESS)
{
hash_result->ptr = buffer_to_hold_result.ptr;
}
return crypto_ret;
return cose_ret;
}

View File

@ -18,13 +18,6 @@
#include <stdint.h>
#include "attestation.h"
#include "attestation_key.h"
/* Implementation of mandatory functions that used by TFM attestation code */
enum psa_attest_err_t
attest_get_and_register_initial_attestation_key(void) {
return PSA_ATTEST_ERR_SUCCESS;
}
enum psa_attest_err_t
attest_check_memory_access(void *addr,

View File

@ -21,16 +21,16 @@ extern "C" {
#define EAT_CBOR_ARM_LABEL_HW_VERSION (EAT_CBOR_ARM_RANGE_BASE - 5)
#define EAT_CBOR_ARM_LABEL_SW_COMPONENTS (EAT_CBOR_ARM_RANGE_BASE - 6)
#define EAT_CBOR_ARM_LABEL_NO_SW_COMPONENTS (EAT_CBOR_ARM_RANGE_BASE - 7)
#define EAT_CBOR_ARM_LABEL_NONCE (EAT_CBOR_ARM_RANGE_BASE - 8)
#define EAT_CBOR_ARM_LABEL_CHALLENGE (EAT_CBOR_ARM_RANGE_BASE - 8)
#define EAT_CBOR_ARM_LABEL_UEID (EAT_CBOR_ARM_RANGE_BASE - 9)
#define EAT_CBOR_ARM_LABEL_ORIGINATION (EAT_CBOR_ARM_RANGE_BASE - 10)
#define EAT_CBOR_SW_COMPONENT_TYPE (1u)
#define EAT_CBOR_SW_COMPONENT_MEASUREMENT (2u)
#define EAT_CBOR_SW_COMPONENT_EPOCH (3u)
#define EAT_CBOR_SW_COMPONENT_VERSION (4u)
#define EAT_CBOR_SW_COMPONENT_SIGNER_ID (5u)
#define EAT_CBOR_SW_COMPONENT_MEASUREMENT_DESC (6u)
#define EAT_CBOR_SW_COMPONENT_MEASUREMENT_TYPE (1)
#define EAT_CBOR_SW_COMPONENT_MEASUREMENT_VALUE (2)
#define EAT_CBOR_SW_COMPONENT_SECURITY_EPOCH (3)
#define EAT_CBOR_SW_COMPONENT_VERSION (4)
#define EAT_CBOR_SW_COMPONENT_SIGNER_ID (5)
#define EAT_CBOR_SW_COMPONENT_MEASUREMENT_DESC (6)
#ifdef __cplusplus
}

View File

@ -10,49 +10,50 @@
#include "attest_token.h"
#include "qcbor.h"
#include "t_cose_sign1.h"
#include "t_cose_sign1_sign.h"
/*
T H E C O M M E N T S
in this file are truthful, but not expansive,
complete of formatted yet...
/**
* \file attest_token.c
*
* \brief Attestation token creation implementation
*
* Outline of token creation. Much of this occurs inside
* t_cose_sign1_init() and t_cose_sign1_finish().
*
* - Create encoder context
* - Open the CBOR array that hold the \c COSE_Sign1
* - Write COSE Headers
* - Protected Header
* - Algorithm ID
* - Unprotected Headers
* - Key ID
* - Open payload bstr
* - Write payload data lots of it
* - Get bstr that is the encoded payload
* - Compute signature
* - Create a separate encoder context for \c Sig_structure
* - Encode CBOR context identifier
* - Encode protected headers
* - Encode two empty bstr
* - Add one more empty bstr that is a "fake payload"
* - Close off \c Sig_structure
* - Hash all but "fake payload" of \c Sig_structure
* - Get payload bstr ptr and length
* - Continue hash of the real encoded payload
* - Run ECDSA
* - Write signature into the CBOR output
* - Close CBOR array holding the \c COSE_Sign1
*/
/*
Outline of what there is to do
start signing operation
- Create encoder context
- Write Headers
- - Protected Header
- - - Algorithm ID
- - Unprotected Headers
- - - Key ID
- Open Payload bstr
- - Write payload data lots of it
- - Get bstr back and hash
- Compute signature
- - Create a separate encoder context for Sig_structure
- - - Encode context
- - - Encode protected headers
- - - Encode two empty bstr
- - - Add one more empty bstr
- - - Close it off
- - Hash all but last two bytes
- - Get payload bstr ptr and length
- - Hash payload
- - Run ECDSA
- Write signature
- Close it out
* \brief Map t_cose error to attestation token error.
*
* \param[in] err The t_cose error to map.
*
* \return the attestation token error.
*
*/
static enum attest_token_err_t t_cose_err_to_attest_err(enum t_cose_err_t err)
{
switch(err) {
@ -63,29 +64,24 @@ static enum attest_token_err_t t_cose_err_to_attest_err(enum t_cose_err_t err)
case T_COSE_ERR_UNSUPPORTED_HASH:
return ATTEST_TOKEN_ERR_HASH_UNAVAILABLE;
/* TODO: fill in more of these */
default:
/* A lot of the errors are not mapped because they
are primarily internal errors that should never
happen. They end up here */
/* A lot of the errors are not mapped because they are
* primarily internal errors that should never happen. They
* end up here.
*/
return ATTEST_TOKEN_ERR_GENERAL;
}
}
#if T_COSE_KEY_SELECT_TEST != ATTEST_TOKEN_KEY_SELECT_TEST
#error KEY_SELECT_TEST not identical for T_COSE and ATTEST_TOKEN
#endif
/*
Public function. See attest_token.h
*/
enum attest_token_err_t attest_token_start(struct attest_token_ctx *me,
uint32_t opt_flags,
int32_t key_select,
int32_t alg_select,
struct useful_buf out_buf)
int32_t cose_alg_id,
const struct useful_buf *out_buf)
{
/* approximate stack usage on 32-bit machine: 4 bytes */
enum t_cose_err_t cose_return_value;
@ -96,16 +92,16 @@ enum attest_token_err_t attest_token_start(struct attest_token_ctx *me,
me->key_select = key_select;
/* Spin up the CBOR encoder */
QCBOREncode_Init(&(me->cbor_enc_ctx), out_buf);
QCBOREncode_Init(&(me->cbor_enc_ctx), *out_buf);
/* Initialize COSE signer. This will cause the cose headers to
be encoded and written into out_buf using me->cbor_enc_ctx
/* Initialize COSE signer. This will cause the cose headers to be
* encoded and written into out_buf using me->cbor_enc_ctx
*/
cose_return_value = t_cose_sign1_init(&(me->signer_ctx),
opt_flags &
TOKEN_OPT_SHORT_CIRCUIT_SIGN,
alg_select,
cose_alg_id,
key_select,
&(me->cbor_enc_ctx));
if(cose_return_value) {
@ -124,6 +120,7 @@ Done:
return return_value;
}
/*
Public function. See attest_token.h
*/
@ -132,6 +129,7 @@ QCBOREncodeContext *attest_token_borrow_cbor_cntxt(struct attest_token_ctx *me)
return &(me->cbor_enc_ctx);
}
/*
Public function. See attest_token.h
*/
@ -142,38 +140,42 @@ void attest_token_add_integer(struct attest_token_ctx *me,
QCBOREncode_AddInt64ToMapN(&(me->cbor_enc_ctx), label, Value);
}
/*
Public function. See attest_token.h
*/
void attest_token_add_bstr(struct attest_token_ctx *me,
int32_t label,
struct useful_buf_c bstr)
const struct useful_buf_c *bstr)
{
QCBOREncode_AddBytesToMapN(&(me->cbor_enc_ctx),
label,
bstr);
*bstr);
}
/*
Public function. See attest_token.h
*/
void attest_token_add_tstr(struct attest_token_ctx *me,
int32_t label,
struct useful_buf_c bstr)
const struct useful_buf_c *tstr)
{
QCBOREncode_AddTextToMapN(&(me->cbor_enc_ctx), label, bstr);
QCBOREncode_AddTextToMapN(&(me->cbor_enc_ctx), label, *tstr);
}
/*
See attest_token.h
*/
void attest_token_add_encoded(struct attest_token_ctx *me,
int32_t label,
struct useful_buf_c encoded)
const struct useful_buf_c *encoded)
{
QCBOREncode_AddEncodedToMapN(&(me->cbor_enc_ctx), label, encoded);
QCBOREncode_AddEncodedToMapN(&(me->cbor_enc_ctx), label, *encoded);
}
/*
Public function. See attest_token.h
*/
@ -192,8 +194,9 @@ attest_token_finish(struct attest_token_ctx *me,
QCBOREncode_CloseMap(&(me->cbor_enc_ctx));
/* Close off the payload-wrapping bstr. This gives us back the pointer
and length of the payload that needs to be hashed as part of the signature
/* Close off the payload-wrapping bstr. This gives us back the
* pointer and length of the payload that needs to be hashed as
* part of the signature
*/
QCBOREncode_CloseBstrWrap(&(me->cbor_enc_ctx), &token_payload_ub);

View File

@ -8,80 +8,103 @@
* See BSD-3-Clause license in README.md
*/
#ifndef __ATTEST_TOKEN_h__
#define __ATTEST_TOKEN_h__
#ifndef __ATTEST_TOKEN_H__
#define __ATTEST_TOKEN_H__
#include <stdint.h>
#include "qcbor.h"
#include "t_cose_sign1.h"
#include "t_cose_sign1_sign.h"
/**
* \file Attestation Token Creation
* \file attest_token.h
*
* The context and functions here are the way to create
* an attestation token. The steps are roughly:
* \brief Attestation Token Creation Interface
*
* 1) Creation and initalize an attest_token_ctx indicating
* the options, key and such.
* 2) Use various add methods to fill in the payload
* with claims
* 3) Call finish to create the signature and finish
* formatting the COSE signed output.
* The context and functions here are the way to create an attestation
* token. The steps are roughly:
*
* -# Creation and initialize an attest_token_ctx indicating the
* options, key and such using attest_token_start().
*
* -# Use various add methods to fill in the payload with claims. The
* encoding context can also be borrowed for more rich payloads.
*
* -# Call attest_token_finish() to create the signature and finish
* formatting the COSE signed output.
*/
/**
Error codes returned from attestation token creation.
*/
enum attest_token_err_t {
/** Success */
ATTEST_TOKEN_ERR_SUCCESS = 0,
/** The buffer passed in to receive the token is too small */
/** The buffer passed in to receive the output is too small. */
ATTEST_TOKEN_ERR_TOO_SMALL,
/** Something went wrong formatting the CBOR, most likely the payload
has maps or arrays that are not closed */
/** Something went wrong formatting the CBOR, most likely the
payload has maps or arrays that are not closed. */
ATTEST_TOKEN_ERR_CBOR_FORMATTING,
/** A general, unspecific error when creating the token */
/** A general, unspecific error when creating or decoding the
token. */
ATTEST_TOKEN_ERR_GENERAL,
/** A hash function that is needed to make the token is not available */
ATTEST_TOKEN_ERR_HASH_UNAVAILABLE
/** A hash function that is needed to make the token is not
available. */
ATTEST_TOKEN_ERR_HASH_UNAVAILABLE,
/** CBOR Syntax not well-formed -- a CBOR syntax error. */
ATTEST_TOKEN_ERR_CBOR_NOT_WELL_FORMED,
/** Bad CBOR structure, for example not a map when was is
required. */
ATTEST_TOKEN_ERR_CBOR_STRUCTURE,
/** Bad CBOR type, for example an not a text string, when a text
string is required. */
ATTETST_TOKEN_ERR_CBOR_TYPE,
/** Integer too large, for example an \c int32_t is required, but
value only fits in \c int64_t */
ATTEST_TOKEN_ERR_INTEGER_VALUE,
/** Something is wrong with the COSE signing structure, missing
headers or such. */
ATTEST_TOKEN_ERR_COSE_SIGN1_FORMAT,
/** COSE signature is invalid, data is corrupted. */
ATTEST_TOKEN_ERR_COSE_SIGN1_VALIDATION,
/** The signing algorithm is not supported. */
ATTEST_TOKEN_ERR_UNSUPPORTED_SIG_ALG,
/** Out of memory. */
ATTEST_TOKEN_ERR_INSUFFICIENT_MEMORY,
/** Tampering detected in cryptographic function. */
ATTEST_TOKEN_ERR_TAMPERING_DETECTED,
/** Verification key is not found or of wrong type. */
ATTEST_TOKEN_ERR_VERIFICATION_KEY
};
/** The default key to sign tokens with for this device
*/
#define TOKEN_OPT_DEFAULT_KEY 0x00
/** Sign with the globally known debug key. This key is
* always available. It is always the same on every device.
* It is very useful for test and debug. Tokens signed
* by it have no security value because they can be forged
* because this debug key is considered to be widely known.
*/
#define TOKEN_OPT_DEBUG_KEY 0x07
/** Request that the claims internally generated not be added to the token.
* This is a test mode that results in a static token that never changes.
/**
* Request that the claims internally generated not be added to the
* token. This is a test mode that results in a static token that
* never changes. Only the nonce is included. The nonce is under
* the callers control unlike the other claims.
*/
#define TOKEN_OPT_OMIT_CLAIMS 0x40000000
/** A special test mode where a proper signature is not produced. In its place
* there is a concatenation of hashes of the payload to be the same size as the
* signature. This works and can be used to verify all of the SW stack except
* the public signature part. The token has no security value in this mode
* because anyone can replicate it. */
/**
* A special test mode where a proper signature is not produced. In
* its place there is a concatenation of hashes of the payload to be
* the same size as the signature. This works and can be used to
* verify all of the SW stack except the public signature part. The
* token has no security value in this mode because anyone can
* replicate it. */
#define TOKEN_OPT_SHORT_CIRCUIT_SIGN 0x80000000
/**
* The context for creating an attestation token.
* The caller of attest_token must create one of these
* and pass it to the functions here. It is small
* enough that it can go on the stack. It is most
* of the memory needed to create a token except
* the output buffer and any memory requirements
* for the cryptographic operations.
* The context for creating an attestation token. The caller of
* attest_token must create one of these and pass it to the functions
* here. It is small enough that it can go on the stack. It is most of
* the memory needed to create a token except the output buffer and
* any memory requirements for the cryptographic operations.
*
* The structure is opaque for the caller.
*
@ -97,56 +120,63 @@ struct attest_token_ctx {
/**
* \brief Initalize a token creation context.
* \brief Initialize a token creation context.
*
* \param[in] me The token creation context to be initialized
* \param[in] opt_flags Flags to select different custom options
* \param[in] key_select Selects which attestation key to sign with
* \param[in] alg_select Ciphersuite-like designator signing and hash
* algorithn to use
* \param[out] out_buffer The output buffer to write the encoded token into
* \param[in] me The token creation context to be initialized.
* \param[in] opt_flags Flags to select different custom options,
for example \ref TOKEN_OPT_OMIT_CLAIMS.
* \param[in] key_select Selects which attestation key to sign with.
* \param[in] cose_alg_id The algorithm to sign with. The IDs are
* defined in [COSE (RFC 8152)]
* (https://tools.ietf.org/html/rfc8152) or
* in the [IANA COSE Registry]
* (https://www.iana.org/assignments/cose/cose.xhtml).
* \param[out] out_buffer The output buffer to write the encoded token into.
*
* \return (TODO: error codes)
* \return one of the \ref attest_token_err_t errors.
*
* The size of the buffer in pOut (pOut->len) determines the size of the
* token that can be created. It must be able to hold the final encoded
* and signed token. The data encoding overhead is just that of
* CBOR. The signing overhead depends on the signing key size. It is
* about 150 bytes for ATTEST_TOKEN_CIPHERSUITE_256.
* The size of the buffer in \c out_buffer->len
* determines the size of the token that can be created. It must be
* able to hold the final encoded and signed token. The data encoding
* overhead is just that of CBOR. The signing overhead depends on the
* signing key size. It is about 150 bytes for 256-bit ECDSA.
*
* If \c out_buffer->ptr is \c NULL and \c out_buffer_ptr->len is
* large like \c UINT32_MAX no token will be created but the length of
* the token that would be created will be in \c completed_token as
* returned by attest_token_finish(). None of the cryptographic
* functions run during this, but the sizes of what they would output
* is taken into account.
*/
enum attest_token_err_t
attest_token_start(struct attest_token_ctx *me,
uint32_t opt_flags,
int32_t key_select,
int32_t alg_select,
struct useful_buf out_buffer);
int32_t cose_alg_id,
const struct useful_buf *out_buffer);
/**
* \brief Get a copy of the CBOR encoding context
*
* \param[in] me Token Creation Context.
* \param[in] me Token creation context.
*
* \return The CBOR encoding context
*
* Allows the caller to encode CBOR right into
* the output buffer using any of the QCBOREncode_AddXXXX()
* methods. Anything added here will be part of the
* payload that gets hashed. This can be used
* to make complex CBOR structures. All open
* arrays and maps must be close before calling
* any other attest_token methods.
* QCBOREncode_Finish() should not be closed on
* this context.
* Allows the caller to encode CBOR right into the output buffer using
* any of the \c QCBOREncode_AddXXXX() methods. Anything added here
* will be part of the payload that gets hashed. This can be used to
* make complex CBOR structures. All open arrays and maps must be
* close before calling any other \c attest_token methods. \c
* QCBOREncode_Finish() should not be closed on this context.
*/
QCBOREncodeContext *attest_token_borrow_cbor_cntxt(struct attest_token_ctx *me);
/**
* \brief Add a 64-bit signed integer claim
*
* \param[in] me Token Creation Context.
* \param[in] me Token creation context.
* \param[in] label Integer label for claim.
* \param[in] value The integer claim data.
*/
@ -157,40 +187,39 @@ void attest_token_add_integer(struct attest_token_ctx *me,
/**
* \brief Add a binary string claim
*
* \param[in] me Token Creation Context.
* \param[in] me Token creation context.
* \param[in] label Integer label for claim.
* \param[in] value The binary claim data.
*/
void attest_token_add_bstr(struct attest_token_ctx *me,
int32_t label,
struct useful_buf_c value);
const struct useful_buf_c *value);
/**
* \brief Add a text string claim
*
* \param[in] me Token Creation Context.
* \param[in] me Token creation context.
* \param[in] label Integer label for claim.
* \param[in] value The text claim data.
*/
void attest_token_add_tstr(struct attest_token_ctx *me,
int32_t label,
struct useful_buf_c value);
const struct useful_buf_c *value);
/**
* \brief Add some already-encoded CBOR to payload
*
* \param[in] me Token Creation Context.
* \param[in] me Token creation context.
* \param[in] label Integer label for claim.
* \param[in] encoded The already-encoded CBOR.
*
* Encoded CBOR must be a full map or full array
* or a non-aggregate type. It cannot be a partial
* map or array. It can be nested maps and
* arrays, but they must all be complete.
* Encoded CBOR must be a full map or full array or a non-aggregate
* type. It cannot be a partial map or array. It can be nested maps
* and arrays, but they must all be complete.
*/
void attest_token_add_encoded(struct attest_token_ctx *me,
int32_t label,
struct useful_buf_c encoded);
const struct useful_buf_c *encoded);
/**
@ -199,14 +228,14 @@ void attest_token_add_encoded(struct attest_token_ctx *me,
* \param[in] me Token Creation Context.
* \param[out] completed_token Pointer and length to completed token.
*
* \return One of the ATTEST_TOKEN_ERR_XXXX codes (TODO: fill all this in)
* \return one of the \ref attest_token_err_t errors.
*
* This completes the token after the payload has been added. When this
* is called the signing algorithm is run and the final formatting of
* the token is completed.
* This completes the token after the payload has been added. When
* this is called the signing algorithm is run and the final
* formatting of the token is completed.
*/
enum attest_token_err_t
attest_token_finish(struct attest_token_ctx *me,
struct useful_buf_c *completed_token);
#endif /* __ATTEST_TOKEN_h__ */
#endif /* __ATTEST_TOKEN_H__ */

View File

@ -9,7 +9,6 @@
#include <string.h>
#include <stddef.h>
#include "tfm_client.h"
#include "psa_initial_attestation_api.h"
#include "attestation.h"
#include "tfm_boot_status.h"
#include "tfm_plat_defs.h"
@ -18,8 +17,7 @@
#include "tfm_attest_hal.h"
#include "attest_token.h"
#include "attest_eat_defines.h"
#include "t_cose/src/t_cose_defines.h"
#include "useful_buf.h"
#include "t_cose_defines.h"
#define MAX_BOOT_STATUS 512
@ -230,7 +228,7 @@ static int32_t attest_get_tlv_by_id(uint8_t claim,
static enum psa_attest_err_t
attest_add_sw_component_claim(struct attest_token_ctx *token_ctx,
uint8_t tlv_id,
struct useful_buf_c claim_value)
const struct useful_buf_c *claim_value)
{
int32_t res;
uint32_t value;
@ -238,7 +236,7 @@ attest_add_sw_component_claim(struct attest_token_ctx *token_ctx,
switch (tlv_id) {
case SW_MEASURE_VALUE:
attest_token_add_bstr(token_ctx,
EAT_CBOR_SW_COMPONENT_MEASUREMENT,
EAT_CBOR_SW_COMPONENT_MEASUREMENT_VALUE,
claim_value);
break;
case SW_MEASURE_TYPE:
@ -257,17 +255,17 @@ attest_add_sw_component_claim(struct attest_token_ctx *token_ctx,
claim_value);
break;
case SW_EPOCH:
res = get_uint(claim_value.ptr, claim_value.len, &value);
res = get_uint(claim_value->ptr, claim_value->len, &value);
if (res) {
return PSA_ATTEST_ERR_GENERAL;
}
attest_token_add_integer(token_ctx,
EAT_CBOR_SW_COMPONENT_EPOCH,
EAT_CBOR_SW_COMPONENT_SECURITY_EPOCH,
(int64_t)value);
break;
case SW_TYPE:
attest_token_add_tstr(token_ctx,
EAT_CBOR_SW_COMPONENT_TYPE,
EAT_CBOR_SW_COMPONENT_MEASUREMENT_TYPE,
claim_value);
break;
default:
@ -311,7 +309,7 @@ attest_add_single_sw_measurment(struct attest_token_ctx *token_ctx,
/* Open nested map for SW component measurement claims */
if (nested_map) {
QCBOREncode_OpenMapInMapN(cbor_encode_ctx,
EAT_CBOR_SW_COMPONENT_MEASUREMENT);
EAT_CBOR_SW_COMPONENT_MEASUREMENT_VALUE);
}
/* Look up all measurement TLV entry which belongs to the SW component */
@ -320,7 +318,9 @@ attest_add_single_sw_measurment(struct attest_token_ctx *token_ctx,
if (GET_IAS_MEASUREMENT_CLAIM(tlv_id)) {
claim_value.ptr = tlv_ptr + SHARED_DATA_ENTRY_HEADER_SIZE;
claim_value.len = tlv_len - SHARED_DATA_ENTRY_HEADER_SIZE;
res = attest_add_sw_component_claim(token_ctx, tlv_id, claim_value);
res = attest_add_sw_component_claim(token_ctx,
tlv_id,
&claim_value);
if (res != PSA_ATTEST_ERR_SUCCESS) {
return res;
}
@ -387,7 +387,7 @@ attest_add_single_sw_component(struct attest_token_ctx *token_ctx,
/* Adding top level claims */
claim_value.ptr = tlv_ptr + SHARED_DATA_ENTRY_HEADER_SIZE;
claim_value.len = tlv_len - SHARED_DATA_ENTRY_HEADER_SIZE;
attest_add_sw_component_claim(token_ctx, tlv_id, claim_value);
attest_add_sw_component_claim(token_ctx, tlv_id, &claim_value);
}
/* Look up next entry which belongs to SW component */
@ -507,7 +507,7 @@ attest_add_boot_seed_claim(struct attest_token_ctx *token_ctx)
attest_token_add_bstr(token_ctx,
EAT_CBOR_ARM_LABEL_BOOT_SEED,
claim_value);
&claim_value);
return PSA_ATTEST_ERR_SUCCESS;
}
@ -546,7 +546,7 @@ attest_add_instance_id_claim(struct attest_token_ctx *token_ctx)
claim_value.len = size;
attest_token_add_bstr(token_ctx,
EAT_CBOR_ARM_LABEL_UEID,
claim_value);
&claim_value);
return PSA_ATTEST_ERR_SUCCESS;
}
@ -580,7 +580,7 @@ attest_add_implementation_id_claim(struct attest_token_ctx *token_ctx)
claim_value.len = size;
attest_token_add_bstr(token_ctx,
EAT_CBOR_ARM_LABEL_IMPLEMENTATION_ID,
claim_value);
&claim_value);
return PSA_ATTEST_ERR_SUCCESS;
}
@ -629,7 +629,7 @@ attest_add_hw_version_claim(struct attest_token_ctx *token_ctx)
attest_token_add_tstr(token_ctx,
EAT_CBOR_ARM_LABEL_HW_VERSION,
claim_value);
&claim_value);
return PSA_ATTEST_ERR_SUCCESS;
}
@ -720,10 +720,10 @@ attest_add_security_lifecycle_claim(struct attest_token_ctx *token_ctx)
* \return Returns error code as specified in \ref psa_attest_err_t
*/
static enum psa_attest_err_t
attest_add_challenge_claim(struct attest_token_ctx *token_ctx,
struct useful_buf_c challenge)
attest_add_challenge_claim(struct attest_token_ctx *token_ctx,
const struct useful_buf_c *challenge)
{
attest_token_add_bstr(token_ctx, EAT_CBOR_ARM_LABEL_NONCE, challenge);
attest_token_add_bstr(token_ctx, EAT_CBOR_ARM_LABEL_CHALLENGE, challenge);
return PSA_ATTEST_ERR_SUCCESS;
}
@ -748,7 +748,7 @@ attest_add_verification_service(struct attest_token_ctx *token_ctx)
service.len = size;
attest_token_add_tstr(token_ctx,
EAT_CBOR_ARM_LABEL_ORIGINATION,
service);
&service);
}
return PSA_ATTEST_ERR_SUCCESS;
@ -773,7 +773,7 @@ attest_add_profile_definition(struct attest_token_ctx *token_ctx)
profile.len = size;
attest_token_add_tstr(token_ctx,
EAT_CBOR_ARM_LABEL_PROFILE_DEFINITION,
profile);
&profile);
}
return PSA_ATTEST_ERR_SUCCESS;
@ -816,8 +816,8 @@ static enum psa_attest_err_t attest_verify_challenge_size(size_t challenge_size)
* \return Returns error code as specified in \ref psa_attest_err_t
*/
static enum psa_attest_err_t
attest_create_token(struct useful_buf_c challenge,
struct useful_buf token,
attest_create_token(struct useful_buf_c *challenge,
struct useful_buf *token,
struct useful_buf_c *completed_token)
{
enum psa_attest_err_t attest_err = PSA_ATTEST_ERR_SUCCESS;
@ -827,20 +827,12 @@ attest_create_token(struct useful_buf_c challenge,
int32_t alg_select;
uint32_t option_flags = 0;
if (challenge.len == 36) {
if (challenge->len == 36) {
/* FixMe: Special challenge with option flags appended. This might can
* be removed when the public API can take option_flags.
*/
option_flags = *(uint32_t *)(challenge.ptr + 32);
challenge.len = 32;
/* Special case to get the size of the minimal token (just hard coded
* challenge is included)
*/
if (challenge.ptr == NULL) {
option_flags |= TOKEN_OPT_SHORT_CIRCUIT_SIGN |
TOKEN_OPT_OMIT_CLAIMS;
}
option_flags = *(uint32_t *)(challenge->ptr + 32);
challenge->len = 32;
}
/* Lower three bits are the key select */
@ -851,16 +843,16 @@ attest_create_token(struct useful_buf_c challenge,
*/
switch (key_select) {
default:
alg_select = COSE_ALG_ES256;
alg_select = COSE_ALGORITHM_ES256;
}
/* Get started creating the token. This sets up the CBOR and COSE contexts
* which causes the COSE headers to be constructed.
*/
token_err = attest_token_start(&attest_token_ctx,
option_flags, /* option_flags */
key_select, /* key_select */
COSE_ALG_ES256, /* alg_select */
option_flags, /* option_flags */
key_select, /* key_select */
COSE_ALGORITHM_ES256, /* alg_select */
token);
if (token_err != ATTEST_TOKEN_ERR_SUCCESS) {
@ -950,7 +942,7 @@ initial_attest_get_token(const psa_invec *in_vec, uint32_t num_invec,
psa_outvec *out_vec, uint32_t num_outvec)
{
enum psa_attest_err_t attest_err = PSA_ATTEST_ERR_SUCCESS;
struct useful_buf_c challenge;
struct useful_buf_c challenge;
struct useful_buf token;
struct useful_buf_c completed_token;
@ -978,7 +970,7 @@ initial_attest_get_token(const psa_invec *in_vec, uint32_t num_invec,
goto error;
}
attest_err = attest_create_token(challenge, token, &completed_token);
attest_err = attest_create_token(&challenge, &token, &completed_token);
if (attest_err != PSA_ATTEST_ERR_SUCCESS) {
goto error;
}
@ -1020,7 +1012,7 @@ initial_attest_get_token_size(const psa_invec *in_vec, uint32_t num_invec,
goto error;
}
attest_err = attest_create_token(challenge, token, &completed_token);
attest_err = attest_create_token(&challenge, &token, &completed_token);
if (attest_err != PSA_ATTEST_ERR_SUCCESS) {
goto error;
}

View File

@ -1,61 +0,0 @@
/*
* Copyright (c) 2019, Arm Limited. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*
*/
#ifndef __ATTESTATION_KEY_H__
#define __ATTESTATION_KEY_H__
#include "psa_initial_attestation_api.h"
#ifdef __cplusplus
extern "C" {
#endif
/**
* \def ATTEST_PRIVATE_KEY_SLOT
*
* \brief Key slot number to store the initial attestation private key.
*
* Private key is used by initial attestation service to sign the
* initial attestation token (IAT).
*/
#define ATTEST_PRIVATE_KEY_SLOT (1u)
/**
* \def ATTEST_PUBLIC_KEY_SLOT
*
* \brief Key slot number to store the initial attestation public key.
*
* Public key is used by initial attestation test suit to verify the signature
* of the initial attestation token (IAT).
*/
#define ATTEST_PUBLIC_KEY_SLOT (2u)
/**
* \brief Get the initial attestation key from platform layer and register it
* to crypto service for further usage (signing or verification).
*
* Private key MUST be present on the device, public key is optional.
*
* \retval PSA_ATTEST_ERR_SUCCESS Key(s) was registered.
* \retval PSA_ATTEST_ERR_GENERAL Key(s) could not be registered.
*/
enum psa_attest_err_t attest_register_initial_attestation_key(void);
/**
* \brief Unregister the initial attestation key(s) from crypto service to do
* not occupy key slot(s).
*
* \retval PSA_ATTEST_ERR_SUCCESS Key(s) was unregistered.
* \retval PSA_ATTEST_ERR_GENERAL Key(s) could not be unregistered.
*/
enum psa_attest_err_t attest_unregister_initial_attestation_key(void);
#ifdef __cplusplus
}
#endif
#endif /* __ATTESTATION_KEY_H__ */

View File

@ -1,32 +0,0 @@
/*
* eat_attest_defines.h
*
* Copyright (c) 2018-2019, Laurence Lundblade. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*
* See BSD-3-Clause license in README.md
*/
#ifndef __EAT_ATTEST_DEFINES_H__
#define __EAT_ATTEST_DEFINES_H__
/* These are definitions of labels for claims for EAT. EAT is
is still in development so, these are not official values
of any sort yet
*/
#define EAT_CBOR_LABEL_NONCE 44
#define EAT_CBOR_LABEL_SW_COMPONENTS 55
#define EAT_CBOR_LABEL_SW_NAME 66
#define EAT_CBOR_LABEL_VERSION 88
#define EAT_CBOR_LABEL_MEASUREMENT 99
#define EAT_CBOR_LABEL_MEASUREMENT_VALUE 77
#define EAT_CBOR_LABEL_MEASUREMENT_TYPE 99
#endif /* __EAT_ATTEST_DEFINES_H__ */

View File

@ -18,7 +18,7 @@ embedded_project_start(CONFIG "${CMAKE_CURRENT_LIST_DIR}/../../../ConfigDefault.
project(tfm_qcbor LANGUAGES C)
embedded_project_fixup()
###Some project global settings
#Some project global settings
set (QCBOR_DIR "${CMAKE_CURRENT_LIST_DIR}")
#Append all our source files to global lists.
@ -32,11 +32,10 @@ list(APPEND ALL_SRC_C
#Setting include directories
embedded_include_directories(PATH ${QCBOR_DIR}/inc ABSOLUTE)
#Specify what we build (for the QCBOR, build as a static library)
add_library(${PROJECT_NAME} STATIC ${ALL_SRC_C})
#Specify what we build (for the QCBOR, build as an object library)
add_library(${PROJECT_NAME} OBJECT ${ALL_SRC_C})
#Set common compiler and linker flags
config_setting_shared_compiler_flags(tfm_qcbor)
config_setting_shared_linker_flags(tfm_qcbor)
#Set common compiler flags
config_setting_shared_compiler_flags(${PROJECT_NAME})
embedded_project_end(${PROJECT_NAME})

View File

@ -15,18 +15,11 @@
#include "UsefulBuf.h"
/*
T H E C O M M E N T S
in this file are truthful, but not expansive,
complete of formatted yet...
*/
/**
\file TF-M coding style version of UsefulBuf
* \file useful_buf.h
*
* \brief This is a TF-M coding style version of UsefulBuf.
* See UsefulBuf for documentation of these functions.
*/
@ -35,7 +28,6 @@
#define NULL_USEFUL_BUF NULLUsefulBuf
/* See UsefulBuf.h */
static inline int useful_buf_c_is_null(struct useful_buf_c in)
{
return UsefulBuf_IsNULLC(in);

View File

@ -101,7 +101,7 @@ test_entry2 s_tests2[] = {
test_entry s_tests[] = {
TEST_ENTRY(ParseMapAsArrayTest),
TEST_ENTRY(AllocAllStringsTest),
TEST_ENTRY_DISABLED(AllocAllStringsTest),
TEST_ENTRY(IndefiniteLengthNestTest),
TEST_ENTRY(NestedMapTestIndefLen),
TEST_ENTRY(ParseSimpleTest),
@ -118,7 +118,7 @@ test_entry s_tests[] = {
TEST_ENTRY(ParseTooDeepArrayTest),
TEST_ENTRY(ComprehensiveInputTest),
TEST_ENTRY(ParseMapTest),
TEST_ENTRY(IndefiniteLengthArrayMapTest),
TEST_ENTRY_DISABLED(IndefiniteLengthArrayMapTest),
TEST_ENTRY(BasicEncodeTest),
TEST_ENTRY(NestedMapTest),
TEST_ENTRY(BignumParseTest),
@ -129,8 +129,8 @@ test_entry s_tests[] = {
TEST_ENTRY(ParseDeepArrayTest),
TEST_ENTRY(SimpleArrayTest),
TEST_ENTRY(IntegerValuesParseTest),
TEST_ENTRY(MemPoolTest),
TEST_ENTRY(IndefiniteLengthStringTest),
TEST_ENTRY_DISABLED(MemPoolTest),
TEST_ENTRY_DISABLED(IndefiniteLengthStringTest),
TEST_ENTRY(HalfPrecisionDecodeBasicTests),
TEST_ENTRY(DoubleAsSmallestTest),
TEST_ENTRY(HalfPrecisionAgainstRFCCodeTest),

View File

@ -0,0 +1,40 @@
#-------------------------------------------------------------------------------
# Copyright (c) 2019, Arm Limited. All rights reserved.
#
# SPDX-License-Identifier: BSD-3-Clause
#
#-------------------------------------------------------------------------------
cmake_minimum_required(VERSION 3.7)
#Tell cmake where our modules can be found
list(APPEND CMAKE_MODULE_PATH ${CMAKE_CURRENT_LIST_DIR}/../../../cmake)
#Include common stuff to control cmake.
include("Common/BuildSys")
#Start an embedded project.
embedded_project_start(CONFIG "${CMAKE_CURRENT_LIST_DIR}/../../ConfigDefault.cmake")
project(tfm_t_cose LANGUAGES C)
embedded_project_fixup()
#Some project global settings
set(T_COSE_DIR "${CMAKE_CURRENT_LIST_DIR}")
#Append all our source files to global lists.
list(APPEND ALL_SRC_C
"${T_COSE_DIR}/src/t_cose_sign1_sign.c"
"${T_COSE_DIR}/src/t_cose_util.c"
"${T_COSE_DIR}/src/t_cose_psa_crypto.c"
)
#Setting include directories
embedded_include_directories(PATH ${T_COSE_DIR}/inc ABSOLUTE)
#Specify what we build (for the t_cose, build as an object library)
add_library(${PROJECT_NAME} OBJECT ${ALL_SRC_C})
#Set common compiler flags
config_setting_shared_compiler_flags(${PROJECT_NAME})
embedded_project_end(${PROJECT_NAME})

View File

@ -0,0 +1,95 @@
# t_cose
## Introduction
t_cose is a partial implementation of the COSE standard (RFC 8152).
COSE is quite a large standard so a full implementation of all of it
is a large undertaking. This implementation is starting out as just
enough for attestation and maybe CWT (Cbor Web Token) which is very
similar.
As it may grow to support more of COSE over time, it is structured
with that in mind.
It is also trying to be portable, the most interesting part of which
is interfacing with the libraries for performing cryptography and
access cryptographic keys.
## Source files
The following files are more or less the public interface.
* t_cose_common.h
* t_cose_sign1.h
* t_cose_sign1_verify.h
The rest of the files are internal source files that callers should
not depend on.
t_cose_defines.h contains contants from RFC 8152 that are
part of the COSE standard. It should never have anything else
in it.
t_cose_util is some utilities and code common to
signing and verification. Both signing and verifcation
depend on it.
t_cose_crypto is the crypto porting layer. Generally
the .h file should not need to change for a new
platform. The .c file will be changed lots for
each new platform.
## Dependency and Portability
t_cose is attempting to be very portable and
have a minmum number of #ifdefs. It is
designed to run 64-bit and 32-bit machines.
It uses a minimum number of standard C
libraries, mostly just <stdint.h>, <string.h> and <stddef.h>.
It uses QCBOR for CBOR encoding and decoding.
QCBOR is very portable.
### Cryptography and Keys
There is a cryptographic adaption layer that
provides the following:
* Impedence match of parameters passed to/from the crypto
* Management of algorithm identifiers
* Management of error codes
* Management of key identifiers
It is framed for the needs of t_cose, and is
not trying to be any kind of general crypto API.
#### Question
Q: How many crypto APIs does it take to screw in a light bulb?
A: One more than it takes to screw in a light bulb.
## Copyright and License
### BSD-3-Clause license
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
* Neither the name of the copyright holder nor the names of its
contributors may be used to endorse or promote products derived from
this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
### Copyright for this README
Copyright (c) 2018-2019, Laurence Lundblade. All rights reserved.

View File

@ -0,0 +1,148 @@
/*
* t_cose_common.h
*
* Copyright 2019, Laurence Lundblade
*
* SPDX-License-Identifier: BSD-3-Clause
*
* See BSD-3-Clause license in README.mdE.
*/
#ifndef __T_COSE_COMMON_H__
#define __T_COSE_COMMON_H__
/**
* \file t_cose_common.h
*
* \brief Defines common to all public t_cose interfaces.
*
*/
/* Private value. Intentionally not documented for Doxygen.
* This is the size allocated for the encoded protected headers. It
* needs to be big enough for make_protected_header() to succeed. It
* currently sized for one header with an algorithm ID up to 32 bits
* long -- one byte for the wrapping map, one byte for the label, 5
* bytes for the ID. If this is made accidentially too small, QCBOR will
* only return an error, and not overrun any buffers.
*
* 9 extra bytes are added, rounding it up to 16 total, in case some
* other protected header is to be added.
*/
#define T_COSE_SIGN1_MAX_PROT_HEADER (1+1+5+9)
/**
* Error codes return by t_cose.
*
* Do not reorder these. It is OK to add
* new ones at the end.
*/
enum t_cose_err_t {
/**
* Operation completed successfully
*/
T_COSE_SUCCESS = 0,
/**
* The requested signing algorithm is not supported.
*/
T_COSE_ERR_UNSUPPORTED_SIGNING_ALG,
/**
* Error constructing the protected headers.
*/
T_COSE_ERR_PROTECTED_HEADERS,
/**
* The hash algorithm needed is not supported. Note that the
* signing algorithm identifier usually identifies the hash
* algorithm.
*/
T_COSE_ERR_UNSUPPORTED_HASH,
/**
* Some system failure when running the hash algorithm.
*/
T_COSE_ERR_HASH_GENERAL_FAIL,
/**
* The buffer to receive a hash result is too small.
*/
T_COSE_ERR_HASH_BUFFER_SIZE,
/**
* The buffer to receive result of a signing operation is too
* small.
*/
T_COSE_ERR_SIG_BUFFER_SIZE,
/**
* The buffer to receive to receive a key is too small.
*/
T_COSE_ERR_KEY_BUFFER_SIZE,
/**
* When verifying a \c COSE_Sign1, something is wrong with the
* format of the CBOR. For example, it is missing something like
* the payload.
*/
T_COSE_ERR_SIGN1_FORMAT,
/**
* When decoding some CBOR like a \c COSE_Sign1, the CBOR was not
* well-formed. Most likely what was supposed to be CBOR was is
* either not or it has been corrupted.
*/
T_COSE_ERR_CBOR_NOT_WELL_FORMED,
/**
* No algorithm ID was found when one is needed. For example, when
* verifying a \c COSE_Sign1.
*/
T_COSE_ERR_NO_ALG_ID,
/**
* No key ID was found when one is needed. For example, when
* verifying a \c COSE_Sign1.
*/
T_COSE_ERR_NO_KID,
/**
* Signature verification failed. For example, the cryptographic
* operations completed successfully but hash wasn't as expected.
*/
T_COSE_ERR_SIG_VERIFY,
/**
* Verification of a short-circuit signature failed.
*/
T_COSE_ERR_BAD_SHORT_CIRCUIT_KID,
/**
* Some (unspecified) argument was not valid.
*/
T_COSE_ERR_INVALID_ARGUMENT,
/**
* Out of heap memory.
*/
T_COSE_ERR_INSUFFICIENT_MEMORY,
/**
* General unspecific failure.
*/
T_COSE_ERR_FAIL,
/**
* Equivalent to \c PSA_ERROR_TAMPERING_DETECTED.
*/
T_COSE_ERR_TAMPERING_DETECTED,
/**
* The key identified by a key slot of a key ID was not found.
*/
T_COSE_ERR_UNKNOWN_KEY,
/**
* The key was found, but it was the wrong type for the operation.
*/
T_COSE_ERR_WRONG_TYPE_OF_KEY,
/**
* Error constructing the \c Sig_structure when signing or verify.
*/
T_COSE_ERR_SIG_STRUCT,
/**
* Signature was short-circuit. THe option to allow verification
* of short-circuit signatures was not set
*/
T_COSE_ERR_SHORT_CIRCUIT_SIG
};
#endif /* __T_COSE_COMMON_H__ */

View File

@ -0,0 +1,181 @@
/*
* t_cose_sign1_sign.h
*
* Copyright (c) 2018-2019, Laurence Lundblade. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*
* See BSD-3-Clause license in README.md
*/
#ifndef __T_COSE_SIGN1_H__
#define __T_COSE_SIGN1_H__
#include <stdint.h>
#include <stdbool.h>
#include "qcbor.h"
#include "t_cose_common.h"
/**
* \file t_cose_sign1_sign.h
*
* \brief Create a \c COSE_Sign1, usually for EAT or CWT Token.
*
* This creates a \c COSE_Sign1 in compliance with [COSE (RFC 8152)]
* (https://tools.ietf.org/html/rfc8152). A \c COSE_Sign1 is a CBOR
* encoded binary blob that contains headers, a payload and a
* signature. Usually the signature is made with an EC signing
* algorithm like ECDSA.
*
* This implementation is intended to be small and portable to
* different OS's and platforms. Its dependencies are:
* - QCBOR
* - <stdint.h>, <string.h>, <stddef.h>
* - Hash functions like SHA-256
* - Signing functions like ECDSA
*
* There is a cryptographic adaptation layer defined in
* t_cose_crypto.h. An implementation can be made of the functions in
* it for different platforms or OS's. This means that different
* platforms and OS's may support only signing with a particular set
* of algorithms.
*
* This \c COSE_Sign1 implementations is optimized for creating EAT
* tokens.
*
* It should work for CWT and others use cases too. The main point of
* the optimization is that only one output buffer is needed. There is
* no need for one buffer to hold the payload and another to hold the
* end result \c COSE_Sign1. The payload is encoded right into its final
* place in the end result \c COSE_Sign1.
*/
/**
* This is the context for creating a \c COSE_Sign1 structure. The caller
* should allocate it and pass it to the functions here. This is
* about 32 bytes so it fits easily on the stack.
*/
struct t_cose_sign1_ctx {
/* Private data structure */
uint8_t buffer_for_protected_headers[
T_COSE_SIGN1_MAX_PROT_HEADER];
struct useful_buf_c protected_headers;
int32_t cose_algorithm_id;
int32_t key_select;
bool short_circuit_sign;
QCBOREncodeContext *cbor_encode_ctx;
};
/**
* \brief Initialize to start creating a \c COSE_Sign1.
*
* \param[in] me The t_cose signing context.
* \param[in] short_circuit_sign \c true to select special test mode.
* \param[in] cose_algorithm_id The algorithm to sign with. The IDs are
* defined in [COSE (RFC 8152)]
* (https://tools.ietf.org/html/rfc8152) or
* in the [IANA COSE Registry]
* (https://www.iana.org/assignments/cose/cose.xhtml).
* \param[in] key_select Which signing key to use.
* \param[in] cbor_encode_ctx The CBOR encoder context to output to.
*
* \return This returns one of the error codes defined by \ref t_cose_err_t.
*
* It is possible to use this to compute the exact size of the
* resulting token so the exact sized buffer can be allocated. To do
* this initialize the \c cbor_encode_ctx with \c UsefulBufC that has
* a \c NULL pointer and large length like \c UINT32_MAX. Then run the
* normal token creation. The result will have a NULL pointer and the
* length of the token that would have been created. When this is run
* like this, the cryptographic functions will not actually run, but
* the size of their output will be taken into account.
*
* The key selection depends on the platform / OS.
*
* Which signing algorithms are supported depends on the platform/OS.
* The header file t_cose_defines.h contains defined constants for
* some of them. A typical example is \ref COSE_ALGORITHM_ES256 which
* indicates ECDSA with the NIST P-256 curve and SHA-256.
*
* To use this, create a \c QCBOREncodeContext and initialize it with
* an output buffer big enough to hold the payload and the COSE Sign 1
* overhead. This overhead is about 30 bytes plus the size of the
* signature and the size of the key ID.
*
* After the \c QCBOREncodeContext is initialized, call
* t_cose_sign1_init() on it.
*
* Next call \c QCBOREncode_BstrWrap() to indicate the start of the
* payload.
*
* Next call various \c QCBOREncode_Addxxxx() methods to create the
* payload.
*
* Next call \c QCBOREncode_CloseBstrWrap() to indicate the end of the
* payload. This will also return a pointer and length of the payload
* that gets hashed.
*
* Next call t_cose_sign1_finish() with the pointer and length of the
* payload. This will do all the cryptography and complete the COSE
* Sign1.
*
* Finally, call \c QCBOREncode_Finish() to get the pointer and length
* of the complete token.
*
* This implements a special signing test mode called _short_
* _circuit_ _signing_. This mode is useful when there is no signing
* key available, perhaps because it has not been provisioned or
* configured for the particular device. It may also be because the
* public key cryptographic functions have not been connected up in
* the cryptographic adaptation layer.
*
* It has no value for security at all. Data signed this way should
* not be trusted as anyone can sign like this.
*
* In this mode the signature is the hash of that would normally be
* signed by the public key algorithm. To make the signature the
* correct size for the particular algorithm instances of the hash are
* concatenated to pad it out.
*
* This mode is very useful for testing because all the code except
* the actual signing algorithm is run exactly as it would if a proper
* signing algorithm was run.
*
* The kid (Key ID) put in the unprotected headers is created as
* follows. The EC public key is CBOR encoded as a \c COSE_Key as
* defined in the COSE standard. That encoded CBOR is then
* hashed with SHA-256. This is similar to key IDs defined in IETF
* PKIX, but is based on COSE and CBOR rather than ASN.1.
*/
enum t_cose_err_t t_cose_sign1_init(struct t_cose_sign1_ctx *me,
bool short_circuit_sign,
int32_t cose_algorithm_id,
int32_t key_select,
QCBOREncodeContext *cbor_encode_ctx);
/**
* \brief Finish creation of the \c COSE_Sign1.
*
* \param[in] me The t_cose signing context.
* \param[in] payload The pointer and length of the payload.
*
* \return This returns one of the error codes defined by \ref t_cose_err_t.
*
* Call this to complete creation of a signed token started with
* t_cose_sign1_init().
*
* This is when the signature algorithm is run.
*
* The payload parameter is used only to compute the hash for
* signing. The completed \c COSE_Sign1 is retrieved from the \c
* cbor_encode_ctx by calling \c QCBOREncode_Finish()
*/
enum t_cose_err_t t_cose_sign1_finish(struct t_cose_sign1_ctx *me,
struct useful_buf_c payload);
#endif /* __T_COSE_SIGN1_H__ */

View File

@ -0,0 +1,413 @@
/*
* t_cose_crypto.h
*
* Copyright 2019, Laurence Lundblade
*
* SPDX-License-Identifier: BSD-3-Clause
*
* See BSD-3-Clause license in README.mdE.
*/
#ifndef __T_COSE_CRYPTO_H__
#define __T_COSE_CRYPTO_H__
#include "t_cose_common.h"
#include "useful_buf.h"
#include <stdint.h>
#include "t_cose_defines.h"
/**
* \file t_cose_crypto.h
*
* \brief This is the adaptation layer for cryptographic functions used by
* t_cose.
*
* This is small wrapper around the cryptographic functions to:
* - Map COSE algorithm IDs to TF-M algorithm IDs
* - Map crypto errors to \ref t_cose_err_t errors
* - Have inputs and outputs be \c struct \c useful_buf_c and
* \c struct \c useful_buf
* - Handle key selection
*
* The idea is that implementations can be made of these functions
* that adapt to various cryptographic libraries that are used on
* various platforms and OSs.
*
* This runs entirely off of COSE-style algorithm identifiers. They
* are simple integers and thus work nice as function parameters. An
* initial set is defined by [COSE (RFC 8152)]
* (https://tools.ietf.org/html/rfc8152). New ones can be registered
* in the [IANA COSE Registry]
* (https://www.iana.org/assignments/cose/cose.xhtml). Local use new
* ones can also be defined (\c \#define) if what is needed is not in
* the IANA registry.
*
* Binary data is returned to the caller using a \c struct \c
* useful_buf to pass the buffer to receive the data and its length in
* and a \c useful_buf_c to return the pointer and length of the
* returned data. The point of this is coding hygiene. The buffer
* passed in is not const as it is to be modified. The \c
* useful_buf_c returned is const.
*
* The pointer in the \c useful_buf_c will always point to the buffer
* passed in via the \c useful_buf so the lifetime of the data is
* under control of the caller.
*
* This is not intended as any sort of general cryptographic API. It
* is just the functions needed by t_cose in the form that is most
* useful for t_cose.
*/
/**
* Size of the signature output for the NIST P-256 Curve.
*/
#define T_COSE_EC_P256_SIG_SIZE 64
/**
* Size of the largest signature of any of the algorithm types
* supported.
*
* This will have to be adjusted if support for other algorithms
* larger is added.
*
* This is a compile time constant so it can be used to define stack
* variable sizes.
*/
#define T_COSE_MAX_EC_SIG_SIZE T_COSE_EC_P256_SIG_SIZE
/**
* \brief Get the size in bytes of a particular signature type.
*
* \param[in] cose_sig_alg_id The COSE algorithm ID.
*
* \return The size in bytes of the signature for a public-key signing
* algorithm.
*/
static inline size_t t_cose_signature_size(int32_t cose_sig_alg_id);
/**
* \brief Perform public key signing. Part of the t_cose crypto
* adaptation layer.
*
* \param[in] cose_alg_id The algorithm to sign with. The IDs are
* defined in [COSE (RFC 8152)]
* (https://tools.ietf.org/html/rfc8152) or
* in the [IANA COSE Registry]
* (https://www.iana.org/assignments/cose/cose.xhtml).
* A proprietary ID can also be defined
* locally (\c \#define) if the needed
* one hasn't been registered.
* \param[in] key_select Indicates which key to use to sign.
* \param[in] hash_to_sign The bytes to sign. Typically, a hash of
* a payload.
* \param[in] signature_buffer Pointer and length of buffer into which
* the resulting signature is put.
* \param[in] signature Pointer and length of the signature
* returned.
*
* \retval T_COSE_SUCCESS
* Successfully created the signature.
* \retval T_COSE_ERR_SIG_BUFFER_SIZE
* The \c signature_buffer too small.
* \retval T_COSE_ERR_UNSUPPORTED_SIGNING_ALG
* The requested signing algorithm, \c cose_alg_id, is not
* supported.
* \retval T_COSE_ERR_UNKNOWN_KEY
* The key identified by \c key_select was not found.
* \retval T_COSE_ERR_WRONG_TYPE_OF_KEY
* The key was found, but it was the wrong type.
* \retval T_COSE_ERR_INVALID_ARGUMENT
* Some (unspecified) argument was not valid.
* \retval T_COSE_ERR_INSUFFICIENT_MEMORY
* Insufficient heap memory.
* \retval T_COSE_ERR_FAIL
* General unspecific failure.
* \retval T_COSE_ERR_TAMPERING_DETECTED
* Equivalent to \c PSA_ERROR_TAMPERING_DETECTED.
*
* This is called to do public key signing. The implementation will
* vary from one platform / OS to another but should conform to the
* description here.
*
* The key selection depends on the platform / OS.
*
* See the note in the Detailed Description (the \\file comment block)
* for details on how \c useful_buf and \c useful_buf_c are used to
* return the signature.
*
* To find out the size of the signature buffer needed, call this with
* \c signature_buffer->ptr \c NULL and \c signature_buffer->len a
* very large number like \c UINT32_MAX. The size will be returned in
* \c signature->len.
*/
enum t_cose_err_t
t_cose_crypto_pub_key_sign(int32_t cose_alg_id,
int32_t key_select,
struct useful_buf_c hash_to_sign,
struct useful_buf signature_buffer,
struct useful_buf_c *signature);
/**
* \brief perform public key signature verification. Part of the
* t_cose crypto adaptation layer.
*
* \param[in] cose_alg_id The algorithm to use for verification.
* The IDs are defined in [COSE (RFC 8152)]
* (https://tools.ietf.org/html/rfc8152)
* or in the [IANA COSE Registry]
* (https://www.iana.org/assignments/cose/cose.xhtml).
* A proprietary ID can also be defined
* locally (\c \#define) if the needed one
* hasn't been registered.
* \param[in] key_select Verification key selection.
* \param[in] key_id A key id or \c NULL_USEFUL_BUF_C.
* \param[in] hash_to_verify The data or hash that is to be verified.
* \param[in] signature The signature.
*
* This verifies that the \c signature passed in was over the \c
* hash_to_verify passed in.
*
* The public key used to verify the signature is selected by the \c
* key_id if it is not \c NULL_USEFUL_BUF_C or the \c key_select if it
* is.
*
* The key selected must be, or include, a public key of the correct
* type for \c cose_alg_id.
*
* \retval T_COSE_SUCCESS
* The signature is valid
* \retval T_COSE_ERR_SIG_VERIFY
* Signature verification failed. For example, the
* cryptographic operations completed successfully but hash
* wasn't as expected.
* \retval T_COSE_ERR_UNKNOWN_KEY
* The key identified by \c key_select or a \c kid was
* not found.
* \retval T_COSE_ERR_WRONG_TYPE_OF_KEY
* The key was found, but it was the wrong type
* for the operation.
* \retval T_COSE_ERR_UNSUPPORTED_SIGNING_ALG
* The requested signing algorithm is not supported.
* \retval T_COSE_ERR_INVALID_ARGUMENT
* Some (unspecified) argument was not valid.
* \retval T_COSE_ERR_INSUFFICIENT_MEMORY
* Out of heap memory.
* \retval T_COSE_ERR_FAIL
* General unspecific failure.
* \retval T_COSE_ERR_TAMPERING_DETECTED
* Equivalent to \c PSA_ERROR_TAMPERING_DETECTED.
*/
enum t_cose_err_t
t_cose_crypto_pub_key_verify(int32_t cose_alg_id,
int32_t key_select,
struct useful_buf_c key_id,
struct useful_buf_c hash_to_verify,
struct useful_buf_c signature);
/**
* The size of X and Y coordinate in 2 parameter style EC public
* key. Format is as defined in [COSE (RFC 8152)]
* (https://tools.ietf.org/html/rfc8152) and [SEC 1: Elliptic Curve
* Cryptography](http://www.secg.org/sec1-v2.pdf).
*
* This size is well-known and documented in public standards.
*/
#define T_COSE_CRYPTO_EC_P256_COORD_SIZE 32
/**
* \brief Get an elliptic curve public key. Part of the t_cose crypto
* adaptation layer.
*
* \param[in] key_select Used to look up the public
* key to return when \c kid is
* \c NULL_USEFUL_BUF_C.
* \param[in] kid A key ID to look up against. May be
* \c NULL_USEFUL_BUF_C. This is typically
* the kid from the COSE unprotected header.
* \param[out] cose_curve_id The curve ID of the key returned as
* defined by [COSE (RFC 8152)]
* (https://tools.ietf.org/html/rfc8152)
* or the IANA COSE registry.
* \param[in] buf_to_hold_x_coord Pointer and length into which the
* X coordinate is put.
* \param[in] buf_to_hold_y_coord Pointer and length into which the
* Y coordinate is put.
* \param[out] x_coord Pointer and length of the returned X
* coordinate.
* \param[out] y_coord Pointer and length of the returned Y
* coordinate.
*
* \retval T_COSE_SUCCESS
* The key was found and is returned.
* \retval T_COSE_ERR_UNKNOWN_KEY
* The key identified by \c key_select or a \c kid was not
* found.
* \retval T_COSE_ERR_WRONG_TYPE_OF_KEY
* The key was found, but it was the wrong type for the
* operation.
* \retval T_COSE_ERR_FAIL
* General unspecific failure.
* \retval T_COSE_ERR_KEY_BUFFER_SIZE
* Buffer to hold the output was too small.
*
* This finds and returns a public key. Where it looks for the key is
* dependent on the OS / platform.
*
* \ref T_COSE_CRYPTO_EC_P256_COORD_SIZE is the size of the X or Y
* coordinate for the NIST P-256 curve.
*
* See the note in the Detailed Description (the \\file comment block)
* for details on how \c useful_buf and \c useful_buf_c are used to
* return the X and Y coordinates.
*/
enum t_cose_err_t
t_cose_crypto_get_ec_pub_key(int32_t key_select,
struct useful_buf_c kid,
int32_t *cose_curve_id,
struct useful_buf buf_to_hold_x_coord,
struct useful_buf buf_to_hold_y_coord,
struct useful_buf_c *x_coord,
struct useful_buf_c *y_coord);
/*
* No function to get private key because there is no need for it.
* The private signing key only needs to exist behind
* t_cose_crypto_pub_key_sign().
*/
/**
* The context for use with the hash adaptation layer here.
*/
struct t_cose_crypto_hash {
/* Can't put the actual size here without creating dependecy on
* actual hash implementation, so this is a fairly large and
* accommodating size.
*/
uint8_t bytes[128];
};
/**
* The size of the output of SHA-256 in bytes.
*
* (It is safe to define this independently here as its size is
* well-known and fixed. There is no need to reference
* platform-specific headers and incur messy dependence.)
*/
#define T_COSE_CRYPTO_SHA256_SIZE 32
/**
* \brief Start cryptographic hash. Part of the t_cose crypto
* adaptation layer.
*
* \param[in,out] hash_ctx Pointer to the hash context that
* will be initialized.
* \param[in] cose_hash_alg_id Algorithm ID that identifies the
* hash to use. This is from the
* [IANA COSE Registry]
* (https://www.iana.org/assignments/cose/cose.xhtml).
* As of the creation of this interface
* no identifiers of only a hash
* functions have been registered.
* Signature algorithms that include
* specification of the hash have been
* registered, but they are not to be
* used here. Until hash functions only
* have been officially registered, some
* IDs are defined in the proprietary
* space in t_cose_common.h.
*
* \retval T_COSE_ERR_UNSUPPORTED_HASH
* The requested algorithm is unknown or unsupported.
*
* \retval T_COSE_ERR_HASH_GENERAL_FAIL
* Some general failure of the hash function
*
* This initializes the hash context for the particular algorithm. It
* must be called first. A \c hash_ctx can be reused if it is
* reinitialized.
*/
enum t_cose_err_t
t_cose_crypto_hash_start(struct t_cose_crypto_hash *hash_ctx,
int32_t cose_hash_alg_id);
/**
* \brief Feed data into a cryptographic hash. Part of the t_cose
* crypto adaptation layer.
*
* \param[in,out] hash_ctx Pointer to the hash context in which
* accumulate the hash.
* \param[in] data_to_hash Pointer and length of data to feed into
* hash. The pointer may by \c NULL in which
* case no hashing is performed.
*
* There is no return value. If an error occurs it is remembered in \c
* hash_ctx and returned when t_cose_crypto_hash_finish() is called.
* Once in the error state, this function may be called, but it will
* not do anything.
*/
void t_cose_crypto_hash_update(struct t_cose_crypto_hash *hash_ctx,
struct useful_buf_c data_to_hash);
/**
* \brief Finish a cryptographic hash. Part of the t_cose crypto
* adaptation layer.
*
* \param[in,out] hash_ctx Pointer to the hash context.
* \param[in] buffer_to_hold_result Pointer and length into which
* the resulting hash is put.
* \param[out] hash_result Pointer and length of the
* resulting hash.
*
* \retval T_COSE_ERR_HASH_GENERAL_FAIL
* Some general failure of the hash function.
* \retval T_COSE_ERR_HASH_BUFFER_SIZE
* The size of the buffer to hold the hash result was
* too small.
*
* Call this to complete the hashing operation. If the everything
* completed correctly, the resulting hash is returned. Note that any
* errors that occurred during t_cose_crypto_hash_update() are
* returned here.
*
* See the note in the Detailed Description (the \\file comment block)
* for details on how \c useful_buf and \c useful_buf_c are used to
* return the hash.
*/
enum t_cose_err_t
t_cose_crypto_hash_finish(struct t_cose_crypto_hash *hash_ctx,
struct useful_buf buffer_to_hold_result,
struct useful_buf_c *hash_result);
/*
* Public inline function. See documentation above.
*/
static inline size_t t_cose_signature_size(int32_t cose_sig_alg_id)
{
switch(cose_sig_alg_id) {
case COSE_ALGORITHM_ES256:
return T_COSE_EC_P256_SIG_SIZE;
default:
return T_COSE_EC_P256_SIG_SIZE;
}
}
#endif /* __T_COSE_CRYPTO_H__ */

View File

@ -0,0 +1,291 @@
/*
* t_cose_defines.h
*
* Copyright (c) 2018-2019, Laurence Lundblade. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*
* See BSD-3-Clause license in README.md
*/
#ifndef __T_COSE_DEFINES_H__
#define __T_COSE_DEFINES_H__
/**
* \file t_cose_defines.h
*
* \brief Constants from COSE standard and IANA registry.
*
* This file contains constants identifiers defined in [COSE (RFC
* 8152)] (https://tools.ietf.org/html/rfc8152) and [IANA COSE
* Registry] (https://www.iana.org/assignments/cose/cose.xhtml). They
* include algorithm IDs and other constants.
*
* Many constants in the IANA registry are not included here yet as
* they are not needed by t_cose. They can be added if they become
* needed.
*/
/* --------------- COSE Header parameters -----------
* https://www.iana.org/assignments/cose/cose.xhtml#header-parameters
*/
/**
* \def COSE_HEADER_PARAM_ALG
*
* \brief Label of COSE header that indicates an algorithm.
*/
#define COSE_HEADER_PARAM_ALG 1
/**
* \def COSE_HEADER_PARAM_KID
*
* \brief Label of COSE header that contains a key ID.
*/
#define COSE_HEADER_PARAM_KID 4
/* ------------ COSE Header Algorithm Parameters --------------
* https://www.iana.org/assignments/cose/cose.xhtml#header-algorithm-parameters
*
* None of these are defined here yet, as they are not needed by t_cose yet.
*/
/* ------------- COSE Algorithms ----------------------------
* https://www.iana.org/assignments/cose/cose.xhtml#algorithms
*/
/**
* \def COSE_ALGORITHM_ES256
*
* \brief Indicates ECDSA with SHA-256.
*
* Value for \ref COSE_HEADER_PARAM_ALG to indicate ECDSA. w/SHA-256
*/
#define COSE_ALGORITHM_ES256 -7
/**
* \def COSE_ALGORITHM_ES384
*
* \brief Indicates ECDSA with SHA-384.
*
* Value for \ref COSE_HEADER_PARAM_ALG to indicate ECDSA. w/SHA-384
*/
#define COSE_ALGORITHM_ES384 -35
/**
* \def COSE_ALGORITHM_ES512
*
* \brief Indicates ECDSA with SHA-384.
*
* Value for \ref COSE_HEADER_PARAM_ALG to indicate ECDSA. w/SHA-512
*/
#define COSE_ALGORITHM_ES512 -36
/**
* \def COSE_ALG_SHA256_PROPRIETARY
*
* \brief COSE-style algorithm ID for SHA256. The official COSE
* algorithm registry doesn't yet define an ID for a pure hash
* function. One is needed for internal use, so this is defined.
*
* This is only used internally in the implementation and doesn't
* appear in any protocol messages so there are no interoperability
* issues. When this gets defined in the IANA registry, that value can
* be substituted here and all will work fine.
*/
#define COSE_ALG_SHA256_PROPRIETARY -72000
/* ---------- COSE Key Common Parameters --------------
* https://www.iana.org/assignments/cose/cose.xhtml#key-common-parameters
*/
/**
* \def COSE_KEY_COMMON_KTY
*
* \brief Label for data item containing the key type.
*
* In a \c COSE_Key, label that indicates the data item containing the
* key type.
*/
#define COSE_KEY_COMMON_KTY 1
/**
* \def COSE_KEY_COMMON_KID
*
* \brief Label for data item containing the key's kid.
*
* In a \c COSE_Key, label that indicates the data item containing the
* kid of this key.
*/
#define COSE_KEY_COMMON_KID 2
/* ---------- COSE Key Type Parameters --------------------
* https://www.iana.org/assignments/cose/cose.xhtml#key-type-parameters
*/
/**
* \def COSE_KEY_PARAM_CRV
*
* \brief Label for data item indicating EC curve.
*
* In a \c COSE_Key that holds an EC key of either type \ref
* COSE_KEY_TYPE_EC2 or \ref COSE_KEY_TYPE_OKP this labels the data
* item with the EC curve for the key.
*/
#define COSE_KEY_PARAM_CRV -1
/**
* \def COSE_KEY_PARAM_X_COORDINATE
*
* \brief Label for data item that is an X coordinate of an EC key.
*
* In a \c COSE_Key that holds an EC key, this is label that indicates
* the data item containing the X coordinate.
*
* This is used for both key types \ref COSE_KEY_TYPE_EC2 and \ref
* COSE_KEY_TYPE_OKP.
*/
#define COSE_KEY_PARAM_X_COORDINATE -2
/**
* \def COSE_KEY_PARAM_Y_COORDINATE
*
* \brief Label for data item that is a y coordinate of an EC key.
*
* In a COSE_Key that holds an EC key, this is label that indicates
* the data item containing the Y coordinate.
*
* This is used only for key type \ref COSE_KEY_TYPE_EC2.
*/
#define COSE_KEY_PARAM_Y_COORDINATE -3
/**
* \def COSE_KEY_PARAM_PRIVATE_D
*
* \brief Label for data item that is d, the private part of EC key.
*
* In a \c COSE_Key that holds an EC key, this is label that indicates
* the data item containing the Y coordinate.
*
* This is used for both key types \ref COSE_KEY_TYPE_EC2 and \ref
* COSE_KEY_TYPE_OKP.
*/
#define COSE_KEY_PARAM_PRIVATE_D -4
/* ---------- COSE Key Types --------------------------------
* https://www.iana.org/assignments/cose/cose.xhtml#key-type
*/
/**
* \def COSE_KEY_TYPE_OKP
*
* \brief Key type is Octet Key Pair
*
* In a \c COSE_Key, this is a value of the data item labeled \ref
* COSE_KEY_COMMON_KTY that indicates the \c COSE_Key is some sort of
* key pair represented by some octets. It may or may not be an EC
* key.
*/
#define COSE_KEY_TYPE_OKP 1
/**
* \def COSE_KEY_TYPE_EC2
*
* \brief Key is a 2-parameter EC key.
*
* In a \c COSE_Key, this is a value of the data item labeled \ref
* COSE_KEY_COMMON_KTY that indicates the \c COSE_Key is an EC key
* specified with two coordinates, X and Y.
*/
#define COSE_KEY_TYPE_EC2 2
/**
* \def COSE_KEY_TYPE_SYMMETRIC
*
* \brief Key is a symmetric key.
*
* In a \c COSE_Key, this is a value of the data item labeled \ref
* COSE_KEY_COMMON_KTY that indicates the \c COSE_Key is a symmetric
* key.
*/
#define COSE_KEY_TYPE_SYMMETRIC 4
/* ----------- COSE Elliptic Curves ---------------------
* https://www.iana.org/assignments/cose/cose.xhtml#elliptic-curves
*/
/**
* \def COSE_ELLIPTIC_CURVE_P_256
*
* \brief Key type for NIST P-256 key
*
* In a \c COSE_Key, this is a value of the data item labeled \ref
* COSE_KEY_PARAM_CRV to indicate the NIST P-256 curve, also known as
* secp256r1.
*
* This key type is always \ref COSE_KEY_TYPE_EC2.
*/
#define COSE_ELLIPTIC_CURVE_P_256 1
/**
* \def COSE_ELLIPTIC_CURVE_P_384
*
* \brief Key type for NIST P-384 key
*
* In a \c COSE_Key, this is a value of the data item labeled \ref
* COSE_KEY_PARAM_CRV to indicate the NIST P-384 curve, also known as
* secp384r1.
*
* This key type is always \ref COSE_KEY_TYPE_EC2.
*/
#define COSE_ELLIPTIC_CURVE_P_384 2
/**
* \def COSE_ELLIPTIC_CURVE_P_521
*
* \brief Key type for NIST P-521 key
*
* In a \c COSE_Key, this is a value of the data item labeled \ref
* COSE_KEY_PARAM_CRV to indicate the NIST P-521 curve, also known as
* secp521r1.
*/
#define COSE_ELLIPTIC_CURVE_P_521 3
/* ------- Constants from RFC 8152 ---------
*/
/**
* \def COSE_SIG_CONTEXT_STRING_SIGNATURE1
*
* \brief This is a string constant used by COSE to label \c COSE_Sign1
* structures. See RFC 8152, section 4.4.
*/
#define COSE_SIG_CONTEXT_STRING_SIGNATURE1 "Signature1"
#endif /* __T_COSE_DEFINES_H__ */

View File

@ -1,6 +1,6 @@
/*
t_cose_sign1.c
* t_cose_sign1_sign.c
*
* Copyright (c) 2018-2019, Laurence Lundblade. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
@ -8,29 +8,41 @@
* See BSD-3-Clause license in README.md
*/
#include "t_cose_sign1.h"
#include "t_cose_sign1_sign.h"
#include "qcbor.h"
#include "t_cose_defines.h"
#include "t_cose_crypto.h"
#include "t_cose_util.h"
/*
T H E C O M M E N T S
in this file are truthful, but not expansive,
complete of formatted yet...
/**
* \file t_cose_sign1_sign.c
*
* \brief This implements t_cose signing
*/
/* This creates the short-circut signature that is a
concatenation of hashes up to the expected size of the
signature. This is a test mode only has it has no
security value. This is retained in commercial production
code as a useful test or demo that can run even if key
material is not set up or acecssible.
/**
* \brief Create a short-circuit signature
*
* \param[in] cose_alg_id Algorithm ID. This is used only to make
* the short-circuit signature the same size
* as the real signature would be for the
* particular algorithm.
* \param[in] hash_to_sign The bytes to sign. Typically, a hash of
* a payload.
* \param[in] signature_buffer Pointer and length of buffer into which
* the resulting signature is put.
* \param[in] signature Pointer and length of the signature
* returned.
*
* \return This returns one of the error codes defined by \ref t_cose_err_t.
*
* This creates the short-circuit signature that is a concatenation of
* hashes up to the expected size of the signature. This is a test
* mode only has it has no security value. This is retained in
* commercial production code as a useful test or demo that can run
* even if key material is not set up or accessible.
*/
static inline enum t_cose_err_t
short_circuit_sign(int32_t cose_alg_id,
@ -38,8 +50,7 @@ short_circuit_sign(int32_t cose_alg_id,
struct useful_buf signature_buffer,
struct useful_buf_c *signature)
{
/* approximate stack use on 32-bit machine:
local use: 16
/* approximate stack use on 32-bit machine: local use: 16
*/
enum t_cose_err_t return_value;
size_t array_indx;
@ -74,28 +85,54 @@ Done:
/**
* The maximum size of a CBOR Encoded \c COSE_Key that this
* implementation can handle. \c COSE_Key is the serialization format
* for public and other types of keys defined by [COSE (RFC 8152)]
* (https://tools.ietf.org/html/rfc8152).
*
* This can be increased to handle larger keys, but stack usage will
* go up with this increase.
*/
#define MAX_ENCODED_COSE_KEY_SIZE \
1 + /* 1 byte to encode map */ \
2 + /* 2 bytes to encode key type */ \
2 + /* 2 bytes to encode curve */ \
2 * /* the X and Y coordinates at 32 bytes each */ \
(T_COSE_CRYPTO_P256_COORD_SIZE + 1 + 2)
(T_COSE_CRYPTO_EC_P256_COORD_SIZE + 1 + 2)
/**
* \brief CBOR encode a public key as a \c COSE_Key
*
* \param[in] key_select Identifies the public key to encode.
*
* \param[in] buffer_for_cose_key Pointer and length of buffer into which
* the encoded \c COSE_Key is put.
* \param[in] cose_key Pointer and length of the encoded \c COSE_Key.
*
* \return This returns one of the error codes defined by \ref t_cose_err_t.
*
* \c COSE_Key is the COSE-defined format for serializing a key for
* transmission in a protocol. This function encodes an EC public key
* expressed as an X and Y coordinate.
*/
static enum t_cose_err_t
t_cose_encode_cose_key(int32_t key_select,
struct useful_buf buffer_for_cose_key,
struct useful_buf_c *key_id)
struct useful_buf_c *cose_key)
{
/* approximate stack use on 32-bit machine:
local use: 328
with calls: 370
* local use: 328
* with calls: 370
*/
enum t_cose_err_t return_value;
QCBORError qcbor_result;
QCBOREncodeContext cbor_encode_ctx;
USEFUL_BUF_MAKE_STACK_UB( buffer_for_x_coord,T_COSE_CRYPTO_P256_COORD_SIZE);
USEFUL_BUF_MAKE_STACK_UB( buffer_for_y_coord,T_COSE_CRYPTO_P256_COORD_SIZE);
USEFUL_BUF_MAKE_STACK_UB( buffer_for_x_coord,
T_COSE_CRYPTO_EC_P256_COORD_SIZE);
USEFUL_BUF_MAKE_STACK_UB( buffer_for_y_coord,
T_COSE_CRYPTO_EC_P256_COORD_SIZE);
struct useful_buf_c x_coord;
struct useful_buf_c y_coord;
int32_t cose_curve_id;
@ -103,6 +140,7 @@ t_cose_encode_cose_key(int32_t key_select,
/* Get the public key x and y */
return_value = t_cose_crypto_get_ec_pub_key(key_select,
NULL_USEFUL_BUF_C,
&cose_curve_id,
buffer_for_x_coord,
buffer_for_y_coord,
@ -116,16 +154,16 @@ t_cose_encode_cose_key(int32_t key_select,
QCBOREncode_Init(&cbor_encode_ctx, buffer_for_cose_key);
QCBOREncode_OpenMap(&cbor_encode_ctx);
QCBOREncode_AddInt64ToMapN(&cbor_encode_ctx,
COSE_KEY_KTY,
COSE_KEY_COMMON_KTY,
COSE_KEY_TYPE_EC2);
QCBOREncode_AddInt64ToMapN(&cbor_encode_ctx,
COSE_KEY_CRV,
COSE_KEY_PARAM_CRV,
cose_curve_id);
QCBOREncode_AddBytesToMapN(&cbor_encode_ctx,
COSE_KEY_X_COORDINATE,
COSE_KEY_PARAM_X_COORDINATE,
x_coord);
QCBOREncode_AddBytesToMapN(&cbor_encode_ctx,
COSE_KEY_Y_COORDINATE,
COSE_KEY_PARAM_Y_COORDINATE,
y_coord);
QCBOREncode_CloseMap(&cbor_encode_ctx);
@ -137,7 +175,7 @@ t_cose_encode_cose_key(int32_t key_select,
}
/* Finish up and return */
*key_id = encoded_key_id;
*cose_key = encoded_key_id;
return_value = T_COSE_SUCCESS;
Done:
@ -145,8 +183,22 @@ Done:
}
/* Having this as a separate function helps keep
stack usage down and is convenient */
/**
* \brief SHA-256 hash a buffer in one quick function
*
* \param[in] bytes_to_hash The bytes to be hashed.
*
* \param[in] buffer_for_hash Pointer and length into which
* the resulting hash is put.
* \param[out] hash Pointer and length of the
* resulting hash.
* \return This returns one of the error codes defined by \ref t_cose_err_t.
*
* Simple wrapper for start, update and finish interface to a hash.
*
* Having this as a separate function helps keep stack usage down and
* is convenient.
*/
static enum t_cose_err_t quick_sha256(struct useful_buf_c bytes_to_hash,
struct useful_buf buffer_for_hash,
struct useful_buf_c *hash)
@ -172,27 +224,39 @@ Done:
}
/*
Get the kid (Key ID) which is the SHA-256 hash of the pub key as a COSE_Key.
Making kids like this probably should be an IETF standard someday.
/**
* \brief Make a key ID based on the public key to go in the kid
* unprotected header.
*
* \param[in] key_select Identifies the public key.
* \param[in] buffer_for_key_id Pointer and length into which
* the resulting key ID is put.
* \param[out] key_id Pointer and length of the
* resulting key ID.
*
* \return This returns one of the error codes defined by \ref t_cose_err_t.
*
*
* See t_cose_sign1_init() for documentation of the key ID format
* created here.
*/
static inline enum t_cose_err_t get_keyid(int32_t key_select,
struct useful_buf buffer_for_key_id,
struct useful_buf_c *key_id)
{
/* approximate stack use on 32-bit machine:
local use: 100
with calls inlined: 560
with calls not inlined: 428
* local use: 100
* with calls inlined: 560
* with calls not inlined: 428
*/
enum t_cose_err_t return_value;
USEFUL_BUF_MAKE_STACK_UB( buffer_for_cose_key, MAX_ENCODED_COSE_KEY_SIZE);
USEFUL_BUF_MAKE_STACK_UB( buffer_for_cose_key,
MAX_ENCODED_COSE_KEY_SIZE);
struct useful_buf_c cose_key;
/* Doing the COSE encoding and the hashing in separate functions
called from here reduces the stack usage in this function by
a lot
* called from here reduces the stack usage in this function by a
* lot
*/
/* Get the key and encode it as a COSE_Key */
@ -211,21 +275,33 @@ Done:
}
/*
Makes the protected headers for COSE.
returns USEFUL_VEC_NULL_INVEC if buffer_for_header was too small See
also definition of T_COSE_SIGN1_MAX_PROT_HEADER
/**
* \brief Makes the protected headers for COSE.
*
* \param[in] cose_alg_id The COSE algorithm ID to put in the headers.
*
* \param[in] buffer_for_header Pointer and length into which
* the resulting encoded protected
* headers is put.
*
* \return The pointer and length of the protected headers is
* returned, or \c NULL_USEFUL_BUF_C if this fails.
*
* The protected headers are returned in fully encoded CBOR format as
* they are added to the \c COSE_Sign1 as a binary string. This is
* different from the unprotected headers which are not handled this
* way.
*
* This returns \c NULL_USEFUL_BUF_C if buffer_for_header was too
* small. See also definition of \ref T_COSE_SIGN1_MAX_PROT_HEADER
*/
static inline struct useful_buf_c
make_protected_header(int32_t algorithm_id,
make_protected_header(int32_t cose_alg_id,
struct useful_buf buffer_for_header)
{
/* approximate stack use on 32-bit machine:
local use: 170
with calls: 210
* local use: 170
* with calls: 210
*/
struct useful_buf_c protected_headers;
QCBORError qcbor_result;
@ -236,7 +312,7 @@ make_protected_header(int32_t algorithm_id,
QCBOREncode_OpenMap(&cbor_encode_ctx);
QCBOREncode_AddInt64ToMapN(&cbor_encode_ctx,
COSE_HEADER_PARAM_ALG,
algorithm_id);
cose_alg_id);
QCBOREncode_CloseMap(&cbor_encode_ctx);
qcbor_result = QCBOREncode_Finish(&cbor_encode_ctx, &protected_headers);
@ -250,24 +326,28 @@ make_protected_header(int32_t algorithm_id,
}
/**
* \brief Add the unprotected headers to a CBOR encoding context
*
* \param[in] cbor_encode_ctx CBOR encoding context to output to
* \param[in] kid The key ID to go into the kid header.
*
* No error is returned. If an error occurred it will be returned when
* \c QCBOR_Finish() is called on \c cbor_encode_ctx.
*
* The unprotected headers added by this are just the key ID
*/
static inline void add_unprotected_headers(QCBOREncodeContext *cbor_encode_ctx,
struct useful_buf_c kid,
bool short_circuit_sign)
struct useful_buf_c kid)
{
QCBOREncode_OpenMap(cbor_encode_ctx);
QCBOREncode_AddBytesToMapN(cbor_encode_ctx, COSE_HEADER_PARAM_KID, kid);
if(short_circuit_sign) {
/* Indicate short-circuit signing was used */
QCBOREncode_AddBoolToMapN(cbor_encode_ctx,
T_COSE_SHORT_CIRCUIT_LABEL,
true);
}
QCBOREncode_CloseMap(cbor_encode_ctx);
}
/*
See t_cose_sign1.h
* Public function. See t_cose_sign1_sign.h
*/
enum t_cose_err_t t_cose_sign1_init(struct t_cose_sign1_ctx *me,
bool short_circuit_sign,
@ -276,9 +356,9 @@ enum t_cose_err_t t_cose_sign1_init(struct t_cose_sign1_ctx *me,
QCBOREncodeContext *cbor_encode_ctx)
{
/* approximate stack use on 32-bit machine:
local use: 66
with calls inlined: 900
with calls not inlined: 500
* local use: 66
* with calls inlined: 900
* with calls not inlined: 500
*/
int32_t hash_alg;
@ -291,7 +371,7 @@ enum t_cose_err_t t_cose_sign1_init(struct t_cose_sign1_ctx *me,
error check even though it is not used until later. */
hash_alg = hash_alg_id_from_sig_alg_id(cose_alg_id);
if(hash_alg == INT32_MAX) {
return T_COSE_ERR_UNKNOWN_SIGNING_ALG;
return T_COSE_ERR_UNSUPPORTED_SIGNING_ALG;
}
/* Remember all the parameters in the context */
@ -302,7 +382,11 @@ enum t_cose_err_t t_cose_sign1_init(struct t_cose_sign1_ctx *me,
/* Get the key id because it goes into the headers that are about
to be made. */
return_value = get_keyid(key_select, buffer_for_kid, &kid);
if(short_circuit_sign) {
return_value = get_short_circuit_kid(buffer_for_kid, &kid);
} else {
return_value = get_keyid(key_select, buffer_for_kid, &kid);
}
if(return_value) {
goto Done;
}
@ -326,7 +410,7 @@ enum t_cose_err_t t_cose_sign1_init(struct t_cose_sign1_ctx *me,
QCBOREncode_AddBytes(cbor_encode_ctx, me->protected_headers);
/* The Unprotected headers */
add_unprotected_headers(cbor_encode_ctx, kid, short_circuit_sign);
add_unprotected_headers(cbor_encode_ctx, kid);
/* Any failures in CBOR encoding will be caught in finish
when the CBOR encoding is closed off. No need to track
@ -340,15 +424,15 @@ Done:
/*
See t_cose_sign1.h
* Public function. See t_cose_sign1_sign.h
*/
enum t_cose_err_t t_cose_sign1_finish(struct t_cose_sign1_ctx *me,
struct useful_buf_c signed_payload)
{
/* approximate stack use on 32-bit machine:
local use: 116
with calls inline: 500
with calls not inlined; 450
* local use: 116
* with calls inline: 500
* with calls not inlined; 450
*/
enum t_cose_err_t return_value;
/* pointer and length of the completed tbs hash */
@ -357,16 +441,17 @@ enum t_cose_err_t t_cose_sign1_finish(struct t_cose_sign1_ctx *me,
struct useful_buf_c signature;
/* Buffer for the actual signature */
USEFUL_BUF_MAKE_STACK_UB( buffer_for_signature,
T_COSE_MAX_SIG_SIZE);
T_COSE_MAX_EC_SIG_SIZE);
/* Buffer for the tbs hash. Only big enough for SHA256 */
USEFUL_BUF_MAKE_STACK_UB( buffer_for_tbs_hash,
T_COSE_CRYPTO_SHA256_SIZE);
/* Create the hash of the to-be-signed bytes. Inputs to the hash
are the protected headers, the payload that getting signed, the
cose signature alg from which the hash alg is determined. The
cose_algorithm_id was checked in t_cose_sign1_init() so it
doesn't need to be checked here. */
* are the protected headers, the payload that getting signed, the
* cose signature alg from which the hash alg is determined. The
* cose_algorithm_id was checked in t_cose_sign1_init() so it
* doesn't need to be checked here.
*/
return_value = create_tbs_hash(me->cose_algorithm_id,
buffer_for_tbs_hash,
&tbs_hash,
@ -377,14 +462,15 @@ enum t_cose_err_t t_cose_sign1_finish(struct t_cose_sign1_ctx *me,
}
/* Compute the signature using public key crypto. The key selector
and algorithm ID are passed in to know how and what to sign
with. The hash of the TBS bytes are what is signed. A buffer in
which to place the signature is passed in and the signature is
returned.
Short-circuit signing is invoked if requested. It does
no public key operation and requires no key. It is
just a test mode. */
* and algorithm ID are passed in to know how and what to sign
* with. The hash of the TBS bytes are what is signed. A buffer in
* which to place the signature is passed in and the signature is
* returned.
*
* Short-circuit signing is invoked if requested. It does no
* public key operation and requires no key. It is just a test
* mode that always works.
*/
if(me->short_circuit_sign) {
return_value = short_circuit_sign(me->cose_algorithm_id,
tbs_hash,
@ -405,8 +491,8 @@ enum t_cose_err_t t_cose_sign1_finish(struct t_cose_sign1_ctx *me,
QCBOREncode_AddBytes(me->cbor_encode_ctx, signature);
QCBOREncode_CloseArray(me->cbor_encode_ctx);
/* CBOR encoding errors are tracked in the CBOR encoding
context and handled in the layer above this */
/* CBOR encoding errors are tracked in the CBOR encoding context
and handled in the layer above this */
Done:
return return_value;

View File

@ -1,7 +1,5 @@
//
// t_cose_util.c
/*
* t_cose_common.h
* t_cose_util.c
*
* Copyright 2019, Laurence Lundblade
*
@ -17,32 +15,26 @@
#include "t_cose_crypto.h"
/*
T H E C O M M E N T S
in this file are truthful, but not expansive,
complete of formatted yet...
/**
* \file t_cose_util.c
*
* \brief Implementation of t_cose utility functions.
*
*/
/*
Returns COSE ID of hash algorithm for a particular signature algorithm
for COSE-defined algorithm IDs.
returns INT32_MAX when sig alg is not known
* Public function. See t_cose_util.h
*/
int32_t hash_alg_id_from_sig_alg_id(int32_t cose_sig_alg_id)
{
/* if other hashes, particularly those that output bigger hashes
are added here, various other parts of this code have
to be changed to have larger buffers.
* are added here, various other parts of this code have to be
* changed to have larger buffers.
*/
switch(cose_sig_alg_id) {
case COSE_ALG_ES256:
case COSE_ALGORITHM_ES256:
return COSE_ALG_SHA256_PROPRIETARY;
default:
@ -52,21 +44,23 @@ int32_t hash_alg_id_from_sig_alg_id(int32_t cose_sig_alg_id)
/*
Format of TBS bytes
Sig_structure = [
context : "Signature" / "Signature1" / "CounterSignature",
body_protected : empty_or_serialized_map,
? sign_protected : empty_or_serialized_map,
external_aad : bstr,
payload : bstr
]
* Format of to-be-signed bytes used by create_tbs_hash().
* This is defined in COSE (RFC 8152). It is the input
* to the hash.
*
* Sig_structure = [
* context : "Signature" / "Signature1" / "CounterSignature",
* body_protected : empty_or_serialized_map,
* ? sign_protected : empty_or_serialized_map,
* external_aad : bstr,
* payload : bstr
* ]
*/
/*
This is the size of the first part of the CBOR encoded
TBS bytes. It is around 20 bytes. See create_tbs_hash()
/**
* This is the size of the first part of the CBOR encoded TBS
* bytes. It is around 20 bytes. See create_tbs_hash().
*/
#define T_COSE_SIZE_OF_TBS \
1 + /* For opening the array */ \
@ -77,14 +71,10 @@ int32_t hash_alg_id_from_sig_alg_id(int32_t cose_sig_alg_id)
1 /* size of a NULL bstr */ \
)
/*
Creates the hash of the to-be-signed (TBS) bytes for COSE
Possible errors:
- Something gone wrong with hashing
- Protected headers too big
* Public function. See t_cose_util.h
*/
enum t_cose_err_t create_tbs_hash(int32_t cose_alg_id,
struct useful_buf buffer_for_hash,
struct useful_buf_c *hash,
@ -92,11 +82,9 @@ enum t_cose_err_t create_tbs_hash(int32_t cose_alg_id,
struct useful_buf_c payload)
{
/* approximate stack use on 32-bit machine:
local use: 320
with calls: 360
* local use: 320
* with calls: 360
*/
enum t_cose_err_t return_value;
QCBOREncodeContext cbor_encode_ctx;
UsefulBuf_MAKE_STACK_UB( buffer_for_TBS_first_part, T_COSE_SIZE_OF_TBS);
@ -127,23 +115,26 @@ enum t_cose_err_t create_tbs_hash(int32_t cose_alg_id,
if(qcbor_result) {
/* Mainly means that the protected_headers were too big
(which should never happen) */
return_value = T_COSE_ERR_PROTECTED_HEADERS;
return_value = T_COSE_ERR_SIG_STRUCT;
goto Done;
}
/* Start the hashing */
hash_alg_id = hash_alg_id_from_sig_alg_id(cose_alg_id);
/* Don't check hash_alg_id for failure. t_cose_crypto_hash_start()
will handle it properly
*/
return_value = t_cose_crypto_hash_start(&hash_ctx, hash_alg_id);
if(return_value) {
goto Done;
}
/* Hash the first part of the TBS. Take all but the last two
bytes. The last two bytes are the fake payload from above. It is
replaced by the real payload which is hashed next. The fake
payload is needed so the array count is right. This is one of the
main things that make it possible to implement with one buffer
for the whole cose sign1.
* bytes. The last two bytes are the fake payload from above. It
* is replaced by the real payload which is hashed next. The fake
* payload is needed so the array count is right. This is one of
* the main things that make it possible to implement with one
* buffer for the whole cose sign1.
*/
t_cose_crypto_hash_update(&hash_ctx,
useful_buf_head(tbs_first_part,
@ -160,3 +151,39 @@ enum t_cose_err_t create_tbs_hash(int32_t cose_alg_id,
Done:
return return_value;
}
/*
* Public function. See t_cose_util.h
*/
enum t_cose_err_t
get_short_circuit_kid(struct useful_buf buffer_for_kid,
struct useful_buf_c *kid)
{
/* This is a random hard coded key ID that is used to indicate
* short-circuit signing. It is OK to hard code this as the
* probability of collision with this ID is very low and the same
* as for collision between any two key IDs of any sort.
*/
uint8_t defined_short_circuit_kid[] = {
0xef, 0x95, 0x4b, 0x4b, 0xd9, 0xbd, 0xf6, 0x70,
0xd0, 0x33, 0x60, 0x82, 0xf5, 0xef, 0x15, 0x2a,
0xf8, 0xf3, 0x5b, 0x6a, 0x6c, 0x00, 0xef, 0xa6,
0xa9, 0xa7, 0x1f, 0x49, 0x51, 0x7e, 0x18, 0xc6};
/* Prevent a dumb error where the size constant in the header is
* wrong.This check will be evaluated at compile time and optimize
* out when all is correct.
*/
if(sizeof(defined_short_circuit_kid) != T_COSE_SHORT_CIRCUIT_KID_SIZE) {
return T_COSE_ERR_BAD_SHORT_CIRCUIT_KID;
}
*kid = useful_buf_copy(buffer_for_kid,
USEFUL_BUF_FROM_BYTE_ARRAY_LITERAL(
defined_short_circuit_kid));
return useful_buf_c_is_null(*kid) ?
T_COSE_ERR_KEY_BUFFER_SIZE :
T_COSE_SUCCESS;
}

View File

@ -0,0 +1,126 @@
/*
* t_cose_util.h
*
* Copyright 2019, Laurence Lundblade
*
* SPDX-License-Identifier: BSD-3-Clause
*
* See BSD-3-Clause license in README.mdE.
*/
#ifndef __T_COSE_UTIL_H__
#define __T_COSE_UTIL_H__
#include <stdint.h>
#include "useful_buf.h"
#include "t_cose_common.h"
/**
* \file t_cose_util.h
*
* \brief Utility functions used internally by the t_cose implementation.
*
*/
/**
* \brief Return hash algorithm ID from a signature algorithm ID
*
* \param[in] cose_sig_alg_id A COSE signature algorithm identifier.
*
* \return \c INT32_MAX when the signature algorithm ID is not known.
*
* This works off of algorithm identifiers defined in the [IANA COSE
* Registry] (https://www.iana.org/assignments/cose/cose.xhtml).
* Corresponding local integer constants are defined in
* t_cose_defines.h.
*
* COSE signing algorithms are the combination of public key
* algorithm, curve, key size, hash algorithm and hash size. They are
* simple integers making them convenient for direct use in code.
*
* This function returns an identifier for only the hash algorithm
* from the combined identifier.
*
* If the needed algorithm identifiers are not in the IANA registry,
* they can be added to it. This will take some time and work. It is
* also fine to use algorithms in the proprietary space.
*/
int32_t hash_alg_id_from_sig_alg_id(int32_t cose_sig_alg_id);
/**
* \brief Create the hash of the to-be-signed (TBS) bytes for COSE.
*
* \param[in] cose_alg_id The COSE signing algorithm ID. Used to
* determine which hash function to use.
* \param[in] buffer_for_hash Pointer and length of buffer into which
* the resulting hash is put.
* \param[out] hash Pointer and length of the
* resulting hash.
* \param[in] protected_headers The CBOR encoded protected headers.
* \param[in] payload The CBOR encoded payload
*
* \return This returns one of the error codes defined by \ref t_cose_err_t.
*
* \retval T_COSE_ERR_SIG_STRUCT
* Most likely this is because the protected_headers passed in
* is larger than \ref T_COSE_SIGN1_MAX_PROT_HEADER.
* \retval T_COSE_ERR_UNSUPPORTED_HASH
* If the hash algorithm is not known.
* \retval T_COSE_ERR_HASH_GENERAL_FAIL
* In case of some general hash failure.
*
* The input to the public key signature algorithm in COSE is the hash
* of a CBOR encoded structure containing the protected headers
* algorithm ID and a few other things. This formats that structure
* and computes the hash of it. These are known as the to-be-signed or
* "TBS" bytes.
*/
enum t_cose_err_t create_tbs_hash(int32_t cose_alg_id,
struct useful_buf buffer_for_hash,
struct useful_buf_c *hash,
struct useful_buf_c protected_headers,
struct useful_buf_c payload);
/**
* Size of the key returned by get_short_circuit_kid(). It is always
* this size.
*/
#define T_COSE_SHORT_CIRCUIT_KID_SIZE 32
/**
* \brief Get the special kid for short-circuit signing.
*
* \param[in] buffer_for_kid Pointer and length of buffer into which
* the resulting hash is put. It should
* always be at least \ref
* T_COSE_SHORT_CIRCUIT_KID_SIZE.
* \param[out] kid Pointer and length of the returned kid.
*
* \retval T_COSE_SUCCESS
* The kid was returned.
* \retval T_COSE_ERR_KEY_BUFFER_SIZE
* \c buffer_for_kid is too small
*
* This always returns the same key ID. It always indicates
* short-circuit signing. It is OK to hard code this as the
* probability of collision with this ID is extremely low and the same
* as for collision between any two key IDs (kids) of any sort.
*
* This is the value of the kid.
*
* 0xef, 0x95, 0x4b, 0x4b, 0xd9, 0xbd, 0xf6, 0x70,
* 0xd0, 0x33, 0x60, 0x82, 0xf5, 0xef, 0x15, 0x2a,
* 0xf8, 0xf3, 0x5b, 0x6a, 0x6c, 0x00, 0xef, 0xa6,
* 0xa9, 0xa7, 0x1f, 0x49, 0x51, 0x7e, 0x18, 0xc6
*
*/
enum t_cose_err_t
get_short_circuit_kid(struct useful_buf buffer_for_kid,
struct useful_buf_c *kid);
#endif /* __T_COSE_UTIL_H__ */

View File

@ -1,63 +0,0 @@
/*
* t_cose_common.h
*
* Copyright 2019, Laurence Lundblade
*
* SPDX-License-Identifier: BSD-3-Clause
*
* See BSD-3-Clause license in README.mdE.
*/
#ifndef __T_COSE_COMMON_H__
#define __T_COSE_COMMON_H__
/*
T H E C O M M E N T S
in this file are truthful, but not expansive,
complete of formatted yet...
*/
/* Private value. Intentionally not documented for Doxygen.
* This is the space allocated for the encoded protected headers. It
* needs to be big enough for make_protected_header() to succeed. It
* currently sized for one header with an algorithm ID up to 32 bits
* long -- one byte for the wrapping map, one byte for the label, 5
* bytes for the ID. If this is made accidentially too small, QCBOR will
* only return an error, and not overrun any buffers.
*/
#define T_COSE_SIGN1_MAX_PROT_HEADER (1+1+5)
/* TODO: document this */
enum t_cose_err_t {
T_COSE_SUCCESS = 0,
T_COSE_ERR_UNKNOWN_SIGNING_ALG,
T_COSE_ERR_PROTECTED_HEADERS,
T_COSE_ERR_UNSUPPORTED_HASH,
T_COSE_ERR_HASH_GENERAL_FAIL,
T_COSE_ERR_HASH_BUFFER_SIZE,
T_COSE_ERR_SIG_BUFFER_SIZE,
T_COSE_ERR_KEY_BUFFER_SIZE,
T_COSE_ERR_FORMAT,
T_COSE_ERR_CBOR_NOT_WELL_FORMED,
T_COSE_ERR_NO_ALG_ID,
T_COSE_ERR_NO_KID,
T_COSE_ERR_SIG_VERIFY
};
/*
CBOR Label for proprietary header indicating short-circuit
signing was used. Just a random number in the proprietary
label space */
#define T_COSE_SHORT_CIRCUIT_LABEL -8675309
#endif /* __T_COSE_COMMON_H__ */

View File

@ -1,102 +0,0 @@
/*
* t_cose_sign1.h
*
* Copyright (c) 2018-2019, Laurence Lundblade. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*
* See BSD-3-Clause license in README.md
*/
#ifndef __T_COSE_SIGN1_H__
#define __T_COSE_SIGN1_H__
#include <stdint.h>
#include "qcbor.h"
#include "t_cose_common.h"
/**
* This is the context for creating a COSE Sign1
* structure. The caller should allocate it and
* pass it to the functions here.
* This is about 32 bytes.
*/
struct t_cose_sign1_ctx {
/* Private data structure */
uint8_t buffer_for_protected_headers[T_COSE_SIGN1_MAX_PROT_HEADER];
struct useful_buf_c protected_headers;
int32_t cose_algorithm_id;
int32_t key_select;
bool short_circuit_sign;
QCBOREncodeContext *cbor_encode_ctx;
};
/**
* \brief Initialize to start creating a COSE_Sign1.
*
* \param[in] me The cose signing context.
* \param[in] short_circuit_sign Select special test mode.
* \param[in] cose_algorithm_id The signing alg ID from COSE IANA registry.
* \param[in] key_select Which signing key to use.
* \param[in] cbor_encode_ctx The CBOR encoder context to output to.
*
* \return Error code (TODO: error codes)
*
* This COSE_Sign1 implementations is optimized for creating EAT tokens. It
* should work for CWT and others use cases too. The main point of the
* optimization is that only one output buffer is needed. There is no need
* for one buffer to hold the payload and another to hold the end result
* COSE Sign 1. The payload can be encoded right into its final place in
* the end result COSE Sign 1.
*
* To use this, create a QCBOREncodeContext and initialize it with an
* output buffer big enough to hold the payload and the COSE Sign 1
* overhead. This overhead is about 30 bytes plus the size of the
* signatue and the size of the key ID.
*
* After the QCBOREncodeContext is initialized, call t_cose_sign1_init()
* on it.
*
* Next call QCBOREncode_BstrWrap() to indicate the start of the paylod.
*
* Next call various QCBOREncode_Addxxxx methods to create the payload.
*
* Next call QCBOREncode_CloseBstrWrap() to indicate the end of the
* payload. This will also return a pointer and length of the payload
* that gets hashed.
*
* Next call t_cose_sign1_finish() with the pointer and length of the
* payload. This will do all the cryptography and complete the COSE
* Sign1.
*
* Finally, call QCBOREncode_Finish() to get the pointer and length of
* the complete token.
*/
enum t_cose_err_t t_cose_sign1_init(struct t_cose_sign1_ctx *me,
bool short_circuit_sign,
int32_t cose_algorithm_id,
int32_t key_select,
QCBOREncodeContext *cbor_encode_ctx);
/**
* \brief Finish creation of the COSE_Sign1.
*
* \param[in] me The cose signing context.
* \param[in] payload The pointer and length of the payload.
*
* \return One of the T_COSE_ERR_XXX errors (TODO: detail the errors)
*
* This is when the signature algorithm is run. The payload is
* used only to compute the hash for signing. The completed COSE_Sign1
* is retrieved from the cbor_encode_ctx by calling QCBOREncode_Finish()
*/
enum t_cose_err_t t_cose_sign1_finish(struct t_cose_sign1_ctx *me,
struct useful_buf_c payload);
#endif /* __T_COSE_SIGN1_H__ */

View File

@ -1,116 +0,0 @@
/*
* t_cose_crypto.h
*
* Copyright 2019, Laurence Lundblade
*
* SPDX-License-Identifier: BSD-3-Clause
*
* See BSD-3-Clause license in README.mdE.
*/
#ifndef __T_COSE_CRYPTO_H__
#define __T_COSE_CRYPTO_H__
#include "t_cose_common.h"
#include "useful_buf.h"
#include <stdint.h>
/*
T H E C O M M E N T S
in this file are truthful, but not expansive,
complete of formatted yet...
*/
/*
A small wrapper around the pub key functions to a) map cose alg IDs to
TF-M alg IDs, b) map crypto errors to t_cose errors, c) have inputs
and outputs be struct useful_buf_c and struct useful_buf,
d) handle key selection.
*/
enum t_cose_err_t
t_cose_crypto_pub_key_sign(int32_t cose_alg_id,
int32_t key_select,
struct useful_buf_c hash_to_sign,
struct useful_buf signature_buffer,
struct useful_buf_c *signature);
enum t_cose_err_t
t_cose_crypto_pub_key_verify(int32_t cose_alg_id,
int32_t key_select,
struct useful_buf_c hash_to_verify,
struct useful_buf_c signature);
/*
Size of X and Y coord in 2 param style EC public key. Format
is as defined in COSE RFC and http://www.secg.org/sec1-v2.pdf.
No function to get private key because there is no need for it.
The private signing key only needs to exist behind
t_cose_crypto_pub_key_sign()
*/
/* This size well-known by public standards. Implementation should
have a compile time cross check to be sure it matches
*/
#define T_COSE_CRYPTO_P256_COORD_SIZE 32
enum t_cose_err_t
t_cose_crypto_get_ec_pub_key(int32_t key_select,
int32_t *cose_curve_id,
struct useful_buf buf_to_hold_x_coord,
struct useful_buf buf_to_hold_y_coord,
struct useful_buf_c *x_coord,
struct useful_buf_c *y_coord);
/*
A small wrapper around the hash function to a) map cose alg IDs to
TF-M alg IDs, b) map crypto errors to t_cose errors, c) have inputs
and outputs be struct useful_buf_c and struct useful_buf.
*/
struct t_cose_crypto_hash {
/* Can't put actual size here without creating dependecy on actual
hash implementation, so pick a fairly large and accommodating
size. There are checks that it is big enough in the implementation
so no risk of buffer overflow */
uint8_t bytes[128];
};
/*
These sizes are well-known and fixed. Do not want to include
platform-dependent headers here and make this file platform
dependent. There are compile-time checks in the implementation
to make sure it matches the platform's size. It would be
very weird if it didn't.
*/
#define T_COSE_CRYPTO_SHA256_SIZE 32
enum t_cose_err_t t_cose_crypto_hash_start(struct t_cose_crypto_hash *hash_ctx,
int32_t cose_hash_alg_id);
void t_cose_crypto_hash_update(struct t_cose_crypto_hash *hash_ctx,
struct useful_buf_c data_to_hash);
enum t_cose_err_t
t_cose_crypto_hash_finish(struct t_cose_crypto_hash *hash_ctx,
struct useful_buf buffer_to_hold_result,
struct useful_buf_c *hash_result);
#endif /* __T_COSE_CRYPTO_H__ */

View File

@ -1,159 +0,0 @@
/*
* t_cose_defines.h
*
* Copyright (c) 2018-2019, Laurence Lundblade. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*
* See BSD-3-Clause license in README.md
*/
#ifndef __T_COSE_DEFINES_H__
#define __T_COSE_DEFINES_H__
/*
These are defined in the COSE standard, RFC 8152, or in the IANA
registry for COSE at https://www.iana.org/assignments/cose/cose.xhtml
*/
/* COSE Header parameters:
https://www.iana.org/assignments/cose/cose.xhtml#header-parameters
*/
/**
* \def COSE_HEADER_PARAM_ALG
*
* \brief Label of COSE header that indicates an algorithm.
*/
#define COSE_HEADER_PARAM_ALG 1
/**
* \def COSE_HEADER_PARAM_KID
*
* \brief Label of COSE header that contains a key ID.
*/
#define COSE_HEADER_PARAM_KID 4
/* COSE Algorithms:
* https://www.iana.org/assignments/cose/cose.xhtml#algorithms
*/
/**
* \def COSE_ALG_ES256
*
* \brief Value for COSE_HEADER_PARAM_ALG to indicate ECDSA
* w/SHA-256
*/
#define COSE_ALG_ES256 -7
/**
* \def COSE_SIG_CONTEXT_STRING_SIGNATURE1
*
* \brief This is a strong constant used by COSE to
* label COSE_Sign1 structures. SeeRFC 8152, section 4.4.
*/
#define COSE_SIG_CONTEXT_STRING_SIGNATURE1 "Signature1"
/**
* \def COSE_ALG_SHA256_PROPRIETARY
*
* \brief COSE-style algorithm ID for SHA256. The offical COSE
* algorithm registry doesn't yet define an ID for a pure hash
* function. One is needed for internal use, so this is defined.
*/
#define COSE_ALG_SHA256_PROPRIETARY -72000
/* From CBOR IANA registry,
* https://www.iana.org/assignments/cbor-tags/cbor-tags.xhtml
*/
/**
* \def COSE_KEY_TYPE_EC2
*
* \brief In a COSE_Key, this is a value of the
* data item labeled COSE_KEY_KTY that indicates
* the COSE_Key is an EC key specified with
* two coordinates, X and Y.
*/
#define COSE_KEY_TYPE_EC2 2
/**
* \def COSE_ELLIPTIC_CURVE_P_256
*
* \brief In a COSE_Key, this is a value of the
* data item labeled COSE_KEY_CRV to indicate the
* NIST P-256 curve.
*/
#define COSE_ELLIPTIC_CURVE_P_256 1
/**
* \def COSE_KEY_KTY
*
* \brief In a COSE_Key, label that indicates
* the data item containing the key type
*/
#define COSE_KEY_KTY 1
/**
* \def COSE_KEY_CRV
*
* \brief In a COSE_Key that holds an EC key,
* this is label that indicates
* the data item containing the specific curve.
*/
#define COSE_KEY_CRV -1
/**
* \def COSE_KEY_X_COORDINATE
*
* \brief In a COSE_Key that holds an EC key,
* this is label that indicates
* the data item containing the X coordinate.
*/
#define COSE_KEY_X_COORDINATE -2
/**
* \def COSE_KEY_Y_COORDINATE
*
* \brief In a COSE_Key that holds an EC key,
* this is label that indicates
* the data item containing the Y coordinate.
*/
#define COSE_KEY_Y_COORDINATE -3
/**
* \def T_COSE_MAX_SIG_SIZE
*
* \brief Compile time constant for largest signature that can be handled.
* Set at 64 bytes for ECDSA 256
*/
#define T_COSE_MAX_SIG_SIZE 64
/**
* \brief Get the size in bytes of a particular signature type
*
* \param[in] cose_signature_algorithm The COSE algorithm ID.
*
* \return The size in bytes of the signature
*/
static inline size_t t_cose_signature_size(int32_t cose_signature_algorithm)
{
switch(cose_signature_algorithm) {
case COSE_ALG_ES256:
return 64; /* Size of an ECDSA 256 signature */
default:
return T_COSE_MAX_SIG_SIZE;
}
}
#endif /* __T_COSE_DEFINES_H__ */

View File

@ -1,29 +0,0 @@
//
// t_cose_util.h
/*
* t_cose_common.h
*
* Copyright 2019, Laurence Lundblade
*
* SPDX-License-Identifier: BSD-3-Clause
*
* See BSD-3-Clause license in README.mdE.
*/
#ifndef t_cose_util_h
#define t_cose_util_h
#include <stdint.h>
#include "useful_buf.h"
#include "t_cose_common.h"
int32_t hash_alg_id_from_sig_alg_id(int32_t cose_sig_alg_id);
enum t_cose_err_t create_tbs_hash(int32_t cose_alg_id,
struct useful_buf buffer_for_hash,
struct useful_buf_c *hash,
struct useful_buf_c protected_headers,
struct useful_buf_c payload);
#endif /* t_cose_util_h */