1 /*
2 * Copyright (C) 2018 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 #include "rpmb_dev.h"
18
19 #include <assert.h>
20 #include <errno.h>
21 #include <lk/compiler.h>
22 #include <openssl/hmac.h>
23 #include <stdio.h>
24 #include <stdlib.h>
25 #include <string.h>
26 #include <sys/types.h>
27 #include <unistd.h>
28
29 /* verbose is an int for getopt */
30 int verbose = false;
31
32 #if OPENSSL_VERSION_NUMBER < 0x10100000L
33
HMAC_CTX_new(void)34 HMAC_CTX* HMAC_CTX_new(void) {
35 HMAC_CTX* ctx = malloc(sizeof(*ctx));
36 if (ctx != NULL) {
37 HMAC_CTX_init(ctx);
38 }
39 return ctx;
40 }
41
HMAC_CTX_free(HMAC_CTX * ctx)42 void HMAC_CTX_free(HMAC_CTX* ctx) {
43 if (ctx != NULL) {
44 HMAC_CTX_cleanup(ctx);
45 free(ctx);
46 }
47 }
48
49 #endif
50
51 /* TODO: move to common location */
rpmb_mac(struct rpmb_key key,struct rpmb_packet * packet,size_t packet_count,struct rpmb_key * mac)52 static int rpmb_mac(struct rpmb_key key,
53 struct rpmb_packet* packet,
54 size_t packet_count,
55 struct rpmb_key* mac) {
56 size_t i;
57 int hmac_ret;
58 unsigned int md_len;
59 HMAC_CTX* hmac_ctx;
60
61 hmac_ctx = HMAC_CTX_new();
62 hmac_ret = HMAC_Init_ex(hmac_ctx, &key, sizeof(key), EVP_sha256(), NULL);
63 if (!hmac_ret) {
64 fprintf(stderr, "HMAC_Init_ex failed\n");
65 goto err;
66 }
67 for (i = 0; i < packet_count; i++) {
68 hmac_ret = HMAC_Update(hmac_ctx, packet[i].data, 284);
69 if (!hmac_ret) {
70 fprintf(stderr, "HMAC_Update failed\n");
71 goto err;
72 }
73 }
74 hmac_ret = HMAC_Final(hmac_ctx, mac->byte, &md_len);
75 if (md_len != sizeof(mac->byte)) {
76 fprintf(stderr, "bad md_len %d != %zd\n", md_len, sizeof(mac->byte));
77 exit(1);
78 }
79 if (!hmac_ret) {
80 fprintf(stderr, "HMAC_Final failed\n");
81 goto err;
82 }
83
84 err:
85 HMAC_CTX_free(hmac_ctx);
86 return hmac_ret ? 0 : -1;
87 }
88
rpmb_file_seek(struct rpmb_dev_state * s,uint16_t addr)89 static int rpmb_file_seek(struct rpmb_dev_state* s, uint16_t addr) {
90 int ret;
91 int pos = addr * RPMB_PACKET_DATA_SIZE + sizeof(s->header);
92 ret = lseek(s->data_fd, pos, SEEK_SET);
93 if (ret != pos) {
94 fprintf(stderr, "rpmb_dev: seek to %d failed, got %d\n", pos, ret);
95 return -1;
96 }
97 return 0;
98 }
99
rpmb_dev_program_key(struct rpmb_dev_state * s)100 static uint16_t rpmb_dev_program_key(struct rpmb_dev_state* s) {
101 int ret;
102
103 if (s->header.key_programmed) {
104 return RPMB_RES_WRITE_FAILURE;
105 }
106
107 s->header.key = s->cmd[0].key_mac;
108 s->header.key_programmed = 1;
109
110 ret = lseek(s->data_fd, 0, SEEK_SET);
111 if (ret) {
112 fprintf(stderr, "rpmb_dev: Failed to seek rpmb data file\n");
113 return RPMB_RES_WRITE_FAILURE;
114 }
115
116 ret = write(s->data_fd, &s->header, sizeof(s->header));
117 if (ret != sizeof(s->header)) {
118 fprintf(stderr, "rpmb_dev: Failed to write rpmb key: %d, %s\n", ret,
119 strerror(errno));
120
121 return RPMB_RES_WRITE_FAILURE;
122 }
123
124 return RPMB_RES_OK;
125 }
126
rpmb_dev_get_counter(struct rpmb_dev_state * s)127 static uint16_t rpmb_dev_get_counter(struct rpmb_dev_state* s) {
128 if (s->fail_next_get_counters > 0) {
129 if (verbose) {
130 fprintf(stderr,
131 "rpmb_dev: failing to get RPMB counter as requested by debug state\n");
132 }
133 s->fail_next_get_counters--;
134 return RPMB_RES_COUNT_FAILURE;
135 }
136
137 s->res[0].write_counter = rpmb_u32(s->header.write_counter);
138
139 return RPMB_RES_OK;
140 }
141
rpmb_dev_data_write(struct rpmb_dev_state * s)142 static uint16_t rpmb_dev_data_write(struct rpmb_dev_state* s) {
143 uint16_t addr = rpmb_get_u16(s->cmd[0].address);
144 uint16_t block_count = s->cmd_count;
145 uint32_t write_counter;
146 int ret;
147
148 if (s->fail_next_writes > 0 && !s->commit_failed_writes) {
149 if (verbose) {
150 fprintf(stderr,
151 "rpmb_dev: failing write as requested by debug state\n");
152 }
153 s->fail_next_writes--;
154 return RPMB_RES_WRITE_FAILURE;
155 }
156
157 if (s->header.write_counter == MAX_WRITE_COUNTER) {
158 if (verbose) {
159 fprintf(stderr, "rpmb_dev: Write counter expired\n");
160 }
161 return RPMB_RES_WRITE_FAILURE;
162 }
163
164 write_counter = rpmb_get_u32(s->cmd[0].write_counter);
165 if (s->header.write_counter != write_counter) {
166 if (verbose) {
167 fprintf(stderr,
168 "rpmb_dev: Invalid write counter %u. Expected: %u\n",
169 write_counter, s->header.write_counter);
170 }
171 return RPMB_RES_COUNT_FAILURE;
172 }
173
174 ret = rpmb_file_seek(s, addr);
175 if (ret) {
176 fprintf(stderr, "rpmb_dev: Failed to seek rpmb data file\n");
177 return RPMB_RES_WRITE_FAILURE;
178 }
179
180 for (int i = 0; i < block_count; i++) {
181 ret = write(s->data_fd, s->cmd[i].data, RPMB_PACKET_DATA_SIZE);
182 if (ret != RPMB_PACKET_DATA_SIZE) {
183 fprintf(stderr,
184 "rpmb_dev: Failed to write rpmb data file: %d, %s\n", ret,
185 strerror(errno));
186 return RPMB_RES_WRITE_FAILURE;
187 }
188 }
189
190 s->header.write_counter++;
191
192 if (s->fail_next_writes > 0) {
193 if (verbose) {
194 fprintf(stderr,
195 "rpmb_dev: Failing write after commit as requested by debug state\n");
196 }
197 s->fail_next_writes--;
198 return RPMB_RES_WRITE_FAILURE;
199 }
200
201 ret = lseek(s->data_fd, 0, SEEK_SET);
202 if (ret) {
203 fprintf(stderr, "rpmb_dev: Failed to seek rpmb data file\n");
204 return RPMB_RES_WRITE_FAILURE;
205 }
206
207 ret = write(s->data_fd, &s->header.write_counter,
208 sizeof(s->header.write_counter));
209 if (ret != sizeof(s->header.write_counter)) {
210 fprintf(stderr,
211 "rpmb_dev: Failed to write rpmb write counter: %d, %s\n", ret,
212 strerror(errno));
213
214 return RPMB_RES_WRITE_FAILURE;
215 }
216
217 s->res[0].write_counter = rpmb_u32(s->header.write_counter);
218 return RPMB_RES_OK;
219 }
220
rpmb_dev_data_read(struct rpmb_dev_state * s)221 static uint16_t rpmb_dev_data_read(struct rpmb_dev_state* s) {
222 uint16_t addr;
223 uint16_t block_count;
224 int ret;
225
226 if (s->fail_next_reads > 0) {
227 if (verbose) {
228 fprintf(stderr,
229 "rpmb_dev: failing read as requested by debug state\n");
230 }
231 s->fail_next_reads--;
232 return RPMB_RES_READ_FAILURE;
233 }
234
235 addr = rpmb_get_u16(s->cmd[0].address);
236 block_count = s->res_count;
237
238 rpmb_file_seek(s, addr);
239
240 for (int i = 0; i < block_count; i++) {
241 ret = read(s->data_fd, s->res[i].data, RPMB_PACKET_DATA_SIZE);
242 if (ret != 0 && ret != RPMB_PACKET_DATA_SIZE) {
243 fprintf(stderr, "rpmb_dev: Failed to read rpmb data file: %d, %s\n",
244 ret, strerror(errno));
245 return RPMB_RES_READ_FAILURE;
246 }
247 }
248
249 return RPMB_RES_OK;
250 }
251
252 struct rpmb_dev_cmd {
253 uint16_t (*func)(struct rpmb_dev_state* s);
254 uint16_t resp;
255 bool key_mac_is_key;
256 bool check_mac;
257 bool check_result_read;
258 bool check_key_programmed;
259 bool check_addr;
260 bool multi_packet_cmd;
261 bool multi_packet_res;
262 bool res_mac;
263 };
264
265 static struct rpmb_dev_cmd rpmb_dev_cmd_table[] = {
266 [RPMB_REQ_PROGRAM_KEY] =
267 {
268 .func = rpmb_dev_program_key,
269 .resp = RPMB_RESP_PROGRAM_KEY,
270 .key_mac_is_key = true,
271 .check_result_read = true,
272 },
273 [RPMB_REQ_GET_COUNTER] =
274 {
275 .func = rpmb_dev_get_counter,
276 .resp = RPMB_RESP_GET_COUNTER,
277 .check_key_programmed = true,
278 .res_mac = true,
279 },
280 [RPMB_REQ_DATA_WRITE] =
281 {
282 .func = rpmb_dev_data_write,
283 .resp = RPMB_RESP_DATA_WRITE,
284 .check_mac = true,
285 .check_result_read = true,
286 .check_key_programmed = true,
287 .check_addr = true,
288 .multi_packet_cmd = true,
289 .res_mac = true,
290 },
291 [RPMB_REQ_DATA_READ] =
292 {
293 .func = rpmb_dev_data_read,
294 .resp = RPMB_RESP_DATA_READ,
295 .check_key_programmed = true,
296 .check_addr = true,
297 .multi_packet_res = true,
298 .res_mac = true,
299 },
300 };
301
rpmb_dev_process_cmd(struct rpmb_dev_state * s)302 void rpmb_dev_process_cmd(struct rpmb_dev_state* s) {
303 assert(s->cmd_count > 0);
304 assert(s->res_count > 0);
305 uint16_t req_resp = rpmb_get_u16(s->cmd[0].req_resp);
306 uint16_t addr = rpmb_get_u16(s->cmd[0].address);
307 uint16_t sub_req;
308 uint16_t cmd_index = req_resp < countof(rpmb_dev_cmd_table) ? req_resp : 0;
309 struct rpmb_dev_cmd* cmd = &rpmb_dev_cmd_table[cmd_index];
310 uint16_t result = RPMB_RES_GENERAL_FAILURE;
311 struct rpmb_key mac;
312 uint16_t block_count = 0;
313
314 if (cmd->check_result_read) {
315 sub_req = rpmb_get_u16(s->cmd[s->cmd_count - 1].req_resp);
316 if (sub_req != RPMB_REQ_RESULT_READ) {
317 if (verbose) {
318 fprintf(stderr,
319 "rpmb_dev: Request %d, missing result read request, got %d, cmd_count %d\n",
320 req_resp, sub_req, s->cmd_count);
321 }
322 goto err;
323 }
324 assert(s->cmd_count > 1);
325 s->cmd_count--;
326 }
327
328 if (cmd->check_mac) {
329 if (rpmb_mac(s->header.key, s->cmd, s->cmd_count, &mac) != 0) {
330 fprintf(stderr, "rpmb_dev: failed to caclulate mac\n");
331 goto err;
332 }
333 } else if (cmd->key_mac_is_key) {
334 mac = s->cmd[s->cmd_count - 1].key_mac;
335 } else {
336 memset(mac.byte, 0, sizeof(mac.byte));
337 }
338
339 if (memcmp(&mac, s->cmd[s->cmd_count - 1].key_mac.byte, sizeof(mac))) {
340 if (verbose) {
341 fprintf(stderr, "rpmb_dev: Request %d, invalid MAC, cmd_count %d\n",
342 req_resp, s->cmd_count);
343 }
344 if (cmd->check_mac) {
345 result = RPMB_RES_AUTH_FAILURE;
346 }
347 goto err;
348 }
349
350 if (cmd->multi_packet_cmd) {
351 block_count = s->cmd_count;
352 }
353 if (cmd->multi_packet_res) {
354 block_count = s->res_count;
355 }
356
357 if (cmd->check_addr && (addr + block_count > s->header.max_block + 1)) {
358 if (verbose) {
359 fprintf(stderr,
360 "rpmb_dev: Request %d, invalid addr: 0x%x count 0x%x, Out of bounds. Max addr 0x%x\n",
361 req_resp, addr, block_count, s->header.max_block + 1);
362 }
363 result = RPMB_RES_ADDR_FAILURE;
364 goto err;
365 }
366 if (!cmd->check_addr && addr) {
367 if (verbose) {
368 fprintf(stderr, "rpmb_dev: Request %d, invalid addr: 0x%x != 0\n",
369 req_resp, addr);
370 }
371 goto err;
372 }
373
374 for (int i = 1; i < s->cmd_count; i++) {
375 sub_req = rpmb_get_u16(s->cmd[i].req_resp);
376 if (sub_req != req_resp) {
377 if (verbose) {
378 fprintf(stderr,
379 "rpmb_dev: Request %d, sub-request mismatch, %d, at %d\n",
380 req_resp, i, sub_req);
381 }
382 goto err;
383 }
384 }
385 if (!cmd->multi_packet_cmd && s->cmd_count != 1) {
386 if (verbose) {
387 fprintf(stderr,
388 "rpmb_dev: Request %d, bad cmd count %d, expected 1\n",
389 req_resp, s->cmd_count);
390 }
391 goto err;
392 }
393 if (!cmd->multi_packet_res && s->res_count != 1) {
394 if (verbose) {
395 fprintf(stderr,
396 "rpmb_dev: Request %d, bad res count %d, expected 1\n",
397 req_resp, s->res_count);
398 }
399 goto err;
400 }
401
402 if (cmd->check_key_programmed && !s->header.key_programmed) {
403 if (verbose) {
404 fprintf(stderr, "rpmb_dev: Request %d, key is not programmed\n",
405 req_resp);
406 }
407 s->res[0].result = rpmb_u16(RPMB_RES_NO_AUTH_KEY);
408 return;
409 }
410
411 if (!cmd->func) {
412 if (verbose) {
413 fprintf(stderr, "rpmb_dev: Unsupported request: %d\n", req_resp);
414 }
415 goto err;
416 }
417
418 result = cmd->func(s);
419
420 err:
421 if (s->header.write_counter == MAX_WRITE_COUNTER) {
422 result |= RPMB_RES_WRITE_COUNTER_EXPIRED;
423 }
424
425 for (int i = 0; i < s->res_count; i++) {
426 s->res[i].nonce = s->cmd[0].nonce;
427 s->res[i].address = rpmb_u16(addr);
428 s->res[i].block_count = rpmb_u16(block_count);
429 s->res[i].result = rpmb_u16(result);
430 s->res[i].req_resp = rpmb_u16(cmd->resp);
431 }
432 if (cmd->res_mac) {
433 rpmb_mac(s->header.key, s->res, s->res_count,
434 &s->res[s->res_count - 1].key_mac);
435 }
436 }
437