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