1 /*
2  * Copyright (c) 2018-2019, Laurence Lundblade. All rights reserved.
3  * Copyright (c) 2020-2023, Arm Limited. All rights reserved.
4  *
5  * SPDX-License-Identifier: BSD-3-Clause
6  */
7 
8 #ifndef __T_COSE_MAC0_SIGN_H_
9 #define __T_COSE_MAC0_SIGN_H_
10 
11 #include <stdint.h>
12 #include "qcbor/qcbor.h"
13 #include "t_cose_common.h"
14 
15 #ifdef __cplusplus
16 extern "C" {
17 #endif
18 
19 
20 /**
21  * This selects a test mode called _short_ _circuit_ _tagging_.
22  * This mode is useful when the symmetric key is unavailable
23  * or unable to be accessed, perhaps because it has not been provisioned or
24  * configured for the particular device.
25  *
26  * It has no value for security at all. Data signed this way MUST NOT
27  * be trusted as anyone can sign like this.
28  *
29  * In this mode, the tag is the hash of that which would normally be MACed by
30  * a symmetric key.
31  *
32  * This mode is very useful for testing because all the code except
33  * the actual MAC algorithm is run exactly as it would if a proper
34  * MAC algorithm was run. This can be used for end-end system
35  * testing all the way to a server or relying party, not just for
36  * testing device code as t_cose_mac0_verify() supports it too.
37  */
38 #define T_COSE_OPT_SHORT_CIRCUIT_TAG 0x00000004
39 
40 
41 /**
42  * This is the context for creating a \c COSE_Mac0 structure. The caller
43  * should allocate it and pass it to the functions here.  This is
44  * about 32 bytes so it fits easily on the stack.
45  */
46 struct t_cose_mac0_sign_ctx {
47     /* Private data structure */
48     uint8_t                protected_parameters_buffer[
49                                     T_COSE_MAC0_MAX_SIZE_PROTECTED_PARAMETERS];
50     struct q_useful_buf_c  protected_parameters; /* The encoded protected parameters */
51     int32_t                cose_algorithm_id;
52     struct t_cose_key      signing_key;
53     int32_t                option_flags;
54     struct q_useful_buf_c  kid;
55 #ifndef T_COSE_DISABLE_CONTENT_TYPE
56     uint32_t               content_type_uint;
57     const char            *content_type_tstr;
58 #endif
59 };
60 
61 
62 /**
63  * \brief  Initialize to start creating a \c COSE_Mac0.
64  *
65  * \param[in] context            The t_cose signing context.
66  * \param[in] option_flags       One of \c T_COSE_OPT_XXXX.
67  * \param[in] cose_algorithm_id  The algorithm to generate the authentication
68  *                               tag, for example
69  *                               \ref T_COSE_ALGORITHM_HMAC256.
70  *
71  * Initialize the \ref t_cose_mac0_sign_ctx context. Typically, no
72  * \c option_flags are needed and 0 is passed. A \c cose_algorithm_id
73  * must always be given. See \ref T_COSE_OPT_SHORT_CIRCUIT_TAG and
74  * related for possible option flags.
75  *
76  * The algorithm ID space is from
77  * [COSE (RFC8152)](https://tools.ietf.org/html/rfc8152) and the
78  * [IANA COSE Registry](https://www.iana.org/assignments/cose/cose.xhtml).
79  * \ref T_COSE_ALGORITHM_HMAC256 is defined here for convenience.
80  * So far, only HMAC is supported in \c COSE_Mac0.
81  *
82  * Errors such as the passing of an unsupported \c cose_algorithm_id
83  * are reported when t_cose_mac0_encode_parameters() is called.
84  */
85 static void
86 t_cose_mac0_sign_init(struct t_cose_mac0_sign_ctx *me,
87                       int32_t                      option_flags,
88                       int32_t                      cose_algorithm_id);
89 
90 /**
91  * \brief  Set the key and kid (key ID) for signing.
92  *
93  * \param[in] context      The t_cose signing context.
94  * \param[in] signing_key  The signing key to use or \ref T_COSE_NULL_KEY.
95  * \param[in] kid          COSE key ID parameter or \c NULL_Q_USEFUL_BUF_C.
96  *
97  * This needs to be called to set the signing key to use. The \c kid
98  * may be omitted by giving \c NULL_Q_USEFUL_BUF_C.
99  *
100  * If short-circuit signing is used,
101  * \ref T_COSE_OPT_SHORT_CIRCUIT_TAG, then this does not need to be
102  * called.
103  */
104 static void
105 t_cose_mac0_set_signing_key(struct t_cose_mac0_sign_ctx *context,
106                             struct t_cose_key            signing_key,
107                             struct q_useful_buf_c        kid);
108 
109 /**
110  * \brief  Output first part and parameters for a \c COSE_Mac0 message.
111  *
112  * \param[in] context          The t_cose signing context.
113  * \param[in] cbor_encode_ctx  Encoding context to output to.
114  *
115  * t_cose_mac0_sign_init() and t_cose_mac0_set_signing_key() must be
116  * called before calling this.
117  *
118  * When this is called, the opening parts of the \c COSE_Mac0 message
119  * are output to the \c cbor_encode_ctx.
120  *
121  * After this is called, the CBOR-formatted payload must be written to
122  * the \c cbor_encode_ctx by calling all the various
123  * \c QCBOREncode_AddXxx calls. It can be as simple or complex as needed.
124  *
125  * To complete the \c COSE_Mac0 call t_cose_mac0_encode_tag().
126  *
127  * The \c cbor_encode_ctx must have been initialized with an output
128  * buffer to hold the \c COSE_Mac0 header parameters, the payload and the
129  * signature.
130  *
131  * This and t_cose_mac0_encode_tag() can be used to calculate
132  * the size of the \c COSE_Mac0 in the way \c QCBOREncode is usually
133  * used to calculate sizes. In this case the \c t_cose_mac0_sign_ctx must
134  * be initialized with the options, algorithm, key and kid just as
135  * normal as these are needed to calculate the size. Then set up the
136  * QCBOR encoder context with a \c NULL pointer and large length like
137  * \c UINT32_MAX.  Call t_cose_mac0_encode_parameters(), then format
138  * the payload into the encoder context, then call
139  * t_cose_mac0_encode_tag().  Finally call \c
140  * QCBOREncode_FinishGetSize() to get the length.
141  */
142 enum t_cose_err_t
143 t_cose_mac0_encode_parameters(struct t_cose_mac0_sign_ctx *context,
144                               QCBOREncodeContext          *cbor_encode_ctx);
145 
146 /**
147  * \brief Finish a \c COSE_Mac0 message by outputting the authentication tag.
148  *
149  * \param[in] context          The t_cose signing context.
150  * \param[in] cbor_encode_ctx  Encoding context to output to.
151  *
152  * \return This returns one of the error codes defined by \ref t_cose_err_t.
153  *
154  * Call this to complete creation of a tagged \c COSE_Mac0 started
155  * with t_cose_mac0_encode_parameters().
156  *
157  * This is when the cryptographic MAC algorithm is run.
158  *
159  * The completed \c COSE_Mac0 message is retrieved from the
160  * \c cbor_encode_ctx by calling \c QCBOREncode_Finish().
161  */
162 enum t_cose_err_t
163 t_cose_mac0_encode_tag(struct t_cose_mac0_sign_ctx *context,
164                        QCBOREncodeContext          *cbor_encode_ctx);
165 
166 
167 #ifndef T_COSE_DISABLE_CONTENT_TYPE
168 /**
169  * \brief Set the payload content type using CoAP content types.
170  *
171  * \param[in] context      The t_cose signing context.
172  * \param[in] content_type The content type of the payload as defined
173  *                         in the IANA CoAP Content-Formats registry.
174  *
175  * It is not allowed to have both a CoAP and MIME content type. This
176  * error will show up when t_cose_mac0_encode_parameters() is called
177  * as no error is returned by this function.
178  *
179  * The IANA CoAP Content-Formats registry is found
180  * [here](https://www.iana.org/assignments/core-parameters/core-parameters.xhtml#content-formats).
181  */
182 static inline void
183 t_cose_mac0_set_content_type_uint(struct t_cose_mac0_sign_ctx *context,
184                                   uint16_t                     content_type);
185 
186 /**
187  * \brief Set the payload content type using MIME content types.
188  *
189  * \param[in] context      The t_cose signing context.
190  * \param[in] content_type The content type of the payload as defined
191  *                         in the IANA Media Types registry.
192 
193  *
194  * It is not allowed to have both a CoAP and MIME content type. This
195  * error will show up when t_cose_mac0_encode_parameters() is called.
196  *
197  * The IANA Media Types registry can be found
198  * [here](https://www.iana.org/assignments/media-types/media-types.xhtml).
199  * These have been known as MIME types in the past.
200  */
201 static inline void
202 t_cose_mac0_set_content_type_tstr(struct t_cose_mac0_sign_ctx *context,
203                                   const char                  *content_type);
204 #endif /* T_COSE_DISABLE_CONTENT_TYPE */
205 
206 /* ------------------------------------------------------------------------
207  * Inline implementations of public functions defined above.
208  */
209 static inline void
t_cose_mac0_sign_init(struct t_cose_mac0_sign_ctx * me,int32_t option_flags,int32_t cose_algorithm_id)210 t_cose_mac0_sign_init(struct t_cose_mac0_sign_ctx *me,
211                       int32_t                      option_flags,
212                       int32_t                      cose_algorithm_id)
213 {
214     memset(me, 0, sizeof(*me));
215 
216 #ifndef T_COSE_DISABLE_CONTENT_TYPE
217     /* Only member for which 0 is not the empty state */
218     me->content_type_uint = T_COSE_EMPTY_UINT_CONTENT_TYPE;
219 #endif
220 
221     me->cose_algorithm_id = cose_algorithm_id;
222     me->option_flags      = option_flags;
223 }
224 
225 static inline void
t_cose_mac0_set_signing_key(struct t_cose_mac0_sign_ctx * me,struct t_cose_key signing_key,struct q_useful_buf_c kid)226 t_cose_mac0_set_signing_key(struct t_cose_mac0_sign_ctx *me,
227                             struct t_cose_key            signing_key,
228                             struct q_useful_buf_c        kid)
229 {
230     me->kid         = kid;
231     me->signing_key = signing_key;
232 }
233 
234 
235 #ifndef T_COSE_DISABLE_CONTENT_TYPE
236 static inline void
t_cose_mac0_set_content_type_uint(struct t_cose_mac0_sign_ctx * me,uint16_t content_type)237 t_cose_mac0_set_content_type_uint(struct t_cose_mac0_sign_ctx *me,
238                                   uint16_t                     content_type)
239 {
240     me->content_type_uint = content_type;
241 }
242 
243 static inline void
t_cose_mac0_set_content_type_tstr(struct t_cose_mac0_sign_ctx * me,const char * content_type)244 t_cose_mac0_set_content_type_tstr(struct t_cose_mac0_sign_ctx *me,
245                                   const char                  *content_type)
246 {
247     me->content_type_tstr = content_type;
248 }
249 #endif /* T_COSE_DISABLE_CONTENT_TYPE */
250 
251 #ifdef __cplusplus
252 }
253 #endif
254 
255 #endif /* __T_COSE_MAC0_SIGN_H_ */
256