1 /*
2 * t_cose_sign1_verify.c
3 *
4 * Copyright 2019, Laurence Lundblade
5 *
6 * SPDX-License-Identifier: BSD-3-Clause
7 *
8 * See BSD-3-Clause license in README.md
9 */
10
11
12 #include "t_cose_sign1_verify.h"
13 #include "qcbor/qcbor.h"
14 #include "t_cose_crypto.h"
15 #include "q_useful_buf.h"
16 #include "t_cose_util.h"
17 #include "t_cose_parameters.h"
18
19
20 /**
21 * \file t_cose_sign1_verify.c
22 *
23 * \brief \c COSE_Sign1 verification implementation.
24 */
25
26
27
28 #ifndef T_COSE_DISABLE_SHORT_CIRCUIT_SIGN
29 /**
30 * \brief Verify a short-circuit signature
31 *
32 * \param[in] hash_to_verify Pointer and length of hash to verify.
33 * \param[in] signature Pointer and length of signature.
34 *
35 * \return This returns one of the error codes defined by \ref
36 * t_cose_err_t.
37 *
38 * See t_cose_sign1_sign_init() for description of the short-circuit
39 * signature.
40 */
41 static inline enum t_cose_err_t
t_cose_crypto_short_circuit_verify(struct q_useful_buf_c hash_to_verify,struct q_useful_buf_c signature)42 t_cose_crypto_short_circuit_verify(struct q_useful_buf_c hash_to_verify,
43 struct q_useful_buf_c signature)
44 {
45 struct q_useful_buf_c hash_from_sig;
46 enum t_cose_err_t return_value;
47
48 hash_from_sig = q_useful_buf_head(signature, hash_to_verify.len);
49 if(q_useful_buf_c_is_null(hash_from_sig)) {
50 return_value = T_COSE_ERR_SIG_VERIFY;
51 goto Done;
52 }
53
54 if(q_useful_buf_compare(hash_from_sig, hash_to_verify)) {
55 return_value = T_COSE_ERR_SIG_VERIFY;
56 } else {
57 return_value = T_COSE_SUCCESS;
58 }
59
60 Done:
61 return return_value;
62 }
63 #endif /* T_COSE_DISABLE_SHORT_CIRCUIT_SIGN */
64
65
66 /*
67 * Public function. See t_cose_sign1_verify.h
68 */
69 enum t_cose_err_t
t_cose_sign1_verify(struct t_cose_sign1_verify_ctx * me,struct q_useful_buf_c cose_sign1,struct q_useful_buf_c * payload,struct t_cose_parameters * parameters)70 t_cose_sign1_verify(struct t_cose_sign1_verify_ctx *me,
71 struct q_useful_buf_c cose_sign1,
72 struct q_useful_buf_c *payload,
73 struct t_cose_parameters *parameters)
74 {
75 /* Stack use for 32-bit CPUs:
76 * 268 for local except hash output
77 * 32 to 64 local for hash output
78 * 220 to 434 to make TBS hash
79 * Total 420 to 768 depending on hash and EC alg.
80 * Stack used internally by hash and crypto is extra.
81 */
82 QCBORDecodeContext decode_context;
83 QCBORItem item;
84 struct q_useful_buf_c protected_parameters;
85 enum t_cose_err_t return_value;
86 Q_USEFUL_BUF_MAKE_STACK_UB( buffer_for_tbs_hash, T_COSE_CRYPTO_MAX_HASH_SIZE);
87 struct q_useful_buf_c tbs_hash;
88 struct q_useful_buf_c signature;
89 struct t_cose_parameters unprotected_parameters;
90 struct t_cose_parameters parsed_protected_parameters;
91 struct t_cose_label_list critical_labels;
92 struct t_cose_label_list unknown_labels;
93 #ifndef T_COSE_DISABLE_SHORT_CIRCUIT_SIGN
94 struct q_useful_buf_c short_circuit_kid;
95 #endif
96
97 *payload = NULL_Q_USEFUL_BUF_C;
98
99 QCBORDecode_Init(&decode_context, cose_sign1, QCBOR_DECODE_MODE_NORMAL);
100 /* Calls to QCBORDecode_GetNext() rely on item.uDataType != QCBOR_TYPE_ARRAY
101 * to detect decoding errors rather than checking the return code.
102 */
103
104 /* -- The array of four -- */
105 (void)QCBORDecode_GetNext(&decode_context, &item);
106 if(item.uDataType != QCBOR_TYPE_ARRAY) {
107 return_value = T_COSE_ERR_SIGN1_FORMAT;
108 goto Done;
109 }
110
111 if((me->option_flags & T_COSE_OPT_TAG_REQUIRED) &&
112 !QCBORDecode_IsTagged(&decode_context, &item, CBOR_TAG_COSE_SIGN1)) {
113 return_value = T_COSE_ERR_INCORRECTLY_TAGGED;
114 goto Done;
115 }
116
117 /* -- Clear list where uknown labels are accumulated -- */
118 clear_label_list(&unknown_labels);
119
120
121 /* -- Get the protected header parameters -- */
122 (void)QCBORDecode_GetNext(&decode_context, &item);
123 if(item.uDataType != QCBOR_TYPE_BYTE_STRING) {
124 return_value = T_COSE_ERR_SIGN1_FORMAT;
125 goto Done;
126 }
127
128 protected_parameters = item.val.string;
129
130 return_value = parse_protected_header_parameters(protected_parameters,
131 &parsed_protected_parameters,
132 &critical_labels,
133 &unknown_labels);
134 if(return_value != T_COSE_SUCCESS) {
135 goto Done;
136 }
137
138
139 /* -- Get the unprotected parameters -- */
140 return_value = parse_unprotected_header_parameters(&decode_context,
141 &unprotected_parameters,
142 &unknown_labels);
143 if(return_value != T_COSE_SUCCESS) {
144 goto Done;
145 }
146 if((me->option_flags & T_COSE_OPT_REQUIRE_KID) &&
147 q_useful_buf_c_is_null(unprotected_parameters.kid)) {
148 return_value = T_COSE_ERR_NO_KID;
149 goto Done;
150 }
151
152
153 /* -- Check critical parameter labels -- */
154 return_value = check_critical_labels(&critical_labels, &unknown_labels);
155 if(return_value != T_COSE_SUCCESS) {
156 goto Done;
157 }
158
159 /* -- Check for duplicate parameters and copy to returned parameters -- */
160 return_value = check_and_copy_parameters(&parsed_protected_parameters,
161 &unprotected_parameters,
162 parameters);
163 if(return_value != T_COSE_SUCCESS) {
164 goto Done;
165 }
166
167
168 /* -- Get the payload -- */
169 (void)QCBORDecode_GetNext(&decode_context, &item);
170 if(item.uDataType != QCBOR_TYPE_BYTE_STRING) {
171 return_value = T_COSE_ERR_SIGN1_FORMAT;
172 goto Done;
173 }
174 *payload = item.val.string;
175
176
177 /* -- Get the signature -- */
178 (void)QCBORDecode_GetNext(&decode_context, &item);
179 if(item.uDataType != QCBOR_TYPE_BYTE_STRING) {
180 return_value = T_COSE_ERR_SIGN1_FORMAT;
181 goto Done;
182 }
183 signature = item.val.string;
184
185
186 /* -- Finish up the CBOR decode -- */
187 /* This check make sure the array only had the expected four
188 * items. Works for definite and indefinte length arrays. Also
189 * make sure there were no extra bytes. */
190 if(QCBORDecode_Finish(&decode_context) != QCBOR_SUCCESS) {
191 return_value = T_COSE_ERR_CBOR_NOT_WELL_FORMED;
192 goto Done;
193 }
194
195
196 /* -- Skip signature verification if such is requested --*/
197 if(me->option_flags & T_COSE_OPT_DECODE_ONLY) {
198 return_value = T_COSE_SUCCESS;
199 goto Done;
200 }
201
202
203 /* -- Compute the TBS bytes -- */
204 return_value = create_tbs_hash(parsed_protected_parameters.cose_algorithm_id,
205 protected_parameters,
206 T_COSE_TBS_BARE_PAYLOAD,
207 *payload,
208 buffer_for_tbs_hash,
209 &tbs_hash);
210 if(return_value) {
211 goto Done;
212 }
213
214
215 /* -- Check for short-circuit signature and verify if it exists -- */
216 #ifndef T_COSE_DISABLE_SHORT_CIRCUIT_SIGN
217 short_circuit_kid = get_short_circuit_kid();
218 if(!q_useful_buf_compare(unprotected_parameters.kid, short_circuit_kid)) {
219 if(!(me->option_flags & T_COSE_OPT_ALLOW_SHORT_CIRCUIT)) {
220 return_value = T_COSE_ERR_SHORT_CIRCUIT_SIG;
221 goto Done;
222 }
223
224 return_value = t_cose_crypto_short_circuit_verify(tbs_hash, signature);
225 goto Done;
226 }
227 #endif /* T_COSE_DISABLE_SHORT_CIRCUIT_SIGN */
228
229
230 /* -- Verify the signature (if it wasn't short-circuit) -- */
231 return_value = t_cose_crypto_pub_key_verify(parsed_protected_parameters.cose_algorithm_id,
232 me->verification_key,
233 unprotected_parameters.kid,
234 tbs_hash,
235 signature);
236
237 Done:
238 return return_value;
239 }
240