Keyple Card Calypso C++ Library 2.1.0
Reference Terminal Reader API for C++
CalypsoCardSelectionAdapter.cpp
Go to the documentation of this file.
1/**************************************************************************************************
2 * Copyright (c) 2022 Calypso Networks Association https://calypsonet.org/ *
3 * *
4 * See the NOTICE file(s) distributed with this work for additional information regarding *
5 * copyright ownership. *
6 * *
7 * This program and the accompanying materials are made available under the terms of the Eclipse *
8 * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0 *
9 * *
10 * SPDX-License-Identifier: EPL-2.0 *
11 **************************************************************************************************/
12
14
15/* Calypsonet Terminal Card */
16#include "ParseException.h"
17
18/* Keyple Card Calypso */
19#include "CalypsoCardAdapter.h"
20#include "CalypsoCardClass.h"
21#include "CalypsoCardConstant.h"
24#include "CmdCardGetDataFci.h"
25#include "CmdCardGetDataFcp.h"
28#include "CmdCardReadRecords.h"
29#include "CmdCardSelectFile.h"
30#include "UnsupportedOperationException.h"
31
32/* Keyple Card Generic */
33#include "CardRequestAdapter.h"
34
35/* Keyple Core Util */
36#include "ByteArrayUtil.h"
37#include "IllegalArgumentException.h"
38#include "KeypleAssert.h"
39#include "Pattern.h"
40#include "PatternSyntaxException.h"
41
42namespace keyple {
43namespace card {
44namespace calypso {
45
46using namespace calypsonet::terminal::card::spi;
47using namespace keyple::core::util;
48using namespace keyple::core::util::cpp;
49using namespace keyple::core::util::cpp::exception;
50
51const int CalypsoCardSelectionAdapter::AID_MIN_LENGTH = 5;
52const int CalypsoCardSelectionAdapter::AID_MAX_LENGTH = 16;
53const int CalypsoCardSelectionAdapter::SW_CARD_INVALIDATED = 0x6283;
54
56: mCardSelector(std::make_shared<CardSelectorAdapter>()) {}
57
59 const std::string& cardProtocol)
60{
61 Assert::getInstance().notEmpty(cardProtocol, "cardProtocol");
62
63 mCardSelector->filterByCardProtocol(cardProtocol);
64
65 return *this;
66}
67
69 const std::string& powerOnDataRegex)
70{
71 Assert::getInstance().notEmpty(powerOnDataRegex, "powerOnDataRegex");
72
73 try {
74 Pattern::compile(powerOnDataRegex);
75 } catch (const PatternSyntaxException& exception) {
76 (void)exception;
77 throw IllegalArgumentException("Invalid regular expression: '" +
78 powerOnDataRegex +
79 "'.");
80 }
81
82 mCardSelector->filterByPowerOnData(powerOnDataRegex);
83
84 return *this;
85}
86
87CalypsoCardSelection& CalypsoCardSelectionAdapter::filterByDfName(const std::vector<uint8_t>& aid)
88{
89 Assert::getInstance().notEmpty(aid, "aid")
90 .isInRange(aid.size(), AID_MIN_LENGTH, AID_MAX_LENGTH, "aid");
91
92 mCardSelector->filterByDfName(aid);
93
94 return *this;
95}
96
97CalypsoCardSelection& CalypsoCardSelectionAdapter::filterByDfName(const std::string& aid)
98{
99 Assert::getInstance().isTrue(ByteArrayUtil::isValidHexString(aid), "aid format");
100
101 filterByDfName(ByteArrayUtil::fromHex(aid));
102
103 return *this;
104}
105
107 const FileOccurrence fileOccurrence)
108{
109 switch (fileOccurrence) {
110 case FileOccurrence::FIRST:
111 mCardSelector->setFileOccurrence(CardSelectorSpi::FileOccurrence::FIRST);
112 break;
113 case FileOccurrence::LAST:
114 mCardSelector->setFileOccurrence(CardSelectorSpi::FileOccurrence::LAST);
115 break;
116 case FileOccurrence::NEXT:
117 mCardSelector->setFileOccurrence(CardSelectorSpi::FileOccurrence::NEXT);
118 break;
119 case FileOccurrence::PREVIOUS:
120 mCardSelector->setFileOccurrence(CardSelectorSpi::FileOccurrence::PREVIOUS);
121 break;
122 }
123
124 return *this;
125}
126
128 const FileControlInformation fileControlInformation)
129{
130 if (fileControlInformation == FileControlInformation::FCI) {
131 mCardSelector->setFileControlInformation(CardSelectorSpi::FileControlInformation::FCI);
132 } else if (fileControlInformation == FileControlInformation::NO_RESPONSE) {
133 mCardSelector->setFileControlInformation(
134 CardSelectorSpi::FileControlInformation::NO_RESPONSE);
135 }
136
137 return *this;
138}
139
140CalypsoCardSelection& CalypsoCardSelectionAdapter::addSuccessfulStatusWord(const int statusWord)
141{
142 Assert::getInstance().isInRange(statusWord, 0, 0xFFFF, "statusWord");
143
144 mCardSelector->addSuccessfulStatusWord(statusWord);
145
146 return *this;
147}
148
150{
151 mCardSelector->addSuccessfulStatusWord(SW_CARD_INVALIDATED);
152
153 return *this;
154}
155
157 const uint8_t sfi, const uint8_t recordNumber)
158{
159 return prepareReadRecord(sfi, recordNumber);
160}
161
162CalypsoCardSelection& CalypsoCardSelectionAdapter::prepareReadRecord(const uint8_t sfi,
163 const uint8_t recordNumber)
164{
165 Assert::getInstance().isInRange(sfi,
168 "sfi")
169 .isInRange(recordNumber,
172 "recordNumber");
173
174 mCommands.push_back(
175 std::make_shared<CmdCardReadRecords>(CalypsoCardClass::ISO,
176 sfi,
177 recordNumber,
179 static_cast<uint8_t>(0)));
180
181 return *this;
182}
183
184CalypsoCardSelection& CalypsoCardSelectionAdapter::prepareGetData(const GetDataTag tag)
185{
186 /* Create the command and add it to the list of commands */
187 switch (tag) {
188 case GetDataTag::FCI_FOR_CURRENT_DF:
189 mCommands.push_back(std::make_shared<CmdCardGetDataFci>(CalypsoCardClass::ISO));
190 break;
191 case GetDataTag::FCP_FOR_CURRENT_FILE:
192 mCommands.push_back(std::make_shared<CmdCardGetDataFcp>(CalypsoCardClass::ISO));
193 break;
194 case GetDataTag::EF_LIST:
195 mCommands.push_back(std::make_shared<CmdCardGetDataEfList>(CalypsoCardClass::ISO));
196 break;
197 case GetDataTag::TRACEABILITY_INFORMATION:
198 mCommands.push_back(
199 std::make_shared<CmdCardGetDataTraceabilityInformation>(CalypsoCardClass::ISO));
200 break;
201 default:
202 throw UnsupportedOperationException("Unsupported Get Data tag: "); // FIXME: + tag.name());
203 }
204
205 return *this;
206}
207
209 const std::vector<uint8_t>& lid)
210{
211 Assert::getInstance().isEqual(lid.size(), 2, "lid length");
212
213 return prepareSelectFile(static_cast<uint16_t>(ByteArrayUtil::twoBytesToInt(lid, 0)));
214}
215
216CalypsoCardSelection& CalypsoCardSelectionAdapter::prepareSelectFile(const uint16_t lid)
217{
218 mCommands.push_back(
219 std::make_shared<CmdCardSelectFile>(CalypsoCardClass::ISO,
220 CalypsoCard::ProductType::PRIME_REVISION_3, lid));
221
222 return *this;
223}
224
226 const SelectFileControl selectControl)
227{
228 mCommands.push_back(std::make_shared<CmdCardSelectFile>(CalypsoCardClass::ISO, selectControl));
229
230 return *this;
231}
232
233const std::shared_ptr<CardSelectionRequestSpi>
235{
236 std::vector<std::shared_ptr<ApduRequestSpi>> cardSelectionApduRequests;
237
238 if (!mCommands.empty()) {
239 for (const auto& command : mCommands) {
240 cardSelectionApduRequests.push_back(command->getApduRequest());
241 }
242
243 return std::make_shared<CardSelectionRequestAdapter>(
244 mCardSelector,
245 std::make_shared<CardRequestAdapter>(cardSelectionApduRequests, false));
246 } else {
247 return std::make_shared<CardSelectionRequestAdapter>(mCardSelector, nullptr);
248 }
249}
250
251const std::shared_ptr<SmartCardSpi> CalypsoCardSelectionAdapter::parse(
252 const std::shared_ptr<CardSelectionResponseApi> cardSelectionResponse)
253{
254 const std::shared_ptr<CardResponseApi> cardResponse = cardSelectionResponse->getCardResponse();
255 std::vector<std::shared_ptr<ApduResponseApi>> apduResponses;
256
257 if (cardResponse != nullptr) {
258 apduResponses = cardResponse->getApduResponses();
259 } else {
260 apduResponses = {};
261 }
262
263 if (mCommands.size() != apduResponses.size()) {
264 throw ParseException("Mismatch in the number of requests/responses.");
265 }
266
267 std::shared_ptr<CalypsoCardAdapter> calypsoCard;
268 try {
269 calypsoCard = std::make_shared<CalypsoCardAdapter>();
270 if (cardSelectionResponse->getSelectApplicationResponse() != nullptr) {
271 calypsoCard->initializeWithFci(cardSelectionResponse->getSelectApplicationResponse());
272 } else if (cardSelectionResponse->getPowerOnData() != "") {
273 calypsoCard->initializeWithPowerOnData(cardSelectionResponse->getPowerOnData());
274 }
275
276 if (!mCommands.empty()) {
277 CalypsoCardUtilAdapter::updateCalypsoCard(calypsoCard, mCommands, apduResponses, false);
278 }
279
280 } catch (const Exception& e) {
281 throw ParseException("Invalid card response: " + e.getMessage(),
282 std::make_shared<Exception>(e));
283 }
284
285 if (calypsoCard->getProductType() == CalypsoCard::ProductType::UNKNOWN &&
286 cardSelectionResponse->getSelectApplicationResponse() == nullptr &&
287 cardSelectionResponse->getPowerOnData() == "") {
288 throw ParseException("Unable to create a CalypsoCard: no power-on data and no FCI " \
289 "provided.");
290 }
291
292 return calypsoCard;
293}
294
295}
296}
297}
static const CalypsoCardClass ISO
CalypsoCardSelection & filterByPowerOnData(const std::string &powerOnDataRegex) override
CalypsoCardSelection & addSuccessfulStatusWord(const int statusWord) override
CalypsoCardSelection & prepareGetData(const GetDataTag tag) override
CalypsoCardSelection & prepareReadRecordFile(const uint8_t sfi, const uint8_t recordNumber) override
CalypsoCardSelection & setFileOccurrence(const FileOccurrence fileOccurrence) override
CalypsoCardSelection & setFileControlInformation(const FileControlInformation fileControlInformation) override
const std::shared_ptr< SmartCardSpi > parse(const std::shared_ptr< CardSelectionResponseApi > cardSelectionResponse) override
const std::shared_ptr< CardSelectionRequestSpi > getCardSelectionRequest() override
CalypsoCardSelection & prepareReadRecord(const uint8_t sfi, const uint8_t recordNumber) override
CalypsoCardSelection & filterByDfName(const std::vector< uint8_t > &aid) override
CalypsoCardSelection & filterByCardProtocol(const std::string &cardProtocol) override
CalypsoCardSelection & prepareSelectFile(const std::vector< uint8_t > &lid) override
static void updateCalypsoCard(std::shared_ptr< CalypsoCardAdapter > calypsoCard, const std::shared_ptr< AbstractCardCommand > command, const std::shared_ptr< ApduResponseApi > apduResponse, const bool isSessionOpen)
CardSelectorSpi::FileOccurrence FileOccurrence
CardSelectorSpi::FileControlInformation FileControlInformation