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