Newer
Older
mbed-os / platform / FEATURE_EXPERIMENTAL_API / FEATURE_PSA / TARGET_MBED_PSA_SRV / services / attestation / tfm_impl / t_cose / inc / t_cose_sign1_sign.h
@Rajkumar Kanagaraj Rajkumar Kanagaraj on 21 Aug 2020 6 KB Move FEATURE_EXPERIMENTAL_API for PSA to platform
/*
 * 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__ */