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) (MIN(MAX_PAGESIZE, (itemcount) - ((page) * MAX_PAGESIZE)))
53 :
54 0 : static void reset_attestation(att_t* att_ctx) {
55 0 : explicit_bzero(att_ctx, sizeof(att_t));
56 0 : att_ctx->state = STATE_ATTESTATION_WAIT_SIGN;
57 0 : }
58 :
59 0 : static void check_state(att_t* att_ctx,
60 : state_attestation_t expected) {
61 0 : if (att_ctx->state != expected) {
62 0 : reset_attestation(att_ctx);
63 0 : THROW(ERR_ATT_PROT_INVALID);
64 : }
65 0 : }
66 :
67 0 : 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 0 : 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 0 : att_ctx->pubkey_length = sizeof(att_ctx->pubkey);
83 0 : if (!seed_derive_pubkey(att_ctx->path,
84 : sizeof(att_ctx->path) / sizeof(att_ctx->path[0]),
85 0 : att_ctx->pubkey,
86 : &att_ctx->pubkey_length)) {
87 0 : goto hash_public_key_error;
88 : }
89 :
90 : // Hash
91 0 : SHA256_UPDATE(&att_ctx->hash_ctx, att_ctx->pubkey, att_ctx->pubkey_length);
92 :
93 : // Cleanup public key
94 0 : explicit_bzero(&att_ctx->pubkey, sizeof(att_ctx->pubkey));
95 0 : att_ctx->pubkey_length = 0;
96 :
97 0 : return;
98 :
99 0 : hash_public_key_error:
100 : // Cleanup public key
101 0 : explicit_bzero(&att_ctx->pubkey, sizeof(att_ctx->pubkey));
102 0 : att_ctx->pubkey_length = 0;
103 0 : THROW(ERR_ATT_INTERNAL);
104 : }
105 :
106 0 : static void write_uint64_be(uint8_t *out, uint64_t in) {
107 0 : out[0] = (uint8_t)(in >> 56);
108 0 : out[1] = (uint8_t)(in >> 48);
109 0 : out[2] = (uint8_t)(in >> 40);
110 0 : out[3] = (uint8_t)(in >> 32);
111 0 : out[4] = (uint8_t)(in >> 24);
112 0 : out[5] = (uint8_t)(in >> 16);
113 0 : out[6] = (uint8_t)(in >> 8);
114 0 : out[7] = (uint8_t)in;
115 0 : }
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 0 : static void generate_message_to_sign(att_t* att_ctx, unsigned char* ud_value) {
124 :
125 : // Initialize message
126 0 : explicit_bzero(att_ctx->msg, sizeof(att_ctx->msg));
127 0 : att_ctx->msg_length = 0;
128 :
129 : // Copy the message prefix
130 0 : 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 0 : att_ctx->msg_length += ATT_MSG_PREFIX_LENGTH;
139 :
140 : // Copy the platform id
141 0 : 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 0 : att_ctx->msg_length += PLATFORM_ID_LENGTH;
150 :
151 : // Copy the UD value
152 0 : 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 0 : att_ctx->msg_length += ATT_UD_VALUE_SIZE;
161 :
162 : // Prepare the digest
163 0 : SHA256_INIT(&att_ctx->hash_ctx);
164 :
165 : // Retrieve and hash the public keys in order
166 0 : for (unsigned int i = 0; i < KEY_PATH_COUNT(); i++) {
167 0 : 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 0 : SHA256_FINAL(&att_ctx->hash_ctx, &att_ctx->msg[att_ctx->msg_length]);
172 0 : att_ctx->msg_length += HASH_LENGTH;
173 :
174 : // Copy the current best block
175 0 : 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 0 : att_ctx->msg_length += sizeof(N_bc_state.best_block);
184 :
185 : // Copy the leading bytes of the last authorised signed tx
186 0 : 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 0 : att_ctx->msg_length += ATT_LAST_SIGNED_TX_BYTES;
195 :
196 : // Copy the current timestamp
197 0 : write_uint64_be(&att_ctx->msg[att_ctx->msg_length], platform_get_timestamp());
198 0 : att_ctx->msg_length += sizeof(uint64_t);
199 0 : }
200 :
201 : // -----------------------------------------------------------------------
202 : // Protocol implementation
203 : // -----------------------------------------------------------------------
204 :
205 : /*
206 : * Implement the attestation protocol.
207 : *
208 : * @arg[in] rx number of received bytes from the Host
209 : * @arg[in] att_ctx attestation context
210 : * @ret number of transmited bytes to the host
211 : */
212 0 : unsigned int get_attestation(volatile unsigned int rx, att_t* att_ctx) {
213 : size_t buf_length;
214 : uint8_t* buf;
215 :
216 0 : switch (APDU_OP()) {
217 0 : case OP_ATT_GET:
218 : // Should receive a user-defined value
219 0 : if (APDU_DATA_SIZE(rx) != ATT_UD_VALUE_SIZE) {
220 0 : reset_attestation(att_ctx);
221 0 : THROW(ERR_ATT_PROT_INVALID);
222 : }
223 :
224 : // Generate the message to attest
225 0 : generate_message_to_sign(att_ctx, APDU_DATA_PTR);
226 :
227 : // Attest message
228 0 : uint8_t endorsement_size = (uint8_t)MIN(APDU_TOTAL_DATA_SIZE_OUT, 0xFF);
229 0 : if (!endorsement_sign(
230 0 : att_ctx->msg, att_ctx->msg_length, APDU_DATA_PTR, &endorsement_size)) {
231 0 : THROW(ERR_ATT_INTERNAL);
232 : }
233 :
234 : // Ready
235 0 : att_ctx->state = STATE_ATTESTATION_READY;
236 :
237 0 : return TX_FOR_DATA_SIZE(endorsement_size);
238 0 : case OP_ATT_GET_ENVELOPE:
239 : case OP_ATT_GET_MESSAGE:
240 0 : check_state(att_ctx, STATE_ATTESTATION_READY);
241 :
242 : // Should receive a page index
243 0 : if (APDU_DATA_SIZE(rx) != 1)
244 0 : THROW(ERR_ATT_PROT_INVALID);
245 :
246 : // Get the envelope or message
247 0 : buf = endorsement_get_envelope();
248 0 : buf_length = endorsement_get_envelope_length();
249 0 : if (!buf || APDU_OP() == OP_ATT_GET_MESSAGE) {
250 0 : buf = att_ctx->msg;
251 0 : buf_length = att_ctx->msg_length;
252 : }
253 :
254 : // Check page index within range (page index is zero based)
255 0 : if (APDU_DATA_PTR[0] >= PAGECOUNT(buf_length)) {
256 0 : THROW(ERR_ATT_PROT_INVALID);
257 : }
258 0 : uint8_t page = APDU_DATA_PTR[0];
259 :
260 : // Copy the page into the APDU buffer (no need to check for limits since
261 : // the chunk size is based directly on the APDU size)
262 0 : SAFE_MEMMOVE(APDU_DATA_PTR,
263 : APDU_TOTAL_DATA_SIZE_OUT,
264 : 1,
265 : buf,
266 : buf_length,
267 : APDU_DATA_PTR[0] * MAX_PAGESIZE,
268 : CURPAGESIZE(buf_length, page),
269 : THROW(ERR_ATT_INTERNAL));
270 0 : APDU_DATA_PTR[0] = page < (PAGECOUNT(buf_length) - 1);
271 :
272 0 : return TX_FOR_DATA_SIZE(
273 : CURPAGESIZE(buf_length, page) + 1);
274 0 : case OP_ATT_APP_HASH:
275 0 : check_state(att_ctx, STATE_ATTESTATION_READY);
276 :
277 0 : buf_length = MIN(APDU_TOTAL_DATA_SIZE_OUT, 0xFF);
278 0 : if (!endorsement_get_code_hash(APDU_DATA_PTR, (uint8_t*)&buf_length)) {
279 0 : THROW(ERR_ATT_INTERNAL);
280 : }
281 0 : return TX_FOR_DATA_SIZE(buf_length);
282 0 : default:
283 0 : THROW(ERR_ATT_PROT_INVALID);
284 : break;
285 : }
286 : return 0;
287 : }
|