Keyple Card Calypso C++ Library - 3.2.2
Component of the Keyple C++ middleware
CalypsoCardAdapter.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/CalypsoCardAdapter.hpp"
15
16#include <map>
17#include <memory>
18#include <string>
19#include <utility>
20#include <vector>
21
22#include "keyple/card/calypso/CalypsoCardClass.hpp"
23#include "keyple/card/calypso/CalypsoCardConstant.hpp"
24#include "keyple/card/calypso/DtoAdapters.hpp"
25#include "keyple/core/util/ByteArrayUtil.hpp"
26#include "keyple/core/util/HexUtil.hpp"
27#include "keyple/core/util/cpp/KeypleStd.hpp"
28#include "keyple/core/util/cpp/System.hpp"
29#include "keyple/core/util/cpp/exception/IllegalArgumentException.hpp"
30#include "keyple/core/util/cpp/exception/IllegalStateException.hpp"
31#include "keypop/card/CardSelectionResponseApi.hpp"
32
33namespace keyple {
34namespace card {
35namespace calypso {
36
37using keyple::core::util::ByteArrayUtil;
38using keyple::core::util::HexUtil;
39using keyple::core::util::cpp::System;
40using keyple::core::util::cpp::exception::IllegalArgumentException;
41using keyple::core::util::cpp::exception::IllegalStateException;
42using keypop::card::CardSelectionResponseApi;
43
44const int CalypsoCardAdapter::CARD_REV1_ATR_LENGTH = 20;
45const int CalypsoCardAdapter ::
46 REV1_CARD_DEFAULT_WRITE_OPERATIONS_NUMBER_SUPPORTED_PER_SESSION = 3;
47const int CalypsoCardAdapter ::
48 REV2_CARD_DEFAULT_WRITE_OPERATIONS_NUMBER_SUPPORTED_PER_SESSION = 6;
49const int CalypsoCardAdapter::SI_BUFFER_SIZE_INDICATOR = 0;
50const int CalypsoCardAdapter::SI_PLATFORM = 1;
51const int CalypsoCardAdapter::SI_APPLICATION_TYPE = 2;
52const int CalypsoCardAdapter::SI_APPLICATION_SUBTYPE = 3;
53const int CalypsoCardAdapter::SI_SOFTWARE_ISSUER = 4;
54const int CalypsoCardAdapter::SI_SOFTWARE_VERSION = 5;
55const int CalypsoCardAdapter::SI_SOFTWARE_REVISION = 6;
56const int CalypsoCardAdapter::DEFAULT_PAYLOAD_CAPACITY = 250;
57
58const uint8_t CalypsoCardAdapter::APP_TYPE_WITH_CALYPSO_PIN = 0x01;
59const uint8_t CalypsoCardAdapter::APP_TYPE_WITH_CALYPSO_SV = 0x02;
60const uint8_t CalypsoCardAdapter::APP_TYPE_RATIFICATION_COMMAND_REQUIRED = 0x04;
61const uint8_t CalypsoCardAdapter::APP_TYPE_CALYPSO_REV_32_MODE = 0x08;
62const uint8_t CalypsoCardAdapter::APP_TYPE_WITH_PUBLIC_AUTHENTICATION = 0x10;
63
64const std::vector<int> CalypsoCardAdapter::BUFFER_SIZE_INDICATOR_TO_BUFFER_SIZE
65 = {0, 0, 0, 0, 0, 0, 215, 256,
66 304, 362, 430, 512, 608, 724, 861, 1024,
67 1217, 1448, 1722, 2048, 2435, 2896, 3444, 4096,
68 4870, 5792, 6888, 8192, 9741, 11585, 13777, 16384,
69 19483, 23170, 27554, 32768, 38967, 46340, 55108, 65536,
70 77935, 92681, 110217, 131072, 155871, 185363, 220435, 262144,
71 311743, 370727, 440871, 524288, 623487, 741455, 881743, 1048576};
72
73const std::vector<std::shared_ptr<CalypsoCardAdapter::PatchRev3>>
74 CalypsoCardAdapter::mPatchesRev3 = initPatchRev3();
75const std::vector<std::shared_ptr<CalypsoCardAdapter::PatchRev12>>
76 CalypsoCardAdapter::mPatchesRev12 = initPatchRev12();
77
78CalypsoCardAdapter::CalypsoCardAdapter()
79{
80}
81
82void
83CalypsoCardAdapter::initialize(
84 const std::shared_ptr<CardSelectionResponseApi> cardSelectionResponse)
85{
86 if (cardSelectionResponse != nullptr) {
87 if (cardSelectionResponse->getSelectApplicationResponse() != nullptr) {
88 initializeWithFci(
89 cardSelectionResponse->getSelectApplicationResponse());
90
91 } else if (cardSelectionResponse->getPowerOnData() != std::string("")) {
92 initializeWithPowerOnData(cardSelectionResponse->getPowerOnData());
93 }
94 }
95}
96
97const std::vector<std::shared_ptr<CalypsoCardAdapter::PatchRev12>>
98CalypsoCardAdapter::initPatchRev12()
99{
100 std::shared_ptr<PatchRev12> p12 = nullptr;
101 std::vector<std::shared_ptr<PatchRev12>> v12;
102
103 /* Patches for revision 1 & 2 */
104
105 /* 03 08 03 04 00 02 00: targets ASK Tango having this startup info value */
106 p12 = std::shared_ptr<PatchRev12>(
107 new PatchRev12("03080304000200", "FFFFFFFFFFFFFF"));
108 p12->setLegacyCase1();
109 v12.push_back(p12);
110
111 return v12;
112}
113
114const std::vector<std::shared_ptr<CalypsoCardAdapter::PatchRev3>>
115CalypsoCardAdapter::initPatchRev3()
116{
117 std::shared_ptr<PatchRev3> p3 = nullptr;
118 std::vector<std::shared_ptr<PatchRev3>> v3;
119
120 /* Patches for revision 3 */
121
122 /* XX 3C XX XX XX 10 XX */
123 p3 = std::shared_ptr<PatchRev3>(
124 new PatchRev3("003C0000001000", "00FF000000FF00"));
125 p3->setPayloadCapacity(235);
126 v3.push_back(p3);
127
128 return v3;
129}
130
131void
132CalypsoCardAdapter::initializeWithPowerOnData(const std::string& powerOnData)
133{
134 mProductType = ProductType::PRIME_REVISION_1;
135 mCalypsoCardClass = CalypsoCardClass::LEGACY;
136
137 mPowerOnData = powerOnData;
138
139 /*
140 * FCI is not provided: we consider it is Calypso card rev 1, it's serial
141 * number is provided in the ATR.
142 */
143 const std::vector<uint8_t> atr = HexUtil::toByteArray(powerOnData);
144
145 /*
146 * Basic check: we expect to be here following a selection based on the ATR.
147 */
148 if (atr.size() != CARD_REV1_ATR_LENGTH) {
149 throw IllegalArgumentException(
150 std::string("ATR is not the correct length. ")
151 + "Expected: " + std::to_string(CARD_REV1_ATR_LENGTH) + ", "
152 + "got: " + std::to_string(atr.size()));
153 }
154
155 mDfName.clear();
156 mCalypsoSerialNumber = std::vector<uint8_t>(8);
157
158 /*
159 * Old cards have their modification counter expressed in number of commands
160 * the array is initialized with 0 (cf. default value for primitive types).
161 */
162 System::arraycopy(atr, 12, mCalypsoSerialNumber, 4, 4);
163 mModificationsCounterMax
164 = REV1_CARD_DEFAULT_WRITE_OPERATIONS_NUMBER_SUPPORTED_PER_SESSION;
165
166 mStartupInfo = std::vector<uint8_t>(7);
167
168 /* Create buffer size indicator */
169 mStartupInfo[0] = static_cast<uint8_t>(mModificationsCounterMax);
170
171 /* Create the startup info with the 6 bytes of the ATR from position 6 */
172 System::arraycopy(atr, 6, mStartupInfo, 1, 6);
173
174 mIsRatificationOnDeselectSupported = true;
175}
176
177void
178CalypsoCardAdapter::initializeWithFci(
179 const std::shared_ptr<ApduResponseApi> selectApplicationResponse)
180{
181 mSelectApplicationResponse = selectApplicationResponse;
182
183 if (selectApplicationResponse->getDataOut().size() == 0) {
184 /* No FCI provided. May be filled later with a Get Data response */
185 return;
186 }
187
188 /*
189 * Parse card FCI - to retrieve DF Name (AID), Serial Number, &amp;
190 * StartupInfo CL-SEL-TLVSTRUC.1
191 */
192 auto cmdCardGetDataFci(
193 std::make_shared<CommandGetDataFci>(
194 std::make_shared<DtoAdapters::TransactionContextDto>(),
195 std::make_shared<DtoAdapters::CommandContextDto>(false, false)));
196 cmdCardGetDataFci->parseResponseForSelection(
197 selectApplicationResponse,
198 std::dynamic_pointer_cast<CalypsoCardAdapter>(shared_from_this()));
199
200 if (!cmdCardGetDataFci->isValidCalypsoFCI()) {
201 throw IllegalArgumentException("FCI has a bad format");
202 }
203}
204
205void
206CalypsoCardAdapter::initializeWithFci(
207 const std::shared_ptr<CommandGetDataFci>& cmdCardGetDataFci)
208{
209 mIsDfInvalidated = cmdCardGetDataFci->isDfInvalidated();
210
211 /* CL-SEL-DATA.1 */
212 mDfName = cmdCardGetDataFci->getDfName();
213 mCalypsoSerialNumber = cmdCardGetDataFci->getApplicationSerialNumber();
214
215 /* CL-SI-OTHER.1 */
216 mStartupInfo = cmdCardGetDataFci->getDiscretionaryData();
217
218 /*
219 * CL-SI-ATRFU.1
220 * CL-SI-ATPRIME.1
221 * CL-SI-ATB6B5.1
222 * CL-SI-ATLIGHT.1
223 * CL-SI-ATBASIC.1
224 */
225 mApplicationType = mStartupInfo[SI_APPLICATION_TYPE];
226 mProductType = computeProductType(mApplicationType & 0xFF);
227
228 /* CL-SI-ASRFU.1 */
229 mApplicationSubType = mStartupInfo[SI_APPLICATION_SUBTYPE];
230 if (mApplicationSubType == 0x00 || mApplicationSubType == 0xFF) {
231 throw IllegalArgumentException(
232 std::string("Unexpected application subtype: ")
233 + HexUtil::toHex(mApplicationSubType));
234 }
235
236 mSessionModification = mStartupInfo[SI_BUFFER_SIZE_INDICATOR];
237
238 if (mProductType == ProductType::PRIME_REVISION_2) {
239 mCalypsoCardClass = CalypsoCardClass::LEGACY;
240
241 /* Old cards have their modification counter expressed in number of
242 * commands */
243 mIsModificationCounterInBytes = false;
244 mModificationsCounterMax
245 = REV2_CARD_DEFAULT_WRITE_OPERATIONS_NUMBER_SUPPORTED_PER_SESSION;
246
247 } else if (mProductType == ProductType::BASIC) {
248 /* CL-SI-SMBASIC.1 */
249 if (mSessionModification < 0x04 || mSessionModification > 0x37) {
250 throw IllegalArgumentException(
251 std::string("Wrong session modification value for a Basic type")
252 + " (should be between 04h and 37h): "
253 + HexUtil::toHex(mSessionModification));
254 }
255
256 mCalypsoCardClass = CalypsoCardClass::ISO;
257 mIsModificationCounterInBytes = false;
258 mModificationsCounterMax = 4; /* 3 generic + 1 counter modification */
259 } else {
260 mCalypsoCardClass = CalypsoCardClass::ISO;
261
262 /*
263 * Session buffer size
264 * CL-SI-SM.1
265 */
266 if (mSessionModification < 0x06 || mSessionModification > 0x37) {
267 throw IllegalArgumentException(
268 "Session modifications byte should be in range [06h..47h]. "
269 "Actual: "
270 + HexUtil::toHex(mSessionModification));
271 }
272
273 mModificationsCounterMax
274 = BUFFER_SIZE_INDICATOR_TO_BUFFER_SIZE[mSessionModification];
275 }
276
277 /* CL-SI-ATOPT.1 */
278 if (mProductType == ProductType::PRIME_REVISION_3) {
279 mIsExtendedModeSupported
280 = (mApplicationType & APP_TYPE_CALYPSO_REV_32_MODE) != 0;
281 mIsRatificationOnDeselectSupported
282 = (mApplicationType & APP_TYPE_RATIFICATION_COMMAND_REQUIRED) == 0;
283 mIsPkiModeSupported
284 = (mApplicationType & APP_TYPE_WITH_PUBLIC_AUTHENTICATION) != 0;
285 }
286
287 if (mProductType == ProductType::PRIME_REVISION_3
288 || mProductType == ProductType::PRIME_REVISION_2) {
289 mIsSvFeatureAvailable
290 = (mApplicationType & APP_TYPE_WITH_CALYPSO_SV) != 0;
291 mIsPinFeatureAvailable
292 = (mApplicationType & APP_TYPE_WITH_CALYPSO_PIN) != 0;
293 }
294
295 mIsHce = (mCalypsoSerialNumber[3] & 0x80) == 0x80;
296
297 if (mProductType != ProductType::PRIME_REVISION_2
298 && mProductType != ProductType::PRIME_REVISION_1) {
299 mIsCounterValuePostponed = std::make_shared<bool>(false);
300 }
301
302 applyPatchIfNeeded();
303}
304
305CalypsoCard::ProductType
306CalypsoCardAdapter::computeProductType(const int applicationType) const
307{
308 if (applicationType == 0) {
309 throw IllegalArgumentException("Invalid application type 00h");
310 } else if (applicationType == 0xFF) {
311 return ProductType::UNKNOWN;
312 } else if (applicationType <= 0x1F) {
313 return ProductType::PRIME_REVISION_2;
314 } else if (applicationType >= 0x90 && applicationType <= 0x97) {
315 return ProductType::LIGHT;
316 } else if (applicationType >= 0x98 && applicationType <= 0x9F) {
317 return ProductType::BASIC;
318 }
319
320 return ProductType::PRIME_REVISION_3;
321}
322
323const CalypsoCard::ProductType&
324CalypsoCardAdapter::getProductType() const
325{
326 return mProductType;
327}
328
329bool
330CalypsoCardAdapter::isHce() const
331{
332 return mIsHce;
333}
334
335const std::vector<uint8_t>&
336CalypsoCardAdapter::getDfName() const
337{
338 return mDfName;
339}
340
341const std::vector<uint8_t>&
342CalypsoCardAdapter::getCalypsoSerialNumberFull() const
343{
344 return mCalypsoSerialNumber;
345}
346
347const std::vector<uint8_t>
348CalypsoCardAdapter::getApplicationSerialNumber() const
349{
350 std::vector<uint8_t> applicationSerialNumber = mCalypsoSerialNumber;
351 applicationSerialNumber[0] = 0;
352 applicationSerialNumber[1] = 0;
353
354 return applicationSerialNumber;
355}
356
357const std::vector<uint8_t>&
358CalypsoCardAdapter::getStartupInfoRawData() const
359{
360 return mStartupInfo;
361}
362
363int
364CalypsoCardAdapter::getPayloadCapacity() const
365{
366 return mPayloadCapacity;
367}
368
369bool
370CalypsoCardAdapter::isModificationsCounterInBytes() const
371{
372 return mIsModificationCounterInBytes;
373}
374
375int
376CalypsoCardAdapter::getModificationsCounter() const
377{
378 return mModificationsCounterMax;
379}
380
381uint8_t
382CalypsoCardAdapter::getPlatform() const
383{
384 return mStartupInfo[SI_PLATFORM];
385}
386
387uint8_t
388CalypsoCardAdapter::getApplicationType() const
389{
390 return mApplicationType;
391}
392
393bool
394CalypsoCardAdapter::isExtendedModeSupported() const
395{
396 return mIsExtendedModeSupported;
397}
398
399bool
400CalypsoCardAdapter::isRatificationOnDeselectSupported() const
401{
402 return mIsRatificationOnDeselectSupported;
403}
404
405bool
406CalypsoCardAdapter::isSvFeatureAvailable() const
407{
408 return mIsSvFeatureAvailable;
409}
410
411bool
412CalypsoCardAdapter::isPinFeatureAvailable() const
413{
414 return mIsPinFeatureAvailable;
415}
416
417bool
418CalypsoCardAdapter::isPkiModeSupported() const
419{
420 return mIsPkiModeSupported;
421}
422
423std::uint8_t
424CalypsoCardAdapter::getApplicationSubtype() const
425{
426 return mApplicationSubType;
427}
428
429std::uint8_t
430CalypsoCardAdapter::getSoftwareIssuer() const
431{
432 return mStartupInfo[SI_SOFTWARE_ISSUER];
433}
434
435std::uint8_t
436CalypsoCardAdapter::getSoftwareVersion() const
437{
438 return mStartupInfo[SI_SOFTWARE_VERSION];
439}
440
441std::uint8_t
442CalypsoCardAdapter::getSoftwareRevision() const
443{
444 return mStartupInfo[SI_SOFTWARE_REVISION];
445}
446
447std::uint8_t
448CalypsoCardAdapter::getSessionModification() const
449{
450 return mSessionModification;
451}
452
453const std::vector<uint8_t>
454CalypsoCardAdapter::getTraceabilityInformation() const
455{
456 /*
457 * Java code:
458 * return traceabilityInformation != null ?
459 * traceabilityInformation : new byte[0];
460 */
461 return mTraceabilityInformation;
462}
463
464const std::vector<std::uint8_t>&
465CalypsoCardAdapter::getCardPublicKey() const
466{
467 return mCardPublicKey;
468}
469
470const std::vector<std::uint8_t>&
471CalypsoCardAdapter::getCardCertificate() const
472{
473 return mCardCertificate;
474}
475
476const std::vector<std::uint8_t>&
477CalypsoCardAdapter::getCaCertificate() const
478{
479 return mCaCertificate;
480}
481
482bool
483CalypsoCardAdapter::isDfInvalidated() const
484{
485 return mIsDfInvalidated;
486}
487
488bool
489CalypsoCardAdapter::isDfRatified() const
490{
491 if (mIsDfRatified != nullptr) {
492 return *mIsDfRatified.get();
493 }
494
495 throw IllegalStateException(
496 "Unable to determine the ratification status. No session was opened");
497}
498
499int
500CalypsoCardAdapter::getTransactionCounter() const
501{
502 if (mTransactionCounter == nullptr) {
503 throw IllegalStateException(
504 "Unable to determine the transaction counter. No session was "
505 "opened");
506 }
507
508 return *mTransactionCounter.get();
509}
510
511void
512CalypsoCardAdapter::setTransactionCounter(const int transactionCounter)
513{
514 mTransactionCounter = std::make_shared<int>(transactionCounter);
515}
516
517void
518CalypsoCardAdapter::setSvData(
519 std::uint8_t svKvc,
520 const std::vector<uint8_t>& svGetHeader,
521 const std::vector<uint8_t>& svGetData,
522 int svBalance,
523 int svLastTNum)
524{
525 mSvKvc = svKvc;
526 mSvGetHeader = svGetHeader;
527 mSvGetData = svGetData;
528 mSvBalance = std::make_shared<int>(svBalance);
529 mSvLastTNum = svLastTNum;
530}
531
532void
533CalypsoCardAdapter::updateSvData(int svBalance, int svLastTNum)
534{
535 *mSvBalance = svBalance;
536 mSvLastTNum = svLastTNum;
537}
538
539int
540CalypsoCardAdapter::getSvBalance() const
541{
542 if (mSvBalance == nullptr) {
543 throw IllegalStateException("No SV Get command has been executed");
544 }
545
546 return *mSvBalance.get();
547}
548
549int
550CalypsoCardAdapter::getSvLastTNum() const
551{
552 if (mSvBalance == nullptr) {
553 new IllegalStateException("No SV Get command has been executed");
554 }
555
556 return mSvLastTNum;
557}
558
559const std::shared_ptr<SvLoadLogRecord>
560CalypsoCardAdapter::getSvLoadLogRecord()
561{
562 /* Try to get it from the file data */
563 const std::shared_ptr<ElementaryFile> ef
564 = getFileBySfi(CalypsoCardConstant::SV_RELOAD_LOG_FILE_SFI);
565 if (ef != nullptr) {
566 const std::vector<uint8_t> logRecord = ef->getData()->getContent();
567 return std::make_shared<DtoAdapters::SvLoadLogRecordAdapter>(
568 logRecord, 0);
569 }
570
571 return nullptr;
572}
573
574const std::shared_ptr<SvDebitLogRecord>
575CalypsoCardAdapter::getSvDebitLogLastRecord()
576{
577 /* Try to get it from the file data */
578 const std::vector<std::shared_ptr<SvDebitLogRecord>> svDebitLogRecords
579 = getSvDebitLogAllRecords();
580 if (!svDebitLogRecords.empty()) {
581 return svDebitLogRecords[0];
582 }
583
584 return nullptr;
585}
586
587const std::vector<std::shared_ptr<SvDebitLogRecord>>
588CalypsoCardAdapter::getSvDebitLogAllRecords() const
589{
590 std::vector<std::shared_ptr<SvDebitLogRecord>> svDebitLogRecords;
591
592 /* Get the logs from the file data */
593 const std::shared_ptr<ElementaryFile> ef
594 = getFileBySfi(CalypsoCardConstant::SV_DEBIT_LOG_FILE_SFI);
595 if (ef == nullptr) {
596 return svDebitLogRecords;
597 }
598
599 const std::map<const uint8_t, std::vector<uint8_t>>& logRecords
600 = ef->getData()->getAllRecordsContent();
601 for (const auto& entry : logRecords) {
602 svDebitLogRecords.push_back(
603 std::make_shared<DtoAdapters::SvDebitLogRecordAdapter>(
604 entry.second, 0));
605 }
606
607 return svDebitLogRecords;
608}
609
610void
611CalypsoCardAdapter::setDfRatified(const bool dfRatified)
612{
613 mIsDfRatified = std::make_shared<bool>(dfRatified);
614}
615
616CalypsoCardClass
617CalypsoCardAdapter::getCardClass() const
618{
619 return mCalypsoCardClass;
620}
621
622const std::shared_ptr<DirectoryHeader>
623CalypsoCardAdapter::getDirectoryHeader() const
624{
625 return mDirectoryHeader;
626}
627
628CalypsoCard&
629CalypsoCardAdapter::setDirectoryHeader(
630 std::unique_ptr<DirectoryHeader> directoryHeader)
631{
632 mDirectoryHeader = std::move(directoryHeader);
633 mIsDfInvalidated = (mDirectoryHeader->getDfStatus() & 0x01) != 0;
634
635 return *this;
636}
637
638const std::shared_ptr<ElementaryFile>
639CalypsoCardAdapter::getFileBySfi(const uint8_t sfi) const
640{
641 if (sfi == 0) {
642 return nullptr;
643 }
644
645 for (const auto& ef : mFiles) {
646 if (ef->getSfi() == sfi) {
647 return ef;
648 }
649 }
650
651 mLogger->warn("EF not found [sfi=%]\n", HexUtil::toHex(sfi));
652
653 return nullptr;
654}
655
656const std::shared_ptr<ElementaryFile>
657CalypsoCardAdapter::getFileByLid(const uint16_t lid) const
658{
659 for (const auto& ef : mFiles) {
660 if (ef->getHeader() != nullptr && ef->getHeader()->getLid() == lid) {
661 return ef;
662 }
663 }
664
665 mLogger->warn("EF not found [lid=%]\n", HexUtil::toHex(lid));
666
667 return nullptr;
668}
669
670const std::vector<std::shared_ptr<ElementaryFile>>&
671CalypsoCardAdapter::getFiles() const
672{
673 return mFiles;
674}
675
676const std::shared_ptr<ElementaryFileAdapter>
677CalypsoCardAdapter::getOrCreateFile(
678 const std::uint8_t sfi, const std::uint16_t lid)
679{
680 if (sfi == 0 && lid == 0 && mCurrentEf != nullptr) {
681 return mCurrentEf;
682 }
683
684 if (sfi != 0) {
685 /* Search by SFI */
686 for (const auto& ef : mFiles) {
687 if (ef->getSfi() == sfi) {
688 mCurrentEf
689 = std::dynamic_pointer_cast<ElementaryFileAdapter>(ef);
690 return mCurrentEf;
691 }
692 }
693
694 } else if (lid != 0) {
695 /* Search by LID */
696 for (const auto& ef : mFiles) {
697 if (ef->getHeader() != nullptr
698 && ef->getHeader()->getLid() == lid) {
699 mCurrentEf
700 = std::dynamic_pointer_cast<ElementaryFileAdapter>(ef);
701 return mCurrentEf;
702 }
703 }
704 }
705
706 /* Create a new EF with the provided SFI */
707 mCurrentEf = std::make_shared<ElementaryFileAdapter>(sfi);
708 mFiles.push_back(mCurrentEf);
709
710 return mCurrentEf;
711}
712
713bool
714CalypsoCardAdapter::isPinBlocked() const
715{
716 return getPinAttemptRemaining() == 0;
717}
718
719int
720CalypsoCardAdapter::getPinAttemptRemaining() const
721{
722 if (mPinAttemptCounter == nullptr) {
723 throw IllegalStateException("PIN status has not been checked.");
724 }
725
726 return *mPinAttemptCounter.get();
727}
728
729void
730CalypsoCardAdapter::setPinAttemptRemaining(int pinAttemptCounter)
731{
732 mPinAttemptCounter = std::make_shared<int>(pinAttemptCounter);
733}
734
735void
736CalypsoCardAdapter::setFileHeader(
737 std::uint8_t sfi, std::shared_ptr<FileHeaderAdapter> header)
738{
739 std::shared_ptr<ElementaryFileAdapter> ef
740 = getOrCreateFile(sfi, header->getLid());
741 if (ef->getHeader() == nullptr) {
742 ef->setHeader(header);
743
744 } else {
745 std::dynamic_pointer_cast<FileHeaderAdapter>(ef->getHeader())
746 ->updateMissingInfoFrom(*header.get());
747 }
748}
749
750void
751CalypsoCardAdapter::setContent(
752 std::uint8_t sfi,
753 std::uint8_t numRecord,
754 const std::vector<uint8_t>& content)
755{
756 std::shared_ptr<ElementaryFileAdapter> ef = getOrCreateFile(sfi, 0);
757 std::dynamic_pointer_cast<FileDataAdapter>(ef->getData())
758 ->setContent(numRecord, content);
759}
760
761void
762CalypsoCardAdapter::setCounter(
763 std::uint8_t sfi,
764 std::uint8_t numCounter,
765 const std::vector<uint8_t>& content)
766{
767 std::shared_ptr<ElementaryFileAdapter> ef = getOrCreateFile(sfi, 0);
768 std::dynamic_pointer_cast<FileDataAdapter>(ef->getData())
769 ->setCounter(numCounter, content);
770}
771
772void
773CalypsoCardAdapter::setContent(
774 std::uint8_t sfi,
775 std::uint8_t numRecord,
776 const std::vector<uint8_t>& content,
777 const int offset)
778{
779 std::shared_ptr<ElementaryFileAdapter> ef = getOrCreateFile(sfi, 0);
780 std::dynamic_pointer_cast<FileDataAdapter>(ef->getData())
781 ->setContent(numRecord, content, offset);
782}
783
784void
785CalypsoCardAdapter::fillContent(
786 std::uint8_t sfi,
787 std::uint8_t numRecord,
788 const std::vector<uint8_t>& content,
789 int offset)
790{
791 std::shared_ptr<ElementaryFileAdapter> ef = getOrCreateFile(sfi, 0);
792 std::dynamic_pointer_cast<FileDataAdapter>(ef->getData())
793 ->fillContent(numRecord, content, offset);
794}
795
796void
797CalypsoCardAdapter::addCyclicContent(
798 std::uint8_t sfi, const std::vector<std::uint8_t>& content)
799{
800 std::shared_ptr<ElementaryFileAdapter> ef = getOrCreateFile(sfi, 0);
801 std::dynamic_pointer_cast<FileDataAdapter>(ef->getData())
802 ->addCyclicContent(content);
803}
804
805void
806CalypsoCardAdapter::backupFiles()
807{
808 copyFiles(mFiles, mFilesBackup);
809 mSvBalanceBackup = mSvBalance;
810 mSvLastTNumBackup = mSvLastTNum;
811}
812
813void
814CalypsoCardAdapter::restoreFiles()
815{
816 copyFiles(mFilesBackup, mFiles);
817 mSvBalance = mSvBalanceBackup;
818 mSvLastTNum = mSvLastTNumBackup;
819}
820
821void
822CalypsoCardAdapter::copyFiles(
823 const std::vector<std::shared_ptr<ElementaryFile>>& src,
824 std::vector<std::shared_ptr<ElementaryFile>>& dest)
825{
826 dest.clear();
827 for (const auto& file : src) {
828 dest.push_back(std::make_shared<ElementaryFileAdapter>(file));
829 }
830}
831
832const std::string&
833CalypsoCardAdapter::getPowerOnData() const
834{
835 return mPowerOnData;
836}
837
838std::vector<std::uint8_t>
839CalypsoCardAdapter::getSelectApplicationResponse() const
840{
841 if (mSelectApplicationResponse == nullptr) {
842 return {};
843 }
844
845 return mSelectApplicationResponse->getApdu();
846}
847
848void
849CalypsoCardAdapter::setDfInvalidated(bool isInvalidated)
850{
851 mIsDfInvalidated = isInvalidated;
852}
853
854void
855CalypsoCardAdapter::setChallenge(const std::vector<uint8_t>& challenge)
856{
857 mChallenge = challenge;
858}
859
860void
861CalypsoCardAdapter::setTraceabilityInformation(
862 const std::vector<uint8_t>& traceabilityInformation)
863{
864 mTraceabilityInformation = traceabilityInformation;
865}
866
867void
868CalypsoCardAdapter::setCardPublicKey(
869 const std::vector<std::uint8_t>& cardPublicKey)
870{
871 mCardPublicKey = cardPublicKey;
872}
873
874void
875CalypsoCardAdapter::setCardPublicKeySpi(
876 std::shared_ptr<CardPublicKeySpi> cardPublicKeySpi)
877{
878 mCardPublicKeySpi = cardPublicKeySpi;
879}
880
881std::shared_ptr<CardPublicKeySpi>
882CalypsoCardAdapter::getCardPublicKeySpi() const
883{
884 return mCardPublicKeySpi;
885}
886
887void
888CalypsoCardAdapter::addCardCertificateBytes(
889 const std::vector<std::uint8_t>& cardCertificateBytes, bool isFirstPart)
890{
891 if (isFirstPart) {
892 mCardCertificate.clear();
893 mCardCertificate.reserve(CalypsoCardConstant::CARD_CERTIFICATE_SIZE);
894 }
895
896 const size_t remaining
897 = CalypsoCardConstant::CARD_CERTIFICATE_SIZE - mCardCertificate.size();
898 if (cardCertificateBytes.size() > remaining) {
899 throw IllegalArgumentException(
900 std::string("Card certificate is not the correct length. ")
901 + "Expected: "
902 + std::to_string(CalypsoCardConstant::CARD_CERTIFICATE_SIZE) + ", "
903 + "Actual: " + std::to_string(cardCertificateBytes.size()));
904 }
905
906 mCardCertificate.insert(
907 mCardCertificate.end(),
908 cardCertificateBytes.begin(),
909 cardCertificateBytes.end());
910}
911
912void
913CalypsoCardAdapter::addCaCertificateBytes(
914 const std::vector<std::uint8_t>& caCertificateBytes, bool isFirstPart)
915{
916 if (isFirstPart) {
917 mCaCertificate.reserve(CalypsoCardConstant::CA_CERTIFICATE_SIZE);
918 }
919
920 const size_t remaining
921 = CalypsoCardConstant::CA_CERTIFICATE_SIZE - mCaCertificate.size();
922 if (caCertificateBytes.size() > remaining) {
923 throw IllegalArgumentException(
924 "CA certificate is not the correct length. Expected: "
925 + std::to_string(CalypsoCardConstant::CA_CERTIFICATE_SIZE) + ", "
926 + "Actual: " + std::to_string(caCertificateBytes.size()));
927 }
928
929 mCaCertificate.insert(
930 mCaCertificate.end(),
931 caCertificateBytes.begin(),
932 caCertificateBytes.end());
933}
934
935void
936CalypsoCardAdapter::setSvOperationSignature(
937 const std::vector<uint8_t>& svOperationSignature)
938{
939 mSvOperationSignature = svOperationSignature;
940}
941
942const std::vector<uint8_t>&
943CalypsoCardAdapter::getChallenge() const
944{
945 return mChallenge;
946}
947
948std::uint8_t
949CalypsoCardAdapter::getSvKvc() const
950{
951 return mSvKvc;
952}
953
954const std::vector<uint8_t>&
955CalypsoCardAdapter::getSvGetHeader() const
956{
957 if (mSvGetHeader.empty()) {
958 throw IllegalStateException("SV Get Header in not available");
959 }
960
961 return mSvGetHeader;
962}
963
964const std::vector<uint8_t>&
965CalypsoCardAdapter::getSvGetData() const
966{
967 if (mSvGetData.empty()) {
968 throw IllegalStateException("SV Get Data is not available");
969 }
970
971 return mSvGetData;
972}
973
974const std::vector<uint8_t>&
975CalypsoCardAdapter::getSvOperationSignature() const
976{
977 return mSvOperationSignature;
978}
979
980void
981CalypsoCardAdapter::setIsCounterValuePostponed(bool isCounterValuePostponed)
982{
983 mIsCounterValuePostponed = std::make_shared<bool>(isCounterValuePostponed);
984}
985
986void
987CalypsoCardAdapter::applyPatchIfNeeded()
988{
989 std::uint64_t startupInfoLong = ByteArrayUtil::extractLong(
990 mStartupInfo, 0, static_cast<int>(mStartupInfo.size()), false);
991
992 if (mProductType == ProductType::PRIME_REVISION_3) {
993 std::vector<std::shared_ptr<CalypsoCardAdapter::Patch>> v;
994 for (const auto& p : mPatchesRev3) {
995 v.push_back(
996 std::dynamic_pointer_cast<CalypsoCardAdapter::Patch>(p));
997 }
998
999 applyPatchIfNeededForRevision(v, startupInfoLong);
1000
1001 } else if (
1002 mProductType == ProductType::PRIME_REVISION_2
1003 || mProductType == ProductType::PRIME_REVISION_1) {
1004 mPayloadCapacity = 128;
1005
1006 std::vector<std::shared_ptr<CalypsoCardAdapter::Patch>> v;
1007 for (const auto& p : mPatchesRev12) {
1008 v.push_back(
1009 std::dynamic_pointer_cast<CalypsoCardAdapter::Patch>(p));
1010 }
1011
1012 applyPatchIfNeededForRevision(v, startupInfoLong);
1013 }
1014}
1015
1016void
1017CalypsoCardAdapter::applyPatchIfNeededForRevision(
1018 const std::vector<std::shared_ptr<CalypsoCardAdapter::Patch>>& patches,
1019 const uint64_t startupInfoLong)
1020{
1021 for (const auto& patch : patches) {
1022 if (patch->isApplicableTo(startupInfoLong)) {
1023 patch->apply(shared_from_this());
1024 return;
1025 }
1026 }
1027}
1028
1029std::shared_ptr<bool>
1030CalypsoCardAdapter::getIsCounterValuePostponed() const
1031{
1032 return mIsCounterValuePostponed;
1033}
1034
1035bool
1036CalypsoCardAdapter::isLegacyCase1() const
1037{
1038 return mIsLegacyCase1;
1039}
1040
1041void
1042CalypsoCardAdapter::disableExtendedMode()
1043{
1044 mIsExtendedModeSupported = false;
1045}
1046
1047WriteAccessLevel
1048CalypsoCardAdapter::getPreOpenWriteAccessLevel() const
1049{
1050 return mPreOpenWriteAccessLevel;
1051}
1052
1053CalypsoCardAdapter&
1054CalypsoCardAdapter::setPreOpenWriteAccessLevel(
1055 WriteAccessLevel preOpenWriteAccessLevel)
1056{
1057 mPreOpenWriteAccessLevel = preOpenWriteAccessLevel;
1058
1059 return *this;
1060}
1061
1062const std::vector<std::uint8_t>&
1063CalypsoCardAdapter::getPreOpenDataOut() const
1064{
1065 return mPreOpenDataOut;
1066}
1067
1068CalypsoCardAdapter&
1069CalypsoCardAdapter::setPreOpenDataOut(
1070 const std::vector<std::uint8_t>& preOpenDataOut)
1071{
1072 mPreOpenDataOut = preOpenDataOut;
1073
1074 return *this;
1075}
1076
1077CalypsoCardAdapter::Patch::Patch(
1078 const std::string& startupInfo, const std::string& mask)
1079: mStartupInfo(HexUtil::toLong(startupInfo))
1080, mMask(HexUtil::toLong(mask))
1081{
1082}
1083
1084bool
1085CalypsoCardAdapter::Patch::isApplicableTo(const uint64_t startupInfo) const
1086{
1087 return mStartupInfo == (startupInfo & mMask);
1088}
1089
1090CalypsoCardAdapter::PatchRev3::PatchRev3(
1091 const std::string& startupInfo, const std::string& mask)
1092: CalypsoCardAdapter::Patch(startupInfo, mask)
1093{
1094}
1095
1096CalypsoCardAdapter::PatchRev3&
1097CalypsoCardAdapter::PatchRev3::setPayloadCapacity(const int payloadCapacity)
1098{
1099 mPayloadCapacity = std::make_shared<int>(payloadCapacity);
1100
1101 return *this;
1102}
1103
1104void
1105CalypsoCardAdapter::PatchRev3::apply(
1106 std::shared_ptr<CalypsoCardAdapter> calypsoCard)
1107{
1108 if (mPayloadCapacity != nullptr) {
1109 calypsoCard->mPayloadCapacity = *mPayloadCapacity;
1110 }
1111}
1112
1113CalypsoCardAdapter::PatchRev12::PatchRev12(
1114 const std::string& startupInfo, const std::string& mask)
1115: CalypsoCardAdapter::Patch(startupInfo, mask)
1116{
1117}
1118
1119CalypsoCardAdapter::PatchRev12&
1120CalypsoCardAdapter::PatchRev12::setLegacyCase1()
1121{
1122 mIsLegacyCase1 = std::make_shared<bool>(true);
1123
1124 return *this;
1125}
1126
1127void
1128CalypsoCardAdapter::PatchRev12::apply(
1129 std::shared_ptr<CalypsoCardAdapter> calypsoCard)
1130{
1131 if (mIsLegacyCase1 != nullptr) {
1132 calypsoCard->mIsLegacyCase1 = *mIsLegacyCase1;
1133 }
1134}
1135
1136std::ostream&
1137operator<<(std::ostream& os, const CalypsoCardAdapter& cca)
1138{
1139 os << "CALYPSO_CARD_ADAPTER: {"
1140 << "SELECT_APPLICATION_RESPONSE: " << cca.mSelectApplicationResponse
1141 << ", "
1142 << "POWER_ON_DATA: " << cca.mPowerOnData << ", "
1143 << "IS_EXTENDED_MODE_SUPPORTED: " << cca.mIsExtendedModeSupported << ", "
1144 << "IS_RATIFICATION_ON_DESELECT_SUPPORTED: "
1145 << cca.mIsRatificationOnDeselectSupported << ", "
1146 << "IS_SV_FEATURE_AVAILABLE: " << cca.mIsSvFeatureAvailable << ", "
1147 << "IS_PIN_FEATURE_AVAILABLE: " << cca.mIsPinFeatureAvailable << ", "
1148 << "IS_PKI_MODE_SUPPORTED:" << cca.mIsPkiModeSupported << ", "
1149 << "IS_DF_INVALIDATED:" << cca.mIsDfInvalidated << ", "
1150 << "CALYPSO_CARD_CLASS: " << cca.mCalypsoCardClass << ", "
1151 << "CALYPSO_SERIAL_NUMBER: " << cca.mCalypsoSerialNumber << ", "
1152 << "STARTUP_INFO:" << cca.mStartupInfo << ", "
1153 << "PRODUCT_TYPE: " << cca.mProductType << ", "
1154 << "DF_NAME: " << cca.mDfName << ", "
1155 << "MODIFICATIONS_COUNTER_MAX: " << cca.mModificationsCounterMax << ", "
1156 << "IS_MODIFICATION_COUNTER_IN_BYTES: "
1157 << cca.mIsModificationCounterInBytes << ", "
1158 << "DIRECTORY_HEADER: " << cca.mDirectoryHeader << ", "
1159 << "FILES: " << cca.mFiles << ", "
1160 << "FILES_BACKUP: " << cca.mFilesBackup << ", "
1161 << "ID_DF_RATIFIED: " << cca.mIsDfRatified << ", "
1162 << "PIN_ATTEMPT_COUNTER: " << cca.mPinAttemptCounter << ", "
1163 << "SV_BALANCE: " << cca.mSvBalance << ", "
1164 << "SV_LAST_T_NUM: " << cca.mSvLastTNum << ", "
1165 << "IS_HCE: " << cca.mIsHce << ", "
1166 << "TRACEABILITY_INFORMATION: " << cca.mTraceabilityInformation << ", "
1167 << "SV_KVC: " << cca.mSvKvc << ", "
1168 << "SV_GET_HEADER: " << cca.mSvGetHeader << ", "
1169 << "SV_GET_DATA: " << cca.mSvGetData << ", "
1170 << "SV_OPERATION_SIGNATURE: " << cca.mSvOperationSignature << ", "
1171 << "APPLICATION_SUB_TYPE: " << cca.mApplicationSubType << ", "
1172 << "APPLICATION_TYPE: " << cca.mApplicationType << ", "
1173 << "SESSION_MODIFICATION: " << cca.mSessionModification << "}";
1174
1175 return os;
1176}
1177
1178std::ostream&
1179operator<<(std::ostream& os, const std::shared_ptr<CalypsoCardAdapter> cca)
1180{
1181 if (cca == nullptr) {
1182 os << "CALYPSO_CARD_ADAPTER: null";
1183
1184 } else {
1185 os << *cca.get();
1186 }
1187
1188 return os;
1189}
1190
1191} /* namespace calypso */
1192} /* namespace card */
1193} /* namespace keyple */
std::ostream & operator<<(std::ostream &os, const std::shared_ptr< CalypsoCardAdapter > cca)