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