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 */
83 /* Warning processing */
84 case (unsigned char)0x62 : /* State of non-volatile memory is unchanged (further qualification in SW2) */
87 case (unsigned char)0x63 : /* State of non-volatile memory has changed (further qualification in SW2) */
91 case (unsigned char)0x61 : /* SW2 encodes the number of data bytes still available */
96 case (unsigned char)0x64 : /* State of non-volatile memory is unchanged (further qualification in SW2) */
100 case (unsigned char)0x65 : /* State of non-volatile memory has changed (further qualification in SW2) */
104 case (unsigned char)0x66 : /* Security-related issues */
109 case (unsigned char)0x67 : /* SW2:00, Wrong length; no further indication */
113 case (unsigned char)0x68 : /* Functions in CLA not supported (further qualification in SW2) */
117 case (unsigned char)0x69 : /* Command not allowed (further qualification in SW2) */
121 case (unsigned char)0x6A : /* Wrong parameters P1-P2 (further qualification in SW2) */
125 case (unsigned char)0x6B : /* SW2:00, Wrong parameters P1-P2 */
129 case (unsigned char)0x6C : /* Wrong Le field; SW2 encodes the exact number of available data bytes */
133 case (unsigned char)0x6D : /* SW2:00, Instruction code not supported or invalid */
137 case (unsigned char)0x6E : /* SW2:00, Class not supported */
141 case (unsigned char)0x6F : /* SW2:00, No precise diagnosis */
153 int ResponseHelper::getStatus(const ByteArray &response)
157 if (response.size() >= 2)
159 const uint8_t* buffer = response.getBuffer((response.size() - 2));
161 status = ResponseHelper::parseStatusWord(buffer);
167 const ByteArray ResponseHelper::getDataField(const ByteArray &response)
171 if (response.size() > 2)
173 result.assign(response.getBuffer(), response.size() - 2);
179 /* APDUCommand class */
180 APDUCommand::APDUCommand()
183 isExtendedLength = false;
184 memset(&header, 0, sizeof(header));
187 APDUCommand::~APDUCommand()
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)
200 setCommandData(commandData);
201 setMaxResponseSize(maxResponseSize);
206 bool APDUCommand::setCommand(const ByteArray &command)
209 const uint8_t *buffer;
211 uint32_t lengthSize = 1;
213 if (command.size() < sizeof(header)) {
217 buffer = command.getBuffer(offset);
222 memcpy(&header, buffer, sizeof(header));
223 offset += sizeof(header);
225 if (isExtendedLength) {
229 if (command.size() - offset > lengthSize) {
230 unsigned int length = 0;
233 if (isExtendedLength) {
237 length = command.at(offset);
244 setCommandData(ByteArray(command.getBuffer(offset), length));
248 if (command.size() - offset == lengthSize) {
249 if (isExtendedLength) {
252 temp = command.at(offset) << 8;
253 temp |= command.at(offset + 1);
256 setMaxResponseSize(APDUCommand::LE_MAX);
258 setMaxResponseSize(temp);
262 if (command.at(offset) == 0)
263 setMaxResponseSize(256);
265 setMaxResponseSize(command.at(offset));
271 if (command.size() == offset) {
274 _ERR("command stream is not correct, command.size() [%d], offset [%d]", command.size(), offset);
280 bool APDUCommand::setChannel(int type, int channelNum)
286 /* don't apply channel number to below command */
289 case INS_TERMINAL_PROFILE :
291 case INS_TERMINAL_RESPONSE :
295 /* apply channel number */
299 case CLA_CHANNEL_STANDARD : /* standard class byte, two logical channel bits (1~3) */
300 if (channelNum > 0 && channelNum < 4)
306 temp |= (channelNum & 0x03);
313 case CLA_CHANNEL_EXTENDED : /* extended class byte, four logical channel bits (1~15) */
314 if (channelNum > 0 && channelNum < 16)
320 temp |= (channelNum & 0x0F);
337 void APDUCommand::setCLA(unsigned char cla)
346 unsigned char APDUCommand::getCLA() const
351 void APDUCommand::setINS(unsigned char ins)
354 if ((ins & 0xF0) == 0x60 || (ins & 0xF0) == 0x90)
360 unsigned char APDUCommand::getINS() const
365 void APDUCommand::setP1(unsigned char p1)
368 header.param[0] = p1;
371 unsigned char APDUCommand::getP1() const
373 return header.param[0];
376 void APDUCommand::setP2(unsigned char p2)
379 header.param[1] = p2;
382 unsigned char APDUCommand::getP2() const
384 return header.param[1];
387 void APDUCommand::setCommandData(const ByteArray &data)
392 const ByteArray APDUCommand::getCommandData() const
397 void APDUCommand::setMaxResponseSize(unsigned int maxResponseSize)
399 this->maxResponseSize = maxResponseSize;
402 unsigned int APDUCommand::getMaxResponseSize() const
404 return maxResponseSize;
407 bool APDUCommand::getBuffer(ByteArray &array) const
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;
418 temp_len += sizeof(header);
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;
428 lc[0] = commandData.size() & 0x000000FF;
436 /* add command data length */
437 temp_len += commandData.size();
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;
447 } else if (maxResponseSize == 65536) {
451 if (maxResponseSize < 256)
452 le[0] = maxResponseSize & 0x000000FF;
460 temp_buffer = new unsigned char[temp_len];
461 if (temp_buffer == NULL)
467 memcpy(temp_buffer + offset, &header, sizeof(header));
468 offset += sizeof(header);
470 if (commandData.size() > 0) {
471 memcpy(temp_buffer + offset, &lc, lc_len);
474 memcpy(temp_buffer + offset, commandData.getBuffer(), commandData.size());
475 offset += commandData.size();
478 if (maxResponseSize > 0) {
479 memcpy(temp_buffer + offset, &le, le_len);
483 array.assign(temp_buffer, temp_len);
484 delete []temp_buffer;
489 /* APDUHelper class */
490 const ByteArray APDUHelper::generateAPDU(int command,
491 int channel, const ByteArray &data)
498 case COMMAND_OPEN_LOGICAL_CHANNEL :
499 apdu.setCommand(0, APDUCommand::INS_MANAGE_CHANNEL, 0, 0, ByteArray::EMPTY, 1);
500 apdu.getBuffer(result);
503 case COMMAND_CLOSE_LOGICAL_CHANNEL :
504 apdu.setCommand(0, APDUCommand::INS_MANAGE_CHANNEL, 0x80, channel, ByteArray::EMPTY, 0);
505 apdu.getBuffer(result);
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);
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);
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);
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);
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);
540 } /* namespace smartcard_service_api */