Keyple Card Calypso C++ Library 2.1.0
Reference Terminal Reader API for C++
CalypsoSamSelectionAdapter.cpp
Go to the documentation of this file.
1/**************************************************************************************************
2 * Copyright (c) 2021 Calypso Networks Association https://calypsonet.org/ *
3 * *
4 * See the NOTICE file(s) distributed with this work for additional information regarding *
5 * copyright ownership. *
6 * *
7 * This program and the accompanying materials are made available under the terms of the Eclipse *
8 * Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0 *
9 * *
10 * SPDX-License-Identifier: EPL-2.0 *
11 **************************************************************************************************/
12
14
15/* Calypsonet Terminal Calypso */
16#include "DesynchronizedExchangesException.h"
17
18/* Calypsonet Terminal Card */
19#include "ParseException.h"
20
21/* Keyple Core Util */
22#include "ByteArrayUtil.h"
23#include "KeypleAssert.h"
24#include "PatternSyntaxException.h"
25
26/* Keyple Card Calypso */
27#include "CalypsoSamAdapter.h"
29#include "CardRequestAdapter.h"
31#include "CmdSamUnlock.h"
32
33namespace keyple {
34namespace card {
35namespace calypso {
36
37using namespace calypsonet::terminal::calypso::transaction;
38using namespace calypsonet::terminal::card::spi;
39using namespace keyple::core::util;
40using namespace keyple::core::util::cpp::exception;
41
43: mSamCardSelector(std::make_shared<CardSelectorAdapter>()),
44 mProductType(CalypsoSam::ProductType::UNKNOWN) {}
45
46const std::shared_ptr<CardSelectionRequestSpi> CalypsoSamSelectionAdapter::getCardSelectionRequest()
47{
48 std::vector<std::shared_ptr<ApduRequestSpi>> cardSelectionApduRequests;
49
50 /* Prepare the UNLOCK command if unlock data has been defined */
51 if (!mUnlockData.empty()) {
52 mSamCommands.push_back(
53 std::make_shared<CmdSamUnlock>(mProductType, ByteArrayUtil::fromHex(mUnlockData)));
54 for (const auto& samCommand : mSamCommands) {
55 cardSelectionApduRequests.push_back(samCommand->getApduRequest());
56 }
57 }
58
59 mSamCardSelector->filterByPowerOnData(buildAtrRegex(mProductType, mSerialNumberRegex));
60
61 if (!cardSelectionApduRequests.empty()) {
62 return std::make_shared<CardSelectionRequestAdapter>(
63 mSamCardSelector,
64 std::make_shared<CardRequestAdapter>(cardSelectionApduRequests, false));
65 } else {
66 return std::make_shared<CardSelectionRequestAdapter>(mSamCardSelector, nullptr);
67 }
68}
69
70const std::shared_ptr<SmartCardSpi> CalypsoSamSelectionAdapter::parse(
71 const std::shared_ptr<CardSelectionResponseApi> cardSelectionResponse)
72{
73 if (mSamCommands.size() == 1) {
74 /* An unlock command has been requested */
75 if (cardSelectionResponse->getCardResponse() == nullptr ||
76 cardSelectionResponse->getCardResponse()->getApduResponses().empty()) {
77 throw DesynchronizedExchangesException("Mismatch in the number of requests/responses");
78 }
79
80 const std::shared_ptr<ApduResponseApi> apduResponse =
81 cardSelectionResponse->getCardResponse()->getApduResponses()[0];
82
83 /* Check the SAM response to the unlock command */
84 try {
85 mSamCommands[0]->setApduResponse(apduResponse).checkStatus();
86 } catch (const CalypsoSamCommandException& e) {
87 throw ParseException("An exception occurred while parse the SAM responses.",
88 std::make_shared<CalypsoSamCommandException>(e));
89 }
90 }
91
92 return std::make_shared<CalypsoSamAdapter>(cardSelectionResponse);
93}
94
96 const CalypsoSam::ProductType productType)
97{
98 mProductType = productType;
99
100 return *this;
101}
102
104 const std::string& serialNumberRegex)
105{
106 try {
107 Pattern::compile(serialNumberRegex);
108 } catch (const PatternSyntaxException& exception) {
109 (void)exception;
110 throw IllegalArgumentException("Invalid regular expression: '" +
111 serialNumberRegex +
112 "'.");
113 }
114
115 mSerialNumberRegex = serialNumberRegex;
116
117 return *this;
118}
119
120CalypsoSamSelection& CalypsoSamSelectionAdapter::setUnlockData(const std::string& unlockData)
121{
122 Assert::getInstance().isTrue(unlockData.size() == 16 || unlockData.size() == 32, "length");
123
124 if (!ByteArrayUtil::isValidHexString(unlockData)) {
125 throw IllegalArgumentException("Invalid hexadecimal string.");
126 }
127
128 mUnlockData = unlockData;
129
130 return *this;
131}
132
133const std::string CalypsoSamSelectionAdapter::buildAtrRegex(
134 const CalypsoSam::ProductType productType,
135 const std::string& samSerialNumberRegex)
136{
137 std::string atrRegex;
138 std::string snRegex;
139
140 /* Check if serialNumber is defined */
141 if (samSerialNumberRegex.empty()) {
142 /* Match all serial numbers */
143 snRegex = ".{8}";
144 } else {
145 /* Match the provided serial number (could be a regex substring) */
146 snRegex = samSerialNumberRegex;
147 }
148
149 /*
150 * Build the final Atr regex according to the SAM subtype and serial number if any.
151 *
152 * The header is starting with 3B, its total length is 4 or 6 bytes (8 or 10 hex digits)
153 */
154 std::string applicationTypeMask;
155 if (productType != CalypsoSam::ProductType::UNKNOWN) {
156 switch (productType) {
157 case CalypsoSam::ProductType::SAM_C1:
158 applicationTypeMask = "C1";
159 break;
160 case CalypsoSam::ProductType::SAM_S1DX:
161 applicationTypeMask = "D?";
162 break;
163 case CalypsoSam::ProductType::SAM_S1E1:
164 applicationTypeMask = "E1";
165 break;
166 case CalypsoSam::ProductType::CSAM_F:
167 /* TODO Check what is the expected mask here */
168 applicationTypeMask = "??";
169 break;
170 default:
171 throw IllegalArgumentException("Unknown SAM subtype.");
172 }
173
174 atrRegex = "3B(.{6}|.{10})805A..80" + applicationTypeMask + "20.{4}" + snRegex + "829000";
175 } else {
176 /* Match any ATR */
177 atrRegex = ".*";
178 }
179
180 return atrRegex;
181}
182
183}
184}
185}
CalypsoSamSelection & setUnlockData(const std::string &unlockData) override
CalypsoSamSelection & filterByProductType(const CalypsoSam::ProductType productType) override
const std::shared_ptr< SmartCardSpi > parse(const std::shared_ptr< CardSelectionResponseApi > cardSelectionResponse) override
const std::shared_ptr< CardSelectionRequestSpi > getCardSelectionRequest() override
CalypsoSamSelection & filterBySerialNumber(const std::string &serialNumberRegex) override
CalypsoSam::ProductType ProductType