14#include "keyple/card/calypso/CommandReadBinary.hpp"
22#include "keyple/card/calypso/CalypsoCardAdapter.hpp"
23#include "keyple/card/calypso/CardAccessForbiddenException.hpp"
24#include "keyple/card/calypso/CardDataAccessException.hpp"
25#include "keyple/card/calypso/CardIllegalParameterException.hpp"
26#include "keyple/card/calypso/CardSecurityContextException.hpp"
27#include "keyple/core/util/ApduUtil.hpp"
28#include "keyple/core/util/HexUtil.hpp"
29#include "keyple/core/util/cpp/Arrays.hpp"
30#include "keyple/core/util/cpp/System.hpp"
31#include "keyple/core/util/cpp/exception/IndexOutOfBoundsException.hpp"
37using keyple::core::util::ApduUtil;
38using keyple::core::util::HexUtil;
39using keyple::core::util::cpp::Arrays;
40using keyple::core::util::cpp::System;
41using keyple::core::util::cpp::exception::IndexOutOfBoundsException;
43const std::map<int, const std::shared_ptr<Command::StatusProperties>>
44 CommandReadBinary::STATUS_TABLE = [] {
45 std::map<int, const std::shared_ptr<Command::StatusProperties>> m(
46 Command::STATUS_TABLE);
50 std::make_shared<StatusProperties>(
51 "Incorrect EF type: not a Binary EF",
52 typeid(CardDataAccessException))},
54 std::make_shared<StatusProperties>(
55 "Security conditions not fulfilled (PIN code not presented, "
56 "encryption required)",
57 typeid(CardSecurityContextException))},
59 std::make_shared<StatusProperties>(
60 "Access forbidden (Never access mode)",
61 typeid(CardAccessForbiddenException))},
63 std::make_shared<StatusProperties>(
64 std::string(
"Incorrect file type: the Current File is not an")
65 +
"EF Supersedes 6981h",
66 typeid(CardDataAccessException))},
68 std::make_shared<StatusProperties>(
69 "File not found",
typeid(CardDataAccessException))},
71 std::make_shared<StatusProperties>(
72 "Offset not in the file (offset overflow)",
73 typeid(CardDataAccessException))},
75 std::make_shared<StatusProperties>(
76 "P1 value not supported",
77 typeid(CardIllegalParameterException))}});
81CommandReadBinary::CommandReadBinary(
82 const std::shared_ptr<DtoAdapters::TransactionContextDto>&
84 const std::shared_ptr<DtoAdapters::CommandContextDto>& commandContext,
89 CardCommandRef::READ_BINARY,
90 std::unique_ptr<int>(new int(length)),
96 const std::uint8_t cardClass
97 = transactionContext->getCard() !=
nullptr
98 ? transactionContext->getCard()->getCardClass().getValue()
99 : CalypsoCardClass::ISO.getValue();
101 = transactionContext->getCard() !=
nullptr
102 && transactionContext->getCard()->getPreOpenWriteAccessLevel()
103 != WriteAccessLevel::UNKOWN;
105 std::uint8_t msb =
static_cast<std::uint8_t
>(
106 offset >> std::numeric_limits<std::uint8_t>::digits);
107 std::uint8_t lsb =
static_cast<std::uint8_t
>(offset & 0xFF);
113 const std::uint8_t p1 = msb > 0 ? msb : (0x80 + sfi);
116 setApduRequestInBestEffortMode(
117 std::make_shared<DtoAdapters::ApduRequestAdapter>(ApduUtil::build(
119 getCommandRef().getInstructionByte(),
122 static_cast<uint8_t
>(length))));
125 std::string(
"SFI: ") + HexUtil::toHex(sfi) +
"h," +
"Offset: "
126 + std::to_string(offset) +
"," +
"Length: " + std::to_string(length));
130CommandReadBinary::finalizeRequest()
132 encryptRequestAndUpdateTerminalSessionMacIfNeeded();
136CommandReadBinary::isCryptoServiceRequiredToFinalizeRequest()
const
138 return getCommandContext()->isEncryptionActive();
142CommandReadBinary::synchronizeCryptoServiceBeforeCardProcessing()
144 if (!getCommandContext()->isSecureSessionOpen()) {
148 if (getCommandContext()->isEncryptionActive()) {
152 if (!mIsPreOpenMode) {
157 if (!isCryptoServiceSynchronized()) {
158 const std::vector<std::uint8_t> anticipatedApduResponse
159 = buildAnticipatedResponse();
160 if (anticipatedApduResponse.empty()) {
161 const std::string sfiHex = HexUtil::toHex(mSfi);
163 std::string(
"Unable to determine anticipated APDU response ")
164 +
"because the record or some records have not been read "
165 +
"beforehand [command={}, sfi={}, offset={}, length={}]",
169 getExpectedResponseLength());
173 mAnticipatedDataOut = Arrays::copyOf(
174 anticipatedApduResponse, anticipatedApduResponse.size() - 2);
175 updateTerminalSessionIfNeeded(anticipatedApduResponse);
181std::vector<std::uint8_t>
182CommandReadBinary::buildAnticipatedResponse()
const
184 std::shared_ptr<ElementaryFile> ef
185 = getTransactionContext()->getCard()->getFileBySfi(mSfi);
191 const std::vector<std::uint8_t> content = ef->getData()->getContent(
193 static_cast<uint8_t
>(mOffset),
194 static_cast<uint8_t
>(*getExpectedResponseLength()));
195 std::vector<std::uint8_t> apdu(*getExpectedResponseLength() + 2);
197 System::arraycopy(content, 0, apdu, 0, *getExpectedResponseLength());
199 apdu[*getExpectedResponseLength()] = 0x90;
202 }
catch (
const IndexOutOfBoundsException&) {
210CommandReadBinary::parseResponse(std::shared_ptr<ApduResponseApi> apduResponse)
212 decryptResponseAndUpdateTerminalSessionMacIfNeeded(apduResponse);
213 if (!setApduResponseAndCheckStatusInBestEffortMode(apduResponse)) {
217 getTransactionContext()->getCard()->setContent(
218 mSfi, 1, apduResponse->getDataOut(), mOffset);
219 if (!isCryptoServiceSynchronized()) {
220 updateTerminalSessionIfNeeded();
222 getCommandContext()->isSecureSessionOpen() && mIsPreOpenMode
223 && !Arrays::equals(apduResponse->getDataOut(), mAnticipatedDataOut)) {
224 throw CardSecurityContextException(
225 "Data out does not match the anticipated data out",
226 CardCommandRef::READ_BINARY);
230const std::map<int, const std::shared_ptr<Command::StatusProperties>>&
231CommandReadBinary::getStatusTable()
const