Fix the Prevent problems
[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                 default :
84                         result *= -1;
85                         break;
86                 }
87
88                 return result;
89         }
90
91         int ResponseHelper::getStatus(const ByteArray &response)
92         {
93                 int status = 0;
94
95                 if (response.size() >= 2)
96                 {
97                         status = ResponseHelper::parseStatusWord(response.getBuffer((response.size() - 2)));
98                 }
99
100                 return status;
101         }
102
103         const ByteArray ResponseHelper::getDataField(const ByteArray &response)
104         {
105                 ByteArray result;
106
107                 if (response.size() > 2)
108                 {
109                         result.assign(response.getBuffer(), response.size() - 2);
110                 }
111
112                 return result;
113         }
114
115         /* APDUCommand class */
116         APDUCommand::APDUCommand()
117         {
118                 maxResponseSize = 0;
119                 isExtendedLength = false;
120                 memset(&header, 0, sizeof(header));
121         }
122
123         APDUCommand::~APDUCommand()
124         {
125         }
126
127         bool APDUCommand::setCommand(unsigned char cla, unsigned char ins,
128                 unsigned char p1, unsigned char p2,
129                 const ByteArray &commandData,
130                 unsigned int maxResponseSize)
131         {
132                 setCLA(cla);
133                 setINS(ins);
134                 setP1(p1);
135                 setP2(p2);
136                 setCommandData(commandData);
137                 setMaxResponseSize(maxResponseSize);
138
139                 return true;
140         }
141
142         bool APDUCommand::setCommand(const ByteArray &command)
143         {
144                 bool result = false;
145                 uint32_t offset = 0;
146                 uint32_t lengthSize = 1;
147
148                 if (command.size() < sizeof(header))
149                 {
150                         return false;
151                 }
152
153                 memcpy(&header, command.getBuffer(offset), sizeof(header));
154                 offset += sizeof(header);
155
156                 if (isExtendedLength)
157                 {
158                         lengthSize = 2;
159                 }
160
161                 if (command.size() - offset > lengthSize)
162                 {
163                         unsigned int length = 0;
164
165                         /* data exist */
166                         if (isExtendedLength)
167                         {
168                                 /* TODO */
169                                 offset += 2;
170                         }
171                         else
172                         {
173                                 length = command.at(offset);
174                                 offset += 1;
175                         }
176
177                         setCommandData(ByteArray(command.getBuffer(offset), length));
178                         offset += length;
179                 }
180
181                 if (command.size() - offset == lengthSize)
182                 {
183                         if (isExtendedLength)
184                         {
185                                 unsigned int temp;
186
187                                 temp = command.at(offset) << 8;
188                                 temp |= command.at(offset + 1);
189
190                                 if (temp == 0)
191                                         setMaxResponseSize(APDUCommand::LE_MAX);
192                                 else
193                                         setMaxResponseSize(temp);
194
195                                 offset += 2;
196                         }
197                         else
198                         {
199                                 if (command.at(offset) == 0)
200                                         setMaxResponseSize(APDUCommand::LE_MAX);
201                                 else
202                                         setMaxResponseSize(command.at(offset));
203
204                                 offset += 1;
205                         }
206                 }
207
208                 if (command.size() == offset)
209                 {
210                         result = true;
211                 }
212                 else
213                 {
214                         _ERR("command stream is not correct, command.size() [%d], offset [%d]", command.size(), offset);
215                 }
216
217                 return result;
218         }
219
220         bool APDUCommand::setChannel(int type, int channelNum)
221         {
222                 bool result = false;
223
224                 if (channelNum != 0)
225                 {
226                         /* don't apply channel number to below command */
227                         switch (getINS())
228                         {
229                         case INS_TERMINAL_PROFILE :
230                         case INS_FETCH :
231                         case INS_ENVELOPE :
232                         case INS_TERMINAL_RESPONSE :
233                                 result = true;
234                                 break;
235
236                         /* apply channel number */
237                         default :
238                                 switch (type)
239                                 {
240                                 case CLA_CHANNEL_STANDARD : /* standard class byte, two logical channel bits (1~3) */
241                                         if (channelNum > 0 && channelNum < 4)
242                                         {
243                                                 unsigned char temp;
244
245                                                 temp = getCLA();
246                                                 temp &= ~0x03;
247                                                 temp |= (channelNum & 0x03);
248                                                 setCLA(temp);
249
250                                                 result = true;
251                                         }
252                                         break;
253
254                                 case CLA_CHANNEL_EXTENDED : /* extended class byte, four logical channel bits (1~15) */
255                                         if (channelNum > 0 && channelNum < 16)
256                                         {
257                                                 unsigned char temp;
258
259                                                 temp = getCLA();
260                                                 temp &= ~0x0F;
261                                                 temp |= (channelNum & 0x0F);
262                                                 setCLA(temp);
263
264                                                 result = true;
265                                         }
266                                         break;
267
268                                 default :
269                                         break;
270                                 }
271                                 break;
272                         }
273                 }
274
275                 return result;
276         }
277
278         void APDUCommand::setCLA(unsigned char cla)
279         {
280                 /* check criteria */
281                 if (cla == 0xFF)
282                         return;
283
284                 header.cla = cla;
285         }
286
287         unsigned char APDUCommand::getCLA() const
288         {
289                 return header.cla;
290         }
291
292         void APDUCommand::setINS(unsigned char ins)
293         {
294                 /* check criteria */
295                 if ((ins & 0xF0) == 0x60 || (ins & 0xF0) == 0x90)
296                         return;
297
298                 header.ins = ins;
299         }
300
301         unsigned char APDUCommand::getINS() const
302         {
303                 return header.ins;
304         }
305
306         void APDUCommand::setP1(unsigned char p1)
307         {
308                 /* check criteria */
309                 header.param[0] = p1;
310         }
311
312         unsigned char APDUCommand::getP1() const
313         {
314                 return header.param[0];
315         }
316
317         void APDUCommand::setP2(unsigned char p2)
318         {
319                 /* check criteria */
320                 header.param[1] = p2;
321         }
322
323         unsigned char APDUCommand::getP2() const
324         {
325                 return header.param[1];
326         }
327
328         void APDUCommand::setCommandData(const ByteArray &data)
329         {
330                 commandData = data;
331         }
332
333         const ByteArray APDUCommand::getCommandData() const
334         {
335                 return commandData;
336         }
337
338         void APDUCommand::setMaxResponseSize(unsigned int maxResponseSize)
339         {
340                 this->maxResponseSize = maxResponseSize;
341         }
342
343         unsigned int APDUCommand::getMaxResponseSize() const
344         {
345                 return maxResponseSize;
346         }
347
348         bool APDUCommand::getBuffer(ByteArray &array) const
349         {
350                 unsigned char *temp_buffer = NULL;
351                 unsigned int temp_len = 0;
352                 unsigned char lc[3] = { 0, };
353                 unsigned int lc_len = 0;
354                 unsigned char le[3] = { 0, };
355                 unsigned int le_len = 0;
356                 unsigned int offset = 0;
357
358                 /* */
359                 temp_len += sizeof(header);
360
361                 /* calculate lc length */
362                 if (commandData.size() > 0)
363                 {
364                         if (isExtendedLength/*commandData.size() > 255*/)
365                         {
366                                 lc[1] = (commandData.size() >> 8) & 0x000000FF;
367                                 lc[2] = commandData.size() & 0x000000FF;
368
369                                 lc_len = 3;
370                         }
371                         else
372                         {
373                                 lc[0] = commandData.size() & 0x000000FF;
374
375                                 lc_len = 1;
376                         }
377                 }
378
379                 temp_len += lc_len;
380
381                 /* add command data length */
382                 temp_len += commandData.size();
383
384                 /* calculate le length */
385                 if (maxResponseSize > 0)
386                 {
387                         if (isExtendedLength/*commandData.size() > 255*/)
388                         {
389                                 if (maxResponseSize < 65536)
390                                 {
391                                         le[1] = (maxResponseSize >> 8) & 0x000000FF;
392                                         le[2] = maxResponseSize & 0x000000FF;
393
394                                         le_len = 3;
395                                 }
396                                 else if (maxResponseSize == 65536)
397                                 {
398                                         le_len = 2;
399                                 }
400                         }
401                         else
402                         {
403                                 if (maxResponseSize < 256)
404                                         le[0] = maxResponseSize & 0x000000FF;
405
406                                 le_len = 1;
407                         }
408                 }
409
410                 temp_len += le_len;
411
412                 temp_buffer = new unsigned char[temp_len];
413                 if (temp_buffer == NULL)
414                         return false;
415
416                 /* fill data */
417                 offset = 0;
418
419                 memcpy(temp_buffer + offset, &header, sizeof(header));
420                 offset += sizeof(header);
421
422                 if (commandData.size() > 0)
423                 {
424                         memcpy(temp_buffer + offset, &lc, lc_len);
425                         offset += lc_len;
426
427                         memcpy(temp_buffer + offset, commandData.getBuffer(), commandData.size());
428                         offset += commandData.size();
429                 }
430
431                 if (maxResponseSize > 0)
432                 {
433                         memcpy(temp_buffer + offset, &le, le_len);
434                         offset += le_len;
435                 }
436
437                 array.assign(temp_buffer, temp_len);
438                 delete []temp_buffer;
439
440                 return true;
441         }
442
443         /* APDUHelper class */
444         const ByteArray APDUHelper::generateAPDU(int command,
445                 int channel, const ByteArray &data)
446         {
447                 ByteArray result;
448                 APDUCommand apdu;
449
450                 switch (command)
451                 {
452                 case COMMAND_OPEN_LOGICAL_CHANNEL :
453                         apdu.setCommand(0, APDUCommand::INS_MANAGE_CHANNEL, 0, 0, ByteArray::EMPTY, APDUCommand::LE_MAX);
454                         apdu.getBuffer(result);
455                         break;
456
457                 case COMMAND_CLOSE_LOGICAL_CHANNEL :
458                         apdu.setCommand(0, APDUCommand::INS_MANAGE_CHANNEL, 0x80, channel, ByteArray::EMPTY, 0);
459                         apdu.getBuffer(result);
460                         break;
461
462                 case COMMAND_SELECT_BY_ID :
463                         apdu.setCommand(0, APDUCommand::INS_SELECT_FILE, APDUCommand::P1_SELECT_BY_ID, APDUCommand::P2_SELECT_GET_FCP, data, 0);
464                         apdu.getBuffer(result);
465                         break;
466
467                 case COMMAND_SELECT_PARENT_DF :
468                         apdu.setCommand(0, APDUCommand::INS_SELECT_FILE, APDUCommand::P1_SELECT_PARENT_DF, APDUCommand::P2_SELECT_GET_FCP, data, 0);
469                         apdu.getBuffer(result);
470                         break;
471
472                 case COMMAND_SELECT_BY_DF_NAME :
473                         apdu.setCommand(0, APDUCommand::INS_SELECT_FILE, APDUCommand::P1_SELECT_BY_DF_NAME, APDUCommand::P2_SELECT_GET_FCP, data, 0);
474                         apdu.getBuffer(result);
475                         break;
476
477                 case COMMAND_SELECT_BY_PATH :
478                         apdu.setCommand(0, APDUCommand::INS_SELECT_FILE, APDUCommand::P1_SELECT_BY_PATH, APDUCommand::P2_SELECT_GET_FCP, data, 0);
479                         apdu.getBuffer(result);
480                         break;
481
482                 case COMMAND_SELECT_BY_PATH_FROM_CURRENT_DF :
483                         apdu.setCommand(0, APDUCommand::INS_SELECT_FILE, APDUCommand::P1_SELECT_BY_PATH_FROM_CURRENT_DF, APDUCommand::P2_SELECT_GET_FCP, data, 0);
484                         apdu.getBuffer(result);
485                         break;
486
487                 default :
488                         break;
489                 }
490
491                 return result;
492         }
493
494 } /* namespace smartcard_service_api */