Home | History | Annotate | Download | only in boot
      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 
     20 const uint8_t kBootStateVersion = 0x1;
     21 const uint16_t kBootStorageLength = 4096;
     22 /* Non-static, but visibility=hidden so they can be used in test. */
     23 const uint8_t kManageChannelOpen[] = {0x00, 0x70, 0x00, 0x00, 0x01};
     24 const uint32_t kManageChannelOpenLength = (uint32_t)sizeof(kManageChannelOpen);
     25 const uint8_t kManageChannelClose[] = {0x00, 0x70, 0x80, 0x00, 0x00};
     26 
     27 const uint8_t kSelectApplet[] = {0x00, 0xA4, 0x04, 0x00, 0x0d, 0xA0,
     28                                  0x00, 0x00, 0x04, 0x76, 0x50, 0x49,
     29                                  0x58, 0x4C, 0x42, 0x4F, 0x4F, 0x54};
     30 const uint32_t kSelectAppletLength = (uint32_t)sizeof(kSelectApplet);
     31 // Supported commands.
     32 const uint8_t kGetState[] = {0x80, 0x00, 0x00, 0x00, 0x00};
     33 const uint8_t kLoadCmd[] = {0x80, 0x02};
     34 const uint8_t kStoreCmd[] = {0x80, 0x04};
     35 const uint8_t kGetLockState[] = {0x80, 0x06, 0x00, 0x00, 0x00};
     36 const uint8_t kSetLockState[] = {0x80, 0x08, 0x00, 0x00, 0x00};
     37 const uint8_t kSetProduction[] = {0x80, 0x0a};
     38 const uint8_t kCarrierLockTest[] = {0x80, 0x0c, 0x00, 0x00};
     39 const uint8_t kFactoryReset[] = {0x80, 0x0e, 0x00, 0x00};
     40 const uint8_t kLockReset[] = {0x80, 0x0e, 0x01, 0x00};
     41 const uint8_t kLoadMetaClear[] = {0x80, 0x10, 0x00, 0x00};
     42 const uint8_t kLoadMetaAppend[] = {0x80, 0x10, 0x01, 0x00};
     43 static const uint16_t kMaxMetadataLoadSize = 1024;
     44 
     45 EseAppResult 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 
     60 ESE_API void ese_boot_session_init(struct EseBootSession *session) {
     61   session->ese = NULL;
     62   session->active = false;
     63   session->channel_id = 0;
     64 }
     65 
     66 ESE_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 
    137 ESE_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 
    169 ESE_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 
    230 ESE_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 
    285 EseAppResult 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 
    322 EseAppResult 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 
    370 ESE_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 
    448 ESE_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 
    493 ESE_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 
    552 ESE_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 
    618 ESE_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 
    669 ESE_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 
    716 ESE_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 
    756 ESE_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