1 /*
2  * Copyright (C) 2017 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  * Commandline tool for interfacing with the Boot Storage app.
17  */
18 
19 #include <ctype.h>
20 #include <inttypes.h>
21 #include <stdio.h>
22 #include <stdint.h>
23 #include <unistd.h>
24 
25 #include <string>
26 #include <vector>
27 
28 #include <cutils/properties.h>
29 #include <ese/ese.h>
30 ESE_INCLUDE_HW(ESE_HW_NXP_PN80T_NQ_NCI);
31 
32 #include "include/ese/app/boot.h"
33 
usage(const char * prog)34 void usage(const char *prog) {
35   fprintf(stderr,
36     "Usage:\n"
37     "%s <cmd> <args>\n"
38     "    state    get\n"
39     "    production set {true,false}\n"
40     "    rollback set <іndex> <value>\n"
41     "             get <іndex>\n"
42     "    lock get {carrier,device,boot,owner}\n"
43     "         set carrier 0 <unlockToken>\n"
44     "                     <nonzero byte> {IMEI,MEID}\n"
45     "             device <byte>\n"
46     "             boot <byte>\n"
47     "             owner 0\n"
48     "             owner <non-zero byte> <keyValue>\n"
49     "         reset\n"
50     "    verify-key test <blob>\n"
51     "    verify-key auto\n"
52     "\n"
53     "Note, any non-zero byte value is considered 'locked'.\n"
54     "\n\n", prog);
55 }
56 
57 #define handle_error(ese, result) ;
58 #if 0  // TODO
59 void handle_error(struct EseInterface *ese, EseAppResult result) {
60    show how to handle different errors, like cooldown before use or after.
61 }
62 #endif
63 
print_hexdump(const uint8_t * data,int start,int stop)64 static void print_hexdump(const uint8_t* data, int start, int stop) {
65   for (int i = start; i < stop; ++i) {
66     if (i % 20 == start - 1) {
67       printf("\n");
68     }
69     printf("%.2x ", data[i]);
70   }
71   printf("\n");
72 }
73 
hexify(const std::string & input,std::vector<uint8_t> * output)74 static uint16_t hexify(const std::string& input, std::vector<uint8_t> *output) {
75   for (auto it = input.cbegin(); it != input.cend(); ++it) {
76     std::string hex;
77     hex.push_back(*it++);
78     hex.push_back(*it);
79     output->push_back(static_cast<uint8_t>(std::stoi(hex, nullptr, 16)));
80   }
81   return static_cast<uint16_t>(output->size() & 0xffff);
82 }
83 
84 
get_property_helper(const char * key,char * value)85 bool get_property_helper(const char *key, char *value) {
86   if (property_get(key, value, NULL) == 0) {
87     fprintf(stderr, "Property '%s' is empty!\n", key);
88     return false;
89   }
90   return true;
91 }
92 
93 // Serializes the data to a string which is hashed by the applet.
collect_device_data(const std::string & modem_id,std::string * device_data)94 bool collect_device_data(const std::string &modem_id, std::string *device_data) {
95   static const char *kDeviceKeys[] = {
96     "ro.product.brand",
97     "ro.product.device",
98     "ro.build.product",
99     "ro.serialno",
100     "",
101     "ro.product.manufacturer",
102     "ro.product.model",
103     NULL,
104   };
105   bool collect_from_env = getenv("COLLECT_FROM_ENV") != NULL;
106   uint8_t len = 0;
107   const char **key = &kDeviceKeys[0];
108   do {
109     if (strlen(*key) == 0) {
110       len = static_cast<uint8_t>(modem_id.length());
111       device_data->push_back(len);
112       device_data->append(modem_id);
113     } else {
114       char value[PROPERTY_VALUE_MAX];
115       char *value_ptr = &value[0];
116       if (collect_from_env) {
117         // Use the last dotted value.
118         value_ptr = getenv(strrchr(*key, '.') + 1);
119         if (value_ptr == NULL) {
120           fprintf(stderr, "fake property '%s' not in env\n",
121                   strrchr(*key, '.') + 1);
122           return false;
123         }
124       } else if (!get_property_helper(*key, value_ptr)) {
125         return false;
126       }
127       len = static_cast<uint8_t>(strlen(value_ptr));
128       device_data->push_back(len);
129       device_data->append(value_ptr);
130     }
131     if (*++key == NULL) {
132       break;
133     }
134   } while (*key != NULL);
135   return true;
136 }
137 
handle_production(struct EseBootSession * session,std::vector<std::string> & args)138 int handle_production(struct EseBootSession *session, std::vector<std::string> &args) {
139   EseAppResult res;
140   if (args[1] != "set") {
141     fprintf(stderr, "production: unknown command '%s'\n", args[2].c_str());
142     return -1;
143   }
144   if (args.size() < 3) {
145     fprintf(stderr, "production: not enough arguments\n");
146     return -1;
147   }
148   bool prod = false;
149   if (args[2] == "true") {
150     prod = true;
151   } else if (args[2] == "false") {
152     prod = false;
153   } else {
154     fprintf(stderr, "production: must be 'true' or 'false'\n");
155     return -1;
156   }
157   res = ese_boot_set_production(session, prod);
158   if (res == ESE_APP_RESULT_OK) {
159     printf("production mode changed\n");
160     return 0;
161   }
162   fprintf(stderr, "production: failed to change (%.8x)\n", res);
163   return 1;
164 }
165 
handle_state(struct EseBootSession * session,std::vector<std::string> & args)166 int handle_state(struct EseBootSession *session, std::vector<std::string> &args) {
167   EseAppResult res;
168   if (args[1] != "get") {
169     fprintf(stderr, "state: unknown command '%s'\n", args[2].c_str());
170     return -1;
171   }
172   // Read in the hex unlockToken and hope for the best.
173   std::vector<uint8_t> data;
174   data.resize(8192);
175   uint16_t len = static_cast<uint16_t>(data.size());
176   res = ese_boot_get_state(session, data.data(), len);
177   if (res != ESE_APP_RESULT_OK) {
178     fprintf(stderr, "state: failed (%.8x)\n", res);
179     return 1;
180   }
181   // TODO: ese_boot_get_state should guarantee length is safe...
182   len = (data[1] << 8) | (data[2]) + 3;
183   printf("Boot Storage State:\n    ");
184   print_hexdump(data.data(), 3, len);
185   return 0;
186 }
187 
188 static const uint8_t auto_data[] = {
189   // lastNonce
190   0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x40,
191   // deviceData
192   0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42,
193   0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42,
194   0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42,
195   0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42,
196   // Version
197   0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
198   // Nonce
199   0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
200   // Signature
201   0x68, 0x86, 0x9a, 0x16, 0xca, 0x62, 0xea, 0xa9,
202   0x9b, 0xa0, 0x51, 0x03, 0xa6, 0x00, 0x3f, 0xe8,
203   0xf1, 0x43, 0xe6, 0xb7, 0xde, 0x76, 0xfe, 0x21,
204   0x65, 0x87, 0x78, 0xe5, 0x1d, 0x11, 0x6a, 0xe1,
205   0x7b, 0xc6, 0x2e, 0xe2, 0x96, 0x25, 0x48, 0xa7,
206   0x09, 0x43, 0x2c, 0xfd, 0x28, 0xa9, 0x66, 0x8a,
207   0x09, 0xd5, 0x83, 0x3b, 0xde, 0x18, 0x5d, 0xef,
208   0x50, 0x12, 0x8a, 0x8d, 0xfb, 0x2d, 0x46, 0x20,
209   0x69, 0x55, 0x4e, 0x86, 0x63, 0xf6, 0x10, 0xe3,
210   0x59, 0x3f, 0x55, 0x72, 0x18, 0xcb, 0x60, 0x80,
211   0x0d, 0x2e, 0x2f, 0xfc, 0xc2, 0xbf, 0xda, 0x3f,
212   0x4f, 0x2b, 0x6b, 0xf1, 0x5d, 0x28, 0x6b, 0x2b,
213   0x9b, 0x92, 0xf3, 0x4e, 0xf2, 0xb6, 0x23, 0x8e,
214   0x50, 0x64, 0xf6, 0xee, 0xc7, 0x78, 0x6a, 0xe0,
215   0xed, 0xce, 0x2c, 0x1f, 0x0a, 0x47, 0x43, 0x5c,
216   0xe4, 0x69, 0xc5, 0xc1, 0xf9, 0x52, 0x8c, 0xed,
217   0xfd, 0x71, 0x8f, 0x9a, 0xde, 0x62, 0xfc, 0x21,
218   0x07, 0xf9, 0x5f, 0xe1, 0x1e, 0xdc, 0x65, 0x95,
219   0x15, 0xc8, 0xe7, 0xf2, 0xce, 0xa9, 0xd0, 0x55,
220   0xf1, 0x18, 0x89, 0xae, 0xe8, 0x47, 0xd8, 0x8a,
221   0x1f, 0x68, 0xa8, 0x6f, 0x5e, 0x5c, 0xda, 0x3d,
222   0x98, 0xeb, 0x82, 0xf8, 0x1f, 0x7a, 0x43, 0x6d,
223   0x3a, 0x7c, 0x36, 0x76, 0x4f, 0x55, 0xa4, 0x55,
224   0x5f, 0x52, 0x47, 0xa5, 0x71, 0x17, 0x7b, 0x73,
225   0xaa, 0x5c, 0x85, 0x94, 0xb6, 0xe2, 0x37, 0x1f,
226   0x22, 0x29, 0x46, 0x59, 0x20, 0x1f, 0x49, 0x36,
227   0x50, 0xa9, 0x60, 0x5d, 0xeb, 0x99, 0x3f, 0x92,
228   0x31, 0xa0, 0x1d, 0xad, 0xdb, 0xde, 0x40, 0xf6,
229   0xaf, 0x9c, 0x36, 0xe4, 0x0c, 0xf4, 0xcc, 0xaf,
230   0x9f, 0x8b, 0xf9, 0xe6, 0x12, 0x53, 0x4e, 0x58,
231   0xeb, 0x9a, 0x57, 0x08, 0x89, 0xa5, 0x4f, 0x7c,
232   0xb9, 0x78, 0x07, 0x02, 0x17, 0x2c, 0xce, 0xb8,
233 };
234 
handle_verify_key(struct EseBootSession * session,std::vector<std::string> & args)235 int handle_verify_key(struct EseBootSession *session, std::vector<std::string> &args) {
236   EseAppResult res;
237   if (args[1] != "test" && args[1] != "auto") {
238     fprintf(stderr, "verify-key: unknown command '%s'\n", args[2].c_str());
239     return -1;
240   }
241   // Read in the hex unlockToken and hope for the best.
242   std::vector<uint8_t> data;
243   uint16_t len;
244   if (args[1] == "test") {
245     len = hexify(args[2], &data);
246     const uint16_t kExpectedLength = (sizeof(uint64_t) * 2 + sizeof(uint64_t) + 32 + 256);
247     if (len != kExpectedLength) {
248       fprintf(stderr, "verify-key: expected blob of length %hu not %hu\n", kExpectedLength, len);
249       fprintf(stderr, "verify-key: format is as follows (in hex):\n");
250       fprintf(stderr, "[lastNonce:8][deviceData:32][version:8][unlockNonce:8][RSA-SHA256PKCS#1 Signature:256]\n");
251       return 2;
252     }
253   } else {
254     len = sizeof(auto_data);
255     data.assign(&auto_data[0], auto_data + sizeof(auto_data));
256   }
257   printf("verify-key: sending the following test data:\n");
258   print_hexdump(data.data(), 0, data.size());
259   res = ese_boot_carrier_lock_test(session, data.data(), len);
260   if (res == ESE_APP_RESULT_OK) {
261     printf("verified\n");
262     return 0;
263   }
264   printf("failed to verify (%.8x)\n", res);
265   return 1;
266 }
267 
handle_lock_state(struct EseBootSession * session,std::vector<std::string> & args)268 int handle_lock_state(struct EseBootSession *session, std::vector<std::string> &args) {
269   EseAppResult res;
270   EseBootLockId lockId;
271   uint16_t lockMetaLen = 0;
272   uint8_t lockMeta[kEseBootOwnerKeyMax + 1];
273   if (args[1] == "reset") {
274     // No work.
275   } else if (args[2] == "carrier") {
276     lockId = kEseBootLockIdCarrier;
277   } else if (args[2] == "device") {
278     lockId = kEseBootLockIdDevice;
279   } else if (args[2] == "boot") {
280     lockId = kEseBootLockIdBoot;
281   } else if (args[2] == "owner") {
282     lockId = kEseBootLockIdOwner;
283   } else {
284     fprintf(stderr, "lock: unknown lock '%s'\n", args[2].c_str());
285     return 1;
286   }
287 
288   if (args[1] == "get") {
289     uint8_t lockVal = 0;
290     if (lockId == kEseBootLockIdCarrier ||
291         lockId == kEseBootLockIdOwner) {
292       res = ese_boot_lock_xget(session, lockId, lockMeta,
293                                sizeof(lockMeta), &lockMetaLen);
294     } else {
295       res = ese_boot_lock_get(session, lockId, &lockVal);
296     }
297     if (res == ESE_APP_RESULT_OK) {
298       if (lockMetaLen > 0) {
299         lockVal = lockMeta[0];
300       }
301       printf("%.2x\n", lockVal);
302       if (lockMetaLen > 0) {
303         print_hexdump(&lockMeta[1], 0, lockMetaLen - 1);
304       }
305       return 0;
306      }
307     fprintf(stderr, "lock: failed to get '%s' (%.8x)\n", args[2].c_str(), res);
308     handle_error(session->ese, res);
309     return 2;
310   } else if (args[1] == "reset") {
311     res = ese_boot_reset_locks(session);
312     if (res == ESE_APP_RESULT_OK) {
313       printf("done.\n");
314       return 0;
315     } else {
316       fprintf(stderr, "lock: failed to reset (%.8x)\n", res);
317       handle_error(session->ese, res);
318       return 3;
319     }
320   } else if (args[1] == "set") {
321     if (args.size() < 4) {
322       fprintf(stderr, "lock set: not enough arguments supplied\n");
323       return 2;
324     }
325     uint8_t lockVal = static_cast<uint8_t>(std::stoi(args[3], nullptr, 0));
326     if (lockId == kEseBootLockIdCarrier) {
327       res = ESE_APP_RESULT_ERROR_UNCONFIGURED;
328       if (lockVal != 0) {
329         std::string device_data;
330         device_data.push_back(lockVal);
331         if (!collect_device_data(args[4], &device_data)) {
332           fprintf(stderr, "carrier set 1: failed to aggregate device data\n");
333           return 3;
334         }
335         printf("Setting carrier lock with '");
336         for (std::string::iterator it = device_data.begin();
337              it != device_data.end(); ++it) {
338           if (isprint(*it)) {
339             printf("%c", *it);
340           } else {
341             printf("[0x%.2x]", *it);
342           }
343         }
344         printf("'\n");
345         const uint8_t *data = reinterpret_cast<const uint8_t *>(device_data.data());
346         res = ese_boot_lock_xset(session, lockId, data, device_data.length());
347       } else {
348         // Read in the hex unlockToken and hope for the best.
349         std::vector<uint8_t> data;
350         data.push_back(lockVal);
351         uint16_t len = hexify(args[4], &data);
352         if (len == 1) {
353           fprintf(stderr, "lock: carrier unlock requires a token\n");
354           return 5;
355         }
356         printf("Passing an unlockToken of length %d to the eSE\n", len - 1);
357         res = ese_boot_lock_xset(session, lockId, data.data(), len);
358       }
359     } else if (lockId == kEseBootLockIdOwner && lockVal != 0) {
360       std::vector<uint8_t> data;
361       data.push_back(lockVal);
362       uint16_t len = hexify(args[4], &data);
363       res = ese_boot_lock_xset(session, lockId, data.data(), len);
364     } else {
365       res = ese_boot_lock_set(session, lockId, lockVal);
366     }
367     if (res != ESE_APP_RESULT_OK) {
368       fprintf(stderr, "lock: failed to set %s state (%.8x)\n",
369               args[2].c_str(), res);
370       handle_error(session->ese, res);
371       return 4;
372     }
373     return 0;
374   }
375   fprintf(stderr, "lock: invalid command\n");
376   return -1;
377 }
378 
handle_rollback(struct EseBootSession * session,std::vector<std::string> & args)379 int handle_rollback(struct EseBootSession *session, std::vector<std::string> &args) {
380   int index = std::stoi(args[2], nullptr, 0);
381   uint8_t slot = static_cast<uint8_t>(index & 0xff);
382   if (slot > 7) {
383     fprintf(stderr, "rollback: slot must be one of [0-7]\n");
384     return 2;
385   }
386 
387   uint64_t value = 0;
388   if (args.size() > 3) {
389     unsigned long long conv = std::stoull(args[3], nullptr, 0);
390     value = static_cast<uint64_t>(conv);
391   }
392 
393   EseAppResult res;
394   if (args[1] == "get") {
395     res = ese_boot_rollback_index_read(session, slot, &value);
396     if (res != ESE_APP_RESULT_OK) {
397       fprintf(stderr, "rollback: failed to read slot %2x (%.8x)\n",
398               slot, res);
399       handle_error(session->ese, res);
400       return 3;
401     }
402     printf("%" PRIu64 "\n", value);
403     return 0;
404   } else if (args[1] == "set") {
405     res = ese_boot_rollback_index_write(session, slot, value);
406     if (res != ESE_APP_RESULT_OK) {
407       fprintf(stderr, "rollback: failed to write slot %2x (%.8x)\n",
408               slot, res);
409       handle_error(session->ese, res);
410       return 4;
411     }
412     return 0;
413   }
414   fprintf(stderr, "rollback: unknown command '%s'\n", args[1].c_str());
415   return -1;
416 }
417 
handle_args(struct EseBootSession * session,const char * prog,std::vector<std::string> & args)418 int handle_args(struct EseBootSession *session, const char *prog, std::vector<std::string> &args) {
419   if (args[0] == "rollback") {
420     return handle_rollback(session, args);
421   } else if (args[0] == "lock") {
422     return handle_lock_state(session, args);
423   } else if (args[0] == "verify-key") {
424     return handle_verify_key(session, args);
425   } else if (args[0] == "production") {
426     return handle_production(session, args);
427   } else if (args[0] == "state") {
428     return handle_state(session, args);
429   } else {
430     usage(prog);
431     return 1;
432   }
433   return 0;
434 }
435 
main(int argc,char ** argv)436 int main(int argc, char **argv) {
437   if (argc < 3) {
438     usage(argv[0]);
439     return 1;
440   }
441   // TODO(wad): move main to a class so we can just dep inject the hw.
442   struct EseInterface ese = ESE_INITIALIZER(ESE_HW_NXP_PN80T_NQ_NCI);
443   if (ese_open(&ese, nullptr) != 0) {
444     fprintf(stderr, "failed to open device\n");
445     return 2;
446   }
447   EseBootSession session;
448   ese_boot_session_init(&session);
449   EseAppResult res = ese_boot_session_open(&ese, &session);
450   if (res != ESE_APP_RESULT_OK) {
451     fprintf(stderr, "failed to initiate session (%.8x)\n", res);
452     handle_error(ese, res);
453     ese_close(&ese);
454     return 1;
455   }
456   std::vector<std::string> args;
457   args.assign(argv + 1, argv + argc);
458   int ret = handle_args(&session, argv[0], args);
459 
460   res = ese_boot_session_close(&session);
461   if (res != ESE_APP_RESULT_OK) {
462     handle_error(&ese, res);
463   }
464   ese_close(&ese);
465   return ret;
466 }
467