Keyple Card Calypso C++ Library 2.2.5.6
Reference Terminal Reader API for C++
CalypsoSamSelectionAdapter.cpp
Go to the documentation of this file.
1/**************************************************************************************************
2 * Copyright (c) 2023 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 Card */
16#include "ParseException.h"
17
18/* Keyple Core Util */
19#include "ByteArrayUtil.h"
20#include "HexUtil.h"
21#include "KeypleAssert.h"
22#include "Pattern.h"
23#include "PatternSyntaxException.h"
24#include "RuntimeException.h"
25
26/* Keyple Card Calypso */
28#include "CalypsoSamAdapter.h"
30#include "CardRequestAdapter.h"
32#include "CmdSamUnlock.h"
33
34namespace keyple {
35namespace card {
36namespace calypso {
37
38using namespace calypsonet::terminal::card::spi;
39using namespace keyple::core::util;
40using namespace keyple::core::util::cpp;
41using namespace keyple::core::util::cpp::exception;
42
43const int CalypsoSamSelectionAdapter::SW_NOT_LOCKED = 0x6985;
44
46: mSamCardSelector(std::make_shared<CardSelectorAdapter>()) {}
47
48const std::shared_ptr<CardSelectionRequestSpi> CalypsoSamSelectionAdapter::getCardSelectionRequest()
49{
50 mSamCardSelector->filterByPowerOnData(buildAtrRegex(mProductType, mSerialNumberRegex));
51
52 /* Prepare the UNLOCK command if unlock data has been defined */
53 if (mUnlockCommand != nullptr) {
54 std::vector<std::shared_ptr<ApduRequestSpi>> cardSelectionApduRequests;
55 std::shared_ptr<ApduRequestAdapter> request = mUnlockCommand->getApduRequest();
56 request->addSuccessfulStatusWord(SW_NOT_LOCKED);
57 cardSelectionApduRequests.push_back(request);
58 return std::make_shared<CardSelectionRequestAdapter>(
59 mSamCardSelector,
60 std::make_shared<CardRequestAdapter>(cardSelectionApduRequests, false));
61 } else {
62 return std::make_shared<CardSelectionRequestAdapter>(mSamCardSelector, nullptr);
63 }
64}
65
66const std::shared_ptr<SmartCardSpi> CalypsoSamSelectionAdapter::parse(
67 const std::shared_ptr<CardSelectionResponseApi> cardSelectionResponse)
68{
69 if (mUnlockCommand != nullptr) {
70
71 /* An unlock command has been requested */
72 if (cardSelectionResponse->getCardResponse() == nullptr ||
73 cardSelectionResponse->getCardResponse()->getApduResponses().empty()) {
74 throw ParseException("Mismatch in the number of requests/responses");
75 }
76
77 /* Check the SAM response to the unlock command */
78 const std::shared_ptr<ApduResponseApi> apduResponse =
79 cardSelectionResponse->getCardResponse()->getApduResponses()[0];
80
81 /* Check the SAM response to the unlock command */
82 try {
83 mUnlockCommand->parseApduResponse(apduResponse);
84 } catch (const CalypsoSamAccessForbiddenException& e) {
85 (void)e;
86 mLogger->warn("SAM not locked or already unlocked\n");
87 } catch (const CalypsoSamCommandException& e) {
88 throw ParseException("An exception occurred while parsing the SAM response.",
89 std::make_shared<CalypsoSamCommandException>(e));
90 }
91 }
92
93 try {
94
95 return std::make_shared<CalypsoSamAdapter>(cardSelectionResponse);
96
97 } catch (const RuntimeException& e) {
98
99 throw ParseException("An exception occurred while parsing the SAM response.",
100 std::make_shared<RuntimeException>(e));
101 }
102}
103
105 const CalypsoSam::ProductType productType)
106{
107 mProductType = productType;
108
109 return *this;
110}
111
113 const std::string& serialNumberRegex)
114{
115 try {
116 Pattern::compile(serialNumberRegex);
117 } catch (const PatternSyntaxException& exception) {
118 (void)exception;
119 throw IllegalArgumentException("Invalid regular expression: '" +
120 serialNumberRegex +
121 "'.");
122 }
123
124 mSerialNumberRegex = serialNumberRegex;
125
126 return *this;
127}
128
129CalypsoSamSelection& CalypsoSamSelectionAdapter::setUnlockData(const std::string& unlockData)
130{
131 Assert::getInstance().isTrue(unlockData.size() == 16 || unlockData.size() == 32,
132 "unlock data length == 16 or 32")
133 .isHexString(unlockData, "unlockData");
134
135 if (!ByteArrayUtil::isValidHexString(unlockData)) {
136 throw IllegalArgumentException("Invalid hexadecimal string.");
137 }
138
139 mUnlockCommand = std::make_shared<CmdSamUnlock>(mProductType, HexUtil::toByteArray(unlockData));
140
141 return *this;
142}
143
144const std::string CalypsoSamSelectionAdapter::buildAtrRegex(
145 const CalypsoSam::ProductType productType,
146 const std::string& samSerialNumberRegex)
147{
148 std::string atrRegex;
149 std::string snRegex;
150
151 /* Check if serialNumber is defined */
152 if (samSerialNumberRegex.empty()) {
153 /* Match all serial numbers */
154 snRegex = ".{8}";
155 } else {
156 /* Match the provided serial number (could be a regex substring) */
157 snRegex = samSerialNumberRegex;
158 }
159
160 /*
161 * Build the final Atr regex according to the SAM subtype and serial number if any.
162 *
163 * The header is starting with 3B, its total length is 4 or 6 bytes (8 or 10 hex digits)
164 */
165 std::string applicationTypeMask;
166 if (productType != CalypsoSam::ProductType::UNKNOWN) {
167 switch (productType) {
168 case CalypsoSam::ProductType::SAM_C1:
169 case CalypsoSam::ProductType::HSM_C1:
170 applicationTypeMask = "C1";
171 break;
172 case CalypsoSam::ProductType::SAM_S1DX:
173 applicationTypeMask = "D?";
174 break;
175 case CalypsoSam::ProductType::SAM_S1E1:
176 applicationTypeMask = "E1";
177 break;
178 case CalypsoSam::ProductType::CSAM_F:
179 /* TODO Check what is the expected mask here */
180 applicationTypeMask = "??";
181 break;
182 default:
183 throw IllegalArgumentException("Unknown SAM subtype.");
184 }
185
186 atrRegex = "3B(.{6}|.{10})805A..80" + applicationTypeMask + ".{6}" + snRegex + "829000";
187 } else {
188 /* Match any ATR */
189 atrRegex = ".*";
190 }
191
192 return atrRegex;
193}
194
195}
196}
197}
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