Keyple Card Calypso C++ Library 2.2.5.6
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 securitySetting,
48 targetCard->getCalypsoSerialNumberFull(),
49 transactionAuditData),
50 mControlSam(securitySetting ? securitySetting->getControlSam() : nullptr),
51 mTargetCard(targetCard),
52 mCardSecuritySetting(securitySetting) {}
53
55 const WriteAccessLevel writeAccessLevel,
56 const std::shared_ptr<uint8_t> kvc) const
57{
58 if (kvc != nullptr) {
59 return kvc;
60 }
61
62 return mCardSecuritySetting->getDefaultKvc(writeAccessLevel);
63}
64
66 const WriteAccessLevel writeAccessLevel,
67 const std::shared_ptr<uint8_t> kif,
68 const std::shared_ptr<uint8_t> kvc) const
69{
70 /* CL-KEY-KIF.1 */
71 if ((kif != nullptr && *kif != 0xFF) || (kvc == nullptr)) {
72 return kif;
73 }
74
75 /* CL-KEY-KIFUNK.1 */
76 std::shared_ptr<uint8_t> result = mCardSecuritySetting->getKif(writeAccessLevel, *kvc);
77 if (result == nullptr) {
78 result = mCardSecuritySetting->getDefaultKif(writeAccessLevel);
79 }
80
81 return result;
82}
83
85{
86 /*
87 * If there are pending SAM commands and the secure session is open and the "Digest Init"
88 * command is not already executed, then we need to flush the session pending commands by
89 * executing the pending "digest" commands "BEFORE" the other SAM commands to make sure that
90 * between the session "Get Challenge" and the "Digest Init", there is no other command
91 * inserted.
92 */
93 if (!getSamCommands().empty() &&
94 mDigestManager != nullptr &&
95 !mDigestManager->mIsDigestInitDone) {
96
97 /* Create a copy - not a reference */
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,
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,
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,
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,
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,
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,
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,
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,
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
318 prepareDigestInit();
319 }
320
321 /* Prepare the "Digest Update" commands and flush the buffer */
322 prepareDigestUpdate();
323 mCardApdus.clear();
324
325 /* Prepare the "Digest Close" command */
326 prepareDigestClose();
327}
328
329void CardControlSamTransactionManagerAdapter::DigestManager::prepareDigestInit()
330{
331 /* CL-SAM-DINIT.1 */
332 mParent->getSamCommands().push_back(std::make_shared<CmdSamDigestInit>(
333 mParent->mControlSam,
334 mIsVerificationMode,
335 mParent->mTargetCard->isExtendedModeSupported(),
336 mSessionKif,
337 mSessionKvc,
338 mOpenSecureSessionDataOut));
339
340 mIsDigestInitDone = true;
341}
342
343void CardControlSamTransactionManagerAdapter::DigestManager::prepareDigestUpdate()
344{
345 if (mCardApdus.empty()) {
346 return;
347 }
348
349 /* CL-SAM-DUPDATE.1 */
350 if (mParent->mControlSam->getProductType() == CalypsoSam::ProductType::SAM_C1) {
351
352 /*
353 * Digest Update Multiple
354 * Construct list of DataIn
355 */
356 std::vector<std::vector<uint8_t>> digestDataList;
357 std::vector<uint8_t> buffer(255);
358 int i = 0;
359
360 for (const auto& cardApdu : mCardApdus) {
361
362 if (static_cast<int>(i + cardApdu.size()) > 254) {
363
364 /* Copy buffer to digestDataList and reset buffer */
365 digestDataList.push_back(Arrays::copyOf(buffer, i));
366 i = 0;
367 }
368
369 /* Add [length][apdu] to current buffer */
370 buffer[i++] = static_cast<uint8_t>(cardApdu.size());
371 System::arraycopy(cardApdu, 0, buffer, i, cardApdu.size());
372 i += cardApdu.size();
373 }
374
375 /* Copy buffer to digestDataList */
376 digestDataList.push_back(Arrays::copyOf(buffer, i));
377
378 /* Add commands */
379 for (const auto& dataIn : digestDataList) {
380
381 mParent->getSamCommands().push_back(
382 std::make_shared<CmdSamDigestUpdateMultiple>(mParent->mControlSam,
383 dataIn));
384 }
385
386 } else {
387
388 /* Digest Update (simple) */
389 for (const auto& cardApdu : mCardApdus) {
390
391 mParent->getSamCommands().push_back(
392 std::make_shared<CmdSamDigestUpdate>(mParent->mControlSam,
393 mIsSessionEncrypted,
394 cardApdu));
395 }
396 }
397}
398
399void CardControlSamTransactionManagerAdapter::DigestManager::prepareDigestClose()
400{
401 /* CL-SAM-DCLOSE.1 */
402 mParent->getSamCommands().push_back(std::make_shared<CmdSamDigestClose>(
403 mParent->mControlSam,
404 mParent->mTargetCard->isExtendedModeSupported() ?
405 8 : 4));
406}
407
408}
409}
410}
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()