boot.c revision 8055858133dca4e507f7d17b9c931f2547a988af
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
17#include "include/ese/app/boot.h"
18#include "boot_private.h"
19
20const uint8_t kBootStateVersion = 0x1;
21const uint16_t kBootStorageLength = 4096;
22/* Non-static, but visibility=hidden so they can be used in test. */
23const uint8_t kManageChannelOpen[] = {0x00, 0x70, 0x00, 0x00, 0x01};
24const uint32_t kManageChannelOpenLength = (uint32_t)sizeof(kManageChannelOpen);
25const uint8_t kManageChannelClose[] = {0x00, 0x70, 0x80, 0x00, 0x00};
26
27const uint8_t kSelectApplet[] = {0x00, 0xA4, 0x04, 0x00, 0x10, 0xA0, 0x00, 0x00,
28                                 0x04, 0x76, 0x50, 0x49, 0x58, 0x4C, 0x42, 0x4F,
29                                 0x4F, 0x54, 0x00, 0x01, 0x01, 0x00};
30const uint32_t kSelectAppletLength = (uint32_t)sizeof(kSelectApplet);
31// Supported commands.
32const uint8_t kGetState[] = {0x80, 0x00, 0x00, 0x00, 0x00};
33const uint8_t kLoadCmd[] = {0x80, 0x02};
34const uint8_t kStoreCmd[] = {0x80, 0x04};
35const uint8_t kGetLockState[] = {0x80, 0x06, 0x00, 0x00, 0x00};
36const uint8_t kSetLockState[] = {0x80, 0x08, 0x00, 0x00, 0x00};
37const uint8_t kSetProduction[] = {0x80, 0x0a};
38const uint8_t kCarrierLockTest[] = {0x80, 0x0c, 0x00, 0x00};
39const uint8_t kFactoryReset[] = {0x80, 0x0e, 0x00, 0x00};
40const uint8_t kLockReset[] = {0x80, 0x0e, 0x01, 0x00};
41
42EseAppResult check_apdu_status(uint8_t code[2]) {
43  if (code[0] == 0x90 && code[1] == 0x00) {
44    return ESE_APP_RESULT_OK;
45  }
46  if (code[0] == 0x66 && code[1] == 0xA5) {
47    return ESE_APP_RESULT_ERROR_COOLDOWN;
48  }
49  if (code[0] == 0x6A && code[1] == 0x83) {
50    return ESE_APP_RESULT_ERROR_UNCONFIGURED;
51  }
52  /* TODO(wad) Bubble up the error code if needed. */
53  ALOGE("unhandled response %.2x %.2x", code[0], code[1]);
54  return ese_make_os_result(code[0], code[1]);
55}
56
57ESE_API void ese_boot_session_init(struct EseBootSession *session) {
58  session->ese = NULL;
59  session->active = false;
60  session->channel_id = 0;
61}
62
63ESE_API EseAppResult ese_boot_session_open(struct EseInterface *ese,
64                                           struct EseBootSession *session) {
65  struct EseSgBuffer tx[2];
66  struct EseSgBuffer rx;
67  uint8_t rx_buf[32];
68  int rx_len;
69  if (!ese || !session) {
70    ALOGE("Invalid |ese| or |session|");
71    return ESE_APP_RESULT_ERROR_ARGUMENTS;
72  }
73  if (session->active == true) {
74    ALOGE("|session| is already active");
75    return ESE_APP_RESULT_ERROR_ARGUMENTS;
76  }
77  /* Instantiate a logical channel */
78  rx_len = ese_transceive(ese, kManageChannelOpen, sizeof(kManageChannelOpen),
79                          rx_buf, sizeof(rx_buf));
80  if (ese_error(ese)) {
81    ALOGE("transceive error: code:%d message:'%s'", ese_error_code(ese),
82          ese_error_message(ese));
83    return ESE_APP_RESULT_ERROR_COMM_FAILED;
84  }
85  if (rx_len < 0) {
86    ALOGE("transceive error: rx_len: %d", rx_len);
87    return ESE_APP_RESULT_ERROR_COMM_FAILED;
88  }
89  if (rx_len < 2) {
90    ALOGE("transceive error: reply too short");
91    return ESE_APP_RESULT_ERROR_COMM_FAILED;
92  }
93  EseAppResult ret;
94  ret = check_apdu_status(&rx_buf[rx_len - 2]);
95  if (ret != ESE_APP_RESULT_OK) {
96    ALOGE("MANAGE CHANNEL OPEN failed with error code: %x %x",
97          rx_buf[rx_len - 2], rx_buf[rx_len - 1]);
98    return ret;
99  }
100  if (rx_len < 3) {
101    ALOGE("transceive error: successful reply unexpectedly short");
102    return ESE_APP_RESULT_ERROR_COMM_FAILED;
103  }
104  session->ese = ese;
105  session->channel_id = rx_buf[rx_len - 3];
106
107  /* Select Boot Applet. */
108  uint8_t chan = kSelectApplet[0] | session->channel_id;
109  tx[0].base = &chan;
110  tx[0].len = 1;
111  tx[1].base = (uint8_t *)&kSelectApplet[1];
112  tx[1].len = sizeof(kSelectApplet) - 1;
113  rx.base = &rx_buf[0];
114  rx.len = sizeof(rx_buf);
115  rx_len = ese_transceive_sg(ese, tx, 2, &rx, 1);
116  if (rx_len < 0 || ese_error(ese)) {
117    ALOGE("transceive error: caller should check ese_error()");
118    return ESE_APP_RESULT_ERROR_COMM_FAILED;
119  }
120  if (rx_len < 2) {
121    ALOGE("transceive error: reply too short");
122    return ESE_APP_RESULT_ERROR_COMM_FAILED;
123  }
124  ret = check_apdu_status(&rx_buf[rx_len - 2]);
125  if (ret != ESE_APP_RESULT_OK) {
126    ALOGE("SELECT failed with error code: %x %x", rx_buf[rx_len - 2],
127          rx_buf[rx_len - 1]);
128    return ret;
129  }
130  session->active = true;
131  return ESE_APP_RESULT_OK;
132}
133
134ESE_API EseAppResult ese_boot_session_close(struct EseBootSession *session) {
135  uint8_t rx_buf[32];
136  int rx_len;
137  if (!session || !session->ese) {
138    return ESE_APP_RESULT_ERROR_ARGUMENTS;
139  }
140  if (!session->active || session->channel_id == 0) {
141    return ESE_APP_RESULT_ERROR_ARGUMENTS;
142  }
143  /* Release the channel */
144  uint8_t close_channel[sizeof(kManageChannelClose)];
145  ese_memcpy(close_channel, kManageChannelClose, sizeof(kManageChannelClose));
146  close_channel[0] |= session->channel_id;
147  close_channel[3] |= session->channel_id;
148  rx_len = ese_transceive(session->ese, close_channel, sizeof(close_channel),
149                          rx_buf, sizeof(rx_buf));
150  if (rx_len < 0 || ese_error(session->ese)) {
151    return ESE_APP_RESULT_ERROR_COMM_FAILED;
152  }
153  if (rx_len < 2) {
154    return ESE_APP_RESULT_ERROR_COMM_FAILED;
155  }
156  EseAppResult ret;
157  ret = check_apdu_status(&rx_buf[rx_len - 2]);
158  if (ret != ESE_APP_RESULT_OK) {
159    return ret;
160  }
161  session->channel_id = 0;
162  session->active = false;
163  return ESE_APP_RESULT_OK;
164}
165
166ESE_API EseAppResult ese_boot_lock_xget(struct EseBootSession *session,
167                                        EseBootLockId lock, uint8_t *lockData,
168                                        uint16_t maxSize, uint16_t *length) {
169  struct EseSgBuffer tx[4];
170  struct EseSgBuffer rx[3];
171  int rx_len;
172  if (!session || !session->ese || !session->active) {
173    return ESE_APP_RESULT_ERROR_ARGUMENTS;
174  }
175  if (lock > kEseBootLockIdMax) {
176    return ESE_APP_RESULT_ERROR_ARGUMENTS;
177  }
178  if (maxSize < 1 || maxSize > 4096) {
179    return ESE_APP_RESULT_ERROR_ARGUMENTS;
180  }
181  uint8_t chan = kGetLockState[0] | session->channel_id;
182  tx[0].base = &chan;
183  tx[0].len = 1;
184  tx[1].base = (uint8_t *)&kGetLockState[1];
185  tx[1].len = 1;
186
187  uint8_t p1p2[] = {lock, 0x01};
188  tx[2].base = &p1p2[0];
189  tx[2].len = sizeof(p1p2);
190
191  // Accomodate the applet 2 byte status code.
192  uint8_t max_reply[] = {0x0, ((maxSize + 2) >> 8), ((maxSize + 2) & 0xff)};
193  tx[3].base = &max_reply[0];
194  tx[3].len = sizeof(max_reply);
195
196  uint8_t reply[2]; // App reply or APDU error.
197  rx[0].base = &reply[0];
198  rx[0].len = sizeof(reply);
199  // Applet data
200  rx[1].base = lockData;
201  rx[1].len = maxSize;
202  // Only used if the full maxSize is used.
203  uint8_t apdu_status[2];
204  rx[2].base = &apdu_status[0];
205  rx[2].len = sizeof(apdu_status);
206
207  rx_len = ese_transceive_sg(session->ese, tx, 4, rx, 3);
208  if (rx_len < 2 || ese_error(session->ese)) {
209    ALOGE("Failed to read lock state (%d).", lock);
210    return ESE_APP_RESULT_ERROR_COMM_FAILED;
211  }
212  if (rx_len == 2) {
213    ALOGE("ese_boot_lock_xget: SE exception");
214    EseAppResult ret = check_apdu_status(&reply[0]);
215    return ret;
216  }
217  // Expect the full payload plus the aplet status and the completion code.
218  *length = (uint16_t)(rx_len - 4);
219  if (rx_len == 4) {
220    ALOGE("Received applet error code %x %x", lockData[0], lockData[1]);
221    return ese_make_app_result(lockData[0], lockData[1]);
222  }
223  return ESE_APP_RESULT_OK;
224}
225
226ESE_API EseAppResult ese_boot_lock_get(struct EseBootSession *session,
227                                       EseBootLockId lock, uint8_t *lockVal) {
228  struct EseSgBuffer tx[3];
229  struct EseSgBuffer rx[1];
230  int rx_len;
231  if (!session || !session->ese || !session->active) {
232    return ESE_APP_RESULT_ERROR_ARGUMENTS;
233  }
234  if (lock > kEseBootLockIdMax) {
235    return ESE_APP_RESULT_ERROR_ARGUMENTS;
236  }
237  uint8_t chan = kGetLockState[0] | session->channel_id;
238  tx[0].base = &chan;
239  tx[0].len = 1;
240  tx[1].base = (uint8_t *)&kGetLockState[1];
241  tx[1].len = 1;
242
243  uint8_t p1p2[] = {lock, 0x0};
244  tx[2].base = &p1p2[0];
245  tx[2].len = sizeof(p1p2);
246
247  uint8_t reply[6];
248  rx[0].base = &reply[0];
249  rx[0].len = sizeof(reply);
250
251  rx_len = ese_transceive_sg(session->ese, tx, 3, rx, 1);
252  if (rx_len < 2 || ese_error(session->ese)) {
253    ALOGE("Failed to read lock state (%d).", lock);
254    return ESE_APP_RESULT_ERROR_COMM_FAILED;
255  }
256  EseAppResult ret = check_apdu_status(&reply[rx_len - 2]);
257  if (ret != ESE_APP_RESULT_OK) {
258    ALOGE("Get lock state returned a SE OS error.");
259    return ret;
260  }
261  if (rx_len < 5) {
262    ALOGE("Get lock state did not receive enough data.");
263    return ESE_APP_RESULT_ERROR_COMM_FAILED;
264  }
265  // TODO: unify in the applet, then map them here.
266  if (reply[0] != 0x0 && reply[1] != 0x0) {
267    ALOGE("INS_GET_LOCK: Applet error: %x %x", reply[0], reply[1]);
268    return ese_make_app_result(reply[0], reply[1]);
269  }
270  if (lockVal) {
271    *lockVal = reply[2];
272    return ESE_APP_RESULT_OK;
273  }
274
275  if (reply[2] != 0) {
276    return ESE_APP_RESULT_TRUE;
277  }
278  return ESE_APP_RESULT_FALSE;
279}
280
281ESE_API EseAppResult ese_boot_lock_xset(struct EseBootSession *session,
282                                        EseBootLockId lockId,
283                                        const uint8_t *lockData,
284                                        uint16_t dataLen) {
285  struct EseSgBuffer tx[5];
286  struct EseSgBuffer rx[1];
287  int rx_len;
288  if (!session || !session->ese || !session->active) {
289    return ESE_APP_RESULT_ERROR_ARGUMENTS;
290  }
291  if (lockId > kEseBootLockIdMax) {
292    return ESE_APP_RESULT_ERROR_ARGUMENTS;
293  }
294  if (dataLen < 1 || dataLen > kEseBootOwnerKeyMax + 1) {
295    ALOGE("set_lock_with_meta: too much data: %hu > %d", dataLen,
296          kEseBootOwnerKeyMax + 1);
297    return ESE_APP_RESULT_ERROR_ARGUMENTS;
298  }
299
300  uint8_t chan = kSetLockState[0] | session->channel_id;
301  tx[0].base = &chan;
302  tx[0].len = 1;
303  tx[1].base = (uint8_t *)&kSetLockState[1];
304  tx[1].len = 1;
305
306  uint8_t p1p2[] = {lockId, lockData[0]};
307  tx[2].base = &p1p2[0];
308  tx[2].len = sizeof(p1p2);
309  dataLen--;
310
311  uint8_t apdu_len[] = {0x0, (dataLen >> 8), (dataLen & 0xff)};
312  tx[3].base = &apdu_len[0];
313  tx[3].len = sizeof(apdu_len);
314
315  tx[4].c_base = &lockData[1];
316  tx[4].len = dataLen;
317
318  uint8_t reply[4]; // App reply or APDU error.
319  rx[0].base = &reply[0];
320  rx[0].len = sizeof(reply);
321
322  rx_len = ese_transceive_sg(session->ese, tx, 5, rx, 1);
323  if (rx_len < 2 || ese_error(session->ese)) {
324    ALOGE("Failed to set lock state (%d).", lockId);
325    return ESE_APP_RESULT_ERROR_COMM_FAILED;
326  }
327  if (rx_len == 2) {
328    ALOGE("ese_boot_lock_xset: SE exception");
329    EseAppResult ret = check_apdu_status(&reply[0]);
330    return ret;
331  }
332  // Expect the full payload plus the aplet status and the completion code.
333  if (rx_len != 4) {
334    ALOGE("Get lock state did not receive enough data: %d", rx_len);
335    return ESE_APP_RESULT_ERROR_COMM_FAILED;
336  }
337  if (reply[0] != 0x0 || reply[1] != 0x0) {
338    ALOGE("Received applet error code %x %x", reply[0], reply[1]);
339    return ese_make_app_result(reply[0], reply[1]);
340  }
341  return ESE_APP_RESULT_OK;
342}
343
344ESE_API EseAppResult ese_boot_lock_set(struct EseBootSession *session,
345                                       EseBootLockId lockId,
346                                       uint8_t lockValue) {
347  struct EseSgBuffer tx[3];
348  struct EseSgBuffer rx[1];
349  int rx_len;
350  if (!session || !session->ese || !session->active) {
351    return ESE_APP_RESULT_ERROR_ARGUMENTS;
352  }
353  if (lockId > kEseBootLockIdMax) {
354    return ESE_APP_RESULT_ERROR_ARGUMENTS;
355  }
356
357  uint8_t chan = kSetLockState[0] | session->channel_id;
358  tx[0].base = &chan;
359  tx[0].len = 1;
360  tx[1].base = (uint8_t *)&kSetLockState[1];
361  tx[1].len = 1;
362
363  uint8_t p1p2[] = {lockId, lockValue};
364  tx[2].base = &p1p2[0];
365  tx[2].len = sizeof(p1p2);
366
367  uint8_t reply[4]; // App reply or APDU error.
368  rx[0].base = &reply[0];
369  rx[0].len = sizeof(reply);
370
371  rx_len = ese_transceive_sg(session->ese, tx, 3, rx, 1);
372  if (rx_len < 2 || ese_error(session->ese)) {
373    ALOGE("Failed to set lock state (%d).", lockId);
374    return ESE_APP_RESULT_ERROR_COMM_FAILED;
375  }
376  // Expect the full payload plus the applet status and the completion code.
377  if (rx_len < 4) {
378    ALOGE("ese_boot_lock_xset: SE exception");
379    EseAppResult ret = check_apdu_status(&reply[rx_len - 2]);
380    return ret;
381  }
382  if (reply[0] != 0x0 || reply[1] != 0x0) {
383    ALOGE("Received applet error code %x %x", reply[0], reply[1]);
384    return ese_make_app_result(reply[0], reply[1]);
385  }
386  return ESE_APP_RESULT_OK;
387}
388
389ESE_API EseAppResult ese_boot_rollback_index_write(
390    struct EseBootSession *session, uint8_t slot, uint64_t value) {
391  struct EseSgBuffer tx[5];
392  struct EseSgBuffer rx[1];
393  uint8_t chan;
394  if (!session || !session->ese || !session->active) {
395    ALOGE("ese_boot_rollback_index_write: invalid session");
396    return ESE_APP_RESULT_ERROR_ARGUMENTS;
397  }
398  if (slot >= kEseBootRollbackSlotCount) {
399    ALOGE("ese_boot_rollback_index_write: slot invalid");
400    return ESE_APP_RESULT_ERROR_ARGUMENTS;
401  }
402
403  // APDU CLA
404  chan = kStoreCmd[0] | session->channel_id;
405  tx[0].base = &chan;
406  tx[0].len = 1;
407  // APDU INS
408  tx[1].base = (uint8_t *)&kStoreCmd[1];
409  tx[1].len = 1;
410  // APDU P1 - P2
411  const uint8_t p1p2[] = {slot, 0x0};
412  tx[2].c_base = &p1p2[0];
413  tx[2].len = sizeof(p1p2);
414  // APDU Lc
415  uint8_t len = (uint8_t)sizeof(value);
416  tx[3].base = &len;
417  tx[3].len = sizeof(len);
418  // APDU data
419  tx[4].base = (uint8_t *)&value;
420  tx[4].len = sizeof(value);
421
422  uint8_t rx_buf[4];
423  rx[0].base = &rx_buf[0];
424  rx[0].len = sizeof(rx_buf);
425
426  int rx_len = ese_transceive_sg(session->ese, tx, 5, rx, 1);
427  if (rx_len < 0 || ese_error(session->ese)) {
428    ALOGE("ese_boot_rollback_index_write: comm error");
429    return ESE_APP_RESULT_ERROR_COMM_FAILED;
430  }
431  if (rx_len < 2) {
432    ALOGE("ese_boot_rollback_index_write: too few bytes recieved.");
433    return ESE_APP_RESULT_ERROR_COMM_FAILED;
434  }
435  if (rx_len < 4) {
436    ALOGE("ese_boot_rollback_index_write: APDU Error");
437    return check_apdu_status(&rx_buf[rx_len - 2]);
438  }
439
440  if (rx_buf[0] != 0 || rx_buf[1] != 0) {
441    ALOGE("ese_boot_rollback_index_write: applet error code %x %x", rx_buf[0],
442          rx_buf[1]);
443    return ese_make_app_result(rx_buf[0], rx_buf[1]);
444  }
445  return ESE_APP_RESULT_OK;
446}
447
448ESE_API EseAppResult ese_boot_rollback_index_read(
449    struct EseBootSession *session, uint8_t slot, uint64_t *value) {
450  struct EseSgBuffer tx[4];
451  struct EseSgBuffer rx[1];
452  uint8_t chan;
453  if (!session || !session->ese || !session->active) {
454    ALOGE("ese_boot_rollback_index_write: invalid session");
455    return ESE_APP_RESULT_ERROR_ARGUMENTS;
456  }
457  if (!value) {
458    ALOGE("ese_boot_rollback_index_write: NULL value supplied");
459    return ESE_APP_RESULT_ERROR_ARGUMENTS;
460  }
461  if (slot >= kEseBootRollbackSlotCount) {
462    ALOGE("ese_boot_rollback_index_write: slot invalid");
463    return ESE_APP_RESULT_ERROR_ARGUMENTS;
464  }
465
466  // APDU CLA
467  chan = kLoadCmd[0] | session->channel_id;
468  tx[0].base = &chan;
469  tx[0].len = 1;
470  // APDU INS
471  tx[1].base = (uint8_t *)&kLoadCmd[1];
472  tx[1].len = 1;
473  // APDU P1 - P2
474  const uint8_t p1p2[] = {slot, 0x0};
475  tx[2].c_base = &p1p2[0];
476  tx[2].len = sizeof(p1p2);
477  // APDU Lc
478  uint8_t len = 0;
479  tx[3].base = &len;
480  tx[3].len = sizeof(len);
481
482  uint8_t rx_buf[4 + sizeof(*value)];
483  rx[0].base = &rx_buf[0];
484  rx[0].len = sizeof(rx_buf);
485
486  int rx_len = ese_transceive_sg(session->ese, tx, 4, rx, 1);
487  if (rx_len < 0 || ese_error(session->ese)) {
488    ALOGE("ese_boot_rollback_index_read: comm error");
489    return ESE_APP_RESULT_ERROR_COMM_FAILED;
490  }
491  if (rx_len < 2) {
492    ALOGE("ese_boot_rollback_index_read: too few bytes recieved.");
493    return ESE_APP_RESULT_ERROR_COMM_FAILED;
494  }
495  // TODO(wad) We should check the APDU status anyway.
496  if (rx_len < 4) {
497    ALOGE("ese_boot_rollback_index_read: APDU Error");
498    return check_apdu_status(&rx_buf[rx_len - 2]);
499  }
500  if (rx_buf[0] != 0 || rx_buf[1] != 0) {
501    ALOGE("ese_boot_rollback_index_read: applet error code %x %x", rx_buf[0],
502          rx_buf[1]);
503    return ese_make_app_result(rx_buf[0], rx_buf[1]);
504  }
505  if (rx_len != (int)sizeof(rx_buf)) {
506    ALOGE("ese_boot_rollback_index_read: unexpected partial reply (%d)",
507          rx_len);
508    return ESE_APP_RESULT_ERROR_COMM_FAILED;
509  }
510  *value = *((uint64_t *)&rx_buf[2]);
511  return ESE_APP_RESULT_OK;
512}
513
514ESE_API EseAppResult ese_boot_carrier_lock_test(struct EseBootSession *session,
515                                                const uint8_t *testdata,
516                                                uint16_t len) {
517  struct EseSgBuffer tx[5];
518  struct EseSgBuffer rx[1];
519  int rx_len;
520  if (!session || !session->ese || !session->active) {
521    return ESE_APP_RESULT_ERROR_ARGUMENTS;
522  }
523  if (len > 2048) {
524    return ESE_APP_RESULT_ERROR_ARGUMENTS;
525  }
526
527  uint8_t chan = kCarrierLockTest[0] | session->channel_id;
528  tx[0].base = &chan;
529  tx[0].len = 1;
530  tx[1].base = (uint8_t *)&kCarrierLockTest[1];
531  tx[1].len = 1;
532
533  uint8_t p1p2[] = {0, 0};
534  tx[2].base = &p1p2[0];
535  tx[2].len = sizeof(p1p2);
536
537  uint8_t apdu_len[] = {0x0, (len >> 8), (len & 0xff)};
538  tx[3].base = &apdu_len[0];
539  tx[3].len = sizeof(apdu_len);
540
541  tx[4].c_base = testdata;
542  tx[4].len = len;
543
544  uint8_t reply[4]; // App reply or APDU error.
545  rx[0].base = &reply[0];
546  rx[0].len = sizeof(reply);
547
548  rx_len = ese_transceive_sg(session->ese, tx, 5, rx, 1);
549  if (rx_len < 2 || ese_error(session->ese)) {
550    ALOGE("ese_boot_carrier_lock_test: failed to test carrier vector");
551    return ESE_APP_RESULT_ERROR_COMM_FAILED;
552  }
553  if (rx_len < 4) {
554    ALOGE("ese_boot_carrier_lock_test: SE exception");
555    EseAppResult ret = check_apdu_status(&reply[rx_len - 2]);
556    return ret;
557  }
558  if (reply[0] != 0x0 || reply[1] != 0x0) {
559    ALOGE("ese_boot_carrier_lock_test: applet error %x %x", reply[0], reply[1]);
560    return ese_make_app_result(reply[0], reply[1]);
561  }
562  return ESE_APP_RESULT_OK;
563}
564
565ESE_API EseAppResult ese_boot_set_production(struct EseBootSession *session,
566                                             bool production_mode) {
567  struct EseSgBuffer tx[3];
568  struct EseSgBuffer rx[1];
569  int rx_len;
570  uint8_t prodVal = production_mode ? 0x1 : 0x00;
571  if (!session || !session->ese || !session->active) {
572    return ESE_APP_RESULT_ERROR_ARGUMENTS;
573  }
574
575  uint8_t chan = kSetProduction[0] | session->channel_id;
576  tx[0].base = &chan;
577  tx[0].len = 1;
578  tx[1].base = (uint8_t *)&kSetProduction[1];
579  tx[1].len = 1;
580
581  uint8_t p1p2[] = {prodVal, 0x0};
582  tx[2].base = &p1p2[0];
583  tx[2].len = sizeof(p1p2);
584
585  uint8_t reply[4]; // App reply or APDU error.
586  rx[0].base = &reply[0];
587  rx[0].len = sizeof(reply);
588
589  rx_len = ese_transceive_sg(session->ese, tx, 3, rx, 1);
590  if (rx_len < 2 || ese_error(session->ese)) {
591    ALOGE("ese_boot_set_production: comms failure.");
592    return ESE_APP_RESULT_ERROR_COMM_FAILED;
593  }
594  if (rx_len == 2) {
595    ALOGE("ese_boot_set_production: SE exception");
596    EseAppResult ret = check_apdu_status(&reply[0]);
597    return ret;
598  }
599  // Expect the full payload plus the aplet status and the completion code.
600  if (rx_len != 4) {
601    ALOGE("ese_boot_set_production: not enough data (%d)", rx_len);
602    return ese_make_app_result(reply[0], reply[1]);
603  }
604  if (reply[0] != 0x0 || reply[1] != 0x0) {
605    ALOGE("ese_boot_set_production: applet error code %x %x", reply[0],
606          reply[1]);
607    return ese_make_app_result(reply[0], reply[1]);
608  }
609  return ESE_APP_RESULT_OK;
610}
611
612ESE_API EseAppResult ese_boot_reset_locks(struct EseBootSession *session) {
613  struct EseSgBuffer tx[2];
614  struct EseSgBuffer rx[1];
615  int rx_len;
616  if (!session || !session->ese || !session->active) {
617    return ESE_APP_RESULT_ERROR_ARGUMENTS;
618  }
619
620  uint8_t chan = kLockReset[0] | session->channel_id;
621  tx[0].base = &chan;
622  tx[0].len = 1;
623  tx[1].base = (uint8_t *)&kLockReset[1];
624  tx[1].len = sizeof(kLockReset) - 1;
625
626  uint8_t reply[4]; // App reply or APDU error.
627  rx[0].base = &reply[0];
628  rx[0].len = sizeof(reply);
629
630  rx_len = ese_transceive_sg(session->ese, tx, 2, rx, 1);
631  if (rx_len < 2 || ese_error(session->ese)) {
632    ALOGE("ese_boot_reset_locks: comms failure.");
633    return ESE_APP_RESULT_ERROR_COMM_FAILED;
634  }
635  if (rx_len == 2) {
636    ALOGE("ese_boot_reset_locks: SE exception");
637    EseAppResult ret = check_apdu_status(&reply[0]);
638    return ret;
639  }
640  // Expect the full payload plus the aplet status and the completion code.
641  if (rx_len != 4) {
642    ALOGE("ese_boot_reset_locks: not enough data (%d)", rx_len);
643    return ese_make_app_result(reply[0], reply[1]);
644  }
645  if (reply[0] != 0x0 || reply[1] != 0x0) {
646    ALOGE("ese_boot_reset_locks: applet error code %x %x", reply[0], reply[1]);
647    return ese_make_app_result(reply[0], reply[1]);
648  }
649  return ESE_APP_RESULT_OK;
650}
651
652ESE_API EseAppResult ese_boot_get_state(struct EseBootSession *session,
653                                        uint8_t *state, uint16_t maxSize) {
654  struct EseSgBuffer tx[4];
655  struct EseSgBuffer rx[3];
656  int rx_len;
657  if (!session || !session->ese || !session->active) {
658    return ESE_APP_RESULT_ERROR_ARGUMENTS;
659  }
660  uint8_t chan = kGetState[0] | session->channel_id;
661  tx[0].base = &chan;
662  tx[0].len = 1;
663  tx[1].base = (uint8_t *)&kGetState[1];
664  tx[1].len = 1;
665
666  uint8_t p1p2[] = {0x0, 0x0};
667  tx[2].base = &p1p2[0];
668  tx[2].len = sizeof(p1p2);
669
670  // Accomodate the applet 2 byte status code.
671  uint8_t max_reply[] = {0x0, ((maxSize + 2) >> 8), ((maxSize + 2) & 0xff)};
672  tx[3].base = &max_reply[0];
673  tx[3].len = sizeof(max_reply);
674
675  uint8_t reply[2]; // App reply or APDU error.
676  rx[0].base = &reply[0];
677  rx[0].len = sizeof(reply);
678  // Applet data
679  rx[1].base = state;
680  rx[1].len = maxSize;
681  // Just in case the maxSize is used. That is unlikely.
682  // TODO(wad) clean this up.
683  uint8_t apdu_status[2];
684  rx[2].base = &apdu_status[0];
685  rx[2].len = sizeof(apdu_status);
686
687  rx_len = ese_transceive_sg(session->ese, tx, 4, rx, 3);
688  if (rx_len < 2 || ese_error(session->ese)) {
689    ALOGE("ese_boot_get_state: comm failure");
690    return ESE_APP_RESULT_ERROR_COMM_FAILED;
691  }
692  if (rx_len == 2) {
693    ALOGE("ese_boot_get_state: SE exception");
694    EseAppResult ret = check_apdu_status(&reply[0]);
695    return ret;
696  }
697  // Expect the full payload plus the aplet status and the completion code.
698  if (rx_len < 3 + 4) {
699    ALOGE("ese_boot_get_state: did not receive enough data: %d", rx_len);
700    if (rx_len == 4) {
701      ALOGE("Received applet error code %x %x", reply[0], reply[1]);
702    }
703    return ese_make_app_result(reply[0], reply[1]);
704  }
705  // Well known version (for now).
706  if (state[0] == kBootStateVersion) {
707    uint16_t expected = (state[1] << 8) | (state[2]);
708    // Reduce for version (1), status (2).
709    if ((rx_len - 3) != expected) {
710      ALOGE("ese_boot_get_state: may be truncated: %d != %d", rx_len - 5,
711            expected);
712    }
713    return ESE_APP_RESULT_OK;
714  }
715  ALOGE("ese_boot_get_state: missing version tag");
716  return ESE_APP_RESULT_ERROR_OS;
717}
718