mirror of https://github.com/ARMmbed/mbed-os.git
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 changespull/9668/head
parent
2117a26cb1
commit
70a14b2f3a
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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__ */
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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__ */
|
|
@ -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__ */
|
|
@ -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})
|
||||
|
|
|
@ -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);
|
|
@ -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),
|
||||
|
|
|
@ -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})
|
|
@ -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.
|
|
@ -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__ */
|
|
@ -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__ */
|
|
@ -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__ */
|
|
@ -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__ */
|
|
@ -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;
|
|
@ -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;
|
||||
}
|
|
@ -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__ */
|
|
@ -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__ */
|
|
@ -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__ */
|
|
@ -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__ */
|
|
@ -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__ */
|
|
@ -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 */
|
Loading…
Reference in New Issue