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