14#include "keyple/card/calypso/Command.hpp"
22#include "keyple/card/calypso/CalypsoCardConstant.hpp"
23#include "keyple/card/calypso/CardAccessForbiddenException.hpp"
24#include "keyple/card/calypso/CardDataAccessException.hpp"
25#include "keyple/card/calypso/CardDataOutOfBoundsException.hpp"
26#include "keyple/card/calypso/CardIllegalArgumentException.hpp"
27#include "keyple/card/calypso/CardIllegalParameterException.hpp"
28#include "keyple/card/calypso/CardPinException.hpp"
29#include "keyple/card/calypso/CardSecurityContextException.hpp"
30#include "keyple/card/calypso/CardSecurityDataException.hpp"
31#include "keyple/card/calypso/CardSessionBufferOverflowException.hpp"
32#include "keyple/card/calypso/CardTerminatedException.hpp"
33#include "keyple/card/calypso/CardUnexpectedResponseLengthException.hpp"
34#include "keyple/card/calypso/CardUnknownStatusException.hpp"
35#include "keyple/core/util/cpp/System.hpp"
36#include "keypop/calypso/card/transaction/CryptoException.hpp"
37#include "keypop/calypso/card/transaction/CryptoIOException.hpp"
38#include "keypop/calypso/crypto/asymmetric/AsymmetricCryptoException.hpp"
39#include "keypop/calypso/crypto/symmetric/SymmetricCryptoException.hpp"
40#include "keypop/calypso/crypto/symmetric/SymmetricCryptoIOException.hpp"
46using keyple::core::util::cpp::System;
47using keypop::calypso::card::transaction::CryptoException;
48using keypop::calypso::card::transaction::CryptoIOException;
49using keypop::calypso::crypto::asymmetric::AsymmetricCryptoException;
50using keypop::calypso::crypto::symmetric::SymmetricCryptoException;
51using keypop::calypso::crypto::symmetric::SymmetricCryptoIOException;
53const std::vector<std::uint8_t> Command::APDU_RESPONSE_9000 = {0x90, 0x00};
55const std::map<int, const std::shared_ptr<Command::StatusProperties>>
56 Command::STATUS_TABLE = [] {
59 std::map<int, const std::shared_ptr<Command::StatusProperties>> m;
62 {{0x9000, std::make_shared<Command::StatusProperties>(
"Success")}});
67 const CardCommandRef& commandRef,
68 std::unique_ptr<int> expectedResponseLength,
69 std::shared_ptr<DtoAdapters::TransactionContextDto> transactionContext,
70 std::shared_ptr<DtoAdapters::CommandContextDto> commandContext)
71: mCommandRef(commandRef)
72, mCommandContext(commandContext)
73, mTransactionContext(transactionContext)
74, mExpectedResponseLength(std::move(expectedResponseLength))
75, mName(commandRef.getName())
76, mIsCryptoServiceSynchronized(false)
81Command::addSubName(
const std::string& subName)
83 mName += (
" - " + subName);
84 mApduRequest->setInfo(mName);
88Command::getCommandRef()
const
94Command::getName()
const
100Command::setApduRequest(
101 std::shared_ptr<DtoAdapters::ApduRequestAdapter> apduRequest)
103 mApduRequest = apduRequest;
104 mApduRequest->setInfo(mName);
108Command::setApduRequestInBestEffortMode(
109 std::shared_ptr<DtoAdapters::ApduRequestAdapter> apduRequest)
111 setApduRequest(apduRequest);
112 if (mCommandContext->isSecureSessionOpen()) {
114 ->addSuccessfulStatusWord(CalypsoCardConstant::SW_FILE_NOT_FOUND)
115 .addSuccessfulStatusWord(CalypsoCardConstant::SW_RECORD_NOT_FOUND);
119std::shared_ptr<DtoAdapters::ApduRequestAdapter>
120Command::getApduRequest()
const
125std::shared_ptr<ApduResponseApi>
126Command::getApduResponse()
const
128 return mApduResponse;
131std::shared_ptr<DtoAdapters::TransactionContextDto>
132Command::getTransactionContext()
const
134 return mTransactionContext;
137std::shared_ptr<DtoAdapters::CommandContextDto>
138Command::getCommandContext()
const
140 return mCommandContext;
144Command::setExpectedResponseLength(std::unique_ptr<int> expectedResponseLength)
146 mExpectedResponseLength = std::move(expectedResponseLength);
150Command::getExpectedResponseLength()
const
152 return mExpectedResponseLength.get();
156Command::confirmCryptoServiceSuccessfullySynchronized()
158 mIsCryptoServiceSynchronized =
true;
162Command::isCryptoServiceSynchronized()
const
164 return mIsCryptoServiceSynchronized;
168Command::parseResponseForSelection(
169 const std::shared_ptr<ApduResponseApi>& apduResponse,
170 std::shared_ptr<CalypsoCardAdapter> calypsoCard)
172 mTransactionContext->setCard(calypsoCard);
173 parseResponse(apduResponse);
177Command::updateTerminalSessionIfNeeded()
179 updateTerminalSessionIfNeeded(mApduResponse->getApdu());
183Command::updateTerminalSessionIfNeeded(
184 const std::vector<std::uint8_t>& apduResponse)
186 if (mIsCryptoServiceSynchronized) {
190 if (mCommandContext->isSecureSessionOpen()) {
191 if (mTransactionContext->isPkiMode()) {
193 std::shared_ptr<AsymmetricCryptoCardTransactionManagerSpi>
194 asymmetricCryptoCardTransactionManagerSpi(
196 ->getAsymmetricCryptoCardTransactionManagerSpi());
198 asymmetricCryptoCardTransactionManagerSpi
199 ->updateTerminalPkiSession(mApduRequest->getApdu());
200 asymmetricCryptoCardTransactionManagerSpi
201 ->updateTerminalPkiSession(apduResponse);
203 }
catch (
const AsymmetricCryptoException& e) {
204 throw CryptoException(e.what(), e);
208 std::shared_ptr<SymmetricCryptoCardTransactionManagerSpi>
209 symmetricCryptoCardTransactionManager(
211 ->getSymmetricCryptoCardTransactionManagerSpi());
214 symmetricCryptoCardTransactionManager->updateTerminalSessionMac(
215 mApduRequest->getApdu());
216 symmetricCryptoCardTransactionManager->updateTerminalSessionMac(
219 }
catch (
const SymmetricCryptoException& e) {
220 throw CryptoException(e.what(), e);
222 }
catch (
const SymmetricCryptoIOException& e) {
223 throw CryptoIOException(e.what(), e);
228 mIsCryptoServiceSynchronized =
true;
232Command::encryptRequestAndUpdateTerminalSessionMacIfNeeded()
234 if (mCommandContext->isEncryptionActive()) {
236 mApduRequest->setApdu(
238 ->getSymmetricCryptoCardTransactionManagerSpi()
239 ->updateTerminalSessionMac(mApduRequest->getApdu()));
241 }
catch (
const SymmetricCryptoException& e) {
242 throw CryptoException(e.what(), e);
244 }
catch (
const SymmetricCryptoIOException& e) {
245 throw CryptoIOException(e.what(), e);
251Command::decryptResponseAndUpdateTerminalSessionMacIfNeeded(
252 std::shared_ptr<ApduResponseApi> apduResponse)
254 if (mCommandContext->isEncryptionActive()) {
256 const std::vector<std::uint8_t> decryptedApdu
257 = mTransactionContext
258 ->getSymmetricCryptoCardTransactionManagerSpi()
259 ->updateTerminalSessionMac(apduResponse->getApdu());
261 apduResponse->setApdu(decryptedApdu);
263 }
catch (
const SymmetricCryptoException& e) {
264 throw CryptoException(e.what(), e);
266 }
catch (
const SymmetricCryptoIOException& e) {
267 throw CryptoIOException(e.what(), e);
270 mIsCryptoServiceSynchronized =
true;
275Command::setApduResponseAndCheckStatus(
276 std::shared_ptr<ApduResponseApi> apduResponse)
278 mApduResponse = apduResponse;
284Command::setApduResponseAndCheckStatusInBestEffortMode(
285 std::shared_ptr<ApduResponseApi> apduResponse)
287 mApduResponse = apduResponse;
292 }
catch (
const CardDataAccessException&) {
293 if (mCommandContext->isSecureSessionOpen()
294 || (apduResponse->getStatusWord()
295 != CalypsoCardConstant::SW_FILE_NOT_FOUND
296 && apduResponse->getStatusWord()
297 != CalypsoCardConstant::SW_RECORD_NOT_FOUND)) {
307const std::map<int, const std::shared_ptr<Command::StatusProperties>>&
308Command::getStatusTable()
const
313std::shared_ptr<Command::StatusProperties>
314Command::getStatusWordProperties()
const
316 const auto statusTable = getStatusTable();
317 auto it = statusTable.find(mApduResponse->getStatusWord());
319 return it != statusTable.end() ? it->second :
nullptr;
323Command::checkStatus()
325 std::shared_ptr<StatusProperties> props = getStatusWordProperties();
327 if (props !=
nullptr && props->isSuccessful()) {
329 if (mExpectedResponseLength !=
nullptr
330 &&
static_cast<int>(mApduResponse->getDataOut().size())
331 != *mExpectedResponseLength) {
332 throw CardUnexpectedResponseLengthException(
333 "APDU response is not the expected length. Command: "
334 + mCommandRef.getName() +
", "
335 +
"Expected: " + std::to_string(*mExpectedResponseLength)
337 + std::to_string(mApduResponse->getDataOut().size()),
348 const std::type_info& exceptionClass
349 = props !=
nullptr ? props->getExceptionClass() :
typeid(
nullptr);
352 const std::string message
353 = props !=
nullptr ? props->getInformation() :
"Unknown status";
356 throwCommandException(exceptionClass, message);
360Command::throwCommandException(
361 const std::type_info& exceptionClass,
const std::string& message)
363 if (exceptionClass ==
typeid(CardAccessForbiddenException)) {
364 throw CardAccessForbiddenException(message, mCommandRef);
365 }
else if (exceptionClass ==
typeid(CardDataAccessException)) {
366 throw CardDataAccessException(message, mCommandRef);
367 }
else if (exceptionClass ==
typeid(CardDataOutOfBoundsException)) {
368 throw CardDataOutOfBoundsException(message, mCommandRef);
369 }
else if (exceptionClass ==
typeid(CardIllegalArgumentException)) {
370 throw CardIllegalArgumentException(message, mCommandRef);
371 }
else if (exceptionClass ==
typeid(CardIllegalParameterException)) {
372 throw CardIllegalParameterException(message, mCommandRef);
373 }
else if (exceptionClass ==
typeid(CardPinException)) {
374 throw CardPinException(message, mCommandRef);
375 }
else if (exceptionClass ==
typeid(CardSecurityContextException)) {
376 throw CardSecurityContextException(message, mCommandRef);
377 }
else if (exceptionClass ==
typeid(CardSecurityDataException)) {
378 throw CardSecurityDataException(message, mCommandRef);
379 }
else if (exceptionClass ==
typeid(CardSessionBufferOverflowException)) {
380 throw CardSessionBufferOverflowException(message, mCommandRef);
381 }
else if (exceptionClass ==
typeid(CardTerminatedException)) {
382 throw CardTerminatedException(message, mCommandRef);
384 throw CardUnknownStatusException(message, mCommandRef);
388Command::StatusProperties::StatusProperties(
const std::string& information)
389: mInformation(information)
391, mExceptionClass(typeid(nullptr))
395Command::StatusProperties::StatusProperties(
396 const std::string& information,
const std::type_info& exceptionClass)
397: mInformation(information)
398, mSuccessful(exceptionClass == typeid(nullptr))
399, mExceptionClass(exceptionClass)
404Command::StatusProperties::getInformation()
const
410Command::StatusProperties::isSuccessful()
const
416Command::StatusProperties::getExceptionClass()
const
418 return mExceptionClass;