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