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