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 #define LOG_TAG "rpmb_mock"
18
19 #include "rpmb_protocol.h"
20
21 #include <assert.h>
22 #include <cutils/sockets.h>
23 #include <errno.h>
24 #include <fcntl.h>
25 #include <getopt.h>
26 #include <log/log.h>
27 #include <openssl/hmac.h>
28 #include <stdio.h>
29 #include <stdlib.h>
30 #include <string.h>
31 #include <sys/socket.h>
32 #include <sys/stat.h>
33 #include <sys/types.h>
34 #include <sys/un.h>
35 #include <unistd.h>
36
37 /* verbose is an int for getopt */
38 static int verbose = false;
39
40 #if OPENSSL_VERSION_NUMBER < 0x10100000L
41
HMAC_CTX_new(void)42 HMAC_CTX* HMAC_CTX_new(void) {
43 HMAC_CTX* ctx = malloc(sizeof(*ctx));
44 if (ctx != NULL) {
45 HMAC_CTX_init(ctx);
46 }
47 return ctx;
48 }
49
HMAC_CTX_free(HMAC_CTX * ctx)50 void HMAC_CTX_free(HMAC_CTX* ctx) {
51 if (ctx != NULL) {
52 HMAC_CTX_cleanup(ctx);
53 free(ctx);
54 }
55 }
56
57 #endif
58
59 #define MAX_WRITE_COUNTER (0xffffffff)
60
61 struct rpmb_data_header {
62 uint32_t write_counter;
63 uint16_t max_block;
64 uint8_t pad1;
65 uint8_t key_programmed;
66 struct rpmb_key key;
67 uint8_t pad[512 - 4 - 2 - 1 - 1 - sizeof(struct rpmb_key)];
68 };
69
70 #define MAX_PACKET_COUNT (8)
71
72 struct rpmb_dev_state {
73 struct rpmb_data_header header;
74 struct rpmb_packet cmd[MAX_PACKET_COUNT];
75 struct rpmb_packet res[MAX_PACKET_COUNT];
76 uint16_t cmd_count;
77 uint16_t res_count;
78 int data_fd;
79 };
80
81 /* TODO: move to common location */
rpmb_mac(struct rpmb_key key,struct rpmb_packet * packet,size_t packet_count,struct rpmb_key * mac)82 static int rpmb_mac(struct rpmb_key key, struct rpmb_packet* packet, size_t packet_count,
83 struct rpmb_key* mac) {
84 size_t i;
85 int hmac_ret;
86 unsigned int md_len;
87 HMAC_CTX* hmac_ctx;
88
89 hmac_ctx = HMAC_CTX_new();
90 hmac_ret = HMAC_Init_ex(hmac_ctx, &key, sizeof(key), EVP_sha256(), NULL);
91 if (!hmac_ret) {
92 ALOGE("HMAC_Init_ex failed\n");
93 goto err;
94 }
95 for (i = 0; i < packet_count; i++) {
96 hmac_ret = HMAC_Update(hmac_ctx, packet[i].data, 284);
97 if (!hmac_ret) {
98 ALOGE("HMAC_Update failed\n");
99 goto err;
100 }
101 }
102 hmac_ret = HMAC_Final(hmac_ctx, mac->byte, &md_len);
103 if (md_len != sizeof(mac->byte)) {
104 ALOGE("bad md_len %d != %zd\n", md_len, sizeof(mac->byte));
105 exit(1);
106 }
107 if (!hmac_ret) {
108 ALOGE("HMAC_Final failed\n");
109 goto err;
110 }
111
112 err:
113 HMAC_CTX_free(hmac_ctx);
114 return hmac_ret ? 0 : -1;
115 }
116
rpmb_file_seek(struct rpmb_dev_state * s,uint16_t addr)117 static int rpmb_file_seek(struct rpmb_dev_state* s, uint16_t addr) {
118 int ret;
119 int pos = addr * RPMB_PACKET_DATA_SIZE + sizeof(s->header);
120 ret = lseek(s->data_fd, pos, SEEK_SET);
121 if (ret != pos) {
122 ALOGE("rpmb_dev: seek to %d failed, got %d\n", pos, ret);
123 return -1;
124 }
125 return 0;
126 }
127
rpmb_dev_program_key(struct rpmb_dev_state * s)128 static uint16_t rpmb_dev_program_key(struct rpmb_dev_state* s) {
129 int ret;
130
131 if (s->header.key_programmed) {
132 return RPMB_RES_WRITE_FAILURE;
133 }
134
135 s->header.key = s->cmd[0].key_mac;
136 s->header.key_programmed = 1;
137
138 ret = lseek(s->data_fd, 0, SEEK_SET);
139 if (ret) {
140 ALOGE("rpmb_dev: Failed to seek rpmb data file\n");
141 return RPMB_RES_WRITE_FAILURE;
142 }
143
144 ret = write(s->data_fd, &s->header, sizeof(s->header));
145 if (ret != sizeof(s->header)) {
146 ALOGE("rpmb_dev: Failed to write rpmb key: %d, %s\n", ret, strerror(errno));
147
148 return RPMB_RES_WRITE_FAILURE;
149 }
150
151 return RPMB_RES_OK;
152 }
153
rpmb_dev_get_counter(struct rpmb_dev_state * s)154 static uint16_t rpmb_dev_get_counter(struct rpmb_dev_state* s) {
155 s->res[0].write_counter = rpmb_u32(s->header.write_counter);
156
157 return RPMB_RES_OK;
158 }
159
rpmb_dev_data_write(struct rpmb_dev_state * s)160 static uint16_t rpmb_dev_data_write(struct rpmb_dev_state* s) {
161 uint16_t addr = rpmb_get_u16(s->cmd[0].address);
162 uint16_t block_count = s->cmd_count;
163 uint32_t write_counter;
164 int ret;
165
166 if (s->header.write_counter == MAX_WRITE_COUNTER) {
167 if (verbose) {
168 ALOGE("rpmb_dev: Write counter expired\n");
169 }
170 return RPMB_RES_WRITE_FAILURE;
171 }
172
173 write_counter = rpmb_get_u32(s->cmd[0].write_counter);
174 if (s->header.write_counter != write_counter) {
175 if (verbose) {
176 ALOGE("rpmb_dev: Invalid write counter %u. Expected: %u\n", write_counter,
177 s->header.write_counter);
178 }
179 return RPMB_RES_COUNT_FAILURE;
180 }
181
182 ret = rpmb_file_seek(s, addr);
183 if (ret) {
184 ALOGE("rpmb_dev: Failed to seek rpmb data file\n");
185 return RPMB_RES_WRITE_FAILURE;
186 }
187
188 for (int i = 0; i < block_count; i++) {
189 ret = write(s->data_fd, s->cmd[i].data, RPMB_PACKET_DATA_SIZE);
190 if (ret != RPMB_PACKET_DATA_SIZE) {
191 ALOGE("rpmb_dev: Failed to write rpmb data file: %d, %s\n", ret, strerror(errno));
192 return RPMB_RES_WRITE_FAILURE;
193 }
194 }
195
196 s->header.write_counter++;
197
198 ret = lseek(s->data_fd, 0, SEEK_SET);
199 if (ret) {
200 ALOGE("rpmb_dev: Failed to seek rpmb data file\n");
201 return RPMB_RES_WRITE_FAILURE;
202 }
203
204 ret = write(s->data_fd, &s->header.write_counter, sizeof(s->header.write_counter));
205 if (ret != sizeof(s->header.write_counter)) {
206 ALOGE("rpmb_dev: Failed to write rpmb write counter: %d, %s\n", ret, strerror(errno));
207
208 return RPMB_RES_WRITE_FAILURE;
209 }
210
211 s->res[0].write_counter = rpmb_u32(s->header.write_counter);
212 return RPMB_RES_OK;
213 }
214
rpmb_dev_data_read(struct rpmb_dev_state * s)215 static uint16_t rpmb_dev_data_read(struct rpmb_dev_state* s) {
216 uint16_t addr;
217 uint16_t block_count;
218 int ret;
219
220 addr = rpmb_get_u16(s->cmd[0].address);
221 block_count = s->res_count;
222
223 rpmb_file_seek(s, addr);
224
225 for (int i = 0; i < block_count; i++) {
226 ret = read(s->data_fd, s->res[i].data, RPMB_PACKET_DATA_SIZE);
227 if (ret != 0 && ret != RPMB_PACKET_DATA_SIZE) {
228 ALOGE("rpmb_dev: Failed to read rpmb data file: %d, %s\n", ret, strerror(errno));
229 return RPMB_RES_READ_FAILURE;
230 }
231 }
232
233 return RPMB_RES_OK;
234 }
235
236 struct rpmb_dev_cmd {
237 uint16_t (*func)(struct rpmb_dev_state* s);
238 uint16_t resp;
239 bool key_mac_is_key;
240 bool check_mac;
241 bool check_result_read;
242 bool check_key_programmed;
243 bool check_addr;
244 bool multi_packet_cmd;
245 bool multi_packet_res;
246 bool res_mac;
247 };
248
249 static struct rpmb_dev_cmd rpmb_dev_cmd_table[] = {
250 [RPMB_REQ_PROGRAM_KEY] =
251 {
252 .func = rpmb_dev_program_key,
253 .resp = RPMB_RESP_PROGRAM_KEY,
254 .key_mac_is_key = true,
255 .check_result_read = true,
256 },
257 [RPMB_REQ_GET_COUNTER] =
258 {
259 .func = rpmb_dev_get_counter,
260 .resp = RPMB_RESP_GET_COUNTER,
261 .check_key_programmed = true,
262 .res_mac = true,
263 },
264 [RPMB_REQ_DATA_WRITE] =
265 {
266 .func = rpmb_dev_data_write,
267 .resp = RPMB_RESP_DATA_WRITE,
268 .check_mac = true,
269 .check_result_read = true,
270 .check_key_programmed = true,
271 .check_addr = true,
272 .multi_packet_cmd = true,
273 .res_mac = true,
274 },
275 [RPMB_REQ_DATA_READ] =
276 {
277 .func = rpmb_dev_data_read,
278 .resp = RPMB_RESP_DATA_READ,
279 .check_key_programmed = true,
280 .check_addr = true,
281 .multi_packet_res = true,
282 .res_mac = true,
283 },
284 };
285
286 #define countof(arr) (sizeof(arr) / sizeof(arr[0]))
287
rpmb_dev_process_cmd(struct rpmb_dev_state * s)288 static void rpmb_dev_process_cmd(struct rpmb_dev_state* s) {
289 assert(s->cmd_count > 0);
290 assert(s->res_count > 0);
291 uint16_t req_resp = rpmb_get_u16(s->cmd[0].req_resp);
292 uint16_t addr = rpmb_get_u16(s->cmd[0].address);
293 uint16_t sub_req;
294 uint16_t cmd_index = req_resp < countof(rpmb_dev_cmd_table) ? req_resp : 0;
295 struct rpmb_dev_cmd* cmd = &rpmb_dev_cmd_table[cmd_index];
296 uint16_t result = RPMB_RES_GENERAL_FAILURE;
297 struct rpmb_key mac;
298 uint16_t block_count = 0;
299
300 if (cmd->check_result_read) {
301 sub_req = rpmb_get_u16(s->cmd[s->cmd_count - 1].req_resp);
302 if (sub_req != RPMB_REQ_RESULT_READ) {
303 if (verbose) {
304 ALOGE("rpmb_dev: Request %d, missing result read request, got %d, cmd_count %d\n",
305 req_resp, sub_req, s->cmd_count);
306 }
307 goto err;
308 }
309 assert(s->cmd_count > 1);
310 s->cmd_count--;
311 }
312
313 if (cmd->check_mac) {
314 if (rpmb_mac(s->header.key, s->cmd, s->cmd_count, &mac) != 0) {
315 ALOGE("rpmb_dev: failed to caclulate mac\n");
316 goto err;
317 }
318 } else if (cmd->key_mac_is_key) {
319 mac = s->cmd[s->cmd_count - 1].key_mac;
320 } else {
321 memset(mac.byte, 0, sizeof(mac.byte));
322 }
323
324 if (memcmp(&mac, s->cmd[s->cmd_count - 1].key_mac.byte, sizeof(mac))) {
325 if (verbose) {
326 ALOGE("rpmb_dev: Request %d, invalid MAC, cmd_count %d\n", req_resp, s->cmd_count);
327 }
328 if (cmd->check_mac) {
329 result = RPMB_RES_AUTH_FAILURE;
330 }
331 goto err;
332 }
333
334 if (cmd->multi_packet_cmd) {
335 block_count = s->cmd_count;
336 }
337 if (cmd->multi_packet_res) {
338 block_count = s->res_count;
339 }
340
341 if (cmd->check_addr && (addr + block_count > s->header.max_block + 1)) {
342 if (verbose) {
343 ALOGE("rpmb_dev: Request %d, invalid addr: 0x%x count 0x%x, Out of bounds. Max addr "
344 "0x%x\n",
345 req_resp, addr, block_count, s->header.max_block + 1);
346 }
347 result = RPMB_RES_ADDR_FAILURE;
348 goto err;
349 }
350 if (!cmd->check_addr && addr) {
351 if (verbose) {
352 ALOGE("rpmb_dev: Request %d, invalid addr: 0x%x != 0\n", req_resp, addr);
353 }
354 goto err;
355 }
356
357 for (int i = 1; i < s->cmd_count; i++) {
358 sub_req = rpmb_get_u16(s->cmd[i].req_resp);
359 if (sub_req != req_resp) {
360 if (verbose) {
361 ALOGE("rpmb_dev: Request %d, sub-request mismatch, %d, at %d\n", req_resp, i,
362 sub_req);
363 }
364 goto err;
365 }
366 }
367 if (!cmd->multi_packet_cmd && s->cmd_count != 1) {
368 if (verbose) {
369 ALOGE("rpmb_dev: Request %d, bad cmd count %d, expected 1\n", req_resp, s->cmd_count);
370 }
371 goto err;
372 }
373 if (!cmd->multi_packet_res && s->res_count != 1) {
374 if (verbose) {
375 ALOGE("rpmb_dev: Request %d, bad res count %d, expected 1\n", req_resp, s->res_count);
376 }
377 goto err;
378 }
379
380 if (cmd->check_key_programmed && !s->header.key_programmed) {
381 if (verbose) {
382 ALOGE("rpmb_dev: Request %d, key is not programmed\n", req_resp);
383 }
384 s->res[0].result = rpmb_u16(RPMB_RES_NO_AUTH_KEY);
385 return;
386 }
387
388 if (!cmd->func) {
389 if (verbose) {
390 ALOGE("rpmb_dev: Unsupported request: %d\n", req_resp);
391 }
392 goto err;
393 }
394
395 result = cmd->func(s);
396
397 err:
398 if (s->header.write_counter == MAX_WRITE_COUNTER) {
399 result |= RPMB_RES_WRITE_COUNTER_EXPIRED;
400 }
401
402 for (int i = 0; i < s->res_count; i++) {
403 s->res[i].nonce = s->cmd[0].nonce;
404 s->res[i].address = rpmb_u16(addr);
405 s->res[i].block_count = rpmb_u16(block_count);
406 s->res[i].result = rpmb_u16(result);
407 s->res[i].req_resp = rpmb_u16(cmd->resp);
408 }
409 if (cmd->res_mac) {
410 rpmb_mac(s->header.key, s->res, s->res_count, &s->res[s->res_count - 1].key_mac);
411 }
412 }
413
414 /*
415 * Receives data until one of the following is true:
416 * - The buffer is full (return will be len)
417 * - The connection closed (return > 0, < len)
418 * - An error occurred (return will be the negative error code from recv)
419 */
recv_until(int sock,void * dest_in,size_t len)420 ssize_t recv_until(int sock, void* dest_in, size_t len) {
421 size_t bytes_recvd = 0;
422 char* dest = dest_in;
423 while (bytes_recvd < len) {
424 ssize_t ret = recv(sock, dest, len - bytes_recvd, 0);
425 if (ret < 0) {
426 return ret;
427 }
428 dest += ret;
429 bytes_recvd += ret;
430 if (ret == 0) {
431 break;
432 }
433 }
434 return bytes_recvd;
435 }
436
437 /*
438 * Handles an incoming connection to the rpmb daemon.
439 * Returns 0 if the client disconnects without violating the protocol.
440 * Returns a negative value if we terminated the connection abnormally.
441 *
442 * Arguments:
443 * conn_sock - an fd to send/recv on
444 * s - an initialized rpmb device
445 */
handle_conn(struct rpmb_dev_state * s,int conn_sock)446 int handle_conn(struct rpmb_dev_state* s, int conn_sock) {
447 int ret;
448
449 while (true) {
450 memset(s->res, 0, sizeof(s->res));
451 ret = recv_until(conn_sock, &s->res_count, sizeof(s->res_count));
452
453 /*
454 * Disconnected while not in the middle of anything.
455 */
456 if (ret <= 0) {
457 return 0;
458 }
459
460 if (s->res_count > MAX_PACKET_COUNT) {
461 ALOGE("rpmb_dev: Receive count too large: %d\n", s->res_count);
462 return -1;
463 }
464 if (s->res_count <= 0) {
465 ALOGE("rpmb_dev: Receive count too small: %d\n", s->res_count);
466 return -1;
467 }
468
469 ret = recv_until(conn_sock, &s->cmd_count, sizeof(s->cmd_count));
470 if (ret != sizeof(s->cmd_count)) {
471 ALOGE("rpmb_dev: Failed to read cmd_count");
472 return -1;
473 }
474
475 if (s->cmd_count == 0) {
476 ALOGE("rpmb_dev: Must contain at least one command\n");
477 return -1;
478 }
479
480 if (s->cmd_count > MAX_PACKET_COUNT) {
481 ALOGE("rpmb_dev: Command count is too large\n");
482 return -1;
483 }
484
485 size_t cmd_size = s->cmd_count * sizeof(s->cmd[0]);
486 ret = recv_until(conn_sock, s->cmd, cmd_size);
487 if (ret != (int)cmd_size) {
488 ALOGE("rpmb_dev: Failed to read command: "
489 "cmd_size: %zu ret: %d, %s\n",
490 cmd_size, ret, strerror(errno));
491 return -1;
492 }
493
494 rpmb_dev_process_cmd(s);
495
496 size_t resp_size = sizeof(s->res[0]) * s->res_count;
497 ret = send(conn_sock, s->res, resp_size, 0);
498 if (ret != (int)resp_size) {
499 ALOGE("rpmb_dev: Failed to send response: %d, %s\n", ret, strerror(errno));
500 return -1;
501 }
502 }
503 }
504
usage(const char * argv0)505 void usage(const char* argv0) {
506 fprintf(stderr, "Usage: %s [-d|--dev] <datafile> [--sock] <socket_path>\n", argv0);
507 fprintf(stderr, "or: %s [-d|--dev] <datafile> [--size <size>] [--key key]\n", argv0);
508 }
509
main(int argc,char ** argv)510 int main(int argc, char** argv) {
511 struct rpmb_dev_state s;
512 int ret;
513 int cmdres_sock;
514 struct sockaddr_un cmdres_sockaddr;
515 const char* data_file_name = NULL;
516 const char* socket_path = NULL;
517 int open_flags;
518 int init = false;
519
520 struct option long_options[] = {{"size", required_argument, 0, 0},
521 {"key", required_argument, 0, 0},
522 {"sock", required_argument, 0, 0},
523 {"dev", required_argument, 0, 'd'},
524 {"init", no_argument, &init, true},
525 {"verbose", no_argument, &verbose, true},
526 {0, 0, 0, 0}};
527
528 memset(&s.header, 0, sizeof(s.header));
529
530 while (1) {
531 int c;
532 int option_index = 0;
533 c = getopt_long(argc, argv, "d:", long_options, &option_index);
534 if (c == -1) {
535 break;
536 }
537
538 switch (c) {
539 /* long args */
540 case 0:
541 switch (option_index) {
542 /* size */
543 case 0:
544 s.header.max_block = atoi(optarg) - 1;
545 break;
546 /* key */
547 case 1:
548 for (size_t i = 0; i < sizeof(s.header.key.byte); i++) {
549 if (!optarg) {
550 break;
551 }
552 s.header.key.byte[i] = strtol(optarg, &optarg, 16);
553 s.header.key_programmed = 1;
554 }
555 break;
556 /* sock */
557 case 2:
558 socket_path = optarg;
559 break;
560 }
561 break;
562 /* dev */
563 case 'd':
564 data_file_name = optarg;
565 break;
566 default:
567 usage(argv[0]);
568 return EXIT_FAILURE;
569 }
570 }
571
572 /*
573 * We always need a data file, and at exactly one of --init or --sock
574 * must be specified.
575 */
576 if (!data_file_name || (!init == !socket_path)) {
577 usage(argv[0]);
578 return EXIT_FAILURE;
579 }
580
581 /*
582 * If the file is already initialized, exit early.
583 */
584 if (init && !access(data_file_name, F_OK)) {
585 return EXIT_SUCCESS;
586 }
587
588 open_flags = O_RDWR | O_SYNC;
589 if (init) {
590 open_flags |= O_CREAT | O_TRUNC;
591 }
592 s.data_fd = open(data_file_name, open_flags, S_IWUSR | S_IRUSR);
593 if (s.data_fd < 0) {
594 ALOGE("rpmb_dev: Failed to open rpmb data file, %s: %s\n", data_file_name, strerror(errno));
595 return EXIT_FAILURE;
596 }
597
598 if (init) {
599 /* Create new rpmb data file */
600 if (s.header.max_block == 0) {
601 s.header.max_block = 512 - 1;
602 }
603 ret = write(s.data_fd, &s.header, sizeof(s.header));
604 if (ret != sizeof(s.header)) {
605 ALOGE("rpmb_dev: Failed to write rpmb data file: %d, %s\n", ret, strerror(errno));
606 return EXIT_FAILURE;
607 }
608 return EXIT_SUCCESS;
609 }
610
611 ret = read(s.data_fd, &s.header, sizeof(s.header));
612 if (ret != sizeof(s.header)) {
613 ALOGE("rpmb_dev: Failed to read rpmb data file: %d, %s\n", ret, strerror(errno));
614 return EXIT_FAILURE;
615 }
616
617 cmdres_sock = android_get_control_socket(socket_path);
618 if (cmdres_sock < 0) {
619 ALOGW("android_get_control_socket(%s) failed, fall back to create it\n", socket_path);
620 cmdres_sock = socket(AF_UNIX, SOCK_STREAM, 0);
621 if (cmdres_sock < 0) {
622 ALOGE("rpmb_dev: Failed to create command/response socket: %s\n", strerror(errno));
623 return EXIT_FAILURE;
624 }
625
626 cmdres_sockaddr.sun_family = AF_UNIX;
627 strncpy(cmdres_sockaddr.sun_path, socket_path, sizeof(cmdres_sockaddr.sun_path));
628
629 ret = bind(cmdres_sock, (struct sockaddr*)&cmdres_sockaddr, sizeof(struct sockaddr_un));
630 if (ret < 0) {
631 ALOGE("rpmb_dev: Failed to bind command/response socket: %s: %s\n", socket_path,
632 strerror(errno));
633 return EXIT_FAILURE;
634 }
635 }
636
637 ret = listen(cmdres_sock, 1);
638 if (ret < 0) {
639 ALOGE("rpmb_dev: Failed to listen on command/response socket: %s\n", strerror(errno));
640 return EXIT_FAILURE;
641 }
642
643 while (true) {
644 int conn_sock = accept(cmdres_sock, NULL, NULL);
645 if (conn_sock < 0) {
646 ALOGE("rpmb_dev: Could not accept connection: %s\n", strerror(errno));
647 return EXIT_FAILURE;
648 }
649 ret = handle_conn(&s, conn_sock);
650 close(conn_sock);
651 if (ret) {
652 ALOGE("rpmb_dev: Connection terminated: %d", ret);
653 }
654 }
655 }
656