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__ */