Create a COSE_Sign1
, usually for EAT or CWT Token.
More...
Go to the source code of this file.
Data Structures | |
struct | t_cose_sign1_ctx |
This is the context for creating a COSE_Sign1 structure. More... | |
Functions | |
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) |
Initialize to start creating a COSE_Sign1 . More... | |
enum t_cose_err_t | t_cose_sign1_finish (struct t_cose_sign1_ctx *me, struct useful_buf_c payload) |
Finish creation of the COSE_Sign1 . More... | |
Create a COSE_Sign1
, usually for EAT or CWT Token.
This creates a COSE_Sign1
in compliance with COSE (RFC 8152). A 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:
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 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_Sign1
. The payload is encoded right into its final place in the end result COSE_Sign1
.
Definition in file t_cose_sign1_sign.h.
enum t_cose_err_t t_cose_sign1_finish | ( | struct t_cose_sign1_ctx * | me, |
struct useful_buf_c | payload | ||
) |
Finish creation of the COSE_Sign1
.
[in] | me | The t_cose signing context. |
[in] | payload | The pointer and length of the payload. |
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 COSE_Sign1
is retrieved from the cbor_encode_ctx
by calling QCBOREncode_Finish()
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 | ||
) |
Initialize to start creating a COSE_Sign1
.
[in] | me | The t_cose signing context. |
[in] | short_circuit_sign | true to select special test mode. |
[in] | cose_algorithm_id | The algorithm to sign with. The IDs are defined in COSE (RFC 8152) or in the IANA COSE Registry. |
[in] | key_select | Which signing key to use. |
[in] | cbor_encode_ctx | The CBOR encoder context to output to. |
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 cbor_encode_ctx
with UsefulBufC
that has a NULL
pointer and large length like 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 COSE_ALGORITHM_ES256 which indicates ECDSA with the NIST P-256 curve and SHA-256.
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 signature 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 payload.
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.
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 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.