19#include "CardIOException.h"
20#include "CardSignatureNotVerifiableException.h"
21#include "InconsistentDataException.h"
22#include "ReaderIOException.h"
23#include "SamIOException.h"
24#include "SessionBufferOverflowException.h"
25#include "UnauthorizedKeyException.h"
26#include "UnexpectedCommandStatusException.h"
27#include "UnexpectedStatusWordException.h"
30#include "ApduResponseApi.h"
31#include "ApduRequestSpi.h"
32#include "CardBrokenCommunicationException.h"
33#include "CardResponseApi.h"
34#include "ReaderBrokenCommunicationException.h"
54#include "ByteArrayUtil.h"
57#include "IllegalStateException.h"
58#include "KeypleAssert.h"
62#include "UnsupportedOperationException.h"
69using namespace calypsonet::terminal::calypso::transaction;
70using namespace calypsonet::terminal::card;
71using namespace calypsonet::terminal::card::spi;
72using namespace keyple::core::util;
73using namespace keyple::core::util::cpp;
74using namespace keyple::core::util::cpp::exception;
77const std::string CardTransactionManagerAdapter::PATTERN_1_BYTE_HEX =
"%020Xh";
79const std::string CardTransactionManagerAdapter::MSG_CARD_READER_COMMUNICATION_ERROR =
80 "A communication error with the card reader occurred ";
81const std::string CardTransactionManagerAdapter::MSG_CARD_COMMUNICATION_ERROR =
82 "A communication error with the card occurred ";
83const std::string CardTransactionManagerAdapter::MSG_CARD_COMMAND_ERROR =
84 "A card command error occurred ";
86const std::string CardTransactionManagerAdapter::MSG_PIN_NOT_AVAILABLE =
87 "PIN is not available for this card.";
88const std::string CardTransactionManagerAdapter::MSG_CARD_SIGNATURE_NOT_VERIFIABLE =
89 "Unable to verify the card signature associated to the successfully closed secure session.";
90const std::string CardTransactionManagerAdapter::MSG_CARD_SIGNATURE_NOT_VERIFIABLE_SV =
91 "Unable to verify the card signature associated to the SV operation.";
93const std::string CardTransactionManagerAdapter::RECORD_NUMBER =
"record number";
94const std::string CardTransactionManagerAdapter::OFFSET =
"offset";
96const int CardTransactionManagerAdapter::SESSION_BUFFER_CMD_ADDITIONAL_COST = 6;
97const int CardTransactionManagerAdapter::APDU_HEADER_LENGTH = 5;
100const std::shared_ptr<ApduResponseApi> CardTransactionManagerAdapter::RESPONSE_OK =
101 std::make_shared<ApduResponseAdapter>(std::vector<uint8_t>({0x90, 0x00}));
102const std::shared_ptr<ApduResponseApi> CardTransactionManagerAdapter::RESPONSE_OK_POSTPONED =
103 std::make_shared<ApduResponseAdapter>(std::vector<uint8_t>({0x62, 0x00}));
106 const std::shared_ptr<ProxyReaderApi> cardReader,
107 const std::shared_ptr<CalypsoCardAdapter> card,
108 const std::shared_ptr<CardSecuritySettingAdapter> securitySetting)
112 std::vector<std::vector<uint8_t>>()),
113 mCardReader(cardReader),
115 mSecuritySetting(securitySetting),
116 mModificationsCounter(card->getModificationsCounter())
118 if (securitySetting !=
nullptr && securitySetting->getControlSam() !=
nullptr) {
120 mControlSamTransactionManager =
121 std::make_shared<CardControlSamTransactionManagerAdapter>(card,
127 mControlSamTransactionManager =
nullptr;
133 return std::dynamic_pointer_cast<CardReader>(mCardReader);
147void CardTransactionManagerAdapter::checkControlSam()
const
149 if (mControlSamTransactionManager ==
nullptr) {
150 throw IllegalStateException(
"Control SAM is not set.");
154void CardTransactionManagerAdapter::processSamPreparedCommands()
156 if (mControlSamTransactionManager !=
nullptr) {
157 mControlSamTransactionManager->processCommands();
161void CardTransactionManagerAdapter::processAtomicOpening(
162 std::vector<std::shared_ptr<AbstractApduCommand>>& cardCommands)
164 if (mSecuritySetting ==
nullptr) {
165 throw IllegalStateException(
"No security settings are available.");
168 mCard->backupFiles();
179 uint8_t recordNumber = 0;
181 if (!cardCommands.empty()) {
182 const auto cardCommand = std::dynamic_pointer_cast<AbstractCardCommand>(cardCommands[0]);
184 std::dynamic_pointer_cast<CmdCardReadRecords>(cardCommand)->getReadMode() ==
186 sfi = std::dynamic_pointer_cast<CmdCardReadRecords>(cardCommand)->getSfi();
188 std::dynamic_pointer_cast<CmdCardReadRecords>(cardCommand)->getFirstRecordNumber();
189 cardCommands.erase(cardCommands.begin());
194 const std::vector<uint8_t> samChallenge = processSamGetChallenge();
197 auto cmdCardOpenSession =
198 std::make_shared<CmdCardOpenSession>(
199 mCard->getProductType(),
200 static_cast<uint8_t
>(
static_cast<int>(mWriteAccessLevel) + 1),
204 isExtendedModeAllowed());
207 cardCommands.insert(cardCommands.begin(), cmdCardOpenSession);
210 const std::vector<std::shared_ptr<ApduRequestSpi>> apduRequests =
214 auto cardRequest = std::make_shared<CardRequestAdapter>(apduRequests,
true);
216 mIsSessionOpen =
true;
219 const std::shared_ptr<CardResponseApi> cardResponse =
220 transmitCardRequest(cardRequest, ChannelControl::KEEP_OPEN);
223 const std::vector<std::shared_ptr<ApduResponseApi>> apduResponses =
224 cardResponse->getApduResponses();
232 }
catch (
const CardCommandException& e) {
233 throw UnexpectedCommandStatusException(MSG_CARD_COMMAND_ERROR +
234 "while processing the response to open session: " +
235 e.getCommand().getName() +
237 std::make_shared<CardCommandException>(e));
238 }
catch (
const InconsistentDataException& e) {
245 const std::shared_ptr<uint8_t> cardKif = cmdCardOpenSession->getSelectedKif();
246 const std::shared_ptr<uint8_t> cardKvc = cmdCardOpenSession->getSelectedKvc();
248 const std::string logCardKif = cardKif !=
nullptr ? std::to_string(*cardKif) :
"null";
249 const std::string logCardKvc = cardKvc !=
nullptr ? std::to_string(*cardKvc) :
"null";
250 mLogger->debug(
"processAtomicOpening => opening: CARD_CHALLENGE=%, CARD_KIF=%, CARD_KVC=%\n",
251 HexUtil::toHex(cmdCardOpenSession->getCardChallenge()),
255 const std::shared_ptr<uint8_t> kvc =
256 mControlSamTransactionManager->computeKvc(mWriteAccessLevel, cardKvc);
257 const std::shared_ptr<uint8_t> kif =
258 mControlSamTransactionManager->computeKif(mWriteAccessLevel, cardKif, kvc);
260 if (!mSecuritySetting->isSessionKeyAuthorized(kif, kvc)) {
261 const std::string logKif = kif !=
nullptr ? std::to_string(*kif) :
"null";
262 const std::string logKvc = kvc !=
nullptr ? std::to_string(*kvc) :
"null";
263 throw UnauthorizedKeyException(
"Unauthorized key error: " \
264 "KIF=" + logKif +
", " +
265 "KVC=" + logKvc +
" " +
270 mControlSamTransactionManager->initializeSession(apduResponses[0]->getDataOut(),
281 mControlSamTransactionManager->updateSession(apduRequests, apduResponses, 1);
284void CardTransactionManagerAdapter::abortSecureSessionSilently()
286 if (mIsSessionOpen) {
290 }
catch (
const RuntimeException& e) {
291 mLogger->warn(
"An error occurred while aborting the current secure session: %",
295 mIsSessionOpen =
false;
300 const uint8_t sfi,
const uint8_t counterNumber,
const int newValue)
302 std::shared_ptr<int> oldValue;
304 const std::shared_ptr<ElementaryFile> ef = mCard->getFileBySfi(sfi);
306 oldValue = ef->getData()->getContentAsCounterValue(counterNumber);
309 if (oldValue ==
nullptr) {
310 throw IllegalStateException(
"The value for counter " + std::to_string(counterNumber) +
311 " in file " + std::to_string(sfi) +
" is not available");
314 const int delta = newValue - *oldValue;
316 mLogger->trace(
"Increment counter % (file %) from % to %\n",
323 }
else if (delta < 0) {
324 mLogger->trace(
"Decrement counter % (file %) from % to %\n",
332 mLogger->info(
"The counter % (SFI %) is already set to the desired value %\n",
341CardTransactionManager& CardTransactionManagerAdapter::prepareIncreaseOrDecreaseCounters(
342 const bool isDecreaseCommand,
344 const std::map<const int, const int>& counterNumberToIncDecValueMap)
346 if (mCard->getProductType() != CalypsoCard::ProductType::PRIME_REVISION_3 &&
347 mCard->getProductType() != CalypsoCard::ProductType::PRIME_REVISION_2) {
348 throw UnsupportedOperationException(
"The 'Increase/Decrease Multiple' commands are not " \
349 "available for this card.");
352 Assert::getInstance().isInRange((
int) sfi,
356 .isInRange(counterNumberToIncDecValueMap.size(),
359 "counterNumberToIncDecValueMap");
361 for (
const auto& entry : counterNumberToIncDecValueMap) {
362 Assert::getInstance().isInRange(entry.first,
365 "counterNumberToIncDecValueMapKey")
366 .isInRange(entry.second,
369 "counterNumberToIncDecValueMapValue");
372 const int nbCountersPerApdu = mCard->getPayloadCapacity() / 4;
374 if (
static_cast<int>(counterNumberToIncDecValueMap.size()) <= nbCountersPerApdu) {
376 const std::map<const int, const int> dummy;
377 mCardCommands.push_back(
378 std::make_shared<CmdCardIncreaseOrDecreaseMultiple>(
380 mCard->getCardClass(),
389 std::map<const int, const int> map;
391 for (
const auto& entry : counterNumberToIncDecValueMap) {
393 map.insert({entry.first, entry.second});
394 if (i == nbCountersPerApdu) {
395 mCardCommands.push_back(
396 std::make_shared<CmdCardIncreaseOrDecreaseMultiple>(
398 mCard->getCardClass(),
407 mCardCommands.push_back(
408 std::make_shared<CmdCardIncreaseOrDecreaseMultiple>(isDecreaseCommand,
409 mCard->getCardClass(),
418void CardTransactionManagerAdapter::processAtomicCardCommands(
419 const std::vector<std::shared_ptr<AbstractApduCommand>> cardCommands,
420 const ChannelControl channelControl)
423 std::vector<std::shared_ptr<ApduRequestSpi>> apduRequests =
getApduRequests(cardCommands);
426 std::shared_ptr<CardRequestSpi> cardRequest =
427 std::make_shared<CardRequestAdapter>(apduRequests,
true);
430 const std::shared_ptr<CardResponseApi> cardResponse =
431 transmitCardRequest(cardRequest, channelControl);
434 const std::vector<std::shared_ptr<ApduResponseApi>> apduResponses =
435 cardResponse->getApduResponses();
441 if (mIsSessionOpen) {
442 mControlSamTransactionManager->updateSession(apduRequests, apduResponses, 0);
450 }
catch (
const CardCommandException& e) {
451 throw UnexpectedCommandStatusException(MSG_CARD_COMMAND_ERROR +
452 "while processing responses to card commands: " +
453 e.getCommand().getName() +
455 std::make_shared<CardCommandException>(e));
456 }
catch (
const InconsistentDataException& e) {
461void CardTransactionManagerAdapter::processAtomicClosing(
462 const std::vector<std::shared_ptr<AbstractApduCommand>>& cardCommands,
463 const bool isRatificationMechanismEnabled,
464 const ChannelControl channelControl)
467 std::vector<std::shared_ptr<ApduRequestSpi>> apduRequests =
getApduRequests(cardCommands);
470 const std::vector<std::shared_ptr<ApduResponseApi>> expectedApduResponses =
471 buildAnticipatedResponses(cardCommands);
474 mControlSamTransactionManager->updateSession(apduRequests, expectedApduResponses, 0);
480 const std::vector<uint8_t> sessionTerminalSignature = processSamSessionClosing();
483 auto cmdCardCloseSession =
484 std::make_shared<CmdCardCloseSession>(mCard,
485 !isRatificationMechanismEnabled,
486 sessionTerminalSignature);
488 apduRequests.push_back(cmdCardCloseSession->getApduRequest());
491 bool isRatificationCommandAdded;
492 if (isRatificationMechanismEnabled &&
493 std::dynamic_pointer_cast<CardReader>(mCardReader)->isContactless()) {
499 apduRequests.push_back(
501 isRatificationCommandAdded =
true;
503 isRatificationCommandAdded =
false;
507 auto cardRequest = std::make_shared<CardRequestAdapter>(apduRequests,
true);
510 std::shared_ptr<CardResponseApi> cardResponse;
513 cardResponse = transmitCardRequest(cardRequest, channelControl);
514 }
catch (
const CardIOException& e) {
515 const auto cause = std::dynamic_pointer_cast<AbstractApduException>(e.getCause());
516 cardResponse = cause->getCardResponse();
525 if (!isRatificationCommandAdded ||
526 cardResponse ==
nullptr ||
527 cardResponse->getApduResponses().size() != apduRequests.size() - 1) {
533 std::vector<std::shared_ptr<ApduResponseApi>> apduResponses = cardResponse->getApduResponses();
536 if (isRatificationCommandAdded && apduResponses.size() == cardCommands.size() + 2) {
537 apduResponses.pop_back();
541 std::shared_ptr<ApduResponseApi> closeSecureSessionApduResponse =
nullptr;
542 if (apduResponses.size() == cardCommands.size() + 1) {
543 closeSecureSessionApduResponse = apduResponses.back();
544 apduResponses.pop_back();
556 }
catch (
const CardCommandException& e) {
557 throw UnexpectedCommandStatusException(MSG_CARD_COMMAND_ERROR +
558 "while processing of responses preceding the close" \
559 " of the session: " +
560 e.getCommand().getName() +
562 std::make_shared<CardCommandException>(e));
563 }
catch (
const InconsistentDataException& e) {
568 mIsSessionOpen =
false;
574 closeSecureSessionApduResponse,
576 }
catch (
const CardSecurityDataException& e) {
577 throw UnexpectedCommandStatusException(
"Invalid card session" +
579 std::make_shared<CardSecurityDataException>(e));
580 }
catch (
const CardCommandException& e) {
581 throw UnexpectedCommandStatusException(MSG_CARD_COMMAND_ERROR +
582 "while processing the response to close session: " +
583 e.getCommand().getName() +
585 std::make_shared<CardCommandException>(e));
592 processSamDigestAuthenticate(cmdCardCloseSession->getSignatureLo());
599 processSamSvCheck(cmdCardCloseSession->getPostponedData());
603int CardTransactionManagerAdapter::getCounterValue(
const uint8_t sfi,
const int counter)
605 const std::shared_ptr<ElementaryFile> ef = mCard->getFileBySfi(sfi);
607 const std::shared_ptr<int> counterValue = ef->getData()->getContentAsCounterValue(counter);
608 if (counterValue !=
nullptr) {
609 return *counterValue;
613 std::stringstream ss;
614 ss <<
"Anticipated response. Unable to determine anticipated value of counter "
618 throw IllegalStateException(ss.str());
621const std::map<const int, const int> CardTransactionManagerAdapter::getCounterValues(
622 const uint8_t sfi,
const std::vector<int>& counters)
624 const std::shared_ptr<ElementaryFile> ef = mCard->getFileBySfi(sfi);
626 const std::map<const int, const int> allCountersValue = ef->getData()->getAllCountersValue();
628 if (Arrays::containsAll(MapUtils::getKeySet(allCountersValue), counters)) {
629 return allCountersValue;
633 std::stringstream ss;
634 ss <<
"Anticipated response. Unable to determine anticipated value of counters in EF sfi "
636 throw IllegalStateException(ss.str());
639const std::shared_ptr<ApduResponseApi>
640 CardTransactionManagerAdapter::buildAnticipatedIncreaseDecreaseResponse(
641 const bool isDecreaseCommand,
const int currentCounterValue,
const int incDecValue)
643 const int newValue = isDecreaseCommand ? currentCounterValue - incDecValue :
644 currentCounterValue + incDecValue;
647 std::vector<uint8_t> response(5);
648 response[0] =
static_cast<uint8_t
>((newValue & 0x00FF0000) >> 16);
649 response[1] =
static_cast<uint8_t
>((newValue & 0x0000FF00) >> 8);
650 response[2] =
static_cast<uint8_t
>(newValue & 0x000000FF);
654 return std::make_shared<ApduResponseAdapter>(response);
657const std::shared_ptr<ApduResponseApi>
658 CardTransactionManagerAdapter::buildAnticipatedIncreaseDecreaseMultipleResponse(
659 const bool isDecreaseCommand,
660 const std::map<const int, const int>& counterNumberToCurrentValueMap,
661 const std::map<const int, const int>& counterNumberToIncDecValueMap)
664 std::vector<uint8_t> response(2 + counterNumberToIncDecValueMap.size() * 4);
667 for (
const auto& entry : counterNumberToIncDecValueMap) {
668 response[index] =
static_cast<uint8_t
>(entry.first);
670 if (isDecreaseCommand) {
671 const auto it = counterNumberToCurrentValueMap.find(entry.first);
672 newCounterValue = it->second - entry.second;
674 const auto it = counterNumberToCurrentValueMap.find(entry.first);
675 newCounterValue = it->second + entry.second;
678 response[index + 1] =
static_cast<uint8_t
>((newCounterValue & 0x00FF0000) >> 16);
679 response[index + 2] =
static_cast<uint8_t
>((newCounterValue & 0x0000FF00) >> 8);
680 response[index + 3] =
static_cast<uint8_t
>(newCounterValue & 0x000000FF);
684 response[index] = 0x90;
685 response[index + 1] = 0x00;
687 return std::make_shared<ApduResponseAdapter>(response);
690const std::vector<std::shared_ptr<ApduResponseApi>>
691 CardTransactionManagerAdapter::buildAnticipatedResponses(
692 const std::vector<std::shared_ptr<AbstractApduCommand>>& cardCommands)
694 std::vector<std::shared_ptr<ApduResponseApi>> apduResponses;
696 if (!cardCommands.empty()) {
697 for (
const auto& command : cardCommands) {
699 auto& commandRef =
dynamic_cast<const CalypsoCardCommand&
>(command->getCommandRef());
703 auto cmdA = std::dynamic_pointer_cast<CmdCardIncreaseOrDecrease>(command);
704 apduResponses.push_back(
705 buildAnticipatedIncreaseDecreaseResponse(
707 getCounterValue(cmdA->getSfi(), cmdA->getCounterNumber()),
708 cmdA->getIncDecValue()));
713 auto cmdB = std::dynamic_pointer_cast<CmdCardIncreaseOrDecreaseMultiple>(command);
714 const std::map<const int, const int>& counterNumberToIncDecValueMap =
715 cmdB->getCounterNumberToIncDecValueMap();
716 apduResponses.push_back(
717 buildAnticipatedIncreaseDecreaseMultipleResponse(
719 getCounterValues(cmdB->getSfi(),
720 MapUtils::getKeySet(counterNumberToIncDecValueMap)),
721 counterNumberToIncDecValueMap));
726 apduResponses.push_back(RESPONSE_OK_POSTPONED);
730 apduResponses.push_back(RESPONSE_OK);
735 return apduResponses;
739 const WriteAccessLevel writeAccessLevel)
745 mWriteAccessLevel = writeAccessLevel;
748 std::vector<std::shared_ptr<AbstractApduCommand>> cardAtomicCommands;
750 for (
const auto& apduCommand : mCardCommands) {
752 const auto& command = std::dynamic_pointer_cast<AbstractCardCommand>(apduCommand);
754 if (command->isSessionBufferUsed()) {
755 mModificationsCounter -= computeCommandSessionBufferSize(command);
756 if (mModificationsCounter < 0) {
757 checkMultipleSessionEnabled(command);
760 processAtomicOpening(cardAtomicCommands);
761 std::vector<std::shared_ptr<AbstractApduCommand>> empty;
762 processAtomicClosing(empty,
false, ChannelControl::KEEP_OPEN);
765 mModificationsCounter = mCard->getModificationsCounter();
766 mModificationsCounter -= computeCommandSessionBufferSize(command);
769 cardAtomicCommands.clear();
773 cardAtomicCommands.push_back(command);
776 processAtomicOpening(cardAtomicCommands);
782 mIsSvOperationInsideSession =
false;
786 }
catch (
const RuntimeException& e) {
787 abortSecureSessionSilently();
792void CardTransactionManagerAdapter::checkMultipleSessionEnabled(
793 std::shared_ptr<AbstractCardCommand> command)
const
800 if (!mSecuritySetting->isMultipleSessionEnabled()) {
801 throw SessionBufferOverflowException(
"ATOMIC mode error! This command would overflow the " \
802 "card modifications buffer: " +
808void CardTransactionManagerAdapter::processCommandsOutsideSession(
809 const ChannelControl channelControl)
812 processAtomicCardCommands(mCardCommands, channelControl);
820 processSamSvCheck(mCard->getSvOperationSignature());
823 processSamPreparedCommands();
827void CardTransactionManagerAdapter::processCommandsInsideSession()
831 std::vector<std::shared_ptr<AbstractApduCommand>> cardAtomicCommands;
832 bool isAtLeastOneReadCommand =
false;
834 for (
const auto& apduCommand : mCardCommands) {
836 const auto& command = std::dynamic_pointer_cast<AbstractCardCommand>(apduCommand);
839 if (command->isSessionBufferUsed()) {
840 mModificationsCounter -= computeCommandSessionBufferSize(command);
841 if (mModificationsCounter < 0) {
842 checkMultipleSessionEnabled(command);
847 if (isAtLeastOneReadCommand) {
848 processAtomicCardCommands(cardAtomicCommands, ChannelControl::KEEP_OPEN);
849 cardAtomicCommands.clear();
852 processAtomicClosing(cardAtomicCommands,
false, ChannelControl::KEEP_OPEN);
853 std::vector<std::shared_ptr<AbstractApduCommand>> empty;
854 processAtomicOpening(empty);
857 mModificationsCounter = mCard->getModificationsCounter();
858 mModificationsCounter -= computeCommandSessionBufferSize(command);
859 isAtLeastOneReadCommand =
false;
862 cardAtomicCommands.clear();
865 isAtLeastOneReadCommand =
true;
869 processAtomicCardCommands(cardAtomicCommands, ChannelControl::KEEP_OPEN);
874 processSamPreparedCommands();
876 }
catch (
const RuntimeException& e) {
877 abortSecureSessionSilently();
884 return mSecuritySetting;
891 mControlSamTransactionManager->prepareComputeSignature(data);
901 mControlSamTransactionManager->prepareVerifySignature(data);
908 finalizeSvCommandIfNeeded();
910 if (mIsSessionOpen) {
911 processCommandsInsideSession();
913 processCommandsOutsideSession(mChannelControl);
928 finalizeSvCommandIfNeeded();
930 std::vector<std::shared_ptr<AbstractApduCommand>> cardAtomicCommands;
931 bool isAtLeastOneReadCommand =
false;
933 for (
const auto& apduCommand : mCardCommands) {
935 const auto& command = std::dynamic_pointer_cast<AbstractCardCommand>(apduCommand);
938 if (command->isSessionBufferUsed()) {
939 mModificationsCounter -= computeCommandSessionBufferSize(command);
940 if (mModificationsCounter < 0) {
941 checkMultipleSessionEnabled(command);
947 if (isAtLeastOneReadCommand) {
948 processAtomicCardCommands(cardAtomicCommands, ChannelControl::KEEP_OPEN);
949 cardAtomicCommands.clear();
952 processAtomicClosing(cardAtomicCommands,
false, ChannelControl::KEEP_OPEN);
953 std::vector<std::shared_ptr<AbstractApduCommand>> empty;
954 processAtomicOpening(empty);
957 mModificationsCounter = mCard->getModificationsCounter();
958 mModificationsCounter -= computeCommandSessionBufferSize(command);
959 isAtLeastOneReadCommand =
false;
962 cardAtomicCommands.clear();
966 isAtLeastOneReadCommand =
true;
970 if (isAtLeastOneReadCommand) {
971 processAtomicCardCommands(cardAtomicCommands, ChannelControl::KEEP_OPEN);
972 cardAtomicCommands.clear();
975 processAtomicClosing(cardAtomicCommands,
976 mSecuritySetting->isRatificationMechanismEnabled(),
984 }
catch (
const RuntimeException& e) {
985 abortSecureSessionSilently();
994 mCard->restoreFiles();
997 auto cmdCardCloseSession = std::make_shared<CmdCardCloseSession>(mCard);
1000 std::vector<std::shared_ptr<ApduRequestSpi>> apduRequests;
1001 apduRequests.push_back(cmdCardCloseSession->getApduRequest());
1004 const std::shared_ptr<CardRequestSpi> cardRequest =
1005 std::make_shared<CardRequestAdapter>(apduRequests,
false);
1006 const std::shared_ptr<CardResponseApi> cardResponse =
1007 transmitCardRequest(cardRequest, mChannelControl);
1010 cmdCardCloseSession->setApduResponse(cardResponse->getApduResponses()[0]).checkStatus();
1012 throw UnexpectedCommandStatusException(MSG_CARD_COMMAND_ERROR +
1013 "while processing the response to close session: " +
1016 std::make_shared<CardCommandException>(e));
1026 mIsSessionOpen =
false;
1032 const std::vector<uint8_t>& pin)
1037 if (!mCard->isPinFeatureAvailable()) {
1038 throw UnsupportedOperationException(MSG_PIN_NOT_AVAILABLE);
1041 if (!mCardCommands.empty()) {
1042 throw IllegalStateException(
"No commands should have been prepared prior to a PIN " \
1046 finalizeSvCommandIfNeeded();
1049 if (mSecuritySetting !=
nullptr && !mSecuritySetting->isPinPlainTransmissionEnabled()) {
1052 mCardCommands.push_back(std::make_shared<CmdCardGetChallenge>(mCard->getCardClass()));
1055 processAtomicCardCommands(mCardCommands, ChannelControl::KEEP_OPEN);
1061 std::vector<uint8_t> cipheredPin = processSamCardCipherPin(pin, std::vector<uint8_t>());
1063 mCardCommands.push_back(
1064 std::make_shared<CmdCardVerifyPin>(mCard->getCardClass(),
true, cipheredPin));
1066 mCardCommands.push_back(
1067 std::make_shared<CmdCardVerifyPin>(mCard->getCardClass(),
false, pin));
1071 processAtomicCardCommands(mCardCommands, mChannelControl);
1076 processSamPreparedCommands();
1080 }
catch (
const RuntimeException& e) {
1081 abortSecureSessionSilently();
1086const std::vector<uint8_t> CardTransactionManagerAdapter::processSamCardCipherPin(
1087 const std::vector<uint8_t>& currentPin,
const std::vector<uint8_t>& newPin)
1089 mControlSamTransactionManager->prepareGiveRandom();
1090 const std::shared_ptr<CmdSamCardCipherPin> cmdSamCardCipherPin =
1091 mControlSamTransactionManager->prepareCardCipherPin(currentPin, newPin);
1092 mControlSamTransactionManager->processCommands();
1094 return cmdSamCardCipherPin->getCipheredData();
1098 const std::vector<uint8_t>& newPin)
1103 if (!mCard->isPinFeatureAvailable()) {
1104 throw UnsupportedOperationException(MSG_PIN_NOT_AVAILABLE);
1107 if (mIsSessionOpen) {
1108 throw IllegalStateException(
"'Change PIN' not allowed when a secure session is open.");
1111 finalizeSvCommandIfNeeded();
1114 if (mSecuritySetting->isPinPlainTransmissionEnabled()) {
1117 if (mCard->getPinAttemptRemaining() >= 0) {
1118 mCardCommands.push_back(
1119 std::make_shared<CmdCardChangePin>(mCard->getCardClass(), newPin));
1123 mCardCommands.push_back(
1124 std::make_shared<CmdCardGetChallenge>(mCard->getCardClass()));
1127 processAtomicCardCommands(mCardCommands, ChannelControl::KEEP_OPEN);
1133 std::vector<uint8_t> currentPin(4);
1134 std::vector<uint8_t> newPinData = processSamCardCipherPin(currentPin, newPin);
1136 mCardCommands.push_back(
1137 std::make_shared<CmdCardChangePin>(mCard->getCardClass(), newPinData));
1141 processAtomicCardCommands(mCardCommands, mChannelControl);
1146 processSamPreparedCommands();
1150 }
catch (
const RuntimeException& e) {
1151 abortSecureSessionSilently();
1157 const uint8_t newKif,
1158 const uint8_t newKvc,
1159 const uint8_t issuerKif,
1160 const uint8_t issuerKvc)
1162 if (mCard->getProductType() == CalypsoCard::ProductType::BASIC) {
1163 throw UnsupportedOperationException(
"The 'Change Key' command is not available for this " \
1167 if (mIsSessionOpen) {
1168 throw IllegalStateException(
"'Change Key' not allowed when a secure session is open.");
1171 Assert::getInstance().isInRange(keyIndex, 1, 3,
"keyIndex");
1173 finalizeSvCommandIfNeeded();
1176 mCardCommands.push_back(std::make_shared<CmdCardGetChallenge>(mCard->getCardClass()));
1179 processAtomicCardCommands(mCardCommands, ChannelControl::KEEP_OPEN);
1185 const std::vector<uint8_t> encryptedKey = processSamCardGenerateKey(issuerKif,
1190 mCardCommands.push_back(std::make_shared<CmdCardChangeKey>(mCard->getCardClass(),
1195 processAtomicCardCommands(mCardCommands, mChannelControl);
1203const std::vector<uint8_t> CardTransactionManagerAdapter::processSamCardGenerateKey(
1204 const uint8_t issuerKif,
const uint8_t issuerKvc,
const uint8_t newKif,
const uint8_t newKvc)
1206 mControlSamTransactionManager->prepareGiveRandom();
1207 const std::shared_ptr<CmdSamCardGenerateKey> cmdSamCardGenerateKey =
1208 mControlSamTransactionManager->prepareCardGenerateKey(issuerKif, issuerKvc, newKif, newKvc);
1209 mControlSamTransactionManager->processCommands();
1211 return cmdSamCardGenerateKey->getCipheredData();
1214const std::shared_ptr<CardResponseApi> CardTransactionManagerAdapter::transmitCardRequest(
1215 const std::shared_ptr<CardRequestSpi> cardRequest,
const ChannelControl channelControl)
1218 std::shared_ptr<CardResponseApi> cardResponse =
nullptr;
1221 cardResponse = mCardReader->transmitCardRequest(cardRequest, channelControl);
1222 }
catch (
const ReaderBrokenCommunicationException& e) {
1224 throw ReaderIOException(MSG_CARD_READER_COMMUNICATION_ERROR +
1227 std::make_shared<ReaderBrokenCommunicationException>(e));
1228 }
catch (
const CardBrokenCommunicationException& e) {
1230 throw CardIOException(MSG_CARD_COMMUNICATION_ERROR +
1233 std::make_shared<CardBrokenCommunicationException>(e));
1234 }
catch (
const UnexpectedStatusWordException& e) {
1235 mLogger->debug(
"A card command has failed: %\n", e.getMessage());
1236 cardResponse = e.getCardResponse();
1241 return cardResponse;
1244void CardTransactionManagerAdapter::finalizeSvCommandIfNeeded()
1246 if (mSvLastModifyingCommand ==
nullptr) {
1250 std::vector<uint8_t> svComplementaryData;
1255 auto svCommand = std::dynamic_pointer_cast<CmdCardSvReload>(mSvLastModifyingCommand);
1257 svComplementaryData = processSamSvPrepareLoad(mCard->getSvGetHeader(),
1258 mCard->getSvGetData(),
1262 svCommand->finalizeCommand(svComplementaryData);
1267 auto svCommand = std::dynamic_pointer_cast<CmdCardSvDebitOrUndebit>(mSvLastModifyingCommand);
1269 svComplementaryData = processSamSvPrepareDebitOrUndebit(
1271 mCard->getSvGetHeader(),
1272 mCard->getSvGetData(),
1276 svCommand->finalizeCommand(svComplementaryData);
1280const std::vector<uint8_t> CardTransactionManagerAdapter::processSamSvPrepareLoad(
1281 const std::vector<uint8_t>& svGetHeader,
1282 const std::vector<uint8_t>& svGetData,
1283 const std::shared_ptr<CmdCardSvReload> cmdCardSvReload)
1285 const std::shared_ptr<CmdSamSvPrepareLoad> cmdSamSvPrepareLoad =
1286 mControlSamTransactionManager->prepareSvPrepareLoad(svGetHeader, svGetData, cmdCardSvReload);
1287 mControlSamTransactionManager->processCommands();
1288 const std::vector<uint8_t> prepareOperationData =
1289 cmdSamSvPrepareLoad->getApduResponse()->getDataOut();
1291 return computeOperationComplementaryData(prepareOperationData);
1294const std::vector<uint8_t> CardTransactionManagerAdapter::processSamSvPrepareDebitOrUndebit(
1295 const bool isDebitCommand,
1296 const std::vector<uint8_t> svGetHeader,
1297 const std::vector<uint8_t> svGetData,
1298 const std::shared_ptr<CmdCardSvDebitOrUndebit> cmdCardSvDebitOrUndebit)
1300 const std::shared_ptr<CmdSamSvPrepareDebitOrUndebit> cmdSamSvPrepareDebitOrUndebit =
1301 mControlSamTransactionManager->prepareSvPrepareDebitOrUndebit(isDebitCommand,
1304 cmdCardSvDebitOrUndebit);
1305 mControlSamTransactionManager->processCommands();
1306 const std::vector<uint8_t> prepareOperationData =
1307 cmdSamSvPrepareDebitOrUndebit->getApduResponse()->getDataOut();
1309 return computeOperationComplementaryData(prepareOperationData);
1312const std::vector<uint8_t> CardTransactionManagerAdapter::computeOperationComplementaryData(
1313 const std::vector<uint8_t>& prepareOperationData)
1315 const std::vector<uint8_t>& samSerialNumber =
1316 mSecuritySetting->getControlSam()->getSerialNumber();
1317 std::vector<uint8_t> operationComplementaryData(samSerialNumber.size() +
1318 prepareOperationData.size());
1320 System::arraycopy(samSerialNumber, 0, operationComplementaryData, 0, samSerialNumber.size());
1321 System::arraycopy(prepareOperationData,
1323 operationComplementaryData,
1324 samSerialNumber.size(),
1325 prepareOperationData.size());
1327 return operationComplementaryData;
1330void CardTransactionManagerAdapter::processSamSvCheck(
const std::vector<uint8_t>& svOperationData)
1332 mControlSamTransactionManager->prepareSvCheck(svOperationData);
1335 mControlSamTransactionManager->processCommands();
1336 }
catch (
const ReaderIOException& e) {
1337 throw CardSignatureNotVerifiableException(MSG_CARD_SIGNATURE_NOT_VERIFIABLE_SV,
1338 std::make_shared<ReaderIOException>(e));
1339 }
catch (
const SamIOException& e) {
1340 throw CardSignatureNotVerifiableException(MSG_CARD_SIGNATURE_NOT_VERIFIABLE_SV,
1341 std::make_shared<SamIOException>(e));
1345const std::vector<uint8_t> CardTransactionManagerAdapter::processSamGetChallenge()
1347 const std::shared_ptr<CmdSamGetChallenge> cmdSamGetChallenge =
1348 mControlSamTransactionManager->prepareGetChallenge();
1349 mControlSamTransactionManager->processCommands();
1350 const std::vector<uint8_t> samChallenge = cmdSamGetChallenge->getChallenge();
1352 mLogger->debug(
"SAM_CHALLENGE=%\n", HexUtil::toHex(samChallenge));
1354 return samChallenge;
1357const std::vector<uint8_t> CardTransactionManagerAdapter::processSamSessionClosing()
1359 const std::shared_ptr<CmdSamDigestClose> cmdSamDigestClose =
1360 mControlSamTransactionManager->prepareSessionClosing();
1361 mControlSamTransactionManager->processCommands();
1362 const std::vector<uint8_t> terminalSignature = cmdSamDigestClose->getSignature();
1364 mLogger->debug(
"SAM_SIGNATURE=%\n", HexUtil::toHex(terminalSignature));
1366 return terminalSignature;
1369void CardTransactionManagerAdapter::processSamDigestAuthenticate(
1370 const std::vector<uint8_t>& cardSignature)
1372 mControlSamTransactionManager->prepareDigestAuthenticate(cardSignature);
1375 mControlSamTransactionManager->processCommands();
1376 }
catch (
const ReaderIOException& e) {
1377 throw CardSignatureNotVerifiableException(MSG_CARD_SIGNATURE_NOT_VERIFIABLE,
1378 std::make_shared<ReaderIOException>(e));
1379 }
catch (
const SamIOException& e) {
1380 throw CardSignatureNotVerifiableException(MSG_CARD_SIGNATURE_NOT_VERIFIABLE,
1381 std::make_shared<SamIOException>(e));
1385void CardTransactionManagerAdapter::checkSession()
1387 if (!mIsSessionOpen) {
1388 throw IllegalStateException(
"No session is open");
1392void CardTransactionManagerAdapter::checkNoSession()
1394 if (mIsSessionOpen) {
1395 throw IllegalStateException(
"Session is open");
1399int CardTransactionManagerAdapter::computeCommandSessionBufferSize(
1400 std::shared_ptr<AbstractCardCommand> command)
1402 return mCard->isModificationsCounterInBytes() ?
1403 static_cast<int>(command->getApduRequest()->getApdu().size()) +
1404 SESSION_BUFFER_CMD_ADDITIONAL_COST -
1405 APDU_HEADER_LENGTH :
1410void CardTransactionManagerAdapter::resetModificationsBufferCounter()
1412 mLogger->trace(
"Modifications buffer counter reset: PREVIOUSVALUE = %, NEWVALUE = %\n",
1413 mModificationsCounter,
1414 mCard->getModificationsCounter());
1416 mModificationsCounter = mCard->getModificationsCounter();
1421 mChannelControl = ChannelControl::CLOSE_AFTER;
1427 const std::vector<uint8_t>& lid)
1429 Assert::getInstance().isEqual(lid.size(), 2,
"lid length");
1431 return prepareSelectFile(
static_cast<uint16_t
>(ByteArrayUtil::extractInt(lid, 0, 2,
false)));
1436 mCardCommands.push_back(std::make_shared<CmdCardSelectFile>(mCard->getCardClass(),
1437 mCard->getProductType(),
1444 const SelectFileControl selectFileControl)
1447 mCardCommands.push_back(std::make_shared<CmdCardSelectFile>(mCard->getCardClass(),
1448 selectFileControl));
1457 case GetDataTag::FCI_FOR_CURRENT_DF:
1458 mCardCommands.push_back(std::make_shared<CmdCardGetDataFci>(mCard->getCardClass()));
1460 case GetDataTag::FCP_FOR_CURRENT_FILE:
1461 mCardCommands.push_back(std::make_shared<CmdCardGetDataFcp>(mCard->getCardClass()));
1463 case GetDataTag::EF_LIST:
1464 mCardCommands.push_back(std::make_shared<CmdCardGetDataEfList>(mCard->getCardClass()));
1466 case GetDataTag::TRACEABILITY_INFORMATION:
1467 mCardCommands.push_back(
1468 std::make_shared<CmdCardGetDataTraceabilityInformation>(mCard->getCardClass()));
1471 std::stringstream ss;
1473 throw UnsupportedOperationException(
"Unsupported Get Data tag: " + ss.str());
1480 const uint8_t sfi,
const uint8_t recordNumber)
1487 const uint8_t firstRecordNumber,
1488 const uint8_t numberOfRecords,
1489 const uint8_t recordSize)
1493 firstRecordNumber + numberOfRecords - 1,
1498 const uint8_t sfi,
const uint8_t countersNumber)
1504 const uint8_t sfi,
const uint8_t recordNumber)
1506 Assert::getInstance().isInRange(sfi,
1510 .isInRange(recordNumber,
1515 if (mIsSessionOpen &&
1516 !std::dynamic_pointer_cast<CardReader>(mCardReader)->isContactless()) {
1517 throw IllegalStateException(
"Explicit record size is expected inside a secure session in " \
1521 auto cmdCardReadRecords =
1522 std::make_shared<CmdCardReadRecords>(mCard->getCardClass(),
1526 static_cast<uint8_t
>(0));
1527 mCardCommands.push_back(cmdCardReadRecords);
1534 const uint8_t fromRecordNumber,
1535 const uint8_t toRecordNumber,
1536 const uint8_t recordSize)
1538 Assert::getInstance().isInRange(sfi,
1542 .isInRange(fromRecordNumber,
1546 .isInRange(toRecordNumber,
1551 if (toRecordNumber == fromRecordNumber) {
1553 mCardCommands.push_back(
1554 std::make_shared<CmdCardReadRecords>(mCard->getCardClass(),
1566 const uint8_t nbBytesPerRecord = recordSize + 2;
1567 const uint8_t nbRecordsPerApdu =
1568 static_cast<uint8_t
>(mCard->getPayloadCapacity() / nbBytesPerRecord);
1569 const uint8_t dataSizeMaxPerApdu = nbRecordsPerApdu * nbBytesPerRecord;
1571 uint8_t currentRecordNumber = fromRecordNumber;
1572 uint8_t nbRecordsRemainingToRead = toRecordNumber - fromRecordNumber + 1;
1573 uint8_t currentLength;
1575 while (currentRecordNumber < toRecordNumber) {
1576 currentLength = nbRecordsRemainingToRead <= nbRecordsPerApdu ?
1577 nbRecordsRemainingToRead * nbBytesPerRecord :
1580 mCardCommands.push_back(
1581 std::make_shared<CmdCardReadRecords>(cardClass,
1583 currentRecordNumber,
1587 currentRecordNumber += (currentLength / nbBytesPerRecord);
1588 nbRecordsRemainingToRead -= (currentLength / nbBytesPerRecord);
1592 if (currentRecordNumber == toRecordNumber) {
1593 mCardCommands.push_back(
1594 std::make_shared<CmdCardReadRecords>(cardClass,
1596 currentRecordNumber,
1607 const uint8_t fromRecordNumber,
1608 const uint8_t toRecordNumber,
1609 const uint8_t offset,
1610 const uint8_t nbBytesToRead)
1612 if (mCard->getProductType() != CalypsoCard::ProductType::PRIME_REVISION_3 &&
1613 mCard->getProductType() != CalypsoCard::ProductType::LIGHT) {
1614 throw UnsupportedOperationException(
"The 'Read Record Multiple' command is not available "\
1618 Assert::getInstance().isInRange(sfi,
1622 .isInRange(fromRecordNumber,
1626 .isInRange(toRecordNumber,
1634 .isInRange(nbBytesToRead,
1640 const uint8_t nbRecordsPerApdu =
1641 static_cast<uint8_t
>(mCard->getPayloadCapacity() / nbBytesToRead);
1643 uint8_t currentRecordNumber = fromRecordNumber;
1645 while (currentRecordNumber <= toRecordNumber) {
1646 mCardCommands.push_back(
1647 std::make_shared<CmdCardReadRecordMultiple>(cardClass,
1649 currentRecordNumber,
1652 currentRecordNumber += nbRecordsPerApdu;
1659 const uint8_t sfi,
const uint8_t offset,
const uint8_t nbBytesToRead)
1661 if (mCard->getProductType() != CalypsoCard::ProductType::PRIME_REVISION_3) {
1662 throw UnsupportedOperationException(
"The 'Read Binary' command is not available for this " \
1666 Assert::getInstance().isInRange(sfi,
1674 .greaterOrEqual(nbBytesToRead, 1,
"nbBytesToRead");
1679 mCardCommands.push_back(
1680 std::make_shared<CmdCardReadBinary>(mCard->getCardClass(),
1682 static_cast<uint8_t
>(0),
1683 static_cast<uint8_t
>(1)));
1686 const uint8_t payloadCapacity = mCard->getPayloadCapacity();
1689 uint8_t currentLength;
1690 uint8_t currentOffset = offset;
1691 uint8_t nbBytesRemainingToRead = nbBytesToRead;
1694 currentLength = std::min(nbBytesRemainingToRead, payloadCapacity);
1695 mCardCommands.push_back(std::make_shared<CmdCardReadBinary>(cardClass,
1700 currentOffset += currentLength;
1701 nbBytesRemainingToRead -= currentLength;
1702 }
while (nbBytesRemainingToRead > 0);
1708 const uint8_t sfi,
const uint8_t nbCountersToRead)
1714 const std::shared_ptr<SearchCommandData> data)
1716 if (mCard->getProductType() != CalypsoCard::ProductType::PRIME_REVISION_3) {
1717 throw UnsupportedOperationException(
"The 'Search Record Multiple' command is not " \
1718 "available for this card.");
1721 auto dataAdapter = std::dynamic_pointer_cast<SearchCommandDataAdapter>(data);
1723 throw IllegalArgumentException(
"The provided data must be an instance of " \
1724 "'SearchCommandDataAdapter'");
1727 Assert::getInstance().notNull(dataAdapter,
"data")
1728 .isInRange(dataAdapter->getSfi(),
1732 .isInRange(dataAdapter->getRecordNumber(),
1736 .isInRange(dataAdapter->getOffset(),
1740 .isInRange(dataAdapter->getSearchData().size(),
1744 if (!dataAdapter->getMask().empty()) {
1745 Assert::getInstance().isInRange(dataAdapter->getMask().size(),
1747 dataAdapter->getSearchData().size(),
1751 mCardCommands.push_back(std::make_shared<CmdCardSearchRecordMultiple>(mCard->getCardClass(),
1758 const uint8_t sfi,
const std::vector<uint8_t>& recordData)
1760 Assert::getInstance().isInRange(sfi,
1766 mCardCommands.push_back(std::make_shared<CmdCardAppendRecord>(mCard->getCardClass(),
1775 const uint8_t recordNumber,
1776 const std::vector<uint8_t>& recordData)
1778 Assert::getInstance().isInRange(sfi,
1782 .isInRange(recordNumber,
1788 mCardCommands.push_back(std::make_shared<CmdCardUpdateRecord>(mCard->getCardClass(),
1798 const uint8_t recordNumber,
1799 const std::vector<uint8_t>& recordData)
1801 Assert::getInstance().isInRange(sfi,
1805 .isInRange(recordNumber,
1811 mCardCommands.push_back(std::make_shared<CmdCardWriteRecord>(mCard->getCardClass(),
1821 const uint8_t offset,
1822 const std::vector<uint8_t>& data)
1824 return prepareUpdateOrWriteBinary(
true, sfi, offset, data);
1829 const uint8_t offset,
1830 const std::vector<uint8_t>& data)
1832 return prepareUpdateOrWriteBinary(
false, sfi, offset, data);
1835CardTransactionManager& CardTransactionManagerAdapter::prepareUpdateOrWriteBinary(
1836 const bool isUpdateCommand,
1838 const uint8_t offset,
1839 const std::vector<uint8_t>& data)
1841 if (mCard->getProductType() != CalypsoCard::ProductType::PRIME_REVISION_3) {
1842 throw UnsupportedOperationException(
"The 'Update/Write Binary' command is not available " \
1846 Assert::getInstance().isInRange(sfi,
1854 .notEmpty(data,
"data");
1859 mCardCommands.push_back(
1860 std::make_shared<CmdCardReadBinary>(mCard->getCardClass(),
1862 static_cast<uint8_t
>(0),
1863 static_cast<uint8_t
>(1)));
1866 const uint8_t dataLength =
static_cast<uint8_t
>(data.size());
1867 const uint8_t payloadCapacity = mCard->getPayloadCapacity();
1868 const CalypsoCardClass cardClass = mCard->getCardClass();
1870 uint8_t currentLength;
1871 uint8_t currentOffset = offset;
1872 uint8_t currentIndex = 0;
1875 currentLength =
static_cast<uint8_t
>(
1876 std::min(
static_cast<int>(dataLength - currentIndex),
1877 static_cast<int>(payloadCapacity)));
1879 mCardCommands.push_back(
1880 std::make_shared<CmdCardUpdateOrWriteBinary>(
1885 Arrays::copyOfRange(data, currentIndex, currentIndex + currentLength)));
1887 currentOffset += currentLength;
1888 currentIndex += currentLength;
1889 }
while (currentIndex < dataLength);
1894CardTransactionManager& CardTransactionManagerAdapter::prepareIncreaseOrDecreaseCounter(
1895 const bool isDecreaseCommand,
1897 const uint8_t counterNumber,
1898 const int incDecValue)
1900 Assert::getInstance().isInRange(sfi,
1904 .isInRange(counterNumber,
1908 .isInRange(incDecValue,
1914 mCardCommands.push_back(std::make_shared<CmdCardIncreaseOrDecrease>(isDecreaseCommand,
1915 mCard->getCardClass(),
1924 const uint8_t sfi,
const uint8_t counterNumber,
const int incValue)
1926 return prepareIncreaseOrDecreaseCounter(
false, sfi, counterNumber, incValue);
1930 const uint8_t sfi,
const uint8_t counterNumber,
const int decValue)
1932 return prepareIncreaseOrDecreaseCounter(
true, sfi, counterNumber, decValue);
1937 const std::map<const int, const int>& counterNumberToIncValueMap)
1939 return prepareIncreaseOrDecreaseCounters(
false, sfi, counterNumberToIncValueMap);
1944 const std::map<const int, const int>& counterNumberToDecValueMap)
1946 return prepareIncreaseOrDecreaseCounters(
true, sfi, counterNumberToDecValueMap);
1951 if (!mCard->isPinFeatureAvailable()) {
1952 throw UnsupportedOperationException(MSG_PIN_NOT_AVAILABLE);
1956 mCardCommands.push_back(std::make_shared<CmdCardVerifyPin>(mCard->getCardClass()));
1962 const SvAction svAction)
1964 if (!mCard->isSvFeatureAvailable()) {
1965 throw UnsupportedOperationException(
"Stored Value is not available for this card.");
1969 std::shared_ptr<CalypsoSam> calypsoSam = mSecuritySetting->getControlSam();
1970 const bool useExtendedMode = mCard->isExtendedModeSupported() &&
1971 (calypsoSam ==
nullptr ||
1972 calypsoSam->getProductType() == CalypsoSam::ProductType::SAM_C1 ||
1973 calypsoSam->getProductType() == CalypsoSam::ProductType::HSM_C1);
1975 if (mSecuritySetting->isSvLoadAndDebitLogEnabled() && !useExtendedMode) {
1982 const SvOperation operation1 = SvOperation::RELOAD == svOperation ? SvOperation::DEBIT :
1983 SvOperation::RELOAD;
1995 mSvAction = svAction;
2002 const std::vector<uint8_t>& date,
2003 const std::vector<uint8_t>& time,
2004 const std::vector<uint8_t>& free)
2006 checkSvInsideSession();
2009 auto svReloadCmdBuild = std::make_shared<CmdCardSvReload>(mCard->getCardClass(),
2015 isExtendedModeAllowed());
2025 const std::vector<uint8_t> zero = {0x00, 0x00};
2032void CardTransactionManagerAdapter::checkSvInsideSession()
2035 if (mIsSessionOpen) {
2036 if (!mIsSvOperationInsideSession) {
2037 mIsSvOperationInsideSession =
true;
2039 throw IllegalStateException(
"Only one SV operation is allowed per Secure Session.");
2044bool CardTransactionManagerAdapter::isExtendedModeAllowed()
const
2046 std::shared_ptr<CalypsoSam> calypsoSam = mSecuritySetting->getControlSam();
2048 return mCard->isExtendedModeSupported() &&
2049 (calypsoSam->getProductType() == CalypsoSam::ProductType::SAM_C1 ||
2050 calypsoSam->getProductType() == CalypsoSam::ProductType::HSM_C1);
2055 const std::vector<uint8_t>& date,
2056 const std::vector<uint8_t>& time)
2058 checkSvInsideSession();
2060 if (mSvAction == SvAction::DO &&
2061 !mSecuritySetting->isSvNegativeBalanceAuthorized() &&
2062 (mCard->getSvBalance() - amount) < 0) {
2063 throw IllegalStateException(
"Negative balances not allowed.");
2067 auto command = std::make_shared<CmdCardSvDebitOrUndebit>(mSvAction == SvAction::DO,
2068 mCard->getCardClass(),
2073 isExtendedModeAllowed());
2083 const std::vector<uint8_t> zero = {0x00, 0x00};
2092 if (!mCard->isSvFeatureAvailable()) {
2093 throw UnsupportedOperationException(
"Stored Value is not available for this card.");
2096 if (mCard->getApplicationSubtype() !=
2098 throw UnsupportedOperationException(
"The currently selected application is not an SV " \
2103 const std::vector<uint8_t> dummy;
2104 mCard->setSvData(0, dummy, dummy, 0, 0,
nullptr,
nullptr);
2119 if (mCard->isDfInvalidated()) {
2120 throw IllegalStateException(
"This card is already invalidated.");
2123 mCardCommands.push_back(std::make_shared<CmdCardInvalidate>(mCard->getCardClass()));
2130 if (!mCard->isDfInvalidated()) {
2131 throw IllegalStateException(
"This card is not invalidated.");
2134 mCardCommands.push_back(std::make_shared<CmdCardRehabilitate>(mCard->getCardClass()));
2140 const std::shared_ptr<AbstractCardCommand> command,
const SvOperation svOperation)
2144 mSvOperation = svOperation;
2153 if (!mCardCommands.empty()) {
2154 throw IllegalStateException(
"This SV command can only be placed in the first position" \
2155 " in the list of prepared commands");
2159 throw IllegalStateException(
"This SV command must follow an SV Get command");
2163 if (svOperation != mSvOperation) {
2164 mLogger->error(
"Sv operation = %, current command = %\n", mSvOperation, svOperation);
2165 throw IllegalStateException(
"Inconsistent SV operation.");
2168 mIsSvOperationComplete =
true;
2169 mSvLastModifyingCommand = command;
2172 throw IllegalStateException(
"An SV command is expected.");
2175 mSvLastCommandRef = command->getCommandRef();
2176 mCardCommands.push_back(command);
2181 mCardCommands.clear();
2182 mSvLastModifyingCommand =
nullptr;
2187 const bool flag = mIsSvOperationComplete;
2188 mIsSvOperationComplete =
false;
2195CardTransactionManagerAdapter::ApduResponseAdapter::ApduResponseAdapter(
2196 const std::vector<uint8_t>& apdu)
2198 mStatusWord(((apdu[apdu.size() - 2] & 0x000000FF) << 8) + (apdu[apdu.size() - 1] & 0x000000FF)) {}
2200const std::vector<uint8_t>& CardTransactionManagerAdapter::ApduResponseAdapter::getApdu()
const
2205const std::vector<uint8_t> CardTransactionManagerAdapter::ApduResponseAdapter::getDataOut()
const
2207 return Arrays::copyOfRange(mApdu, 0, mApdu.size() - 2);
2210int CardTransactionManagerAdapter::ApduResponseAdapter::getStatusWord()
const
2215std::ostream&
operator<<(std::ostream& os,
const CardTransactionManagerAdapter::ApduResponseAdapter& ara)
2217 os <<
"APDU_RESPONSE_ADAPTER: {"
2218 <<
"APDU: " << ara.getApdu() <<
", "
2219 <<
"STATUS_WORD: " << ara.getStatusWord()
2226std::ostream&
operator<<(std::ostream& os,
const std::shared_ptr<CardTransactionManagerAdapter::ApduResponseAdapter> ara)
2228 if (ara ==
nullptr) {
2229 os <<
"APDU_RESPONSE_ADAPTER: null";
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_GET
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
const std::vector< std::vector< uint8_t > > & getTransactionAuditData() const final
CardTransactionManager & processChangePin(const std::vector< uint8_t > &newPin) override
CardTransactionManager & prepareUpdateBinary(const uint8_t sfi, const uint8_t offset, const std::vector< uint8_t > &data) final
CardTransactionManager & prepareWriteRecord(const uint8_t sfi, const uint8_t recordNumber, const std::vector< uint8_t > &recordData) override
CardTransactionManager & prepareAppendRecord(const uint8_t sfi, const std::vector< uint8_t > &recordData) override
CardTransactionManager & prepareSvGet(const SvOperation svOperation, const SvAction svAction) override
const std::shared_ptr< CardSecuritySetting > getCardSecuritySetting() const override
const std::shared_ptr< CardSecuritySetting > getSecuritySetting() const override
CardTransactionManager & processCardCommands() override
CardTransactionManager & prepareIncreaseCounter(const uint8_t sfi, const uint8_t counterNumber, const int incValue) override
CardTransactionManagerAdapter(const std::shared_ptr< ProxyReaderApi > cardReader, const std::shared_ptr< CalypsoCardAdapter > card, const std::shared_ptr< CardSecuritySettingAdapter > securitySetting)
CardTransactionManager & prepareReadRecord(const uint8_t sfi, const uint8_t recordNumber) override
CardTransactionManager & prepareVerifySignature(const any data) override
CardTransactionManager & processOpening(const WriteAccessLevel writeAccessLevel) override
void notifyCommandsProcessed()
CardTransactionManager & processVerifyPin(const std::vector< uint8_t > &pin) override
CardTransactionManager & processChangeKey(const uint8_t keyIndex, const uint8_t newKif, const uint8_t newKvc, const uint8_t issuerKif, const uint8_t issuerKvc) override
CardTransactionManager & prepareCheckPinStatus() override
CardTransactionManager & prepareSvReadAllLogs() override
CardTransactionManager & prepareReadRecords(const uint8_t sfi, const uint8_t fromRecordNumber, const uint8_t toRecordNumber, const uint8_t recordSize) override
CardTransactionManager & prepareReadBinary(const uint8_t sfi, const uint8_t offset, const uint8_t nbBytesToRead) override
const std::shared_ptr< CardReader > getCardReader() const override
CardTransactionManager & prepareInvalidate() override
CardTransactionManager & prepareReleaseCardChannel() override
CardTransactionManager & prepareGetData(const GetDataTag tag) override
CardTransactionManager & prepareDecreaseCounter(const uint8_t sfi, const uint8_t counterNumber, const int decValue) override
CardTransactionManager & prepareIncreaseCounters(const uint8_t sfi, const std::map< const int, const int > &counterNumberToIncValueMap) override
CardTransactionManager & prepareRehabilitate() override
CardTransactionManager & prepareSvReload(const int amount, const std::vector< uint8_t > &date, const std::vector< uint8_t > &time, const std::vector< uint8_t > &free) override
bool isSvOperationCompleteOneTime()
CardTransactionManager & prepareReadCounter(const uint8_t sfi, const uint8_t nbCountersToRead) override
CardTransactionManager & processCancel() override
CardTransactionManager & prepareReadRecordsPartially(const uint8_t sfi, const uint8_t fromRecordNumber, const uint8_t toRecordNumber, const uint8_t offset, const uint8_t nbBytesToRead) override
CardTransactionManager & prepareSetCounter(const uint8_t sfi, const uint8_t counterNumber, const int newValue) override
CardTransactionManager & prepareComputeSignature(const any data) override
CardTransactionManager & prepareSvDebit(const int amount, const std::vector< uint8_t > &date, const std::vector< uint8_t > &time) override
CardTransactionManager & processClosing() override
CardTransactionManager & processCommands() override
void addStoredValueCommand(const std::shared_ptr< AbstractCardCommand > command, const SvOperation svOperation)
CardTransactionManager & prepareWriteBinary(const uint8_t sfi, const uint8_t offset, const std::vector< uint8_t > &data) final
CardTransactionManager & prepareDecreaseCounters(const uint8_t sfi, const std::map< const int, const int > &counterNumberToDecValueMap) override
CardTransactionManager & prepareReadCounterFile(const uint8_t sfi, const uint8_t countersNumber) override
CardTransactionManager & prepareSearchRecords(const std::shared_ptr< SearchCommandData > data) override
CardTransactionManager & prepareSelectFile(const std::vector< uint8_t > &lid) override
CardTransactionManager & prepareUpdateRecord(const uint8_t sfi, const uint8_t recordNumber, const std::vector< uint8_t > &recordData) override
CardTransactionManager & prepareReadRecordFile(const uint8_t sfi, const uint8_t recordNumber) override
static const std::shared_ptr< ApduRequestAdapter > getApduRequest(const CalypsoCardClass calypsoCardClass)
const std::string getTransactionAuditDataAsString() const
virtual void saveTransactionAuditData(const std::shared_ptr< CardRequestSpi > cardRequest, const std::shared_ptr< CardResponseApi > cardResponse)
const std::string MSG_WHILE_TRANSMITTING_COMMANDS
const std::vector< std::shared_ptr< ApduRequestSpi > > getApduRequests(const std::vector< std::shared_ptr< AbstractApduCommand > > &commands)
std::ostream & operator<<(std::ostream &os, const std::shared_ptr< ApduRequestAdapter > ara)