Keyple Card Calypso C++ Library - 3.2.2
Component of the Keyple C++ middleware
CommandGetDataFci.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/CommandGetDataFci.hpp"
15
16#include <map>
17#include <memory>
18#include <string>
19#include <vector>
20
21#include "keyple/card/calypso/CalypsoCardAdapter.hpp"
22#include "keyple/card/calypso/CalypsoCardClass.hpp"
23#include "keyple/card/calypso/CalypsoCardConstant.hpp"
24#include "keyple/card/calypso/CardCommandRef.hpp"
25#include "keyple/card/calypso/CardDataAccessException.hpp"
26#include "keyple/core/util/ApduUtil.hpp"
27#include "keyple/core/util/BerTlvUtil.hpp"
28#include "keyple/core/util/HexUtil.hpp"
29
30namespace keyple {
31namespace card {
32namespace calypso {
33
34using keyple::core::util::ApduUtil;
35using keyple::core::util::BerTlvUtil;
36using keyple::core::util::HexUtil;
37
38const int CommandGetDataFci::TAG_DF_NAME = 0x84;
39const int CommandGetDataFci::TAG_APPLICATION_SERIAL_NUMBER = 0xC7;
40const int CommandGetDataFci::TAG_DISCRETIONARY_DATA = 0x53;
41
42const std::map<int, const std::shared_ptr<Command::StatusProperties>>
43 CommandGetDataFci::STATUS_TABLE = [] {
44 std::map<int, const std::shared_ptr<Command::StatusProperties>> m(
45 Command::STATUS_TABLE);
46
47 m.insert(
48 {{0x6A88,
49 std::make_shared<StatusProperties>(
50 "Data object not found (optional mode not "
51 "available)",
52 typeid(CardDataAccessException))},
53 {0x6B00,
54 std::make_shared<StatusProperties>(
55 "P1 or P2 value not supported",
56 typeid(CardDataAccessException))},
57 {0x6283,
58 std::make_shared<StatusProperties>(
59 "Successful execution, FCI request and DF is "
60 "invalidated",
61 typeid(nullptr))}});
62 return m;
63 }();
64
65CommandGetDataFci::CommandGetDataFci(
66 const std::shared_ptr<DtoAdapters::TransactionContextDto>&
67 transactionContext,
68 const std::shared_ptr<DtoAdapters::CommandContextDto>& commandContext)
69: Command(CardCommandRef::GET_DATA, nullptr, transactionContext, commandContext)
70{
71 const std::uint8_t cardClass
72 = transactionContext->getCard() != nullptr
73 ? transactionContext->getCard()->getCardClass().getValue()
74 : CalypsoCardClass::ISO.getValue();
75
76 /* APDU Case 2 - always outside secure session */
77 setApduRequest(
78 std::make_shared<DtoAdapters::ApduRequestAdapter>(ApduUtil::build(
79 cardClass,
80 getCommandRef().getInstructionByte(),
81 CalypsoCardConstant::TAG_FCI_FOR_CURRENT_DF_MSB,
82 CalypsoCardConstant::TAG_FCI_FOR_CURRENT_DF_LSB,
83 0)));
84
85 addSubName("FCI_FOR_CURRENT_DF");
86}
87
88void
89CommandGetDataFci::finalizeRequest()
90{
91 /* NOP */
92}
93
94bool
95CommandGetDataFci::isCryptoServiceRequiredToFinalizeRequest() const
96{
97 return false;
98}
99
100bool
101CommandGetDataFci::synchronizeCryptoServiceBeforeCardProcessing()
102{
103 return true;
104}
105
106void
107CommandGetDataFci::parseResponse(std::shared_ptr<ApduResponseApi> apduResponse)
108{
109 Command::setApduResponseAndCheckStatus(apduResponse);
110
111 /*
112 * Check the command status to determine if the DF has been invalidated
113 * CL-INV-STATUS.1
114 */
115 if (getApduResponse()->getStatusWord() == 0x6283) {
116 mLogger->debug("DF invalidated\n");
117 mIsDfInvalidated = true;
118 }
119
120 /* Parse the raw data with the help of the TLV class */
121 try {
122 /* Init TLV object with the raw data and extract the FCI Template */
123 const std::vector<uint8_t> responseData
124 = getApduResponse()->getDataOut();
125
126 /*
127 * CL-SEL-TLVDATA.1
128 * CL-TLV-VAR.1
129 * CL-TLV-ORDER.1
130 */
131 const std::map<const int, const std::vector<uint8_t>> tags
132 = BerTlvUtil::parseSimple(responseData, true);
133
134 auto it = tags.find(TAG_DF_NAME);
135 if (it == tags.end()) {
136 mLogger->error("DF name tag (84h) not found\n");
137 return;
138 }
139
140 mDfName = it->second;
141
142 if (mDfName.size() < 5 || mDfName.size() > 16) {
143 mLogger->error(
144 std::string("DF name is not the correct length (should be in")
145 + " range [5..16]) [actual=%]\n",
146 mDfName.size());
147 return;
148 }
149
150 mLogger->debug("DF name = %\n", HexUtil::toHex(mDfName));
151
152 it = tags.find(TAG_APPLICATION_SERIAL_NUMBER);
153 if (it == tags.end()) {
154 mLogger->error("Serial number tag (C7h) not found\n");
155 return;
156 }
157
158 mApplicationSN = it->second;
159
160 /* CL-SEL-CSN.1 */
161 if (mApplicationSN.size() != 8) {
162 mLogger->error(
163 std::string("Application serial number is not the correct ")
164 + "length (expected 8) [actual=%]\n",
165 mApplicationSN.size());
166 return;
167 }
168
169 mLogger->debug(
170 "Application Serial Number = %\n", HexUtil::toHex(mApplicationSN));
171
172 it = tags.find(TAG_DISCRETIONARY_DATA);
173 if (it == tags.end()) {
174 mLogger->error("Discretionary data tag (53h) not found\n");
175 return;
176 }
177
178 mDiscretionaryData = it->second;
179
180 if (mDiscretionaryData.size() < 7) {
181 mLogger->error(
182 std::string("Startup info is not the correct length (should")
183 + " be >= 7) [actual=%]\n",
184 mDiscretionaryData.size());
185 return;
186 }
187
188 mLogger->debug(
189 "Discretionary Data = %\n", HexUtil::toHex(mDiscretionaryData));
190
191 /* All 3 main fields were retrieved */
192 mIsValidCalypsoFCI = true;
193
194 mLogger->debug(
195 "DF parsed [dfName=%, serialNumber=%, discretionaryData=%]\n",
196 HexUtil::toHex(mDfName),
197 HexUtil::toHex(mApplicationSN),
198 HexUtil::toHex(mDiscretionaryData));
199
200 } catch (const Exception& e) {
201 /* Silently ignore problems decoding TLV structure. Just log. */
202 mLogger->debug(
203 "failed to parse FCI BER-TLV data structure [reason=%]\n",
204 e.getMessage());
205 }
206
207 getTransactionContext()->getCard()->initializeWithFci(shared_from_this());
208}
209
210bool
211CommandGetDataFci::isValidCalypsoFCI() const
212{
213 return mIsValidCalypsoFCI;
214}
215
216const std::vector<uint8_t>&
217CommandGetDataFci::getDfName() const
218{
219 return mDfName;
220}
221
222const std::vector<uint8_t>&
223CommandGetDataFci::getApplicationSerialNumber() const
224{
225 return mApplicationSN;
226}
227
228const std::vector<uint8_t>&
229CommandGetDataFci::getDiscretionaryData() const
230{
231 return mDiscretionaryData;
232}
233
234bool
235CommandGetDataFci::isDfInvalidated() const
236{
237 return mIsDfInvalidated;
238}
239
240const std::map<int, const std::shared_ptr<Command::StatusProperties>>&
241CommandGetDataFci::getStatusTable() const
242{
243 return STATUS_TABLE;
244}
245
246} /* namespace calypso */
247} /* namespace card */
248} /* namespace keyple */