Keyple Card Calypso C++ Library 2.1.0
Reference Terminal Reader API for C++
SamCommandProcessor.cpp
Go to the documentation of this file.
1/**************************************************************************************************
2 * Copyright (c) 2022 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
13#include "SamCommandProcessor.h"
14
15/* Calypsonet Terminal Calypso */
16#include "DesynchronizedExchangesException.h"
17
18/* Calypsonet Terminal Card */
20#include "ChannelControl.h"
21#include "UnexpectedStatusWordException.h"
22
23/* Keyple Card Calypso */
24#include "ApduRequestSpi.h"
25#include "CmdSamCardCipherPin.h"
28#include "CmdSamDigestClose.h"
29#include "CmdSamDigestInit.h"
30#include "CmdSamDigestUpdate.h"
31#include "CmdSamGetChallenge.h"
32#include "CmdSamGiveRandom.h"
34#include "CmdSamSvCheck.h"
36#include "CmdSamSvPrepareLoad.h"
38
39/* Keyple Card Generic */
40#include "CardRequestAdapter.h"
41
42/* Keyple Core Util */
43#include "ApduUtil.h"
44#include "Arrays.h"
45#include "ByteArrayUtil.h"
46#include "IllegalStateException.h"
47#include "KeypleAssert.h"
48#include "System.h"
49
50namespace keyple {
51namespace card {
52namespace calypso {
53
54using namespace calypsonet::terminal::calypso::transaction;
55using namespace calypsonet::terminal::card;
56using namespace calypsonet::terminal::card::spi;
57using namespace keyple::core::util;
58using namespace keyple::core::util::cpp;
59using namespace keyple::core::util::cpp::exception;
60
61const uint8_t SamCommandProcessor::KIF_UNDEFINED = 0xFF;
62const uint8_t SamCommandProcessor::CHALLENGE_LENGTH_REV_INF_32 = 0x04;
63const uint8_t SamCommandProcessor::CHALLENGE_LENGTH_REV32 = 0x08;
64const uint8_t SamCommandProcessor::SIGNATURE_LENGTH_REV_INF_32 = 0x04;
65const uint8_t SamCommandProcessor::SIGNATURE_LENGTH_REV32 = 0x08;
66const std::string SamCommandProcessor::UNEXPECTED_EXCEPTION = "An unexpected exception was raised.";
67std::vector<std::vector<uint8_t>> SamCommandProcessor::mCardDigestDataCache;
68
70 const std::shared_ptr<CalypsoCard> calypsoCard,
71 const std::shared_ptr<CardSecuritySetting> cardSecuritySetting)
72: mCardSecuritySettings(cardSecuritySetting),
73 mCalypsoCard(std::dynamic_pointer_cast<CalypsoCardAdapter>(calypsoCard)),
74 mIsDiversificationDone(false)
75{
76 const auto stngs = std::dynamic_pointer_cast<CardSecuritySettingAdapter>(cardSecuritySetting);
77 Assert::getInstance().notNull(stngs, "securitySettings")
78 .notNull(stngs->getSamReader(), "samReader")
79 .notNull(stngs->getCalypsoSam(), "calypsoSam");
80
81 const auto calypsoSam = stngs->getCalypsoSam();
82 mSamProductType = calypsoSam->getProductType();
83 mSamSerialNumber = calypsoSam->getSerialNumber();
84 mSamReader = std::dynamic_pointer_cast<ProxyReaderApi>(stngs->getSamReader());
85}
86
88{
89 std::vector<std::shared_ptr<ApduRequestSpi>> apduRequests;
90
91 /* Diversify only if this has not already been done */
92 if (!mIsDiversificationDone) {
93 /*
94 * Build the SAM Select Diversifier command to provide the SAM with the card S/N
95 * CL-SAM-CSN.1
96 */
97 const auto selectDiversifierCmd =
98 std::make_shared<CmdSamSelectDiversifier>(mSamProductType,
99 mCalypsoCard->getCalypsoSerialNumberFull());
100
101 apduRequests.push_back(selectDiversifierCmd->getApduRequest());
102
103 /* Note that the diversification has been made */
104 mIsDiversificationDone = true;
105 }
106
107 /* Build the SAM Get Challenge command */
108 const uint8_t challengeLength = mCalypsoCard->isExtendedModeSupported() ?
109 CHALLENGE_LENGTH_REV32 : CHALLENGE_LENGTH_REV_INF_32;
110
111 auto samGetChallengeCmd = std::make_shared<CmdSamGetChallenge>(mSamProductType,challengeLength);
112
113 apduRequests.push_back(samGetChallengeCmd->getApduRequest());
114
115 /* Transmit the CardRequest to the SAM and get back the CardResponse (list of ApduResponseApi)*/
116 std::shared_ptr<CardResponseApi> samCardResponse;
117 try {
118 samCardResponse = mSamReader->transmitCardRequest(
119 std::make_shared<CardRequestAdapter>(apduRequests, false),
120 ChannelControl::KEEP_OPEN);
121 } catch (const UnexpectedStatusWordException& e) {
122 throw IllegalStateException(UNEXPECTED_EXCEPTION,
123 std::make_shared<UnexpectedStatusWordException>(e));
124 }
125
126 const std::vector<std::shared_ptr<ApduResponseApi>>&
127 samApduResponses = samCardResponse->getApduResponses();
128 std::vector<uint8_t> sessionTerminalChallenge;
129
130 const size_t numberOfSamCmd = apduRequests.size();
131 if (samApduResponses.size() == numberOfSamCmd) {
132 samGetChallengeCmd->setApduResponse(samApduResponses[numberOfSamCmd - 1]).checkStatus();
133 sessionTerminalChallenge = samGetChallengeCmd->getChallenge();
134 mLogger->debug("identification: TERMINALCHALLENGE = %\n",
135 ByteArrayUtil::toHex(sessionTerminalChallenge));
136
137 } else {
138 throw DesynchronizedExchangesException("The number of commands/responses does not match: " \
139 "cmd=" + std::to_string(numberOfSamCmd) + ", " +
140 "resp=" + std::to_string(samApduResponses.size()));
141 }
142
143 return sessionTerminalChallenge;
144}
145
146const std::shared_ptr<uint8_t> SamCommandProcessor::computeKvc(
147 const WriteAccessLevel writeAccessLevel, const std::shared_ptr<uint8_t> kvc) const
148{
149 if (kvc != nullptr) {
150 return kvc;
151 }
152
153 return std::dynamic_pointer_cast<CardSecuritySettingAdapter>(mCardSecuritySettings)
154 ->getDefaultKvc(writeAccessLevel);
155}
156
157const std::shared_ptr<uint8_t> SamCommandProcessor::computeKif(
158 const WriteAccessLevel writeAccessLevel,
159 const std::shared_ptr<uint8_t> kif,
160 const std::shared_ptr<uint8_t> kvc)
161{
162 /* CL-KEY-KIF.1 */
163 if ((kif != nullptr && *kif.get() != KIF_UNDEFINED) || (kvc == nullptr)) {
164 return kif;
165 }
166
167 /* CL-KEY-KIFUNK.1 */
168 const auto adptr = std::dynamic_pointer_cast<CardSecuritySettingAdapter>(mCardSecuritySettings);
169 std::shared_ptr<uint8_t> result = adptr->getKif(writeAccessLevel, *kvc.get());
170 if (result == nullptr) {
171 result = adptr->getDefaultKif(writeAccessLevel);
172 }
173
174 return result;
175}
176
177void SamCommandProcessor::initializeDigester(const bool sessionEncryption,
178 const bool verificationMode,
179 const uint8_t kif,
180 const uint8_t kvc,
181 const std::vector<uint8_t>& digestData)
182{
183 mSessionEncryption = sessionEncryption;
184 mVerificationMode = verificationMode;
185 mKif = kif;
186 mKvc = kvc;
187
188 mLogger->debug("initialize: POREVISION = %, SAMREVISION = %, SESSIONENCRYPTION = %, " \
189 "VERIFICATIONMODE = %\n",
190 mCalypsoCard->getProductType(),
191 mSamProductType,
192 sessionEncryption,
193 verificationMode);
194 mLogger->debug("initialize: VERIFICATIONMODE = %, REV32MODE = %\n",
195 verificationMode,
196 mCalypsoCard->isExtendedModeSupported());
197 mLogger->debug("initialize: KIF = %, KVC %, DIGESTDATA = %\n",
198 kif,
199 kvc,
200 ByteArrayUtil::toHex(digestData));
201
202 /* Clear data cache */
203 mCardDigestDataCache.clear();
204
205 /* Build Digest Init command as first ApduRequestAdapter of the digest computation process */
206 mCardDigestDataCache.push_back(digestData);
207
208 mIsDigestInitDone = false;
209 mIsDigesterInitialized = true;
210}
211
212void SamCommandProcessor::pushCardExchangedData(const std::shared_ptr<ApduRequestSpi> request,
213 const std::shared_ptr<ApduResponseApi> response)
214{
215 mLogger->trace("pushCardExchangedData: %\n", request);
216
217 /*
218 * Add an ApduRequestAdapter to the digest computation: if the request is of case4 type, Le must
219 * be excluded from the digest computation. In this cas, we remove here the last byte of the
220 * command buffer.
221 * CL-C4-MAC.1
222 */
223 if (ApduUtil::isCase4(request->getApdu())) {
224 mCardDigestDataCache.push_back(
225 Arrays::copyOfRange(request->getApdu(), 0, request->getApdu().size() - 1));
226 } else {
227 mCardDigestDataCache.push_back(request->getApdu());
228 }
229
230 mLogger->trace("pushCardExchangedData: %\n", response);
231
232 /* Add an ApduResponseApi to the digest computation */
233 mCardDigestDataCache.push_back(response->getApdu());
234}
235
237 const std::vector<std::shared_ptr<ApduRequestSpi>>& requests,
238 const std::vector<std::shared_ptr<ApduResponseApi>>& responses,
239 const int startIndex)
240{
241 for (int i = startIndex; i < static_cast<int>(requests.size()); i++) {
242 /* Add requests and responses to the digest processor */
243 pushCardExchangedData(requests[i], responses[i]);
244 }
245}
246
247const std::vector<std::shared_ptr<AbstractSamCommand>> SamCommandProcessor::getPendingSamCommands(
248 const bool addDigestClose)
249{
250 /* TODO optimization with the use of Digest Update Multiple whenever possible */
251 std::vector<std::shared_ptr<AbstractSamCommand>> samCommands;
252
253 /* Sanity checks */
254 if (mCardDigestDataCache.empty()) {
255 mLogger->debug("getSamDigestRequest: no data in cache\n");
256 throw IllegalStateException("Digest data cache is empty.");
257 }
258
259 if (!mIsDigestInitDone && mCardDigestDataCache.size() % 2 == 0) {
260 /* The number of buffers should be 2*n + 1 */
261 mLogger->debug("getSamDigestRequest: wrong number of buffer in cache NBR = %\n",
262 mCardDigestDataCache.size());
263 throw IllegalStateException("Digest data cache is inconsistent.");
264 }
265
266 if (!mIsDigestInitDone) {
267 /*
268 * Build and append Digest Init command as first ApduRequestAdapter of the digest
269 * computation process. The Digest Init command comes from the Open Secure Session response
270 * from the card. Once added to the ApduRequestAdapter list, the data is remove from the
271 * cache to keep only couples of card request/response
272 * CL-SAM-DINIT.1
273 */
274 samCommands.push_back(
275 std::make_shared<CmdSamDigestInit>(mSamProductType,
276 mVerificationMode,
277 mCalypsoCard->isExtendedModeSupported(),
278 mKif,
279 mKvc,
280 mCardDigestDataCache[0]));
281 mCardDigestDataCache.erase(mCardDigestDataCache.begin());
282
283 /* Note that the digest init has been made */
284 mIsDigestInitDone = true;
285 }
286
287 /*
288 * Build and append Digest Update commands
289 * CL-SAM-DUPDATE.1
290 */
291 for (const auto& bytes : mCardDigestDataCache) {
292 samCommands.push_back(
293 std::make_shared<CmdSamDigestUpdate>(mSamProductType, mSessionEncryption, bytes));
294 }
295
296 /* Clears cached commands once they have been processed */
297 mCardDigestDataCache.clear();
298
299 if (addDigestClose) {
300 /*
301 * Build and append Digest Close command
302 * CL-SAM-DCLOSE.1
303 */
304 samCommands.push_back(
305 std::make_shared<CmdSamDigestClose>(mSamProductType,
306 mCalypsoCard->isExtendedModeSupported() ?
307 SIGNATURE_LENGTH_REV32 :
308 SIGNATURE_LENGTH_REV_INF_32));
309 }
310
311 return samCommands;
312}
313
315{
316 /*
317 * All remaining SAM digest operations will now run at once.
318 * Get the SAM Digest request including Digest Close from the cache manager
319 */
320 std::vector<std::shared_ptr<AbstractSamCommand>> samCommands = getPendingSamCommands(true);
321
322 auto samCardRequest = std::make_shared<CardRequestAdapter>(getApduRequests(samCommands), false);
323
324 /* Transmit CardRequest and get CardResponse */
325 std::shared_ptr<CardResponseApi> samCardResponse;
326
327 try {
328 samCardResponse = mSamReader->transmitCardRequest(samCardRequest,
329 ChannelControl::KEEP_OPEN);
330 } catch (const UnexpectedStatusWordException& e) {
331 throw IllegalStateException(UNEXPECTED_EXCEPTION,
332 std::make_shared<UnexpectedStatusWordException>(e));
333 }
334
335 std::vector<std::shared_ptr<ApduResponseApi>> samApduResponses =
336 samCardResponse->getApduResponses();
337
338 if (samApduResponses.size() != samCommands.size()) {
339 throw DesynchronizedExchangesException("The number of commands/responses does not match: " \
340 "cmd=" + std::to_string(samCommands.size()) + ", " +
341 "resp="+ std::to_string(samApduResponses.size()));
342 }
343
344 /* Check all responses status */
345 for (int i = 0; i < static_cast<int>(samApduResponses.size()); i++) {
346 samCommands[i]->setApduResponse(samApduResponses[i]).checkStatus();
347 }
348
349 /* Get Terminal Signature from the latest response */
350 auto cmdSamDigestClose = std::dynamic_pointer_cast<CmdSamDigestClose>(samCommands.back());
351 cmdSamDigestClose->setApduResponse(samApduResponses[samCommands.size() - 1]);
352
353 const std::vector<uint8_t> sessionTerminalSignature = cmdSamDigestClose->getSignature();
354
355 mLogger->debug("SIGNATURE = %\n", ByteArrayUtil::toHex(sessionTerminalSignature));
356
357 return sessionTerminalSignature;
358}
359
360const std::vector<std::shared_ptr<ApduRequestSpi>> SamCommandProcessor::getApduRequests(
361 const std::vector<std::shared_ptr<AbstractSamCommand>> samCommands) const
362{
363 std::vector<std::shared_ptr<ApduRequestSpi>> apduRequests;
364
365 if (!samCommands.empty()) {
366 for (const auto& samCommand : samCommands) {
367 apduRequests.push_back(samCommand->getApduRequest());
368 }
369 }
370
371 return apduRequests;
372}
373
374void SamCommandProcessor::authenticateCardSignature(const std::vector<uint8_t>& cardSignatureLo)
375{
376 /*
377 * Check the card signature part with the SAM
378 * Build and send SAM Digest Authenticate command
379 */
380 auto cmdSamDigestAuthenticate = std::make_shared<CmdSamDigestAuthenticate>(mSamProductType,
381 cardSignatureLo);
382
383 std::vector<std::shared_ptr<ApduRequestSpi>> samApduRequests;
384 samApduRequests.push_back(cmdSamDigestAuthenticate->getApduRequest());
385
386 auto samCardRequest = std::dynamic_pointer_cast<CardRequestSpi>(
387 std::make_shared<CardRequestAdapter>(samApduRequests, false));
388
389 std::shared_ptr<CardResponseApi> samCardResponse;
390 try {
391 samCardResponse = mSamReader->transmitCardRequest(samCardRequest,
392 ChannelControl::KEEP_OPEN);
393 } catch (const UnexpectedStatusWordException& e) {
394 throw IllegalStateException(UNEXPECTED_EXCEPTION,
395 std::make_shared<UnexpectedStatusWordException>(e));
396 }
397
398 /* Get transaction result parsing the response */
399 std::vector<std::shared_ptr<ApduResponseApi>> samApduResponses =
400 samCardResponse->getApduResponses();
401
402 if (samApduResponses.empty()) {
403 throw DesynchronizedExchangesException("No response to Digest Authenticate command.");
404 }
405
406 cmdSamDigestAuthenticate->setApduResponse(samApduResponses[0]).checkStatus();
407}
408
409const std::vector<uint8_t> SamCommandProcessor::getEncryptedKey(
410 const std::vector<uint8_t>& poChallenge,
411 const uint8_t cipheringKif,
412 const uint8_t cipheringKvc,
413 const uint8_t sourceKif,
414 const uint8_t sourceKvc)
415{
416 std::vector<std::shared_ptr<AbstractSamCommand>> samCommands;
417
418 if (!mIsDiversificationDone) {
419 /*
420 * Build the SAM Select Diversifier command to provide the SAM with the card S/N
421 * CL-SAM-CSN.1
422 */
423 samCommands.push_back(
424 std::make_shared<CmdSamSelectDiversifier>(mSamProductType,
425 mCalypsoCard->getCalypsoSerialNumberFull()));
426 mIsDiversificationDone = true;
427 }
428
429 samCommands.push_back(std::make_shared<CmdSamGiveRandom>(mSamProductType, poChallenge));
430
431 const size_t cardGenerateKeyCmdIndex = samCommands.size();
432
433 auto cmdSamCardGenerateKey = std::make_shared<CmdSamCardGenerateKey>(mSamProductType,
434 cipheringKif,
435 cipheringKvc,
436 sourceKif,
437 sourceKvc);
438
439 samCommands.push_back(cmdSamCardGenerateKey);
440
441 /* Build a SAM CardRequest */
442 auto samCardRequest = std::make_shared<CardRequestAdapter>(getApduRequests(samCommands), false);
443
444 /* Execute the command */
445 std::shared_ptr<CardResponseApi> samCardResponse;
446 try {
447 samCardResponse = mSamReader->transmitCardRequest(samCardRequest,
448 ChannelControl::KEEP_OPEN);
449 } catch (const UnexpectedStatusWordException& e) {
450 throw IllegalStateException(UNEXPECTED_EXCEPTION,
451 std::make_shared<UnexpectedStatusWordException>(e));
452 }
453
454 std::shared_ptr<ApduResponseApi> cmdSamCardGenerateKeyResponse =
455 samCardResponse->getApduResponses()[cardGenerateKeyCmdIndex];
456
457 /* Check execution status */
458 cmdSamCardGenerateKey->setApduResponse(cmdSamCardGenerateKeyResponse).checkStatus();
459
460 return cmdSamCardGenerateKey->getCipheredData();
461}
462
464 const std::vector<uint8_t>& poChallenge,
465 const std::vector<uint8_t>& currentPin,
466 const std::vector<uint8_t>& newPin)
467{
468 std::vector<std::shared_ptr<AbstractSamCommand>> samCommands;
469 uint8_t pinCipheringKif;
470 uint8_t pinCipheringKvc;
471
472 if (mKif != 0) {
473 /* The current work key has been set (a secure session is open) */
474 pinCipheringKif = mKif;
475 pinCipheringKvc = mKvc;
476 } else {
477 auto adapter = std::dynamic_pointer_cast<CardSecuritySettingAdapter>(mCardSecuritySettings);
478
479 /* No current work key is available (outside secure session) */
480 if (newPin.empty()) {
481 /* PIN verification */
482
483 if (adapter->getPinVerificationCipheringKif() == nullptr ||
484 adapter->getPinVerificationCipheringKvc() == nullptr) {
485 throw IllegalStateException("No KIF or KVC defined for the PIN verification " \
486 "ciphering key");
487 }
488
489 pinCipheringKif = *adapter->getPinVerificationCipheringKif();
490 pinCipheringKvc = *adapter->getPinVerificationCipheringKvc();
491 } else {
492 /* PIN modification */
493 if (adapter->getPinModificationCipheringKif() == nullptr ||
494 adapter->getPinModificationCipheringKvc() == nullptr) {
495 throw IllegalStateException("No KIF or KVC defined for the PIN modification " \
496 "ciphering key");
497 }
498
499 pinCipheringKif = *adapter->getPinModificationCipheringKif();
500 pinCipheringKvc = *adapter->getPinModificationCipheringKvc();
501 }
502 }
503
504 if (!mIsDiversificationDone) {
505 /*
506 * Build the SAM Select Diversifier command to provide the SAM with the card S/N
507 * CL-SAM-CSN.1
508 */
509 samCommands.push_back(
510 std::make_shared<CmdSamSelectDiversifier>(mSamProductType,
511 mCalypsoCard->getCalypsoSerialNumberFull()));
512 mIsDiversificationDone = true;
513 }
514
515 if (mIsDigesterInitialized) {
516 /*
517 * Get the pending SAM ApduRequestAdapter and add it to the current ApduRequestAdapter list
518 */
519 Arrays::addAll(samCommands, getPendingSamCommands(false));
520 }
521
522 samCommands.push_back(std::make_shared<CmdSamGiveRandom>(mSamProductType, poChallenge));
523
524 const size_t cardCipherPinCmdIndex = samCommands.size();
525
526 auto cmdSamCardCipherPin = std::make_shared<CmdSamCardCipherPin>(mSamProductType,
527 pinCipheringKif,
528 pinCipheringKvc,
529 currentPin,
530 newPin);
531
532 samCommands.push_back(cmdSamCardCipherPin);
533
534 /* Build a SAM CardRequest */
535 auto samCardRequest = std::make_shared<CardRequestAdapter>(getApduRequests(samCommands), false);
536
537 /* Execute the command */
538 std::shared_ptr<CardResponseApi> samCardResponse;
539 try {
540 samCardResponse = mSamReader->transmitCardRequest(samCardRequest,
541 ChannelControl::KEEP_OPEN);
542 } catch (const UnexpectedStatusWordException& e) {
543 throw IllegalStateException(UNEXPECTED_EXCEPTION,
544 std::make_shared<UnexpectedStatusWordException>(e));
545 }
546
547 std::shared_ptr<ApduResponseApi> cardCipherPinResponse =
548 samCardResponse->getApduResponses()[cardCipherPinCmdIndex];
549
550 /* Check execution status */
551 cmdSamCardCipherPin->setApduResponse(cardCipherPinResponse).checkStatus();
552
553 return cmdSamCardCipherPin->getCipheredData();
554}
555
556const std::vector<uint8_t> SamCommandProcessor::getSvComplementaryData(
557 const std::shared_ptr<AbstractSamCommand> cmdSamSvPrepare)
558{
559 std::vector<std::shared_ptr<AbstractSamCommand>> samCommands;
560
561 if (!mIsDiversificationDone) {
562 /*
563 * Build the SAM Select Diversifier command to provide the SAM with the card S/N
564 * CL-SAM-CSN.1
565 */
566 samCommands.push_back(
567 std::make_shared<CmdSamSelectDiversifier>(mSamProductType,
568 mCalypsoCard->getCalypsoSerialNumberFull()));
569 mIsDiversificationDone = true;
570 }
571
572 if (mIsDigesterInitialized) {
573 /*
574 * Get the pending SAM ApduRequestAdapter and add it to the current ApduRequestAdapter list
575 */
576 Arrays::addAll(samCommands, getPendingSamCommands(false));
577 }
578
579 const size_t svPrepareOperationCmdIndex = samCommands.size();
580
581 samCommands.push_back(cmdSamSvPrepare);
582
583 /* Build a SAM CardRequest */
584 auto samCardRequest = std::make_shared<CardRequestAdapter>(getApduRequests(samCommands), false);
585
586 /* Execute the command */
587 std::shared_ptr<CardResponseApi> samCardResponse;
588 try {
589 samCardResponse = mSamReader->transmitCardRequest(samCardRequest,
590 ChannelControl::KEEP_OPEN);
591 } catch (const UnexpectedStatusWordException& e) {
592 throw IllegalStateException(UNEXPECTED_EXCEPTION,
593 std::make_shared<UnexpectedStatusWordException>(e));
594 }
595
596 const std::shared_ptr<ApduResponseApi> svPrepareResponse =
597 samCardResponse->getApduResponses()[svPrepareOperationCmdIndex];
598
599 /* Check execution status */
600 cmdSamSvPrepare->setApduResponse(svPrepareResponse).checkStatus();
601
602 std::vector<uint8_t> prepareOperationData = cmdSamSvPrepare->getApduResponse()->getDataOut();
603 std::vector<uint8_t> operationComplementaryData(mSamSerialNumber.size() + prepareOperationData.size());
604
605 System::arraycopy(mSamSerialNumber, 0, operationComplementaryData, 0, mSamSerialNumber.size());
606 System::arraycopy(prepareOperationData,
607 0,
608 operationComplementaryData,
609 mSamSerialNumber.size(),
610 prepareOperationData.size());
611
612 return operationComplementaryData;
613}
614
616 const std::shared_ptr<CmdCardSvReload> cmdCardSvReload,
617 const std::vector<uint8_t>& svGetHeader,
618 const std::vector<uint8_t>& svGetData)
619{
620 /* Get the complementary data from the SAM */
621 const auto cmdSamSvPrepareLoad =
622 std::make_shared<CmdSamSvPrepareLoad>(mSamProductType,
623 svGetHeader,
624 svGetData,
625 cmdCardSvReload->getSvReloadData());
626
627 return getSvComplementaryData(cmdSamSvPrepareLoad);
628}
629
631 const std::shared_ptr<CmdCardSvDebit> cmdCardSvDebit,
632 const std::vector<uint8_t>& svGetHeader,
633 const std::vector<uint8_t>& svGetData)
634{
635 /* Get the complementary data from the SAM */
636 const auto cmdSamSvPrepareDebit =
637 std::make_shared<CmdSamSvPrepareDebit>(mSamProductType,
638 svGetHeader,
639 svGetData,
640 cmdCardSvDebit->getSvDebitData());
641
642 return getSvComplementaryData(cmdSamSvPrepareDebit);
643}
644
646 const std::shared_ptr<CmdCardSvUndebit> cmdCardSvUndebit,
647 const std::vector<uint8_t>& svGetHeader,
648 const std::vector<uint8_t>& svGetData)
649{
650 /* Get the complementary data from the SAM */
651 const auto cmdSamSvPrepareUndebit =
652 std::make_shared<CmdSamSvPrepareUndebit>(mSamProductType,
653 svGetHeader,
654 svGetData,
655 cmdCardSvUndebit->getSvUndebitData());
656
657 return getSvComplementaryData(cmdSamSvPrepareUndebit);
658}
659
660void SamCommandProcessor::checkSvStatus(const std::vector<uint8_t>& svOperationResponseData)
661{
662 std::vector<std::shared_ptr<AbstractSamCommand>> samCommands;
663 const auto cmdSamSvCheck = std::make_shared<CmdSamSvCheck>(mSamProductType,
664 svOperationResponseData);
665 samCommands.push_back(cmdSamSvCheck);
666
667 /* Build a SAM CardRequest */
668 auto samCardRequest = std::dynamic_pointer_cast<CardRequestSpi>(
669 std::make_shared<CardRequestAdapter>(getApduRequests(samCommands),
670 false));
671
672 /* Execute the command */
673 std::shared_ptr<CardResponseApi> samCardResponse;
674 try {
675 samCardResponse = mSamReader->transmitCardRequest(samCardRequest,
676 ChannelControl::KEEP_OPEN);
677 } catch (const UnexpectedStatusWordException& e) {
678 throw IllegalStateException(UNEXPECTED_EXCEPTION,
679 std::make_shared<UnexpectedStatusWordException>(e));
680 }
681
682 const std::shared_ptr<ApduResponseApi> svCheckResponse = samCardResponse->getApduResponses()[0];
683
684 /* Check execution status */
685 cmdSamSvCheck->setApduResponse(svCheckResponse).checkStatus();
686}
687
688}
689}
690}
const std::vector< uint8_t > getEncryptedKey(const std::vector< uint8_t > &poChallenge, const uint8_t cipheringKif, const uint8_t cipheringKvc, const uint8_t sourceKif, const uint8_t sourceKvc)
const std::vector< uint8_t > getSvReloadComplementaryData(const std::shared_ptr< CmdCardSvReload > cmdCardSvReload, const std::vector< uint8_t > &svGetHeader, const std::vector< uint8_t > &svGetData)
const std::shared_ptr< uint8_t > computeKvc(const WriteAccessLevel writeAccessLevel, const std::shared_ptr< uint8_t > kvc) const
const std::vector< uint8_t > getCipheredPinData(const std::vector< uint8_t > &poChallenge, const std::vector< uint8_t > &currentPin, const std::vector< uint8_t > &newPin)
const std::vector< uint8_t > getTerminalSignature()
const std::vector< uint8_t > getSessionTerminalChallenge()
void pushCardExchangedData(const std::vector< std::shared_ptr< ApduRequestSpi > > &requests, const std::vector< std::shared_ptr< ApduResponseApi > > &responses, const int startIndex)
const std::shared_ptr< uint8_t > computeKif(const WriteAccessLevel writeAccessLevel, const std::shared_ptr< uint8_t > kif, const std::shared_ptr< uint8_t > kvc)
const std::vector< uint8_t > getSvUndebitComplementaryData(const std::shared_ptr< CmdCardSvUndebit > cmdCardSvUndebit, const std::vector< uint8_t > &svGetHeader, const std::vector< uint8_t > &svGetData)
const std::vector< uint8_t > getSvDebitComplementaryData(const std::shared_ptr< CmdCardSvDebit > cmdCardSvDebit, const std::vector< uint8_t > &svGetHeader, const std::vector< uint8_t > &svGetData)
SamCommandProcessor(const std::shared_ptr< CalypsoCard > calypsoCard, const std::shared_ptr< CardSecuritySetting > cardSecuritySetting)
void authenticateCardSignature(const std::vector< uint8_t > &cardSignatureLo)
void initializeDigester(const bool sessionEncryption, const bool verificationMode, const uint8_t kif, const uint8_t kvc, const std::vector< uint8_t > &digestData)
void checkSvStatus(const std::vector< uint8_t > &svOperationResponseData)