Keyple Card Calypso C++ Library - 3.2.2
Component of the Keyple C++ middleware
CommandSvGet.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/CommandSvGet.hpp"
15
16#include <map>
17#include <memory>
18#include <vector>
19
20#include "keyple/card/calypso/CalypsoCardAdapter.hpp"
21#include "keyple/card/calypso/CalypsoCardConstant.hpp"
22#include "keyple/card/calypso/CardAccessForbiddenException.hpp"
23#include "keyple/card/calypso/CardIllegalParameterException.hpp"
24#include "keyple/card/calypso/CardSecurityContextException.hpp"
25#include "keyple/core/util/ApduUtil.hpp"
26#include "keyple/core/util/ByteArrayUtil.hpp"
27#include "keyple/core/util/cpp/Arrays.hpp"
28#include "keyple/core/util/cpp/exception/IllegalStateException.hpp"
29
30namespace keyple {
31namespace card {
32namespace calypso {
33
34using keyple::core::util::ApduUtil;
35using keyple::core::util::ByteArrayUtil;
36using keyple::core::util::cpp::Arrays;
37using keyple::core::util::cpp::exception::IllegalStateException;
38
39const std::map<int, const std::shared_ptr<Command::StatusProperties>>
40 CommandSvGet::STATUS_TABLE = [] {
41 std::map<int, const std::shared_ptr<Command::StatusProperties>> m(
42 Command::STATUS_TABLE);
43
44 m.insert(
45 {{0x6982,
46 std::make_shared<StatusProperties>(
47 "Security conditions not fulfilled",
48 typeid(CardSecurityContextException))},
49 {0x6985,
50 std::make_shared<StatusProperties>(
51 "Preconditions not satisfied (a store value operation was "
52 "already done in the current session)",
53 typeid(CardAccessForbiddenException))},
54 {0x6A81,
55 std::make_shared<StatusProperties>(
56 "Incorrect P1 or P2", typeid(CardIllegalParameterException))},
57 {0x6A86,
58 std::make_shared<StatusProperties>(
59 "Le inconsistent with P2",
60 typeid(CardIllegalParameterException))},
61 {0x6D00,
62 std::make_shared<StatusProperties>(
63 "SV function not present",
64 typeid(CardIllegalParameterException))}});
65 return m;
66 }();
67
68CommandSvGet::CommandSvGet(
69 const std::shared_ptr<DtoAdapters::TransactionContextDto>&
70 transactionContext,
71 const std::shared_ptr<DtoAdapters::CommandContextDto>& commandContext,
72 SvOperation svOperation,
73 bool useExtendedMode)
74: Command(
75 CardCommandRef::SV_GET,
76 std::unique_ptr<int>(
77 new int(computeExpectedResponseLength(svOperation, useExtendedMode))),
78 transactionContext,
79 commandContext)
80{
81 const std::uint8_t cla
82 = transactionContext->getCard()->getCardClass()
83 == CalypsoCardClass::LEGACY
84 ? CalypsoCardClass::LEGACY_STORED_VALUE.getValue()
85 : CalypsoCardClass::ISO.getValue();
86
87 const std::uint8_t p1 = useExtendedMode ? 0x01 : 0x00;
88 const std::uint8_t p2 = svOperation == SvOperation::RELOAD ? 0x07 : 0x09;
89
90 /* APDU Case 2 */
91 const int* le = getExpectedResponseLength();
92 if (le == nullptr) {
93 setApduRequest(
94 std::make_shared<DtoAdapters::ApduRequestAdapter>(ApduUtil::build(
95 cla, getCommandRef().getInstructionByte(), p1, p2)));
96 } else {
97 setApduRequest(
98 std::make_shared<DtoAdapters::ApduRequestAdapter>(ApduUtil::build(
99 cla,
100 getCommandRef().getInstructionByte(),
101 p1,
102 p2,
103 static_cast<uint8_t>(*le))));
104 }
105
106 addSubName("Operation: " + std::to_string(static_cast<int>(svOperation)));
107
108 mHeader.resize(4);
109 mHeader[0] = getCommandRef().getInstructionByte();
110 mHeader[1] = p1;
111 mHeader[2] = p2;
112 mHeader[3] = static_cast<uint8_t>(le == nullptr ? 0 : *le);
113}
114
115void
116CommandSvGet::finalizeRequest()
117{
118 encryptRequestAndUpdateTerminalSessionMacIfNeeded();
119}
120
121bool
122CommandSvGet::isCryptoServiceRequiredToFinalizeRequest() const
123{
124 return getCommandContext()->isEncryptionActive();
125}
126
127bool
128CommandSvGet::synchronizeCryptoServiceBeforeCardProcessing()
129{
130 return false;
131}
132
133void
134CommandSvGet::parseResponse(std::shared_ptr<ApduResponseApi> apduResponse)
135{
136 decryptResponseAndUpdateTerminalSessionMacIfNeeded(apduResponse);
137 Command::setApduResponseAndCheckStatus(apduResponse);
138
139 const std::vector<std::uint8_t> cardResponse = apduResponse->getDataOut();
140 std::uint8_t currentKvc;
141 int transactionNumber;
142 int balance;
143 std::vector<std::uint8_t> loadLog;
144 std::vector<std::uint8_t> debitLog;
145
146 switch (cardResponse.size()) {
147 case 0x21: /* Compatibility mode, Reload */
148 case 0x1E: /* Compatibility mode, Debit or Undebit */
149 currentKvc = cardResponse[0];
150 transactionNumber
151 = ByteArrayUtil::extractInt(cardResponse, 1, 2, false);
152 balance = ByteArrayUtil::extractInt(cardResponse, 8, 3, true);
153
154 if (cardResponse.size() == 0x21) {
155 /* Reload */
156 loadLog
157 = Arrays::copyOfRange(cardResponse, 11, cardResponse.size());
158 debitLog = {};
159 } else {
160 /* Debit */
161 loadLog = {};
162 debitLog
163 = Arrays::copyOfRange(cardResponse, 11, cardResponse.size());
164 }
165 break;
166 case 0x3D: /* Revision 3.2 mode */
167 currentKvc = cardResponse[8];
168 transactionNumber
169 = ByteArrayUtil::extractInt(cardResponse, 9, 2, false);
170 balance = ByteArrayUtil::extractInt(cardResponse, 17, 3, true);
171 loadLog = Arrays::copyOfRange(cardResponse, 20, 42);
172 debitLog = Arrays::copyOfRange(cardResponse, 42, cardResponse.size());
173 break;
174 default:
175 throw IllegalStateException(
176 "SV Get response is not the correct length. Expected: 30/33/61, "
177 "Actual: "
178 + std::to_string(cardResponse.size()));
179 }
180
181 std::shared_ptr<CalypsoCardAdapter> calypsoCard
182 = getTransactionContext()->getCard();
183 calypsoCard->setSvData(
184 currentKvc,
185 mHeader,
186 apduResponse->getApdu(),
187 balance,
188 transactionNumber);
189
190 if (!loadLog.empty()) {
191 calypsoCard->addCyclicContent(
192 CalypsoCardConstant::SV_RELOAD_LOG_FILE_SFI, loadLog);
193 }
194
195 if (!debitLog.empty()) {
196 calypsoCard->addCyclicContent(
197 CalypsoCardConstant::SV_DEBIT_LOG_FILE_SFI, debitLog);
198 }
199
200 updateTerminalSessionIfNeeded();
201}
202
203const std::map<int, const std::shared_ptr<Command::StatusProperties>>&
204CommandSvGet::getStatusTable() const
205{
206 return STATUS_TABLE;
207}
208
209int
210CommandSvGet::computeExpectedResponseLength(
211 SvOperation svOperation, bool useExtendedMode)
212{
213 if (useExtendedMode) {
214 return 0x3D;
215
216 } else {
217 return svOperation == SvOperation::RELOAD ? 0x21 : 0x1E;
218 }
219}
220
221} /* namespace calypso */
222} /* namespace card */
223} /* namespace keyple */