update the latest source
[framework/system/smartcard-service.git] / common / APDUHelper.cpp
1 /*
2 * Copyright (c) 2012 Samsung Electronics Co., Ltd All Rights Reserved
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
18 /* standard library header */
19 #include <stdio.h>
20 #include <string.h>
21
22 /* SLP library header */
23
24 /* local header */
25 #include "Debug.h"
26 #include "APDUHelper.h"
27
28 namespace smartcard_service_api
29 {
30         /* ResponseHelper class */
31         ResponseHelper::ResponseHelper()
32         {
33         }
34
35         ResponseHelper::ResponseHelper(const ByteArray &response)
36         {
37                 setResponse(response);
38         }
39
40         ResponseHelper::~ResponseHelper()
41         {
42         }
43
44         bool ResponseHelper::setResponse(const ByteArray &response)
45         {
46                 bool result = false;
47                 status = 0;
48                 dataField.releaseBuffer();
49
50                 this->response = response;
51
52                 if (response.getLength() >= 2)
53                 {
54                         sw[0] = response.getReverseAt(1);
55                         sw[1] = response.getReverseAt(0);
56
57                         status = parseStatusWord(sw);
58
59                         if (response.getLength() > 2)
60                         {
61                                 dataField.setBuffer(response.getBuffer(), response.getLength() - 2);
62                         }
63
64                         result = true;
65                 }
66
67                 return result;
68         }
69
70         int ResponseHelper::parseStatusWord(unsigned char *sw)
71         {
72                 int result = 0;
73
74                 switch (sw[0])
75                 {
76                 /* Normal processing */
77                 case (unsigned char)0x90 : /* SW2:00, No further qulification */
78                         break;
79
80                 case (unsigned char)0x91 : /* extra information */
81                         break;
82
83                 case (unsigned char)0x61 : /* SW2 encodes the number of data bytes still available */
84                         break;
85
86                 /* Warning processing */
87                 case (unsigned char)0x62 : /* State of non-volatile memory is unchanged (further qualification in SW2) */
88                         break;
89
90                 case (unsigned char)0x63 : /* State of non-volatile memory has changed (further qualification in SW2) */
91                         break;
92
93                 /* Execution error */
94                 case (unsigned char)0x64 : /* State of non-volatile memory is unchanged (further qualification in SW2) */
95                         result = -1;
96                         break;
97
98                 case (unsigned char)0x65 : /* State of non-volatile memory has changed (further qualification in SW2) */
99                         result = -1;
100                         break;
101
102                 case (unsigned char)0x66 : /* Security-related issues */
103                         result = -1;
104                         break;
105
106                 /* Checking error */
107                 case (unsigned char)0x67 : /* SW2:00, Wrong length; no further indication */
108                         result = -1;
109                         break;
110
111                 case (unsigned char)0x68 : /* Functions in CLA not supported (further qualification in SW2) */
112                         result = -1;
113                         break;
114
115                 case (unsigned char)0x69 : /* Command not allowed (further qualification in SW2) */
116                         result = -1;
117                         break;
118
119                 case (unsigned char)0x6A : /* Wrong parameters P1-P2 (further qualification in SW2) */
120                         result = -1;
121                         break;
122
123                 case (unsigned char)0x6B : /* SW2:00, Wrong parameters P1-P2 */
124                         result = -1;
125                         break;
126
127                 case (unsigned char)0x6C : /* Wrong Le field; SW2 encodes the exact number of available data bytes */
128                         result = -1;
129                         break;
130
131                 case (unsigned char)0x6D : /* SW2:00, Instruction code not supported or invalid */
132                         result = -1;
133                         break;
134
135                 case (unsigned char)0x6E : /* SW2:00, Class not supported */
136                         result = -1;
137                         break;
138
139                 case (unsigned char)0x6F : /* SW2:00, No precise diagnosis */
140                         result = -1;
141                         break;
142
143                 default :
144                         result = -1;
145                         break;
146                 }
147
148                 return result;
149         }
150
151         int ResponseHelper::getStatus()
152         {
153                 return status;
154         }
155
156         int ResponseHelper::getStatus(const ByteArray &response)
157         {
158                 int status = 0;
159
160                 if (response.getLength() >= 2)
161                 {
162                         status = ResponseHelper::parseStatusWord(response.getBuffer((response.getLength() - 2)));
163                 }
164
165                 return status;
166         }
167
168         ByteArray ResponseHelper::getDataField()
169         {
170                 return dataField;
171         }
172
173         ByteArray ResponseHelper::getDataField(const ByteArray &response)
174         {
175                 ByteArray result;
176
177                 if (response.getLength() > 2)
178                 {
179                         result.setBuffer(response.getBuffer(), response.getLength() - 2);
180                 }
181
182                 return result;
183         }
184
185         /* APDUCommand class */
186         APDUCommand::APDUCommand()
187         {
188                 maxResponseSize = 0;
189                 isExtendedLength = false;
190                 memset(&header, 0, sizeof(header));
191         }
192
193         APDUCommand::~APDUCommand()
194         {
195         }
196
197         bool APDUCommand::setCommand(unsigned char cla, unsigned char ins, unsigned char p1, unsigned char p2, ByteArray commandData, unsigned int maxResponseSize)
198         {
199                 setCLA(cla);
200                 setINS(ins);
201                 setP1(p1);
202                 setP2(p2);
203                 setCommandData(commandData);
204                 setMaxResponseSize(maxResponseSize);
205
206                 return true;
207         }
208
209         bool APDUCommand::setCommand(const ByteArray &command)
210         {
211                 bool result = false;
212                 uint32_t offset = 0;
213                 uint32_t lengthSize = 1;
214
215                 if (command.getLength() < sizeof(header))
216                 {
217                         return false;
218                 }
219
220                 memcpy(&header, command.getBuffer(offset), sizeof(header));
221                 offset += sizeof(header);
222
223                 if (isExtendedLength)
224                 {
225                         lengthSize = 2;
226                 }
227
228                 if (command.getLength() - offset > lengthSize)
229                 {
230                         unsigned int length = 0;
231
232                         /* data exist */
233                         if (isExtendedLength)
234                         {
235                                 /* TODO */
236                                 offset += 2;
237                         }
238                         else
239                         {
240                                 length = command.getAt(offset);
241                                 offset += 1;
242                         }
243
244                         setCommandData(ByteArray(command.getBuffer(offset), length));
245                         offset += length;
246                 }
247
248                 if (command.getLength() - offset == lengthSize)
249                 {
250                         if (isExtendedLength)
251                         {
252                                 /* TODO */
253                                 offset += 2;
254                         }
255                         else
256                         {
257                                 setMaxResponseSize(command.getAt(offset));
258                                 offset += 1;
259                         }
260                 }
261
262                 if (command.getLength() == offset)
263                 {
264                         result = true;
265                 }
266                 else
267                 {
268                         SCARD_DEBUG_ERR("command stream is not correct, command.getLength() [%d], offset [%d]", command.getLength(), offset);
269                 }
270
271                 return result;
272         }
273
274         bool APDUCommand::setChannel(int type, int channelNum)
275         {
276                 bool result = false;
277
278                 if (channelNum != 0)
279                 {
280                         switch (type)
281                         {
282                         case 0 :
283                                 if (channelNum > 0 && channelNum < 4)
284                                 {
285                                         unsigned char temp;
286
287                                         temp = getCLA();
288                                         temp &= ~0x03;
289                                         temp |= (channelNum & 0x03);
290                                         setCLA(temp);
291
292                                         result = true;
293                                 }
294                                 break;
295
296                         default :
297                                 break;
298                         }
299                 }
300
301                 return result;
302         }
303
304         void APDUCommand::setCLA(unsigned char cla)
305         {
306                 /* check criteria */
307                 if (cla == 0xFF)
308                         return;
309
310                 header.cla = cla;
311         }
312
313         unsigned char APDUCommand::getCLA()
314         {
315                 return header.cla;
316         }
317
318         void APDUCommand::setINS(unsigned char ins)
319         {
320                 /* check criteria */
321                 if ((ins & 0xF0) == 0x60 || (ins & 0xF0) == 0x90)
322                         return;
323
324                 header.ins = ins;
325         }
326
327         unsigned char APDUCommand::getINS()
328         {
329                 return header.ins;
330         }
331
332         void APDUCommand::setP1(unsigned char p1)
333         {
334                 /* check criteria */
335                 header.param[0] = p1;
336         }
337
338         unsigned char APDUCommand::getP1()
339         {
340                 return header.param[0];
341         }
342
343         void APDUCommand::setP2(unsigned char p2)
344         {
345                 /* check criteria */
346                 header.param[1] = p2;
347         }
348
349         unsigned char APDUCommand::getP2()
350         {
351                 return header.param[1];
352         }
353
354         void APDUCommand::setCommandData(const ByteArray &data)
355         {
356                 commandData = data;
357         }
358
359         ByteArray APDUCommand::getCommandData()
360         {
361                 return commandData;
362         }
363
364         void APDUCommand::setMaxResponseSize(unsigned int maxResponseSize)
365         {
366                 this->maxResponseSize = maxResponseSize;
367         }
368
369         unsigned int APDUCommand::setMaxResponseSize()
370         {
371                 return maxResponseSize;
372         }
373
374         bool APDUCommand::getBuffer(ByteArray &array)
375         {
376                 unsigned char *temp_buffer = NULL;
377                 unsigned int temp_len = 0;
378                 unsigned char lc[3] = { 0, };
379                 unsigned int lc_len = 0;
380                 unsigned char le[3] = { 0, };
381                 unsigned int le_len = 0;
382                 unsigned int offset = 0;
383
384                 /* */
385                 temp_len += sizeof(header);
386
387                 /* calculate lc length */
388                 if (commandData.getLength() > 0)
389                 {
390                         if (isExtendedLength/*commandData.getLength() > 255*/)
391                         {
392                                 lc[1] = (commandData.getLength() >> 8) & 0x000000FF;
393                                 lc[2] = commandData.getLength() & 0x000000FF;
394
395                                 lc_len = 3;
396                         }
397                         else
398                         {
399                                 lc[0] = commandData.getLength() & 0x000000FF;
400
401                                 lc_len = 1;
402                         }
403                 }
404
405                 temp_len += lc_len;
406
407                 /* add command data length */
408                 temp_len += commandData.getLength();
409
410                 /* calculate le length */
411                 if (maxResponseSize > 0)
412                 {
413                         if (isExtendedLength/*commandData.getLength() > 255*/)
414                         {
415                                 if (maxResponseSize < 65536)
416                                 {
417                                         le[1] = (maxResponseSize >> 8) & 0x000000FF;
418                                         le[2] = maxResponseSize & 0x000000FF;
419
420                                         le_len = 3;
421                                 }
422                                 else if (maxResponseSize == 65536)
423                                 {
424                                         le_len = 2;
425                                 }
426                         }
427                         else
428                         {
429                                 if (maxResponseSize != 256)
430                                         le[0] = maxResponseSize & 0x000000FF;
431
432                                 le_len = 1;
433                         }
434                 }
435
436                 temp_len += le_len;
437
438                 temp_buffer = new unsigned char[temp_len];
439                 if (temp_buffer == NULL)
440                         return false;
441
442                 /* fill data */
443                 offset = 0;
444
445                 memcpy(temp_buffer + offset, &header, sizeof(header));
446                 offset += sizeof(header);
447
448                 if (commandData.getLength() > 0)
449                 {
450                         memcpy(temp_buffer + offset, &lc, lc_len);
451                         offset += lc_len;
452
453                         memcpy(temp_buffer + offset, commandData.getBuffer(), commandData.getLength());
454                         offset += commandData.getLength();
455                 }
456
457                 if (maxResponseSize > 0)
458                 {
459                         memcpy(temp_buffer + offset, &le, le_len);
460                         offset += le_len;
461                 }
462
463                 array.setBuffer(temp_buffer, temp_len);
464                 delete []temp_buffer;
465
466                 return true;
467         }
468
469         /* APDUHelper class */
470         ByteArray APDUHelper::generateAPDU(int command, int channel, ByteArray data)
471         {
472                 ByteArray result;
473                 APDUCommand apdu;
474
475                 switch (command)
476                 {
477                 case COMMAND_OPEN_LOGICAL_CHANNEL :
478                         apdu.setCommand(0, APDUCommand::INS_MANAGE_CHANNEL, 0, 0, ByteArray::EMPTY, 1);
479                         apdu.getBuffer(result);
480                         break;
481
482                 case COMMAND_CLOSE_LOGICAL_CHANNEL :
483                         apdu.setCommand(0, APDUCommand::INS_MANAGE_CHANNEL, 0x80, channel, ByteArray::EMPTY, 0);
484                         apdu.getBuffer(result);
485                         break;
486
487                 case COMMAND_SELECT_BY_ID :
488                         apdu.setCommand(0, APDUCommand::INS_SELECT_FILE, APDUCommand::P1_SELECT_BY_ID, APDUCommand::P2_SELECT_GET_FCP, data, 0);
489                         apdu.getBuffer(result);
490                         break;
491
492                 case COMMAND_SELECT_PARENT_DF :
493                         apdu.setCommand(0, APDUCommand::INS_SELECT_FILE, APDUCommand::P1_SELECT_PARENT_DF, APDUCommand::P2_SELECT_GET_FCP, data, 0);
494                         apdu.getBuffer(result);
495                         break;
496
497                 case COMMAND_SELECT_BY_DF_NAME :
498                         apdu.setCommand(0, APDUCommand::INS_SELECT_FILE, APDUCommand::P1_SELECT_BY_DF_NAME, APDUCommand::P2_SELECT_GET_FCP, data, 0);
499                         apdu.getBuffer(result);
500                         break;
501
502                 case COMMAND_SELECT_BY_PATH :
503                         apdu.setCommand(0, APDUCommand::INS_SELECT_FILE, APDUCommand::P1_SELECT_BY_PATH, APDUCommand::P2_SELECT_GET_FCP, data, 0);
504                         apdu.getBuffer(result);
505                         break;
506
507                 case COMMAND_SELECT_BY_PATH_FROM_CURRENT_DF :
508                         apdu.setCommand(0, APDUCommand::INS_SELECT_FILE, APDUCommand::P1_SELECT_BY_PATH_FROM_CURRENT_DF, APDUCommand::P2_SELECT_GET_FCP, data, 0);
509                         apdu.getBuffer(result);
510                         break;
511
512                 default :
513                         break;
514                 }
515
516                 return result;
517         }
518
519 } /* namespace smartcard_service_api */