aboutsummaryrefslogtreecommitdiff
path: root/lib/ext/t_cose/src/t_cose_sign1_verify.c
blob: 69404f32a3cee6d996d8c326f3b31ffbf3af8cd0 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
/*
 *  t_cose_sign1_verify.c
 *
 * Copyright 2019, Laurence Lundblade
 *
 * SPDX-License-Identifier: BSD-3-Clause
 *
 * See BSD-3-Clause license in README.md
 */


#include "t_cose_sign1_verify.h"
#include "qcbor.h"
#include "t_cose_crypto.h"
#include "q_useful_buf.h"
#include "t_cose_util.h"
#include "t_cose_parameters.h"


/**
 * \file t_cose_sign1_verify.c
 *
 * \brief \c COSE_Sign1 verification implementation.
 */



#ifndef T_COSE_DISABLE_SHORT_CIRCUIT_SIGN
/**
 *  \brief Verify a short-circuit signature
 *
 * \param[in] hash_to_verify  Pointer and length of hash to verify.
 * \param[in] signature       Pointer and length of signature.
 *
 * \return This returns one of the error codes defined by \ref
 *         t_cose_err_t.
 *
 * See t_cose_sign1_sign_init() for description of the short-circuit
 * signature.
 */
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)
{
    struct q_useful_buf_c hash_from_sig;
    enum t_cose_err_t     return_value;

    hash_from_sig = q_useful_buf_head(signature, hash_to_verify.len);
    if(q_useful_buf_c_is_null(hash_from_sig)) {
        return_value = T_COSE_ERR_SIG_VERIFY;
        goto Done;
    }

    if(q_useful_buf_compare(hash_from_sig, hash_to_verify)) {
        return_value = T_COSE_ERR_SIG_VERIFY;
    } else {
        return_value = T_COSE_SUCCESS;
    }

Done:
    return return_value;
}
#endif /* T_COSE_DISABLE_SHORT_CIRCUIT_SIGN */


