Keyple Card Calypso C++ Library - 3.2.2
Component of the Keyple C++ middleware
TransactionManagerAdapter.cpp
Go to the documentation of this file.
1/******************************************************************************
2 * Copyright (c) 2025 Calypso Networks Association https://calypsonet.org/ *
3 * *
4 * See the NOTICE file(s) distributed with this work for additional *
5 * information regarding copyright ownership. *
6 * *
7 * This program and the accompanying materials are made available under the *
8 * terms of the Eclipse Public License 2.0 which is available at *
9 * http://www.eclipse.org/legal/epl-2.0 *
10 * *
11 * SPDX-License-Identifier: EPL-2.0 *
12 ******************************************************************************/
13
14#include "keyple/card/calypso/TransactionManagerAdapter.hpp"
15
16#include <algorithm>
17#include <map>
18#include <memory>
19#include <sstream>
20#include <string>
21#include <utility>
22#include <vector>
23
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"
59
60namespace keyple {
61namespace card {
62namespace calypso {
63
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;
78
79template <typename T>
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 ";
83template <typename T>
84const std::string TransactionManagerAdapter<T>::MSG_RESPONSES_GOT
85 = " responses, got ";
86template <typename T>
87const std::string
88 TransactionManagerAdapter<T>::MSG_CARD_READER_COMMUNICATION_ERROR
89 = "Failed to communicate with card reader";
90template <typename T>
91const std::string TransactionManagerAdapter<T>::MSG_CARD_COMMUNICATION_ERROR
92 = "Failed to communicate with card";
93template <typename T>
94const std::string TransactionManagerAdapter<T>::MSG_WHILE_TRANSMITTING_COMMANDS
95 = " while transmitting commands.";
96template <typename T>
97const std::string TransactionManagerAdapter<T>::MSG_PIN_NOT_AVAILABLE
98 = "PIN is not available for this card";
99template <typename T>
100const std::string TransactionManagerAdapter<T>::MSG_RECORD_NUMBER
101 = "record number";
102template <typename T>
103const std::string TransactionManagerAdapter<T>::MSG_OFFSET = "offset";
104template <typename T>
105const std::string TransactionManagerAdapter<T>::MSG_RECORD_DATA = "record data";
106template <typename T>
107const std::string TransactionManagerAdapter<T>::MSG_RECORD_DATA_LENGTH
108 = "record data length";
109template <typename T>
110const std::string TransactionManagerAdapter<T>::MSG_SECURE_SESSION_OPEN
111 = "Secure session is open";
112template <typename T>
113const std::string
114 TransactionManagerAdapter<T>::MSG_PKI_MODE_IS_NOT_AVAILABLE_FOR_THIS_CARD
115 = "PKI mode is not available for this card";
116template <typename T>
117const std::string TransactionManagerAdapter<T>::MSG_DATA_LENGTH = "data length";
118
119template <typename T>
120TransactionManagerAdapter<T>::TransactionManagerAdapter(
121 std::shared_ptr<ProxyReaderApi> cardReader,
122 std::shared_ptr<CalypsoCardAdapter> card)
123: mCard(card)
124, mCardReader(cardReader)
125{
126}
127
128template <typename T>
129void
130TransactionManagerAdapter<T>::executeCardCommands(
131 const std::vector<std::shared_ptr<Command>>& commands,
132 ChannelControl channelControl)
133{
134 /* Retrieve the list of C-APDUs */
135 std::vector<std::shared_ptr<ApduRequestSpi>> apduRequests
136 = getApduRequests(commands);
137
138 /* Wrap the list of C-APDUs into a card request */
139 auto cardRequest
140 = std::make_shared<DtoAdapters::CardRequestAdapter>(apduRequests, true);
141
142 /* Transmit the commands to the card */
143 std::shared_ptr<CardResponseApi> cardResponse
144 = transmitCardRequest(cardRequest, channelControl);
145
146 /* Retrieve the list of R-APDUs */
147 std::vector<std::shared_ptr<ApduResponseApi>> apduResponses
148 = cardResponse->getApduResponses();
149
150 /*
151 * If there are more responses than requests, then we are unable to fill the
152 * card image. In this case we stop processing immediately because it may be
153 * a case of fraud, and we throw a desynchronized exception.
154 */
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());
161 }
162
163 /*
164 * We go through all the responses (and not the requests) because there may
165 * be fewer in the case of an error that occurred in strict mode. In this
166 * case the last response will raise an exception.
167 */
168 for (int i = 0; i < static_cast<int>(apduResponses.size()); i++) {
169 std::shared_ptr<Command> command = commands[i];
170 try {
171 parseCommandResponse(command, apduResponses[i]);
172 handleCommandPostProcessing(i, commands);
173 } catch (const CardCommandException& e) {
174 const std::string sw
175 = command->getApduResponse() != nullptr
176 ? HexUtil::toHex(
177 static_cast<std::uint16_t>(
178 command->getApduResponse()->getStatusWord()))
179 : "null";
180 throw InvalidCardResponseException(
181 "Failed to process card response. Command: "
182 + command->getCommandRef().getName() + ", SW: " + sw
183 + getTransactionAuditDataAsString(),
184 e);
185 }
186 }
187
188 /*
189 * Finally, if no error has occurred and there are fewer responses than
190 * requests, then we throw a desynchronized exception.
191 */
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());
198 }
199}
200
201template <typename T>
202void
203TransactionManagerAdapter<T>::parseCommandResponse(
204 const std::shared_ptr<Command>& command,
205 const std::shared_ptr<ApduResponseApi>& apduResponse)
206{
207 command->parseResponse(apduResponse);
208}
209
210template <typename T>
211void
212TransactionManagerAdapter<T>::handleCommandPostProcessing(
213 int /*commandIndex*/,
214 const std::vector<std::shared_ptr<Command>>& /*commands*/)
215{
216}
217
218template <typename T>
219std::vector<std::shared_ptr<ApduRequestSpi>>
220TransactionManagerAdapter<T>::getApduRequests(
221 const std::vector<std::shared_ptr<Command>>& commands)
222{
223 std::vector<std::shared_ptr<ApduRequestSpi>> apduRequests;
224 if (!commands.empty()) {
225 for (const auto& command : commands) {
226 apduRequests.push_back(command->getApduRequest());
227 }
228 }
229
230 return apduRequests;
231}
232
233template <typename T>
234std::shared_ptr<CardResponseApi>
235TransactionManagerAdapter<T>::transmitCardRequest(
236 std::shared_ptr<CardRequestSpi> cardRequest, ChannelControl channelControl)
237{
238 std::shared_ptr<CardResponseApi> cardResponse;
239
240 try {
241 cardResponse = mCardReader->transmitCardRequest(
242 cardRequest, mapToInternalChannelControl(channelControl));
243
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(),
250 e);
251
252 } catch (const CardBrokenCommunicationException& e) {
253 saveTransactionAuditData(cardRequest, e.getCardResponse());
254 throw CardCommunicationException(
255 MSG_CARD_COMMUNICATION_ERROR + MSG_WHILE_TRANSMITTING_COMMANDS
256 + getTransactionAuditDataAsString(),
257 e);
258
259 } catch (const UnexpectedStatusWordException& e) {
260 cardResponse = e.getCardResponse();
261 }
262
263 saveTransactionAuditData(cardRequest, cardResponse);
264
265 return cardResponse;
266}
267
268template <typename T>
269std::string
270TransactionManagerAdapter<T>::getTransactionAuditDataAsString() const
271{
272 std::stringstream ss;
273
274 ss << "\nTransaction audit JSON data: {\"targetSmartCard\":";
275
276 if (mCard == nullptr) {
277 ss << "null";
278 } else {
279 ss << "{"
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()) << "\""
289 << "}";
290 }
291
292 ss << ",\"apdus\":[";
293
294 for (size_t i = 0; i < mTransactionAuditData.size(); i++) {
295 if (i != 0) {
296 ss << ",";
297 }
298 ss << "\"" << HexUtil::toHex(mTransactionAuditData[i]) << "\"";
299 }
300
301 ss << "]}";
302
303 return ss.str();
304}
305
306template <typename T>
307keypop::card::ChannelControl
308TransactionManagerAdapter<T>::mapToInternalChannelControl(
309 ChannelControl channelControl) const
310{
311 return keypop::card::valueOf(static_cast<int>(channelControl));
312}
313
314template <typename T>
315void
316TransactionManagerAdapter<T>::saveTransactionAuditData(
317 const std::shared_ptr<CardRequestSpi>& cardRequest,
318 const std::shared_ptr<CardResponseApi>& cardResponse)
319{
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();
325
326 int responsesSize = static_cast<int>(responses.size());
327
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);
333 }
334 }
335}
336
337template <typename T>
338T&
339TransactionManagerAdapter<T>::prepareSelectFile(std::uint16_t lid)
340{
341 try {
342 mCommands.push_back(
343 std::unique_ptr<CommandSelectFile>(new CommandSelectFile(
344 getTransactionContext(), getCommandContext(), lid)));
345
346 } catch (...) {
347 resetTransaction();
348 throw;
349 }
350
351 return dynamic_cast<T&>(*this);
352}
353
354template <typename T>
355T&
356TransactionManagerAdapter<T>::prepareSelectFile(
357 SelectFileControl selectFileControl)
358{
359 try {
360 mCommands.push_back(
361 std::unique_ptr<CommandSelectFile>(new CommandSelectFile(
362 getTransactionContext(),
363 getCommandContext(),
364 selectFileControl)));
365
366 } catch (...) {
367 resetTransaction();
368 throw;
369 }
370
371 return dynamic_cast<T&>(*this);
372}
373
374template <typename T>
375T&
376TransactionManagerAdapter<T>::prepareGetData(GetDataTag tag)
377{
378 try {
379 if (getCommandContext()->isSecureSessionOpen()) {
380 throw IllegalStateException(MSG_SECURE_SESSION_OPEN);
381 }
382
383 switch (tag) {
384 case GetDataTag::FCI_FOR_CURRENT_DF:
385 mCommands.push_back(
386 std::make_shared<CommandGetDataFci>(
387 getTransactionContext(), getCommandContext()));
388 break;
389 case GetDataTag::FCP_FOR_CURRENT_FILE:
390 mCommands.push_back(
391 std::make_shared<CommandGetDataFcp>(
392 getTransactionContext(), getCommandContext()));
393 break;
394 case GetDataTag::EF_LIST:
395 mCommands.push_back(
396 std::make_shared<CommandGetDataEfList>(
397 getTransactionContext(), getCommandContext()));
398 break;
399 case GetDataTag::TRACEABILITY_INFORMATION:
400 mCommands.push_back(
401 std::make_shared<CommandGetDataTraceabilityInformation>(
402 getTransactionContext(), getCommandContext()));
403 break;
404 case GetDataTag::CARD_PUBLIC_KEY:
405 mCommands.push_back(
406 std::make_shared<CommandGetDataCardPublicKey>(
407 getTransactionContext(), getCommandContext()));
408 break;
409 case GetDataTag::CARD_CERTIFICATE:
410 mCommands.push_back(
411 std::make_shared<CommandGetDataCertificate>(
412 getTransactionContext(), getCommandContext(), true, true));
413 mCommands.push_back(
414 std::make_shared<CommandGetDataCertificate>(
415 getTransactionContext(), getCommandContext(), true, false));
416 break;
417 case GetDataTag::CA_CERTIFICATE:
418 mCommands.push_back(
419 std::make_shared<CommandGetDataCertificate>(
420 getTransactionContext(), getCommandContext(), false, true));
421 mCommands.push_back(
422 std::make_shared<CommandGetDataCertificate>(
423 getTransactionContext(),
424 getCommandContext(),
425 false,
426 false));
427 break;
428 default:
429 throw UnsupportedOperationException(
430 "Unsupported GetDataTag: "
431 + std::to_string(static_cast<int>(tag)));
432 }
433
434 } catch (...) {
435 resetTransaction();
436 throw;
437 }
438
439 return dynamic_cast<T&>(*this);
440}
441
442template <typename T>
443T&
444TransactionManagerAdapter<T>::preparePutData(
445 PutDataTag putDataTag, const std::vector<std::uint8_t>& data)
446{
447 if (getCommandContext()->isSecureSessionOpen()) {
448 throw IllegalStateException(MSG_SECURE_SESSION_OPEN);
449 }
450
451 switch (putDataTag) {
452 case PutDataTag::CARD_KEY_PAIR:
453 preparePutDataCardKeyPair(putDataTag, data);
454 break;
455 case PutDataTag::CARD_CERTIFICATE:
456 preparePutDataCertificate(
457 putDataTag, data, CalypsoCardConstant::CARD_CERTIFICATE_SIZE);
458 break;
459 case PutDataTag::CA_CERTIFICATE:
460 preparePutDataCertificate(
461 putDataTag, data, CalypsoCardConstant::CA_CERTIFICATE_SIZE);
462 break;
463 default:
464 throw UnsupportedOperationException(
465 "Unsupported PutDataTag: "
466 + std::to_string(static_cast<int>(putDataTag)));
467 }
468
469 return dynamic_cast<T&>(*this);
470}
471
472template <typename T>
473void
474TransactionManagerAdapter<T>::preparePutDataCardKeyPair(
475 PutDataTag putDataTag, const std::vector<std::uint8_t>& data)
476{
477 if (!mCard->isPkiModeSupported()) {
478 throw UnsupportedOperationException(
479 MSG_PKI_MODE_IS_NOT_AVAILABLE_FOR_THIS_CARD);
480 }
481
482 Assert::getInstance().isEqual(
483 data.size(), CalypsoCardConstant::CARD_KEY_PAIR_SIZE, MSG_DATA_LENGTH);
484
485 mCommands.push_back(
486 std::make_shared<CommandPutData>(
487 getTransactionContext(),
488 getCommandContext(),
489 putDataTag,
490 true,
491 data));
492}
493
494template <typename T>
495void
496TransactionManagerAdapter<T>::preparePutDataCertificate(
497 PutDataTag putDataTag,
498 const std::vector<std::uint8_t>& data,
499 int certificateSize)
500{
501 std::shared_ptr<DtoAdapters::TransactionContextDto> transactionContext
502 = getTransactionContext();
503 std::shared_ptr<DtoAdapters::CommandContextDto> commandContext
504 = getCommandContext();
505
506 int payloadCapacity
507 = getTransactionContext()->getCard()->getPayloadCapacity();
508
509 if (!mCard->isPkiModeSupported()) {
510 throw UnsupportedOperationException(
511 MSG_PKI_MODE_IS_NOT_AVAILABLE_FOR_THIS_CARD);
512 }
513
514 Assert::getInstance().isEqual(
515 data.size(), certificateSize, MSG_DATA_LENGTH);
516
517 mCommands.push_back(
518 std::make_shared<CommandPutData>(
519 transactionContext,
520 commandContext,
521 putDataTag,
522 true,
523 Arrays::copyOf(
524 data,
525 payloadCapacity
526 - CalypsoCardConstant::TAG_CERTIFICATE_HEADER_SIZE)));
527 mCommands.push_back(
528 std::make_shared<CommandPutData>(
529 transactionContext,
530 commandContext,
531 putDataTag,
532 false,
533 Arrays::copyOfRange(
534 data,
535 payloadCapacity
536 - CalypsoCardConstant::TAG_CERTIFICATE_HEADER_SIZE,
537 data.size())));
538}
539
540template <typename T>
541T&
542TransactionManagerAdapter<T>::prepareReadRecord(
543 std::uint8_t sfi, int recordNumber)
544{
545 try {
546 if (getCommandContext()->isSecureSessionOpen()) {
547 throw IllegalStateException(MSG_SECURE_SESSION_OPEN);
548 }
549
550 Assert::getInstance()
551 .isInRange(
552 static_cast<int>(sfi),
553 CalypsoCardConstant::SFI_MIN,
554 CalypsoCardConstant::SFI_MAX,
555 "sfi")
556 .isInRange(
557 recordNumber,
558 CalypsoCardConstant::NB_REC_MIN,
559 CalypsoCardConstant::NB_REC_MAX,
560 MSG_RECORD_NUMBER);
561
562 /*
563 * A null record size indicates that the card determines the output
564 * length. However, "legacy case 1" cards require a non-zero value.
565 */
566 std::unique_ptr<int> recordSize
567 = mCard->isLegacyCase1()
568 ? std::unique_ptr<int>(
569 new int(CalypsoCardConstant::LEGACY_REC_LENGTH))
570 : nullptr;
571
572 mCommands.push_back(
573 std::make_shared<CommandReadRecords>(
574 getTransactionContext(),
575 getCommandContext(),
576 sfi,
577 recordNumber,
578 CommandReadRecords::ReadMode::ONE_RECORD,
579 std::move(recordSize),
580 recordSize != nullptr ? *recordSize : 0));
581
582 } catch (...) {
583 resetTransaction();
584 throw;
585 }
586
587 return dynamic_cast<T&>(*this);
588}
589
590template <typename T>
591T&
592TransactionManagerAdapter<T>::prepareReadRecords(
593 std::uint8_t sfi, int fromRecordNumber, int toRecordNumber, int recordSize)
594{
595 try {
596 Assert::getInstance()
597 .isInRange(
598 static_cast<int>(sfi),
599 CalypsoCardConstant::SFI_MIN,
600 CalypsoCardConstant::SFI_MAX,
601 "sfi")
602 .isInRange(
603 fromRecordNumber,
604 CalypsoCardConstant::NB_REC_MIN,
605 CalypsoCardConstant::NB_REC_MAX,
606 "fromRecordNumber")
607 .isInRange(
608 toRecordNumber,
609 fromRecordNumber,
610 CalypsoCardConstant::NB_REC_MAX,
611 "toRecordNumber")
612 .isInRange(recordSize, 0, getPayloadCapacity(), "recordSize");
613
614 if (toRecordNumber == fromRecordNumber
615 || (mCard->getProductType()
616 != CalypsoCard::ProductType::PRIME_REVISION_3
617 && mCard->getProductType()
618 != CalypsoCard::ProductType::LIGHT)) {
619 /*
620 * Creates N unitary "Read Records" commands.
621 * Try to group the first read record command with the open secure
622 * session command.
623 */
624 if (canConfigureReadOnOpenSecureSession()) {
625 auto session
626 = std::dynamic_pointer_cast<CommandOpenSecureSession>(
627 mCommands[mCommands.size() - 1]);
628 session->configureReadMode(sfi, fromRecordNumber, recordSize);
629 fromRecordNumber++;
630 }
631
632 for (int i = fromRecordNumber; i <= toRecordNumber; i++) {
633 mCommands.push_back(
634 std::make_shared<CommandReadRecords>(
635 getTransactionContext(),
636 getCommandContext(),
637 sfi,
638 i,
639 CommandReadRecords::ReadMode::ONE_RECORD,
640 std::unique_ptr<int>(new int(recordSize)),
641 recordSize));
642 }
643 } else {
644 /*
645 * Manages the reading of multiple records taking into account the
646 * transmission capacity of the card and the response format (2
647 * extra bytes).
648 * Multiple APDUs can be generated depending on record size and
649 * transmission capacity.
650 */
651 const int nbBytesPerRecord = recordSize + 2;
652 const int nbRecordsPerApdu
653 = getPayloadCapacity() / nbBytesPerRecord;
654 const int dataSizeMaxPerApdu = nbRecordsPerApdu * nbBytesPerRecord;
655
656 int currentRecordNumber = fromRecordNumber;
657 int nbRecordsRemainingToRead
658 = toRecordNumber - fromRecordNumber + 1;
659
660 while (currentRecordNumber < toRecordNumber) {
661 int currentLength
662 = nbRecordsRemainingToRead <= nbRecordsPerApdu
663 ? nbRecordsRemainingToRead * nbBytesPerRecord
664 : dataSizeMaxPerApdu;
665
666 mCommands.push_back(
667 std::make_shared<CommandReadRecords>(
668 getTransactionContext(),
669 getCommandContext(),
670 sfi,
671 currentRecordNumber,
672 CommandReadRecords::ReadMode::MULTIPLE_RECORD,
673 std::unique_ptr<int>(new int(currentLength)),
674 recordSize));
675 currentRecordNumber += (currentLength / nbBytesPerRecord);
676 nbRecordsRemainingToRead -= (currentLength / nbBytesPerRecord);
677 }
678
679 /*
680 * Optimization: prepare a read "one record" if possible for last
681 * iteration.
682 */
683 if (currentRecordNumber == toRecordNumber) {
684 mCommands.push_back(
685 std::make_shared<CommandReadRecords>(
686 getTransactionContext(),
687 getCommandContext(),
688 sfi,
689 currentRecordNumber,
690 CommandReadRecords::ReadMode::ONE_RECORD,
691 std::unique_ptr<int>(new int(recordSize)),
692 recordSize));
693 }
694 }
695
696 } catch (...) {
697 resetTransaction();
698 throw;
699 }
700
701 return dynamic_cast<T&>(*this);
702}
703
704template <typename T>
705T&
706TransactionManagerAdapter<T>::prepareReadRecordsPartially(
707 std::uint8_t sfi,
708 int fromRecordNumber,
709 int toRecordNumber,
710 int offset,
711 int nbBytesToRead)
712{
713 try {
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 ")
719 + "for this card");
720 }
721
722 if (getCommandContext()->isSecureSessionOpen()) {
723 throw IllegalStateException(MSG_SECURE_SESSION_OPEN);
724 }
725
726 Assert::getInstance()
727 .isInRange(
728 static_cast<int>(sfi),
729 CalypsoCardConstant::SFI_MIN,
730 CalypsoCardConstant::SFI_MAX,
731 "sfi")
732 .isInRange(
733 fromRecordNumber,
734 CalypsoCardConstant::NB_REC_MIN,
735 CalypsoCardConstant::NB_REC_MAX,
736 "fromRecordNumber")
737 .isInRange(
738 toRecordNumber,
739 fromRecordNumber,
740 CalypsoCardConstant::NB_REC_MAX,
741 "toRecordNumber")
742 .isInRange(
743 offset,
744 CalypsoCardConstant::OFFSET_MIN,
745 CalypsoCardConstant::OFFSET_MAX,
746 MSG_OFFSET)
747 .isInRange(
748 nbBytesToRead,
749 CalypsoCardConstant::DATA_LENGTH_MIN,
750 getPayloadCapacity(),
751 "nbBytesToRead");
752
753 const int nbRecordsPerApdu = getPayloadCapacity() / nbBytesToRead;
754
755 int currentRecordNumber = fromRecordNumber;
756
757 while (currentRecordNumber <= toRecordNumber) {
758 mCommands.push_back(
759 std::make_shared<CommandReadRecordMultiple>(
760 getTransactionContext(),
761 getCommandContext(),
762 sfi,
763 static_cast<std::uint8_t>(currentRecordNumber),
764 static_cast<std::uint8_t>(offset),
765 static_cast<std::uint8_t>(nbBytesToRead)));
766 currentRecordNumber += nbRecordsPerApdu;
767 }
768
769 } catch (...) {
770 resetTransaction();
771 throw;
772 }
773
774 return dynamic_cast<T&>(*this);
775}
776
777template <typename T>
778T&
779TransactionManagerAdapter<T>::prepareReadBinary(
780 std::uint8_t sfi, int offset, int nbBytesToRead)
781{
782 try {
783 if (mCard->getProductType()
784 != CalypsoCard::ProductType::PRIME_REVISION_3) {
785 if (mCard->getProductType()
786 == CalypsoCard::ProductType::PRIME_REVISION_2) {
787 mLogger->warn(
788 std::string("Command may not be supported for ")
789 + "PRIME_REVISION_2 card: Read Binary");
790 } else {
791 throw UnsupportedOperationException(
792 "'Read Binary' command is not available for this card");
793 }
794 }
795
796 Assert::getInstance()
797 .isInRange(
798 static_cast<int>(sfi),
799 CalypsoCardConstant::SFI_MIN,
800 CalypsoCardConstant::SFI_MAX,
801 "sfi")
802 .isInRange(
803 offset,
804 CalypsoCardConstant::OFFSET_MIN,
805 CalypsoCardConstant::OFFSET_BINARY_MAX,
806 MSG_OFFSET)
807 .greaterOrEqual(nbBytesToRead, 1, "nbBytesToRead");
808
809 if (sfi > 0 && offset > 255) {
810 /*
811 * Tips to select the file: add a "Read Binary" command (read one
812 * byte at offset 0).
813 */
814 mCommands.push_back(
815 std::make_shared<CommandReadBinary>(
816 getTransactionContext(), getCommandContext(), sfi, 0, 1));
817 }
818
819 int currentOffset = offset;
820 int nbBytesRemainingToRead = nbBytesToRead;
821
822 do {
823 int currentLength
824 = std::min(nbBytesRemainingToRead, getPayloadCapacity());
825
826 mCommands.push_back(
827 std::make_shared<CommandReadBinary>(
828 getTransactionContext(),
829 getCommandContext(),
830 sfi,
831 currentOffset,
832 currentLength));
833
834 currentOffset += currentLength;
835 nbBytesRemainingToRead -= currentLength;
836
837 } while (nbBytesRemainingToRead > 0);
838
839 } catch (const RuntimeException&) {
840 resetTransaction();
841 throw;
842 }
843
844 return dynamic_cast<T&>(*this);
845}
846
847template <typename T>
848T&
849TransactionManagerAdapter<T>::prepareReadCounter(
850 std::uint8_t sfi, int nbCountersToRead)
851{
852 return prepareReadRecords(sfi, 1, 1, nbCountersToRead * 3);
853}
854
855template <typename T>
856T&
857TransactionManagerAdapter<T>::prepareSearchRecords(
858 std::shared_ptr<SearchCommandData> data)
859{
860 try {
861 if (mCard->getProductType()
862 != CalypsoCard::ProductType::PRIME_REVISION_3) {
863 throw UnsupportedOperationException(
864 std::string("'Search Record Multiple' command is not available")
865 + " for this card");
866 }
867
868 Assert::getInstance().notNull(data, "data");
869
870 auto dataAdapter
871 = std::dynamic_pointer_cast<DtoAdapters::SearchCommandDataAdapter>(
872 data);
873 if (!dataAdapter) {
874 throw IllegalArgumentException(
875 "Cannot cast 'data' to SearchCommandDataAdapter. Actual type: "
876 /* FIXME? + data->getClass().getName()*/);
877 }
878
879 if (getCommandContext()->isSecureSessionOpen()) {
880 throw IllegalStateException(MSG_SECURE_SESSION_OPEN);
881 }
882
883 Assert::getInstance()
884 .isInRange(
885 static_cast<int>(dataAdapter->getSfi()),
886 CalypsoCardConstant::SFI_MIN,
887 CalypsoCardConstant::SFI_MAX,
888 "sfi")
889 .isInRange(
890 dataAdapter->getRecordNumber(),
891 CalypsoCardConstant::NB_REC_MIN,
892 CalypsoCardConstant::NB_REC_MAX,
893 "startAtRecord")
894 .isInRange(
895 dataAdapter->getOffset(),
896 CalypsoCardConstant::OFFSET_MIN,
897 CalypsoCardConstant::OFFSET_MAX,
898 MSG_OFFSET)
899 .isInRange(
900 dataAdapter->getSearchData().size(),
901 CalypsoCardConstant::DATA_LENGTH_MIN,
902 getPayloadCapacity(),
903 "searchData");
904 if (dataAdapter->getMask().size() != 0) {
905 Assert::getInstance().isInRange(
906 dataAdapter->getMask().size(),
907 CalypsoCardConstant::DATA_LENGTH_MIN,
908 dataAdapter->getSearchData().size(),
909 "mask");
910 }
911
912 mCommands.push_back(
913 std::make_shared<CommandSearchRecordMultiple>(
914 getTransactionContext(), getCommandContext(), dataAdapter));
915
916 } catch (...) {
917 resetTransaction();
918 throw;
919 }
920
921 return dynamic_cast<T&>(*this);
922}
923
924template <typename T>
925T&
926TransactionManagerAdapter<T>::prepareCheckPinStatus()
927{
928 try {
929 if (!mCard->isPinFeatureAvailable()) {
930 throw UnsupportedOperationException(MSG_PIN_NOT_AVAILABLE);
931 }
932
933 mCommands.push_back(
934 std::make_shared<CommandVerifyPin>(
935 getTransactionContext(), getCommandContext()));
936
937 } catch (...) {
938 resetTransaction();
939 throw;
940 }
941
942 return dynamic_cast<T&>(*this);
943}
944
945template <typename T>
946T&
947TransactionManagerAdapter<T>::prepareAppendRecord(
948 std::uint8_t sfi, const std::vector<std::uint8_t>& recordData)
949{
950 try {
951 Assert::getInstance()
952 .isInRange(
953 static_cast<int>(sfi),
954 CalypsoCardConstant::SFI_MIN,
955 CalypsoCardConstant::SFI_MAX,
956 "sfi")
957 .isInRange(
958 recordData.size(),
959 0,
960 getPayloadCapacity(),
961 MSG_RECORD_DATA_LENGTH);
962
963 auto command = std::make_shared<CommandAppendRecord>(
964 getTransactionContext(), getCommandContext(), sfi, recordData);
965 prepareNewSecureSessionIfNeeded(command);
966 mCommands.push_back(command);
967
968 } catch (...) {
969 resetTransaction();
970 throw;
971 }
972
973 return dynamic_cast<T&>(*this);
974}
975
976template <typename T>
977T&
978TransactionManagerAdapter<T>::prepareUpdateRecord(
979 std::uint8_t sfi,
980 int recordNumber,
981 const std::vector<std::uint8_t>& recordData)
982{
983 try {
984 Assert::getInstance()
985 .isInRange(
986 static_cast<int>(sfi),
987 CalypsoCardConstant::SFI_MIN,
988 CalypsoCardConstant::SFI_MAX,
989 "sfi")
990 .isInRange(
991 recordNumber,
992 CalypsoCardConstant::NB_REC_MIN,
993 CalypsoCardConstant::NB_REC_MAX,
994 MSG_RECORD_NUMBER)
995 .isInRange(
996 recordData.size(),
997 0,
998 getPayloadCapacity(),
999 MSG_RECORD_DATA_LENGTH);
1000
1001 auto command = std::make_shared<CommandUpdateRecord>(
1002 getTransactionContext(),
1003 getCommandContext(),
1004 sfi,
1005 static_cast<std::uint8_t>(recordNumber),
1006 recordData);
1007 prepareNewSecureSessionIfNeeded(command);
1008 mCommands.push_back(command);
1009
1010 } catch (...) {
1011 resetTransaction();
1012 throw;
1013 }
1014
1015 return dynamic_cast<T&>(*this);
1016}
1017
1018template <typename T>
1019T&
1020TransactionManagerAdapter<T>::prepareWriteRecord(
1021 std::uint8_t sfi,
1022 int recordNumber,
1023 const std::vector<std::uint8_t>& recordData)
1024{
1025 try {
1026 Assert::getInstance()
1027 .isInRange(
1028 static_cast<int>(sfi),
1029 CalypsoCardConstant::SFI_MIN,
1030 CalypsoCardConstant::SFI_MAX,
1031 "sfi")
1032 .isInRange(
1033 recordNumber,
1034 CalypsoCardConstant::NB_REC_MIN,
1035 CalypsoCardConstant::NB_REC_MAX,
1036 MSG_RECORD_NUMBER)
1037 .isInRange(
1038 recordData.size(),
1039 0,
1040 getPayloadCapacity(),
1041 MSG_RECORD_DATA_LENGTH);
1042 auto command = std::make_shared<CommandWriteRecord>(
1043 getTransactionContext(),
1044 getCommandContext(),
1045 sfi,
1046 static_cast<std::uint8_t>(recordNumber),
1047 recordData);
1048 prepareNewSecureSessionIfNeeded(command);
1049 mCommands.push_back(command);
1050
1051 } catch (...) {
1052 resetTransaction();
1053 throw;
1054 }
1055
1056 return dynamic_cast<T&>(*this);
1057}
1058
1059template <typename T>
1060T&
1061TransactionManagerAdapter<T>::prepareUpdateBinary(
1062 std::uint8_t sfi, int offset, const std::vector<std::uint8_t>& data)
1063{
1064 return prepareUpdateOrWriteBinary(true, sfi, offset, data);
1065}
1066
1067template <typename T>
1068T&
1069TransactionManagerAdapter<T>::prepareWriteBinary(
1070 std::uint8_t sfi, int offset, const std::vector<std::uint8_t>& data)
1071{
1072 return prepareUpdateOrWriteBinary(false, sfi, offset, data);
1073}
1074
1075template <typename T>
1076T&
1077TransactionManagerAdapter<T>::prepareUpdateOrWriteBinary(
1078 bool isUpdateCommand,
1079 std::uint8_t sfi,
1080 int offset,
1081 const std::vector<std::uint8_t>& data)
1082{
1083 try {
1084 if (mCard->getProductType()
1085 != CalypsoCard::ProductType::PRIME_REVISION_3) {
1086 if (mCard->getProductType()
1087 == CalypsoCard::ProductType::PRIME_REVISION_2) {
1088 mLogger->warn(
1089 std::string("Command may not be supported for ")
1090 + "PRIME_REVISION_2 card: Update/Write Binary");
1091 } else {
1092 throw UnsupportedOperationException(
1093 std::string("'Update/Write Binary' command is not ")
1094 + "available for this card");
1095 }
1096 }
1097
1098 Assert::getInstance()
1099 .isInRange(
1100 static_cast<int>(sfi),
1101 CalypsoCardConstant::SFI_MIN,
1102 CalypsoCardConstant::SFI_MAX,
1103 "sfi")
1104 .isInRange(
1105 offset,
1106 CalypsoCardConstant::OFFSET_MIN,
1107 CalypsoCardConstant::OFFSET_BINARY_MAX,
1108 MSG_OFFSET)
1109 .notEmpty(data, "data");
1110
1111 if (sfi > 0 && offset > 255) {
1112 /*
1113 * Tips to select the file: add a "Read Binary" command (read one
1114 * byte at offset 0).
1115 */
1116 mCommands.push_back(
1117 std::make_shared<CommandReadBinary>(
1118 getTransactionContext(), getCommandContext(), sfi, 0, 1));
1119 }
1120
1121 const int dataLength = static_cast<int>(data.size());
1122 int currentOffset = offset;
1123 int currentIndex = 0;
1124
1125 do {
1126 int currentLength
1127 = std::min(dataLength - currentIndex, getPayloadCapacity());
1128
1129 auto command = std::make_shared<CommandUpdateOrWriteBinary>(
1130 isUpdateCommand,
1131 getTransactionContext(),
1132 getCommandContext(),
1133 sfi,
1134 currentOffset,
1135 Arrays::copyOfRange(
1136 data, currentIndex, currentIndex + currentLength));
1137 prepareNewSecureSessionIfNeeded(command);
1138 mCommands.push_back(command);
1139
1140 currentOffset += currentLength;
1141 currentIndex += currentLength;
1142
1143 } while (currentIndex < dataLength);
1144
1145 } catch (...) {
1146 resetTransaction();
1147 throw;
1148 }
1149
1150 return dynamic_cast<T&>(*this);
1151}
1152
1153template <typename T>
1154T&
1155TransactionManagerAdapter<T>::prepareIncreaseCounter(
1156 std::uint8_t sfi, int counterNumber, int incValue)
1157{
1158 return prepareIncreaseOrDecreaseCounter(
1159 false, sfi, counterNumber, incValue);
1160}
1161
1162template <typename T>
1163T&
1164TransactionManagerAdapter<T>::prepareIncreaseCounters(
1165 std::uint8_t sfi, const std::map<int, int>& counterNumberToIncValueMap)
1166{
1167 return prepareIncreaseOrDecreaseCounters(
1168 false, sfi, counterNumberToIncValueMap);
1169}
1170
1171template <typename T>
1172T&
1173TransactionManagerAdapter<T>::prepareDecreaseCounter(
1174 std::uint8_t sfi, int counterNumber, int decValue)
1175{
1176 return prepareIncreaseOrDecreaseCounter(true, sfi, counterNumber, decValue);
1177}
1178
1179template <typename T>
1180T&
1181TransactionManagerAdapter<T>::prepareDecreaseCounters(
1182 std::uint8_t sfi, const std::map<int, int>& counterNumberToDecValueMap)
1183{
1184 return prepareIncreaseOrDecreaseCounters(
1185 true, sfi, counterNumberToDecValueMap);
1186}
1187
1188template <typename T>
1189T&
1190TransactionManagerAdapter<T>::prepareSetCounter(
1191 std::uint8_t sfi, int counterNumber, int newValue)
1192{
1193 try {
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);
1199 }
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));
1205 }
1206
1207 int delta = newValue - *oldValue.get();
1208 if (delta > 0) {
1209 mLogger->trace(
1210 "Increment counter #% (file %h) from % to %\n",
1211 counterNumber,
1212 HexUtil::toHex(sfi),
1213 newValue - delta,
1214 newValue);
1215 prepareIncreaseCounter(sfi, counterNumber, delta);
1216
1217 } else if (delta < 0) {
1218 mLogger->trace(
1219 "Decrement counter #% (file %h) from % to %",
1220 counterNumber,
1221 HexUtil::toHex(sfi),
1222 newValue - delta,
1223 newValue);
1224 prepareDecreaseCounter(sfi, counterNumber, -delta);
1225
1226 } else {
1227 mLogger->debug(
1228 "Counter #% (sfi %h) already set to the desired value %\n",
1229 counterNumber,
1230 HexUtil::toHex(sfi),
1231 newValue);
1232 }
1233
1234 } catch (...) {
1235 resetTransaction();
1236 throw;
1237 }
1238
1239 return dynamic_cast<T&>(*this);
1240}
1241
1242template <typename T>
1243T&
1244TransactionManagerAdapter<T>::prepareIncreaseOrDecreaseCounter(
1245 bool isDecreaseCommand,
1246 std::uint8_t sfi,
1247 int counterNumber,
1248 int incDecValue)
1249{
1250 try {
1251 Assert::getInstance()
1252 .isInRange(
1253 static_cast<int>(sfi),
1254 CalypsoCardConstant::SFI_MIN,
1255 CalypsoCardConstant::SFI_MAX,
1256 "sfi")
1257 .isInRange(
1258 counterNumber,
1259 0, // Allows simulated counters
1260 getPayloadCapacity() / 3,
1261 "counterNumber")
1262 .isInRange(
1263 incDecValue,
1264 CalypsoCardConstant::CNT_VALUE_MIN,
1265 CalypsoCardConstant::CNT_VALUE_MAX,
1266 "incDecValue");
1267
1268 auto command = std::make_shared<CommandIncreaseOrDecrease>(
1269 isDecreaseCommand,
1270 getTransactionContext(),
1271 getCommandContext(),
1272 sfi,
1273 counterNumber,
1274 incDecValue);
1275 prepareNewSecureSessionIfNeeded(command);
1276 mCommands.push_back(command);
1277
1278 } catch (...) {
1279 resetTransaction();
1280 throw;
1281 }
1282
1283 return dynamic_cast<T&>(*this);
1284}
1285
1286template <typename T>
1287T&
1288TransactionManagerAdapter<T>::prepareIncreaseOrDecreaseCounters(
1289 bool isDecreaseCommand,
1290 std::uint8_t sfi,
1291 const std::map<int, int>& counterNumberToIncDecValueMap)
1292{
1293 try {
1294 Assert::getInstance()
1295 .isInRange(
1296 static_cast<int>(sfi),
1297 CalypsoCardConstant::SFI_MIN,
1298 CalypsoCardConstant::SFI_MAX,
1299 "sfi")
1300 .isInRange(
1301 counterNumberToIncDecValueMap.size(),
1302 1,
1303 getPayloadCapacity() / 3,
1304 "counterNumberToIncDecValueMap");
1305
1306 for (const auto& entry : counterNumberToIncDecValueMap) {
1307 Assert::getInstance()
1308 .isInRange(
1309 entry.first,
1310 CalypsoCardConstant::NUM_CNT_MIN,
1311 getPayloadCapacity() / 3,
1312 "counterNumberToIncDecValueMapKey")
1313 .isInRange(
1314 entry.second,
1315 CalypsoCardConstant::CNT_VALUE_MIN,
1316 CalypsoCardConstant::CNT_VALUE_MAX,
1317 "counterNumberToIncDecValueMapValue");
1318 }
1319
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);
1327
1328 } else {
1329 prepareIncreaseCounter(sfi, entry.first, entry.second);
1330 }
1331 }
1332
1333 } else {
1334 const int nbCountersPerApdu = getPayloadCapacity() / 4;
1335 if (static_cast<int>(counterNumberToIncDecValueMap.size())
1336 <= nbCountersPerApdu) {
1337 auto command
1338 = std::make_shared<CommandIncreaseOrDecreaseMultiple>(
1339 isDecreaseCommand,
1340 getTransactionContext(),
1341 getCommandContext(),
1342 sfi,
1343 counterNumberToIncDecValueMap);
1344
1345 prepareNewSecureSessionIfNeeded(command);
1346 mCommands.push_back(command);
1347
1348 } else {
1349 /*
1350 * The number of counters exceeds the payload capacity, let's
1351 * split into several apdu commands
1352 */
1353 int i = 0;
1354 std::map<int, int> map;
1355 for (const auto& entry : counterNumberToIncDecValueMap) {
1356 i++;
1357 map[entry.first] = entry.second;
1358 if (i == nbCountersPerApdu) {
1359 auto command = std::make_shared<
1360 CommandIncreaseOrDecreaseMultiple>(
1361 isDecreaseCommand,
1362 getTransactionContext(),
1363 getCommandContext(),
1364 sfi,
1365 map);
1366
1367 prepareNewSecureSessionIfNeeded(command);
1368 mCommands.push_back(command);
1369 i = 0;
1370 map.clear();
1371 }
1372 }
1373 if (!map.empty()) {
1374 auto command
1375 = std::make_shared<CommandIncreaseOrDecreaseMultiple>(
1376 isDecreaseCommand,
1377 getTransactionContext(),
1378 getCommandContext(),
1379 sfi,
1380 map);
1381
1382 prepareNewSecureSessionIfNeeded(command);
1383 mCommands.push_back(command);
1384 }
1385 }
1386 }
1387
1388 } catch (...) {
1389 resetTransaction();
1390 throw;
1391 }
1392
1393 return dynamic_cast<T&>(*this);
1394}
1395
1396template <typename T>
1397T&
1398TransactionManagerAdapter<T>::prepareSvReadAllLogs()
1399{
1400 try {
1401 if (!mCard->isSvFeatureAvailable()) {
1402 throw UnsupportedOperationException(
1403 "Stored Value is not available for this card");
1404 }
1405
1406 if (mCard->getApplicationSubtype()
1407 != CalypsoCardConstant::STORED_VALUE_FILE_STRUCTURE_ID) {
1408 throw UnsupportedOperationException(
1409 "The currently selected application is not an SV application");
1410 }
1411
1412 /* Reset SV data in CalypsoCard if any */
1413 const std::vector<std::uint8_t> empty;
1414 mCard->setSvData((std::uint8_t)0, empty, empty, 0, 0);
1415 prepareReadRecords(
1416 CalypsoCardConstant::SV_RELOAD_LOG_FILE_SFI,
1417 1,
1418 CalypsoCardConstant::SV_RELOAD_LOG_FILE_NB_REC,
1419 CalypsoCardConstant::SV_LOG_FILE_REC_LENGTH);
1420 prepareReadRecords(
1421 CalypsoCardConstant::SV_DEBIT_LOG_FILE_SFI,
1422 1,
1423 CalypsoCardConstant::SV_DEBIT_LOG_FILE_NB_REC,
1424 CalypsoCardConstant::SV_LOG_FILE_REC_LENGTH);
1425
1426 } catch (...) {
1427 resetTransaction();
1428 throw;
1429 }
1430
1431 return dynamic_cast<T&>(*this);
1432}
1433
1434template <typename T>
1435T&
1436TransactionManagerAdapter<T>::prepareGenerateAsymmetricKeyPair()
1437{
1438 if (!mCard->isPkiModeSupported()) {
1439 throw UnsupportedOperationException(
1440 MSG_PKI_MODE_IS_NOT_AVAILABLE_FOR_THIS_CARD);
1441 }
1442
1443 if (getTransactionContext()->isSecureSessionOpen()) {
1444 throw IllegalStateException(MSG_SECURE_SESSION_OPEN);
1445 }
1446
1447 mCommands.push_back(
1448 std::unique_ptr<CommandGenerateAsymmetricKeyPair>(
1449 new CommandGenerateAsymmetricKeyPair(
1450 getTransactionContext(), getCommandContext())));
1451
1452 return dynamic_cast<T&>(*this);
1453}
1454
1455template <typename T>
1456const std::vector<std::vector<std::uint8_t>>&
1457TransactionManagerAdapter<T>::getTransactionAuditData() const
1458{
1459 /* CL-CSS-INFODATA.1 */
1460 return mTransactionAuditData;
1461}
1462
1463} /* namespace calypso */
1464} /* namespace card */
1465} /* namespace keyple */
1466
1467/* Explicit template instantiations for concrete transaction manager bases */
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"
1472
1473template class keyple::card::calypso::TransactionManagerAdapter<
1474 keypop::calypso::card::transaction::FreeTransactionManager>;
1475
1476template class keyple::card::calypso::TransactionManagerAdapter<
1477 keypop::calypso::card::cpp::SecureExtendedModeTransactionManagerBase>;
1478
1479template class keyple::card::calypso::TransactionManagerAdapter<
1480 keypop::calypso::card::cpp::SecureRegularModeTransactionManagerBase>;
1481
1482template class keyple::card::calypso::TransactionManagerAdapter<
1483 keypop::calypso::card::transaction::SecurePkiModeTransactionManager>;