Keyple Plugin PC/SC C++ Library - 2.5.2
Component of the Keyple C++ middleware
CardChannel.cpp
Go to the documentation of this file.
1/******************************************************************************
2 * Copyright (c) 2025 Calypso Networks Association https://calypsonet.org/ *
3 * *
4 * See the NOTICE file(s) distributed with this work for additional *
5 * information regarding copyright ownership. *
6 * *
7 * This program and the accompanying materials are made available under the *
8 * terms of the Eclipse Public License 2.0 which is available at *
9 * http://www.eclipse.org/legal/epl-2.0 *
10 * *
11 * SPDX-License-Identifier: EPL-2.0 *
12 ******************************************************************************/
13
14#include "keyple/plugin/pcsc/cpp/CardChannel.hpp"
15
16#include "PcscUtils.hpp"
17
18#include "keyple/core/util/cpp/KeypleStd.hpp"
19#include "keyple/core/util/cpp/exception/IllegalArgumentException.hpp"
20#include "keyple/plugin/pcsc/cpp/Card.hpp"
21#include "keyple/plugin/pcsc/cpp/exception/CardException.hpp"
22
23namespace keyple {
24namespace plugin {
25namespace pcsc {
26namespace cpp {
27
28using keyple::core::util::cpp::exception::IllegalArgumentException;
29using keyple::plugin::pcsc::cpp::exception::CardException;
30
31CardChannel::CardChannel(const std::shared_ptr<Card> card, const int channel)
32: mChannel(channel)
33, mIsClosed(true)
34, mCard(card)
35{
36
37}
38
39std::shared_ptr<Card>
40CardChannel::getCard() const
41{
42 return mCard;
43}
44
45std::vector<uint8_t>
46CardChannel::transmit(const std::vector<uint8_t>& apduIn)
47{
48 if (apduIn.size() == 0)
49 throw IllegalArgumentException("command cannot be empty");
50
51 /* Make a copy */
52 std::vector<uint8_t> _apduIn = apduIn;
53
54 /* To check */
55 bool t0GetResponse = true;
56 bool t1GetResponse = true;
57
58 /*
59 * Note that we modify the 'command' array in some cases, so it must be
60 * a copy of the application provided data
61 */
62 int n = static_cast<int>(_apduIn.size());
63 bool t0 = mCard->mProtocol == SCARD_PROTOCOL_T0;
64 bool t1 = mCard->mProtocol == SCARD_PROTOCOL_T1;
65
66 if (t0 && (n >= 7) && (_apduIn[4] == 0))
67 throw CardException("Extended len. not supported for T=0");
68
69 if ((t0 || t1) && (n >= 7)) {
70 int lc = _apduIn[4] & 0xff;
71 if (lc != 0) {
72 if (n == lc + 6) {
73 n--;
74 }
75 } else {
76 lc = ((_apduIn[5] & 0xff) << 8) | (_apduIn[6] & 0xff);
77 if (n == lc + 9) {
78 n -= 2;
79 }
80 }
81 }
82
83 bool getresponse = (t0 && t0GetResponse) || (t1 && t1GetResponse);
84 int k = 0;
85 std::vector<uint8_t> result;
86
87 while (true) {
88 if (++k >= 32) {
89 throw CardException("Could not obtain response");
90 }
91
92 char r_apdu[261];
93 DWORD dwRecv = sizeof(r_apdu);
94 uint64_t rv;
95
96 mLogger->debug("transmitApdu - c-apdu >> %\n", _apduIn);
97
98 rv = SCardTransmit(
99 mCard->mHandle,
100 &mCard->mIORequest,
101 (LPCBYTE)_apduIn.data(),
102 static_cast<DWORD>(_apduIn.size()),
103 NULL,
104 (LPBYTE)r_apdu,
105 &dwRecv);
106 if (rv != SCARD_S_SUCCESS) {
107 mLogger->error(
108 "SCardTransmit failed with error: %\n",
109 std::string(pcsc_stringify_error(rv)));
110
111 if (isCardCommunicationError(rv)) {
112 throw CardException("ScardTransmit failed (CARD)");
113 } else {
114 throw CardException("ScardTransmit failed (READER)");
115 }
116 }
117
118 std::vector<uint8_t> response(r_apdu, r_apdu + dwRecv);
119
120 mLogger->debug("transmitApdu - r-apdu << %\n", response);
121
122 int rn = static_cast<int>(response.size());
123 if (getresponse && (rn >= 2)) {
124 /* See ISO 7816/2005, 5.1.3 */
125 if ((rn == 2) && (response[0] == 0x6c)) {
126 // Resend command using SW2 as short Le field
127 _apduIn[n - 1] = response[1];
128 continue;
129 }
130
131 if (response[rn - 2] == 0x61) {
132 /* Issue a GET RESPONSE command with the same CLA using SW2
133 * as short Le field */
134 if (rn > 2)
135 result.insert(
136 result.end(),
137 response.begin(),
138 response.begin() + rn - 2);
139
140 std::vector<uint8_t> getResponse(5);
141 getResponse[0] = _apduIn[0];
142 getResponse[1] = 0xC0;
143 getResponse[2] = 0;
144 getResponse[3] = 0;
145 getResponse[4] = response[rn - 1];
146 n = 5;
147 _apduIn.swap(getResponse);
148 continue;
149 }
150 }
151
152 result.insert(result.end(), response.begin(), response.begin() + rn);
153 break;
154 }
155
156 return result;
157}
158
159} /* namespace cpp */
160} /* namespace pcsc */
161} /* namespace plugin */
162} /* namespace keyple */
bool isCardCommunicationError(uint64_t rv)
Definition: PcscUtils.hpp:95
Definition: Card.cpp:20