2 * Copyright (c) 2012, 2013 Samsung Electronics Co., Ltd.
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
17 /* standard library header */
21 /* SLP library header */
24 #include "smartcard-types.h"
26 #include "APDUHelper.h"
28 namespace smartcard_service_api
30 /* ResponseHelper class */
31 ResponseHelper::ResponseHelper() : status(0)
35 ResponseHelper::ResponseHelper(const ByteArray &response)
37 setResponse(response);
40 ResponseHelper::~ResponseHelper()
44 bool ResponseHelper::setResponse(const ByteArray &response)
47 status = SCARD_ERROR_UNKNOWN;
50 this->response = response;
52 if (response.size() >= 2)
54 sw[0] = response.reverseAt(1);
55 sw[1] = response.reverseAt(0);
57 status = parseStatusWord(sw);
59 if (response.size() > 2)
61 dataField.assign(response.getBuffer(),
71 int ResponseHelper::parseStatusWord(const unsigned char *sw)
73 int result = sw[0] << 8 | sw[1];
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 */
91 int ResponseHelper::getStatus(const ByteArray &response)
95 if (response.size() >= 2)
97 status = ResponseHelper::parseStatusWord(response.getBuffer((response.size() - 2)));
103 const ByteArray ResponseHelper::getDataField(const ByteArray &response)
107 if (response.size() > 2)
109 result.assign(response.getBuffer(), response.size() - 2);
115 /* APDUCommand class */
116 APDUCommand::APDUCommand()
119 isExtendedLength = false;
120 memset(&header, 0, sizeof(header));
123 APDUCommand::~APDUCommand()
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)
136 setCommandData(commandData);
137 setMaxResponseSize(maxResponseSize);
142 bool APDUCommand::setCommand(const ByteArray &command)
146 uint32_t lengthSize = 1;
148 if (command.size() < sizeof(header))
153 memcpy(&header, command.getBuffer(offset), sizeof(header));
154 offset += sizeof(header);
156 if (isExtendedLength)
161 if (command.size() - offset > lengthSize)
163 unsigned int length = 0;
166 if (isExtendedLength)
173 length = command.at(offset);
177 setCommandData(ByteArray(command.getBuffer(offset), length));
181 if (command.size() - offset == lengthSize)
183 if (isExtendedLength)
187 temp = command.at(offset) << 8;
188 temp |= command.at(offset + 1);
191 setMaxResponseSize(APDUCommand::LE_MAX);
193 setMaxResponseSize(temp);
199 if (command.at(offset) == 0)
200 setMaxResponseSize(APDUCommand::LE_MAX);
202 setMaxResponseSize(command.at(offset));
208 if (command.size() == offset)
214 _ERR("command stream is not correct, command.size() [%d], offset [%d]", command.size(), offset);
220 bool APDUCommand::setChannel(int type, int channelNum)
226 /* don't apply channel number to below command */
229 case INS_TERMINAL_PROFILE :
232 case INS_TERMINAL_RESPONSE :
236 /* apply channel number */
240 case CLA_CHANNEL_STANDARD : /* standard class byte, two logical channel bits (1~3) */
241 if (channelNum > 0 && channelNum < 4)
247 temp |= (channelNum & 0x03);
254 case CLA_CHANNEL_EXTENDED : /* extended class byte, four logical channel bits (1~15) */
255 if (channelNum > 0 && channelNum < 16)
261 temp |= (channelNum & 0x0F);
278 void APDUCommand::setCLA(unsigned char cla)
287 unsigned char APDUCommand::getCLA() const
292 void APDUCommand::setINS(unsigned char ins)
295 if ((ins & 0xF0) == 0x60 || (ins & 0xF0) == 0x90)
301 unsigned char APDUCommand::getINS() const
306 void APDUCommand::setP1(unsigned char p1)
309 header.param[0] = p1;
312 unsigned char APDUCommand::getP1() const
314 return header.param[0];
317 void APDUCommand::setP2(unsigned char p2)
320 header.param[1] = p2;
323 unsigned char APDUCommand::getP2() const
325 return header.param[1];
328 void APDUCommand::setCommandData(const ByteArray &data)
333 const ByteArray APDUCommand::getCommandData() const
338 void APDUCommand::setMaxResponseSize(unsigned int maxResponseSize)
340 this->maxResponseSize = maxResponseSize;
343 unsigned int APDUCommand::getMaxResponseSize() const
345 return maxResponseSize;
348 bool APDUCommand::getBuffer(ByteArray &array) const
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;
359 temp_len += sizeof(header);
361 /* calculate lc length */
362 if (commandData.size() > 0)
364 if (isExtendedLength/*commandData.size() > 255*/)
366 lc[1] = (commandData.size() >> 8) & 0x000000FF;
367 lc[2] = commandData.size() & 0x000000FF;
373 lc[0] = commandData.size() & 0x000000FF;
381 /* add command data length */
382 temp_len += commandData.size();
384 /* calculate le length */
385 if (maxResponseSize > 0)
387 if (isExtendedLength/*commandData.size() > 255*/)
389 if (maxResponseSize < 65536)
391 le[1] = (maxResponseSize >> 8) & 0x000000FF;
392 le[2] = maxResponseSize & 0x000000FF;
396 else if (maxResponseSize == 65536)
403 if (maxResponseSize < 256)
404 le[0] = maxResponseSize & 0x000000FF;
412 temp_buffer = new unsigned char[temp_len];
413 if (temp_buffer == NULL)
419 memcpy(temp_buffer + offset, &header, sizeof(header));
420 offset += sizeof(header);
422 if (commandData.size() > 0)
424 memcpy(temp_buffer + offset, &lc, lc_len);
427 memcpy(temp_buffer + offset, commandData.getBuffer(), commandData.size());
428 offset += commandData.size();
431 if (maxResponseSize > 0)
433 memcpy(temp_buffer + offset, &le, le_len);
437 array.assign(temp_buffer, temp_len);
438 delete []temp_buffer;
443 /* APDUHelper class */
444 const ByteArray APDUHelper::generateAPDU(int command,
445 int channel, const ByteArray &data)
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);
457 case COMMAND_CLOSE_LOGICAL_CHANNEL :
458 apdu.setCommand(0, APDUCommand::INS_MANAGE_CHANNEL, 0x80, channel, ByteArray::EMPTY, 0);
459 apdu.getBuffer(result);
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);
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);
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);
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);
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);
494 } /* namespace smartcard_service_api */