Line data Source code
1 : /**
2 : * The MIT License (MIT)
3 : *
4 : * Copyright (c) 2021 RSK Labs Ltd
5 : *
6 : * Permission is hereby granted, free of charge, to any person obtaining a copy
7 : * of this software and associated documentation files (the "Software"), to
8 : * deal in the Software without restriction, including without limitation the
9 : * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
10 : * sell copies of the Software, and to permit persons to whom the Software is
11 : * furnished to do so, subject to the following conditions:
12 : *
13 : * The above copyright notice and this permission notice shall be included in
14 : * all copies or substantial portions of the Software.
15 : *
16 : * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 : * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 : * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 : * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 : * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21 : * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
22 : * IN THE SOFTWARE.
23 : */
24 :
25 : #include <string.h>
26 :
27 : #include "hal/seed.h"
28 : #include "hal/endorsement.h"
29 : #include "hal/platform.h"
30 : #include "hal/exceptions.h"
31 :
32 : #include "attestation.h"
33 : #include "apdu.h"
34 : #include "defs.h"
35 : #include "pathAuth.h"
36 : #include "bc_state.h"
37 : #include "bc_hash.h"
38 : #include "mem.h"
39 : #include "memutil.h"
40 : #include "util.h"
41 :
42 : // Attestation message prefix
43 : const char att_msg_prefix[ATT_MSG_PREFIX_LENGTH] = ATT_MSG_PREFIX;
44 :
45 : // Utility macros for message gathering paging
46 : // Maximum page size is APDU data part size minus one
47 : // byte (first byte of the response), which is used to indicate
48 : // whether there is a next page or not.
49 : #define MIN(x, y) ((x) < (y) ? (x) : (y))
50 : #define MAX_PAGESIZE (APDU_TOTAL_DATA_SIZE_OUT - 1)
51 : #define PAGECOUNT(itemcount) (((itemcount) + MAX_PAGESIZE - 1) / MAX_PAGESIZE)
52 : #define CURPAGESIZE(itemcount, page) \
53 : (MIN(MAX_PAGESIZE, (itemcount) - ((page)*MAX_PAGESIZE)))
54 :
55 4 : static void reset_attestation(att_t* att_ctx) {
56 4 : explicit_bzero(att_ctx, sizeof(att_t));
57 4 : att_ctx->state = STATE_ATTESTATION_WAIT_SIGN;
58 4 : }
59 :
60 19 : static void check_state(att_t* att_ctx, state_attestation_t expected) {
61 19 : if (att_ctx->state != expected) {
62 3 : reset_attestation(att_ctx);
63 3 : THROW(ERR_ATT_PROT_INVALID);
64 : }
65 16 : }
66 :
67 13 : static void hash_public_key(const char* path,
68 : size_t path_size,
69 : att_t* att_ctx) {
70 : // Derive public key
71 :
72 : // Skip first byte of path when copying (path size byte)
73 26 : SAFE_MEMMOVE(att_ctx->path,
74 : sizeof(att_ctx->path),
75 : MEMMOVE_ZERO_OFFSET,
76 : (unsigned int*)path,
77 : path_size,
78 : 1,
79 : sizeof(att_ctx->path),
80 : { goto hash_public_key_error; });
81 :
82 13 : att_ctx->pubkey_length = sizeof(att_ctx->pubkey);
83 13 : if (!seed_derive_pubkey(att_ctx->path,
84 : sizeof(att_ctx->path) / sizeof(att_ctx->path[0]),
85 13 : att_ctx->pubkey,
86 : &att_ctx->pubkey_length)) {
87 1 : goto hash_public_key_error;
88 : }
89 :
90 : // Hash
91 12 : SHA256_UPDATE(&att_ctx->hash_ctx, att_ctx->pubkey, att_ctx->pubkey_length);
92 :
93 : // Cleanup public key
94 12 : explicit_bzero(&att_ctx->pubkey, sizeof(att_ctx->pubkey));
95 12 : att_ctx->pubkey_length = 0;
96 :
97 12 : return;
98 :
99 1 : hash_public_key_error:
100 : // Cleanup public key
101 1 : explicit_bzero(&att_ctx->pubkey, sizeof(att_ctx->pubkey));
102 1 : att_ctx->pubkey_length = 0;
103 1 : THROW(ERR_ATT_INTERNAL);
104 : }
105 :
106 2 : static void write_uint64_be(uint8_t* out, uint64_t in) {
107 2 : out[0] = (uint8_t)(in >> 56);
108 2 : out[1] = (uint8_t)(in >> 48);
109 2 : out[2] = (uint8_t)(in >> 40);
110 2 : out[3] = (uint8_t)(in >> 32);
111 2 : out[4] = (uint8_t)(in >> 24);
112 2 : out[5] = (uint8_t)(in >> 16);
113 2 : out[6] = (uint8_t)(in >> 8);
114 2 : out[7] = (uint8_t)in;
115 2 : }
116 :
117 : /*
118 : * Generate the attestation message.
119 : *
120 : * @arg[in] att_ctx attestation context
121 : * @arg[in] ud_value pointer to the user-defined value
122 : */
123 3 : static void generate_message_to_sign(att_t* att_ctx, unsigned char* ud_value) {
124 :
125 : // Initialize message
126 3 : explicit_bzero(att_ctx->msg, sizeof(att_ctx->msg));
127 3 : att_ctx->msg_length = 0;
128 :
129 : // Copy the message prefix
130 6 : SAFE_MEMMOVE(att_ctx->msg,
131 : sizeof(att_ctx->msg),
132 : att_ctx->msg_length,
133 : (void*)PIC(ATT_MSG_PREFIX),
134 : ATT_MSG_PREFIX_LENGTH,
135 : MEMMOVE_ZERO_OFFSET,
136 : ATT_MSG_PREFIX_LENGTH,
137 : THROW(ERR_ATT_INTERNAL));
138 3 : att_ctx->msg_length += ATT_MSG_PREFIX_LENGTH;
139 :
140 : // Copy the platform id
141 6 : SAFE_MEMMOVE(att_ctx->msg,
142 : sizeof(att_ctx->msg),
143 : att_ctx->msg_length,
144 : (void*)PIC(platform_get_id()),
145 : PLATFORM_ID_LENGTH,
146 : MEMMOVE_ZERO_OFFSET,
147 : PLATFORM_ID_LENGTH,
148 : THROW(ERR_ATT_INTERNAL));
149 3 : att_ctx->msg_length += PLATFORM_ID_LENGTH;
150 :
151 : // Copy the UD value
152 6 : SAFE_MEMMOVE(att_ctx->msg,
153 : sizeof(att_ctx->msg),
154 : att_ctx->msg_length,
155 : (void*)PIC(ud_value),
156 : ATT_UD_VALUE_SIZE,
157 : MEMMOVE_ZERO_OFFSET,
158 : ATT_UD_VALUE_SIZE,
159 : THROW(ERR_ATT_INTERNAL));
160 3 : att_ctx->msg_length += ATT_UD_VALUE_SIZE;
161 :
162 : // Prepare the digest
163 3 : SHA256_INIT(&att_ctx->hash_ctx);
164 :
165 : // Retrieve and hash the public keys in order
166 15 : for (unsigned int i = 0; i < TOTAL_AUTHORIZED_PATHS; i++) {
167 13 : hash_public_key(get_ordered_path(i), SINGLE_PATH_SIZE_BYTES, att_ctx);
168 : }
169 :
170 : // Finalise the public keys hash straight into the message
171 2 : SHA256_FINAL(&att_ctx->hash_ctx, &att_ctx->msg[att_ctx->msg_length]);
172 2 : att_ctx->msg_length += HASH_LENGTH;
173 :
174 : // Copy the current best block
175 4 : SAFE_MEMMOVE(att_ctx->msg,
176 : sizeof(att_ctx->msg),
177 : att_ctx->msg_length,
178 : N_bc_state.best_block,
179 : sizeof(N_bc_state.best_block),
180 : MEMMOVE_ZERO_OFFSET,
181 : sizeof(N_bc_state.best_block),
182 : THROW(ERR_ATT_INTERNAL));
183 2 : att_ctx->msg_length += sizeof(N_bc_state.best_block);
184 :
185 : // Copy the leading bytes of the last authorised signed tx
186 4 : SAFE_MEMMOVE(att_ctx->msg,
187 : sizeof(att_ctx->msg),
188 : att_ctx->msg_length,
189 : N_bc_state.last_auth_signed_btc_tx_hash,
190 : sizeof(N_bc_state.last_auth_signed_btc_tx_hash),
191 : MEMMOVE_ZERO_OFFSET,
192 : ATT_LAST_SIGNED_TX_BYTES,
193 : THROW(ERR_ATT_INTERNAL));
194 2 : att_ctx->msg_length += ATT_LAST_SIGNED_TX_BYTES;
195 :
196 : // Copy the current timestamp
197 2 : write_uint64_be(&att_ctx->msg[att_ctx->msg_length],
198 : platform_get_timestamp());
199 2 : att_ctx->msg_length += sizeof(uint64_t);
200 2 : }
201 :
202 : // -----------------------------------------------------------------------
203 : // Protocol implementation
204 : // -----------------------------------------------------------------------
205 :
206 : /*
207 : * Implement the attestation protocol.
208 : *
209 : * @arg[in] rx number of received bytes from the Host
210 : * @arg[in] att_ctx attestation context
211 : * @ret number of transmited bytes to the host
212 : */
213 24 : unsigned int get_attestation(volatile unsigned int rx, att_t* att_ctx) {
214 : size_t buf_length;
215 : uint8_t* buf;
216 :
217 24 : switch (APDU_OP()) {
218 4 : case OP_ATT_GET:
219 : // Should receive a user-defined value
220 4 : if (APDU_DATA_SIZE(rx) != ATT_UD_VALUE_SIZE) {
221 1 : reset_attestation(att_ctx);
222 1 : THROW(ERR_ATT_PROT_INVALID);
223 : }
224 :
225 : // Generate the message to attest
226 3 : generate_message_to_sign(att_ctx, APDU_DATA_PTR);
227 :
228 : // Attest message
229 2 : uint8_t endorsement_size = (uint8_t)MIN(APDU_TOTAL_DATA_SIZE_OUT, 0xFF);
230 2 : if (!endorsement_sign(att_ctx->msg,
231 2 : att_ctx->msg_length,
232 2 : APDU_DATA_PTR,
233 : &endorsement_size)) {
234 1 : THROW(ERR_ATT_INTERNAL);
235 : }
236 :
237 : // Ready
238 1 : att_ctx->state = STATE_ATTESTATION_READY;
239 :
240 1 : return TX_FOR_DATA_SIZE(endorsement_size);
241 16 : case OP_ATT_GET_ENVELOPE:
242 : case OP_ATT_GET_MESSAGE:
243 16 : check_state(att_ctx, STATE_ATTESTATION_READY);
244 :
245 : // Should receive a page index
246 14 : if (APDU_DATA_SIZE(rx) != 1)
247 2 : THROW(ERR_ATT_PROT_INVALID);
248 :
249 : // Get the envelope or message
250 12 : buf = endorsement_get_envelope();
251 12 : buf_length = endorsement_get_envelope_length();
252 12 : if (!buf || APDU_OP() == OP_ATT_GET_MESSAGE) {
253 7 : buf = att_ctx->msg;
254 7 : buf_length = att_ctx->msg_length;
255 : }
256 :
257 : // Check page index within range (page index is zero based)
258 12 : if (APDU_DATA_PTR[0] >= PAGECOUNT(buf_length)) {
259 2 : THROW(ERR_ATT_PROT_INVALID);
260 : }
261 10 : uint8_t page = APDU_DATA_PTR[0];
262 :
263 : // Copy the page into the APDU buffer (no need to check for limits since
264 : // the chunk size is based directly on the APDU size)
265 20 : SAFE_MEMMOVE(APDU_DATA_PTR,
266 : APDU_TOTAL_DATA_SIZE_OUT,
267 : 1,
268 : buf,
269 : buf_length,
270 : APDU_DATA_PTR[0] * MAX_PAGESIZE,
271 : CURPAGESIZE(buf_length, page),
272 : THROW(ERR_ATT_INTERNAL));
273 10 : APDU_DATA_PTR[0] = page < (PAGECOUNT(buf_length) - 1);
274 :
275 10 : return TX_FOR_DATA_SIZE(CURPAGESIZE(buf_length, page) + 1);
276 3 : case OP_ATT_APP_HASH:
277 3 : check_state(att_ctx, STATE_ATTESTATION_READY);
278 :
279 2 : buf_length = MIN(APDU_TOTAL_DATA_SIZE_OUT, 0xFF);
280 2 : if (!endorsement_get_code_hash(APDU_DATA_PTR, (uint8_t*)&buf_length)) {
281 1 : THROW(ERR_ATT_INTERNAL);
282 : }
283 1 : return TX_FOR_DATA_SIZE(buf_length);
284 1 : default:
285 1 : THROW(ERR_ATT_PROT_INVALID);
286 : break;
287 : }
288 : return 0;
289 : }
|