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"
64using namespace calypsonet::terminal::card;
65using namespace keyple::core::util::cpp;
77 SamSecuritySettingAdapter>,
78 public SamTransactionManager {
91 const std::shared_ptr<ProxyReaderApi> samReader,
92 const std::shared_ptr<CalypsoSamAdapter> sam,
93 const std::shared_ptr<SamSecuritySettingAdapter> securitySetting)
98 std::vector<std::vector<uint8_t>>()),
99 mSamReader(samReader),
104 mDefaultKeyDiversifier(sam->getSerialNumber()) {}
119 const std::shared_ptr<SmartCard> targetSmartCard,
121 const std::vector<uint8_t>& defaultKeyDiversifier,
122 const std::vector<std::vector<uint8_t>>& transactionAuditData)
127 transactionAuditData),
128 mSamReader(securitySetting->getControlSamReader()),
129 mSam(securitySetting->getControlSam()),
130 mSecuritySetting(securitySetting),
131 mDefaultKeyDiversifier(defaultKeyDiversifier) {}
151 return std::dynamic_pointer_cast<CardReader>(mSamReader);
175 any_cast<std::shared_ptr<BasicSignatureComputationDataAdapter>>(data);
177 Assert::getInstance().notNull(dataAdapter, MSG_INPUT_OUTPUT_DATA)
178 .isInRange(dataAdapter->getData().size(),
181 "length of data to sign")
182 .isTrue(dataAdapter->getData().size() % 8 == 0,
183 "length of data to sign is a multiple of 8")
184 .isInRange(dataAdapter->getSignatureSize(),
188 .isTrue(dataAdapter->isKeyDiversifierSet() ==
false ||
189 (dataAdapter->getKeyDiversifier().size() >= 1 &&
190 dataAdapter->getKeyDiversifier().size() <= 8),
191 MSG_KEY_DIVERSIFIER_SIZE_IS_IN_RANGE_1_8);
194 mSamCommands.push_back(std::make_shared<CmdSamDataCipher>(mSam->getProductType(),
199 }
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(std::make_shared<CmdSamPsoComputeSignature>(
234 mSam->getProductType(),
239 }
catch (
const std::exception& e) {
243 throw IllegalArgumentException(
"The provided data must be an instance of " \
244 "'BasicSignatureComputationDataAdapter' or " \
245 "'TraceableSignatureComputationDataAdapter'");
259 any_cast<std::shared_ptr<BasicSignatureVerificationDataAdapter>>(data);
261 Assert::getInstance().notNull(dataAdapter, MSG_INPUT_OUTPUT_DATA)
262 .isInRange(dataAdapter->getData().size(),
265 "length of signed data to verify")
266 .isTrue(dataAdapter->getData().size() % 8 == 0,
267 "length of data to verify is a multiple of 8")
268 .isInRange(dataAdapter->getSignature().size(),
272 .isTrue(dataAdapter->isKeyDiversifierSet() ==
false ||
273 (dataAdapter->getKeyDiversifier().size() >= 1 &&
274 dataAdapter->getKeyDiversifier().size() <= 8),
275 MSG_KEY_DIVERSIFIER_SIZE_IS_IN_RANGE_1_8);
278 mSamCommands.push_back(std::make_shared<CmdSamDataCipher>(mSam->getProductType(),
284 }
catch (
const std::exception& e) {
291 any_cast<std::shared_ptr<TraceableSignatureVerificationDataAdapter>>(data);
293 Assert::getInstance().notNull(dataAdapter, MSG_INPUT_OUTPUT_DATA)
294 .isInRange(dataAdapter->getData().size(),
296 dataAdapter->isSamTraceabilityMode() ? 206 : 208,
297 "length of signed data to verify")
298 .isInRange(dataAdapter->getSignature().size(),
302 .isTrue(!dataAdapter->isSamTraceabilityMode() ||
303 (dataAdapter->getTraceabilityOffset() >= 0 &&
304 dataAdapter->getTraceabilityOffset() <=
305 static_cast<int>((dataAdapter->getData().size() * 8) -
306 (dataAdapter->isPartialSamSerialNumber() ?
308 "traceability offset is in range [0.." +
309 std::to_string((dataAdapter->getData().size() * 8) -
310 (dataAdapter->isPartialSamSerialNumber() ? 7 * 8 : 8 * 8)) +
312 .isTrue(dataAdapter->isKeyDiversifierSet() ==
false ||
313 (dataAdapter->getKeyDiversifier().size() >= 1 &&
314 dataAdapter->getKeyDiversifier().size() <= 8),
315 MSG_KEY_DIVERSIFIER_SIZE_IS_IN_RANGE_1_8);
318 if (dataAdapter->isSamRevocationStatusVerificationRequested()) {
319 Assert::getInstance().notNull(mSecuritySetting,
"security settings")
320 .notNull(mSecuritySetting->getSamRevocationServiceSpi(),
321 "SAM revocation service");
324 const std::vector<uint8_t> samSerialNumber =
325 ByteArrayUtil::extractBytes(dataAdapter->getData(),
326 dataAdapter->getTraceabilityOffset(),
327 dataAdapter->isPartialSamSerialNumber() ? 3 : 4);
329 const int samCounterValue =
330 ByteArrayUtil::extractInt(
331 ByteArrayUtil::extractBytes(dataAdapter->getData(),
332 dataAdapter->getTraceabilityOffset() +
333 (dataAdapter->isPartialSamSerialNumber() ?
341 if (mSecuritySetting->getSamRevocationServiceSpi()
342 ->isSamRevoked(samSerialNumber, samCounterValue)) {
343 throw SamRevokedException(
344 StringUtils::format(
"SAM with serial number '%s' and counter value '%d' " \
346 HexUtil::toHex(samSerialNumber).c_str(),
352 mSamCommands.push_back(
353 std::make_shared<CmdSamPsoVerifySignature>(mSam->getProductType(), dataAdapter));
357 }
catch (
const std::bad_cast& e) {
361 }
catch (
const Exception& e) {
367 throw IllegalArgumentException(
"The provided data must be an instance of " \
368 "'CommonSignatureVerificationDataAdapter'");
378 if (mSamCommands.empty()) {
384 const std::vector<std::shared_ptr<ApduRequestSpi>> apduRequests =
388 auto cardRequest = std::make_shared<CardRequestAdapter>(apduRequests,
true);
391 const std::shared_ptr<CardResponseApi> cardResponse = transmitCardRequest(cardRequest);
394 const std::vector<std::shared_ptr<ApduResponseApi>>& apduResponses =
395 cardResponse->getApduResponses();
398 std::cout <<
"apduResponses size: " << apduResponses.size() <<
", "
399 <<
"apduRequests size: " << apduRequests.size()
407 if (apduResponses.size() > apduRequests.size()) {
408 throw InconsistentDataException(
"The number of SAM commands/responses does not " \
409 "match: nb commands = " +
410 std::to_string(apduRequests.size()) +
411 ", nb responses = " +
412 std::to_string(apduResponses.size()) +
421 for (
int i = 0; i < static_cast<int>(apduResponses.size()); i++) {
423 mSamCommands[i]->setApduResponse(apduResponses[i]).checkStatus();
425 }
catch (
const Exception& ex) {
435 std::dynamic_pointer_cast<AbstractSamCommand>(mSamCommands[i])
441 throw InvalidCardSignatureException(
442 "Invalid card signature.",
443 std::make_shared<CalypsoSamCommandException>(e));
449 throw InvalidSignatureException(
450 "Invalid signature.",
451 std::make_shared<CalypsoSamSecurityDataException>(
459 throw InvalidCardSignatureException(
460 "Invalid SV card signature.",
461 std::make_shared<CalypsoSamSecurityDataException>(
467 }
catch (
const std::bad_cast& e) {
471 }
catch (
const Exception& e) {
477 throw UnexpectedCommandStatusException(
479 "while processing responses to SAM commands: " +
482 std::make_shared<CalypsoSamCommandException>(e));
490 if (apduResponses.size() < apduRequests.size()) {
491 throw InconsistentDataException(
492 "The number of SAM commands/responses does not match:" \
493 " nb commands = " + std::to_string(apduRequests.size()) +
494 ", nb responses = " + std::to_string(apduResponses.size()) +
498 }
catch (
const Exception& e) {
503 mSamCommands.clear();
509 mSamCommands.clear();
539 if (!specificKeyDiversifier.empty()) {
540 if (!Arrays::equals(specificKeyDiversifier, mCurrentKeyDiversifier)) {
541 mCurrentKeyDiversifier = specificKeyDiversifier;
542 prepareSelectDiversifier();
558 if (!Arrays::equals(mCurrentKeyDiversifier, mDefaultKeyDiversifier)) {
559 mCurrentKeyDiversifier = mDefaultKeyDiversifier;
560 prepareSelectDiversifier();
568 const std::unique_ptr<Logger> mLogger =
571 const std::string MSG_INPUT_OUTPUT_DATA =
"input/output data";
572 const std::string MSG_SIGNATURE_SIZE =
"signature size";
573 const std::string MSG_KEY_DIVERSIFIER_SIZE_IS_IN_RANGE_1_8 =
574 "key diversifier size is in range [1..8]";
577 const std::shared_ptr<ProxyReaderApi> mSamReader;
578 const std::shared_ptr<CalypsoSamAdapter> mSam;
579 const std::shared_ptr<CommonSecuritySettingAdapter<T>> mSecuritySetting;
585 std::vector<std::shared_ptr<AbstractApduCommand>> mSamCommands;
586 const std::vector<uint8_t> mDefaultKeyDiversifier;
589 std::vector<uint8_t> mCurrentKeyDiversifier;
598 virtual std::shared_ptr<CardResponseApi> transmitCardRequest(
599 const std::shared_ptr<CardRequestSpi> cardRequest)
601 std::shared_ptr<CardResponseApi> cardResponse =
nullptr;
604 cardResponse = mSamReader->transmitCardRequest(cardRequest, ChannelControl::KEEP_OPEN);
606 }
catch (
const ReaderBrokenCommunicationException& e) {
611 std::make_shared<ReaderBrokenCommunicationException>(e));
613 }
catch (
const CardBrokenCommunicationException& e) {
618 std::make_shared<CardBrokenCommunicationException>(e));
620 }
catch (
const UnexpectedStatusWordException& e) {
621 mLogger->debug(
"A SAM command has failed: %\n", e.getMessage());
622 cardResponse = e.getCardResponse();
636 virtual void prepareSelectDiversifier()
638 mSamCommands.push_back(std::make_shared<CmdSamSelectDiversifier>(mSam->getProductType(),
639 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