blob: 3fa357296f631b55263adbc6a5e5e9fe3aba5aaf [file] [log] [blame]
Laurence Lundbladeaffd65a2018-12-18 10:50:48 -08001/*
2 * t_cose_util.c
3 *
4 * Copyright 2019, Laurence Lundblade
5 *
6 * SPDX-License-Identifier: BSD-3-Clause
7 *
Tamas Ban32814992019-04-25 14:25:43 +01008 * See BSD-3-Clause license in README.md.
Laurence Lundbladeaffd65a2018-12-18 10:50:48 -08009 */
10
11#include "t_cose_util.h"
12#include "qcbor.h"
13#include "t_cose_defines.h"
14#include "t_cose_common.h"
15#include "t_cose_crypto.h"
16
17
18/**
19 * \file t_cose_util.c
20 *
21 * \brief Implementation of t_cose utility functions.
22 *
Laurence Lundblade2ad4e4f2019-04-07 12:02:49 -070023 * These are some functions common to signing and
24 * verification.
Laurence Lundbladeaffd65a2018-12-18 10:50:48 -080025 */
26
27
28/*
29 * Public function. See t_cose_util.h
30 */
31int32_t hash_alg_id_from_sig_alg_id(int32_t cose_sig_alg_id)
32{
Laurence Lundblade2ad4e4f2019-04-07 12:02:49 -070033 /* If other hashes, particularly those that output bigger hashes
Laurence Lundbladeaffd65a2018-12-18 10:50:48 -080034 * are added here, various other parts of this code have to be
35 * changed to have larger buffers.
36 */
37 switch(cose_sig_alg_id) {
Laurence Lundblade2ad4e4f2019-04-07 12:02:49 -070038 case COSE_ALGORITHM_ES256:
39 return COSE_ALG_SHA256_PROPRIETARY;
Laurence Lundbladeaffd65a2018-12-18 10:50:48 -080040
Laurence Lundblade2ad4e4f2019-04-07 12:02:49 -070041 default:
42 return INT32_MAX;
Laurence Lundbladeaffd65a2018-12-18 10:50:48 -080043 }
44}
45
46
47/*
48 * Format of to-be-signed bytes used by create_tbs_hash().
49 * This is defined in COSE (RFC 8152). It is the input
50 * to the hash.
51 *
52 * Sig_structure = [
53 * context : "Signature" / "Signature1" / "CounterSignature",
54 * body_protected : empty_or_serialized_map,
55 * ? sign_protected : empty_or_serialized_map,
56 * external_aad : bstr,
57 * payload : bstr
58 * ]
Laurence Lundblade2ad4e4f2019-04-07 12:02:49 -070059 *
60 * body_protected refers to the protected headers from the
61 * main COSE_Sign1 structure. This is a little hard to
62 * to understand in the spec.
63 *
64 * sign_protected is not used with COSE_Sign1 since
65 * there is no signer chunk.
66 *
67 * external_aad allows external data to be covered
68 * by the hash, but is not supported by this implementation.
Laurence Lundbladeaffd65a2018-12-18 10:50:48 -080069 */
70
71
72/**
73 * This is the size of the first part of the CBOR encoded TBS
Laurence Lundblade2ad4e4f2019-04-07 12:02:49 -070074 * bytes. It is around 30 bytes. See create_tbs_hash().
Laurence Lundbladeaffd65a2018-12-18 10:50:48 -080075 */
76#define T_COSE_SIZE_OF_TBS \
77 1 + /* For opening the array */ \
78 sizeof(COSE_SIG_CONTEXT_STRING_SIGNATURE1) + /* "Signature1" */ \
79 2 + /* Overhead for encoding string */ \
80 T_COSE_SIGN1_MAX_PROT_HEADER + /* entire protected headers */ \
Laurence Lundblade2ad4e4f2019-04-07 12:02:49 -070081 1 + /* Empty bstr for absent external_aad */ \
82 9 /* The max CBOR length encoding for start of payload */
Laurence Lundbladeaffd65a2018-12-18 10:50:48 -080083
84
85/*
86 * Public function. See t_cose_util.h
87 */
88enum t_cose_err_t create_tbs_hash(int32_t cose_alg_id,
Laurence Lundbladee1610ad2019-02-20 13:53:20 -080089 struct q_useful_buf buffer_for_hash,
90 struct q_useful_buf_c *hash,
91 struct q_useful_buf_c protected_headers,
Laurence Lundblade2ad4e4f2019-04-07 12:02:49 -070092 enum t_cose_tbs_hash_mode_t payload_mode,
Laurence Lundbladee1610ad2019-02-20 13:53:20 -080093 struct q_useful_buf_c payload)
Laurence Lundbladeaffd65a2018-12-18 10:50:48 -080094{
95 /* approximate stack use on 32-bit machine:
Laurence Lundblade2ad4e4f2019-04-07 12:02:49 -070096 * local use: 210
97 * total with calls: 250
98 * Can be another 128 bytes or so depending on
99 * t_cose_crypto_hash implementation. It sometimes
100 * includes the full hashing context.
Laurence Lundbladeaffd65a2018-12-18 10:50:48 -0800101 */
102 enum t_cose_err_t return_value;
103 QCBOREncodeContext cbor_encode_ctx;
104 UsefulBuf_MAKE_STACK_UB( buffer_for_TBS_first_part, T_COSE_SIZE_OF_TBS);
Laurence Lundbladee1610ad2019-02-20 13:53:20 -0800105 struct q_useful_buf_c tbs_first_part;
Laurence Lundbladeaffd65a2018-12-18 10:50:48 -0800106 QCBORError qcbor_result;
107 struct t_cose_crypto_hash hash_ctx;
108 int32_t hash_alg_id;
Laurence Lundblade2ad4e4f2019-04-07 12:02:49 -0700109 size_t bytes_to_omit;
Laurence Lundbladeaffd65a2018-12-18 10:50:48 -0800110
111 /* This builds the CBOR-format to-be-signed bytes */
112 QCBOREncode_Init(&cbor_encode_ctx, buffer_for_TBS_first_part);
113 QCBOREncode_OpenArray(&cbor_encode_ctx);
114 /* context */
115 QCBOREncode_AddSZString(&cbor_encode_ctx,
116 COSE_SIG_CONTEXT_STRING_SIGNATURE1);
117 /* body_protected */
118 QCBOREncode_AddBytes(&cbor_encode_ctx,
119 protected_headers);
Laurence Lundblade2ad4e4f2019-04-07 12:02:49 -0700120 /* sign_protected is not used for Sign1 */
121
122 /* external_aad. There is none so an empty bstr */
Laurence Lundbladee1610ad2019-02-20 13:53:20 -0800123 QCBOREncode_AddBytes(&cbor_encode_ctx, NULL_Q_USEFUL_BUF_C);
Laurence Lundblade2ad4e4f2019-04-07 12:02:49 -0700124
125 /* The short fake payload. */
126 if(payload_mode == T_COSE_TBS_PAYLOAD_IS_BSTR_WRAPPED) {
127 /* Fake payload is just an empty bstr. It is here only
128 * to make the array count right. It must be ommitted
129 * in the actual hashing below
130 */
131 bytes_to_omit = 1;
132 QCBOREncode_AddBytes(&cbor_encode_ctx, NULL_Q_USEFUL_BUF_C);
133 } else {
134 /* Fake payload is the type and length of the wrapping
135 * bstr. It gets hashed with the first part, so no
136 * bytes to omit.
137 */
138 bytes_to_omit = 0;
139 QCBOREncode_AddBytesLenOnly(&cbor_encode_ctx, payload);
140 }
141 /* Cleverness only works because the payload is last in the array */
142
143 /* Close of the array */
Laurence Lundbladeaffd65a2018-12-18 10:50:48 -0800144 QCBOREncode_CloseArray(&cbor_encode_ctx);
145
Laurence Lundblade2ad4e4f2019-04-07 12:02:49 -0700146 /* get the encoded results, except for payload */
Laurence Lundbladeaffd65a2018-12-18 10:50:48 -0800147 qcbor_result = QCBOREncode_Finish(&cbor_encode_ctx, &tbs_first_part);
148 if(qcbor_result) {
149 /* Mainly means that the protected_headers were too big
Laurence Lundblade2ad4e4f2019-04-07 12:02:49 -0700150 * (which should never happen) */
Laurence Lundbladeaffd65a2018-12-18 10:50:48 -0800151 return_value = T_COSE_ERR_SIG_STRUCT;
152 goto Done;
153 }
154
155 /* Start the hashing */
156 hash_alg_id = hash_alg_id_from_sig_alg_id(cose_alg_id);
157 /* Don't check hash_alg_id for failure. t_cose_crypto_hash_start()
Laurence Lundblade2ad4e4f2019-04-07 12:02:49 -0700158 * will handle it properly.
Laurence Lundbladeaffd65a2018-12-18 10:50:48 -0800159 */
160 return_value = t_cose_crypto_hash_start(&hash_ctx, hash_alg_id);
161 if(return_value) {
162 goto Done;
163 }
164
Laurence Lundblade2ad4e4f2019-04-07 12:02:49 -0700165 /* This structure is hashed in two parts. The first part is
166 * the CBOR-formatted array with protected headers and such.
167 * The last part is the actual bytes of the payload. Doing it
168 * this way avoids having to allocate a big buffer to hold
169 * these two parts together. It avoids having two copies of
170 * the payload in the implementaiton as the payload as formatted
171 * in the output buffer can be what is hashed. They payload
172 * is the largest memory use, so this saves a lot.
173 *
174 * This is further complicated because the the payload
175 * does have to be wrapped in a bstr. It is done one way
176 * when signing and another when verifying.
177 */
178
179 /* This is hashing of the first part, all the CBOR
180 * except the payload.
Laurence Lundbladeaffd65a2018-12-18 10:50:48 -0800181 */
182 t_cose_crypto_hash_update(&hash_ctx,
Laurence Lundbladee1610ad2019-02-20 13:53:20 -0800183 q_useful_buf_head(tbs_first_part,
Laurence Lundblade2ad4e4f2019-04-07 12:02:49 -0700184 tbs_first_part.len - bytes_to_omit));
Laurence Lundbladeaffd65a2018-12-18 10:50:48 -0800185
Laurence Lundblade2ad4e4f2019-04-07 12:02:49 -0700186 /* Hash the payload, the second part. This may or may not
187 * have the bstr wrapping. If not, it was hashed above.
188 */
Laurence Lundbladeaffd65a2018-12-18 10:50:48 -0800189 t_cose_crypto_hash_update(&hash_ctx, payload);
190
191 /* Finish the hash and set up to return it */
192 return_value = t_cose_crypto_hash_finish(&hash_ctx,
193 buffer_for_hash,
194 hash);
Laurence Lundbladeaffd65a2018-12-18 10:50:48 -0800195Done:
196 return return_value;
197}
198
199
200/*
201 * Public function. See t_cose_util.h
202 */
203enum t_cose_err_t
Laurence Lundbladee1610ad2019-02-20 13:53:20 -0800204get_short_circuit_kid(struct q_useful_buf buffer_for_kid,
205 struct q_useful_buf_c *kid)
Laurence Lundbladeaffd65a2018-12-18 10:50:48 -0800206{
207 /* This is a random hard coded key ID that is used to indicate
208 * short-circuit signing. It is OK to hard code this as the
209 * probability of collision with this ID is very low and the same
210 * as for collision between any two key IDs of any sort.
211 */
212 uint8_t defined_short_circuit_kid[] = {
213 0xef, 0x95, 0x4b, 0x4b, 0xd9, 0xbd, 0xf6, 0x70,
214 0xd0, 0x33, 0x60, 0x82, 0xf5, 0xef, 0x15, 0x2a,
215 0xf8, 0xf3, 0x5b, 0x6a, 0x6c, 0x00, 0xef, 0xa6,
216 0xa9, 0xa7, 0x1f, 0x49, 0x51, 0x7e, 0x18, 0xc6};
217
218 /* Prevent a dumb error where the size constant in the header is
219 * wrong.This check will be evaluated at compile time and optimize
220 * out when all is correct.
221 */
222 if(sizeof(defined_short_circuit_kid) != T_COSE_SHORT_CIRCUIT_KID_SIZE) {
223 return T_COSE_ERR_BAD_SHORT_CIRCUIT_KID;
224 }
225
Laurence Lundbladee1610ad2019-02-20 13:53:20 -0800226 *kid = q_useful_buf_copy(buffer_for_kid,
227 Q_USEFUL_BUF_FROM_BYTE_ARRAY_LITERAL(
228 defined_short_circuit_kid));
Laurence Lundbladeaffd65a2018-12-18 10:50:48 -0800229
Laurence Lundbladee1610ad2019-02-20 13:53:20 -0800230 return q_useful_buf_c_is_null(*kid) ?
Laurence Lundbladeaffd65a2018-12-18 10:50:48 -0800231 T_COSE_ERR_KEY_BUFFER_SIZE :
232 T_COSE_SUCCESS;
233}