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"
35#include "SelectFileException.h"
74#include "ByteArrayUtil.h"
77#include "IllegalStateException.h"
78#include "KeypleAssert.h"
82#include "UnsupportedOperationException.h"
88using namespace calypsonet::terminal::calypso::transaction;
89using namespace calypsonet::terminal::card;
90using namespace calypsonet::terminal::card::spi;
91using namespace keyple::core::util;
92using namespace keyple::core::util::cpp;
93using namespace keyple::core::util::cpp::exception;
96const std::string CardTransactionManagerAdapter::PATTERN_1_BYTE_HEX =
"%020Xh";
98const std::string CardTransactionManagerAdapter::MSG_CARD_READER_COMMUNICATION_ERROR =
99 "A communication error with the card reader occurred ";
100const std::string CardTransactionManagerAdapter::MSG_CARD_COMMUNICATION_ERROR =
101 "A communication error with the card occurred ";
102const std::string CardTransactionManagerAdapter::MSG_CARD_COMMAND_ERROR =
103 "A card command error occurred ";
105const std::string CardTransactionManagerAdapter::MSG_PIN_NOT_AVAILABLE =
106 "PIN is not available for this card.";
107const std::string CardTransactionManagerAdapter::MSG_CARD_SIGNATURE_NOT_VERIFIABLE =
108 "Unable to verify the card signature associated to the successfully closed secure session.";
109const std::string CardTransactionManagerAdapter::MSG_CARD_SIGNATURE_NOT_VERIFIABLE_SV =
110 "Unable to verify the card signature associated to the SV operation.";
112const std::string CardTransactionManagerAdapter::RECORD_NUMBER =
"record number";
113const std::string CardTransactionManagerAdapter::OFFSET =
"offset";
115const int CardTransactionManagerAdapter::SESSION_BUFFER_CMD_ADDITIONAL_COST = 6;
116const int CardTransactionManagerAdapter::APDU_HEADER_LENGTH = 5;
119const std::shared_ptr<ApduResponseApi> CardTransactionManagerAdapter::RESPONSE_OK =
120 std::make_shared<ApduResponseAdapter>(std::vector<uint8_t>({0x90, 0x00}));
121const std::shared_ptr<ApduResponseApi> CardTransactionManagerAdapter::RESPONSE_OK_POSTPONED =
122 std::make_shared<ApduResponseAdapter>(std::vector<uint8_t>({0x62, 0x00}));
125 const std::shared_ptr<ProxyReaderApi> cardReader,
126 const std::shared_ptr<CalypsoCardAdapter> card,
127 const std::shared_ptr<CardSecuritySettingAdapter> securitySetting)
131 std::vector<std::vector<uint8_t>>()),
132 mCardReader(cardReader),
134 mSecuritySetting(securitySetting),
135 mModificationsCounter(card->getModificationsCounter())
137 if (securitySetting !=
nullptr && securitySetting->getControlSam() !=
nullptr) {
139 mControlSamTransactionManager =
140 std::make_shared<CardControlSamTransactionManagerAdapter>(card,
146 mControlSamTransactionManager =
nullptr;
152 return std::dynamic_pointer_cast<CardReader>(mCardReader);
166void CardTransactionManagerAdapter::checkControlSam()
const
168 if (mControlSamTransactionManager ==
nullptr) {
169 throw IllegalStateException(
"Control SAM is not set.");
173void CardTransactionManagerAdapter::processSamPreparedCommands()
175 if (mControlSamTransactionManager !=
nullptr) {
176 mControlSamTransactionManager->processCommands();
180void CardTransactionManagerAdapter::processAtomicOpening(
181 std::vector<std::shared_ptr<AbstractApduCommand>>& cardCommands)
183 if (mSecuritySetting ==
nullptr) {
184 throw IllegalStateException(
"No security settings are available.");
187 mCard->backupFiles();
188 mNbPostponedData = 0;
199 uint8_t recordNumber = 0;
200 uint8_t recordSize = 0;
202 if (!cardCommands.empty()) {
204 const auto cardCommand = std::dynamic_pointer_cast<AbstractCardCommand>(cardCommands[0]);
206 std::dynamic_pointer_cast<CmdCardReadRecords>(cardCommand)->getReadMode() ==
208 sfi = std::dynamic_pointer_cast<CmdCardReadRecords>(cardCommand)->getSfi();
210 std::dynamic_pointer_cast<CmdCardReadRecords>(cardCommand)->getFirstRecordNumber();
212 std::dynamic_pointer_cast<CmdCardReadRecords>(cardCommand)->getRecordSize();
213 cardCommands.erase(cardCommands.begin());
218 const std::vector<uint8_t> samChallenge = processSamGetChallenge();
221 auto cmdCardOpenSession =
222 std::make_shared<CmdCardOpenSession>(
224 static_cast<uint8_t
>(
static_cast<int>(mWriteAccessLevel) + 1),
229 isExtendedModeAllowed());
232 cardCommands.insert(cardCommands.begin(), cmdCardOpenSession);
235 const std::vector<std::shared_ptr<ApduRequestSpi>> apduRequests =
239 auto cardRequest = std::make_shared<CardRequestAdapter>(apduRequests,
true);
241 mIsSessionOpen =
true;
244 const std::shared_ptr<CardResponseApi> cardResponse =
245 transmitCardRequest(cardRequest, ChannelControl::KEEP_OPEN);
248 const std::vector<std::shared_ptr<ApduResponseApi>> apduResponses =
249 cardResponse->getApduResponses();
258 std::vector<std::shared_ptr<AbstractCardCommand>> copy;
259 for (
int i = 0; i < static_cast<int>(cardCommands.size()); i++) {
261 copy.push_back(std::dynamic_pointer_cast<AbstractCardCommand>(cardCommands[i]));
264 parseApduResponses(copy, apduResponses);
266 }
catch (
const CardCommandException& e) {
268 throw UnexpectedCommandStatusException(MSG_CARD_COMMAND_ERROR +
269 "while processing the response to open session: " +
270 e.getCommand().getName() +
272 std::make_shared<CardCommandException>(e));
274 }
catch (
const InconsistentDataException& e) {
282 const std::shared_ptr<uint8_t> cardKif = cmdCardOpenSession->getSelectedKif();
283 const std::shared_ptr<uint8_t> cardKvc = cmdCardOpenSession->getSelectedKvc();
285 const std::string logCardKif = cardKif !=
nullptr ? std::to_string(*cardKif) :
"null";
286 const std::string logCardKvc = cardKvc !=
nullptr ? std::to_string(*cardKvc) :
"null";
288 mLogger->debug(
"processAtomicOpening => opening: CARD_CHALLENGE=%, CARD_KIF=%, CARD_KVC=%\n",
289 HexUtil::toHex(cmdCardOpenSession->getCardChallenge()),
293 const std::shared_ptr<uint8_t> kvc =
294 mControlSamTransactionManager->computeKvc(mWriteAccessLevel, cardKvc);
295 const std::shared_ptr<uint8_t> kif =
296 mControlSamTransactionManager->computeKif(mWriteAccessLevel, cardKif, kvc);
298 if (!mSecuritySetting->isSessionKeyAuthorized(kif, kvc)) {
300 const std::string logKif = kif !=
nullptr ? std::to_string(*kif) :
"null";
301 const std::string logKvc = kvc !=
nullptr ? std::to_string(*kvc) :
"null";
303 throw UnauthorizedKeyException(
"Unauthorized key error: " \
304 "KIF=" + logKif +
", " +
305 "KVC=" + logKvc +
" " +
310 mControlSamTransactionManager
311 ->initializeSession(apduResponses[0]->getDataOut(), *kif, *kvc,
false,
false);
318 mControlSamTransactionManager->updateSession(apduRequests, apduResponses, 1);
321void CardTransactionManagerAdapter::abortSecureSessionSilently()
323 if (mIsSessionOpen) {
329 }
catch (
const RuntimeException& e) {
331 mLogger->warn(
"An error occurred while aborting the current secure session: %",
335 mIsSessionOpen =
false;
340 const uint8_t sfi,
const uint8_t counterNumber,
const int newValue)
342 std::shared_ptr<int> oldValue;
344 const std::shared_ptr<ElementaryFile> ef = mCard->getFileBySfi(sfi);
347 oldValue = ef->getData()->getContentAsCounterValue(counterNumber);
350 if (oldValue ==
nullptr) {
352 throw IllegalStateException(
"The value for counter " + std::to_string(counterNumber) +
353 " in file " + std::to_string(sfi) +
" is not available");
356 const int delta = newValue - *oldValue;
359 mLogger->trace(
"Increment counter % (file %) from % to %\n",
367 }
else if (delta < 0) {
369 mLogger->trace(
"Decrement counter % (file %) from % to %\n",
379 mLogger->info(
"The counter % (SFI %) is already set to the desired value %\n",
388CardTransactionManager& CardTransactionManagerAdapter::prepareIncreaseOrDecreaseCounters(
389 const bool isDecreaseCommand,
391 const std::map<const int, const int>& counterNumberToIncDecValueMap)
393 Assert::getInstance().isInRange((
int) sfi,
397 .isInRange(counterNumberToIncDecValueMap.size(),
400 "counterNumberToIncDecValueMap");
402 for (
const auto& entry : counterNumberToIncDecValueMap) {
404 Assert::getInstance().isInRange(entry.first,
407 "counterNumberToIncDecValueMapKey")
408 .isInRange(entry.second,
411 "counterNumberToIncDecValueMapValue");
414 if (mCard->getProductType() != CalypsoCard::ProductType::PRIME_REVISION_3 &&
415 mCard->getProductType() != CalypsoCard::ProductType::PRIME_REVISION_2) {
417 for (
const auto& entry : counterNumberToIncDecValueMap) {
419 if (isDecreaseCommand) {
431 const int nbCountersPerApdu = mCard->getPayloadCapacity() / 4;
433 if (
static_cast<int>(counterNumberToIncDecValueMap.size()) <= nbCountersPerApdu) {
436 mCardCommands.push_back(
437 std::make_shared<CmdCardIncreaseOrDecreaseMultiple>(
441 counterNumberToIncDecValueMap));
450 std::map<const int, const int> map;
452 for (
const auto& entry : counterNumberToIncDecValueMap) {
456 map.insert({entry.first, entry.second});
458 if (i == nbCountersPerApdu) {
460 mCardCommands.push_back(
461 std::make_shared<CmdCardIncreaseOrDecreaseMultiple>(
474 mCardCommands.push_back(
475 std::make_shared<CmdCardIncreaseOrDecreaseMultiple>(
487void CardTransactionManagerAdapter::processAtomicCardCommands(
488 const std::vector<std::shared_ptr<AbstractApduCommand>> cardCommands,
489 const ChannelControl channelControl)
492 std::vector<std::shared_ptr<ApduRequestSpi>> apduRequests =
getApduRequests(cardCommands);
495 std::shared_ptr<CardRequestSpi> cardRequest =
496 std::make_shared<CardRequestAdapter>(apduRequests,
true);
499 const std::shared_ptr<CardResponseApi> cardResponse =
500 transmitCardRequest(cardRequest, channelControl);
503 const std::vector<std::shared_ptr<ApduResponseApi>> apduResponses =
504 cardResponse->getApduResponses();
510 if (mIsSessionOpen) {
512 mControlSamTransactionManager->updateSession(apduRequests, apduResponses, 0);
521 std::vector<std::shared_ptr<AbstractCardCommand>> copy;
523 for (
int i = 0; i < static_cast<int>(cardCommands.size()); i++) {
525 copy.push_back(std::dynamic_pointer_cast<AbstractCardCommand>(cardCommands[i]));
528 parseApduResponses(copy, apduResponses);
530 }
catch (
const CardCommandException& e) {
532 throw UnexpectedCommandStatusException(MSG_CARD_COMMAND_ERROR +
533 "while processing responses to card commands: " +
534 e.getCommand().getName() +
536 std::make_shared<CardCommandException>(e));
538 }
catch (
const InconsistentDataException& e) {
544void CardTransactionManagerAdapter::parseApduResponses(
545 const std::vector<std::shared_ptr<AbstractCardCommand>>& commands,
546 const std::vector<std::shared_ptr<ApduResponseApi>>& apduResponses)
553 if (apduResponses.size() > commands.size()) {
555 throw InconsistentDataException(
"The number of commands/responses does not match: nb " \
557 std::to_string(commands.size()) +
558 ", nb responses = " +
559 std::to_string(apduResponses.size()));
567 for (
int i = 0; i < static_cast<int>(apduResponses.size()); i++) {
571 commands[i]->parseApduResponse(apduResponses[i]);
573 }
catch (
const CardCommandException& e) {
575 const CalypsoCardCommand& commandRef = commands[i]->getCommandRef();
579 (void)
dynamic_cast<const CardDataAccessException&
>(e);
586 checkResponseStatusForStrictAndBestEffortMode(commands[i], e);
590 throw SelectFileException(
"File not found",
591 std::make_shared<CardCommandException>(e));
595 throw UnexpectedCommandStatusException(
596 MSG_CARD_COMMAND_ERROR +
597 "while processing responses to card commands: " +
598 e.getCommand().getName() +
600 std::make_shared<CardCommandException>(e));
603 }
catch (
const std::bad_cast& ex) {
607 throw UnexpectedCommandStatusException(
608 MSG_CARD_COMMAND_ERROR +
609 "while processing responses to card commands: " +
610 e.getCommand().getName() +
612 std::make_shared<CardCommandException>(e));
621 if (apduResponses.size() < commands.size()) {
623 throw InconsistentDataException(
"The number of commands/responses does not match: nb " \
625 std::to_string(commands.size()) +
626 ", nb responses = " +
627 std::to_string(apduResponses.size()));
631void CardTransactionManagerAdapter::checkResponseStatusForStrictAndBestEffortMode(
632 const std::shared_ptr<AbstractCardCommand> command,
633 const CardCommandException& e)
const
635 if (mIsSessionOpen) {
645 if (command->getApduResponse()->getStatusWord() != 0x6A82 &&
646 command->getApduResponse()->getStatusWord() != 0x6A83) {
653void CardTransactionManagerAdapter::processAtomicClosing(
654 const std::vector<std::shared_ptr<AbstractApduCommand>>& cardCommands,
655 const bool isRatificationMechanismEnabled,
656 const ChannelControl channelControl)
659 std::vector<std::shared_ptr<ApduRequestSpi>> apduRequests =
getApduRequests(cardCommands);
662 const std::vector<std::shared_ptr<ApduResponseApi>> expectedApduResponses =
663 buildAnticipatedResponses(cardCommands);
666 mControlSamTransactionManager->updateSession(apduRequests, expectedApduResponses, 0);
672 const std::vector<uint8_t> sessionTerminalSignature = processSamSessionClosing();
675 auto cmdCardCloseSession =
676 std::make_shared<CmdCardCloseSession>(mCard,
677 !isRatificationMechanismEnabled,
678 sessionTerminalSignature);
680 apduRequests.push_back(cmdCardCloseSession->getApduRequest());
683 bool isRatificationCommandAdded;
685 if (isRatificationMechanismEnabled &&
686 std::dynamic_pointer_cast<CardReader>(mCardReader)->isContactless()) {
693 apduRequests.push_back(
695 isRatificationCommandAdded =
true;
699 isRatificationCommandAdded =
false;
703 auto cardRequest = std::make_shared<CardRequestAdapter>(apduRequests,
true);
706 std::shared_ptr<CardResponseApi> cardResponse;
710 cardResponse = transmitCardRequest(cardRequest, channelControl);
712 }
catch (
const CardIOException& e) {
714 const auto cause = std::dynamic_pointer_cast<AbstractApduException>(e.getCause());
715 cardResponse = cause->getCardResponse();
724 if (!isRatificationCommandAdded ||
725 cardResponse ==
nullptr ||
726 cardResponse->getApduResponses().size() != apduRequests.size() - 1) {
732 std::vector<std::shared_ptr<ApduResponseApi>> apduResponses = cardResponse->getApduResponses();
735 if (isRatificationCommandAdded && apduResponses.size() == cardCommands.size() + 2) {
736 apduResponses.pop_back();
740 std::shared_ptr<ApduResponseApi> closeSecureSessionApduResponse =
nullptr;
741 if (apduResponses.size() == cardCommands.size() + 1) {
742 closeSecureSessionApduResponse = apduResponses.back();
743 apduResponses.pop_back();
755 std::vector<std::shared_ptr<AbstractCardCommand>> copy;
756 for (
int i = 0; i < static_cast<int>(cardCommands.size()); i++) {
758 copy.push_back(std::dynamic_pointer_cast<AbstractCardCommand>(cardCommands[i]));
761 parseApduResponses(copy, apduResponses);
763 }
catch (
const CardCommandException& e) {
765 throw UnexpectedCommandStatusException(MSG_CARD_COMMAND_ERROR +
766 "while processing of responses preceding the close" \
767 " of the session: " +
768 e.getCommand().getName() +
770 std::make_shared<CardCommandException>(e));
772 }
catch (
const InconsistentDataException& e) {
778 mIsSessionOpen =
false;
783 cmdCardCloseSession->parseApduResponse(closeSecureSessionApduResponse);
785 }
catch (
const CardSecurityDataException& e) {
787 throw UnexpectedCommandStatusException(
"Invalid card session" +
789 std::make_shared<CardSecurityDataException>(e));
791 }
catch (
const CardCommandException& e) {
793 throw UnexpectedCommandStatusException(MSG_CARD_COMMAND_ERROR +
794 "while processing the response to close session: " +
795 e.getCommand().getName() +
797 std::make_shared<CardCommandException>(e));
804 processSamDigestAuthenticate(cmdCardCloseSession->getSignatureLo());
811 processSamSvCheck(cmdCardCloseSession->getPostponedData()[mSvPostponedDataIndex]);
815int CardTransactionManagerAdapter::getCounterValue(
const uint8_t sfi,
const int counter)
817 const std::shared_ptr<ElementaryFile> ef = mCard->getFileBySfi(sfi);
819 const std::shared_ptr<int> counterValue = ef->getData()->getContentAsCounterValue(counter);
820 if (counterValue !=
nullptr) {
821 return *counterValue;
825 std::stringstream ss;
826 ss <<
"Anticipated response. Unable to determine anticipated value of counter "
830 throw IllegalStateException(ss.str());
833const std::map<const int, const int> CardTransactionManagerAdapter::getCounterValues(
834 const uint8_t sfi,
const std::vector<int>& counters)
836 const std::shared_ptr<ElementaryFile> ef = mCard->getFileBySfi(sfi);
838 const std::map<const int, const int> allCountersValue = ef->getData()->getAllCountersValue();
840 if (Arrays::containsAll(MapUtils::getKeySet(allCountersValue), counters)) {
841 return allCountersValue;
845 std::stringstream ss;
846 ss <<
"Anticipated response. Unable to determine anticipated value of counters in EF sfi "
848 throw IllegalStateException(ss.str());
851const std::vector<uint8_t>
852 CardTransactionManagerAdapter::buildAnticipatedIncreaseDecreaseResponseData(
853 const bool isDecreaseCommand,
854 const int currentCounterValue,
855 const int incDecValue)
857 const int newValue = isDecreaseCommand ? currentCounterValue - incDecValue :
858 currentCounterValue + incDecValue;
860 return ByteArrayUtil::extractBytes(newValue, 3);
863const std::shared_ptr<ApduResponseApi>
864 CardTransactionManagerAdapter::buildAnticipatedIncreaseDecreaseResponse(
865 const std::vector<uint8_t>& data)
868 std::vector<uint8_t> response(5);
869 response[0] = data[0];
870 response[1] = data[1];
871 response[2] = data[2];
875 return std::make_shared<ApduResponseAdapter>(response);
878const std::shared_ptr<ApduResponseApi>
879 CardTransactionManagerAdapter::buildAnticipatedIncreaseDecreaseMultipleResponse(
880 const bool isDecreaseCommand,
881 const std::map<const int, const int>& counterNumberToCurrentValueMap,
882 const std::map<const int, const int>& counterNumberToIncDecValueMap)
885 std::vector<uint8_t> response(2 + counterNumberToIncDecValueMap.size() * 4);
888 for (
const auto& entry : counterNumberToIncDecValueMap) {
889 response[index] =
static_cast<uint8_t
>(entry.first);
891 if (isDecreaseCommand) {
892 const auto it = counterNumberToCurrentValueMap.find(entry.first);
893 newCounterValue = it->second - entry.second;
895 const auto it = counterNumberToCurrentValueMap.find(entry.first);
896 newCounterValue = it->second + entry.second;
899 ByteArrayUtil::copyBytes(newCounterValue, response, index + 1, 3);
904 response[index] = 0x90;
905 response[index + 1] = 0x00;
907 return std::make_shared<ApduResponseAdapter>(response);
910const std::vector<std::shared_ptr<ApduResponseApi>>
911 CardTransactionManagerAdapter::buildAnticipatedResponses(
912 const std::vector<std::shared_ptr<AbstractApduCommand>>& cardCommands)
914 std::vector<std::shared_ptr<ApduResponseApi>> apduResponses;
916 if (!cardCommands.empty()) {
918 for (
const auto& command : cardCommands) {
920 auto& commandRef =
dynamic_cast<const CalypsoCardCommand&
>(command->getCommandRef());
924 auto cmdA = std::dynamic_pointer_cast<CmdCardIncreaseOrDecrease>(command);
926 const std::vector<uint8_t> anticipatedValue =
927 buildAnticipatedIncreaseDecreaseResponseData(
929 getCounterValue(cmdA->getSfi(), cmdA->getCounterNumber()),
930 cmdA->getIncDecValue());
932 if (mCard->isCounterValuePostponed()) {
934 cmdA->setComputedData(anticipatedValue);
935 apduResponses.push_back(RESPONSE_OK_POSTPONED);
940 apduResponses.push_back(
941 buildAnticipatedIncreaseDecreaseResponse(anticipatedValue));
947 auto cmdB = std::dynamic_pointer_cast<CmdCardIncreaseOrDecreaseMultiple>(command);
948 const std::map<const int, const int>& counterNumberToIncDecValueMap =
949 cmdB->getCounterNumberToIncDecValueMap();
950 apduResponses.push_back(
951 buildAnticipatedIncreaseDecreaseMultipleResponse(
953 getCounterValues(cmdB->getSfi(),
954 MapUtils::getKeySet(counterNumberToIncDecValueMap)),
955 counterNumberToIncDecValueMap));
961 apduResponses.push_back(RESPONSE_OK_POSTPONED);
962 mSvPostponedDataIndex = mNbPostponedData;
968 apduResponses.push_back(RESPONSE_OK);
973 return apduResponses;
977 const WriteAccessLevel writeAccessLevel)
983 mWriteAccessLevel = writeAccessLevel;
986 std::vector<std::shared_ptr<AbstractApduCommand>> cardAtomicCommands;
988 for (
const auto& apduCommand : mCardCommands) {
990 const auto& command = std::dynamic_pointer_cast<AbstractCardCommand>(apduCommand);
994 throw IllegalStateException(
"Command not allowed in secure session.");
997 && std::dynamic_pointer_cast<CmdCardReadRecords>(command)->getSfi() != 0
998 && std::dynamic_pointer_cast<CmdCardReadRecords>(command)->getRecordSize() == -1) {
999 throw IllegalStateException(
"Explicit record size is expected inside a secure session.");
1002 if (command->isSessionBufferUsed()) {
1003 mModificationsCounter -= computeCommandSessionBufferSize(command);
1004 if (mModificationsCounter < 0) {
1005 checkMultipleSessionEnabled(command);
1008 processAtomicOpening(cardAtomicCommands);
1009 std::vector<std::shared_ptr<AbstractApduCommand>> empty;
1010 processAtomicClosing(empty,
false, ChannelControl::KEEP_OPEN);
1013 mModificationsCounter = mCard->getModificationsCounter();
1014 mModificationsCounter -= computeCommandSessionBufferSize(command);
1017 cardAtomicCommands.clear();
1021 cardAtomicCommands.push_back(command);
1024 processAtomicOpening(cardAtomicCommands);
1030 mIsSvOperationInsideSession =
false;
1034 }
catch (
const RuntimeException& e) {
1036 abortSecureSessionSilently();
1041void CardTransactionManagerAdapter::checkMultipleSessionEnabled(
1042 std::shared_ptr<AbstractCardCommand> command)
const
1049 if (!mSecuritySetting->isMultipleSessionEnabled()) {
1050 throw SessionBufferOverflowException(
"ATOMIC mode error! This command would overflow the " \
1051 "card modifications buffer: " +
1052 command->getName() +
1057void CardTransactionManagerAdapter::processCommandsOutsideSession(
1058 const ChannelControl channelControl)
1061 processAtomicCardCommands(mCardCommands, channelControl);
1069 processSamSvCheck(mCard->getSvOperationSignature());
1072 processSamPreparedCommands();
1076void CardTransactionManagerAdapter::processCommandsInsideSession()
1080 std::vector<std::shared_ptr<AbstractApduCommand>> cardAtomicCommands;
1081 bool isAtLeastOneReadCommand =
false;
1083 for (
const auto& apduCommand : mCardCommands) {
1085 const auto& command = std::dynamic_pointer_cast<AbstractCardCommand>(apduCommand);
1088 if (command->isSessionBufferUsed()) {
1089 mModificationsCounter -= computeCommandSessionBufferSize(command);
1090 if (mModificationsCounter < 0) {
1091 checkMultipleSessionEnabled(command);
1096 if (isAtLeastOneReadCommand) {
1097 processAtomicCardCommands(cardAtomicCommands, ChannelControl::KEEP_OPEN);
1098 cardAtomicCommands.clear();
1101 processAtomicClosing(cardAtomicCommands,
false, ChannelControl::KEEP_OPEN);
1102 std::vector<std::shared_ptr<AbstractApduCommand>> empty;
1103 processAtomicOpening(empty);
1106 mModificationsCounter = mCard->getModificationsCounter();
1107 mModificationsCounter -= computeCommandSessionBufferSize(command);
1108 isAtLeastOneReadCommand =
false;
1111 cardAtomicCommands.clear();
1114 isAtLeastOneReadCommand =
true;
1117 cardAtomicCommands.push_back(command);
1120 processAtomicCardCommands(cardAtomicCommands, ChannelControl::KEEP_OPEN);
1125 processSamPreparedCommands();
1127 }
catch (
const RuntimeException& e) {
1128 abortSecureSessionSilently();
1135 return mSecuritySetting;
1142 mControlSamTransactionManager->prepareComputeSignature(data);
1152 mControlSamTransactionManager->prepareVerifySignature(data);
1159 finalizeSvCommandIfNeeded();
1161 if (mIsSessionOpen) {
1162 processCommandsInsideSession();
1164 processCommandsOutsideSession(mChannelControl);
1179 finalizeSvCommandIfNeeded();
1181 std::vector<std::shared_ptr<AbstractApduCommand>> cardAtomicCommands;
1182 bool isAtLeastOneReadCommand =
false;
1184 for (
const auto& apduCommand : mCardCommands) {
1186 const auto& command = std::dynamic_pointer_cast<AbstractCardCommand>(apduCommand);
1189 if (command->isSessionBufferUsed()) {
1190 mModificationsCounter -= computeCommandSessionBufferSize(command);
1191 if (mModificationsCounter < 0) {
1192 checkMultipleSessionEnabled(command);
1198 if (isAtLeastOneReadCommand) {
1199 processAtomicCardCommands(cardAtomicCommands, ChannelControl::KEEP_OPEN);
1200 cardAtomicCommands.clear();
1203 processAtomicClosing(cardAtomicCommands,
false, ChannelControl::KEEP_OPEN);
1204 std::vector<std::shared_ptr<AbstractApduCommand>> empty;
1205 processAtomicOpening(empty);
1208 mModificationsCounter = mCard->getModificationsCounter();
1209 mModificationsCounter -= computeCommandSessionBufferSize(command);
1210 isAtLeastOneReadCommand =
false;
1213 cardAtomicCommands.clear();
1217 isAtLeastOneReadCommand =
true;
1220 cardAtomicCommands.push_back(command);
1223 if (isAtLeastOneReadCommand) {
1224 processAtomicCardCommands(cardAtomicCommands, ChannelControl::KEEP_OPEN);
1225 cardAtomicCommands.clear();
1228 processAtomicClosing(cardAtomicCommands,
1229 mSecuritySetting->isRatificationMechanismEnabled(),
1237 }
catch (
const RuntimeException& e) {
1239 abortSecureSessionSilently();
1248 mCard->restoreFiles();
1251 auto cmdCardCloseSession = std::make_shared<CmdCardCloseSession>(mCard);
1254 std::vector<std::shared_ptr<ApduRequestSpi>> apduRequests;
1255 apduRequests.push_back(cmdCardCloseSession->getApduRequest());
1258 const std::shared_ptr<CardRequestSpi> cardRequest =
1259 std::make_shared<CardRequestAdapter>(apduRequests,
false);
1260 const std::shared_ptr<CardResponseApi> cardResponse =
1261 transmitCardRequest(cardRequest, mChannelControl);
1264 cmdCardCloseSession->parseApduResponse(cardResponse->getApduResponses()[0]);
1266 throw UnexpectedCommandStatusException(MSG_CARD_COMMAND_ERROR +
1267 "while processing the response to close session: " +
1270 std::make_shared<CardCommandException>(e));
1280 mIsSessionOpen =
false;
1286 const std::vector<uint8_t>& pin)
1292 if (!mCard->isPinFeatureAvailable()) {
1294 throw UnsupportedOperationException(MSG_PIN_NOT_AVAILABLE);
1297 if (!mCardCommands.empty()) {
1299 throw IllegalStateException(
"No commands should have been prepared prior to a PIN " \
1303 finalizeSvCommandIfNeeded();
1306 if (mSecuritySetting !=
nullptr && !mSecuritySetting->isPinPlainTransmissionEnabled()) {
1309 mCardCommands.push_back(std::make_shared<CmdCardGetChallenge>(mCard));
1312 processAtomicCardCommands(mCardCommands, ChannelControl::KEEP_OPEN);
1318 std::vector<uint8_t> cipheredPin = processSamCardCipherPin(pin, std::vector<uint8_t>());
1320 mCardCommands.push_back(std::make_shared<CmdCardVerifyPin>(mCard,
true, cipheredPin));
1324 mCardCommands.push_back(std::make_shared<CmdCardVerifyPin>(mCard,
false, pin));
1328 processAtomicCardCommands(mCardCommands, mChannelControl);
1333 processSamPreparedCommands();
1337 }
catch (
const UnsupportedOperationException& e) {
1343 }
catch (
const IllegalStateException& e) {
1349 }
catch (
const RuntimeException& e) {
1351 abortSecureSessionSilently();
1357const std::vector<uint8_t> CardTransactionManagerAdapter::processSamCardCipherPin(
1358 const std::vector<uint8_t>& currentPin,
const std::vector<uint8_t>& newPin)
1360 mControlSamTransactionManager->prepareGiveRandom();
1361 const std::shared_ptr<CmdSamCardCipherPin> cmdSamCardCipherPin =
1362 mControlSamTransactionManager->prepareCardCipherPin(currentPin, newPin);
1363 mControlSamTransactionManager->processCommands();
1365 return cmdSamCardCipherPin->getCipheredData();
1369 const std::vector<uint8_t>& newPin)
1375 if (!mCard->isPinFeatureAvailable()) {
1377 throw UnsupportedOperationException(MSG_PIN_NOT_AVAILABLE);
1380 if (mIsSessionOpen) {
1382 throw IllegalStateException(
"'Change PIN' not allowed when a secure session is open.");
1385 finalizeSvCommandIfNeeded();
1388 if (mSecuritySetting->isPinPlainTransmissionEnabled()) {
1391 if (mCard->getPinAttemptRemaining() >= 0) {
1393 mCardCommands.push_back(std::make_shared<CmdCardChangePin>(mCard, newPin));
1399 mCardCommands.push_back(std::make_shared<CmdCardGetChallenge>(mCard));
1402 processAtomicCardCommands(mCardCommands, ChannelControl::KEEP_OPEN);
1408 std::vector<uint8_t> currentPin(4);
1409 std::vector<uint8_t> newPinData = processSamCardCipherPin(currentPin, newPin);
1411 mCardCommands.push_back(std::make_shared<CmdCardChangePin>(mCard, newPinData));
1415 processAtomicCardCommands(mCardCommands, mChannelControl);
1420 processSamPreparedCommands();
1424 }
catch (
const RuntimeException& e) {
1426 abortSecureSessionSilently();
1432 const uint8_t newKif,
1433 const uint8_t newKvc,
1434 const uint8_t issuerKif,
1435 const uint8_t issuerKvc)
1437 if (mCard->getProductType() == CalypsoCard::ProductType::BASIC) {
1439 throw UnsupportedOperationException(
"The 'Change Key' command is not available for this " \
1443 if (mIsSessionOpen) {
1445 throw IllegalStateException(
"'Change Key' not allowed when a secure session is open.");
1448 Assert::getInstance().isInRange(keyIndex, 1, 3,
"keyIndex");
1450 finalizeSvCommandIfNeeded();
1453 mCardCommands.push_back(std::make_shared<CmdCardGetChallenge>(mCard));
1456 processAtomicCardCommands(mCardCommands, ChannelControl::KEEP_OPEN);
1462 const std::vector<uint8_t> encryptedKey = processSamCardGenerateKey(issuerKif,
1467 mCardCommands.push_back(std::make_shared<CmdCardChangeKey>(mCard, keyIndex, encryptedKey));
1470 processAtomicCardCommands(mCardCommands, mChannelControl);
1478const std::vector<uint8_t> CardTransactionManagerAdapter::processSamCardGenerateKey(
1479 const uint8_t issuerKif,
const uint8_t issuerKvc,
const uint8_t newKif,
const uint8_t newKvc)
1481 mControlSamTransactionManager->prepareGiveRandom();
1482 const std::shared_ptr<CmdSamCardGenerateKey> cmdSamCardGenerateKey =
1483 mControlSamTransactionManager->prepareCardGenerateKey(issuerKif, issuerKvc, newKif, newKvc);
1484 mControlSamTransactionManager->processCommands();
1486 return cmdSamCardGenerateKey->getCipheredData();
1489const std::shared_ptr<CardResponseApi> CardTransactionManagerAdapter::transmitCardRequest(
1490 const std::shared_ptr<CardRequestSpi> cardRequest,
const ChannelControl channelControl)
1493 std::shared_ptr<CardResponseApi> cardResponse =
nullptr;
1496 cardResponse = mCardReader->transmitCardRequest(cardRequest, channelControl);
1497 }
catch (
const ReaderBrokenCommunicationException& e) {
1499 throw ReaderIOException(MSG_CARD_READER_COMMUNICATION_ERROR +
1502 std::make_shared<ReaderBrokenCommunicationException>(e));
1503 }
catch (
const CardBrokenCommunicationException& e) {
1505 throw CardIOException(MSG_CARD_COMMUNICATION_ERROR +
1508 std::make_shared<CardBrokenCommunicationException>(e));
1509 }
catch (
const UnexpectedStatusWordException& e) {
1510 mLogger->debug(
"A card command has failed: %\n", e.getMessage());
1511 cardResponse = e.getCardResponse();
1516 return cardResponse;
1519void CardTransactionManagerAdapter::finalizeSvCommandIfNeeded()
1521 if (mSvLastModifyingCommand ==
nullptr) {
1525 std::vector<uint8_t> svComplementaryData;
1530 auto svCommand = std::dynamic_pointer_cast<CmdCardSvReload>(mSvLastModifyingCommand);
1532 svComplementaryData = processSamSvPrepareLoad(mCard->getSvGetHeader(),
1533 mCard->getSvGetData(),
1537 svCommand->finalizeCommand(svComplementaryData);
1542 auto svCommand = std::dynamic_pointer_cast<CmdCardSvDebitOrUndebit>(mSvLastModifyingCommand);
1544 svComplementaryData = processSamSvPrepareDebitOrUndebit(
1546 mCard->getSvGetHeader(),
1547 mCard->getSvGetData(),
1551 svCommand->finalizeCommand(svComplementaryData);
1555const std::vector<uint8_t> CardTransactionManagerAdapter::processSamSvPrepareLoad(
1556 const std::vector<uint8_t>& svGetHeader,
1557 const std::vector<uint8_t>& svGetData,
1558 const std::shared_ptr<CmdCardSvReload> cmdCardSvReload)
1560 const std::shared_ptr<CmdSamSvPrepareLoad> cmdSamSvPrepareLoad =
1561 mControlSamTransactionManager->prepareSvPrepareLoad(svGetHeader, svGetData, cmdCardSvReload);
1562 mControlSamTransactionManager->processCommands();
1563 const std::vector<uint8_t> prepareOperationData =
1564 cmdSamSvPrepareLoad->getApduResponse()->getDataOut();
1566 return computeOperationComplementaryData(prepareOperationData);
1569const std::vector<uint8_t> CardTransactionManagerAdapter::processSamSvPrepareDebitOrUndebit(
1570 const bool isDebitCommand,
1571 const std::vector<uint8_t> svGetHeader,
1572 const std::vector<uint8_t> svGetData,
1573 const std::shared_ptr<CmdCardSvDebitOrUndebit> cmdCardSvDebitOrUndebit)
1575 const std::shared_ptr<CmdSamSvPrepareDebitOrUndebit> cmdSamSvPrepareDebitOrUndebit =
1576 mControlSamTransactionManager->prepareSvPrepareDebitOrUndebit(isDebitCommand,
1579 cmdCardSvDebitOrUndebit);
1580 mControlSamTransactionManager->processCommands();
1581 const std::vector<uint8_t> prepareOperationData =
1582 cmdSamSvPrepareDebitOrUndebit->getApduResponse()->getDataOut();
1584 return computeOperationComplementaryData(prepareOperationData);
1587const std::vector<uint8_t> CardTransactionManagerAdapter::computeOperationComplementaryData(
1588 const std::vector<uint8_t>& prepareOperationData)
1590 const std::vector<uint8_t>& samSerialNumber =
1591 mSecuritySetting->getControlSam()->getSerialNumber();
1592 std::vector<uint8_t> operationComplementaryData(samSerialNumber.size() +
1593 prepareOperationData.size());
1595 System::arraycopy(samSerialNumber, 0, operationComplementaryData, 0, samSerialNumber.size());
1596 System::arraycopy(prepareOperationData,
1598 operationComplementaryData,
1599 samSerialNumber.size(),
1600 prepareOperationData.size());
1602 return operationComplementaryData;
1605void CardTransactionManagerAdapter::processSamSvCheck(
const std::vector<uint8_t>& svOperationData)
1607 mControlSamTransactionManager->prepareSvCheck(svOperationData);
1610 mControlSamTransactionManager->processCommands();
1611 }
catch (
const ReaderIOException& e) {
1612 throw CardSignatureNotVerifiableException(MSG_CARD_SIGNATURE_NOT_VERIFIABLE_SV,
1613 std::make_shared<ReaderIOException>(e));
1614 }
catch (
const SamIOException& e) {
1615 throw CardSignatureNotVerifiableException(MSG_CARD_SIGNATURE_NOT_VERIFIABLE_SV,
1616 std::make_shared<SamIOException>(e));
1620const std::vector<uint8_t> CardTransactionManagerAdapter::processSamGetChallenge()
1622 const std::shared_ptr<CmdSamGetChallenge> cmdSamGetChallenge =
1623 mControlSamTransactionManager->prepareGetChallenge();
1624 mControlSamTransactionManager->processCommands();
1625 const std::vector<uint8_t> samChallenge = cmdSamGetChallenge->getChallenge();
1627 mLogger->debug(
"SAM_CHALLENGE=%\n", HexUtil::toHex(samChallenge));
1629 return samChallenge;
1632const std::vector<uint8_t> CardTransactionManagerAdapter::processSamSessionClosing()
1634 const std::shared_ptr<CmdSamDigestClose> cmdSamDigestClose =
1635 mControlSamTransactionManager->prepareSessionClosing();
1636 mControlSamTransactionManager->processCommands();
1637 const std::vector<uint8_t> terminalSignature = cmdSamDigestClose->getSignature();
1639 mLogger->debug(
"SAM_SIGNATURE=%\n", HexUtil::toHex(terminalSignature));
1641 return terminalSignature;
1644void CardTransactionManagerAdapter::processSamDigestAuthenticate(
1645 const std::vector<uint8_t>& cardSignature)
1647 mControlSamTransactionManager->prepareDigestAuthenticate(cardSignature);
1650 mControlSamTransactionManager->processCommands();
1651 }
catch (
const ReaderIOException& e) {
1652 throw CardSignatureNotVerifiableException(MSG_CARD_SIGNATURE_NOT_VERIFIABLE,
1653 std::make_shared<ReaderIOException>(e));
1654 }
catch (
const SamIOException& e) {
1655 throw CardSignatureNotVerifiableException(MSG_CARD_SIGNATURE_NOT_VERIFIABLE,
1656 std::make_shared<SamIOException>(e));
1660void CardTransactionManagerAdapter::checkSession()
1662 if (!mIsSessionOpen) {
1663 throw IllegalStateException(
"No session is open");
1667void CardTransactionManagerAdapter::checkNoSession()
1669 if (mIsSessionOpen) {
1670 throw IllegalStateException(
"Session is open");
1674int CardTransactionManagerAdapter::computeCommandSessionBufferSize(
1675 std::shared_ptr<AbstractCardCommand> command)
1677 return mCard->isModificationsCounterInBytes() ?
1678 static_cast<int>(command->getApduRequest()->getApdu().size()) +
1679 SESSION_BUFFER_CMD_ADDITIONAL_COST -
1680 APDU_HEADER_LENGTH :
1685void CardTransactionManagerAdapter::resetModificationsBufferCounter()
1687 mLogger->trace(
"Modifications buffer counter reset: PREVIOUSVALUE = %, NEWVALUE = %\n",
1688 mModificationsCounter,
1689 mCard->getModificationsCounter());
1691 mModificationsCounter = mCard->getModificationsCounter();
1696 mChannelControl = ChannelControl::CLOSE_AFTER;
1702 const std::vector<uint8_t>& lid)
1704 Assert::getInstance().isEqual(lid.size(), 2,
"lid length");
1706 return prepareSelectFile(
static_cast<uint16_t
>(ByteArrayUtil::extractInt(lid, 0, 2,
false)));
1711 mCardCommands.push_back(std::make_shared<CmdCardSelectFile>(mCard, lid));
1717 const SelectFileControl selectFileControl)
1720 mCardCommands.push_back(std::make_shared<CmdCardSelectFile>(mCard, selectFileControl));
1727 if (mIsSessionOpen) {
1728 throw IllegalStateException(
"Secure session open.");
1733 case GetDataTag::FCI_FOR_CURRENT_DF:
1734 mCardCommands.push_back(std::make_shared<CmdCardGetDataFci>(mCard));
1737 case GetDataTag::FCP_FOR_CURRENT_FILE:
1738 mCardCommands.push_back(std::make_shared<CmdCardGetDataFcp>(mCard));
1741 case GetDataTag::EF_LIST:
1742 mCardCommands.push_back(std::make_shared<CmdCardGetDataEfList>(mCard));
1745 case GetDataTag::TRACEABILITY_INFORMATION:
1746 mCardCommands.push_back(std::make_shared<CmdCardGetDataTraceabilityInformation>(mCard));
1750 std::stringstream ss;
1752 throw UnsupportedOperationException(
"Unsupported Get Data tag: " + ss.str());
1759 const uint8_t sfi,
const uint8_t recordNumber)
1766 const uint8_t firstRecordNumber,
1767 const uint8_t numberOfRecords,
1768 const uint8_t recordSize)
1772 firstRecordNumber + numberOfRecords - 1,
1777 const uint8_t sfi,
const uint8_t countersNumber)
1783 const uint8_t sfi,
const uint8_t recordNumber)
1785 Assert::getInstance().isInRange(sfi,
1789 .isInRange(recordNumber,
1794 if (mIsSessionOpen) {
1795 throw IllegalStateException(
"Explicit record size is expected inside a secure session.");
1798 auto cmdCardReadRecords =
1799 std::make_shared<CmdCardReadRecords>(mCard,
1804 mCardCommands.push_back(cmdCardReadRecords);
1811 const uint8_t fromRecordNumber,
1812 const uint8_t toRecordNumber,
1813 const uint8_t recordSize)
1815 Assert::getInstance().isInRange(sfi,
1819 .isInRange(fromRecordNumber,
1823 .isInRange(toRecordNumber,
1828 if (toRecordNumber == fromRecordNumber) {
1831 mCardCommands.push_back(
1832 std::make_shared<CmdCardReadRecords>(mCard,
1845 const uint8_t nbBytesPerRecord = recordSize + 2;
1846 const uint8_t nbRecordsPerApdu =
1847 static_cast<uint8_t
>(mCard->getPayloadCapacity() / nbBytesPerRecord);
1848 const uint8_t dataSizeMaxPerApdu = nbRecordsPerApdu * nbBytesPerRecord;
1850 uint8_t currentRecordNumber = fromRecordNumber;
1851 uint8_t nbRecordsRemainingToRead = toRecordNumber - fromRecordNumber + 1;
1852 uint8_t currentLength;
1854 while (currentRecordNumber < toRecordNumber) {
1855 currentLength = nbRecordsRemainingToRead <= nbRecordsPerApdu ?
1856 nbRecordsRemainingToRead * nbBytesPerRecord :
1859 mCardCommands.push_back(
1860 std::make_shared<CmdCardReadRecords>(mCard,
1862 currentRecordNumber,
1866 currentRecordNumber += (currentLength / nbBytesPerRecord);
1867 nbRecordsRemainingToRead -= (currentLength / nbBytesPerRecord);
1871 if (currentRecordNumber == toRecordNumber) {
1873 mCardCommands.push_back(
1874 std::make_shared<CmdCardReadRecords>(mCard,
1876 currentRecordNumber,
1887 const uint8_t fromRecordNumber,
1888 const uint8_t toRecordNumber,
1889 const uint8_t offset,
1890 const uint8_t nbBytesToRead)
1892 if (mCard->getProductType() != CalypsoCard::ProductType::PRIME_REVISION_3 &&
1893 mCard->getProductType() != CalypsoCard::ProductType::LIGHT) {
1895 throw UnsupportedOperationException(
"The 'Read Record Multiple' command is not available "\
1898 if (mIsSessionOpen) {
1899 throw IllegalStateException(
"Command not allowed inside a secure session.");
1902 Assert::getInstance().isInRange(sfi,
1906 .isInRange(fromRecordNumber,
1910 .isInRange(toRecordNumber,
1918 .isInRange(nbBytesToRead,
1923 const uint8_t nbRecordsPerApdu =
1924 static_cast<uint8_t
>(mCard->getPayloadCapacity() / nbBytesToRead);
1926 uint8_t currentRecordNumber = fromRecordNumber;
1928 while (currentRecordNumber <= toRecordNumber) {
1930 mCardCommands.push_back(
1931 std::make_shared<CmdCardReadRecordMultiple>(mCard,
1933 currentRecordNumber,
1936 currentRecordNumber += nbRecordsPerApdu;
1943 const uint8_t sfi,
const int offset,
const int nbBytesToRead)
1945 if (mCard->getProductType() != CalypsoCard::ProductType::PRIME_REVISION_3) {
1947 if (mCard->getProductType() == CalypsoCard::ProductType::PRIME_REVISION_2) {
1949 mLogger->warn(
"The 'Read Binary' command may not be supported by this " \
1950 "PRIME_REVISION_2 card\n");
1953 throw UnsupportedOperationException(
"The 'Read Binary' command is not available for " \
1958 Assert::getInstance().isInRange(sfi,
1966 .greaterOrEqual(nbBytesToRead, 1,
"nbBytesToRead");
1968 if (sfi > 0 && offset > 255) {
1971 mCardCommands.push_back(std::make_shared<CmdCardReadBinary>(mCard, sfi, 0, 1));
1974 const int payloadCapacity = mCard->getPayloadCapacity();
1977 int currentOffset = offset;
1978 int nbBytesRemainingToRead = nbBytesToRead;
1982 currentLength = std::min(nbBytesRemainingToRead, payloadCapacity);
1983 mCardCommands.push_back(
1984 std::make_shared<CmdCardReadBinary>(mCard, sfi, currentOffset, currentLength));
1986 currentOffset += currentLength;
1987 nbBytesRemainingToRead -= currentLength;
1989 }
while (nbBytesRemainingToRead > 0);
1995 const uint8_t sfi,
const uint8_t nbCountersToRead)
2001 const std::shared_ptr<SearchCommandData> data)
2003 if (mCard->getProductType() != CalypsoCard::ProductType::PRIME_REVISION_3) {
2005 throw UnsupportedOperationException(
"The 'Search Record Multiple' command is not " \
2006 "available for this card.");
2008 if (mIsSessionOpen) {
2009 throw IllegalStateException(
"Command not allowed inside a secure session.");
2012 auto dataAdapter = std::dynamic_pointer_cast<SearchCommandDataAdapter>(data);
2015 throw IllegalArgumentException(
"The provided data must be an instance of " \
2016 "'SearchCommandDataAdapter'");
2019 Assert::getInstance().notNull(dataAdapter,
"data")
2020 .isInRange(dataAdapter->getSfi(),
2024 .isInRange(dataAdapter->getRecordNumber(),
2028 .isInRange(dataAdapter->getOffset(),
2032 .isInRange(dataAdapter->getSearchData().size(),
2036 if (!dataAdapter->getMask().empty()) {
2037 Assert::getInstance().isInRange(dataAdapter->getMask().size(),
2039 dataAdapter->getSearchData().size(),
2043 mCardCommands.push_back(std::make_shared<CmdCardSearchRecordMultiple>(mCard, dataAdapter));
2049 const uint8_t sfi,
const std::vector<uint8_t>& recordData)
2051 Assert::getInstance().isInRange(sfi,
2057 mCardCommands.push_back(std::make_shared<CmdCardAppendRecord>(mCard, sfi, recordData));
2064 const uint8_t recordNumber,
2065 const std::vector<uint8_t>& recordData)
2067 Assert::getInstance().isInRange(sfi,
2071 .isInRange(recordNumber,
2077 mCardCommands.push_back(
2078 std::make_shared<CmdCardUpdateRecord>(mCard, sfi, recordNumber, recordData));
2085 const uint8_t recordNumber,
2086 const std::vector<uint8_t>& recordData)
2088 Assert::getInstance().isInRange(sfi,
2092 .isInRange(recordNumber,
2098 mCardCommands.push_back(
2099 std::make_shared<CmdCardWriteRecord>(mCard, sfi, recordNumber, recordData));
2107 const std::vector<uint8_t>& data)
2109 return prepareUpdateOrWriteBinary(
true, sfi, offset, data);
2115 const std::vector<uint8_t>& data)
2117 return prepareUpdateOrWriteBinary(
false, sfi, offset, data);
2120CardTransactionManager& CardTransactionManagerAdapter::prepareUpdateOrWriteBinary(
2121 const bool isUpdateCommand,
2124 const std::vector<uint8_t>& data)
2126 if (mCard->getProductType() != CalypsoCard::ProductType::PRIME_REVISION_3) {
2128 if (mCard->getProductType() == CalypsoCard::ProductType::PRIME_REVISION_2) {
2130 mLogger->warn(
"The 'Update/Write Binary' command may not be supported by this " \
2131 "PRIME_REVISION_2 card\n");
2134 throw UnsupportedOperationException(
"The 'Update/Write Binary' command is not " \
2135 "available for this card.");
2139 Assert::getInstance().isInRange(sfi,
2147 .notEmpty(data,
"data");
2149 if (sfi > 0 && offset > 255) {
2152 mCardCommands.push_back(std::make_shared<CmdCardReadBinary>(mCard, sfi, 0, 1));
2155 const uint8_t dataLength =
static_cast<uint8_t
>(data.size());
2156 const uint8_t payloadCapacity = mCard->getPayloadCapacity();
2159 int currentOffset = offset;
2160 int currentIndex = 0;
2164 currentLength =
static_cast<uint8_t
>(
2165 std::min(
static_cast<int>(dataLength - currentIndex),
2166 static_cast<int>(payloadCapacity)));
2168 mCardCommands.push_back(
2169 std::make_shared<CmdCardUpdateOrWriteBinary>(
2174 Arrays::copyOfRange(data, currentIndex, currentIndex + currentLength)));
2176 currentOffset += currentLength;
2177 currentIndex += currentLength;
2179 }
while (currentIndex < dataLength);
2184CardTransactionManager& CardTransactionManagerAdapter::prepareIncreaseOrDecreaseCounter(
2185 const bool isDecreaseCommand,
2187 const uint8_t counterNumber,
2188 const int incDecValue)
2190 Assert::getInstance().isInRange(sfi,
2194 .isInRange(counterNumber,
2198 .isInRange(incDecValue,
2204 mCardCommands.push_back(std::make_shared<CmdCardIncreaseOrDecrease>(isDecreaseCommand,
2214 const uint8_t sfi,
const uint8_t counterNumber,
const int incValue)
2216 return prepareIncreaseOrDecreaseCounter(
false, sfi, counterNumber, incValue);
2220 const uint8_t sfi,
const uint8_t counterNumber,
const int decValue)
2222 return prepareIncreaseOrDecreaseCounter(
true, sfi, counterNumber, decValue);
2227 const std::map<const int, const int>& counterNumberToIncValueMap)
2229 return prepareIncreaseOrDecreaseCounters(
false, sfi, counterNumberToIncValueMap);
2234 const std::map<const int, const int>& counterNumberToDecValueMap)
2236 return prepareIncreaseOrDecreaseCounters(
true, sfi, counterNumberToDecValueMap);
2241 if (!mCard->isPinFeatureAvailable()) {
2243 throw UnsupportedOperationException(MSG_PIN_NOT_AVAILABLE);
2247 mCardCommands.push_back(std::make_shared<CmdCardVerifyPin>(mCard));
2253 const SvAction svAction)
2255 if (!mCard->isSvFeatureAvailable()) {
2257 throw UnsupportedOperationException(
"Stored Value is not available for this card.");
2261 std::shared_ptr<CalypsoSam> calypsoSam = mSecuritySetting->getControlSam();
2262 const bool useExtendedMode = mCard->isExtendedModeSupported() &&
2263 (calypsoSam ==
nullptr ||
2264 calypsoSam->getProductType() == CalypsoSam::ProductType::SAM_C1 ||
2265 calypsoSam->getProductType() == CalypsoSam::ProductType::HSM_C1);
2267 if (mSecuritySetting->isSvLoadAndDebitLogEnabled() && !useExtendedMode) {
2274 const SvOperation operation1 =
2275 SvOperation::RELOAD == svOperation ? SvOperation::DEBIT : SvOperation::RELOAD;
2283 mSvAction = svAction;
2290 const std::vector<uint8_t>& date,
2291 const std::vector<uint8_t>& time,
2292 const std::vector<uint8_t>& free)
2294 checkSvInsideSession();
2297 auto svReloadCmdBuild = std::make_shared<CmdCardSvReload>(mCard,
2303 isExtendedModeAllowed());
2313 const std::vector<uint8_t> zero = {0x00, 0x00};
2320void CardTransactionManagerAdapter::checkSvInsideSession()
2323 if (mIsSessionOpen) {
2324 if (!mIsSvOperationInsideSession) {
2325 mIsSvOperationInsideSession =
true;
2327 throw IllegalStateException(
"Only one SV operation is allowed per Secure Session.");
2332bool CardTransactionManagerAdapter::isExtendedModeAllowed()
const
2334 std::shared_ptr<CalypsoSam> calypsoSam = mSecuritySetting->getControlSam();
2336 return mCard->isExtendedModeSupported() &&
2337 (calypsoSam->getProductType() == CalypsoSam::ProductType::SAM_C1 ||
2338 calypsoSam->getProductType() == CalypsoSam::ProductType::HSM_C1);
2343 const std::vector<uint8_t>& date,
2344 const std::vector<uint8_t>& time)
2346 checkSvInsideSession();
2348 if (mSvAction == SvAction::DO &&
2349 !mSecuritySetting->isSvNegativeBalanceAuthorized() &&
2350 (mCard->getSvBalance() - amount) < 0) {
2351 throw IllegalStateException(
"Negative balances not allowed.");
2355 auto command = std::make_shared<CmdCardSvDebitOrUndebit>(mSvAction == SvAction::DO,
2361 isExtendedModeAllowed());
2371 const std::vector<uint8_t> zero = {0x00, 0x00};
2380 if (!mCard->isSvFeatureAvailable()) {
2381 throw UnsupportedOperationException(
"Stored Value is not available for this card.");
2384 if (mCard->getApplicationSubtype() !=
2386 throw UnsupportedOperationException(
"The currently selected application is not an SV " \
2391 const std::vector<uint8_t> dummy;
2392 mCard->setSvData(0, dummy, dummy, 0, 0,
nullptr,
nullptr);
2407 if (mCard->isDfInvalidated()) {
2408 throw IllegalStateException(
"This card is already invalidated.");
2411 mCardCommands.push_back(std::make_shared<CmdCardInvalidate>(mCard));
2418 if (!mCard->isDfInvalidated()) {
2419 throw IllegalStateException(
"This card is not invalidated.");
2422 mCardCommands.push_back(std::make_shared<CmdCardRehabilitate>(mCard));
2428 const std::shared_ptr<AbstractCardCommand> command,
const SvOperation svOperation)
2432 mSvOperation = svOperation;
2441 if (!mCardCommands.empty()) {
2442 throw IllegalStateException(
"This SV command can only be placed in the first position" \
2443 " in the list of prepared commands");
2447 throw IllegalStateException(
"This SV command must follow an SV Get command");
2451 if (svOperation != mSvOperation) {
2452 mLogger->error(
"Sv operation = %, current command = %\n", mSvOperation, svOperation);
2453 throw IllegalStateException(
"Inconsistent SV operation.");
2456 mIsSvOperationComplete =
true;
2457 mSvLastModifyingCommand = command;
2460 throw IllegalStateException(
"An SV command is expected.");
2463 mSvLastCommandRef = command->getCommandRef();
2464 mCardCommands.push_back(command);
2469 mCardCommands.clear();
2470 mSvLastModifyingCommand =
nullptr;
2475 const bool flag = mIsSvOperationComplete;
2476 mIsSvOperationComplete =
false;
2483CardTransactionManagerAdapter::ApduResponseAdapter::ApduResponseAdapter(
2484 const std::vector<uint8_t>& apdu)
2486 mStatusWord(ByteArrayUtil::extractInt(apdu, apdu.size() - 2, 2, false)) {}
2488const std::vector<uint8_t>& CardTransactionManagerAdapter::ApduResponseAdapter::getApdu()
const
2493const std::vector<uint8_t> CardTransactionManagerAdapter::ApduResponseAdapter::getDataOut()
const
2495 return Arrays::copyOfRange(mApdu, 0, mApdu.size() - 2);
2498int CardTransactionManagerAdapter::ApduResponseAdapter::getStatusWord()
const
2503std::ostream&
operator<<(std::ostream& os,
const CardTransactionManagerAdapter::ApduResponseAdapter& ara)
2505 os <<
"APDU_RESPONSE_ADAPTER: {"
2506 <<
"APDU: " << ara.getApdu() <<
", "
2507 <<
"STATUS_WORD: " << ara.getStatusWord()
2514std::ostream&
operator<<(std::ostream& os,
const std::shared_ptr<CardTransactionManagerAdapter::ApduResponseAdapter> ara)
2516 if (ara ==
nullptr) {
2517 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_RECORD_MULTIPLE
static const CalypsoCardCommand SELECT_FILE
static const CalypsoCardCommand GET_DATA
static const CalypsoCardCommand READ_RECORDS
static const CalypsoCardCommand READ_BINARY
static const CalypsoCardCommand SEARCH_RECORD_MULTIPLE
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
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 & 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
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 & prepareUpdateBinary(const uint8_t sfi, const int offset, const std::vector< uint8_t > &data) final
CardTransactionManager & prepareReadRecord(const uint8_t sfi, const uint8_t recordNumber) override
CardTransactionManager & prepareWriteBinary(const uint8_t sfi, const int offset, const std::vector< uint8_t > &data) final
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 & prepareReadBinary(const uint8_t sfi, const int offset, const int nbBytesToRead) override
CardTransactionManager & prepareReadRecords(const uint8_t sfi, const uint8_t fromRecordNumber, const uint8_t toRecordNumber, const uint8_t recordSize) 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 & 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
const std::shared_ptr< CommonSecuritySetting > getSecuritySetting() const 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)