blob: 9c212962cf79f926c5647e139d3b5f3825e16ce2 [file] [log] [blame]
Imre Kis23d1ba52023-10-20 13:56:47 +02001/*
2 * Copyright (c) 2023, Arm Limited. All rights reserved.
3 *
4 * SPDX-License-Identifier: BSD-3-Clause
5 */
6
7#include "rpmb_frontend.h"
8#include "util.h"
9#include <stdlib.h>
10#include <string.h>
11
12static void u32_to_rpmb_field(uint32_t u32, uint8_t *rpmb_field)
13{
14 rpmb_field[0] = (u32 >> 24) & 0xff;
15 rpmb_field[1] = (u32 >> 16) & 0xff;
16 rpmb_field[2] = (u32 >> 8) & 0xff;
17 rpmb_field[3] = u32 & 0xff;
18}
19
20static uint32_t u32_from_rpmb_field(const uint8_t *rpmb_field)
21{
22 return (rpmb_field[0] << 24) | (rpmb_field[1] << 16) | (rpmb_field[2] << 8) | rpmb_field[3];
23}
24
25static void u16_to_rpmb_field(uint16_t u16, uint8_t *rpmb_field)
26{
27 rpmb_field[0] = (u16 >> 8) & 0xff;
28 rpmb_field[1] = u16 & 0xff;
29}
30
31static uint16_t u16_from_rpmb_field(const uint8_t *rpmb_field)
32{
33 return (rpmb_field[0] << 8) | rpmb_field[1];
34}
35
36static inline psa_status_t rpmb_derive_key(struct rpmb_frontend *frontend, const uint8_t *data,
37 size_t data_length, uint8_t *key, size_t key_length)
38{
39 struct rpmb_platform *platform = frontend->platform;
40
41 return platform->interface->derive_key(platform->context, data, data_length, key,
42 key_length);
43}
44
45
46static inline psa_status_t rpmb_get_nonce(struct rpmb_frontend *frontend, uint8_t *nonce,
47 size_t nonce_length)
48{
49 struct rpmb_platform *platform = frontend->platform;
50
51 return platform->interface->get_nonce(platform->context, nonce, nonce_length);
52}
53
54
55static inline psa_status_t rpmb_calculate_mac(struct rpmb_frontend *frontend,
56 const struct rpmb_data_frame *frames,
57 size_t frame_count, uint8_t *mac)
58{
59 struct rpmb_platform *platform = frontend->platform;
60
61 return platform->interface->calculate_mac(platform->context, frontend->key,
62 sizeof(frontend->key), frames, frame_count, mac,
63 RPMB_KEY_MAC_SIZE);
64}
65
66static psa_status_t rpmb_read_write_counter(struct rpmb_frontend *context)
67{
68 struct rpmb_data_frame frame = { 0 };
69 size_t response_frame_count = 1;
70 uint8_t nonce[RPMB_NONCE_SIZE] = { 0 };
71 uint8_t mac[RPMB_KEY_MAC_SIZE] = { 0 };
72 psa_status_t status = PSA_ERROR_GENERIC_ERROR;
73 uint16_t resp_type = 0;
74 uint16_t op_result = RPMB_RES_GENERAL_FAILURE;
75
76 status = rpmb_get_nonce(context, nonce, sizeof(nonce));
77 if (status != PSA_SUCCESS)
78 return status;
79
80 /* Setting nonce and request type */
81 memcpy(frame.nonce, nonce, sizeof(frame.nonce));
82 u16_to_rpmb_field(RPMB_REQ_TYPE_READ_WRITE_COUNTER, frame.msg_type);
83
84 status = rpmb_backend_data_request(context->backend, context->dev_id, &frame, 1,
85 &frame, &response_frame_count);
86 if (status != PSA_SUCCESS)
87 return status;
88
89 /* Validate response type, result, nonce and MAC */
90 op_result = u16_from_rpmb_field(frame.op_result);
91 if (op_result != RPMB_RES_OK)
92 return PSA_ERROR_STORAGE_FAILURE;
93
94 resp_type = u16_from_rpmb_field(frame.msg_type);
95 if (resp_type != RPMB_RESP_TYPE_READ_WRITE_COUNTER)
96 return PSA_ERROR_STORAGE_FAILURE;
97
98 if (memcmp(frame.nonce, nonce, sizeof(frame.nonce)) != 0)
99 return PSA_ERROR_STORAGE_FAILURE;
100
101 status = rpmb_calculate_mac(context, &frame, 1, mac);
102 if (status != PSA_SUCCESS)
103 return status;
104
105 if (memcmp(frame.key_mac, mac, sizeof(frame.key_mac)) != 0)
106 return PSA_ERROR_STORAGE_FAILURE;
107
108 context->write_counter = u32_from_rpmb_field(frame.write_counter);
109
110 return PSA_SUCCESS;
111}
112
113#if RPMB_WRITE_KEY
114static bool rpmb_is_key_set(struct rpmb_frontend *context)
115{
116 return rpmb_read_write_counter(context) == PSA_SUCCESS;
117}
118
119static psa_status_t rpmb_write_key(struct rpmb_frontend *context)
120{
121 psa_status_t status = PSA_ERROR_GENERIC_ERROR;
122 struct rpmb_data_frame frames[2] = { 0 };
123 size_t response_count = 0;
124 uint16_t msg_type = 0;
125
126 /* Authentication Key Data Packet */
127 memcpy(frames[0].key_mac, context->key, sizeof(frames[0].key_mac));
128 u16_to_rpmb_field(RPMB_REQ_TYPE_AUTHENTICATION_KEY_WRITE, frames[0].msg_type);
129
130 /* Result Register Read Request Packet*/
131 u16_to_rpmb_field(RPMB_REQ_TYPE_RESULT_READ_REQUEST, frames[1].msg_type);
132
133 response_count = 1;
134 status = rpmb_backend_data_request(context->backend, context->dev_id, frames, 2, frames,
135 &response_count);
136 if (status != PSA_SUCCESS)
137 return status;
138
139 if (response_count != 1)
140 return PSA_ERROR_INSUFFICIENT_DATA;
141
142 /* Parse Response for Key Programming Result Request */
143 msg_type = u16_from_rpmb_field(frames[0].msg_type);
144 if (u16_from_rpmb_field(frames[0].op_result) != RPMB_RES_OK ||
145 msg_type != RPMB_RESP_TYPE_AUTHENTICATION_KEY_WRITE)
146 return PSA_ERROR_STORAGE_FAILURE;
147
148 return PSA_SUCCESS;
149}
150#endif /* RPMB_WRITE_KEY */
151
152psa_status_t rpmb_frontend_create(struct rpmb_frontend *context, struct rpmb_platform *platform,
153 struct rpmb_backend *backend, uint32_t dev_id)
154{
155 if (!context || !platform || !backend)
156 return PSA_ERROR_INVALID_ARGUMENT;
157
158 *context = (struct rpmb_frontend){ 0 };
159
160 context->platform = platform;
161 context->backend = backend;
162 context->dev_id = dev_id;
163
164 return PSA_SUCCESS;
165}
166
167psa_status_t rpmb_frontend_init(struct rpmb_frontend *context)
168{
169 psa_status_t status = PSA_ERROR_GENERIC_ERROR;
170 struct rpmb_dev_info dev_info = { 0 };
171
172 status = rpmb_backend_get_dev_info(context->backend, context->dev_id, &dev_info);
173 if (status != PSA_SUCCESS)
174 return status;
175
176 if (!dev_info.rpmb_size_mult)
177 return PSA_ERROR_INVALID_ARGUMENT;
178
179 if (MUL_OVERFLOW(dev_info.rpmb_size_mult, RPMB_SIZE_MULT_UNIT / RPMB_DATA_SIZE,
180 &context->block_count))
181 return PSA_ERROR_INVALID_ARGUMENT;
182
183 /* Mask product revision and CRC because it might change on eMMC FFU */
184 dev_info.cid[RPMB_CID_PRODUCT_REVISION] = 0;
185 dev_info.cid[RPMB_CID_CRC7] = 0;
186 status = rpmb_derive_key(context, dev_info.cid, sizeof(dev_info.cid), context->key,
187 RPMB_KEY_MAC_SIZE);
188 if (status != PSA_SUCCESS)
189 return status;
190
191#if RPMB_WRITE_KEY
192 if (!rpmb_is_key_set(context)) {
193 status = rpmb_write_key(context);
194 if (status != PSA_SUCCESS)
195 return status;
196 }
197#endif /* RPMB_WRITE_KEY */
198
199 status = rpmb_read_write_counter(context);
200 if (status != PSA_SUCCESS)
201 return status;
202
203 context->initialized = true;
204
205 return PSA_SUCCESS;
206}
207
208void rpmb_frontend_destroy(struct rpmb_frontend *context)
209{
210 *context = (struct rpmb_frontend){ 0 };
211}
212
213psa_status_t rpmb_frontend_block_size(struct rpmb_frontend *context, size_t *block_size)
214{
215 *block_size = RPMB_DATA_SIZE;
216 return PSA_SUCCESS;
217}
218
219psa_status_t rpmb_frontend_block_count(struct rpmb_frontend *context, size_t *block_count)
220{
221 if (!context->initialized)
222 return PSA_ERROR_BAD_STATE;
223
224 *block_count = context->block_count;
225 return PSA_SUCCESS;
226}
227
228psa_status_t rpmb_frontend_write(struct rpmb_frontend *context, uint16_t block_index,
229 const uint8_t *data, size_t block_count)
230{
231 psa_status_t status = PSA_ERROR_GENERIC_ERROR;
232 struct rpmb_data_frame frames[2] = { 0 };
233 uint8_t mac[RPMB_KEY_MAC_SIZE] = { 0 };
234 size_t response_count = 0;
235 uint32_t write_counter = 0;
236 uint16_t op_result = 0;
237 size_t last_block = 0;
238 uint16_t msg_type = 0;
239 uint16_t address = 0;
240 uint16_t i = 0;
241
242 if (!context)
243 return PSA_ERROR_INVALID_ARGUMENT;
244
245 if (!context->initialized)
246 return PSA_ERROR_BAD_STATE;
247
248 /* Validating block range */
249 if (block_index >= context->block_count ||
250 ADD_OVERFLOW(block_index, block_count, &last_block) ||
251 last_block > context->block_count)
252 return PSA_ERROR_INVALID_ARGUMENT;
253
254 if (block_count == 0)
255 return PSA_SUCCESS;
256
257 for (i = 0; i < block_count; i++) {
258 /* Program Data Packet */
259 memset(frames, 0x00, sizeof(frames));
260 memcpy(frames[0].data, &data[i * RPMB_DATA_SIZE], RPMB_DATA_SIZE);
261 u32_to_rpmb_field(context->write_counter, frames[0].write_counter);
262 u16_to_rpmb_field(block_index + i, frames[0].address);
263 u16_to_rpmb_field(1, frames[0].block_count);
264 u16_to_rpmb_field(RPMB_REQ_TYPE_AUTHENTICATED_DATA_WRITE, frames[0].msg_type);
265
266 status = rpmb_calculate_mac(context, frames, 1, frames[0].key_mac);
267 if (status != PSA_SUCCESS)
268 return status;
269
270 /* Result Register Read Request Packet */
271 memset(&frames[1], 0x00, sizeof(frames[1]));
272 u16_to_rpmb_field(RPMB_REQ_TYPE_RESULT_READ_REQUEST, frames[1].msg_type);
273
274 /* Do the request to the backend */
275 response_count = 1;
276 status = rpmb_backend_data_request(context->backend, context->dev_id, frames,
277 ARRAY_SIZE(frames), frames, &response_count);
278 if (status != PSA_SUCCESS)
279 return status;
280
281 if (response_count != 1)
282 return PSA_ERROR_INSUFFICIENT_DATA;
283
284 /* Parse Response for Data Programming Result Request */
285 status = rpmb_calculate_mac(context, &frames[0], 1, mac);
286 if (status != PSA_SUCCESS)
287 return status;
288
289 if (memcmp(frames[0].key_mac, mac, sizeof(mac)) != 0)
290 return PSA_ERROR_INVALID_SIGNATURE;
291
292 write_counter = u32_from_rpmb_field(frames[0].write_counter);
293 if (write_counter != context->write_counter + 1)
294 return PSA_ERROR_INVALID_ARGUMENT;
295
296 address = u16_from_rpmb_field(frames[0].address);
297 if (address != block_index + i)
298 return PSA_ERROR_INVALID_ARGUMENT;
299
300 op_result = u16_from_rpmb_field(frames[0].op_result);
301 if (op_result != RPMB_RES_OK)
302 return PSA_ERROR_INVALID_ARGUMENT;
303
304 msg_type = u16_from_rpmb_field(frames[0].msg_type);
305 if (msg_type != RPMB_RESP_TYPE_AUTHENTICATED_DATA_WRITE)
306 return PSA_ERROR_INVALID_ARGUMENT;
307
308 context->write_counter = write_counter;
309 }
310
311 return PSA_SUCCESS;
312
313}
314
315psa_status_t rpmb_frontend_read(struct rpmb_frontend *context, uint16_t block_index,
316 uint8_t *data, size_t block_count)
317{
318 psa_status_t status = PSA_ERROR_GENERIC_ERROR;
319 uint8_t mac[RPMB_KEY_MAC_SIZE] = { 0 };
320 uint8_t nonce[RPMB_NONCE_SIZE] = { 0 };
321 struct rpmb_data_frame *frames = NULL;
322 size_t response_count = 0;
323 size_t last_block = 0;
324 uint16_t msg_type = 0;
325 uint16_t i = 0;
326
327 if (!context)
328 return PSA_ERROR_INVALID_ARGUMENT;
329
330 if (!context->initialized)
331 return PSA_ERROR_BAD_STATE;
332
333 /* Validating block range */
334 if (block_index >= context->block_count ||
335 ADD_OVERFLOW(block_index, block_count, &last_block) ||
336 last_block > context->block_count)
337 return PSA_ERROR_INVALID_ARGUMENT;
338
339 if (block_count == 0)
340 return PSA_SUCCESS;
341
342 frames = (struct rpmb_data_frame *)calloc(block_count, sizeof(*frames));
343 if (!frames)
344 return PSA_ERROR_INSUFFICIENT_MEMORY;
345
346 /* Data Read Request Initiation Packet */
347 status = rpmb_get_nonce(context, nonce, sizeof(nonce));
348 if (status != PSA_SUCCESS)
349 goto err;
350
351 memcpy(frames[0].nonce, nonce, sizeof(frames[0].nonce));
352 u16_to_rpmb_field(block_index, frames[0].address);
353 u16_to_rpmb_field(block_count, frames[0].block_count);
354 u16_to_rpmb_field(RPMB_REQ_TYPE_AUTHENTICATED_DATA_READ, frames[0].msg_type);
355
356 response_count = block_count;
357 status = rpmb_backend_data_request(context->backend, context->dev_id, frames, 1, frames,
358 &response_count);
359 if (status != PSA_SUCCESS)
360 goto err;
361
362 if (response_count != block_count) {
363 status = PSA_ERROR_INSUFFICIENT_DATA;
364 goto err;
365 }
366
367 status = rpmb_calculate_mac(context, frames, block_count, mac);
368 if (status != PSA_SUCCESS)
369 goto err;
370
371 if (memcmp(mac, frames[block_count - 1].key_mac, sizeof(mac)) != 0) {
372 status = PSA_ERROR_INVALID_SIGNATURE;
373 goto err;
374 }
375
376 for (i = 0; i < block_count; i++) {
377 /* Parse Read Data Packets */
378 if (memcmp(frames[i].nonce, nonce, sizeof(nonce)) != 0) {
379 status = PSA_ERROR_INVALID_SIGNATURE;
380 goto err;
381 }
382
383 msg_type = u16_from_rpmb_field(frames[i].msg_type);
384 if (u16_from_rpmb_field(frames[i].address) != block_index ||
385 u16_from_rpmb_field(frames[i].block_count) != block_count ||
386 u16_from_rpmb_field(frames[i].op_result) != RPMB_RES_OK ||
387 msg_type != RPMB_RESP_TYPE_AUTHENTICATED_DATA_READ) {
388 status = PSA_ERROR_INVALID_ARGUMENT;
389 goto err;
390 }
391
392 memcpy(&data[i * RPMB_DATA_SIZE], frames[i].data, RPMB_DATA_SIZE);
393 }
394
395err:
396 free(frames);
397 return status;
398}