/*
 * Public function. See t_cose_sign1_verify.h
 */
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)
{
    /* Stack use for 32-bit CPUs:
     *   268 for local except hash output
     *   32 to 64 local for hash output
     *   220 to 434 to make TBS hash
     * Total 420 to 768 depending on hash and EC alg.
     * Stack used internally by hash and crypto is extra.
     */
    QCBORDecodeContext            decode_context;
    QCBORItem                     item;
    struct q_useful_buf_c         protected_parameters;
    enum t_cose_err_t             return_value;
    Q_USEFUL_BUF_MAKE_STACK_UB(   buffer_for_tbs_hash, T_COSE_CRYPTO_MAX_HASH_SIZE);
    struct q_useful_buf_c         tbs_hash;
    struct q_useful_buf_c         signature;
    struct t_cose_parameters      unprotected_parameters;
    struct t_cose_parameters      parsed_protected_parameters;
    struct t_cose_label_list      critical_labels;
    struct t_cose_label_list      unknown_labels;
#ifndef T_COSE_DISABLE_SHORT_CIRCUIT_SIGN
    struct q_useful_buf_c         short_circuit_kid;
#endif

    *payload = NULL_Q_USEFUL_BUF_C;

    QCBORDecode_Init(&decode_context, cose_sign1, QCBOR_DECODE_MODE_NORMAL);
    /* Calls to QCBORDecode_GetNext() rely on item.uDataType != QCBOR_TYPE_ARRAY
     * to detect decoding errors rather than checking the return code.
     */

    /* --  The array of four -- */
    (void)QCBORDecode_GetNext(&decode_context, &item);
    if(item.uDataType != QCBOR_TYPE_ARRAY) {
        return_value = T_COSE_ERR_SIGN1_FORMAT;
        goto Done;
    }

    if((me->option_flags & T_COSE_OPT_TAG_REQUIRED) &&
       !QCBORDecode_IsTagged(&decode_context, &item, CBOR_TAG_COSE_SIGN1)) {
        return_value = T_COSE_ERR_INCORRECTLY_TAGGED;
        goto Done;
    }

    /* -- Clear list where uknown labels are accumulated -- */
    clear_label_list(&unknown_labels);


    /* --  Get the protected header parameters -- */
    (void)QCBORDecode_GetNext(&decode_context, &item);
    if(item.uDataType != QCBOR_TYPE_BYTE_STRING) {
        return_value = T_COSE_ERR_SIGN1_FORMAT;
        goto Done;
    }

    protected_parameters = item.val.string;

    return_value = parse_protected_header_parameters(protected_parameters,
                                                    &parsed_protected_parameters,
                                                    &critical_labels,
                                                    &unknown_labels);
    if(return_value != T_COSE_SUCCESS) {
        goto Done;
    }


    /* --  Get the unprotected parameters -- */
    return_value = parse_unprotected_header_parameters(&decode_context,
                                                       &unprotected_parameters,
                                                       &unknown_labels);
    if(return_value != T_COSE_SUCCESS) {
        goto Done;
    }
    if((me->option_flags & T_COSE_OPT_REQUIRE_KID) &&
       q_useful_buf_c_is_null(unprotected_parameters.kid)) {
        return_value = T_COSE_ERR_NO_KID;
        goto Done;
    }


    /* -- Check critical parameter labels -- */
    return_value = check_critical_labels(&unknown_labels, &critical_labels);
    if(return_value != T_COSE_SUCCESS) {
        goto Done;
    }

    /* -- Check for duplicate parameters and copy to returned parameters -- */
    return_value = check_and_copy_parameters(&parsed_protected_parameters,
                                             &unprotected_parameters,
                                              parameters);
    if(return_value != T_COSE_SUCCESS) {
        goto Done;
    }


    /* -- Get the payload -- */
    (void)QCBORDecode_GetNext(&decode_context, &item);
    if(item.uDataType != QCBOR_TYPE_BYTE_STRING) {
        return_value = T_COSE_ERR_SIGN1_FORMAT;
        goto Done;
    }
    *payload = item.val.string;


    /* -- Get the signature -- */
    (void)QCBORDecode_GetNext(&decode_context, &item);
    if(item.uDataType != QCBOR_TYPE_BYTE_STRING) {
        return_value = T_COSE_ERR_SIGN1_FORMAT;
        goto Done;
    }
    signature = item.val.string;


    /* -- Finish up the CBOR decode -- */
    /* This check make sure the array only had the expected four
     * items. Works for definite and indefinte length arrays. Also
     * make sure there were no extra bytes. */
    if(QCBORDecode_Finish(&decode_context) != QCBOR_SUCCESS) {
        return_value = T_COSE_ERR_CBOR_NOT_WELL_FORMED;
        goto Done;
    }


    /* -- Skip signature verification if such is requested --*/
    if(me->option_flags & T_COSE_OPT_DECODE_ONLY) {
        return_value = T_COSE_SUCCESS;
        goto Done;
    }


    /* -- Compute the TBS bytes -- */
    return_value = create_tbs_hash(parsed_protected_parameters.cose_algorithm_id,
                                   protected_parameters,
                                   T_COSE_TBS_BARE_PAYLOAD,
                                   *payload,
                                   buffer_for_tbs_hash,
                                   &tbs_hash);
    if(return_value) {
        goto Done;
    }


    /* -- Check for short-circuit signature and verify if it exists -- */
#ifndef T_COSE_DISABLE_SHORT_CIRCUIT_SIGN
    short_circuit_kid = get_short_circuit_kid();
    if(!q_useful_buf_compare(unprotected_parameters.kid, short_circuit_kid)) {
        if(!(me->option_flags & T_COSE_OPT_ALLOW_SHORT_CIRCUIT)) {
            return_value = T_COSE_ERR_SHORT_CIRCUIT_SIG;
            goto Done;
        }

        return_value = t_cose_crypto_short_circuit_verify(tbs_hash, signature);
        goto Done;
    }
#endif /* T_COSE_DISABLE_SHORT_CIRCUIT_SIGN */


    /* -- Verify the signature (if it wasn't short-circuit) -- */
    return_value = t_cose_crypto_pub_key_verify(parsed_protected_parameters.cose_algorithm_id,
                                                me->verification_key,
                                                unprotected_parameters.kid,
                                                tbs_hash,
                                                signature);

Done:
    return return_value;
}