blob: a8ac08b386c627c82c77b427a00183c99b37f45c [file] [log] [blame]
Will Drewry92973c72017-04-02 15:04:32 -05001/*
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
Will Drewry695e3182017-04-27 20:08:37 -050027const uint8_t kSelectApplet[] = {0x00, 0xA4, 0x04, 0x00, 0x0d, 0xA0,
28 0x00, 0x00, 0x04, 0x76, 0x50, 0x49,
29 0x58, 0x4C, 0x42, 0x4F, 0x4F, 0x54};
Will Drewry92973c72017-04-02 15:04:32 -050030const 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};
Will Drewry80558582017-04-18 13:44:43 -050039const uint8_t kFactoryReset[] = {0x80, 0x0e, 0x00, 0x00};
40const uint8_t kLockReset[] = {0x80, 0x0e, 0x01, 0x00};
Will Drewry5c2c3b92017-05-09 12:31:10 -050041const uint8_t kLoadMetaClear[] = {0x80, 0x10, 0x00, 0x00};
42const uint8_t kLoadMetaAppend[] = {0x80, 0x10, 0x01, 0x00};
43static const uint16_t kMaxMetadataLoadSize = 1024;
Will Drewry92973c72017-04-02 15:04:32 -050044
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)) {
Will Drewry5c2c3b92017-05-09 12:31:10 -0500212 ALOGE("ese_boot_lock_xget: failed to read lock state (%d)", lock);
Will Drewry92973c72017-04-02 15:04:32 -0500213 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) {
Will Drewry5c2c3b92017-05-09 12:31:10 -0500223 ALOGE("ese_boot_lock_xget: received applet error code %x %x", lockData[0],
224 lockData[1]);
Will Drewry92973c72017-04-02 15:04:32 -0500225 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)) {
Will Drewry5c2c3b92017-05-09 12:31:10 -0500257 ALOGE("ese_boot_lock_get: failed to read lock state (%d).", lock);
Will Drewry92973c72017-04-02 15:04:32 -0500258 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) {
Will Drewry5c2c3b92017-05-09 12:31:10 -0500262 ALOGE("ese_boot_lock_get: SE OS error.");
Will Drewry92973c72017-04-02 15:04:32 -0500263 return ret;
264 }
265 if (rx_len < 5) {
Will Drewry5c2c3b92017-05-09 12:31:10 -0500266 ALOGE("ese_boot_lock_get: communication error");
Will Drewry92973c72017-04-02 15:04:32 -0500267 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) {
Will Drewry5c2c3b92017-05-09 12:31:10 -0500271 ALOGE("ese_boot_lock_get: Applet error: %x %x", reply[0], reply[1]);
Will Drewry92973c72017-04-02 15:04:32 -0500272 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
Will Drewry5c2c3b92017-05-09 12:31:10 -0500285EseAppResult 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
Will Drewry92973c72017-04-02 15:04:32 -0500370ESE_API EseAppResult ese_boot_lock_xset(struct EseBootSession *session,
371 EseBootLockId lockId,
372 const uint8_t *lockData,
373 uint16_t dataLen) {
Will Drewry5c2c3b92017-05-09 12:31:10 -0500374 struct EseSgBuffer tx[3];
Will Drewry92973c72017-04-02 15:04:32 -0500375 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) {
Will Drewry5c2c3b92017-05-09 12:31:10 -0500384 ALOGE("ese_boot_lock_xset: too much data: %hu > %d", dataLen,
Will Drewry92973c72017-04-02 15:04:32 -0500385 kEseBootOwnerKeyMax + 1);
386 return ESE_APP_RESULT_ERROR_ARGUMENTS;
387 }
388
Will Drewry5c2c3b92017-05-09 12:31:10 -0500389 // 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
Will Drewry92973c72017-04-02 15:04:32 -0500411 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
Will Drewry5c2c3b92017-05-09 12:31:10 -0500417 uint8_t lockIdLockValueUseMeta[] = {lockId, lockData[0], 0x1, 0x1};
418 tx[2].base = &lockIdLockValueUseMeta[0];
419 tx[2].len = sizeof(lockIdLockValueUseMeta);
Will Drewry92973c72017-04-02 15:04:32 -0500420
421 uint8_t reply[4]; // App reply or APDU error.
422 rx[0].base = &reply[0];
423 rx[0].len = sizeof(reply);
424
Will Drewry5c2c3b92017-05-09 12:31:10 -0500425 rx_len = ese_transceive_sg(session->ese, tx, 3, rx, 1);
Will Drewry92973c72017-04-02 15:04:32 -0500426 if (rx_len < 2 || ese_error(session->ese)) {
Will Drewry5c2c3b92017-05-09 12:31:10 -0500427 ALOGE("ese_boot_lock_xset: failed to set lock state (%d).", lockId);
Will Drewry92973c72017-04-02 15:04:32 -0500428 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 }
Will Drewry5c2c3b92017-05-09 12:31:10 -0500435 // Expect the full payload plus the applet status and the completion code.
Will Drewry92973c72017-04-02 15:04:32 -0500436 if (rx_len != 4) {
Will Drewry5c2c3b92017-05-09 12:31:10 -0500437 ALOGE("ese_boot_lock_xset: communication error");
Will Drewry92973c72017-04-02 15:04:32 -0500438 return ESE_APP_RESULT_ERROR_COMM_FAILED;
439 }
440 if (reply[0] != 0x0 || reply[1] != 0x0) {
Will Drewry5c2c3b92017-05-09 12:31:10 -0500441 ALOGE("ese_boot_lock_xset: received applet error code %x %x", reply[0],
442 reply[1]);
Will Drewry92973c72017-04-02 15:04:32 -0500443 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
Will Drewry5c2c3b92017-05-09 12:31:10 -0500467 uint8_t lockIdLockValueNoMeta[] = {lockId, lockValue, 0x1, 0x0};
468 tx[2].base = &lockIdLockValueNoMeta[0];
469 tx[2].len = sizeof(lockIdLockValueNoMeta);
Will Drewry92973c72017-04-02 15:04:32 -0500470
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) {
Will Drewry5c2c3b92017-05-09 12:31:10 -0500482 ALOGE("ese_boot_lock_set: SE exception");
Will Drewry92973c72017-04-02 15:04:32 -0500483 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
Will Drewry80558582017-04-18 13:44:43 -0500716ESE_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
Will Drewry92973c72017-04-02 15:04:32 -0500756ESE_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}