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