Implement raising exceptions
[platform/core/connectivity/smartcard-service.git] / common / APDUHelper.cpp
1 /*
2 * Copyright (c) 2012, 2013 Samsung Electronics Co., Ltd.
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 qualification */
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         unsigned char ResponseHelper::getSW1()
169         {
170                 return sw[0];
171         }
172
173         unsigned char ResponseHelper::getSW2()
174         {
175                 return sw[1];
176         }
177
178         ByteArray ResponseHelper::getDataField()
179         {
180                 return dataField;
181         }
182
183         ByteArray ResponseHelper::getDataField(const ByteArray &response)
184         {
185                 ByteArray result;
186
187                 if (response.getLength() > 2)
188                 {
189                         result.setBuffer(response.getBuffer(), response.getLength() - 2);
190                 }
191
192                 return result;
193         }
194
195         /* APDUCommand class */
196         APDUCommand::APDUCommand()
197         {
198                 maxResponseSize = 0;
199                 isExtendedLength = false;
200                 memset(&header, 0, sizeof(header));
201         }
202
203         APDUCommand::~APDUCommand()
204         {
205         }
206
207         bool APDUCommand::setCommand(unsigned char cla, unsigned char ins, unsigned char p1, unsigned char p2, ByteArray commandData, unsigned int maxResponseSize)
208         {
209                 setCLA(cla);
210                 setINS(ins);
211                 setP1(p1);
212                 setP2(p2);
213                 setCommandData(commandData);
214                 setMaxResponseSize(maxResponseSize);
215
216                 return true;
217         }
218
219         bool APDUCommand::setCommand(const ByteArray &command)
220         {
221                 bool result = false;
222                 uint32_t offset = 0;
223                 uint32_t lengthSize = 1;
224
225                 if (command.getLength() < sizeof(header))
226                 {
227                         return false;
228                 }
229
230                 memcpy(&header, command.getBuffer(offset), sizeof(header));
231                 offset += sizeof(header);
232
233                 if (isExtendedLength)
234                 {
235                         lengthSize = 2;
236                 }
237
238                 if (command.getLength() - offset > lengthSize)
239                 {
240                         unsigned int length = 0;
241
242                         /* data exist */
243                         if (isExtendedLength)
244                         {
245                                 /* TODO */
246                                 offset += 2;
247                         }
248                         else
249                         {
250                                 length = command.getAt(offset);
251                                 offset += 1;
252                         }
253
254                         setCommandData(ByteArray(command.getBuffer(offset), length));
255                         offset += length;
256                 }
257
258                 if (command.getLength() - offset == lengthSize)
259                 {
260                         if (isExtendedLength)
261                         {
262                                 /* TODO */
263                                 offset += 2;
264                         }
265                         else
266                         {
267                                 setMaxResponseSize(command.getAt(offset));
268                                 offset += 1;
269                         }
270                 }
271
272                 if (command.getLength() == offset)
273                 {
274                         result = true;
275                 }
276                 else
277                 {
278                         SCARD_DEBUG_ERR("command stream is not correct, command.getLength() [%d], offset [%d]", command.getLength(), offset);
279                 }
280
281                 return result;
282         }
283
284         bool APDUCommand::setChannel(int type, int channelNum)
285         {
286                 bool result = false;
287
288                 if (channelNum != 0)
289                 {
290                         /* don't apply channel number to below command */
291                         switch (getINS())
292                         {
293                         case INS_TERMINAL_PROFILE :
294                         case INS_FETCH :
295                         case INS_ENVELOPE :
296                         case INS_TERMINAL_RESPONSE :
297                                 result = true;
298                                 break;
299
300                         /* apply channel number */
301                         default :
302                                 switch (type)
303                                 {
304                                 case CLA_CHANNEL_STANDARD : /* standard class byte, two logical channel bits (1~3) */
305                                         if (channelNum > 0 && channelNum < 4)
306                                         {
307                                                 unsigned char temp;
308
309                                                 temp = getCLA();
310                                                 temp &= ~0x03;
311                                                 temp |= (channelNum & 0x03);
312                                                 setCLA(temp);
313
314                                                 result = true;
315                                         }
316                                         break;
317
318                                 case CLA_CHANNEL_EXTENDED : /* extended class byte, four logical channel bits (1~15) */
319                                         if (channelNum > 0 && channelNum < 16)
320                                         {
321                                                 unsigned char temp;
322
323                                                 temp = getCLA();
324                                                 temp &= ~0x0F;
325                                                 temp |= (channelNum & 0x0F);
326                                                 setCLA(temp);
327
328                                                 result = true;
329                                         }
330                                         break;
331
332                                 default :
333                                         break;
334                                 }
335                                 break;
336                         }
337                 }
338
339                 return result;
340         }
341
342         void APDUCommand::setCLA(unsigned char cla)
343         {
344                 /* check criteria */
345                 if (cla == 0xFF)
346                         return;
347
348                 header.cla = cla;
349         }
350
351         unsigned char APDUCommand::getCLA()
352         {
353                 return header.cla;
354         }
355
356         void APDUCommand::setINS(unsigned char ins)
357         {
358                 /* check criteria */
359                 if ((ins & 0xF0) == 0x60 || (ins & 0xF0) == 0x90)
360                         return;
361
362                 header.ins = ins;
363         }
364
365         unsigned char APDUCommand::getINS()
366         {
367                 return header.ins;
368         }
369
370         void APDUCommand::setP1(unsigned char p1)
371         {
372                 /* check criteria */
373                 header.param[0] = p1;
374         }
375
376         unsigned char APDUCommand::getP1()
377         {
378                 return header.param[0];
379         }
380
381         void APDUCommand::setP2(unsigned char p2)
382         {
383                 /* check criteria */
384                 header.param[1] = p2;
385         }
386
387         unsigned char APDUCommand::getP2()
388         {
389                 return header.param[1];
390         }
391
392         void APDUCommand::setCommandData(const ByteArray &data)
393         {
394                 commandData = data;
395         }
396
397         ByteArray APDUCommand::getCommandData()
398         {
399                 return commandData;
400         }
401
402         void APDUCommand::setMaxResponseSize(unsigned int maxResponseSize)
403         {
404                 this->maxResponseSize = maxResponseSize;
405         }
406
407         unsigned int APDUCommand::setMaxResponseSize()
408         {
409                 return maxResponseSize;
410         }
411
412         bool APDUCommand::getBuffer(ByteArray &array)
413         {
414                 unsigned char *temp_buffer = NULL;
415                 unsigned int temp_len = 0;
416                 unsigned char lc[3] = { 0, };
417                 unsigned int lc_len = 0;
418                 unsigned char le[3] = { 0, };
419                 unsigned int le_len = 0;
420                 unsigned int offset = 0;
421
422                 /* */
423                 temp_len += sizeof(header);
424
425                 /* calculate lc length */
426                 if (commandData.getLength() > 0)
427                 {
428                         if (isExtendedLength/*commandData.getLength() > 255*/)
429                         {
430                                 lc[1] = (commandData.getLength() >> 8) & 0x000000FF;
431                                 lc[2] = commandData.getLength() & 0x000000FF;
432
433                                 lc_len = 3;
434                         }
435                         else
436                         {
437                                 lc[0] = commandData.getLength() & 0x000000FF;
438
439                                 lc_len = 1;
440                         }
441                 }
442
443                 temp_len += lc_len;
444
445                 /* add command data length */
446                 temp_len += commandData.getLength();
447
448                 /* calculate le length */
449                 if (maxResponseSize > 0)
450                 {
451                         if (isExtendedLength/*commandData.getLength() > 255*/)
452                         {
453                                 if (maxResponseSize < 65536)
454                                 {
455                                         le[1] = (maxResponseSize >> 8) & 0x000000FF;
456                                         le[2] = maxResponseSize & 0x000000FF;
457
458                                         le_len = 3;
459                                 }
460                                 else if (maxResponseSize == 65536)
461                                 {
462                                         le_len = 2;
463                                 }
464                         }
465                         else
466                         {
467                                 if (maxResponseSize != 256)
468                                         le[0] = maxResponseSize & 0x000000FF;
469
470                                 le_len = 1;
471                         }
472                 }
473
474                 temp_len += le_len;
475
476                 temp_buffer = new unsigned char[temp_len];
477                 if (temp_buffer == NULL)
478                         return false;
479
480                 /* fill data */
481                 offset = 0;
482
483                 memcpy(temp_buffer + offset, &header, sizeof(header));
484                 offset += sizeof(header);
485
486                 if (commandData.getLength() > 0)
487                 {
488                         memcpy(temp_buffer + offset, &lc, lc_len);
489                         offset += lc_len;
490
491                         memcpy(temp_buffer + offset, commandData.getBuffer(), commandData.getLength());
492                         offset += commandData.getLength();
493                 }
494
495                 if (maxResponseSize > 0)
496                 {
497                         memcpy(temp_buffer + offset, &le, le_len);
498                         offset += le_len;
499                 }
500
501                 array.setBuffer(temp_buffer, temp_len);
502                 delete []temp_buffer;
503
504                 return true;
505         }
506
507         /* APDUHelper class */
508         ByteArray APDUHelper::generateAPDU(int command, int channel, ByteArray data)
509         {
510                 ByteArray result;
511                 APDUCommand apdu;
512
513                 switch (command)
514                 {
515                 case COMMAND_OPEN_LOGICAL_CHANNEL :
516                         apdu.setCommand(0, APDUCommand::INS_MANAGE_CHANNEL, 0, 0, ByteArray::EMPTY, 1);
517                         apdu.getBuffer(result);
518                         break;
519
520                 case COMMAND_CLOSE_LOGICAL_CHANNEL :
521                         apdu.setCommand(0, APDUCommand::INS_MANAGE_CHANNEL, 0x80, channel, ByteArray::EMPTY, 0);
522                         apdu.getBuffer(result);
523                         break;
524
525                 case COMMAND_SELECT_BY_ID :
526                         apdu.setCommand(0, APDUCommand::INS_SELECT_FILE, APDUCommand::P1_SELECT_BY_ID, APDUCommand::P2_SELECT_GET_FCP, data, 0);
527                         apdu.getBuffer(result);
528                         break;
529
530                 case COMMAND_SELECT_PARENT_DF :
531                         apdu.setCommand(0, APDUCommand::INS_SELECT_FILE, APDUCommand::P1_SELECT_PARENT_DF, APDUCommand::P2_SELECT_GET_FCP, data, 0);
532                         apdu.getBuffer(result);
533                         break;
534
535                 case COMMAND_SELECT_BY_DF_NAME :
536                         apdu.setCommand(0, APDUCommand::INS_SELECT_FILE, APDUCommand::P1_SELECT_BY_DF_NAME, APDUCommand::P2_SELECT_GET_FCP, data, 0);
537                         apdu.getBuffer(result);
538                         break;
539
540                 case COMMAND_SELECT_BY_PATH :
541                         apdu.setCommand(0, APDUCommand::INS_SELECT_FILE, APDUCommand::P1_SELECT_BY_PATH, APDUCommand::P2_SELECT_GET_FCP, data, 0);
542                         apdu.getBuffer(result);
543                         break;
544
545                 case COMMAND_SELECT_BY_PATH_FROM_CURRENT_DF :
546                         apdu.setCommand(0, APDUCommand::INS_SELECT_FILE, APDUCommand::P1_SELECT_BY_PATH_FROM_CURRENT_DF, APDUCommand::P2_SELECT_GET_FCP, data, 0);
547                         apdu.getBuffer(result);
548                         break;
549
550                 default :
551                         break;
552                 }
553
554                 return result;
555         }
556
557 } /* namespace smartcard_service_api */