Keyple Card Calypso C++ Library - 3.2.2
Component of the Keyple C++ middleware
CommandSearchRecordMultiple.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/CommandSearchRecordMultiple.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/CardAccessForbiddenException.hpp"
23#include "keyple/card/calypso/CardDataAccessException.hpp"
24#include "keyple/card/calypso/CardIllegalParameterException.hpp"
25#include "keyple/card/calypso/CardSecurityContextException.hpp"
26#include "keyple/card/calypso/CardSessionBufferOverflowException.hpp"
27#include "keyple/core/util/ApduUtil.hpp"
28#include "keyple/core/util/HexUtil.hpp"
29#include "keyple/core/util/cpp/Arrays.hpp"
30#include "keyple/core/util/cpp/System.hpp"
31
32namespace keyple {
33namespace card {
34namespace calypso {
35
36using keyple::core::util::ApduUtil;
37using keyple::core::util::HexUtil;
38using keyple::core::util::cpp::Arrays;
39using keyple::core::util::cpp::System;
40
41const std::map<int, const std::shared_ptr<Command::StatusProperties>>
42 CommandSearchRecordMultiple::STATUS_TABLE = [] {
43 std::map<int, const std::shared_ptr<Command::StatusProperties>> m(
44 Command::STATUS_TABLE);
45
46 m.insert(
47 {{0x6400,
48 std::make_shared<Command::StatusProperties>(
49 "Data Out overflow (outgoing data would be too long)",
50 typeid(CardSessionBufferOverflowException))},
51 {0x6700,
52 std::make_shared<Command::StatusProperties>(
53 "Lc value not supported (<4)",
54 typeid(CardIllegalParameterException))},
55 {0x6981,
56 std::make_shared<Command::StatusProperties>(
57 "Incorrect EF type: Binary EF",
58 typeid(CardDataAccessException))},
59 {0x6982,
60 std::make_shared<Command::StatusProperties>(
61 "Security conditions not fulfilled (PIN code not presented, "
62 "encryption required)",
63 typeid(CardSecurityContextException))},
64 {0x6985,
65 std::make_shared<Command::StatusProperties>(
66 "Access forbidden (Never access mode, Stored Value log file "
67 "and a Stored Value operation was done during the current "
68 "secure session)",
69 typeid(CardAccessForbiddenException))},
70 {0x6986,
71 std::make_shared<Command::StatusProperties>(
72 "Incorrect file type: the Current File is not an EF. "
73 "Supersedes 6981h",
74 typeid(CardDataAccessException))},
75 {0x6A80,
76 std::make_shared<Command::StatusProperties>(
77 "Incorrect command data (S. Length incompatible with Lc, S. "
78 "Length > RecSize, S. Offset + S. Length > RecSize, S. Mask "
79 "bigger than S. Data)",
80 typeid(CardIllegalParameterException))},
81 {0x6A82,
82 std::make_shared<Command::StatusProperties>(
83 "File not found", typeid(CardDataAccessException))},
84 {0x6A83,
85 std::make_shared<Command::StatusProperties>(
86 "Record not found (record index is 0, or above NumRec",
87 typeid(CardDataAccessException))},
88 {0x6B00,
89 std::make_shared<Command::StatusProperties>(
90 "P2 value not supported",
91 typeid(CardIllegalParameterException))}});
92
93 return m;
94 }();
95
96CommandSearchRecordMultiple::CommandSearchRecordMultiple(
97 const std::shared_ptr<DtoAdapters::TransactionContextDto>&
98 transactionContext,
99 const std::shared_ptr<DtoAdapters::CommandContextDto>& commandContext,
100 const std::shared_ptr<DtoAdapters::SearchCommandDataAdapter> data)
101: Command(
102 CardCommandRef::SEARCH_RECORD_MULTIPLE,
103 nullptr,
104 transactionContext,
105 commandContext)
106, mData(data)
107{
108 const int searchDataLength = static_cast<int>(data->getSearchData().size());
109 const uint8_t p2 = data->getSfi() * 8 + 7;
110
111 std::vector<uint8_t> dataIn(3 + (2 * searchDataLength));
112 if (data->isEnableRepeatedOffset()) {
113 dataIn[0] = 0x80;
114 }
115
116 if (data->isFetchFirstMatchingResult()) {
117 dataIn[0] |= 1;
118 }
119
120 dataIn[1] = static_cast<uint8_t>(data->getOffset());
121 dataIn[2] = static_cast<uint8_t>(searchDataLength);
122
123 System::arraycopy(data->getSearchData(), 0, dataIn, 3, searchDataLength);
124
125 if (data->getMask().empty()) {
126 /* CL-CMD-SEARCH.1 */
127 Arrays::fill(
128 dataIn,
129 dataIn.size() - searchDataLength,
130 dataIn.size(),
131 static_cast<uint8_t>(0xFF));
132
133 } else {
134 System::arraycopy(
135 data->getMask(),
136 0,
137 dataIn,
138 dataIn.size() - searchDataLength,
139 data->getMask().size());
140
141 if (static_cast<int>(data->getMask().size()) != searchDataLength) {
142 /* CL-CMD-SEARCH.1 */
143 Arrays::fill(
144 dataIn,
145 dataIn.size() - searchDataLength + data->getMask().size(),
146 dataIn.size(),
147 static_cast<uint8_t>(0xFF));
148 }
149 }
150
151 /* APDU Case 4 - always outside secure session */
152 setApduRequestInBestEffortMode(
153 std::make_shared<DtoAdapters::ApduRequestAdapter>(ApduUtil::build(
154 transactionContext->getCard()->getCardClass().getValue(),
155 getCommandRef().getInstructionByte(),
156 static_cast<uint8_t>(data->getRecordNumber()),
157 p2,
158 dataIn,
159 0x00)));
160
161 const std::string extraInfo
162 = "SFI: " + HexUtil::toHex(data->getSfi())
163 + "h, Rec: " + std::to_string(data->getRecordNumber()) + ", Offset: "
164 + std::to_string(data->getOffset()) + ", Repeated offset: "
165 + std::to_string(data->isEnableRepeatedOffset())
166 + ", Fetch first result: "
167 + std::to_string(data->isFetchFirstMatchingResult())
168 + ", Search data: " + HexUtil::toHex(data->getSearchData()) + "h,"
169 + " Mask: " + HexUtil::toHex(data->getMask()) + "h";
170
171 addSubName(extraInfo);
172}
173
174void
175CommandSearchRecordMultiple::finalizeRequest()
176{
177 /* NOP */
178}
179
180bool
181CommandSearchRecordMultiple::isCryptoServiceRequiredToFinalizeRequest() const
182{
183 return false;
184}
185
186bool
187CommandSearchRecordMultiple::synchronizeCryptoServiceBeforeCardProcessing()
188{
189 return true;
190}
191
192const std::map<int, const std::shared_ptr<Command::StatusProperties>>&
193CommandSearchRecordMultiple::getStatusTable() const
194{
195 return STATUS_TABLE;
196}
197
198void
199CommandSearchRecordMultiple::parseResponse(
200 const std::shared_ptr<ApduResponseApi> apduResponse)
201{
202 if (!setApduResponseAndCheckStatusInBestEffortMode(apduResponse)) {
203 return;
204 }
205
206 const std::vector<uint8_t> dataOut = apduResponse->getDataOut();
207 const int nbRecords = dataOut[0];
208
209 for (int i = 1; i <= nbRecords; i++) {
210 mData->getMatchingRecordNumbers().push_back(dataOut[i]);
211 }
212
213 if (mData->isFetchFirstMatchingResult() && nbRecords > 0) {
214 getTransactionContext()->getCard()->setContent(
215 mData->getSfi(),
216 static_cast<uint8_t>(mData->getMatchingRecordNumbers()[0]),
217 Arrays::copyOfRange(dataOut, nbRecords + 1, dataOut.size()));
218 }
219}
220
221} /* namespace calypso */
222} /* namespace card */
223} /* namespace keyple */