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