• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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
get_uint32(uint8_t buf[4])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 
put_uint32(uint8_t buf[4],uint32_t val)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 
check_apdu_status(uint8_t code[2])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 
ese_weaver_session_init(struct EseWeaverSession * session)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 
ese_weaver_session_open(struct EseInterface * ese,struct EseWeaverSession * session)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
ese_weaver_session_close(struct EseWeaverSession * session)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 
ese_weaver_get_num_slots(struct EseWeaverSession * session,uint32_t * numSlots)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 
ese_weaver_write(struct EseWeaverSession * session,uint32_t slotId,const uint8_t * key,const uint8_t * value)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 
ese_weaver_read(struct EseWeaverSession * session,uint32_t slotId,const uint8_t * key,uint8_t * value,uint32_t * timeout)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 
ese_weaver_erase_value(struct EseWeaverSession * session,uint32_t slotId)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