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