14#include "keyple/card/calypso/CalypsoCardSelectionExtensionAdapter.hpp"
20#include "keyple/card/calypso/CalypsoCardAdapter.hpp"
21#include "keyple/card/calypso/CalypsoCardConstant.hpp"
22#include "keyple/card/calypso/CardDataAccessException.hpp"
23#include "keyple/card/calypso/CommandGetDataEfList.hpp"
24#include "keyple/card/calypso/CommandGetDataFci.hpp"
25#include "keyple/card/calypso/CommandGetDataFcp.hpp"
26#include "keyple/card/calypso/CommandGetDataTraceabilityInformation.hpp"
27#include "keyple/card/calypso/CommandOpenSecureSession.hpp"
28#include "keyple/card/calypso/CommandReadBinary.hpp"
29#include "keyple/card/calypso/CommandReadRecords.hpp"
30#include "keyple/card/calypso/CommandSelectFile.hpp"
31#include "keyple/core/util/HexUtil.hpp"
32#include "keyple/core/util/KeypleAssert.hpp"
33#include "keyple/core/util/cpp/exception/IllegalArgumentException.hpp"
34#include "keyple/core/util/cpp/exception/IllegalStateException.hpp"
35#include "keyple/core/util/cpp/exception/UnsupportedOperationException.hpp"
36#include "keypop/calypso/card/transaction/InconsistentDataException.hpp"
37#include "keypop/calypso/card/transaction/SelectFileException.hpp"
38#include "keypop/card/CardResponseApi.hpp"
39#include "keypop/card/ParseException.hpp"
40#include "keypop/reader/selection/InvalidCardResponseException.hpp"
46using keyple::core::util::Assert;
47using keyple::core::util::HexUtil;
48using keyple::core::util::cpp::exception::IllegalArgumentException;
49using keyple::core::util::cpp::exception::IllegalStateException;
50using keyple::core::util::cpp::exception::UnsupportedOperationException;
51using keypop::calypso::card::transaction::InconsistentDataException;
52using keypop::calypso::card::transaction::SelectFileException;
53using keypop::card::CardResponseApi;
54using keypop::card::ParseException;
55using keypop::reader::selection::InvalidCardResponseException;
57const int CalypsoCardSelectionExtensionAdapter::SW_CARD_INVALIDATED = 0x6283;
59CalypsoCardSelectionExtensionAdapter::CalypsoCardSelectionExtensionAdapter()
61 std::unique_ptr<DtoAdapters::TransactionContextDto>(
62 new DtoAdapters::TransactionContextDto()))
64 std::unique_ptr<DtoAdapters::CommandContextDto>(
65 new DtoAdapters::CommandContextDto(false, false)))
66, mIsPreOpenPrepared(false)
67, mIsInvalidatedCardAccepted(false)
71CalypsoCardSelectionExtension&
72CalypsoCardSelectionExtensionAdapter::acceptInvalidatedCard()
74 mIsInvalidatedCardAccepted =
true;
79CalypsoCardSelectionExtension&
80CalypsoCardSelectionExtensionAdapter::prepareReadRecord(
81 std::uint8_t sfi,
int recordNumber)
86 CalypsoCardConstant::SFI_MIN,
87 CalypsoCardConstant::SFI_MAX,
91 CalypsoCardConstant::NB_REC_MIN,
92 CalypsoCardConstant::NB_REC_MAX,
96 std::make_shared<CommandReadRecords>(
101 CommandReadRecords::ReadMode::ONE_RECORD,
108CalypsoCardSelectionExtension&
109CalypsoCardSelectionExtensionAdapter::prepareSelectFile(std::uint16_t lid)
112 std::make_shared<CommandSelectFile>(
113 mTransactionContext, mCommandContext, lid));
118CalypsoCardSelectionExtension&
119CalypsoCardSelectionExtensionAdapter::prepareSelectFile(
120 SelectFileControl selectControl)
123 std::make_shared<CommandSelectFile>(
124 mTransactionContext, mCommandContext, selectControl));
129std::unique_ptr<CardSelectionRequestSpi>
130CalypsoCardSelectionExtensionAdapter::getCardSelectionRequest()
132 std::unique_ptr<DtoAdapters::CardSelectionRequestAdapter>
133 cardSelectionRequest;
135 if (mCommands.empty()) {
137 = std::unique_ptr<DtoAdapters::CardSelectionRequestAdapter>(
138 new DtoAdapters::CardSelectionRequestAdapter(
nullptr));
141 std::vector<std::shared_ptr<ApduRequestSpi>> cardSelectionApduRequests;
142 for (
const auto& command : mCommands) {
143 cardSelectionApduRequests.push_back(command->getApduRequest());
146 = std::unique_ptr<DtoAdapters::CardSelectionRequestAdapter>(
147 new DtoAdapters::CardSelectionRequestAdapter(
148 std::unique_ptr<DtoAdapters::CardRequestAdapter>(
149 new DtoAdapters::CardRequestAdapter(
150 cardSelectionApduRequests,
false))));
153 if (mIsInvalidatedCardAccepted) {
154 cardSelectionRequest->addSuccessfulSelectionStatusWord(
155 SW_CARD_INVALIDATED);
158 return cardSelectionRequest;
161CalypsoCardSelectionExtension&
162CalypsoCardSelectionExtensionAdapter::prepareReadBinary(
163 std::uint8_t sfi,
int offset,
int nbBytesToRead)
165 Assert::getInstance()
167 static_cast<int>(sfi),
168 CalypsoCardConstant::SFI_MIN,
169 CalypsoCardConstant::SFI_MAX,
173 CalypsoCardConstant::OFFSET_MIN,
174 CalypsoCardConstant::OFFSET_BINARY_MAX,
176 .greaterOrEqual(nbBytesToRead, 1,
"nbBytesToRead");
178 if (sfi > 0 && offset > 255) {
184 std::make_shared<CommandReadBinary>(
185 mTransactionContext, mCommandContext, sfi, 0, 1));
188 int currentOffset = offset;
189 int nbBytesRemainingToRead = nbBytesToRead;
192 int currentLength = std::min(
193 nbBytesRemainingToRead,
194 CalypsoCardConstant::DEFAULT_PAYLOAD_CAPACITY);
197 std::make_shared<CommandReadBinary>(
204 currentOffset += currentLength;
205 nbBytesRemainingToRead -= currentLength;
207 }
while (nbBytesRemainingToRead > 0);
212CalypsoCardSelectionExtension&
213CalypsoCardSelectionExtensionAdapter::prepareReadCounter(
214 std::uint8_t sfi,
int nbCountersToRead)
216 Assert::getInstance()
218 static_cast<int>(sfi),
219 CalypsoCardConstant::SFI_MIN,
220 CalypsoCardConstant::SFI_MAX,
225 CalypsoCardConstant::DEFAULT_PAYLOAD_CAPACITY / 3,
229 std::make_shared<CommandReadRecords>(
234 CommandReadRecords::ReadMode::ONE_RECORD,
235 std::unique_ptr<int>(
new int(nbCountersToRead * 3)),
241CalypsoCardSelectionExtension&
242CalypsoCardSelectionExtensionAdapter::preparePreOpenSecureSession(
243 WriteAccessLevel writeAccessLevel)
245 if (mIsPreOpenPrepared) {
246 throw IllegalStateException(
247 "'Pre-Open Secure Session' command is already prepared");
251 std::make_shared<CommandOpenSecureSession>(
252 mTransactionContext, mCommandContext, writeAccessLevel));
254 mIsPreOpenPrepared =
true;
259CalypsoCardSelectionExtension&
260CalypsoCardSelectionExtensionAdapter::prepareGetData(GetDataTag tag)
263 case GetDataTag::FCI_FOR_CURRENT_DF:
265 std::make_shared<CommandGetDataFci>(
266 mTransactionContext, mCommandContext));
268 case GetDataTag::FCP_FOR_CURRENT_FILE:
270 std::make_shared<CommandGetDataFcp>(
271 mTransactionContext, mCommandContext));
273 case GetDataTag::EF_LIST:
275 std::make_shared<CommandGetDataEfList>(
276 mTransactionContext, mCommandContext));
278 case GetDataTag::TRACEABILITY_INFORMATION:
280 std::make_shared<CommandGetDataTraceabilityInformation>(
281 mTransactionContext, mCommandContext));
284 throw UnsupportedOperationException(
285 "Unsupported GetDataTag: " + std::to_string(
static_cast<int>(tag)));
291std::shared_ptr<SmartCardSpi>
292CalypsoCardSelectionExtensionAdapter::parse(
293 const std::shared_ptr<CardSelectionResponseApi>& cardSelectionResponse)
295 std::shared_ptr<CardResponseApi> cardResponse
296 = cardSelectionResponse->getCardResponse();
298 std::vector<std::shared_ptr<ApduResponseApi>> apduResponses
299 = cardResponse !=
nullptr
300 ? cardResponse->getApduResponses()
301 : std::vector<std::shared_ptr<ApduResponseApi>> {};
303 if (mCommands.size() != apduResponses.size()) {
304 throw ParseException(
305 "The number of commands/responses does not match. Expected "
306 + std::to_string(mCommands.size()) +
" responses, got "
307 + std::to_string(apduResponses.size()));
310 std::shared_ptr<CalypsoCardAdapter> calypsoCard;
313 calypsoCard = std::make_shared<CalypsoCardAdapter>();
314 calypsoCard->initialize(cardSelectionResponse);
315 if (!mCommands.empty()) {
316 parseApduResponses(calypsoCard, mCommands, apduResponses);
319 }
catch (
const Exception& e) {
320 throw ParseException(
321 "Invalid card response", std::make_shared<Exception>(e));
324 if (calypsoCard->getProductType() == CalypsoCard::ProductType::UNKNOWN
325 && cardSelectionResponse->getSelectApplicationResponse() ==
nullptr
326 && cardSelectionResponse->getPowerOnData() ==
"") {
327 throw ParseException(
328 std::string(
"No power-on data and no FCI provided. Unable to ")
329 +
"create a CalypsoCard");
336CalypsoCardSelectionExtensionAdapter::parseApduResponses(
337 const std::shared_ptr<CalypsoCardAdapter>& calypsoCard,
338 const std::vector<std::shared_ptr<Command>>& commands,
339 const std::vector<std::shared_ptr<ApduResponseApi>>& apduResponses)
346 if (apduResponses.size() > commands.size()) {
347 throw InconsistentDataException(
348 std::string(
"The number of commands/responses does not match. ")
349 +
"Expected " + std::to_string(commands.size()) +
" responses, "
350 +
"got " + std::to_string(apduResponses.size()));
358 for (
int i = 0; i < static_cast<int>(apduResponses.size()); i++) {
360 commands[i]->parseResponseForSelection(
361 apduResponses[i], calypsoCard);
363 }
catch (
const CardCommandException& e) {
364 CardCommandRef commandRef = commands[i]->getCommandRef();
365 if (commandRef == CardCommandRef::READ_RECORDS
366 || commandRef == CardCommandRef::READ_BINARY
367 || commandRef == CardCommandRef::OPEN_SECURE_SESSION) {
372 auto cardDataAccessException
373 =
dynamic_cast<const CardDataAccessException&
>(e);
374 if (commandRef == CardCommandRef::SELECT_FILE) {
375 throw SelectFileException(
"File not found", e);
379 throw std::bad_cast();
382 }
catch (
const std::bad_cast&) {
383 const std::string sw = commands[i]->getApduResponse() !=
nullptr
385 static_cast<std::uint16_t
>(
390 throw InvalidCardResponseException(
391 std::string(
"Failed to process SAM response. ")
392 +
"Command: " + commandRef.getName() +
", "
403 if (apduResponses.size() < commands.size()) {
404 throw InconsistentDataException(
405 std::string(
"The number of commands/responses does not match. ")
406 +
"Expected " + std::to_string(commands.size()) +
" responses, "
407 +
"got " + std::to_string(apduResponses.size()));