16#include "InconsistentDataException.h"
17#include "InvalidCardSignatureException.h"
18#include "InvalidSignatureException.h"
19#include "ReaderIOException.h"
20#include "SamIOException.h"
21#include "SamRevokedException.h"
22#include "UnexpectedCommandStatusException.h"
25#include "ProxyReaderApi.h"
33#include "CardBrokenCommunicationException.h"
40#include "CommonSignatureComputationData.h"
41#include "CommonSignatureVerificationData.h"
43#include "ReaderBrokenCommunicationException.h"
44#include "SamSecuritySetting.h"
46#include "SamTransactionManager.h"
49#include "UnexpectedStatusWordException.h"
53#include "ByteArrayUtil.h"
55#include "KeypleAssert.h"
57#include "LoggerFactory.h"
58#include "StringUtils.h"
59#include "UnsupportedOperationException.h"
65using namespace calypsonet::terminal::card;
66using namespace keyple::core::util::cpp;
67using namespace keyple::core::util::cpp::exception;
78 CommonSecuritySetting,
79 CommonSecuritySetting>,
80 public SamTransactionManager {
93 const std::shared_ptr<ProxyReaderApi> samReader,
94 const std::shared_ptr<CalypsoSamAdapter> sam,
95 const std::shared_ptr<SamSecuritySettingAdapter> securitySetting)
99 std::vector<std::vector<uint8_t>>()),
100 mSamReader(samReader),
102 mSecuritySetting(securitySetting),
103 mDefaultKeyDiversifier(sam->getSerialNumber()) {}
118 const std::shared_ptr<SmartCard> targetSmartCard,
120 const std::vector<uint8_t>& defaultKeyDiversifier,
121 const std::vector<std::vector<uint8_t>>& transactionAuditData)
125 transactionAuditData),
126 mSamReader(securitySetting->getControlSamReader()),
127 mSam(securitySetting->getControlSam()),
128 mSecuritySetting(securitySetting),
129 mDefaultKeyDiversifier(defaultKeyDiversifier) {}
149 return std::dynamic_pointer_cast<CardReader>(mSamReader);
174 any_cast<std::shared_ptr<BasicSignatureComputationDataAdapter>>(data);
176 Assert::getInstance().notNull(dataAdapter, MSG_INPUT_OUTPUT_DATA)
177 .isInRange(dataAdapter->getData().size(),
180 "length of data to sign")
181 .isTrue(dataAdapter->getData().size() % 8 == 0,
182 "length of data to sign is a multiple of 8")
183 .isInRange(dataAdapter->getSignatureSize(),
187 .isTrue(dataAdapter->isKeyDiversifierSet() ==
false ||
188 (dataAdapter->getKeyDiversifier().size() >= 1 &&
189 dataAdapter->getKeyDiversifier().size() <= 8),
190 MSG_KEY_DIVERSIFIER_SIZE_IS_IN_RANGE_1_8);
193 mSamCommands.push_back(std::make_shared<CmdSamDataCipher>(mSam, dataAdapter,
nullptr));
197 }
catch (
const std::exception& e) {
206 any_cast<std::shared_ptr<TraceableSignatureComputationDataAdapter>>(data);
208 Assert::getInstance().notNull(dataAdapter, MSG_INPUT_OUTPUT_DATA)
209 .isInRange(dataAdapter->getData().size(),
211 dataAdapter->isSamTraceabilityMode() ? 206 : 208,
212 "length of data to sign")
213 .isInRange(dataAdapter->getSignatureSize(),
217 .isTrue(!dataAdapter->isSamTraceabilityMode() ||
218 (dataAdapter->getTraceabilityOffset() >= 0 &&
219 dataAdapter->getTraceabilityOffset() <=
220 static_cast<int>((dataAdapter->getData().size() * 8) -
221 (dataAdapter->isPartialSamSerialNumber() ?
223 "traceability offset is in range [0.." +
224 std::to_string(((dataAdapter->getData().size() * 8) -
225 (dataAdapter->isPartialSamSerialNumber() ? 7 * 8 : 8 * 8))) +
227 .isTrue(dataAdapter->isKeyDiversifierSet() ==
false ||
228 (dataAdapter->getKeyDiversifier().size() >= 1 &&
229 dataAdapter->getKeyDiversifier().size() <= 8),
230 MSG_KEY_DIVERSIFIER_SIZE_IS_IN_RANGE_1_8);
233 mSamCommands.push_back(
234 std::make_shared<CmdSamPsoComputeSignature>(mSam, dataAdapter));
238 }
catch (
const std::exception& e) {
243 throw IllegalArgumentException(
"The provided data must be an instance of " \
244 "'BasicSignatureComputationDataAdapter' or " \
245 "'TraceableSignatureComputationDataAdapter'");
260 any_cast<std::shared_ptr<BasicSignatureVerificationDataAdapter>>(data);
262 Assert::getInstance().notNull(dataAdapter, MSG_INPUT_OUTPUT_DATA)
263 .isInRange(dataAdapter->getData().size(),
266 "length of signed data to verify")
267 .isTrue(dataAdapter->getData().size() % 8 == 0,
268 "length of data to verify is a multiple of 8")
269 .isInRange(dataAdapter->getSignature().size(),
273 .isTrue(dataAdapter->isKeyDiversifierSet() ==
false ||
274 (dataAdapter->getKeyDiversifier().size() >= 1 &&
275 dataAdapter->getKeyDiversifier().size() <= 8),
276 MSG_KEY_DIVERSIFIER_SIZE_IS_IN_RANGE_1_8);
279 mSamCommands.push_back(
280 std::make_shared<CmdSamDataCipher>(mSam,
nullptr, dataAdapter));
284 }
catch (
const std::exception& e) {
293 any_cast<std::shared_ptr<TraceableSignatureVerificationDataAdapter>>(data);
295 Assert::getInstance().notNull(dataAdapter, MSG_INPUT_OUTPUT_DATA)
296 .isInRange(dataAdapter->getData().size(),
298 dataAdapter->isSamTraceabilityMode() ? 206 : 208,
299 "length of signed data to verify")
300 .isInRange(dataAdapter->getSignature().size(),
304 .isTrue(!dataAdapter->isSamTraceabilityMode() ||
305 (dataAdapter->getTraceabilityOffset() >= 0 &&
306 dataAdapter->getTraceabilityOffset() <=
307 static_cast<int>((dataAdapter->getData().size() * 8) -
308 (dataAdapter->isPartialSamSerialNumber() ?
310 "traceability offset is in range [0.." +
311 std::to_string((dataAdapter->getData().size() * 8) -
312 (dataAdapter->isPartialSamSerialNumber() ? 7 * 8 : 8 * 8)) +
314 .isTrue(dataAdapter->isKeyDiversifierSet() ==
false ||
315 (dataAdapter->getKeyDiversifier().size() >= 1 &&
316 dataAdapter->getKeyDiversifier().size() <= 8),
317 MSG_KEY_DIVERSIFIER_SIZE_IS_IN_RANGE_1_8);
320 if (dataAdapter->isSamRevocationStatusVerificationRequested()) {
322 Assert::getInstance().notNull(mSecuritySetting,
"security settings")
323 .notNull(mSecuritySetting->getSamRevocationServiceSpi(),
324 "SAM revocation service");
327 const std::vector<uint8_t> samSerialNumber =
328 ByteArrayUtil::extractBytes(dataAdapter->getData(),
329 dataAdapter->getTraceabilityOffset(),
330 dataAdapter->isPartialSamSerialNumber() ? 3 : 4);
332 const int samCounterValue =
333 ByteArrayUtil::extractInt(
334 ByteArrayUtil::extractBytes(dataAdapter->getData(),
335 dataAdapter->getTraceabilityOffset() +
336 (dataAdapter->isPartialSamSerialNumber() ?
344 if (mSecuritySetting->getSamRevocationServiceSpi()
345 ->isSamRevoked(samSerialNumber, samCounterValue)) {
347 throw SamRevokedException(
348 StringUtils::format(
"SAM with serial number '%s' and counter value '%d' " \
350 HexUtil::toHex(samSerialNumber).c_str(),
356 mSamCommands.push_back(
357 std::make_shared<CmdSamPsoVerifySignature>(mSam, dataAdapter));
361 }
catch (
const std::bad_cast& e) {
366 }
catch (
const Exception& e) {
373 throw IllegalArgumentException(
"The provided data must be an instance of " \
374 "'CommonSignatureVerificationDataAdapter'");
384 if (mSamCommands.empty()) {
392 const std::vector<std::shared_ptr<ApduRequestSpi>> apduRequests =
396 auto cardRequest = std::make_shared<CardRequestAdapter>(apduRequests,
true);
399 const std::shared_ptr<CardResponseApi> cardResponse = transmitCardRequest(cardRequest);
402 const std::vector<std::shared_ptr<ApduResponseApi>>& apduResponses =
403 cardResponse->getApduResponses();
410 if (apduResponses.size() > apduRequests.size()) {
412 throw InconsistentDataException(
"The number of SAM commands/responses does not " \
413 "match: nb commands = " +
414 std::to_string(apduRequests.size()) +
415 ", nb responses = " +
416 std::to_string(apduResponses.size()) +
425 for (
int i = 0; i < static_cast<int>(apduResponses.size()); i++) {
429 mSamCommands[i]->parseApduResponse(apduResponses[i]);
431 }
catch (
const Exception& ex) {
443 std::dynamic_pointer_cast<AbstractSamCommand>(mSamCommands[i])
450 throw InvalidCardSignatureException(
451 "Invalid card signature.",
452 std::make_shared<CalypsoSamCommandException>(e));
459 throw InvalidSignatureException(
460 "Invalid signature.",
461 std::make_shared<CalypsoSamSecurityDataException>(
470 throw InvalidCardSignatureException(
471 "Invalid SV card signature.",
472 std::make_shared<CalypsoSamSecurityDataException>(
478 }
catch (
const std::bad_cast& e) {
483 }
catch (
const Exception& e) {
490 throw UnexpectedCommandStatusException(
492 "while processing responses to SAM commands: " +
495 std::make_shared<CalypsoSamCommandException>(e));
503 if (apduResponses.size() < apduRequests.size()) {
505 throw InconsistentDataException(
506 "The number of SAM commands/responses does not match:" \
507 " nb commands = " + std::to_string(apduRequests.size()) +
508 ", nb responses = " + std::to_string(apduResponses.size()) +
512 }
catch (
const Exception& e) {
518 mSamCommands.clear();
524 mSamCommands.clear();
554 if (!specificKeyDiversifier.empty()) {
555 if (!Arrays::equals(specificKeyDiversifier, mCurrentKeyDiversifier)) {
556 mCurrentKeyDiversifier = specificKeyDiversifier;
557 prepareSelectDiversifier();
573 if (!Arrays::equals(mCurrentKeyDiversifier, mDefaultKeyDiversifier)) {
574 mCurrentKeyDiversifier = mDefaultKeyDiversifier;
575 prepareSelectDiversifier();
647 const std::unique_ptr<Logger> mLogger =
650 const std::string MSG_INPUT_OUTPUT_DATA =
"input/output data";
651 const std::string MSG_SIGNATURE_SIZE =
"signature size";
652 const std::string MSG_KEY_DIVERSIFIER_SIZE_IS_IN_RANGE_1_8 =
653 "key diversifier size is in range [1..8]";
656 const std::shared_ptr<ProxyReaderApi> mSamReader;
657 const std::shared_ptr<CalypsoSamAdapter> mSam;
658 const std::shared_ptr<CommonSecuritySettingAdapter<CommonSecuritySetting>> mSecuritySetting;
664 std::vector<std::shared_ptr<AbstractApduCommand>> mSamCommands;
665 const std::vector<uint8_t> mDefaultKeyDiversifier;
668 std::vector<uint8_t> mCurrentKeyDiversifier;
677 virtual std::shared_ptr<CardResponseApi> transmitCardRequest(
678 const std::shared_ptr<CardRequestSpi> cardRequest)
680 std::shared_ptr<CardResponseApi> cardResponse =
nullptr;
683 cardResponse = mSamReader->transmitCardRequest(cardRequest, ChannelControl::KEEP_OPEN);
685 }
catch (
const ReaderBrokenCommunicationException& e) {
690 std::make_shared<ReaderBrokenCommunicationException>(e));
692 }
catch (
const CardBrokenCommunicationException& e) {
697 std::make_shared<CardBrokenCommunicationException>(e));
699 }
catch (
const UnexpectedStatusWordException& e) {
700 mLogger->debug(
"A SAM command has failed: %\n", e.getMessage());
701 cardResponse = e.getCardResponse();
715 virtual void prepareSelectDiversifier()
717 mSamCommands.push_back(std::make_shared<CmdSamSelectDiversifier>(mSam,
718 mCurrentKeyDiversifier));
const std::shared_ptr< int > getStatusWord() const
const CardCommand & getCommand() const
static const CalypsoSamCommand PSO_VERIFY_SIGNATURE
static const CalypsoSamCommand SV_CHECK
static const CalypsoSamCommand DIGEST_AUTHENTICATE
static const CalypsoSamCommand DATA_CIPHER
virtual const std::string & getName() const =0
const std::shared_ptr< CalypsoSam > getCalypsoSam() const final
const std::shared_ptr< CardReader > getSamReader() const final
CommonSamTransactionManagerAdapter(const std::shared_ptr< SmartCard > targetSmartCard, const std::shared_ptr< CommonSecuritySettingAdapter< T > > securitySetting, const std::vector< uint8_t > &defaultKeyDiversifier, const std::vector< std::vector< uint8_t > > &transactionAuditData)
virtual std::vector< std::shared_ptr< AbstractApduCommand > > & getSamCommands()
SamTransactionManager & processCommands() override
void prepareSelectDiversifierIfNeeded()
SamTransactionManager & prepareComputeSignature(const any data) override
const std::vector< std::vector< uint8_t > > & getTransactionAuditData() const final
CommonSamTransactionManagerAdapter(const std::shared_ptr< ProxyReaderApi > samReader, const std::shared_ptr< CalypsoSamAdapter > sam, const std::shared_ptr< SamSecuritySettingAdapter > securitySetting)
SamTransactionManager & prepareVerifySignature(const any data) override
void prepareSelectDiversifierIfNeeded(const std::vector< uint8_t > &specificKeyDiversifier)
const std::string getTransactionAuditDataAsString() const
const std::string MSG_SAM_READER_COMMUNICATION_ERROR
virtual void saveTransactionAuditData(const std::shared_ptr< CardRequestSpi > cardRequest, const std::shared_ptr< CardResponseApi > cardResponse)
const std::string MSG_SAM_COMMAND_ERROR
const std::string MSG_SAM_COMMUNICATION_ERROR
const std::string MSG_WHILE_TRANSMITTING_COMMANDS
const std::vector< std::shared_ptr< ApduRequestSpi > > getApduRequests(const std::vector< std::shared_ptr< AbstractApduCommand > > &commands)
const std::vector< std::vector< uint8_t > > & getTransactionAuditData() const override