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 * See BSD-3-Clause license in README.md
8 */
9
10 #include "qcbor/qcbor.h"
11 #include "t_cose_crypto.h"
12 #include "t_cose_mac0_verify.h"
13 #include "t_cose_parameters.h"
14 #include "t_cose_util.h"
15
16 #ifndef T_COSE_DISABLE_SHORT_CIRCUIT_SIGN
17 /**
18 * \brief Verify a short-circuit tag
19 *
20 * \param[in] cose_alg_id Algorithm ID. This is used only to make
21 * the short-circuit signature the same size as the
22 * real tag would be for the particular algorithm.
23 * \param[in] header The Header of COSE_Mac0.
24 * \param[in] payload The payload of COSE_Mac0
25 * \param[in] tag Pointer and length of tag to be verified
26 *
27 * \return This returns one of the error codes defined by \ref
28 * t_cose_err_t.
29 *
30 * See short_circuit_tag() in t_cose_mac0_sign.c for description of
31 * the short-circuit tag.
32 */
33 static inline enum t_cose_err_t
short_circuit_verify(int32_t cose_alg_id,struct q_useful_buf_c header,struct q_useful_buf_c payload,struct q_useful_buf_c tag_to_verify)34 short_circuit_verify(int32_t cose_alg_id,
35 struct q_useful_buf_c header,
36 struct q_useful_buf_c payload,
37 struct q_useful_buf_c tag_to_verify)
38 {
39 /* approximate stack use on 32-bit machine: local use: 16 bytes */
40 enum t_cose_err_t return_value;
41 struct t_cose_crypto_hash hash_ctx;
42 Q_USEFUL_BUF_MAKE_STACK_UB(tag_buffer, T_COSE_CRYPTO_HMAC_TAG_MAX_SIZE);
43 struct q_useful_buf_c tag;
44 int32_t hash_alg_id;
45
46 hash_alg_id = t_cose_hmac_to_hash_alg_id(cose_alg_id);
47 if (hash_alg_id == INT32_MAX) {
48 return_value = T_COSE_ERR_UNSUPPORTED_SIGNING_ALG;
49 goto Done;
50 }
51
52 return_value = t_cose_crypto_hash_start(&hash_ctx, hash_alg_id);
53 if (return_value != T_COSE_SUCCESS) {
54 goto Done;
55 }
56
57 /* Hash the Header */
58 t_cose_crypto_hash_update(&hash_ctx, q_useful_buf_head(header, header.len));
59
60 /* Hash the payload */
61 t_cose_crypto_hash_update(&hash_ctx, payload);
62
63 return_value = t_cose_crypto_hash_finish(&hash_ctx, tag_buffer, &tag);
64 if (return_value != T_COSE_SUCCESS) {
65 goto Done;
66 }
67
68 if (q_useful_buf_compare(tag_to_verify, tag)) {
69 return_value = T_COSE_ERR_SIG_VERIFY;
70 } else {
71 return_value = T_COSE_SUCCESS;
72 }
73
74 Done:
75 return return_value;
76 }
77 #endif /* T_COSE_DISABLE_SHORT_CIRCUIT_SIGN */
78
79 /**
80 * \file t_cose_mac0_verify.c
81 *
82 * \brief This verifies t_cose Mac authentication structure without a recipient
83 * structure.
84 * Only HMAC is supported so far.
85 */
86
87 /*
88 * Public function. See t_cose_mac0.h
89 */
t_cose_mac0_verify(struct t_cose_mac0_verify_ctx * context,struct q_useful_buf_c cose_mac0,struct q_useful_buf_c * payload,struct t_cose_parameters * parameters)90 enum t_cose_err_t t_cose_mac0_verify(struct t_cose_mac0_verify_ctx *context,
91 struct q_useful_buf_c cose_mac0,
92 struct q_useful_buf_c *payload,
93 struct t_cose_parameters *parameters)
94 {
95 QCBORDecodeContext decode_context;
96 QCBORItem item;
97 struct q_useful_buf_c protected_parameters;
98 struct t_cose_parameters parsed_protected_parameters;
99 struct t_cose_parameters unprotected_parameters;
100 struct t_cose_label_list critical_labels;
101 struct t_cose_label_list unknown_labels;
102 enum t_cose_err_t return_value;
103 struct q_useful_buf_c tag;
104 struct q_useful_buf_c tbm_first_part;
105 /* Buffer for the ToBeMaced */
106 Q_USEFUL_BUF_MAKE_STACK_UB( tbm_first_part_buf,
107 T_COSE_SIZE_OF_TBM);
108 struct t_cose_crypto_hmac hmac_ctx;
109
110 *payload = NULL_Q_USEFUL_BUF_C;
111
112 QCBORDecode_Init(&decode_context, cose_mac0, QCBOR_DECODE_MODE_NORMAL);
113 /* Calls to QCBORDecode_GetNext() rely on item.uDataType != QCBOR_TYPE_ARRAY
114 * to detect decoding errors rather than checking the return code.
115 */
116
117 /* -- The array of four -- */
118 (void)QCBORDecode_GetNext(&decode_context, &item);
119 if(item.uDataType != QCBOR_TYPE_ARRAY) {
120 return_value = T_COSE_ERR_MAC0_FORMAT;
121 goto Done;
122 }
123
124 if((context->option_flags & T_COSE_OPT_TAG_REQUIRED) &&
125 !QCBORDecode_IsTagged(&decode_context, &item, CBOR_TAG_COSE_MAC0)) {
126 return_value = T_COSE_ERR_INCORRECTLY_TAGGED;
127 goto Done;
128 }
129
130 /* -- Clear list where unknown labels are accumulated -- */
131 clear_label_list(&unknown_labels);
132
133 /* -- Get the protected header parameters -- */
134 (void)QCBORDecode_GetNext(&decode_context, &item);
135 if(item.uDataType != QCBOR_TYPE_BYTE_STRING) {
136 return_value = T_COSE_ERR_MAC0_FORMAT;
137 goto Done;
138 }
139
140 protected_parameters = item.val.string;
141
142 return_value = parse_protected_header_parameters(protected_parameters,
143 &parsed_protected_parameters,
144 &critical_labels,
145 &unknown_labels);
146 if(return_value != T_COSE_SUCCESS) {
147 goto Done;
148 }
149
150 /* -- Get the unprotected parameters -- */
151 return_value = parse_unprotected_header_parameters(&decode_context,
152 &unprotected_parameters,
153 &unknown_labels);
154 if(return_value != T_COSE_SUCCESS) {
155 goto Done;
156 }
157 if((context->option_flags & T_COSE_OPT_REQUIRE_KID) &&
158 q_useful_buf_c_is_null(unprotected_parameters.kid)) {
159 return_value = T_COSE_ERR_NO_KID;
160 goto Done;
161 }
162
163 /* -- Check critical parameter labels -- */
164 return_value = check_critical_labels(&critical_labels, &unknown_labels);
165 if(return_value != T_COSE_SUCCESS) {
166 goto Done;
167 }
168
169 /* -- Check for duplicate parameters and copy to returned parameters -- */
170 return_value = check_and_copy_parameters(&parsed_protected_parameters,
171 &unprotected_parameters,
172 parameters);
173 if(return_value != T_COSE_SUCCESS) {
174 goto Done;
175 }
176
177 /* -- Get the payload -- */
178 QCBORDecode_GetNext(&decode_context, &item);
179 if(item.uDataType != QCBOR_TYPE_BYTE_STRING) {
180 return_value = T_COSE_ERR_MAC0_FORMAT;
181 goto Done;
182 }
183 *payload = item.val.string;
184
185 /* -- Get the tag -- */
186 QCBORDecode_GetNext(&decode_context, &item);
187 if(item.uDataType != QCBOR_TYPE_BYTE_STRING) {
188 return_value = T_COSE_ERR_MAC0_FORMAT;
189 goto Done;
190 }
191 tag = item.val.string;
192
193 /* -- Finish up the CBOR decode -- */
194 /* This check make sure the array only had the expected four
195 * items. Works for definite and indefinite length arrays. Also
196 * make sure there were no extra bytes.
197 */
198 if(QCBORDecode_Finish(&decode_context) != QCBOR_SUCCESS) {
199 return_value = T_COSE_ERR_CBOR_NOT_WELL_FORMED;
200 goto Done;
201 }
202
203 /* -- Skip tag verification if such is requested --*/
204 if(context->option_flags & T_COSE_OPT_DECODE_ONLY) {
205 return_value = T_COSE_SUCCESS;
206 goto Done;
207 }
208
209 /* -- Compute the ToBeMaced -- */
210 return_value = create_tbm(tbm_first_part_buf,
211 protected_parameters,
212 &tbm_first_part,
213 T_COSE_TBM_BARE_PAYLOAD,
214 *payload);
215 if(return_value) {
216 goto Done;
217 }
218
219 if (context->option_flags & T_COSE_OPT_ALLOW_SHORT_CIRCUIT) {
220 #ifndef T_COSE_DISABLE_SHORT_CIRCUIT_SIGN
221 /* Short-circuit tag. Hash is used to generated tag instead of HMAC */
222 return_value = short_circuit_verify(
223 parsed_protected_parameters.cose_algorithm_id,
224 tbm_first_part,
225 *payload,
226 tag);
227 #else
228 return_value = T_COSE_ERR_SHORT_CIRCUIT_SIG_DISABLED;
229 #endif
230 goto Done;
231
232 }
233 /*
234 * Start the HMAC verification.
235 * Calculate the tag of the first part of ToBeMaced and the wrapped
236 * payload, to save a bigger buffer containing the entire ToBeMaced.
237 */
238 return_value = t_cose_crypto_hmac_verify_setup(&hmac_ctx,
239 parsed_protected_parameters.cose_algorithm_id,
240 context->verification_key);
241 if(return_value) {
242 goto Done;
243 }
244
245 /* Compute the tag of the first part. */
246 return_value = t_cose_crypto_hmac_update(&hmac_ctx,
247 q_useful_buf_head(tbm_first_part,
248 tbm_first_part.len));
249 if(return_value) {
250 goto Done;
251 }
252
253 return_value = t_cose_crypto_hmac_update(&hmac_ctx, *payload);
254 if(return_value) {
255 goto Done;
256 }
257
258 return_value = t_cose_crypto_hmac_verify_finish(&hmac_ctx, tag);
259
260 Done:
261 return return_value;
262 }
263