14#include "keyple/card/calypso/CommandSvDebitOrUndebit.hpp"
21#include "keyple/card/calypso/CalypsoCardAdapter.hpp"
22#include "keyple/card/calypso/CalypsoCardConstant.hpp"
23#include "keyple/card/calypso/CardAccessForbiddenException.hpp"
24#include "keyple/card/calypso/CardIllegalParameterException.hpp"
25#include "keyple/card/calypso/CardSecurityDataException.hpp"
26#include "keyple/card/calypso/CardSessionBufferOverflowException.hpp"
27#include "keyple/card/calypso/CardTerminatedException.hpp"
28#include "keyple/core/util/ApduUtil.hpp"
29#include "keyple/core/util/ByteArrayUtil.hpp"
30#include "keyple/core/util/cpp/Arrays.hpp"
31#include "keyple/core/util/cpp/System.hpp"
32#include "keyple/core/util/cpp/exception/IllegalStateException.hpp"
33#include "keypop/calypso/card/transaction/CardSignatureNotVerifiableException.hpp"
34#include "keypop/calypso/card/transaction/CryptoException.hpp"
35#include "keypop/calypso/card/transaction/CryptoIOException.hpp"
36#include "keypop/calypso/card/transaction/InvalidCardSignatureException.hpp"
37#include "keypop/calypso/crypto/symmetric/SymmetricCryptoException.hpp"
38#include "keypop/calypso/crypto/symmetric/SymmetricCryptoIOException.hpp"
44using keyple::core::util::ApduUtil;
45using keyple::core::util::ByteArrayUtil;
46using keyple::core::util::cpp::Arrays;
47using keyple::core::util::cpp::System;
48using keyple::core::util::cpp::exception::IllegalStateException;
49using keypop::calypso::card::transaction::CardSignatureNotVerifiableException;
50using keypop::calypso::card::transaction::CryptoException;
51using keypop::calypso::card::transaction::CryptoIOException;
52using keypop::calypso::card::transaction::InvalidCardSignatureException;
53using keypop::calypso::crypto::symmetric::SymmetricCryptoException;
54using keypop::calypso::crypto::symmetric::SymmetricCryptoIOException;
56const std::string CommandSvDebitOrUndebit::MSG_CARD_SV_MAC_NOT_VERIFIABLE
57 =
"Unable to verify the card SV MAC associated to the SV operation";
58const std::string CommandSvDebitOrUndebit::MSG_INVALID_CARD_SESSION_MAC
59 =
"Invalid card session MAC";
60const int CommandSvDebitOrUndebit::SW_POSTPONED_DATA = 0x6200;
62const std::map<int, const std::shared_ptr<Command::StatusProperties>>
63 CommandSvDebitOrUndebit::STATUS_TABLE = [] {
64 std::map<int, const std::shared_ptr<Command::StatusProperties>> m(
65 Command::STATUS_TABLE);
69 std::make_shared<StatusProperties>(
70 "Too many modifications in session",
71 typeid(CardSessionBufferOverflowException))},
73 std::make_shared<StatusProperties>(
74 "Lc value not supported",
75 typeid(CardIllegalParameterException))},
77 std::make_shared<StatusProperties>(
78 "Transaction counter is 0 or SV TNum is FFFEh or FFFFh",
79 typeid(CardTerminatedException))},
81 std::make_shared<StatusProperties>(
82 "Preconditions not satisfied",
83 typeid(CardAccessForbiddenException))},
85 std::make_shared<StatusProperties>(
86 "Incorrect signatureHi",
typeid(CardSecurityDataException))},
88 std::make_shared<StatusProperties>(
89 "Successful execution, response data postponed until session "
94CommandSvDebitOrUndebit::CommandSvDebitOrUndebit(
96 const std::shared_ptr<DtoAdapters::TransactionContextDto>&
98 const std::shared_ptr<DtoAdapters::CommandContextDto>& commandContext,
100 const std::vector<std::uint8_t>& date,
101 const std::vector<std::uint8_t>& time,
102 bool isExtendedModeAllowed,
103 bool isSvNegativeBalanceAuthorized)
105 isDebitCommand ? CardCommandRef::SV_DEBIT : CardCommandRef::SV_UNDEBIT,
106 std::unique_ptr<int>(new int(computeExpectedResponseLength(
107 commandContext, isExtendedModeAllowed))),
113, mIsDebitCommand(isDebitCommand)
114, mIsExtendedModeAllowed(isExtendedModeAllowed)
115, mIsSvNegativeBalanceAuthorized(isSvNegativeBalanceAuthorized)
121 mDataIn = std::vector<std::uint8_t>(15 + (isExtendedModeAllowed ? 10 : 5));
124 const std::uint16_t amountShort = isDebitCommand
125 ?
static_cast<std::uint16_t
>(-amount)
126 :
static_cast<std::uint16_t
>(amount);
127 ByteArrayUtil::copyBytes(amountShort, mDataIn, 1, 2);
128 mDataIn[3] = date[0];
129 mDataIn[4] = date[1];
130 mDataIn[5] = time[0];
131 mDataIn[6] = time[1];
132 mDataIn[7] = transactionContext->getCard()->getSvKvc();
139 std::unique_ptr<std::uint8_t> le(
140 computeLe(commandContext, isExtendedModeAllowed));
142 std::vector<std::uint8_t> apdu;
144 apdu = ApduUtil::build(0, 0, 0, 0, mDataIn);
147 apdu = ApduUtil::build(0, 0, 0, 0, mDataIn, *le.get());
150 setApduRequest(std::make_shared<DtoAdapters::ApduRequestAdapter>(apdu));
154CommandSvDebitOrUndebit::finalizeRequest()
156 if (mIsDebitCommand && !mIsSvNegativeBalanceAuthorized
157 && (getTransactionContext()->getCard()->getSvBalance() - mAmount) < 0) {
158 throw IllegalStateException(
"Negative balances are not allowed");
161 auto svCommandSecurityData(
162 std::make_shared<DtoAdapters::SvCommandSecurityDataApiAdapter>());
163 svCommandSecurityData->setSvGetRequest(
164 getTransactionContext()->getCard()->getSvGetHeader());
165 svCommandSecurityData->setSvGetResponse(
166 getTransactionContext()->getCard()->getSvGetData());
167 svCommandSecurityData->setSvCommandPartialRequest(
168 getSvDebitOrUndebitData());
171 getTransactionContext()
172 ->getSymmetricCryptoCardTransactionManagerSpi()
173 ->computeSvCommandSecurityData(svCommandSecurityData);
175 }
catch (
const SymmetricCryptoException& e) {
176 throw CryptoException(e.what(), e);
178 }
catch (
const SymmetricCryptoIOException& e) {
179 throw CryptoIOException(e.what(), e);
182 finalizeCommand(svCommandSecurityData);
183 encryptRequestAndUpdateTerminalSessionMacIfNeeded();
187CommandSvDebitOrUndebit::isCryptoServiceRequiredToFinalizeRequest()
const
193CommandSvDebitOrUndebit::synchronizeCryptoServiceBeforeCardProcessing()
199CommandSvDebitOrUndebit::parseResponse(
200 std::shared_ptr<ApduResponseApi> apduResponse)
202 decryptResponseAndUpdateTerminalSessionMacIfNeeded(apduResponse);
203 Command::setApduResponseAndCheckStatus(apduResponse);
205 if (apduResponse->getDataOut().size() != 0
206 && apduResponse->getDataOut().size() != 3
207 && apduResponse->getDataOut().size() != 6) {
208 throw IllegalStateException(
209 "SV Debit/Undebit response is not the correct length. Expected: "
211 + std::to_string(apduResponse->getDataOut().size()));
214 std::shared_ptr<CalypsoCardAdapter> calypsoCard
215 = getTransactionContext()->getCard();
216 calypsoCard->setSvOperationSignature(apduResponse->getDataOut());
217 updateCalypsoCardSvHistory(calypsoCard);
218 updateTerminalSessionIfNeeded();
220 if (!getCommandContext()->isSecureSessionOpen()) {
222 if (!getTransactionContext()
223 ->getSymmetricCryptoCardTransactionManagerSpi()
225 getTransactionContext()
227 ->getSvOperationSignature())) {
228 throw InvalidCardSignatureException(
229 MSG_INVALID_CARD_SESSION_MAC);
232 }
catch (
const SymmetricCryptoIOException& e) {
233 throw CardSignatureNotVerifiableException(
234 MSG_CARD_SV_MAC_NOT_VERIFIABLE, e);
236 }
catch (
const SymmetricCryptoException& e) {
237 throw CryptoIOException(e.what(), e);
242const std::map<int, const std::shared_ptr<Command::StatusProperties>>&
243CommandSvDebitOrUndebit::getStatusTable()
const
249CommandSvDebitOrUndebit::computeExpectedResponseLength(
250 const std::shared_ptr<DtoAdapters::CommandContextDto>& commandContext,
251 bool isExtendedModeAllowed)
253 if (commandContext->isSecureSessionOpen()) {
256 return isExtendedModeAllowed ? 6 : 3;
260std::unique_ptr<std::uint8_t>
261CommandSvDebitOrUndebit::computeLe(
262 const std::shared_ptr<DtoAdapters::CommandContextDto>& commandContext,
263 bool isExtendedModeAllowed)
265 if (commandContext->isSecureSessionOpen()) {
268 return std::unique_ptr<std::uint8_t>(
269 new std::uint8_t(isExtendedModeAllowed ? 6 : 3));
274CommandSvDebitOrUndebit::finalizeCommand(
275 std::shared_ptr<DtoAdapters::SvCommandSecurityDataApiAdapter>
276 svCommandSecurityData)
278 const std::uint8_t p1 = svCommandSecurityData->getTerminalChallenge()[0];
279 std::uint8_t p2 = svCommandSecurityData->getTerminalChallenge()[1];
280 mDataIn[0] = svCommandSecurityData->getTerminalChallenge()[2];
282 svCommandSecurityData->getSerialNumber(), 0, mDataIn, 8, 4);
284 svCommandSecurityData->getTransactionNumber(), 0, mDataIn, 12, 3);
286 svCommandSecurityData->getTerminalSvMac(),
290 svCommandSecurityData->getTerminalSvMac().size());
294 std::make_shared<DtoAdapters::ApduRequestAdapter>(ApduUtil::build(
295 getTransactionContext()->getCard()->getCardClass()
296 == CalypsoCardClass::LEGACY
297 ? CalypsoCardClass::LEGACY_STORED_VALUE.getValue()
298 : CalypsoCardClass::ISO.getValue(),
299 getCommandRef().getInstructionByte(),
303 *computeLe(getCommandContext(), mIsExtendedModeAllowed))));
304 apdu->addSuccessfulStatusWord(SW_POSTPONED_DATA);
305 setApduRequest(apdu);
308std::vector<std::uint8_t>
309CommandSvDebitOrUndebit::getSvDebitOrUndebitData()
311 std::vector<std::uint8_t> svDebitOrUndebitData(12);
312 svDebitOrUndebitData[0] = getCommandRef().getInstructionByte();
318 svDebitOrUndebitData[3] = mIsExtendedModeAllowed ? 0x19 : 0x14;
321 System::arraycopy(mDataIn, 0, svDebitOrUndebitData, 4, 8);
323 return svDebitOrUndebitData;
327CommandSvDebitOrUndebit::updateCalypsoCardSvHistory(
328 std::shared_ptr<CalypsoCardAdapter> calypsoCard)
330 const int balance = calypsoCard->getSvBalance() - mAmount;
331 calypsoCard->updateSvData(balance, calypsoCard->getSvLastTNum() + 1);
333 std::vector<std::uint8_t> debitLog(19);
334 System::arraycopy(getApduRequest()->getApdu(), 6, debitLog, 0, 14);
335 ByteArrayUtil::copyBytes(balance, debitLog, 14, 3);
336 ByteArrayUtil::copyBytes(calypsoCard->getSvLastTNum(), debitLog, 17, 2);
337 calypsoCard->addCyclicContent(
338 CalypsoCardConstant::SV_DEBIT_LOG_FILE_SFI, debitLog);