14#include "keyple/card/calypso/CommandIncreaseOrDecrease.hpp"
21#include "keyple/card/calypso/CalypsoCardAdapter.hpp"
22#include "keyple/card/calypso/CalypsoCardClass.hpp"
23#include "keyple/card/calypso/CardAccessForbiddenException.hpp"
24#include "keyple/card/calypso/CardCommandRef.hpp"
25#include "keyple/card/calypso/CardDataAccessException.hpp"
26#include "keyple/card/calypso/CardDataOutOfBoundsException.hpp"
27#include "keyple/card/calypso/CardIllegalParameterException.hpp"
28#include "keyple/card/calypso/CardSecurityContextException.hpp"
29#include "keyple/card/calypso/CardSessionBufferOverflowException.hpp"
30#include "keyple/core/util/ApduUtil.hpp"
31#include "keyple/core/util/ByteArrayUtil.hpp"
32#include "keyple/core/util/HexUtil.hpp"
33#include "keyple/core/util/cpp/Arrays.hpp"
34#include "keyple/core/util/cpp/System.hpp"
35#include "keyple/core/util/cpp/exception/IllegalStateException.hpp"
41using keyple::core::util::ApduUtil;
42using keyple::core::util::ByteArrayUtil;
43using keyple::core::util::HexUtil;
44using keyple::core::util::cpp::Arrays;
45using keyple::core::util::cpp::System;
46using keyple::core::util::cpp::exception::IllegalStateException;
48const int CommandIncreaseOrDecrease::SW_POSTPONED_DATA = 0x6200;
50const std::map<int, const std::shared_ptr<Command::StatusProperties>>
51 CommandIncreaseOrDecrease::STATUS_TABLE = [] {
52 std::map<int, const std::shared_ptr<Command::StatusProperties>> m(
53 Command::STATUS_TABLE);
57 std::make_shared<Command::StatusProperties>(
58 "Too many modifications in session",
59 typeid(CardSessionBufferOverflowException))},
61 std::make_shared<Command::StatusProperties>(
62 "Lc value not supported",
typeid(CardDataAccessException))},
64 std::make_shared<Command::StatusProperties>(
65 "The current EF is not a Counters or Simulated Counter EF",
66 typeid(CardDataAccessException))},
68 std::make_shared<Command::StatusProperties>(
69 "Security conditions not fulfilled (no session, wrong key, "
70 "encryption required)",
71 typeid(CardSecurityContextException))},
73 std::make_shared<Command::StatusProperties>(
74 "Access forbidden (Never access mode, DF is invalidated, "
76 typeid(CardAccessForbiddenException))},
78 std::make_shared<Command::StatusProperties>(
79 "Command not allowed (no current EF)",
80 typeid(CardDataAccessException))},
82 std::make_shared<Command::StatusProperties>(
83 "Overflow error",
typeid(CardDataOutOfBoundsException))},
85 std::make_shared<Command::StatusProperties>(
86 "File not found",
typeid(CardDataAccessException))},
88 std::make_shared<Command::StatusProperties>(
89 "P1 or P2 value not supported",
90 typeid(CardIllegalParameterException))},
92 std::make_shared<Command::StatusProperties>(
93 "Successful execution (possible only in ISO7816 T=0)",
94 typeid(CardIllegalParameterException))},
96 std::make_shared<Command::StatusProperties>(
97 "Successful execution, response data postponed until session "
99 typeid(CardIllegalParameterException))}});
103CommandIncreaseOrDecrease::CommandIncreaseOrDecrease(
104 bool isDecreaseCommand,
105 const std::shared_ptr<DtoAdapters::TransactionContextDto>&
107 const std::shared_ptr<DtoAdapters::CommandContextDto>& commandContext,
112 isDecreaseCommand ? CardCommandRef::DECREASE : CardCommandRef::INCREASE,
113 std::unique_ptr<int>(new int(3)),
117, mCounterNumber(counterNumber)
118, mIncDecValue(incDecValue)
124 const std::vector<std::uint8_t> valueBuffer
125 = ByteArrayUtil::extractBytes(incDecValue, 3);
127 const std::uint8_t p2 = (sfi * 8);
129 std::shared_ptr<DtoAdapters::ApduRequestAdapter> apduRequest;
131 if (transactionContext->getCard()->getIsCounterValuePostponed() !=
nullptr
132 && *(transactionContext->getCard()->getIsCounterValuePostponed())
139 = std::make_shared<DtoAdapters::ApduRequestAdapter>(ApduUtil::build(
140 transactionContext->getCard()->getCardClass().getValue(),
141 getCommandRef().getInstructionByte(),
142 static_cast<uint8_t
>(counterNumber),
152 = std::make_shared<DtoAdapters::ApduRequestAdapter>(ApduUtil::build(
153 transactionContext->getCard()->getCardClass().getValue(),
154 getCommandRef().getInstructionByte(),
155 static_cast<uint8_t
>(counterNumber),
159 apduRequest->addSuccessfulStatusWord(SW_POSTPONED_DATA);
162 setApduRequest(apduRequest);
164 std::stringstream extraInfo;
165 extraInfo <<
"SFI:" << sfi <<
"h, "
166 <<
"Counter:" << counterNumber <<
","
167 << (isDecreaseCommand ?
"Decrement" :
"Increment") <<
": "
170 addSubName(extraInfo.str());
174CommandIncreaseOrDecrease::finalizeRequest()
176 encryptRequestAndUpdateTerminalSessionMacIfNeeded();
180CommandIncreaseOrDecrease::isCryptoServiceRequiredToFinalizeRequest()
const
182 return getCommandContext()->isEncryptionActive();
186CommandIncreaseOrDecrease::synchronizeCryptoServiceBeforeCardProcessing()
188 if (getCommandContext()->isEncryptionActive()
189 || getTransactionContext()->getCard()->getIsCounterValuePostponed()
194 updateTerminalSessionIfNeeded(buildAnticipatedResponse());
200CommandIncreaseOrDecrease::parseResponse(
201 std::shared_ptr<ApduResponseApi> apduResponse)
203 decryptResponseAndUpdateTerminalSessionMacIfNeeded(apduResponse);
204 if (apduResponse->getDataOut().size() == 0
205 && (getTransactionContext()->getCard()->getIsCounterValuePostponed()
207 || *(getTransactionContext()
209 ->getIsCounterValuePostponed())
211 setExpectedResponseLength(0);
214 Command::setApduResponseAndCheckStatus(apduResponse);
216 if (apduResponse->getStatusWord() == SW_POSTPONED_DATA) {
217 getTransactionContext()->getCard()->setIsCounterValuePostponed(
true);
218 getTransactionContext()->getCard()->setCounter(
220 static_cast<uint8_t
>(mCounterNumber != 0 ? mCounterNumber : 1),
221 buildAnticipatedDataOut());
224 getTransactionContext()->getCard()->setIsCounterValuePostponed(
false);
225 getTransactionContext()->getCard()->setCounter(
227 static_cast<uint8_t
>(mCounterNumber != 0 ? mCounterNumber : 1),
228 apduResponse->getDataOut());
231 updateTerminalSessionIfNeeded();
234const std::map<int, const std::shared_ptr<Command::StatusProperties>>&
235CommandIncreaseOrDecrease::getStatusTable()
const
240std::vector<std::uint8_t>
241CommandIncreaseOrDecrease::buildAnticipatedResponse()
243 std::vector<std::uint8_t> response;
244 if (getTransactionContext()->getCard()->getIsCounterValuePostponed()
246 && *(getTransactionContext()->getCard()->getIsCounterValuePostponed())
254 const std::vector<std::uint8_t> dataOut = buildAnticipatedDataOut();
256 response[0] = dataOut[0];
257 response[1] = dataOut[1];
258 response[2] = dataOut[2];
266std::vector<std::uint8_t>
267CommandIncreaseOrDecrease::buildAnticipatedDataOut()
269 const std::shared_ptr<ElementaryFile> ef
270 = getTransactionContext()->getCard()->getFileBySfi(mSfi);
273 std::shared_ptr<int> oldCounterValue
274 = ef->getData()->getContentAsCounterValue(
275 mCounterNumber != 0 ? mCounterNumber : 1);
276 if (oldCounterValue !=
nullptr) {
277 return ByteArrayUtil::extractBytes(
278 getCommandRef() == CardCommandRef::DECREASE
279 ? *oldCounterValue - mIncDecValue
280 : *oldCounterValue + mIncDecValue,
285 throw IllegalStateException(
286 std::string(
"Unable to determine anticipated APDU response ")
287 +
"because the counter has not been read beforehand. "
288 +
"Command: " + getName() +
", SFI: " + HexUtil::toHex(mSfi)
289 +
"h, Counter: " + std::to_string(mCounterNumber));