Keyple Card Calypso C++ Library 2.2.2
Reference Terminal Reader API for C++
CardControlSamTransactionManagerAdapter.cpp
Go to the documentation of this file.
1/**************************************************************************************************
2 * Copyright (c) 2023 Calypso Networks Association https://calypsonet.org/ *
3 * *
4 * See the NOTICE file(s) distributed with this work for additional information regarding *
5 * copyright ownership. *
6 * *
7 * This program and the accompanying materials are made available under the terms of the Eclipse *
8 * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0 *
9 * *
10 * SPDX-License-Identifier: EPL-2.0 *
11 **************************************************************************************************/
12
14
15/* Keyple Card Calypso */
17#include "CmdSamDigestUpdate.h"
19#include "CmdSamDigestInit.h"
20#include "CmdSamGiveRandom.h"
21#include "CmdSamSvCheck.h"
22
23/* Keyple Core Util */
24#include "ApduUtil.h"
25#include "Arrays.h"
26#include "IllegalStateException.h"
27#include "KeypleStd.h"
28#include "System.h"
29
30namespace keyple {
31namespace card {
32namespace calypso {
33
34using namespace keyple::core::util;
35using namespace keyple::core::util::cpp;
36using namespace keyple::core::util::cpp::exception;
37
38/* CARD CONTROL SAM TRANSACTION MANAGER ADAPTER ------------------------------------------------- */
39
41 const std::shared_ptr<CalypsoCardAdapter> targetCard,
42 const std::shared_ptr<CardSecuritySettingAdapter> securitySetting,
43 const std::vector<std::vector<uint8_t>>& transactionAuditData)
44/* CL-SAM-CSN.1 */
46 targetCard,
47 std::reinterpret_pointer_cast<CommonSecuritySettingAdapter<CardSecuritySettingAdapter>>(
48 securitySetting),
49 targetCard->getCalypsoSerialNumberFull(),
50 transactionAuditData),
51 mControlSam(securitySetting ? securitySetting->getControlSam() : nullptr),
52 mTargetCard(targetCard),
53 mCardSecuritySetting(securitySetting) {}
54
56 const WriteAccessLevel writeAccessLevel,
57 const std::shared_ptr<uint8_t> kvc) const
58{
59 if (kvc != nullptr) {
60 return kvc;
61 }
62
63 return mCardSecuritySetting->getDefaultKvc(writeAccessLevel);
64}
65
67 const WriteAccessLevel writeAccessLevel,
68 const std::shared_ptr<uint8_t> kif,
69 const std::shared_ptr<uint8_t> kvc) const
70{
71 /* CL-KEY-KIF.1 */
72 if ((kif != nullptr && *kif != 0xFF) || (kvc == nullptr)) {
73 return kif;
74 }
75
76 /* CL-KEY-KIFUNK.1 */
77 std::shared_ptr<uint8_t> result = mCardSecuritySetting->getKif(writeAccessLevel, *kvc);
78 if (result == nullptr) {
79 result = mCardSecuritySetting->getDefaultKif(writeAccessLevel);
80 }
81
82 return result;
83}
84
86{
87 /*
88 * If there are pending SAM commands and the secure session is open and the "Digest Init"
89 * command is not already executed, then we need to flush the session pending commands by
90 * executing the pending "digest" commands "BEFORE" the other SAM commands to make sure that
91 * between the session "Get Challenge" and the "Digest Init", there is no other command
92 * inserted.
93 */
94 if (!getSamCommands().empty() &&
95 mDigestManager != nullptr &&
96 !mDigestManager->mIsDigestInitDone) {
97
98 std::vector<std::shared_ptr<AbstractApduCommand>>& samCommands = getSamCommands();
99 getSamCommands().clear();
100 mDigestManager->prepareDigestInit();
101 Arrays::addAll(getSamCommands(), samCommands);
102 }
103
105}
106
108{
110
111 const auto cmd = std::make_shared<CmdSamGetChallenge>(mControlSam->getProductType(),
112 mTargetCard->isExtendedModeSupported() ?
113 8 : 4);
114 getSamCommands().push_back(cmd);
115
116 return cmd;
117}
118
120{
122
123 getSamCommands().push_back(std::make_shared<CmdSamGiveRandom>(mControlSam->getProductType(),
124 mTargetCard->getCardChallenge()));
125}
126
127const std::shared_ptr<CmdSamCardGenerateKey>
129 const uint8_t cipheringKvc,
130 const uint8_t sourceKif,
131 const uint8_t sourceKvc)
132{
133 const auto cmd = std::make_shared<CmdSamCardGenerateKey>(mControlSam->getProductType(),
134 cipheringKif,
135 cipheringKvc,
136 sourceKif,
137 sourceKvc);
138 getSamCommands().push_back(cmd);
139
140 return cmd;
141}
142
143const std::shared_ptr<CmdSamCardCipherPin>
145 const std::vector<uint8_t>& currentPin,
146 const std::vector<uint8_t>& newPin)
147{
148 uint8_t pinCipheringKif;
149 uint8_t pinCipheringKvc;
150
151 if (mDigestManager != nullptr && mDigestManager->mSessionKif != 0) {
152 /* The current work key has been set (a secure session is open) */
153 pinCipheringKif = mDigestManager->mSessionKif;
154 pinCipheringKvc = mDigestManager->mSessionKvc;
155
156 } else {
157 /* No current work key is available (outside secure session) */
158 if (newPin.empty()) {
159 /* PIN verification */
160 if (mCardSecuritySetting->getPinVerificationCipheringKif() == nullptr ||
161 mCardSecuritySetting->getPinVerificationCipheringKvc() == nullptr) {
162 throw IllegalStateException("No KIF or KVC defined for the PIN verification " \
163 "ciphering key");
164 }
165
166 pinCipheringKif = *mCardSecuritySetting->getPinVerificationCipheringKif();
167 pinCipheringKvc = *mCardSecuritySetting->getPinVerificationCipheringKvc();
168 } else {
169 /* PIN modification */
170 if (mCardSecuritySetting->getPinModificationCipheringKif() == nullptr ||
171 mCardSecuritySetting->getPinModificationCipheringKvc() == nullptr) {
172 throw IllegalStateException("No KIF or KVC defined for the PIN modification " \
173 "ciphering key");
174 }
175
176 pinCipheringKif = *mCardSecuritySetting->getPinModificationCipheringKif();
177 pinCipheringKvc = *mCardSecuritySetting->getPinModificationCipheringKvc();
178 }
179 }
180
181 const auto cmd = std::make_shared<CmdSamCardCipherPin>(mControlSam->getProductType(),
182 pinCipheringKif,
183 pinCipheringKvc,
184 currentPin,
185 newPin);
186 getSamCommands().push_back(cmd);
187
188 return cmd;
189}
190
191const std::shared_ptr<CmdSamSvPrepareLoad>
193 const std::vector<uint8_t>& svGetHeader,
194 const std::vector<uint8_t>& svGetData,
195 const std::shared_ptr<CmdCardSvReload> cmdCardSvReload)
196{
198 const auto cmd = std::make_shared<CmdSamSvPrepareLoad>(mControlSam->getProductType(),
199 svGetHeader,
200 svGetData,
201 cmdCardSvReload->getSvReloadData());
202 getSamCommands().push_back(cmd);
203
204 return cmd;
205}
206
207const std::shared_ptr<CmdSamSvPrepareDebitOrUndebit>
209 const bool isDebitCommand,
210 const std::vector<uint8_t>& svGetHeader,
211 const std::vector<uint8_t>& svGetData,
212 const std::shared_ptr<CmdCardSvDebitOrUndebit> cmdCardSvDebitOrUndebit)
213{
215 const auto cmd = std::make_shared<CmdSamSvPrepareDebitOrUndebit>(
216 isDebitCommand,
217 mControlSam->getProductType(),
218 svGetHeader,
219 svGetData,
220 cmdCardSvDebitOrUndebit->getSvDebitOrUndebitData());
221 getSamCommands().push_back(cmd);
222
223 return cmd;
224}
225
227 const std::vector<uint8_t>& svOperationData)
228{
229 getSamCommands().push_back(std::make_shared<CmdSamSvCheck>(mControlSam->getProductType(),
230 svOperationData));
231}
232
234 const std::vector<uint8_t>& openSecureSessionDataOut,
235 const uint8_t kif,
236 const uint8_t kvc,
237 const bool isSessionEncrypted,
238 const bool isVerificationMode)
239{
240 mDigestManager = std::make_shared<DigestManager>(this,
241 openSecureSessionDataOut,
242 kif,
243 kvc,
244 isSessionEncrypted,
245 isVerificationMode);
246}
247
249 const std::vector<std::shared_ptr<ApduRequestSpi>>& requests,
250 const std::vector<std::shared_ptr<ApduResponseApi>>& responses,
251 const int startIndex)
252{
253 mDigestManager->updateSession(requests, responses, startIndex);
254}
255
256const std::shared_ptr<CmdSamDigestClose>
258{
259 mDigestManager->prepareCommands();
260 mDigestManager = nullptr;
261
262 return std::dynamic_pointer_cast<CmdSamDigestClose>(
263 getSamCommands()[getSamCommands().size() - 1]);
264}
265
267 const std::vector<uint8_t>& cardSignatureLo)
268{
269 getSamCommands().push_back(std::make_shared<CmdSamDigestAuthenticate>(
270 mControlSam->getProductType(),
271 cardSignatureLo));
272}
273
274/* DIGEST MANAGER ------------------------------------------------------------------------------- */
275
276CardControlSamTransactionManagerAdapter::DigestManager::DigestManager(
278 const std::vector<uint8_t>& openSecureSessionDataOut,
279 const uint8_t kif,
280 const uint8_t kvc,
281 const bool isSessionEncrypted,
282 const bool isVerificationMode)
283: mSessionKif(kif),
284 mSessionKvc(kvc),
285 mOpenSecureSessionDataOut(openSecureSessionDataOut),
286 mIsSessionEncrypted(isSessionEncrypted),
287 mIsVerificationMode(isVerificationMode),
288 mParent(parent) {}
289
290void CardControlSamTransactionManagerAdapter::DigestManager::updateSession(
291 const std::vector<std::shared_ptr<ApduRequestSpi>>& requests,
292 const std::vector<std::shared_ptr<ApduResponseApi>>& responses,
293 const int startIndex)
294{
295 for (int i = startIndex; i < static_cast<int>(requests.size()); i++) {
296 /*
297 * If the request is of case4 type, LE must be excluded from the digest computation. In this
298 * case, we remove here the last byte of the command buffer.
299 * CL-C4-MAC.1
300 */
301 const std::shared_ptr<ApduRequestSpi> request = requests[i];
302 mCardApdus.push_back(ApduUtil::isCase4(request->getApdu()) ?
303 Arrays::copyOfRange(request->getApdu(),
304 0,
305 request->getApdu().size() - 1) :
306 request->getApdu());
307
308 const std::shared_ptr<ApduResponseApi> response = responses[i];
309 mCardApdus.push_back(response->getApdu());
310 }
311}
312
313void CardControlSamTransactionManagerAdapter::DigestManager::prepareCommands()
314{
315 /* Prepare the "Digest Init" command if not already done */
316 if (!mIsDigestInitDone) {
317 prepareDigestInit();
318 }
319
320 /* Prepare the "Digest Update" commands and flush the buffer */
321 prepareDigestUpdate();
322 mCardApdus.clear();
323
324 /* Prepare the "Digest Close" command */
325 prepareDigestClose();
326}
327
328void CardControlSamTransactionManagerAdapter::DigestManager::prepareDigestInit()
329{
330 /* CL-SAM-DINIT.1 */
331 mParent->getSamCommands().push_back(std::make_shared<CmdSamDigestInit>(
332 mParent->mControlSam->getProductType(),
333 mIsVerificationMode,
334 mParent->mTargetCard->isExtendedModeSupported(),
335 mSessionKif,
336 mSessionKvc,
337 mOpenSecureSessionDataOut));
338
339 mIsDigestInitDone = true;
340}
341
342void CardControlSamTransactionManagerAdapter::DigestManager::prepareDigestUpdate()
343{
344 if (mCardApdus.empty()) {
345 return;
346 }
347
348 /* CL-SAM-DUPDATE.1 */
349 if (mParent->mControlSam->getProductType() == CalypsoSam::ProductType::SAM_C1) {
350
351 /*
352 * Digest Update Multiple
353 * Construct list of DataIn
354 */
355 std::vector<std::vector<uint8_t>> digestDataList(1);
356 std::vector<uint8_t> buffer(255);
357 int i = 0;
358
359 for (const auto& cardApdu : mCardApdus) {
360 if (static_cast<int>(i + cardApdu.size()) > 254) {
361 /* Copy buffer to digestDataList and reset buffer */
362 digestDataList.push_back(Arrays::copyOf(buffer, i));
363 i = 0;
364 }
365
366 /* Add [length][apdu] to current buffer */
367 buffer[i++] = static_cast<uint8_t>(cardApdu.size());
368 System::arraycopy(cardApdu, 0, buffer, i, cardApdu.size());
369 i += cardApdu.size();
370 }
371
372 /* Copy buffer to digestDataList */
373 digestDataList.push_back(Arrays::copyOf(buffer, i));
374
375 /* Add commands */
376 for (const auto& dataIn : digestDataList) {
377 mParent->getSamCommands().push_back(
378 std::make_shared<CmdSamDigestUpdateMultiple>(mParent->mControlSam->getProductType(),
379 dataIn));
380 }
381
382 } else {
383 /* Digest Update (simple) */
384 for (const auto& cardApdu : mCardApdus) {
385 mParent->getSamCommands().push_back(
386 std::make_shared<CmdSamDigestUpdate>(mParent->mControlSam->getProductType(),
387 mIsSessionEncrypted,
388 cardApdu));
389 }
390 }
391}
392
393void CardControlSamTransactionManagerAdapter::DigestManager::prepareDigestClose()
394{
395 /* CL-SAM-DCLOSE.1 */
396 mParent->getSamCommands().push_back(std::make_shared<CmdSamDigestClose>(
397 mParent->mControlSam->getProductType(),
398 mParent->mTargetCard->isExtendedModeSupported() ?
399 8 : 4));
400}
401
402}
403}
404}
const std::shared_ptr< CmdSamSvPrepareDebitOrUndebit > prepareSvPrepareDebitOrUndebit(const bool isDebitCommand, const std::vector< uint8_t > &svGetHeader, const std::vector< uint8_t > &svGetData, const std::shared_ptr< CmdCardSvDebitOrUndebit > cmdCardSvDebitOrUndebit)
const std::shared_ptr< CmdSamSvPrepareLoad > prepareSvPrepareLoad(const std::vector< uint8_t > &svGetHeader, const std::vector< uint8_t > &svGetData, const std::shared_ptr< CmdCardSvReload > cmdCardSvReload)
void updateSession(const std::vector< std::shared_ptr< ApduRequestSpi > > &requests, const std::vector< std::shared_ptr< ApduResponseApi > > &responses, const int startIndex)
const std::shared_ptr< CmdSamCardGenerateKey > prepareCardGenerateKey(const uint8_t cipheringKif, const uint8_t cipheringKvc, const uint8_t sourceKif, const uint8_t sourceKvc)
CardControlSamTransactionManagerAdapter(const std::shared_ptr< CalypsoCardAdapter > targetCard, const std::shared_ptr< CardSecuritySettingAdapter > securitySetting, const std::vector< std::vector< uint8_t > > &transactionAuditData)
std::shared_ptr< uint8_t > computeKif(const WriteAccessLevel writeAccessLevel, const std::shared_ptr< uint8_t > kif, const std::shared_ptr< uint8_t > kvc) const
void initializeSession(const std::vector< uint8_t > &openSecureSessionDataOut, const uint8_t kif, const uint8_t kvc, const bool isSessionEncrypted, const bool isVerificationMode)
std::shared_ptr< uint8_t > computeKvc(const WriteAccessLevel writeAccessLevel, const std::shared_ptr< uint8_t > kvc) const
const std::shared_ptr< CmdSamCardCipherPin > prepareCardCipherPin(const std::vector< uint8_t > &currentPin, const std::vector< uint8_t > &newPin)
virtual std::vector< std::shared_ptr< AbstractApduCommand > > & getSamCommands()