Home | History | Annotate | Download | only in weaver
      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/weaver.h"
     18 
     19 /* Non-static, but visibility=hidden so they can be used in test. */
     20 const uint8_t kManageChannelOpen[] = {0x00, 0x70, 0x00, 0x00, 0x01};
     21 const uint32_t kManageChannelOpenLength = (uint32_t)sizeof(kManageChannelOpen);
     22 const uint8_t kManageChannelClose[] = {0x00, 0x70, 0x80, 0x00, 0x00};
     23 const uint8_t kSelectApplet[] = {0x00, 0xA4, 0x04, 0x00, 0x0D, 0xA0,
     24                                  0x00, 0x00, 0x04, 0x76, 0x57, 0x56,
     25                                  0x52, 0x43, 0x4F, 0x4D, 0x4D, 0x30};
     26 const uint32_t kSelectAppletLength = (uint32_t)sizeof(kSelectApplet);
     27 // Supported commands.
     28 const uint8_t kGetNumSlots[] = {0x80, 0x02, 0x00, 0x00, 0x04};
     29 const uint8_t kWrite[] = {0x80, 0x04, 0x00, 0x00,
     30                           4 + kEseWeaverKeySize +
     31                               kEseWeaverValueSize}; // slotid + key + value
     32 const uint8_t kRead[] = {0x80, 0x06, 0x00, 0x00,
     33                          4 + kEseWeaverKeySize}; // slotid + key
     34 const uint8_t kEraseValue[] = {0x80, 0x08, 0x00, 0x00, 4}; // slotid
     35 const uint8_t kEraseAll[] = {0x80, 0x0a, 0x00, 0x00};
     36 
     37 // Build 32-bit int from big endian bytes
     38 static uint32_t get_uint32(uint8_t buf[4]) {
     39   uint32_t x = buf[3];
     40   x |= buf[2] << 8;
     41   x |= buf[1] << 16;
     42   x |= buf[0] << 24;
     43   return x;
     44 }
     45 
     46 static void put_uint32(uint8_t buf[4], uint32_t val) {
     47   buf[0] = 0xff & (val >> 24);
     48   buf[1] = 0xff & (val >> 16);
     49   buf[2] = 0xff & (val >> 8);
     50   buf[3] = 0xff & val;
     51 }
     52 
     53 EseAppResult check_apdu_status(uint8_t code[2]) {
     54   if (code[0] == 0x90 && code[1] == 0x00) {
     55     return ESE_APP_RESULT_OK;
     56   }
     57   if (code[0] == 0x66 && code[1] == 0xA5) {
     58     return ESE_APP_RESULT_ERROR_COOLDOWN;
     59   }
     60   if (code[0] == 0x6A && code[1] == 0x83) {
     61     return ESE_APP_RESULT_ERROR_UNCONFIGURED;
     62   }
     63   /* TODO(wad) Bubble up the error code if needed. */
     64   ALOGE("unhandled response %.2x %.2x", code[0], code[1]);
     65   return ese_make_os_result(code[0], code[1]);
     66 }
     67 
     68 ESE_API void ese_weaver_session_init(struct EseWeaverSession *session) {
     69   session->ese = NULL;
     70   session->active = false;
     71   session->channel_id = 0;
     72 }
     73 
     74 ESE_API EseAppResult ese_weaver_session_open(struct EseInterface *ese,
     75                                              struct EseWeaverSession *session) {
     76   struct EseSgBuffer tx[2];
     77   struct EseSgBuffer rx;
     78   uint8_t rx_buf[32];
     79   int rx_len;
     80   if (!ese || !session) {
     81     ALOGE("Invalid |ese| or |session|");
     82     return ESE_APP_RESULT_ERROR_ARGUMENTS;
     83   }
     84   if (session->active == true) {
     85     ALOGE("|session| is already active");
     86     return ESE_APP_RESULT_ERROR_ARGUMENTS;
     87   }
     88   /* Instantiate a logical channel */
     89   rx_len = ese_transceive(ese, kManageChannelOpen, sizeof(kManageChannelOpen),
     90                           rx_buf, sizeof(rx_buf));
     91   if (ese_error(ese)) {
     92     ALOGE("transceive error: code:%d message:'%s'", ese_error_code(ese),
     93           ese_error_message(ese));
     94     return ESE_APP_RESULT_ERROR_COMM_FAILED;
     95   }
     96   if (rx_len < 0) {
     97     ALOGE("transceive error: rx_len: %d", rx_len);
     98     return ESE_APP_RESULT_ERROR_COMM_FAILED;
     99   }
    100   if (rx_len < 2) {
    101     ALOGE("transceive error: reply too short");
    102     return ESE_APP_RESULT_ERROR_COMM_FAILED;
    103   }
    104   EseAppResult ret;
    105   ret = check_apdu_status(&rx_buf[rx_len - 2]);
    106   if (ret != ESE_APP_RESULT_OK) {
    107     ALOGE("MANAGE CHANNEL OPEN failed with error code: %x %x",
    108           rx_buf[rx_len - 2], rx_buf[rx_len - 1]);
    109     return ret;
    110   }
    111   if (rx_len < 3) {
    112     ALOGE("transceive error: successful reply unexpectedly short");
    113     return ESE_APP_RESULT_ERROR_COMM_FAILED;
    114   }
    115   session->ese = ese;
    116   session->channel_id = rx_buf[rx_len - 3];
    117 
    118   /* Select Weaver Applet. */
    119   uint8_t chan = kSelectApplet[0] | session->channel_id;
    120   tx[0].base = &chan;
    121   tx[0].len = 1;
    122   tx[1].base = (uint8_t *)&kSelectApplet[1];
    123   tx[1].len = sizeof(kSelectApplet) - 1;
    124   rx.base = &rx_buf[0];
    125   rx.len = sizeof(rx_buf);
    126   rx_len = ese_transceive_sg(ese, tx, 2, &rx, 1);
    127   if (rx_len < 0 || ese_error(ese)) {
    128     ALOGE("transceive error: caller should check ese_error()");
    129     return ESE_APP_RESULT_ERROR_COMM_FAILED;
    130   }
    131   if (rx_len < 2) {
    132     ALOGE("transceive error: reply too short");
    133     return ESE_APP_RESULT_ERROR_COMM_FAILED;
    134   }
    135   ret = check_apdu_status(&rx_buf[rx_len - 2]);
    136   if (ret != ESE_APP_RESULT_OK) {
    137     ALOGE("SELECT failed with error code: %x %x", rx_buf[rx_len - 2],
    138           rx_buf[rx_len - 1]);
    139     return ret;
    140   }
    141   session->active = true;
    142   return ESE_APP_RESULT_OK;
    143 }
    144 
    145 ESE_API EseAppResult
    146 ese_weaver_session_close(struct EseWeaverSession *session) {
    147   uint8_t rx_buf[32];
    148   int rx_len;
    149   if (!session || !session->ese) {
    150     return ESE_APP_RESULT_ERROR_ARGUMENTS;
    151   }
    152   if (!session->active || session->channel_id == 0) {
    153     return ESE_APP_RESULT_ERROR_ARGUMENTS;
    154   }
    155   /* Release the channel */
    156   uint8_t close_channel[sizeof(kManageChannelClose)];
    157   ese_memcpy(close_channel, kManageChannelClose, sizeof(kManageChannelClose));
    158   close_channel[0] |= session->channel_id;
    159   close_channel[3] |= session->channel_id;
    160   rx_len = ese_transceive(session->ese, close_channel, sizeof(close_channel),
    161                           rx_buf, sizeof(rx_buf));
    162   if (rx_len < 0 || ese_error(session->ese)) {
    163     return ESE_APP_RESULT_ERROR_COMM_FAILED;
    164   }
    165   if (rx_len < 2) {
    166     return ESE_APP_RESULT_ERROR_COMM_FAILED;
    167   }
    168   EseAppResult ret;
    169   ret = check_apdu_status(&rx_buf[rx_len - 2]);
    170   if (ret != ESE_APP_RESULT_OK) {
    171     return ret;
    172   }
    173   session->channel_id = 0;
    174   session->active = false;
    175   return ESE_APP_RESULT_OK;
    176 }
    177 
    178 ESE_API EseAppResult ese_weaver_get_num_slots(struct EseWeaverSession *session,
    179                                               uint32_t *numSlots) {
    180   if (!session || !session->ese || !session->active) {
    181     return ESE_APP_RESULT_ERROR_ARGUMENTS;
    182   }
    183   if (!session->active || session->channel_id == 0) {
    184     return ESE_APP_RESULT_ERROR_ARGUMENTS;
    185   }
    186   if (!numSlots) {
    187     return ESE_APP_RESULT_ERROR_ARGUMENTS;
    188   }
    189 
    190   // Prepare command
    191   uint8_t get_num_slots[sizeof(kGetNumSlots)];
    192   ese_memcpy(get_num_slots, kGetNumSlots, sizeof(kGetNumSlots));
    193   get_num_slots[0] |= session->channel_id;
    194 
    195   // Send command
    196   uint8_t rx_buf[6];
    197   const int rx_len =
    198       ese_transceive(session->ese, get_num_slots, sizeof(get_num_slots), rx_buf,
    199                      sizeof(rx_buf));
    200 
    201   // Check for errors
    202   if (rx_len < 2 || ese_error(session->ese)) {
    203     ALOGE("Failed to get num slots");
    204     return ESE_APP_RESULT_ERROR_COMM_FAILED;
    205   }
    206   if (rx_len == 2) {
    207     ALOGE("ese_weaver_get_num_slots: SE exception");
    208     EseAppResult ret = check_apdu_status(rx_buf);
    209     return ret;
    210   }
    211   if (rx_len != 6) {
    212     ALOGE("Unexpected response from Weaver applet");
    213     return ESE_APP_RESULT_ERROR_COMM_FAILED;
    214   }
    215 
    216   *numSlots = get_uint32(rx_buf);
    217   return ESE_APP_RESULT_OK;
    218 }
    219 
    220 ESE_API EseAppResult ese_weaver_write(struct EseWeaverSession *session,
    221                                       uint32_t slotId, const uint8_t *key,
    222                                       const uint8_t *value) {
    223   if (!session || !session->ese || !session->active) {
    224     return ESE_APP_RESULT_ERROR_ARGUMENTS;
    225   }
    226   if (!session->active || session->channel_id == 0) {
    227     return ESE_APP_RESULT_ERROR_ARGUMENTS;
    228   }
    229   if (!key || !value) {
    230     return ESE_APP_RESULT_ERROR_ARGUMENTS;
    231   }
    232 
    233   // Prepare data to send
    234   struct EseSgBuffer tx[5];
    235   uint8_t chan = kWrite[0] | session->channel_id;
    236   tx[0].base = &chan;
    237   tx[0].len = 1;
    238   tx[1].base = (uint8_t *)&kWrite[1];
    239   tx[1].len = sizeof(kWrite) - 1;
    240 
    241   // Slot ID in big endian
    242   uint8_t slot_id[4];
    243   put_uint32(slot_id, slotId);
    244   tx[2].base = slot_id;
    245   tx[2].len = sizeof(slot_id);
    246 
    247   // Key and value
    248   tx[3].c_base = key;
    249   tx[3].len = kEseWeaverKeySize;
    250   tx[4].c_base = value;
    251   tx[4].len = kEseWeaverValueSize;
    252 
    253   // Prepare buffer for result
    254   struct EseSgBuffer rx;
    255   uint8_t rx_buf[2];
    256   rx.base = rx_buf;
    257   rx.len = sizeof(rx_buf);
    258 
    259   // Send the command
    260   const int rx_len = ese_transceive_sg(session->ese, tx, 5, &rx, 1);
    261 
    262   // Check for errors
    263   if (rx_len < 2 || ese_error(session->ese)) {
    264     ALOGE("Failed to write to slot");
    265     return ESE_APP_RESULT_ERROR_COMM_FAILED;
    266   }
    267   if (rx_len > 2) {
    268     ALOGE("Unexpected response from Weaver applet");
    269     return ESE_APP_RESULT_ERROR_COMM_FAILED;
    270   }
    271   return check_apdu_status(rx_buf);
    272 }
    273 
    274 ESE_API EseAppResult ese_weaver_read(struct EseWeaverSession *session,
    275                                      uint32_t slotId, const uint8_t *key,
    276                                      uint8_t *value, uint32_t *timeout) {
    277   if (!session || !session->ese || !session->active) {
    278     return ESE_APP_RESULT_ERROR_ARGUMENTS;
    279   }
    280   if (!session->active || session->channel_id == 0) {
    281     return ESE_APP_RESULT_ERROR_ARGUMENTS;
    282   }
    283   if (!key || !value || !timeout) {
    284     return ESE_APP_RESULT_ERROR_ARGUMENTS;
    285   }
    286 
    287   // Prepare data to send
    288   struct EseSgBuffer tx[5];
    289   uint8_t chan = kRead[0] | session->channel_id;
    290   tx[0].base = &chan;
    291   tx[0].len = 1;
    292   tx[1].base = (uint8_t *)&kRead[1];
    293   tx[1].len = sizeof(kRead) - 1;
    294 
    295   // Slot ID in big endian
    296   uint8_t slot_id[4];
    297   put_uint32(slot_id, slotId);
    298   tx[2].base = slot_id;
    299   tx[2].len = sizeof(slot_id);
    300 
    301   // Key of 16 bytes
    302   tx[3].c_base = key;
    303   tx[3].len = kEseWeaverKeySize;
    304 
    305   // Value response is 16 bytes
    306   const uint8_t maxResponse = 1 + kEseWeaverValueSize;
    307   tx[4].c_base = &maxResponse;
    308   tx[4].len = 1;
    309 
    310   // Prepare buffer for result
    311   struct EseSgBuffer rx[3];
    312   uint8_t appletStatus;
    313   rx[0].base = &appletStatus;
    314   rx[0].len = 1;
    315   rx[1].base = value;
    316   rx[1].len = kEseWeaverValueSize;
    317   uint8_t rx_buf[2];
    318   rx[2].base = rx_buf;
    319   rx[2].len = sizeof(rx_buf);
    320 
    321   // Send the command
    322   const int rx_len = ese_transceive_sg(session->ese, tx, 5, rx, 3);
    323 
    324   // Check for errors
    325   if (rx_len < 2 || ese_error(session->ese)) {
    326     ALOGE("Failed to write to slot");
    327     return ESE_APP_RESULT_ERROR_COMM_FAILED;
    328   }
    329   if (rx_len == 2) {
    330     rx_buf[0] = appletStatus;
    331     rx_buf[1] = value[0];
    332     ALOGE("ese_weaver_read: SE exception");
    333     EseAppResult ret = check_apdu_status(rx_buf);
    334     return ret;
    335   }
    336   if (rx_len < 7) {
    337     ALOGE("Unexpected response from Weaver applet");
    338     return ESE_APP_RESULT_ERROR_COMM_FAILED;
    339   }
    340   const uint8_t READ_SUCCESS = 0x00;
    341   const uint8_t READ_WRONG_KEY = 0x7f;
    342   const uint8_t READ_BACK_OFF = 0x76;
    343   const uint32_t millisInSecond = 1000;
    344   // wrong key
    345   if (appletStatus == READ_WRONG_KEY) {
    346     ALOGI("ese_weaver_read wrong key provided");
    347     *timeout = get_uint32(value) * millisInSecond;
    348     return ESE_WEAVER_READ_WRONG_KEY;
    349   }
    350   // backoff
    351   if (appletStatus == READ_BACK_OFF) {
    352     ALOGI("ese_weaver_read wrong key provided");
    353     *timeout = get_uint32(value) * millisInSecond;
    354     return ESE_WEAVER_READ_TIMEOUT;
    355   }
    356   if (rx_len != 19) {
    357     ALOGE("Unexpected response from Weaver applet");
    358     return ESE_APP_RESULT_ERROR_COMM_FAILED;
    359   }
    360   return ESE_APP_RESULT_OK;
    361 }
    362 
    363 ESE_API EseAppResult ese_weaver_erase_value(struct EseWeaverSession *session,
    364                                             uint32_t slotId) {
    365   if (!session || !session->ese || !session->active) {
    366     return ESE_APP_RESULT_ERROR_ARGUMENTS;
    367   }
    368   if (!session->active || session->channel_id == 0) {
    369     return ESE_APP_RESULT_ERROR_ARGUMENTS;
    370   }
    371 
    372   // Prepare data to send
    373   struct EseSgBuffer tx[3];
    374   uint8_t chan = kEraseValue[0] | session->channel_id;
    375   tx[0].base = &chan;
    376   tx[0].len = 1;
    377   tx[1].base = (uint8_t *)&kEraseValue[1];
    378   tx[1].len = sizeof(kEraseValue) - 1;
    379 
    380   // Slot ID in big endian
    381   uint8_t slot_id[4];
    382   put_uint32(slot_id, slotId);
    383   tx[2].base = slot_id;
    384   tx[2].len = sizeof(slot_id);
    385 
    386   // Prepare buffer for result
    387   struct EseSgBuffer rx;
    388   uint8_t rx_buf[2];
    389   rx.base = rx_buf;
    390   rx.len = sizeof(rx_buf);
    391 
    392   // Send the command
    393   const int rx_len = ese_transceive_sg(session->ese, tx, 3, &rx, 1);
    394 
    395   // Check for errors
    396   if (rx_len < 2 || ese_error(session->ese)) {
    397     ALOGE("Failed to write to slot");
    398     return ESE_APP_RESULT_ERROR_COMM_FAILED;
    399   }
    400   if (rx_len > 2) {
    401     ALOGE("Unexpected response from Weaver applet");
    402     return ESE_APP_RESULT_ERROR_COMM_FAILED;
    403   }
    404   return check_apdu_status(rx_buf);
    405 }
    406 
    407 // TODO: erase all, not currently used
    408