Attest: Add attestation core, COSE library & tests
Adds core library for creating EAT (draft-mandyam-eat-01)
format attestations. Adds t_cose an implementation of
COSE_Sign1 as defined in RFC 8152 section 4.2. Adds
basic test for creation of EAT format attestations.
Change-Id: I1ff8339edc55d50bd7639e42539844f2394280dc
Signed-off-by: Laurence Lundblade <lgl@securitytheory.com>
diff --git a/lib/t_cose/src/t_cose_crypto.h b/lib/t_cose/src/t_cose_crypto.h
new file mode 100644
index 0000000..b77af32
--- /dev/null
+++ b/lib/t_cose/src/t_cose_crypto.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__ */
diff --git a/lib/t_cose/src/t_cose_defines.h b/lib/t_cose/src/t_cose_defines.h
new file mode 100644
index 0000000..e2cc970e
--- /dev/null
+++ b/lib/t_cose/src/t_cose_defines.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__ */
diff --git a/lib/t_cose/src/t_cose_sign1_sign.c b/lib/t_cose/src/t_cose_sign1_sign.c
new file mode 100644
index 0000000..8f55bc0
--- /dev/null
+++ b/lib/t_cose/src/t_cose_sign1_sign.c
@@ -0,0 +1,499 @@
+/*
+ * t_cose_sign1_sign.c
+ *
+ * Copyright (c) 2018-2019, Laurence Lundblade. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ * See BSD-3-Clause license in README.md
+ */
+
+#include "t_cose_sign1_sign.h"
+#include "qcbor.h"
+#include "t_cose_defines.h"
+#include "t_cose_crypto.h"
+#include "t_cose_util.h"
+
+
+/**
+ * \file t_cose_sign1_sign.c
+ *
+ * \brief This implements t_cose signing
+ */
+
+
+/**
+ * \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,
+ struct useful_buf_c hash_to_sign,
+ struct useful_buf signature_buffer,
+ struct useful_buf_c *signature)
+{
+ /* approximate stack use on 32-bit machine: local use: 16
+ */
+ enum t_cose_err_t return_value;
+ size_t array_indx;
+ size_t amount_to_copy;
+ size_t sig_size;
+
+ sig_size = t_cose_signature_size(cose_alg_id);
+
+ if(sig_size > signature_buffer.len) {
+ /* Buffer too small for this signature type */
+ return_value = T_COSE_ERR_SIG_BUFFER_SIZE;
+ goto Done;
+ }
+
+ /* Loop concatening copies of the hash to fill out to signature size */
+ for(array_indx = 0; array_indx < sig_size; array_indx += hash_to_sign.len) {
+ amount_to_copy = sig_size - array_indx;
+ if(amount_to_copy > hash_to_sign.len) {
+ amount_to_copy = hash_to_sign.len;
+ }
+ memcpy((uint8_t *)signature_buffer.ptr + array_indx,
+ hash_to_sign.ptr,
+ amount_to_copy);
+ }
+ signature->ptr = signature_buffer.ptr;
+ signature->len = sig_size;
+ return_value = T_COSE_SUCCESS;
+
+Done:
+ return return_value;
+}
+
+
+
+/**
+ * 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_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 *cose_key)
+{
+ /* approximate stack use on 32-bit machine:
+ * 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_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;
+ struct useful_buf_c encoded_key_id;
+
+ /* 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,
+ &x_coord,
+ &y_coord);
+ if(return_value != T_COSE_SUCCESS) {
+ goto Done;
+ }
+
+ /* Encode it into a COSE_Key structure */
+ QCBOREncode_Init(&cbor_encode_ctx, buffer_for_cose_key);
+ QCBOREncode_OpenMap(&cbor_encode_ctx);
+ QCBOREncode_AddInt64ToMapN(&cbor_encode_ctx,
+ COSE_KEY_COMMON_KTY,
+ COSE_KEY_TYPE_EC2);
+ QCBOREncode_AddInt64ToMapN(&cbor_encode_ctx,
+ COSE_KEY_PARAM_CRV,
+ cose_curve_id);
+ QCBOREncode_AddBytesToMapN(&cbor_encode_ctx,
+ COSE_KEY_PARAM_X_COORDINATE,
+ x_coord);
+ QCBOREncode_AddBytesToMapN(&cbor_encode_ctx,
+ COSE_KEY_PARAM_Y_COORDINATE,
+ y_coord);
+ QCBOREncode_CloseMap(&cbor_encode_ctx);
+
+ qcbor_result = QCBOREncode_Finish(&cbor_encode_ctx, &encoded_key_id);
+ if(qcbor_result != QCBOR_SUCCESS) {
+ /* Mainly means that the COSE_Key was too big for buffer_for_cose_key */
+ return_value = T_COSE_ERR_PROTECTED_HEADERS;
+ goto Done;
+ }
+
+ /* Finish up and return */
+ *cose_key = encoded_key_id;
+ return_value = T_COSE_SUCCESS;
+
+Done:
+ return return_value;
+}
+
+
+/**
+ * \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)
+{
+ /* approximate stack use on 32-bit machine:
+ local use: 132
+ */
+ enum t_cose_err_t return_value = 0;
+ struct t_cose_crypto_hash hash_ctx;
+
+ return_value = t_cose_crypto_hash_start(&hash_ctx,
+ COSE_ALG_SHA256_PROPRIETARY);
+ if(return_value) {
+ goto Done;
+ }
+ t_cose_crypto_hash_update(&hash_ctx, bytes_to_hash);
+ return_value = t_cose_crypto_hash_finish(&hash_ctx,
+ buffer_for_hash,
+ hash);
+
+Done:
+ return return_value;
+}
+
+
+/**
+ * \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
+ */
+ enum t_cose_err_t return_value;
+ 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
+ */
+
+ /* Get the key and encode it as a COSE_Key */
+ return_value = t_cose_encode_cose_key(key_select,
+ buffer_for_cose_key,
+ &cose_key);
+ if(return_value != T_COSE_SUCCESS) {
+ goto Done;
+ }
+
+ /* SHA256 hash of it is all we care about in the end */
+ return_value = quick_sha256(cose_key, buffer_for_key_id, key_id);
+
+Done:
+ return return_value;
+}
+
+
+/**
+ * \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 cose_alg_id,
+ struct useful_buf buffer_for_header)
+{
+ /* approximate stack use on 32-bit machine:
+ * local use: 170
+ * with calls: 210
+ */
+ struct useful_buf_c protected_headers;
+ QCBORError qcbor_result;
+ QCBOREncodeContext cbor_encode_ctx;
+ struct useful_buf_c return_value;
+
+ QCBOREncode_Init(&cbor_encode_ctx, buffer_for_header);
+ QCBOREncode_OpenMap(&cbor_encode_ctx);
+ QCBOREncode_AddInt64ToMapN(&cbor_encode_ctx,
+ COSE_HEADER_PARAM_ALG,
+ cose_alg_id);
+ QCBOREncode_CloseMap(&cbor_encode_ctx);
+ qcbor_result = QCBOREncode_Finish(&cbor_encode_ctx, &protected_headers);
+
+ if(qcbor_result == QCBOR_SUCCESS) {
+ return_value = protected_headers;
+ } else {
+ return_value = NULL_USEFUL_BUF_C;
+ }
+
+ return return_value;
+}
+
+
+/**
+ * \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)
+{
+ QCBOREncode_OpenMap(cbor_encode_ctx);
+ QCBOREncode_AddBytesToMapN(cbor_encode_ctx, COSE_HEADER_PARAM_KID, kid);
+ QCBOREncode_CloseMap(cbor_encode_ctx);
+}
+
+
+/*
+ * 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,
+ int32_t cose_alg_id,
+ int32_t key_select,
+ QCBOREncodeContext *cbor_encode_ctx)
+{
+ /* approximate stack use on 32-bit machine:
+ * local use: 66
+ * with calls inlined: 900
+ * with calls not inlined: 500
+ */
+
+ int32_t hash_alg;
+ enum t_cose_err_t return_value;
+ USEFUL_BUF_MAKE_STACK_UB( buffer_for_kid, T_COSE_CRYPTO_SHA256_SIZE);
+ struct useful_buf_c kid;
+ struct useful_buf buffer_for_protected_header;
+
+ /* Check the cose_alg_id now by getting the hash alg as an early
+ 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_UNSUPPORTED_SIGNING_ALG;
+ }
+
+ /* Remember all the parameters in the context */
+ me->cose_algorithm_id = cose_alg_id;
+ me->key_select = key_select;
+ me->short_circuit_sign = short_circuit_sign;
+ me->cbor_encode_ctx = cbor_encode_ctx;
+
+ /* Get the key id because it goes into the headers that are about
+ to be made. */
+ 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;
+ }
+
+ /* Get started with the tagged array that holds the four parts of
+ a cose single signed message */
+ QCBOREncode_AddTag(cbor_encode_ctx, CBOR_TAG_COSE_SIGN1);
+ QCBOREncode_OpenArray(cbor_encode_ctx);
+
+ /* The protected headers, which are added as a wrapped bstr */
+ buffer_for_protected_header =
+ USEFUL_BUF_FROM_BYTE_ARRAY(me->buffer_for_protected_headers);
+ me->protected_headers = make_protected_header(cose_alg_id,
+ buffer_for_protected_header);
+ if(useful_buf_c_is_null(me->protected_headers)) {
+ /* The sizing of storage for protected headers is
+ off (should never happen in tested, released code) */
+ return_value = T_COSE_SUCCESS;
+ goto Done;
+ }
+ QCBOREncode_AddBytes(cbor_encode_ctx, me->protected_headers);
+
+ /* The Unprotected headers */
+ 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
+ here as the CBOR encoder tracks it internally. */
+
+ return_value = T_COSE_SUCCESS;
+
+Done:
+ return return_value;
+}
+
+
+/*
+ * 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
+ */
+ enum t_cose_err_t return_value;
+ /* pointer and length of the completed tbs hash */
+ struct useful_buf_c tbs_hash;
+ /* Pointer and length of the completed signature */
+ struct useful_buf_c signature;
+ /* Buffer for the actual signature */
+ USEFUL_BUF_MAKE_STACK_UB( buffer_for_signature,
+ 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.
+ */
+ return_value = create_tbs_hash(me->cose_algorithm_id,
+ buffer_for_tbs_hash,
+ &tbs_hash,
+ me->protected_headers,
+ signed_payload);
+ if(return_value) {
+ goto Done;
+ }
+
+ /* 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 that always works.
+ */
+ if(me->short_circuit_sign) {
+ return_value = short_circuit_sign(me->cose_algorithm_id,
+ tbs_hash,
+ buffer_for_signature,
+ &signature);
+ } else {
+ return_value = t_cose_crypto_pub_key_sign(me->cose_algorithm_id,
+ me->key_select,
+ tbs_hash,
+ buffer_for_signature,
+ &signature);
+ }
+ if(return_value) {
+ goto Done;
+ }
+
+ /* Add signature to CBOR and close out the array */
+ 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 */
+
+Done:
+ return return_value;
+}
diff --git a/lib/t_cose/src/t_cose_util.c b/lib/t_cose/src/t_cose_util.c
new file mode 100644
index 0000000..ba4910e
--- /dev/null
+++ b/lib/t_cose/src/t_cose_util.c
@@ -0,0 +1,189 @@
+/*
+ * t_cose_util.c
+ *
+ * Copyright 2019, Laurence Lundblade
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ * See BSD-3-Clause license in README.mdE.
+ */
+
+#include "t_cose_util.h"
+#include "qcbor.h"
+#include "t_cose_defines.h"
+#include "t_cose_common.h"
+#include "t_cose_crypto.h"
+
+
+/**
+ * \file t_cose_util.c
+ *
+ * \brief Implementation of t_cose utility functions.
+ *
+ */
+
+
+/*
+ * 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.
+ */
+ switch(cose_sig_alg_id) {
+
+ case COSE_ALGORITHM_ES256:
+ return COSE_ALG_SHA256_PROPRIETARY;
+
+ default:
+ return INT32_MAX;
+ }
+}
+
+
+/*
+ * 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().
+ */
+#define T_COSE_SIZE_OF_TBS \
+ 1 + /* For opening the array */ \
+ sizeof(COSE_SIG_CONTEXT_STRING_SIGNATURE1) + /* "Signature1" */ \
+ 2 + /* Overhead for encoding string */ \
+ T_COSE_SIGN1_MAX_PROT_HEADER + /* entire protected headers */ \
+ 3 * ( /* 3 NULL bstrs for fields not used */ \
+ 1 /* size of a NULL bstr */ \
+ )
+
+
+/*
+ * 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,
+ struct useful_buf_c protected_headers,
+ struct useful_buf_c payload)
+{
+ /* approximate stack use on 32-bit machine:
+ * 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);
+ struct useful_buf_c tbs_first_part;
+ QCBORError qcbor_result;
+ struct t_cose_crypto_hash hash_ctx;
+ int32_t hash_alg_id;
+
+ /* This builds the CBOR-format to-be-signed bytes */
+ QCBOREncode_Init(&cbor_encode_ctx, buffer_for_TBS_first_part);
+ QCBOREncode_OpenArray(&cbor_encode_ctx);
+ /* context */
+ QCBOREncode_AddSZString(&cbor_encode_ctx,
+ COSE_SIG_CONTEXT_STRING_SIGNATURE1);
+ /* body_protected */
+ QCBOREncode_AddBytes(&cbor_encode_ctx,
+ protected_headers);
+ /* sign_protected */
+ QCBOREncode_AddBytes(&cbor_encode_ctx, NULL_USEFUL_BUF_C);
+ /* external_aad */
+ QCBOREncode_AddBytes(&cbor_encode_ctx, NULL_USEFUL_BUF_C);
+ /* fake payload */
+ QCBOREncode_AddBytes(&cbor_encode_ctx, NULL_USEFUL_BUF_C);
+ QCBOREncode_CloseArray(&cbor_encode_ctx);
+
+ /* get the result and convert it to struct useful_buf_c representation */
+ qcbor_result = QCBOREncode_Finish(&cbor_encode_ctx, &tbs_first_part);
+ if(qcbor_result) {
+ /* Mainly means that the protected_headers were too big
+ (which should never happen) */
+ 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.
+ */
+ t_cose_crypto_hash_update(&hash_ctx,
+ useful_buf_head(tbs_first_part,
+ tbs_first_part.len - 2));
+
+ /* Hash the payload */
+ t_cose_crypto_hash_update(&hash_ctx, payload);
+
+ /* Finish the hash and set up to return it */
+ return_value = t_cose_crypto_hash_finish(&hash_ctx,
+ buffer_for_hash,
+ hash);
+
+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;
+}
diff --git a/lib/t_cose/src/t_cose_util.h b/lib/t_cose/src/t_cose_util.h
new file mode 100644
index 0000000..7b39dc3
--- /dev/null
+++ b/lib/t_cose/src/t_cose_util.h
@@ -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__ */