14#include "keyple/card/calypso/TransactionManagerAdapter.hpp"
24#include "keyple/card/calypso/CalypsoCardConstant.hpp"
25#include "keyple/card/calypso/CommandAppendRecord.hpp"
26#include "keyple/card/calypso/CommandGenerateAsymmetricKeyPair.hpp"
27#include "keyple/card/calypso/CommandGetDataCardPublicKey.hpp"
28#include "keyple/card/calypso/CommandGetDataCertificate.hpp"
29#include "keyple/card/calypso/CommandGetDataEfList.hpp"
30#include "keyple/card/calypso/CommandGetDataFcp.hpp"
31#include "keyple/card/calypso/CommandGetDataTraceabilityInformation.hpp"
32#include "keyple/card/calypso/CommandIncreaseOrDecrease.hpp"
33#include "keyple/card/calypso/CommandIncreaseOrDecreaseMultiple.hpp"
34#include "keyple/card/calypso/CommandOpenSecureSession.hpp"
35#include "keyple/card/calypso/CommandPutData.hpp"
36#include "keyple/card/calypso/CommandReadBinary.hpp"
37#include "keyple/card/calypso/CommandReadRecordMultiple.hpp"
38#include "keyple/card/calypso/CommandReadRecords.hpp"
39#include "keyple/card/calypso/CommandSearchRecordMultiple.hpp"
40#include "keyple/card/calypso/CommandSelectFile.hpp"
41#include "keyple/card/calypso/CommandUpdateOrWriteBinary.hpp"
42#include "keyple/card/calypso/CommandUpdateRecord.hpp"
43#include "keyple/card/calypso/CommandVerifyPin.hpp"
44#include "keyple/card/calypso/CommandWriteRecord.hpp"
45#include "keyple/core/util/HexUtil.hpp"
46#include "keyple/core/util/KeypleAssert.hpp"
47#include "keyple/core/util/cpp/Arrays.hpp"
48#include "keyple/core/util/cpp/exception/IllegalArgumentException.hpp"
49#include "keyple/core/util/cpp/exception/IllegalStateException.hpp"
50#include "keyple/core/util/cpp/exception/RuntimeException.hpp"
51#include "keyple/core/util/cpp/exception/UnsupportedOperationException.hpp"
52#include "keypop/calypso/card/transaction/InconsistentDataException.hpp"
53#include "keypop/card/CardBrokenCommunicationException.hpp"
54#include "keypop/card/ReaderBrokenCommunicationException.hpp"
55#include "keypop/card/UnexpectedStatusWordException.hpp"
56#include "keypop/reader/CardCommunicationException.hpp"
57#include "keypop/reader/ReaderCommunicationException.hpp"
58#include "keypop/reader/selection/InvalidCardResponseException.hpp"
64using keyple::core::util::Assert;
65using keyple::core::util::HexUtil;
66using keyple::core::util::cpp::Arrays;
67using keyple::core::util::cpp::exception::IllegalArgumentException;
68using keyple::core::util::cpp::exception::IllegalStateException;
69using keyple::core::util::cpp::exception::RuntimeException;
70using keyple::core::util::cpp::exception::UnsupportedOperationException;
71using keypop::calypso::card::transaction::InconsistentDataException;
72using keypop::card::CardBrokenCommunicationException;
73using keypop::card::ReaderBrokenCommunicationException;
74using keypop::card::UnexpectedStatusWordException;
75using keypop::reader::CardCommunicationException;
76using keypop::reader::ReaderCommunicationException;
77using keypop::reader::selection::InvalidCardResponseException;
80const std::string TransactionManagerAdapter<
81 T>::MSG_THE_NUMBER_OF_COMMANDS_RESPONSES_DOES_NOT_MATCH_EXPECTED
82 =
"The number of commands/responses does not match. Expected ";
84const std::string TransactionManagerAdapter<T>::MSG_RESPONSES_GOT
88 TransactionManagerAdapter<T>::MSG_CARD_READER_COMMUNICATION_ERROR
89 =
"Failed to communicate with card reader";
91const std::string TransactionManagerAdapter<T>::MSG_CARD_COMMUNICATION_ERROR
92 =
"Failed to communicate with card";
94const std::string TransactionManagerAdapter<T>::MSG_WHILE_TRANSMITTING_COMMANDS
95 =
" while transmitting commands.";
97const std::string TransactionManagerAdapter<T>::MSG_PIN_NOT_AVAILABLE
98 =
"PIN is not available for this card";
100const std::string TransactionManagerAdapter<T>::MSG_RECORD_NUMBER
103const std::string TransactionManagerAdapter<T>::MSG_OFFSET =
"offset";
105const std::string TransactionManagerAdapter<T>::MSG_RECORD_DATA =
"record data";
107const std::string TransactionManagerAdapter<T>::MSG_RECORD_DATA_LENGTH
108 =
"record data length";
110const std::string TransactionManagerAdapter<T>::MSG_SECURE_SESSION_OPEN
111 =
"Secure session is open";
114 TransactionManagerAdapter<T>::MSG_PKI_MODE_IS_NOT_AVAILABLE_FOR_THIS_CARD
115 =
"PKI mode is not available for this card";
117const std::string TransactionManagerAdapter<T>::MSG_DATA_LENGTH =
"data length";
120TransactionManagerAdapter<T>::TransactionManagerAdapter(
121 std::shared_ptr<ProxyReaderApi> cardReader,
122 std::shared_ptr<CalypsoCardAdapter> card)
124, mCardReader(cardReader)
130TransactionManagerAdapter<T>::executeCardCommands(
131 const std::vector<std::shared_ptr<Command>>& commands,
132 ChannelControl channelControl)
135 std::vector<std::shared_ptr<ApduRequestSpi>> apduRequests
136 = getApduRequests(commands);
140 = std::make_shared<DtoAdapters::CardRequestAdapter>(apduRequests,
true);
143 std::shared_ptr<CardResponseApi> cardResponse
144 = transmitCardRequest(cardRequest, channelControl);
147 std::vector<std::shared_ptr<ApduResponseApi>> apduResponses
148 = cardResponse->getApduResponses();
155 if (apduResponses.size() > commands.size()) {
156 throw InconsistentDataException(
157 MSG_THE_NUMBER_OF_COMMANDS_RESPONSES_DOES_NOT_MATCH_EXPECTED
158 + std::to_string(commands.size()) + MSG_RESPONSES_GOT
159 + std::to_string(apduResponses.size())
160 + getTransactionAuditDataAsString());
168 for (
int i = 0; i < static_cast<int>(apduResponses.size()); i++) {
169 std::shared_ptr<Command> command = commands[i];
171 parseCommandResponse(command, apduResponses[i]);
172 handleCommandPostProcessing(i, commands);
173 }
catch (
const CardCommandException& e) {
175 = command->getApduResponse() !=
nullptr
177 static_cast<std::uint16_t
>(
178 command->getApduResponse()->getStatusWord()))
180 throw InvalidCardResponseException(
181 "Failed to process card response. Command: "
182 + command->getCommandRef().getName() +
", SW: " + sw
183 + getTransactionAuditDataAsString(),
192 if (apduResponses.size() < commands.size()) {
193 throw InconsistentDataException(
194 MSG_THE_NUMBER_OF_COMMANDS_RESPONSES_DOES_NOT_MATCH_EXPECTED
195 + std::to_string(commands.size()) + MSG_RESPONSES_GOT
196 + std::to_string(apduResponses.size())
197 + getTransactionAuditDataAsString());
203TransactionManagerAdapter<T>::parseCommandResponse(
204 const std::shared_ptr<Command>& command,
205 const std::shared_ptr<ApduResponseApi>& apduResponse)
207 command->parseResponse(apduResponse);
212TransactionManagerAdapter<T>::handleCommandPostProcessing(
214 const std::vector<std::shared_ptr<Command>>& )
219std::vector<std::shared_ptr<ApduRequestSpi>>
220TransactionManagerAdapter<T>::getApduRequests(
221 const std::vector<std::shared_ptr<Command>>& commands)
223 std::vector<std::shared_ptr<ApduRequestSpi>> apduRequests;
224 if (!commands.empty()) {
225 for (
const auto& command : commands) {
226 apduRequests.push_back(command->getApduRequest());
234std::shared_ptr<CardResponseApi>
235TransactionManagerAdapter<T>::transmitCardRequest(
236 std::shared_ptr<CardRequestSpi> cardRequest, ChannelControl channelControl)
238 std::shared_ptr<CardResponseApi> cardResponse;
241 cardResponse = mCardReader->transmitCardRequest(
242 cardRequest, mapToInternalChannelControl(channelControl));
244 }
catch (
const ReaderBrokenCommunicationException& e) {
245 saveTransactionAuditData(cardRequest, e.getCardResponse());
246 throw ReaderCommunicationException(
247 MSG_CARD_READER_COMMUNICATION_ERROR
248 + MSG_WHILE_TRANSMITTING_COMMANDS
249 + getTransactionAuditDataAsString(),
252 }
catch (
const CardBrokenCommunicationException& e) {
253 saveTransactionAuditData(cardRequest, e.getCardResponse());
254 throw CardCommunicationException(
255 MSG_CARD_COMMUNICATION_ERROR + MSG_WHILE_TRANSMITTING_COMMANDS
256 + getTransactionAuditDataAsString(),
259 }
catch (
const UnexpectedStatusWordException& e) {
260 cardResponse = e.getCardResponse();
263 saveTransactionAuditData(cardRequest, cardResponse);
270TransactionManagerAdapter<T>::getTransactionAuditDataAsString()
const
272 std::stringstream ss;
274 ss <<
"\nTransaction audit JSON data: {\"targetSmartCard\":";
276 if (mCard ==
nullptr) {
280 <<
"\"productType\":\"" << mCard->getProductType() <<
"\","
281 <<
"\"powerOnData\":\"" << mCard->getPowerOnData() <<
"\","
282 <<
"\"selectApplicationResponse\":\""
283 << HexUtil::toHex(mCard->getSelectApplicationResponse()) <<
"\","
284 <<
"\"dfName\":\"" << HexUtil::toHex(mCard->getDfName()) <<
"\","
285 <<
"\"serialNumber\":\""
286 << HexUtil::toHex(mCard->getCalypsoSerialNumberFull()) <<
"\","
287 <<
"\"startupInfo\":\""
288 << HexUtil::toHex(mCard->getStartupInfoRawData()) <<
"\""
292 ss <<
",\"apdus\":[";
294 for (
size_t i = 0; i < mTransactionAuditData.size(); i++) {
298 ss <<
"\"" << HexUtil::toHex(mTransactionAuditData[i]) <<
"\"";
307keypop::card::ChannelControl
308TransactionManagerAdapter<T>::mapToInternalChannelControl(
309 ChannelControl channelControl)
const
311 return keypop::card::valueOf(
static_cast<int>(channelControl));
316TransactionManagerAdapter<T>::saveTransactionAuditData(
317 const std::shared_ptr<CardRequestSpi>& cardRequest,
318 const std::shared_ptr<CardResponseApi>& cardResponse)
320 if (cardResponse !=
nullptr) {
321 std::vector<std::shared_ptr<ApduRequestSpi>> requests
322 = cardRequest->getApduRequests();
323 std::vector<std::shared_ptr<ApduResponseApi>> responses
324 = cardResponse->getApduResponses();
326 int responsesSize =
static_cast<int>(responses.size());
328 for (
int i = 0; i < static_cast<int>(requests.size()); i++) {
329 const std::vector<std::uint8_t> empty;
330 mTransactionAuditData.push_back(requests[i]->getApdu());
331 mTransactionAuditData.push_back(
332 (i < responsesSize) ? responses[i]->getApdu() : empty);
339TransactionManagerAdapter<T>::prepareSelectFile(std::uint16_t lid)
343 std::unique_ptr<CommandSelectFile>(
new CommandSelectFile(
344 getTransactionContext(), getCommandContext(), lid)));
351 return dynamic_cast<T&
>(*this);
356TransactionManagerAdapter<T>::prepareSelectFile(
357 SelectFileControl selectFileControl)
361 std::unique_ptr<CommandSelectFile>(
new CommandSelectFile(
362 getTransactionContext(),
364 selectFileControl)));
371 return dynamic_cast<T&
>(*this);
376TransactionManagerAdapter<T>::prepareGetData(GetDataTag tag)
379 if (getCommandContext()->isSecureSessionOpen()) {
380 throw IllegalStateException(MSG_SECURE_SESSION_OPEN);
384 case GetDataTag::FCI_FOR_CURRENT_DF:
386 std::make_shared<CommandGetDataFci>(
387 getTransactionContext(), getCommandContext()));
389 case GetDataTag::FCP_FOR_CURRENT_FILE:
391 std::make_shared<CommandGetDataFcp>(
392 getTransactionContext(), getCommandContext()));
394 case GetDataTag::EF_LIST:
396 std::make_shared<CommandGetDataEfList>(
397 getTransactionContext(), getCommandContext()));
399 case GetDataTag::TRACEABILITY_INFORMATION:
401 std::make_shared<CommandGetDataTraceabilityInformation>(
402 getTransactionContext(), getCommandContext()));
404 case GetDataTag::CARD_PUBLIC_KEY:
406 std::make_shared<CommandGetDataCardPublicKey>(
407 getTransactionContext(), getCommandContext()));
409 case GetDataTag::CARD_CERTIFICATE:
411 std::make_shared<CommandGetDataCertificate>(
412 getTransactionContext(), getCommandContext(),
true,
true));
414 std::make_shared<CommandGetDataCertificate>(
415 getTransactionContext(), getCommandContext(),
true,
false));
417 case GetDataTag::CA_CERTIFICATE:
419 std::make_shared<CommandGetDataCertificate>(
420 getTransactionContext(), getCommandContext(),
false,
true));
422 std::make_shared<CommandGetDataCertificate>(
423 getTransactionContext(),
429 throw UnsupportedOperationException(
430 "Unsupported GetDataTag: "
431 + std::to_string(
static_cast<int>(tag)));
439 return dynamic_cast<T&
>(*this);
444TransactionManagerAdapter<T>::preparePutData(
445 PutDataTag putDataTag,
const std::vector<std::uint8_t>& data)
447 if (getCommandContext()->isSecureSessionOpen()) {
448 throw IllegalStateException(MSG_SECURE_SESSION_OPEN);
451 switch (putDataTag) {
452 case PutDataTag::CARD_KEY_PAIR:
453 preparePutDataCardKeyPair(putDataTag, data);
455 case PutDataTag::CARD_CERTIFICATE:
456 preparePutDataCertificate(
457 putDataTag, data, CalypsoCardConstant::CARD_CERTIFICATE_SIZE);
459 case PutDataTag::CA_CERTIFICATE:
460 preparePutDataCertificate(
461 putDataTag, data, CalypsoCardConstant::CA_CERTIFICATE_SIZE);
464 throw UnsupportedOperationException(
465 "Unsupported PutDataTag: "
466 + std::to_string(
static_cast<int>(putDataTag)));
469 return dynamic_cast<T&
>(*this);
474TransactionManagerAdapter<T>::preparePutDataCardKeyPair(
475 PutDataTag putDataTag,
const std::vector<std::uint8_t>& data)
477 if (!mCard->isPkiModeSupported()) {
478 throw UnsupportedOperationException(
479 MSG_PKI_MODE_IS_NOT_AVAILABLE_FOR_THIS_CARD);
482 Assert::getInstance().isEqual(
483 data.size(), CalypsoCardConstant::CARD_KEY_PAIR_SIZE, MSG_DATA_LENGTH);
486 std::make_shared<CommandPutData>(
487 getTransactionContext(),
496TransactionManagerAdapter<T>::preparePutDataCertificate(
497 PutDataTag putDataTag,
498 const std::vector<std::uint8_t>& data,
501 std::shared_ptr<DtoAdapters::TransactionContextDto> transactionContext
502 = getTransactionContext();
503 std::shared_ptr<DtoAdapters::CommandContextDto> commandContext
504 = getCommandContext();
507 = getTransactionContext()->getCard()->getPayloadCapacity();
509 if (!mCard->isPkiModeSupported()) {
510 throw UnsupportedOperationException(
511 MSG_PKI_MODE_IS_NOT_AVAILABLE_FOR_THIS_CARD);
514 Assert::getInstance().isEqual(
515 data.size(), certificateSize, MSG_DATA_LENGTH);
518 std::make_shared<CommandPutData>(
526 - CalypsoCardConstant::TAG_CERTIFICATE_HEADER_SIZE)));
528 std::make_shared<CommandPutData>(
536 - CalypsoCardConstant::TAG_CERTIFICATE_HEADER_SIZE,
542TransactionManagerAdapter<T>::prepareReadRecord(
543 std::uint8_t sfi,
int recordNumber)
546 if (getCommandContext()->isSecureSessionOpen()) {
547 throw IllegalStateException(MSG_SECURE_SESSION_OPEN);
550 Assert::getInstance()
552 static_cast<int>(sfi),
553 CalypsoCardConstant::SFI_MIN,
554 CalypsoCardConstant::SFI_MAX,
558 CalypsoCardConstant::NB_REC_MIN,
559 CalypsoCardConstant::NB_REC_MAX,
566 std::unique_ptr<int> recordSize
567 = mCard->isLegacyCase1()
568 ? std::unique_ptr<int>(
569 new int(CalypsoCardConstant::LEGACY_REC_LENGTH))
573 std::make_shared<CommandReadRecords>(
574 getTransactionContext(),
578 CommandReadRecords::ReadMode::ONE_RECORD,
579 std::move(recordSize),
580 recordSize !=
nullptr ? *recordSize : 0));
587 return dynamic_cast<T&
>(*this);
592TransactionManagerAdapter<T>::prepareReadRecords(
593 std::uint8_t sfi,
int fromRecordNumber,
int toRecordNumber,
int recordSize)
596 Assert::getInstance()
598 static_cast<int>(sfi),
599 CalypsoCardConstant::SFI_MIN,
600 CalypsoCardConstant::SFI_MAX,
604 CalypsoCardConstant::NB_REC_MIN,
605 CalypsoCardConstant::NB_REC_MAX,
610 CalypsoCardConstant::NB_REC_MAX,
612 .isInRange(recordSize, 0, getPayloadCapacity(),
"recordSize");
614 if (toRecordNumber == fromRecordNumber
615 || (mCard->getProductType()
616 != CalypsoCard::ProductType::PRIME_REVISION_3
617 && mCard->getProductType()
618 != CalypsoCard::ProductType::LIGHT)) {
624 if (canConfigureReadOnOpenSecureSession()) {
626 = std::dynamic_pointer_cast<CommandOpenSecureSession>(
627 mCommands[mCommands.size() - 1]);
628 session->configureReadMode(sfi, fromRecordNumber, recordSize);
632 for (
int i = fromRecordNumber; i <= toRecordNumber; i++) {
634 std::make_shared<CommandReadRecords>(
635 getTransactionContext(),
639 CommandReadRecords::ReadMode::ONE_RECORD,
640 std::unique_ptr<int>(
new int(recordSize)),
651 const int nbBytesPerRecord = recordSize + 2;
652 const int nbRecordsPerApdu
653 = getPayloadCapacity() / nbBytesPerRecord;
654 const int dataSizeMaxPerApdu = nbRecordsPerApdu * nbBytesPerRecord;
656 int currentRecordNumber = fromRecordNumber;
657 int nbRecordsRemainingToRead
658 = toRecordNumber - fromRecordNumber + 1;
660 while (currentRecordNumber < toRecordNumber) {
662 = nbRecordsRemainingToRead <= nbRecordsPerApdu
663 ? nbRecordsRemainingToRead * nbBytesPerRecord
664 : dataSizeMaxPerApdu;
667 std::make_shared<CommandReadRecords>(
668 getTransactionContext(),
672 CommandReadRecords::ReadMode::MULTIPLE_RECORD,
673 std::unique_ptr<int>(
new int(currentLength)),
675 currentRecordNumber += (currentLength / nbBytesPerRecord);
676 nbRecordsRemainingToRead -= (currentLength / nbBytesPerRecord);
683 if (currentRecordNumber == toRecordNumber) {
685 std::make_shared<CommandReadRecords>(
686 getTransactionContext(),
690 CommandReadRecords::ReadMode::ONE_RECORD,
691 std::unique_ptr<int>(
new int(recordSize)),
701 return dynamic_cast<T&
>(*this);
706TransactionManagerAdapter<T>::prepareReadRecordsPartially(
708 int fromRecordNumber,
714 if (mCard->getProductType()
715 != CalypsoCard::ProductType::PRIME_REVISION_3
716 && mCard->getProductType() != CalypsoCard::ProductType::LIGHT) {
717 throw UnsupportedOperationException(
718 std::string(
"'Read Record Multiple' command is not available ")
722 if (getCommandContext()->isSecureSessionOpen()) {
723 throw IllegalStateException(MSG_SECURE_SESSION_OPEN);
726 Assert::getInstance()
728 static_cast<int>(sfi),
729 CalypsoCardConstant::SFI_MIN,
730 CalypsoCardConstant::SFI_MAX,
734 CalypsoCardConstant::NB_REC_MIN,
735 CalypsoCardConstant::NB_REC_MAX,
740 CalypsoCardConstant::NB_REC_MAX,
744 CalypsoCardConstant::OFFSET_MIN,
745 CalypsoCardConstant::OFFSET_MAX,
749 CalypsoCardConstant::DATA_LENGTH_MIN,
750 getPayloadCapacity(),
753 const int nbRecordsPerApdu = getPayloadCapacity() / nbBytesToRead;
755 int currentRecordNumber = fromRecordNumber;
757 while (currentRecordNumber <= toRecordNumber) {
759 std::make_shared<CommandReadRecordMultiple>(
760 getTransactionContext(),
763 static_cast<std::uint8_t
>(currentRecordNumber),
764 static_cast<std::uint8_t
>(offset),
765 static_cast<std::uint8_t
>(nbBytesToRead)));
766 currentRecordNumber += nbRecordsPerApdu;
774 return dynamic_cast<T&
>(*this);
779TransactionManagerAdapter<T>::prepareReadBinary(
780 std::uint8_t sfi,
int offset,
int nbBytesToRead)
783 if (mCard->getProductType()
784 != CalypsoCard::ProductType::PRIME_REVISION_3) {
785 if (mCard->getProductType()
786 == CalypsoCard::ProductType::PRIME_REVISION_2) {
788 std::string(
"Command may not be supported for ")
789 +
"PRIME_REVISION_2 card: Read Binary");
791 throw UnsupportedOperationException(
792 "'Read Binary' command is not available for this card");
796 Assert::getInstance()
798 static_cast<int>(sfi),
799 CalypsoCardConstant::SFI_MIN,
800 CalypsoCardConstant::SFI_MAX,
804 CalypsoCardConstant::OFFSET_MIN,
805 CalypsoCardConstant::OFFSET_BINARY_MAX,
807 .greaterOrEqual(nbBytesToRead, 1,
"nbBytesToRead");
809 if (sfi > 0 && offset > 255) {
815 std::make_shared<CommandReadBinary>(
816 getTransactionContext(), getCommandContext(), sfi, 0, 1));
819 int currentOffset = offset;
820 int nbBytesRemainingToRead = nbBytesToRead;
824 = std::min(nbBytesRemainingToRead, getPayloadCapacity());
827 std::make_shared<CommandReadBinary>(
828 getTransactionContext(),
834 currentOffset += currentLength;
835 nbBytesRemainingToRead -= currentLength;
837 }
while (nbBytesRemainingToRead > 0);
839 }
catch (
const RuntimeException&) {
844 return dynamic_cast<T&
>(*this);
849TransactionManagerAdapter<T>::prepareReadCounter(
850 std::uint8_t sfi,
int nbCountersToRead)
852 return prepareReadRecords(sfi, 1, 1, nbCountersToRead * 3);
857TransactionManagerAdapter<T>::prepareSearchRecords(
858 std::shared_ptr<SearchCommandData> data)
861 if (mCard->getProductType()
862 != CalypsoCard::ProductType::PRIME_REVISION_3) {
863 throw UnsupportedOperationException(
864 std::string(
"'Search Record Multiple' command is not available")
868 Assert::getInstance().notNull(data,
"data");
871 = std::dynamic_pointer_cast<DtoAdapters::SearchCommandDataAdapter>(
874 throw IllegalArgumentException(
875 "Cannot cast 'data' to SearchCommandDataAdapter. Actual type: "
879 if (getCommandContext()->isSecureSessionOpen()) {
880 throw IllegalStateException(MSG_SECURE_SESSION_OPEN);
883 Assert::getInstance()
885 static_cast<int>(dataAdapter->getSfi()),
886 CalypsoCardConstant::SFI_MIN,
887 CalypsoCardConstant::SFI_MAX,
890 dataAdapter->getRecordNumber(),
891 CalypsoCardConstant::NB_REC_MIN,
892 CalypsoCardConstant::NB_REC_MAX,
895 dataAdapter->getOffset(),
896 CalypsoCardConstant::OFFSET_MIN,
897 CalypsoCardConstant::OFFSET_MAX,
900 dataAdapter->getSearchData().size(),
901 CalypsoCardConstant::DATA_LENGTH_MIN,
902 getPayloadCapacity(),
904 if (dataAdapter->getMask().size() != 0) {
905 Assert::getInstance().isInRange(
906 dataAdapter->getMask().size(),
907 CalypsoCardConstant::DATA_LENGTH_MIN,
908 dataAdapter->getSearchData().size(),
913 std::make_shared<CommandSearchRecordMultiple>(
914 getTransactionContext(), getCommandContext(), dataAdapter));
921 return dynamic_cast<T&
>(*this);
926TransactionManagerAdapter<T>::prepareCheckPinStatus()
929 if (!mCard->isPinFeatureAvailable()) {
930 throw UnsupportedOperationException(MSG_PIN_NOT_AVAILABLE);
934 std::make_shared<CommandVerifyPin>(
935 getTransactionContext(), getCommandContext()));
942 return dynamic_cast<T&
>(*this);
947TransactionManagerAdapter<T>::prepareAppendRecord(
948 std::uint8_t sfi,
const std::vector<std::uint8_t>& recordData)
951 Assert::getInstance()
953 static_cast<int>(sfi),
954 CalypsoCardConstant::SFI_MIN,
955 CalypsoCardConstant::SFI_MAX,
960 getPayloadCapacity(),
961 MSG_RECORD_DATA_LENGTH);
963 auto command = std::make_shared<CommandAppendRecord>(
964 getTransactionContext(), getCommandContext(), sfi, recordData);
965 prepareNewSecureSessionIfNeeded(command);
966 mCommands.push_back(command);
973 return dynamic_cast<T&
>(*this);
978TransactionManagerAdapter<T>::prepareUpdateRecord(
981 const std::vector<std::uint8_t>& recordData)
984 Assert::getInstance()
986 static_cast<int>(sfi),
987 CalypsoCardConstant::SFI_MIN,
988 CalypsoCardConstant::SFI_MAX,
992 CalypsoCardConstant::NB_REC_MIN,
993 CalypsoCardConstant::NB_REC_MAX,
998 getPayloadCapacity(),
999 MSG_RECORD_DATA_LENGTH);
1001 auto command = std::make_shared<CommandUpdateRecord>(
1002 getTransactionContext(),
1003 getCommandContext(),
1005 static_cast<std::uint8_t
>(recordNumber),
1007 prepareNewSecureSessionIfNeeded(command);
1008 mCommands.push_back(command);
1015 return dynamic_cast<T&
>(*this);
1018template <
typename T>
1020TransactionManagerAdapter<T>::prepareWriteRecord(
1023 const std::vector<std::uint8_t>& recordData)
1026 Assert::getInstance()
1028 static_cast<int>(sfi),
1029 CalypsoCardConstant::SFI_MIN,
1030 CalypsoCardConstant::SFI_MAX,
1034 CalypsoCardConstant::NB_REC_MIN,
1035 CalypsoCardConstant::NB_REC_MAX,
1040 getPayloadCapacity(),
1041 MSG_RECORD_DATA_LENGTH);
1042 auto command = std::make_shared<CommandWriteRecord>(
1043 getTransactionContext(),
1044 getCommandContext(),
1046 static_cast<std::uint8_t
>(recordNumber),
1048 prepareNewSecureSessionIfNeeded(command);
1049 mCommands.push_back(command);
1056 return dynamic_cast<T&
>(*this);
1059template <
typename T>
1061TransactionManagerAdapter<T>::prepareUpdateBinary(
1062 std::uint8_t sfi,
int offset,
const std::vector<std::uint8_t>& data)
1064 return prepareUpdateOrWriteBinary(
true, sfi, offset, data);
1067template <
typename T>
1069TransactionManagerAdapter<T>::prepareWriteBinary(
1070 std::uint8_t sfi,
int offset,
const std::vector<std::uint8_t>& data)
1072 return prepareUpdateOrWriteBinary(
false, sfi, offset, data);
1075template <
typename T>
1077TransactionManagerAdapter<T>::prepareUpdateOrWriteBinary(
1078 bool isUpdateCommand,
1081 const std::vector<std::uint8_t>& data)
1084 if (mCard->getProductType()
1085 != CalypsoCard::ProductType::PRIME_REVISION_3) {
1086 if (mCard->getProductType()
1087 == CalypsoCard::ProductType::PRIME_REVISION_2) {
1089 std::string(
"Command may not be supported for ")
1090 +
"PRIME_REVISION_2 card: Update/Write Binary");
1092 throw UnsupportedOperationException(
1093 std::string(
"'Update/Write Binary' command is not ")
1094 +
"available for this card");
1098 Assert::getInstance()
1100 static_cast<int>(sfi),
1101 CalypsoCardConstant::SFI_MIN,
1102 CalypsoCardConstant::SFI_MAX,
1106 CalypsoCardConstant::OFFSET_MIN,
1107 CalypsoCardConstant::OFFSET_BINARY_MAX,
1109 .notEmpty(data,
"data");
1111 if (sfi > 0 && offset > 255) {
1116 mCommands.push_back(
1117 std::make_shared<CommandReadBinary>(
1118 getTransactionContext(), getCommandContext(), sfi, 0, 1));
1121 const int dataLength =
static_cast<int>(data.size());
1122 int currentOffset = offset;
1123 int currentIndex = 0;
1127 = std::min(dataLength - currentIndex, getPayloadCapacity());
1129 auto command = std::make_shared<CommandUpdateOrWriteBinary>(
1131 getTransactionContext(),
1132 getCommandContext(),
1135 Arrays::copyOfRange(
1136 data, currentIndex, currentIndex + currentLength));
1137 prepareNewSecureSessionIfNeeded(command);
1138 mCommands.push_back(command);
1140 currentOffset += currentLength;
1141 currentIndex += currentLength;
1143 }
while (currentIndex < dataLength);
1150 return dynamic_cast<T&
>(*this);
1153template <
typename T>
1155TransactionManagerAdapter<T>::prepareIncreaseCounter(
1156 std::uint8_t sfi,
int counterNumber,
int incValue)
1158 return prepareIncreaseOrDecreaseCounter(
1159 false, sfi, counterNumber, incValue);
1162template <
typename T>
1164TransactionManagerAdapter<T>::prepareIncreaseCounters(
1165 std::uint8_t sfi,
const std::map<int, int>& counterNumberToIncValueMap)
1167 return prepareIncreaseOrDecreaseCounters(
1168 false, sfi, counterNumberToIncValueMap);
1171template <
typename T>
1173TransactionManagerAdapter<T>::prepareDecreaseCounter(
1174 std::uint8_t sfi,
int counterNumber,
int decValue)
1176 return prepareIncreaseOrDecreaseCounter(
true, sfi, counterNumber, decValue);
1179template <
typename T>
1181TransactionManagerAdapter<T>::prepareDecreaseCounters(
1182 std::uint8_t sfi,
const std::map<int, int>& counterNumberToDecValueMap)
1184 return prepareIncreaseOrDecreaseCounters(
1185 true, sfi, counterNumberToDecValueMap);
1188template <
typename T>
1190TransactionManagerAdapter<T>::prepareSetCounter(
1191 std::uint8_t sfi,
int counterNumber,
int newValue)
1194 std::shared_ptr<int> oldValue =
nullptr;
1195 std::shared_ptr<ElementaryFile> ef = mCard->getFileBySfi(sfi);
1196 if (ef !=
nullptr) {
1197 oldValue = ef->getData()->getContentAsCounterValue(
1198 counterNumber != 0 ? counterNumber : 1);
1200 if (oldValue ==
nullptr) {
1201 throw IllegalStateException(
1202 std::string(
"The counter value is not available. SFI: ")
1203 + std::to_string(sfi)
1204 +
", Counter: " + std::to_string(counterNumber));
1207 int delta = newValue - *oldValue.get();
1210 "Increment counter #% (file %h) from % to %\n",
1212 HexUtil::toHex(sfi),
1215 prepareIncreaseCounter(sfi, counterNumber, delta);
1217 }
else if (delta < 0) {
1219 "Decrement counter #% (file %h) from % to %",
1221 HexUtil::toHex(sfi),
1224 prepareDecreaseCounter(sfi, counterNumber, -delta);
1228 "Counter #% (sfi %h) already set to the desired value %\n",
1230 HexUtil::toHex(sfi),
1239 return dynamic_cast<T&
>(*this);
1242template <
typename T>
1244TransactionManagerAdapter<T>::prepareIncreaseOrDecreaseCounter(
1245 bool isDecreaseCommand,
1251 Assert::getInstance()
1253 static_cast<int>(sfi),
1254 CalypsoCardConstant::SFI_MIN,
1255 CalypsoCardConstant::SFI_MAX,
1260 getPayloadCapacity() / 3,
1264 CalypsoCardConstant::CNT_VALUE_MIN,
1265 CalypsoCardConstant::CNT_VALUE_MAX,
1268 auto command = std::make_shared<CommandIncreaseOrDecrease>(
1270 getTransactionContext(),
1271 getCommandContext(),
1275 prepareNewSecureSessionIfNeeded(command);
1276 mCommands.push_back(command);
1283 return dynamic_cast<T&
>(*this);
1286template <
typename T>
1288TransactionManagerAdapter<T>::prepareIncreaseOrDecreaseCounters(
1289 bool isDecreaseCommand,
1291 const std::map<int, int>& counterNumberToIncDecValueMap)
1294 Assert::getInstance()
1296 static_cast<int>(sfi),
1297 CalypsoCardConstant::SFI_MIN,
1298 CalypsoCardConstant::SFI_MAX,
1301 counterNumberToIncDecValueMap.size(),
1303 getPayloadCapacity() / 3,
1304 "counterNumberToIncDecValueMap");
1306 for (
const auto& entry : counterNumberToIncDecValueMap) {
1307 Assert::getInstance()
1310 CalypsoCardConstant::NUM_CNT_MIN,
1311 getPayloadCapacity() / 3,
1312 "counterNumberToIncDecValueMapKey")
1315 CalypsoCardConstant::CNT_VALUE_MIN,
1316 CalypsoCardConstant::CNT_VALUE_MAX,
1317 "counterNumberToIncDecValueMapValue");
1320 if (mCard->getProductType()
1321 != CalypsoCard::ProductType::PRIME_REVISION_3
1322 && mCard->getProductType()
1323 != CalypsoCard::ProductType::PRIME_REVISION_2) {
1324 for (
const auto& entry : counterNumberToIncDecValueMap) {
1325 if (isDecreaseCommand) {
1326 prepareDecreaseCounter(sfi, entry.first, entry.second);
1329 prepareIncreaseCounter(sfi, entry.first, entry.second);
1334 const int nbCountersPerApdu = getPayloadCapacity() / 4;
1335 if (
static_cast<int>(counterNumberToIncDecValueMap.size())
1336 <= nbCountersPerApdu) {
1338 = std::make_shared<CommandIncreaseOrDecreaseMultiple>(
1340 getTransactionContext(),
1341 getCommandContext(),
1343 counterNumberToIncDecValueMap);
1345 prepareNewSecureSessionIfNeeded(command);
1346 mCommands.push_back(command);
1354 std::map<int, int> map;
1355 for (
const auto& entry : counterNumberToIncDecValueMap) {
1357 map[entry.first] = entry.second;
1358 if (i == nbCountersPerApdu) {
1359 auto command = std::make_shared<
1360 CommandIncreaseOrDecreaseMultiple>(
1362 getTransactionContext(),
1363 getCommandContext(),
1367 prepareNewSecureSessionIfNeeded(command);
1368 mCommands.push_back(command);
1375 = std::make_shared<CommandIncreaseOrDecreaseMultiple>(
1377 getTransactionContext(),
1378 getCommandContext(),
1382 prepareNewSecureSessionIfNeeded(command);
1383 mCommands.push_back(command);
1393 return dynamic_cast<T&
>(*this);
1396template <
typename T>
1398TransactionManagerAdapter<T>::prepareSvReadAllLogs()
1401 if (!mCard->isSvFeatureAvailable()) {
1402 throw UnsupportedOperationException(
1403 "Stored Value is not available for this card");
1406 if (mCard->getApplicationSubtype()
1407 != CalypsoCardConstant::STORED_VALUE_FILE_STRUCTURE_ID) {
1408 throw UnsupportedOperationException(
1409 "The currently selected application is not an SV application");
1413 const std::vector<std::uint8_t> empty;
1414 mCard->setSvData((std::uint8_t)0, empty, empty, 0, 0);
1416 CalypsoCardConstant::SV_RELOAD_LOG_FILE_SFI,
1418 CalypsoCardConstant::SV_RELOAD_LOG_FILE_NB_REC,
1419 CalypsoCardConstant::SV_LOG_FILE_REC_LENGTH);
1421 CalypsoCardConstant::SV_DEBIT_LOG_FILE_SFI,
1423 CalypsoCardConstant::SV_DEBIT_LOG_FILE_NB_REC,
1424 CalypsoCardConstant::SV_LOG_FILE_REC_LENGTH);
1431 return dynamic_cast<T&
>(*this);
1434template <
typename T>
1436TransactionManagerAdapter<T>::prepareGenerateAsymmetricKeyPair()
1438 if (!mCard->isPkiModeSupported()) {
1439 throw UnsupportedOperationException(
1440 MSG_PKI_MODE_IS_NOT_AVAILABLE_FOR_THIS_CARD);
1443 if (getTransactionContext()->isSecureSessionOpen()) {
1444 throw IllegalStateException(MSG_SECURE_SESSION_OPEN);
1447 mCommands.push_back(
1448 std::unique_ptr<CommandGenerateAsymmetricKeyPair>(
1449 new CommandGenerateAsymmetricKeyPair(
1450 getTransactionContext(), getCommandContext())));
1452 return dynamic_cast<T&
>(*this);
1455template <
typename T>
1456const std::vector<std::vector<std::uint8_t>>&
1457TransactionManagerAdapter<T>::getTransactionAuditData()
const
1460 return mTransactionAuditData;
1468#include "keypop/calypso/card/cpp/SecureExtendedModeTransactionManagerBase.hpp"
1469#include "keypop/calypso/card/cpp/SecureRegularModeTransactionManagerBase.hpp"
1470#include "keypop/calypso/card/transaction/FreeTransactionManager.hpp"
1471#include "keypop/calypso/card/transaction/SecurePkiModeTransactionManager.hpp"
1473template class keyple::card::calypso::TransactionManagerAdapter<
1474 keypop::calypso::card::transaction::FreeTransactionManager>;
1476template class keyple::card::calypso::TransactionManagerAdapter<
1477 keypop::calypso::card::cpp::SecureExtendedModeTransactionManagerBase>;
1479template class keyple::card::calypso::TransactionManagerAdapter<
1480 keypop::calypso::card::cpp::SecureRegularModeTransactionManagerBase>;
1482template class keyple::card::calypso::TransactionManagerAdapter<
1483 keypop::calypso::card::transaction::SecurePkiModeTransactionManager>;