19#include "AtomicTransactionException.h"
20#include "CardAnomalyException.h"
21#include "CardCloseSecureSessionException.h"
22#include "CardIOException.h"
23#include "DesynchronizedExchangesException.h"
24#include "SamAnomalyException.h"
25#include "SamAnomalyException.h"
26#include "SamIOException.h"
27#include "SessionAuthenticationException.h"
28#include "SvAuthenticationException.h"
29#include "UnauthorizedKeyException.h"
32#include "ApduResponseApi.h"
33#include "CardBrokenCommunicationException.h"
34#include "CardResponseApi.h"
35#include "ReaderBrokenCommunicationException.h"
36#include "UnexpectedStatusWordException.h"
56#include "ByteArrayUtil.h"
57#include "IllegalStateException.h"
58#include "KeypleAssert.h"
61#include "UnsupportedOperationException.h"
68using namespace calypsonet::terminal::calypso::transaction;
69using namespace calypsonet::terminal::card;
70using namespace keyple::core::util;
71using namespace keyple::core::util::cpp;
72using namespace keyple::core::util::cpp::exception;
76const std::string CardTransactionManagerAdapter::CARD_READER_COMMUNICATION_ERROR =
77 "A communication error with the card reader occurred while ";
78const std::string CardTransactionManagerAdapter::CARD_COMMUNICATION_ERROR =
79 "A communication error with the card occurred while ";
80const std::string CardTransactionManagerAdapter::CARD_COMMAND_ERROR =
81 "A card command error occurred while ";
82const std::string CardTransactionManagerAdapter::SAM_READER_COMMUNICATION_ERROR =
83 "A communication error with the SAM reader occurred while ";
84const std::string CardTransactionManagerAdapter::SAM_COMMUNICATION_ERROR =
85 "A communication error with the SAM occurred while ";
86const std::string CardTransactionManagerAdapter::SAM_COMMAND_ERROR =
87 "A SAM command error occurred while ";
88const std::string CardTransactionManagerAdapter::PIN_NOT_AVAILABLE_ERROR =
89 "PIN is not available for this card.";
90const std::string CardTransactionManagerAdapter::GENERATING_OF_THE_PIN_CIPHERED_DATA_ERROR =
91 "generating of the PIN ciphered data.";
92const std::string CardTransactionManagerAdapter::GENERATING_OF_THE_KEY_CIPHERED_DATA_ERROR =
93 "generating of the key ciphered data.";
94const std::string CardTransactionManagerAdapter::TRANSMITTING_COMMANDS =
95 "transmitting commands.";
96const std::string CardTransactionManagerAdapter::CHECKING_THE_SV_OPERATION =
97 "checking the SV operation.";
98const std::string CardTransactionManagerAdapter::UNEXPECTED_EXCEPTION =
99 "An unexpected exception was raised.";
100const std::string CardTransactionManagerAdapter::RECORD_NUMBER =
"recordNumber";
102const int CardTransactionManagerAdapter::SESSION_BUFFER_CMD_ADDITIONAL_COST = 6;
103const int CardTransactionManagerAdapter::APDU_HEADER_LENGTH = 5;
105const std::string CardTransactionManagerAdapter::OFFSET =
"offset";
107const std::shared_ptr<ApduResponseApi> CardTransactionManagerAdapter::RESPONSE_OK =
108 std::make_shared<ApduResponseAdapter>(std::vector<uint8_t>({0x90, 0x00}));
109const std::shared_ptr<ApduResponseApi> CardTransactionManagerAdapter::RESPONSE_OK_POSTPONED =
110 std::make_shared<ApduResponseAdapter>(std::vector<uint8_t>({0x62, 0x00}));
113 const std::shared_ptr<CardReader> cardReader,
114 const std::shared_ptr<CalypsoCard> calypsoCard,
115 const std::shared_ptr<CardSecuritySetting> cardSecuritySetting)
116: mCardReader(std::dynamic_pointer_cast<ProxyReaderApi>(cardReader)),
117 mCardSecuritySettings(cardSecuritySetting),
118 mSamCommandProcessor(cardSecuritySetting ?
123 mCurrentWriteAccessLevel(WriteAccessLevel::DEBIT),
124 mModificationsCounter(mCalypsoCard->getModificationsCounter()),
126 mSvAction(SvAction::DO),
127 mChannelControl(ChannelControl::KEEP_OPEN) {}
130 const std::shared_ptr<CardReader> cardReader,
131 const std::shared_ptr<CalypsoCard> calypsoCard)
136 return std::dynamic_pointer_cast<CardReader>(mCardReader);
147 return mCardSecuritySettings;
155void CardTransactionManagerAdapter::processAtomicOpening(
156 const WriteAccessLevel writeAccessLevel,
157 std::vector<std::shared_ptr<AbstractCardCommand>>& cardCommands)
160 checkSessionNotOpen();
162 if (mCardSecuritySettings ==
nullptr) {
163 throw IllegalStateException(
"No security settings are available.");
166 const std::vector<uint8_t> sessionTerminalChallenge = getSessionTerminalChallenge();
169 std::vector<std::shared_ptr<ApduRequestSpi>> cardApduRequests;
177 uint8_t recordNumber = 0;
185 if (!cardCommands.empty()) {
186 const std::shared_ptr<AbstractCardCommand> cardCommand = cardCommands[0];
188 std::dynamic_pointer_cast<CmdCardReadRecords>(cardCommand)->getReadMode() ==
190 sfi = std::dynamic_pointer_cast<CmdCardReadRecords>(cardCommand)->getSfi();
192 std::dynamic_pointer_cast<CmdCardReadRecords>(cardCommand)->getFirstRecordNumber();
193 cardCommands.erase(cardCommands.begin());
198 auto cmdCardOpenSession =
199 std::make_shared<CmdCardOpenSession>(mCalypsoCard,
200 static_cast<uint8_t
>(
201 static_cast<int>(writeAccessLevel) + 1),
202 sessionTerminalChallenge,
207 cardApduRequests.push_back(cmdCardOpenSession->getApduRequest());
210 Arrays::addAll(cardApduRequests, getApduRequests(cardCommands));
216 auto cardRequest = std::make_shared<CardRequestAdapter>(cardApduRequests,
false);
219 const std::shared_ptr<CardResponseApi> cardResponse = safeTransmit(cardRequest,
220 ChannelControl::KEEP_OPEN);
223 std::vector<std::shared_ptr<ApduResponseApi>> cardApduResponses =
224 cardResponse->getApduResponses();
227 checkCommandsResponsesSynchronization(cardApduRequests.size(), cardApduResponses.size());
236 cardApduResponses[0],
238 }
catch (
const CardCommandException& e) {
239 throw CardAnomalyException(std::string(CARD_COMMAND_ERROR) +
240 "processing the response to open session: " +
241 e.getCommand().getName(),
242 std::make_shared<CardCommandException>(e));
249 const std::vector<uint8_t> sessionCardChallenge = cmdCardOpenSession->getCardChallenge();
252 const std::shared_ptr<uint8_t> cardKif = cmdCardOpenSession->getSelectedKif();
255 const std::shared_ptr<uint8_t> cardKvc = cmdCardOpenSession->getSelectedKvc();
257 const std::string logCardKif = cardKif !=
nullptr ? std::to_string(*cardKif) :
"null";
258 const std::string logCardKvc = cardKvc !=
nullptr ? std::to_string(*cardKvc) :
"null";
259 mLogger->debug(
"processAtomicOpening => opening: CARDCHALLENGE = %, CARDKIF = %, CARDKVC = %\n",
260 ByteArrayUtil::toHex(sessionCardChallenge),
264 const std::shared_ptr<uint8_t> kvc = mSamCommandProcessor->computeKvc(writeAccessLevel, cardKvc);
265 const std::shared_ptr<uint8_t> kif =
266 mSamCommandProcessor->computeKif(writeAccessLevel, cardKif, kvc);
268 if (!std::dynamic_pointer_cast<CardSecuritySettingAdapter>(mCardSecuritySettings)
269 ->isSessionKeyAuthorized(kif, kvc)) {
270 const std::string logKif = kif !=
nullptr ? std::to_string(*kif) :
"null";
271 const std::string logKvc = kvc !=
nullptr ? std::to_string(*kvc) :
"null";
272 throw UnauthorizedKeyException(
"Unauthorized key error: KIF = " +
283 mSamCommandProcessor->initializeDigester(
false,
287 cardApduResponses[0]->getDataOut());
294 if (!cardCommands.empty()) {
296 mSamCommandProcessor->pushCardExchangedData(cardApduRequests, cardApduResponses, 1);
300 cardApduResponses.erase(cardApduResponses.begin());
308 }
catch (
const CardCommandException& e) {
309 throw CardAnomalyException(CARD_COMMAND_ERROR +
310 "processing the response to open session: " +
311 e.getCommand().getName(),
312 std::make_shared<CardCommandException>(e));
319 const uint8_t sfi,
const uint8_t counterNumber,
const int newValue)
321 std::shared_ptr<int> oldValue;
323 const std::shared_ptr<ElementaryFile> ef = mCalypsoCard->getFileBySfi(sfi);
325 oldValue = ef->getData()->getContentAsCounterValue(counterNumber);
328 if (oldValue ==
nullptr) {
329 throw IllegalStateException(
"The value for counter " + std::to_string(counterNumber) +
330 " in file " + std::to_string(sfi) +
" is not available");
333 const int delta = newValue - *oldValue;
335 mLogger->trace(
"Increment counter % (file %) from % to %\n",
342 }
else if (delta < 0) {
343 mLogger->trace(
"Decrement counter % (file %) from % to %\n",
351 mLogger->info(
"The counter % (SFI %) is already set to the desired value %\n",
360CardTransactionManager& CardTransactionManagerAdapter::prepareIncreaseOrDecreaseCounters(
361 const bool isDecreaseCommand,
363 const std::map<const int, const int>& counterNumberToIncDecValueMap)
365 if (mCalypsoCard->getProductType() != CalypsoCard::ProductType::PRIME_REVISION_3 &&
366 mCalypsoCard->getProductType() != CalypsoCard::ProductType::PRIME_REVISION_2) {
367 throw UnsupportedOperationException(
"The 'Increase/Decrease Multiple' commands are not " \
368 "available for this card.");
371 Assert::getInstance().isInRange((
int) sfi,
375 .isInRange(counterNumberToIncDecValueMap.size(),
378 "counterNumberToIncDecValueMap");
380 for (
const auto& entry : counterNumberToIncDecValueMap) {
381 Assert::getInstance().isInRange(entry.first,
384 "counterNumberToIncDecValueMapKey")
385 .isInRange(entry.second,
388 "counterNumberToIncDecValueMapValue");
391 const int nbCountersPerApdu = mCalypsoCard->getPayloadCapacity() / 4;
393 if (
static_cast<int>(counterNumberToIncDecValueMap.size()) <= nbCountersPerApdu) {
395 const std::map<const int, const int> dummy;
396 mCardCommandManager->addRegularCommand(
397 std::make_shared<CmdCardIncreaseOrDecreaseMultiple>(
399 mCalypsoCard->getCardClass(),
408 std::map<const int, const int> map;
410 for (
const auto& entry : counterNumberToIncDecValueMap) {
412 map.insert({entry.first, entry.second});
413 if (i == nbCountersPerApdu) {
414 mCardCommandManager->addRegularCommand(
415 std::make_shared<CmdCardIncreaseOrDecreaseMultiple>(
417 mCalypsoCard->getCardClass(),
426 mCardCommandManager->addRegularCommand(
427 std::make_shared<CmdCardIncreaseOrDecreaseMultiple>(isDecreaseCommand,
428 mCalypsoCard->getCardClass(),
437const std::vector<std::shared_ptr<ApduRequestSpi>> CardTransactionManagerAdapter::getApduRequests(
438 const std::vector<std::shared_ptr<AbstractCardCommand>>& cardCommands)
440 std::vector<std::shared_ptr<ApduRequestSpi>> apduRequests;
442 if (!cardCommands.empty()) {
443 for (
const auto& command : cardCommands) {
444 apduRequests.push_back(command->getApduRequest());
451void CardTransactionManagerAdapter::processAtomicCardCommands(
452 const std::vector<std::shared_ptr<AbstractCardCommand>> cardCommands,
453 const ChannelControl channelControl)
456 std::vector<std::shared_ptr<ApduRequestSpi>> apduRequests = getApduRequests(cardCommands);
462 std::shared_ptr<CardRequestSpi> cardRequest =
463 std::make_shared<CardRequestAdapter>(apduRequests,
false);
466 const std::shared_ptr<CardResponseApi> cardResponse = safeTransmit(cardRequest, channelControl);
469 const std::vector<std::shared_ptr<ApduResponseApi>> cardApduResponses =
470 cardResponse->getApduResponses();
473 checkCommandsResponsesSynchronization(apduRequests.size(), cardApduResponses.size());
480 mSamCommandProcessor->pushCardExchangedData(apduRequests, cardApduResponses, 0);
486 cardResponse->getApduResponses(),
488 }
catch (
const CardCommandException& e) {
489 throw CardAnomalyException(CARD_COMMAND_ERROR +
490 "processing responses to card commands: " +
491 e.getCommand().getName(),
492 std::make_shared<CardCommandException>(e));
496void CardTransactionManagerAdapter::processAtomicClosing(
497 const std::vector<std::shared_ptr<AbstractCardCommand>>& cardModificationCommands,
498 const std::vector<std::shared_ptr<ApduResponseApi>>& cardAnticipatedResponses,
499 const bool isRatificationMechanismEnabled,
500 const ChannelControl channelControl)
505 std::vector<std::shared_ptr<ApduRequestSpi>> apduRequests =
506 getApduRequests(cardModificationCommands);
509 if (!cardModificationCommands.empty() && !apduRequests.empty()) {
510 checkCommandsResponsesSynchronization(apduRequests.size(), cardAnticipatedResponses.size());
513 mSamCommandProcessor->pushCardExchangedData(apduRequests, cardAnticipatedResponses, 0);
520 const std::vector<uint8_t> sessionTerminalSignature = getSessionTerminalSignature();
523 auto cmdCardCloseSession =
524 std::make_shared<CmdCardCloseSession>(mCalypsoCard,
525 !isRatificationMechanismEnabled,
526 sessionTerminalSignature);
528 apduRequests.push_back(cmdCardCloseSession->getApduRequest());
531 const int closeCommandIndex =
static_cast<int>(apduRequests.size()) - 1;
534 bool ratificationCommandAdded;
535 if (isRatificationMechanismEnabled &&
536 std::dynamic_pointer_cast<CardReader>(mCardReader)->isContactless()) {
542 apduRequests.push_back(
544 ratificationCommandAdded =
true;
546 ratificationCommandAdded =
false;
550 auto cardRequest = std::make_shared<CardRequestAdapter>(apduRequests,
false);
551 std::shared_ptr<CardResponseApi> cardResponse;
554 cardResponse = mCardReader->transmitCardRequest(cardRequest, channelControl);
555 }
catch (
const CardBrokenCommunicationException& e) {
556 cardResponse = e.getCardResponse();
567 if (!ratificationCommandAdded ||
568 cardResponse ==
nullptr ||
569 cardResponse->getApduResponses().size() != apduRequests.size() - 1) {
570 throw CardIOException(CARD_COMMUNICATION_ERROR + TRANSMITTING_COMMANDS,
571 std::make_shared<CardBrokenCommunicationException>(e));
573 }
catch (
const ReaderBrokenCommunicationException& e) {
574 throw CardIOException(CARD_READER_COMMUNICATION_ERROR + TRANSMITTING_COMMANDS,
575 std::make_shared<ReaderBrokenCommunicationException>(e));
576 }
catch (
const UnexpectedStatusWordException& e) {
577 throw IllegalStateException(UNEXPECTED_EXCEPTION,
578 std::make_shared<UnexpectedStatusWordException>(e));
581 const std::vector<std::shared_ptr<ApduResponseApi>> apduResponses =
582 cardResponse->getApduResponses();
590 cardModificationCommands,
593 }
catch (
const CardCommandException& e) {
594 throw CardAnomalyException(CARD_COMMAND_ERROR +
595 "processing of responses preceding the close of the session: " +
596 e.getCommand().getName(),
597 std::make_shared<CardCommandException>(e));
604 apduResponses[closeCommandIndex],
606 }
catch (
const CardSecurityDataException& e) {
607 throw CardCloseSecureSessionException(
"Invalid card session",
608 std::make_shared<CardSecurityDataException>(e));
609 }
catch (
const CardCommandException& e) {
610 throw CardAnomalyException(CARD_COMMAND_ERROR +
611 "processing the response to close session: " +
612 e.getCommand().getName(),
613 std::make_shared<CardCommandException>(e));
620 checkCardSignature(cmdCardCloseSession->getSignatureLo());
626 if (mCardCommandManager->isSvOperationCompleteOneTime()) {
627 checkSvOperationStatus(cmdCardCloseSession->getPostponedData());
633void CardTransactionManagerAdapter::processAtomicClosing(
634 const std::vector<std::shared_ptr<AbstractCardCommand>>& cardCommands,
635 const bool isRatificationMechanismEnabled,
636 const ChannelControl channelControl)
638 const std::vector<std::shared_ptr<ApduResponseApi>> cardAnticipatedResponses =
639 getAnticipatedResponses(cardCommands);
641 processAtomicClosing(cardCommands,
642 cardAnticipatedResponses,
643 isRatificationMechanismEnabled,
647int CardTransactionManagerAdapter::getCounterValue(
const uint8_t sfi,
const int counter)
649 const std::shared_ptr<ElementaryFile> ef = mCalypsoCard->getFileBySfi(sfi);
651 const std::shared_ptr<int> counterValue = ef->getData()->getContentAsCounterValue(counter);
652 if (counterValue !=
nullptr) {
653 return *counterValue;
657 std::stringstream ss;
658 ss <<
"Anticipated response. Unable to determine anticipated value of counter "
662 throw IllegalStateException(ss.str());
665const std::map<const int, const int> CardTransactionManagerAdapter::getCounterValues(
666 const uint8_t sfi,
const std::vector<int>& counters)
668 const std::shared_ptr<ElementaryFile> ef = mCalypsoCard->getFileBySfi(sfi);
670 const std::map<const int, const int> allCountersValue = ef->getData()->getAllCountersValue();
672 if (Arrays::containsAll(MapUtils::getKeySet(allCountersValue), counters)) {
673 return allCountersValue;
677 std::stringstream ss;
678 ss <<
"Anticipated response. Unable to determine anticipated value of counters in EF sfi "
680 throw IllegalStateException(ss.str());
683const std::shared_ptr<ApduResponseApi> CardTransactionManagerAdapter::createIncreaseDecreaseResponse(
684 const bool isDecreaseCommand,
const int currentCounterValue,
const int incDecValue)
686 const int newValue = isDecreaseCommand ? currentCounterValue - incDecValue :
687 currentCounterValue + incDecValue;
690 std::vector<uint8_t> response(5);
691 response[0] =
static_cast<uint8_t
>((newValue & 0x00FF0000) >> 16);
692 response[1] =
static_cast<uint8_t
>((newValue & 0x0000FF00) >> 8);
693 response[2] =
static_cast<uint8_t
>(newValue & 0x000000FF);
697 return std::make_shared<ApduResponseAdapter>(response);
700const std::shared_ptr<ApduResponseApi>
701 CardTransactionManagerAdapter::createIncreaseDecreaseMultipleResponse(
702 const bool isDecreaseCommand,
703 const std::map<const int, const int>& counterNumberToCurrentValueMap,
704 const std::map<const int, const int>& counterNumberToIncDecValueMap)
707 std::vector<uint8_t> response(2 + counterNumberToIncDecValueMap.size() * 4);
710 for (
const auto& entry : counterNumberToIncDecValueMap) {
711 response[index] =
static_cast<uint8_t
>(entry.first);
713 if (isDecreaseCommand) {
714 const auto it = counterNumberToCurrentValueMap.find(entry.first);
715 newCounterValue = it->second - entry.second;
717 const auto it = counterNumberToCurrentValueMap.find(entry.first);
718 newCounterValue = it->second + entry.second;
721 response[index + 1] =
static_cast<uint8_t
>((newCounterValue & 0x00FF0000) >> 16);
722 response[index + 2] =
static_cast<uint8_t
>((newCounterValue & 0x0000FF00) >> 8);
723 response[index + 3] =
static_cast<uint8_t
>(newCounterValue & 0x000000FF);
727 response[index] = 0x90;
728 response[index + 1] = 0x00;
730 return std::make_shared<ApduResponseAdapter>(response);
733const std::vector<std::shared_ptr<ApduResponseApi>>
734 CardTransactionManagerAdapter::getAnticipatedResponses(
735 const std::vector<std::shared_ptr<AbstractCardCommand>>& cardCommands)
737 std::vector<std::shared_ptr<ApduResponseApi>> apduResponses;
739 if (!cardCommands.empty()) {
740 for (
const auto& command : cardCommands) {
743 auto incdec = std::dynamic_pointer_cast<CmdCardIncreaseOrDecrease>(command);
744 const uint8_t sfi = incdec->getSfi();
745 const int counter = incdec->getCounterNumber();
747 apduResponses.push_back(
748 createIncreaseDecreaseResponse(
750 getCounterValue(sfi, counter),
751 incdec->getIncDecValue()));
755 auto incdec = std::dynamic_pointer_cast<CmdCardIncreaseOrDecreaseMultiple>(command);
756 const uint8_t sfi = incdec->getSfi();
757 const std::map<const int, const int> counterNumberToIncDecValueMap =
758 incdec->getCounterNumberToIncDecValueMap();
760 apduResponses.push_back(
761 createIncreaseDecreaseMultipleResponse(
763 getCounterValues(sfi, MapUtils::getKeySet(counterNumberToIncDecValueMap)),
764 counterNumberToIncDecValueMap));
769 apduResponses.push_back(RESPONSE_OK_POSTPONED);
773 apduResponses.push_back(RESPONSE_OK);
778 return apduResponses;
782 const WriteAccessLevel writeAccessLevel)
785 mCurrentWriteAccessLevel = writeAccessLevel;
788 std::vector<std::shared_ptr<AbstractCardCommand>> cardAtomicCommands;
790 std::atomic<int> neededSessionBufferSpace;
791 std::atomic<bool> overflow;
793 for (
const auto& command : mCardCommandManager->getCardCommands()) {
799 if (checkModifyingCommand(command, overflow, neededSessionBufferSpace)) {
802 processAtomicOpening(mCurrentWriteAccessLevel, cardAtomicCommands);
808 processAtomicClosing(std::vector<std::shared_ptr<AbstractCardCommand>>(),
810 ChannelControl::KEEP_OPEN);
811 resetModificationsBufferCounter();
817 cardAtomicCommands.clear();
818 cardAtomicCommands.push_back(command);
821 isSessionBufferOverflowed(neededSessionBufferSpace);
824 cardAtomicCommands.push_back(command);
828 cardAtomicCommands.push_back(command);
832 processAtomicOpening(mCurrentWriteAccessLevel, cardAtomicCommands);
835 mCardCommandManager->notifyCommandsProcessed();
840void CardTransactionManagerAdapter::processCardCommandsOutOfSession(
841 const ChannelControl channelControl)
844 processAtomicCardCommands(mCardCommandManager->getCardCommands(), channelControl);
847 mCardCommandManager->notifyCommandsProcessed();
850 if (mCardCommandManager->isSvOperationCompleteOneTime()) {
852 mSamCommandProcessor->checkSvStatus(mCalypsoCard->getSvOperationSignature());
853 }
catch (
const CalypsoSamSecurityDataException& e) {
854 throw SvAuthenticationException(
"The checking of the SV operation by the SAM has " \
856 std::make_shared<CalypsoSamSecurityDataException>(e));
857 }
catch (
const CalypsoSamCommandException& e) {
858 throw SamAnomalyException(SAM_COMMAND_ERROR +
859 "checking the SV operation: " +
860 e.getCommand().getName(),
861 std::make_shared<CalypsoSamCommandException>(e));
862 }
catch (
const ReaderBrokenCommunicationException& e) {
863 throw SvAuthenticationException(
864 SAM_READER_COMMUNICATION_ERROR + CHECKING_THE_SV_OPERATION,
865 std::make_shared<ReaderBrokenCommunicationException>(e));
866 }
catch (
const CardBrokenCommunicationException& e) {
867 throw SvAuthenticationException(SAM_COMMUNICATION_ERROR + CHECKING_THE_SV_OPERATION,
868 std::make_shared<CardBrokenCommunicationException>(e));
873void CardTransactionManagerAdapter::processCardCommandsInSession()
876 std::vector<std::shared_ptr<AbstractCardCommand>> cardAtomicCommands;
878 std::atomic<int> neededSessionBufferSpace;
879 std::atomic<bool> overflow;
881 for (
const auto& command : mCardCommandManager->getCardCommands()) {
888 if (checkModifyingCommand(command, overflow, neededSessionBufferSpace)) {
895 processAtomicCardCommands(cardAtomicCommands, ChannelControl::KEEP_OPEN);
898 processAtomicClosing(std::vector<std::shared_ptr<AbstractCardCommand>>(),
900 ChannelControl::KEEP_OPEN);
901 resetModificationsBufferCounter();
904 std::vector<std::shared_ptr<AbstractCardCommand>> dummy;
905 processAtomicOpening(mCurrentWriteAccessLevel, dummy);
911 cardAtomicCommands.clear();
912 cardAtomicCommands.push_back(command);
915 isSessionBufferOverflowed(neededSessionBufferSpace);
918 cardAtomicCommands.push_back(command);
922 cardAtomicCommands.push_back(command);
926 if (!cardAtomicCommands.empty()) {
927 processAtomicCardCommands(cardAtomicCommands, ChannelControl::KEEP_OPEN);
931 mCardCommandManager->notifyCommandsProcessed();
937 processCardCommandsInSession();
939 processCardCommandsOutOfSession(mChannelControl);
949 bool atLeastOneReadCommand =
false;
950 bool sessionPreviouslyClosed =
false;
952 std::atomic<int> neededSessionBufferSpace;
953 std::atomic<bool> overflow;
955 std::vector<std::shared_ptr<AbstractCardCommand>> cardAtomicCommands;
957 for (
const auto& command : mCardCommandManager->getCardCommands()) {
963 if (checkModifyingCommand(command, overflow, neededSessionBufferSpace)) {
969 if (sessionPreviouslyClosed) {
971 std::vector<std::shared_ptr<AbstractCardCommand>> dummy;
972 processAtomicOpening(mCurrentWriteAccessLevel, dummy);
979 if (atLeastOneReadCommand) {
980 processAtomicCardCommands(cardAtomicCommands, ChannelControl::KEEP_OPEN);
983 cardAtomicCommands.clear();
984 processAtomicClosing(cardAtomicCommands,
false, ChannelControl::KEEP_OPEN);
985 resetModificationsBufferCounter();
986 sessionPreviouslyClosed =
true;
987 atLeastOneReadCommand =
false;
990 processAtomicClosing(cardAtomicCommands,
false, ChannelControl::KEEP_OPEN);
993 cardAtomicCommands.clear();
994 resetModificationsBufferCounter();
995 sessionPreviouslyClosed =
true;
1002 cardAtomicCommands.push_back(command);
1005 isSessionBufferOverflowed(neededSessionBufferSpace);
1008 cardAtomicCommands.push_back(command);
1012 cardAtomicCommands.push_back(command);
1013 atLeastOneReadCommand =
true;
1017 if (sessionPreviouslyClosed) {
1019 std::vector<std::shared_ptr<AbstractCardCommand>> dummy;
1020 processAtomicOpening(mCurrentWriteAccessLevel, dummy);
1023 if (atLeastOneReadCommand) {
1025 processAtomicCardCommands(cardAtomicCommands, ChannelControl::KEEP_OPEN);
1026 cardAtomicCommands.clear();
1030 processAtomicClosing(cardAtomicCommands,
1031 std::dynamic_pointer_cast<CardSecuritySettingAdapter>(mCardSecuritySettings)
1032 ->isRatificationMechanismEnabled(),
1036 mCardCommandManager->notifyCommandsProcessed();
1046 std::vector<std::shared_ptr<ApduRequestSpi>> apduRequests;
1049 auto cmdCardCloseSession = std::make_shared<CmdCardCloseSession>(mCalypsoCard);
1051 apduRequests.push_back(cmdCardCloseSession->getApduRequest());
1054 std::shared_ptr<CardRequestSpi> cardRequest =
1055 std::make_shared<CardRequestAdapter>(apduRequests,
false);
1057 const std::shared_ptr<CardResponseApi> cardResponse = safeTransmit(cardRequest,
1061 cmdCardCloseSession->setApduResponse(cardResponse->getApduResponses()[0]).checkStatus();
1063 throw CardAnomalyException(CARD_COMMAND_ERROR +
1064 "processing the response to close session: " +
1066 std::make_shared<CardCommandException>(e));
1070 mCardCommandManager->notifyCommandsProcessed();
1082 const std::vector<uint8_t>& pin)
1086 if (!mCalypsoCard->isPinFeatureAvailable()) {
1087 throw UnsupportedOperationException(PIN_NOT_AVAILABLE_ERROR);
1090 if (mCardCommandManager->hasCommands()) {
1091 throw IllegalStateException(
"No commands should have been prepared prior to a PIN " \
1096 if (mCardSecuritySettings !=
nullptr &&
1097 !std::dynamic_pointer_cast<CardSecuritySettingAdapter>(mCardSecuritySettings)
1098 ->isPinPlainTransmissionEnabled()) {
1101 mCardCommandManager->addRegularCommand(
1102 std::make_shared<CmdCardGetChallenge>(mCalypsoCard->getCardClass()));
1105 processAtomicCardCommands(mCardCommandManager->getCardCommands(),
1106 ChannelControl::KEEP_OPEN);
1109 mCardCommandManager->notifyCommandsProcessed();
1112 std::vector<uint8_t> cipheredPin;
1114 cipheredPin = mSamCommandProcessor->getCipheredPinData(mCalypsoCard->getCardChallenge(),
1116 std::vector<uint8_t>());
1118 throw SamAnomalyException(SAM_COMMAND_ERROR +
1119 "generating of the PIN ciphered data: " +
1121 std::make_shared<CalypsoSamCommandException>(e));
1122 }
catch (
const ReaderBrokenCommunicationException& e) {
1123 throw SamIOException(SAM_READER_COMMUNICATION_ERROR +
1124 GENERATING_OF_THE_PIN_CIPHERED_DATA_ERROR,
1125 std::make_shared<ReaderBrokenCommunicationException>(e));
1126 }
catch (
const CardBrokenCommunicationException& e) {
1127 throw SamIOException(SAM_COMMUNICATION_ERROR +
1128 GENERATING_OF_THE_PIN_CIPHERED_DATA_ERROR,
1129 std::make_shared<CardBrokenCommunicationException>(e));
1132 mCardCommandManager->addRegularCommand(
1133 std::make_shared<CmdCardVerifyPin>(mCalypsoCard->getCardClass(),
true, cipheredPin));
1135 mCardCommandManager->addRegularCommand(
1136 std::make_shared<CmdCardVerifyPin>(mCalypsoCard->getCardClass(),
false, pin));
1140 processAtomicCardCommands(mCardCommandManager->getCardCommands(), mChannelControl);
1143 mCardCommandManager->notifyCommandsProcessed();
1149 const std::vector<uint8_t>& newPin)
1154 if (!mCalypsoCard->isPinFeatureAvailable()) {
1155 throw UnsupportedOperationException(PIN_NOT_AVAILABLE_ERROR);
1159 throw IllegalStateException(
"'Change PIN' not allowed when a secure session is open.");
1163 if (std::dynamic_pointer_cast<CardSecuritySettingAdapter>(mCardSecuritySettings)
1164 ->isPinPlainTransmissionEnabled()) {
1166 if (mCalypsoCard->getPinAttemptRemaining() >= 0) {
1167 mCardCommandManager->addRegularCommand(
1168 std::make_shared<CmdCardChangePin>(mCalypsoCard->getCardClass(), newPin));
1172 mCardCommandManager->addRegularCommand(
1173 std::make_shared<CmdCardGetChallenge>(mCalypsoCard->getCardClass()));
1176 processAtomicCardCommands(mCardCommandManager->getCardCommands(),
1177 ChannelControl::KEEP_OPEN);
1180 mCardCommandManager->notifyCommandsProcessed();
1183 std::vector<uint8_t> newPinData;
1184 std::vector<uint8_t> currentPin(4);
1187 mSamCommandProcessor->getCipheredPinData(
1188 mCalypsoCard->getCardChallenge(), currentPin, newPin);
1190 throw SamAnomalyException(SAM_COMMAND_ERROR +
1191 "generating of the PIN ciphered data: " +
1193 std::make_shared<CalypsoSamCommandException>(e));
1194 }
catch (
const ReaderBrokenCommunicationException& e) {
1195 throw SamIOException(SAM_READER_COMMUNICATION_ERROR +
1196 GENERATING_OF_THE_PIN_CIPHERED_DATA_ERROR,
1197 std::make_shared<ReaderBrokenCommunicationException>(e));
1198 }
catch (
const CardBrokenCommunicationException& e) {
1199 throw SamIOException(SAM_COMMUNICATION_ERROR +
1200 GENERATING_OF_THE_PIN_CIPHERED_DATA_ERROR,
1201 std::make_shared<CardBrokenCommunicationException>(e));
1204 mCardCommandManager->addRegularCommand(
1205 std::make_shared<CmdCardChangePin>(mCalypsoCard->getCardClass(), newPinData));
1209 processAtomicCardCommands(mCardCommandManager->getCardCommands(), mChannelControl);
1212 mCardCommandManager->notifyCommandsProcessed();
1218 const uint8_t newKif,
1219 const uint8_t newKvc,
1220 const uint8_t issuerKif,
1221 const uint8_t issuerKvc)
1223 if (mCalypsoCard->getProductType() == CalypsoCard::ProductType::BASIC) {
1224 throw UnsupportedOperationException(
"The 'Change Key' command is not available for this " \
1229 throw IllegalStateException(
"'Change Key' not allowed when a secure session is open.");
1232 Assert::getInstance().isInRange(keyIndex, 1, 3,
"keyIndex");
1235 mCardCommandManager->addRegularCommand(
1236 std::make_shared<CmdCardGetChallenge>(mCalypsoCard->getCardClass()));
1239 processAtomicCardCommands(mCardCommandManager->getCardCommands(), ChannelControl::KEEP_OPEN);
1242 mCardCommandManager->notifyCommandsProcessed();
1246 const std::vector<uint8_t> encryptedKey =
1247 mSamCommandProcessor->getEncryptedKey(
1248 mCalypsoCard->getCardChallenge(), issuerKif, issuerKvc, newKif, newKvc);
1249 mCardCommandManager->addRegularCommand(
1250 std::make_shared<CmdCardChangeKey>(mCalypsoCard->getCardClass(),
1254 throw SamAnomalyException(SAM_COMMAND_ERROR +
1255 "generating the encrypted key: " +
1257 std::make_shared<CalypsoSamCommandException>(e));
1258 }
catch (
const ReaderBrokenCommunicationException& e) {
1259 throw SamIOException(SAM_READER_COMMUNICATION_ERROR +
1260 GENERATING_OF_THE_KEY_CIPHERED_DATA_ERROR,
1261 std::make_shared<ReaderBrokenCommunicationException>(e));
1262 }
catch (
const CardBrokenCommunicationException& e) {
1263 throw SamIOException(SAM_COMMUNICATION_ERROR + GENERATING_OF_THE_KEY_CIPHERED_DATA_ERROR,
1264 std::make_shared<CardBrokenCommunicationException>(e));
1268 processAtomicCardCommands(mCardCommandManager->getCardCommands(), mChannelControl);
1271 mCardCommandManager->notifyCommandsProcessed();
1276const std::shared_ptr<CardResponseApi> CardTransactionManagerAdapter::safeTransmit(
1277 const std::shared_ptr<CardRequestSpi> cardRequest,
const ChannelControl channelControl)
1280 return mCardReader->transmitCardRequest(cardRequest, channelControl);
1281 }
catch (
const ReaderBrokenCommunicationException& e) {
1282 throw CardIOException(CARD_READER_COMMUNICATION_ERROR + TRANSMITTING_COMMANDS,
1283 std::make_shared<ReaderBrokenCommunicationException>(e));
1284 }
catch (
const CardBrokenCommunicationException& e) {
1285 throw CardIOException(CARD_COMMUNICATION_ERROR + TRANSMITTING_COMMANDS,
1286 std::make_shared<CardBrokenCommunicationException>(e));
1287 }
catch (
const UnexpectedStatusWordException& e) {
1288 throw IllegalStateException(UNEXPECTED_EXCEPTION,
1289 std::make_shared<UnexpectedStatusWordException>(e));
1293const std::vector<uint8_t> CardTransactionManagerAdapter::getSessionTerminalChallenge()
1295 std::vector<uint8_t> sessionTerminalChallenge;
1298 sessionTerminalChallenge = mSamCommandProcessor->getSessionTerminalChallenge();
1299 }
catch (
const CalypsoSamCommandException& e) {
1300 throw SamAnomalyException(SAM_COMMAND_ERROR +
1301 "getting the terminal challenge: " +
1302 e.getCommand().getName(),
1303 std::make_shared<CalypsoSamCommandException>(e));
1304 }
catch (
const ReaderBrokenCommunicationException& e) {
1305 throw SamIOException(SAM_READER_COMMUNICATION_ERROR +
"getting the terminal challenge.",
1306 std::make_shared<ReaderBrokenCommunicationException>(e));
1307 }
catch (
const CardBrokenCommunicationException& e) {
1308 throw SamIOException(SAM_COMMUNICATION_ERROR +
"getting terminal challenge.",
1309 std::make_shared<CardBrokenCommunicationException>(e));
1312 return sessionTerminalChallenge;
1315const std::vector<uint8_t> CardTransactionManagerAdapter::getSessionTerminalSignature()
1317 std::vector<uint8_t> sessionTerminalSignature;
1320 sessionTerminalSignature = mSamCommandProcessor->getTerminalSignature();
1321 }
catch (
const CalypsoSamCommandException& e) {
1322 throw SamAnomalyException(SAM_COMMAND_ERROR +
1323 "getting the terminal signature: " +
1324 e.getCommand().getName(),
1325 std::make_shared<CalypsoSamCommandException>(e));
1326 }
catch (
const CardBrokenCommunicationException& e) {
1327 throw SamIOException(SAM_COMMUNICATION_ERROR +
"getting the terminal signature.",
1328 std::make_shared<CardBrokenCommunicationException>(e));
1329 }
catch (
const ReaderBrokenCommunicationException& e) {
1330 throw SamIOException(SAM_READER_COMMUNICATION_ERROR +
"getting the terminal signature.",
1331 std::make_shared<ReaderBrokenCommunicationException>(e));
1334 return sessionTerminalSignature;
1337void CardTransactionManagerAdapter::checkCardSignature(
const std::vector<uint8_t>& cardSignature)
1340 mSamCommandProcessor->authenticateCardSignature(cardSignature);
1341 }
catch (
const CalypsoSamSecurityDataException& e) {
1342 throw SessionAuthenticationException(
"The authentication of the card by the SAM has " \
1344 std::make_shared<CalypsoSamSecurityDataException>(e));
1345 }
catch (
const CalypsoSamCommandException& e) {
1346 throw SamAnomalyException(SAM_COMMAND_ERROR +
1347 "authenticating the card signature: " +
1348 e.getCommand().getName(),
1349 std::make_shared<CalypsoSamCommandException>(e));
1350 }
catch (
const ReaderBrokenCommunicationException& e) {
1351 throw SamIOException(SAM_READER_COMMUNICATION_ERROR +
1352 "authenticating the card signature.",
1353 std::make_shared<ReaderBrokenCommunicationException>(e));
1354 }
catch (
const CardBrokenCommunicationException& e) {
1355 throw SamIOException(SAM_COMMUNICATION_ERROR +
"authenticating the card signature.",
1356 std::make_shared<CardBrokenCommunicationException>(e));
1360void CardTransactionManagerAdapter::checkSvOperationStatus(
1361 const std::vector<uint8_t>& cardPostponedData)
1364 mSamCommandProcessor->checkSvStatus(cardPostponedData);
1365 }
catch (
const CalypsoSamSecurityDataException& e) {
1366 throw SvAuthenticationException(
"The checking of the SV operation by the SAM has failed.",
1367 std::make_shared<CalypsoSamSecurityDataException>(e));
1368 }
catch (
const CalypsoSamCommandException& e) {
1369 throw SamAnomalyException(SAM_COMMAND_ERROR +
1370 "checking the SV operation: " +
1371 e.getCommand().getName(),
1372 std::make_shared<CalypsoSamCommandException>(e));
1373 }
catch (
const ReaderBrokenCommunicationException& e) {
1374 throw SamIOException(SAM_READER_COMMUNICATION_ERROR + CHECKING_THE_SV_OPERATION,
1375 std::make_shared<ReaderBrokenCommunicationException>(e));
1376 }
catch (
const CardBrokenCommunicationException& e) {
1377 throw SamIOException(SAM_COMMUNICATION_ERROR + CHECKING_THE_SV_OPERATION,
1378 std::make_shared<CardBrokenCommunicationException>(e));
1382void CardTransactionManagerAdapter::checkSessionOpen()
1385 std::stringstream ss;
1386 ss <<
"Bad session state. Current: " << mSessionState
1388 throw IllegalStateException(ss.str());
1392void CardTransactionManagerAdapter::checkSessionNotOpen()
1395 std::stringstream ss;
1396 ss <<
"Bad session state. Current: " << mSessionState <<
", expected: not open";
1397 throw IllegalStateException(ss.str());
1401void CardTransactionManagerAdapter::checkCommandsResponsesSynchronization(
1402 const size_t commandsNumber,
const size_t responsesNumber)
1404 if (commandsNumber != responsesNumber) {
1405 throw DesynchronizedExchangesException(
"The number of commands/responses does not match: " \
1407 std::to_string(commandsNumber) +
1409 std::to_string(responsesNumber));
1413bool CardTransactionManagerAdapter::checkModifyingCommand(
1414 const std::shared_ptr<AbstractCardCommand> command,
1415 std::atomic<bool>& overflow,
1416 std::atomic<int>& neededSessionBufferSpace)
1418 if (command->isSessionBufferUsed()) {
1420 neededSessionBufferSpace =
static_cast<int>(command->getApduRequest()->getApdu().size()) +
1421 SESSION_BUFFER_CMD_ADDITIONAL_COST -
1424 if (isSessionBufferOverflowed(neededSessionBufferSpace)) {
1431 if (!std::dynamic_pointer_cast<CardSecuritySettingAdapter>(mCardSecuritySettings)
1432 ->isMultipleSessionEnabled()) {
1433 throw AtomicTransactionException(
"ATOMIC mode error! This command would overflow " \
1434 "the card modifications buffer: " +
1435 command->getName());
1448bool CardTransactionManagerAdapter::isSessionBufferOverflowed(
const int sessionBufferSizeConsumed)
1450 bool isSessionBufferFull =
false;
1452 if (mCalypsoCard->isModificationsCounterInBytes()) {
1453 if (mModificationsCounter - sessionBufferSizeConsumed >= 0) {
1454 mModificationsCounter -= sessionBufferSizeConsumed;
1456 mLogger->debug(
"Modifications buffer overflow! BYTESMODE, CURRENTCOUNTER = %, " \
1457 "REQUIREMENT = %\n",
1458 mModificationsCounter,
1459 sessionBufferSizeConsumed);
1461 isSessionBufferFull =
true;
1464 if (mModificationsCounter > 0) {
1465 mModificationsCounter--;
1467 mLogger->debug(
"Modifications buffer overflow! COMMANDSMODE, CURRENTCOUNTER = %, " \
1468 "REQUIREMENT = %\n",
1469 mModificationsCounter,
1472 isSessionBufferFull =
true;
1476 return isSessionBufferFull;
1480void CardTransactionManagerAdapter::resetModificationsBufferCounter()
1482 mLogger->trace(
"Modifications buffer counter reset: PREVIOUSVALUE = %, NEWVALUE = %\n",
1483 mModificationsCounter,
1484 mCalypsoCard->getModificationsCounter());
1486 mModificationsCounter = mCalypsoCard->getModificationsCounter();
1491 mChannelControl = ChannelControl::CLOSE_AFTER;
1497 const std::vector<uint8_t>& lid)
1499 Assert::getInstance().isEqual(lid.size(), 2,
"lid length");
1501 return prepareSelectFile(
static_cast<uint16_t
>(ByteArrayUtil::twoBytesToInt(lid, 0)));
1506 mCardCommandManager->addRegularCommand(
1507 std::make_shared<CmdCardSelectFile>(mCalypsoCard->getCardClass(),
1508 mCalypsoCard->getProductType(),
1515 const SelectFileControl selectFileControl)
1518 mCardCommandManager->addRegularCommand(
1519 std::make_shared<CmdCardSelectFile>(mCalypsoCard->getCardClass(), selectFileControl));
1528 case GetDataTag::FCI_FOR_CURRENT_DF:
1529 mCardCommandManager->addRegularCommand(
1530 std::make_shared<CmdCardGetDataFci>(mCalypsoCard->getCardClass()));
1532 case GetDataTag::FCP_FOR_CURRENT_FILE:
1533 mCardCommandManager->addRegularCommand(
1534 std::make_shared<CmdCardGetDataFcp>(mCalypsoCard->getCardClass()));
1536 case GetDataTag::EF_LIST:
1537 mCardCommandManager->addRegularCommand(
1538 std::make_shared<CmdCardGetDataEfList>(mCalypsoCard->getCardClass()));
1540 case GetDataTag::TRACEABILITY_INFORMATION:
1541 mCardCommandManager->addRegularCommand(
1542 std::make_shared<CmdCardGetDataTraceabilityInformation>(mCalypsoCard->getCardClass()));
1545 std::stringstream ss;
1547 throw UnsupportedOperationException(
"Unsupported Get Data tag: " + ss.str());
1554 const uint8_t sfi,
const uint8_t recordNumber)
1561 const uint8_t firstRecordNumber,
1562 const uint8_t numberOfRecords,
1563 const uint8_t recordSize)
1567 firstRecordNumber + numberOfRecords - 1,
1572 const uint8_t sfi,
const uint8_t countersNumber)
1578 const uint8_t sfi,
const uint8_t recordNumber)
1580 Assert::getInstance().isInRange(sfi,
1584 .isInRange(recordNumber,
1590 !std::dynamic_pointer_cast<CardReader>(mCardReader)->isContactless()) {
1591 throw IllegalStateException(
"Explicit record size is expected inside a secure session in " \
1595 auto cmdCardReadRecords =
1596 std::make_shared<CmdCardReadRecords>(mCalypsoCard->getCardClass(),
1600 static_cast<uint8_t
>(0));
1601 mCardCommandManager->addRegularCommand(cmdCardReadRecords);
1608 const uint8_t fromRecordNumber,
1609 const uint8_t toRecordNumber,
1610 const uint8_t recordSize)
1612 Assert::getInstance().isInRange(sfi,
1616 .isInRange(fromRecordNumber,
1620 .isInRange(toRecordNumber,
1625 if (toRecordNumber == fromRecordNumber) {
1627 mCardCommandManager->addRegularCommand(
1628 std::make_shared<CmdCardReadRecords>(mCalypsoCard->getCardClass(),
1640 const uint8_t nbBytesPerRecord = recordSize + 2;
1641 const uint8_t nbRecordsPerApdu =
1642 static_cast<uint8_t
>(mCalypsoCard->getPayloadCapacity() / nbBytesPerRecord);
1643 const uint8_t dataSizeMaxPerApdu = nbRecordsPerApdu * nbBytesPerRecord;
1645 uint8_t currentRecordNumber = fromRecordNumber;
1646 uint8_t nbRecordsRemainingToRead = toRecordNumber - fromRecordNumber + 1;
1647 uint8_t currentLength;
1649 while (currentRecordNumber < toRecordNumber) {
1650 currentLength = nbRecordsRemainingToRead <= nbRecordsPerApdu ?
1651 nbRecordsRemainingToRead * nbBytesPerRecord :
1654 mCardCommandManager->addRegularCommand(
1655 std::make_shared<CmdCardReadRecords>(cardClass,
1657 currentRecordNumber,
1661 currentRecordNumber += (currentLength / nbBytesPerRecord);
1662 nbRecordsRemainingToRead -= (currentLength / nbBytesPerRecord);
1666 if (currentRecordNumber == toRecordNumber) {
1667 mCardCommandManager->addRegularCommand(
1668 std::make_shared<CmdCardReadRecords>(cardClass,
1670 currentRecordNumber,
1681 const uint8_t fromRecordNumber,
1682 const uint8_t toRecordNumber,
1683 const uint8_t offset,
1684 const uint8_t nbBytesToRead)
1686 if (mCalypsoCard->getProductType() != CalypsoCard::ProductType::PRIME_REVISION_3 &&
1687 mCalypsoCard->getProductType() != CalypsoCard::ProductType::LIGHT) {
1688 throw UnsupportedOperationException(
"The 'Read Record Multiple' command is not available "\
1692 Assert::getInstance().isInRange(sfi,
1696 .isInRange(fromRecordNumber,
1700 .isInRange(toRecordNumber,
1708 .isInRange(nbBytesToRead,
1714 const uint8_t nbRecordsPerApdu =
1715 static_cast<uint8_t
>(mCalypsoCard->getPayloadCapacity() / nbBytesToRead);
1717 uint8_t currentRecordNumber = fromRecordNumber;
1719 while (currentRecordNumber <= toRecordNumber) {
1720 mCardCommandManager->addRegularCommand(
1721 std::make_shared<CmdCardReadRecordMultiple>(cardClass,
1723 currentRecordNumber,
1726 currentRecordNumber += nbRecordsPerApdu;
1733 const uint8_t sfi,
const uint8_t offset,
const uint8_t nbBytesToRead)
1735 if (mCalypsoCard->getProductType() != CalypsoCard::ProductType::PRIME_REVISION_3) {
1736 throw UnsupportedOperationException(
"The 'Read Binary' command is not available for this " \
1740 Assert::getInstance().isInRange(sfi,
1748 .greaterOrEqual(nbBytesToRead, 1,
"nbBytesToRead");
1753 mCardCommandManager->addRegularCommand(
1754 std::make_shared<CmdCardReadBinary>(mCalypsoCard->getCardClass(),
1756 static_cast<uint8_t
>(0),
1757 static_cast<uint8_t
>(1)));
1760 const uint8_t payloadCapacity = mCalypsoCard->getPayloadCapacity();
1763 uint8_t currentLength;
1764 uint8_t currentOffset = offset;
1765 uint8_t nbBytesRemainingToRead = nbBytesToRead;
1768 currentLength = std::min(nbBytesRemainingToRead, payloadCapacity);
1769 mCardCommandManager->addRegularCommand(
1770 std::make_shared<CmdCardReadBinary>(cardClass, sfi, currentOffset, currentLength));
1772 currentOffset += currentLength;
1773 nbBytesRemainingToRead -= currentLength;
1774 }
while (nbBytesRemainingToRead > 0);
1780 const uint8_t sfi,
const uint8_t nbCountersToRead)
1786 const std::shared_ptr<SearchCommandData> data)
1788 if (mCalypsoCard->getProductType() != CalypsoCard::ProductType::PRIME_REVISION_3) {
1789 throw UnsupportedOperationException(
"The 'Search Record Multiple' command is not " \
1790 "available for this card.");
1793 auto dataAdapter = std::dynamic_pointer_cast<SearchCommandDataAdapter>(data);
1795 throw IllegalArgumentException(
"The provided data must be an instance of " \
1796 "'SearchCommandDataAdapter' class.");
1799 Assert::getInstance().notNull(data,
"data")
1800 .isInRange(dataAdapter->getSfi(),
1804 .isInRange(dataAdapter->getRecordNumber(),
1808 .isInRange(dataAdapter->getOffset(),
1812 .isInRange(dataAdapter->getSearchData().size(),
1816 if (!dataAdapter->getMask().empty()) {
1817 Assert::getInstance().isInRange(dataAdapter->getMask().size(),
1819 dataAdapter->getSearchData().size(),
1823 mCardCommandManager->addRegularCommand(
1824 std::make_shared<CmdCardSearchRecordMultiple>(mCalypsoCard->getCardClass(), dataAdapter));
1830 const uint8_t sfi,
const std::vector<uint8_t>& recordData)
1832 Assert::getInstance().isInRange(sfi,
1838 mCardCommandManager->addRegularCommand(
1839 std::make_shared<CmdCardAppendRecord>(mCalypsoCard->getCardClass(), sfi, recordData));
1846 const uint8_t recordNumber,
1847 const std::vector<uint8_t>& recordData)
1849 Assert::getInstance().isInRange(sfi,
1853 .isInRange(recordNumber,
1859 mCardCommandManager->addRegularCommand(
1860 std::make_shared<CmdCardUpdateRecord>(mCalypsoCard->getCardClass(),
1870 const uint8_t recordNumber,
1871 const std::vector<uint8_t>& recordData)
1873 Assert::getInstance().isInRange(sfi,
1877 .isInRange(recordNumber,
1883 mCardCommandManager->addRegularCommand(
1884 std::make_shared<CmdCardWriteRecord>(mCalypsoCard->getCardClass(),
1894 const uint8_t offset,
1895 const std::vector<uint8_t>& data)
1897 return prepareUpdateOrWriteBinary(
true, sfi, offset, data);
1902 const uint8_t offset,
1903 const std::vector<uint8_t>& data)
1905 return prepareUpdateOrWriteBinary(
false, sfi, offset, data);
1908CardTransactionManager& CardTransactionManagerAdapter::prepareUpdateOrWriteBinary(
1909 const bool isUpdateCommand,
1911 const uint8_t offset,
1912 const std::vector<uint8_t>& data)
1914 if (mCalypsoCard->getProductType() != CalypsoCard::ProductType::PRIME_REVISION_3) {
1915 throw UnsupportedOperationException(
"The 'Update/Write Binary' command is not available " \
1919 Assert::getInstance().isInRange(sfi,
1927 .notEmpty(data,
"data");
1932 mCardCommandManager->addRegularCommand(
1933 std::make_shared<CmdCardReadBinary>(mCalypsoCard->getCardClass(),
1935 static_cast<uint8_t
>(0),
1936 static_cast<uint8_t
>(1)));
1939 const uint8_t dataLength =
static_cast<uint8_t
>(data.size());
1940 const uint8_t payloadCapacity = mCalypsoCard->getPayloadCapacity();
1941 const CalypsoCardClass cardClass = mCalypsoCard->getCardClass();
1943 uint8_t currentLength;
1944 uint8_t currentOffset = offset;
1945 uint8_t currentIndex = 0;
1948 currentLength =
static_cast<uint8_t
>(
1949 std::min(
static_cast<int>(dataLength - currentIndex),
1950 static_cast<int>(payloadCapacity)));
1952 mCardCommandManager->addRegularCommand(
1953 std::make_shared<CmdCardUpdateOrWriteBinary>(
1958 Arrays::copyOfRange(data, currentIndex, currentIndex + currentLength)));
1960 currentOffset += currentLength;
1961 currentIndex += currentLength;
1962 }
while (currentIndex < dataLength);
1967CardTransactionManager& CardTransactionManagerAdapter::prepareIncreaseOrDecreaseCounter(
1968 const bool isDecreaseCommand,
1970 const uint8_t counterNumber,
1971 const int incDecValue)
1973 Assert::getInstance().isInRange(sfi,
1977 .isInRange(counterNumber,
1981 .isInRange(incDecValue,
1987 mCardCommandManager->addRegularCommand(
1988 std::make_shared<CmdCardIncreaseOrDecrease>(isDecreaseCommand,
1989 mCalypsoCard->getCardClass(),
1998 const uint8_t sfi,
const uint8_t counterNumber,
const int incValue)
2000 return prepareIncreaseOrDecreaseCounter(
false, sfi, counterNumber, incValue);
2004 const uint8_t sfi,
const uint8_t counterNumber,
const int decValue)
2006 return prepareIncreaseOrDecreaseCounter(
true, sfi, counterNumber, decValue);
2011 const std::map<const int, const int>& counterNumberToIncValueMap)
2013 return prepareIncreaseOrDecreaseCounters(
false, sfi, counterNumberToIncValueMap);
2018 const std::map<const int, const int>& counterNumberToDecValueMap)
2020 return prepareIncreaseOrDecreaseCounters(
true, sfi, counterNumberToDecValueMap);
2025 if (!mCalypsoCard->isPinFeatureAvailable()) {
2026 throw UnsupportedOperationException(PIN_NOT_AVAILABLE_ERROR);
2030 mCardCommandManager->addRegularCommand(
2031 std::make_shared<CmdCardVerifyPin>(mCalypsoCard->getCardClass()));
2037 const SvAction svAction)
2039 if (!mCalypsoCard->isSvFeatureAvailable()) {
2040 throw UnsupportedOperationException(
"Stored Value is not available for this card.");
2043 if (std::dynamic_pointer_cast<CardSecuritySettingAdapter>(mCardSecuritySettings)
2044 ->isSvLoadAndDebitLogEnabled() &&
2045 !mCalypsoCard->isExtendedModeSupported()) {
2051 const SvOperation operation1 = SvOperation::RELOAD == svOperation ? SvOperation::DEBIT :
2052 SvOperation::RELOAD;
2053 mCardCommandManager->addStoredValueCommand(
2054 std::make_shared<CmdCardSvGet>(mCalypsoCard->getCardClass(), mCalypsoCard, operation1),
2058 mCardCommandManager->addStoredValueCommand(
2059 std::make_shared<CmdCardSvGet>(mCalypsoCard->getCardClass(), mCalypsoCard, svOperation),
2062 mSvAction = svAction;
2069 const std::vector<uint8_t>& date,
2070 const std::vector<uint8_t>& time,
2071 const std::vector<uint8_t>& free)
2074 auto svReloadCmdBuild = std::make_shared<CmdCardSvReload>(mCalypsoCard,
2076 mCalypsoCard->getSvKvc(),
2082 std::vector<uint8_t> svReloadComplementaryData;
2084 svReloadComplementaryData =
2085 mSamCommandProcessor->getSvReloadComplementaryData(svReloadCmdBuild,
2086 mCalypsoCard->getSvGetHeader(),
2087 mCalypsoCard->getSvGetData());
2089 throw SamAnomalyException(SAM_COMMAND_ERROR +
2090 "preparing the SV reload command: " +
2092 std::make_shared<CalypsoSamCommandException>(e));
2093 }
catch (
const ReaderBrokenCommunicationException& e) {
2094 throw SamIOException(SAM_READER_COMMUNICATION_ERROR +
"preparing the SV reload command.",
2095 std::make_shared<ReaderBrokenCommunicationException>(e));
2096 }
catch (
const CardBrokenCommunicationException& e) {
2097 throw SamIOException(SAM_COMMUNICATION_ERROR +
"preparing the SV reload command.",
2098 std::make_shared<CardBrokenCommunicationException>(e));
2102 svReloadCmdBuild->finalizeCommand(svReloadComplementaryData);
2105 mCardCommandManager->addStoredValueCommand(svReloadCmdBuild, SvOperation::RELOAD);
2112 const std::vector<uint8_t> zero = {0x00, 0x00};
2121 const std::vector<uint8_t>& date,
2122 const std::vector<uint8_t>& time)
2125 if (SvAction::DO == mSvAction) {
2126 prepareInternalSvDebit(amount, date, time);
2128 prepareInternalSvUndebit(amount, date, time);
2131 throw SamAnomalyException(SAM_COMMAND_ERROR +
2132 "preparing the SV debit/undebit command: " +
2134 std::make_shared<CalypsoSamCommandException>(e));
2135 }
catch (
const ReaderBrokenCommunicationException& e) {
2136 throw SamIOException(SAM_READER_COMMUNICATION_ERROR +
2137 "preparing the SV debit/undebit command.",
2138 std::make_shared<ReaderBrokenCommunicationException>(e));
2139 }
catch (
const CardBrokenCommunicationException& e) {
2140 throw SamIOException(SAM_COMMUNICATION_ERROR +
2141 "preparing the SV debit/undebit command.",
2142 std::make_shared<CardBrokenCommunicationException>(e));
2148void CardTransactionManagerAdapter::prepareInternalSvDebit(
const int amount,
2149 const std::vector<uint8_t>& date,
2150 const std::vector<uint8_t>& time)
2152 if (!std::dynamic_pointer_cast<CardSecuritySettingAdapter>(mCardSecuritySettings)
2153 ->isSvNegativeBalanceAuthorized() &&
2154 (mCalypsoCard->getSvBalance() - amount) < 0) {
2155 throw IllegalStateException(
"Negative balances not allowed.");
2159 auto svDebitCmdBuild = std::make_shared<CmdCardSvDebit>(mCalypsoCard,
2161 mCalypsoCard->getSvKvc(),
2166 const std::vector<uint8_t> svDebitComplementaryData =
2167 mSamCommandProcessor->getSvDebitComplementaryData(svDebitCmdBuild,
2168 mCalypsoCard->getSvGetHeader(),
2169 mCalypsoCard->getSvGetData());
2172 svDebitCmdBuild->finalizeCommand(svDebitComplementaryData);
2175 mCardCommandManager->addStoredValueCommand(svDebitCmdBuild, SvOperation::DEBIT);
2178void CardTransactionManagerAdapter::prepareInternalSvUndebit(
const int amount,
2179 const std::vector<uint8_t>& date,
2180 const std::vector<uint8_t>& time)
2183 auto svUndebitCmdBuild = std::make_shared<CmdCardSvUndebit>(mCalypsoCard,
2185 mCalypsoCard->getSvKvc(),
2190 std::vector<uint8_t> svDebitComplementaryData;
2191 svDebitComplementaryData =
2192 mSamCommandProcessor->getSvUndebitComplementaryData(svUndebitCmdBuild,
2193 mCalypsoCard->getSvGetHeader(),
2194 mCalypsoCard->getSvGetData());
2197 svUndebitCmdBuild->finalizeCommand(svDebitComplementaryData);
2200 mCardCommandManager->addStoredValueCommand(svUndebitCmdBuild, SvOperation::DEBIT);
2205 const std::vector<uint8_t> zero = {0x00, 0x00};
2214 if (!mCalypsoCard->isSvFeatureAvailable()) {
2215 throw UnsupportedOperationException(
"Stored Value is not available for this card.");
2218 if (mCalypsoCard->getApplicationSubtype() !=
2220 throw UnsupportedOperationException(
"The currently selected application is not an SV " \
2225 const std::vector<uint8_t> dummy;
2226 mCalypsoCard->setSvData(0, dummy, dummy, 0, 0,
nullptr,
nullptr);
2241 if (mCalypsoCard->isDfInvalidated()) {
2242 throw IllegalStateException(
"This card is already invalidated.");
2245 mCardCommandManager->addRegularCommand(
2246 std::make_shared<CmdCardInvalidate>(mCalypsoCard->getCardClass()));
2253 if (!mCalypsoCard->isDfInvalidated()) {
2254 throw IllegalStateException(
"This card is not invalidated.");
2257 mCardCommandManager->addRegularCommand(
2258 std::make_shared<CmdCardRehabilitate>(mCalypsoCard->getCardClass()));
2265CardTransactionManagerAdapter::ApduResponseAdapter::ApduResponseAdapter(
2266 const std::vector<uint8_t>& apdu)
2268 mStatusWord(((apdu[apdu.size() - 2] & 0x000000FF) << 8) + (apdu[apdu.size() - 1] & 0x000000FF)) {}
2270const std::vector<uint8_t>& CardTransactionManagerAdapter::ApduResponseAdapter::getApdu()
const
2275const std::vector<uint8_t> CardTransactionManagerAdapter::ApduResponseAdapter::getDataOut()
const
2277 return Arrays::copyOfRange(mApdu, 0, mApdu.size() - 2);
2280int CardTransactionManagerAdapter::ApduResponseAdapter::getStatusWord()
const
2285std::ostream&
operator<<(std::ostream& os,
const CardTransactionManagerAdapter::ApduResponseAdapter& ara)
2287 os <<
"APDU_RESPONSE_ADAPTER: {"
2288 <<
"APDU: " << ara.getApdu() <<
", "
2289 <<
"STATUS_WORD: " << ara.getStatusWord()
2296std::ostream&
operator<<(std::ostream& os,
const std::shared_ptr<CardTransactionManagerAdapter::ApduResponseAdapter> ara)
2298 if (ara ==
nullptr) {
2299 os <<
"APDU_RESPONSE_ADAPTER: null";
2313 os <<
"SESSION_UNINITIALIZED";
2316 os <<
"SESSION_OPEN";
2319 os <<
"SESSION_CLOSED";
const CardCommand & getCommand() const
static const CalypsoCardCommand DECREASE
static const CalypsoCardCommand SV_RELOAD
static const CalypsoCardCommand INCREASE
static const CalypsoCardCommand SV_DEBIT
static const CalypsoCardCommand READ_RECORDS
static const CalypsoCardCommand DECREASE_MULTIPLE
static const CalypsoCardCommand SV_UNDEBIT
static const CalypsoCardCommand INCREASE_MULTIPLE
static const int OFFSET_MIN
static const uint8_t SV_DEBIT_LOG_FILE_SFI
static const int NB_CNT_MIN
static const uint8_t SV_RELOAD_LOG_FILE_NB_REC
static const int OFFSET_MAX
static const int NB_REC_MAX
static const uint8_t SV_DEBIT_LOG_FILE_NB_REC
static const int PIN_LENGTH
static const int DATA_LENGTH_MAX
static const int CNT_VALUE_MAX
static const int NB_REC_MIN
static const int OFFSET_BINARY_MAX
static const uint8_t STORED_VALUE_FILE_STRUCTURE_ID
static const int DATA_LENGTH_MIN
static const uint8_t SV_RELOAD_LOG_FILE_SFI
static const uint8_t SV_LOG_FILE_REC_LENGTH
static const int NB_CNT_MAX
static const int CNT_VALUE_MIN
static void updateCalypsoCard(std::shared_ptr< CalypsoCardAdapter > calypsoCard, const std::shared_ptr< AbstractCardCommand > command, const std::shared_ptr< ApduResponseApi > apduResponse, const bool isSessionOpen)
virtual const std::string & getName() const =0
const std::shared_ptr< CalypsoCard > getCalypsoCard() const override
CardTransactionManager & processChangePin(const std::vector< uint8_t > &newPin) override
CardTransactionManager & prepareInvalidate() final
CardTransactionManager & prepareUpdateBinary(const uint8_t sfi, const uint8_t offset, const std::vector< uint8_t > &data) final
CardTransactionManager & processClosing() final
const std::shared_ptr< CardSecuritySetting > getCardSecuritySetting() const override
CardTransactionManager & prepareCheckPinStatus() final
CardTransactionManager & prepareSetCounter(const uint8_t sfi, const uint8_t counterNumber, const int newValue) final
CardTransactionManager & prepareReadRecordFile(const uint8_t sfi, const uint8_t recordNumber) final
CardTransactionManager & prepareReadRecord(const uint8_t sfi, const uint8_t recordNumber) override
CardTransactionManager & prepareIncreaseCounters(const uint8_t sfi, const std::map< const int, const int > &counterNumberToIncValueMap) final
const std::string getTransactionAuditData() const override
CardTransactionManager & prepareReleaseCardChannel() final
CardTransactionManager & processChangeKey(const uint8_t keyIndex, const uint8_t newKif, const uint8_t newKvc, const uint8_t issuerKif, const uint8_t issuerKvc) override
CardTransactionManager & prepareDecreaseCounter(const uint8_t sfi, const uint8_t counterNumber, const int decValue) final
CardTransactionManager & prepareReadRecords(const uint8_t sfi, const uint8_t fromRecordNumber, const uint8_t toRecordNumber, const uint8_t recordSize) override
CardTransactionManager & prepareSelectFile(const std::vector< uint8_t > &lid) final
CardTransactionManager & prepareReadBinary(const uint8_t sfi, const uint8_t offset, const uint8_t nbBytesToRead) override
CardTransactionManager & prepareRehabilitate() final
const std::shared_ptr< CardReader > getCardReader() const override
CardTransactionManager & prepareWriteRecord(const uint8_t sfi, const uint8_t recordNumber, const std::vector< uint8_t > &recordData) final
CardTransactionManagerAdapter(const std::shared_ptr< CardReader > cardReader, const std::shared_ptr< CalypsoCard > calypsoCard, const std::shared_ptr< CardSecuritySetting > cardSecuritySetting)
CardTransactionManager & prepareSvReadAllLogs() final
CardTransactionManager & prepareGetData(const GetDataTag tag) override
CardTransactionManager & processOpening(const WriteAccessLevel writeAccessLevel) final
CardTransactionManager & processVerifyPin(const std::vector< uint8_t > &pin) final
CardTransactionManager & prepareReadCounterFile(const uint8_t sfi, const uint8_t countersNumber) final
CardTransactionManager & prepareUpdateRecord(const uint8_t sfi, const uint8_t recordNumber, const std::vector< uint8_t > &recordData) final
CardTransactionManager & prepareIncreaseCounter(const uint8_t sfi, const uint8_t counterNumber, const int incValue) final
CardTransactionManager & processCancel() final
CardTransactionManager & prepareSvDebit(const int amount, const std::vector< uint8_t > &date, const std::vector< uint8_t > &time) final
CardTransactionManager & prepareReadCounter(const uint8_t sfi, const uint8_t nbCountersToRead) override
CardTransactionManager & prepareAppendRecord(const uint8_t sfi, const std::vector< uint8_t > &recordData) final
CardTransactionManager & prepareReadRecordsPartially(const uint8_t sfi, const uint8_t fromRecordNumber, const uint8_t toRecordNumber, const uint8_t offset, const uint8_t nbBytesToRead) override
CardTransactionManager & prepareSvGet(const SvOperation svOperation, const SvAction svAction) final
CardTransactionManager & prepareWriteBinary(const uint8_t sfi, const uint8_t offset, const std::vector< uint8_t > &data) final
CardTransactionManager & prepareSvReload(const int amount, const std::vector< uint8_t > &date, const std::vector< uint8_t > &time, const std::vector< uint8_t > &free) final
CardTransactionManager & prepareSearchRecords(const std::shared_ptr< SearchCommandData > data) override
CardTransactionManager & processCardCommands() final
CardTransactionManager & prepareDecreaseCounters(const uint8_t sfi, const std::map< const int, const int > &counterNumberToDecValueMap) final
static const std::shared_ptr< ApduRequestAdapter > getApduRequest(const CalypsoCardClass calypsoCardClass)
std::ostream & operator<<(std::ostream &os, const std::shared_ptr< ApduRequestAdapter > ara)