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