Keyple Card Calypso C++ Library 2.1.0
Reference Terminal Reader API for C++
CmdCardOpenSession.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
13#include "CmdCardOpenSession.h"
14
15#include <sstream>
16
17/* Keyple Core Util */
18#include "ApduUtil.h"
19#include "Arrays.h"
20#include "ByteArrayUtil.h"
21#include "IllegalArgumentException.h"
22#include "IllegalStateException.h"
23#include "System.h"
24
25/* Keyple Card Calypso */
32
33namespace keyple {
34namespace card {
35namespace calypso {
36
37using namespace keyple::core::util;
38using namespace keyple::core::util::cpp;
39using namespace keyple::core::util::cpp::exception;
40
41/* SECURE SESSION -------------------------------------------------------------------------------- */
42
43CmdCardOpenSession::SecureSession::SecureSession(const std::vector<uint8_t>& challengeTransactionCounter,
44 const std::vector<uint8_t>& challengeRandomNumber,
45 const bool previousSessionRatified,
46 const bool manageSecureSessionAuthorized,
47 const std::shared_ptr<uint8_t> kif,
48 const std::shared_ptr<uint8_t> kvc,
49 const std::vector<uint8_t>& originalData,
50 const std::vector<uint8_t>& secureSessionData)
51: mChallengeTransactionCounter(challengeTransactionCounter),
52 mChallengeRandomNumber(challengeRandomNumber),
53 mPreviousSessionRatified(previousSessionRatified),
54 mManageSecureSessionAuthorized(manageSecureSessionAuthorized),
55 mKif(kif),
56 mKvc(kvc),
57 mOriginalData(originalData),
58 mSecureSessionData(secureSessionData) {}
59
60const std::vector<uint8_t>&
61 CmdCardOpenSession::SecureSession::getChallengeTransactionCounter() const
62{
63 return mChallengeTransactionCounter;
64}
65
66const std::vector<uint8_t>& CmdCardOpenSession::SecureSession::getChallengeRandomNumber() const
67{
68 return mChallengeRandomNumber;
69}
70
71bool CmdCardOpenSession::SecureSession::isPreviousSessionRatified() const
72{
73 return mPreviousSessionRatified;
74}
75
76bool CmdCardOpenSession::SecureSession::isManageSecureSessionAuthorized() const
77{
78 return mManageSecureSessionAuthorized;
79}
80
81const std::shared_ptr<uint8_t> CmdCardOpenSession::SecureSession::getKIF() const
82{
83 return mKif;
84}
85
86const std::shared_ptr<uint8_t> CmdCardOpenSession::SecureSession::getKVC() const
87{
88 return mKvc;
89}
90
91const std::vector<uint8_t>& CmdCardOpenSession::SecureSession::getOriginalData() const
92{
93 return mOriginalData;
94}
95
96const std::vector<uint8_t>& CmdCardOpenSession::SecureSession::getSecureSessionData() const
97{
98 return mSecureSessionData;
99}
100
101/* CMD CARD OPEN SESSIO ------------------------------------------------------------------------- */
102
103const std::map<const int, const std::shared_ptr<StatusProperties>>
104 CmdCardOpenSession::STATUS_TABLE = initStatusTable();
105
106CmdCardOpenSession::CmdCardOpenSession(const std::shared_ptr<CalypsoCard> calypsoCard,
107 const uint8_t debitKeyIndex,
108 const std::vector<uint8_t> sessionTerminalChallenge,
109 const uint8_t sfi,
110 const uint8_t recordNumber)
112 mCalypsoCard(calypsoCard)
113{
114 switch (calypsoCard->getProductType()) {
115 case CalypsoCard::ProductType::PRIME_REVISION_1:
116 createRev10(debitKeyIndex, sessionTerminalChallenge, sfi, recordNumber);
117 break;
118 case CalypsoCard::ProductType::PRIME_REVISION_2:
119 createRev24(debitKeyIndex, sessionTerminalChallenge, sfi, recordNumber);
120 break;
121 case CalypsoCard::ProductType::PRIME_REVISION_3:
122 case CalypsoCard::ProductType::LIGHT:
123 case CalypsoCard::ProductType::BASIC:
124 createRev3(debitKeyIndex, sessionTerminalChallenge, sfi, recordNumber, calypsoCard);
125 break;
126 default:
127 std::stringstream ss;
128 ss << "Product type " << calypsoCard->getProductType() << " isn't supported";
129 throw IllegalArgumentException(ss.str());
130 }
131}
132
133void CmdCardOpenSession::createRev3(const uint8_t keyIndex,
134 const std::vector<uint8_t>& samChallenge,
135 const uint8_t sfi,
136 const uint8_t recordNumber,
137 const std::shared_ptr<CalypsoCard> calypsoCard)
138{
139 mSfi = sfi;
140 mRecordNumber = recordNumber;
141
142 const uint8_t p1 = static_cast<uint8_t>(recordNumber * 8 + keyIndex);
143 uint8_t p2;
144 std::vector<uint8_t> dataIn;
145
146 /* CL-CSS-OSSMODE.1 fullfilled only for SAM C1 */
147 if (!calypsoCard->isExtendedModeSupported()) {
148 p2 = static_cast<uint8_t>(sfi * 8 + 1);
149 dataIn = samChallenge;
150 } else {
151 p2 = static_cast<uint8_t>(sfi * 8 + 2);
152 dataIn = std::vector<uint8_t>(samChallenge.size() + 1);
153 dataIn[0] = 0x00;
154 System::arraycopy(samChallenge, 0, dataIn, 1, samChallenge.size());
155 }
156
157 /*
158 * Case 4: this command contains incoming and outgoing data. We define le = 0, the actual
159 * length will be processed by the lower layers.
160 */
161 const uint8_t le = 0;
162
164 std::make_shared<ApduRequestAdapter>(
165 ApduUtil::build(CalypsoCardClass::ISO.getValue(),
166 CalypsoCardCommand::OPEN_SESSION.getInstructionByte(),
167 p1,
168 p2,
169 dataIn,
170 le)));
171
172 std::stringstream extraInfo;
173 extraInfo << "KEYINDEX:" << keyIndex << ", "
174 << "SFI:" << sfi << "h, "
175 << "REC:" << recordNumber;
176
177 addSubName(extraInfo.str());
178}
179
180void CmdCardOpenSession::createRev24(const uint8_t keyIndex,
181 const std::vector<uint8_t>& samChallenge,
182 const uint8_t sfi,
183 const uint8_t recordNumber)
184{
185 if (keyIndex == 0x00) {
186 throw IllegalArgumentException("Key index can't be zero for rev 2.4!");
187 }
188
189 mSfi = sfi;
190 mRecordNumber = recordNumber;
191
192 const uint8_t p1 = static_cast<uint8_t>(0x80 + recordNumber * 8 + keyIndex);
193
194 buildLegacyApduRequest(keyIndex, samChallenge, sfi, recordNumber, p1);
195}
196
197void CmdCardOpenSession::createRev10(const uint8_t keyIndex,
198 const std::vector<uint8_t>& samChallenge,
199 const uint8_t sfi,
200 const uint8_t recordNumber)
201{
202 if (keyIndex == 0x00) {
203 throw IllegalArgumentException("Key index can't be zero for rev 1.0!");
204 }
205
206 mSfi = sfi;
207 mRecordNumber = recordNumber;
208
209 const uint8_t p1 = static_cast<uint8_t>(recordNumber * 8 + keyIndex);
210
211 buildLegacyApduRequest(keyIndex, samChallenge, sfi, recordNumber, p1);
212}
213
215 const std::vector<uint8_t>& samChallenge,
216 const uint8_t sfi,
217 const uint8_t recordNumber,
218 const uint8_t p1)
219{
220 const uint8_t p2 = static_cast<uint8_t>(sfi * 8);
221
222 /*
223 * Case 4: this command contains incoming and outgoing data. We define le = 0, the actual
224 * length will be processed by the lower layers.
225 */
226 const uint8_t le = 0;
227
229 std::make_shared<ApduRequestAdapter>(
230 ApduUtil::build(CalypsoCardClass::LEGACY.getValue(),
231 CalypsoCardCommand::OPEN_SESSION.getInstructionByte(),
232 p1,
233 p2,
234 samChallenge,
235 le)));
236
237 std::stringstream extraInfo;
238 extraInfo << "KEYINDEX:" << keyIndex << ", "
239 << "SFI:" << sfi << "h, "
240 << "REC:" << recordNumber;
241
242 addSubName(extraInfo.str());
243}
244
246{
247 return false;
248}
249
251{
252 return mSfi;
253}
254
256{
257 return mRecordNumber;
258}
259
261 const std::shared_ptr<ApduResponseApi> apduResponse)
262{
264
265 const std::vector<uint8_t> dataOut = getApduResponse()->getDataOut();
266 if (dataOut.size() > 0) {
267 switch (mCalypsoCard->getProductType()) {
268 case CalypsoCard::ProductType::PRIME_REVISION_1:
269 parseRev10(dataOut);
270 break;
271 case CalypsoCard::ProductType::PRIME_REVISION_2:
272 parseRev24(dataOut);
273 break;
274 default:
275 parseRev3(dataOut);
276 }
277 }
278
279 return *this;
280}
281
282void CmdCardOpenSession::parseRev3(const std::vector<uint8_t>& apduResponseData)
283{
284 bool previousSessionRatified;
285 bool manageSecureSessionAuthorized;
286 int offset;
287
288 /* CL-CSS-OSSRFU.1 */
289 if (!mCalypsoCard->isExtendedModeSupported()) {
290 offset = 0;
291 previousSessionRatified = apduResponseData[4] == 0x00;
292 manageSecureSessionAuthorized = false;
293 } else {
294 offset = 4;
295 previousSessionRatified = (apduResponseData[8] & 0x01) == 0x00;
296 manageSecureSessionAuthorized = (apduResponseData[8] & 0x02) == 0x02;
297 }
298
299 const auto kif = std::make_shared<uint8_t>(apduResponseData[5 + offset]);
300 const auto kvc = std::make_shared<uint8_t>(apduResponseData[6 + offset]);
301 const int dataLength = apduResponseData[7 + offset];
302 const std::vector<uint8_t> data =
303 Arrays::copyOfRange(apduResponseData, 8 + offset, 8 + offset + dataLength);
304
305 mSecureSession = std::shared_ptr<SecureSession>(
306 new SecureSession(
307 Arrays::copyOfRange(apduResponseData, 0, 3),
308 Arrays::copyOfRange(apduResponseData, 3, 4 + offset),
309 previousSessionRatified,
310 manageSecureSessionAuthorized,
311 kif,
312 kvc,
313 data,
314 apduResponseData));
315}
316
317void CmdCardOpenSession::parseRev24(const std::vector<uint8_t>& apduResponseData)
318{
319 bool previousSessionRatified;
320 std::vector<uint8_t> data;
321
322 switch (apduResponseData.size()) {
323 case 5:
324 previousSessionRatified = true;
325 data = std::vector<uint8_t>(0);
326 break;
327 case 34:
328 previousSessionRatified = true;
329 data = Arrays::copyOfRange(apduResponseData, 5, 34);
330 break;
331 case 7:
332 previousSessionRatified = false;
333 data = std::vector<uint8_t>(0);
334 break;
335 case 36:
336 previousSessionRatified = false;
337 data = Arrays::copyOfRange(apduResponseData, 7, 36);
338 break;
339 default:
340 throw IllegalStateException("Bad response length to Open Secure Session: " +
341 std::to_string(apduResponseData.size()));
342 }
343
344 const auto kvc = std::make_shared<uint8_t>(apduResponseData[0]);
345
346 mSecureSession = std::shared_ptr<SecureSession>(
347 new SecureSession(
348 Arrays::copyOfRange(apduResponseData, 1, 4),
349 Arrays::copyOfRange(apduResponseData, 4, 5),
350 previousSessionRatified,
351 false,
352 nullptr,
353 kvc,
354 data,
355 apduResponseData));
356}
357
358void CmdCardOpenSession::parseRev10(const std::vector<uint8_t>& apduResponseData) {
359
360 bool previousSessionRatified;
361 std::vector<uint8_t> data;
362
363 switch (apduResponseData.size()) {
364 case 4:
365 previousSessionRatified = true;
366 data = std::vector<uint8_t>(0);
367 break;
368 case 33:
369 previousSessionRatified = true;
370 data = Arrays::copyOfRange(apduResponseData, 4, 33);
371 break;
372 case 6:
373 previousSessionRatified = false;
374 data = std::vector<uint8_t>(0);
375 break;
376 case 35:
377 previousSessionRatified = false;
378 data = Arrays::copyOfRange(apduResponseData, 6, 35);
379 break;
380 default:
381 throw IllegalStateException("Bad response length to Open Secure Session: " +
382 std::to_string(apduResponseData.size()));
383 }
384
385 /* KVC doesn't exist and is set to null for this type of card */
386 mSecureSession = std::shared_ptr<SecureSession>(
387 new SecureSession(
388 Arrays::copyOfRange(apduResponseData, 0, 3),
389 Arrays::copyOfRange(apduResponseData, 3, 4),
390 previousSessionRatified,
391 false,
392 nullptr,
393 nullptr,
394 data,
395 apduResponseData));
396}
397
398const std::vector<uint8_t>& CmdCardOpenSession::getCardChallenge() const
399{
400 return mSecureSession->getChallengeRandomNumber();
401}
402
404{
405 return ByteArrayUtil::threeBytesToInt(mSecureSession->getChallengeTransactionCounter(), 0);
406}
407
409{
410 return mSecureSession->isPreviousSessionRatified();
411}
412
414{
415 return mSecureSession->isManageSecureSessionAuthorized();
416}
417
418const std::shared_ptr<uint8_t> CmdCardOpenSession::getSelectedKif() const
419{
420 return mSecureSession->getKIF();
421}
422
423const std::shared_ptr<uint8_t> CmdCardOpenSession::getSelectedKvc() const
424{
425 return mSecureSession->getKVC();
426}
427
428const std::vector<uint8_t>& CmdCardOpenSession::getRecordDataRead() const
429{
430 return mSecureSession->getOriginalData();
431}
432
433const std::map<const int, const std::shared_ptr<StatusProperties>>
434 CmdCardOpenSession::initStatusTable()
435{
436 std::map<const int, const std::shared_ptr<StatusProperties>> m =
438
439 m.insert({0x6700,
440 std::make_shared<StatusProperties>("Lc value not supported.",
442 m.insert({0x6900,
443 std::make_shared<StatusProperties>("Transaction Counter is 0",
444 typeid(CardTerminatedException))});
445 m.insert({0x6981,
446 std::make_shared<StatusProperties>("Command forbidden (read requested and current " \
447 "EF is a Binary file).",
448 typeid(CardDataAccessException))});
449 m.insert({0x6982,
450 std::make_shared<StatusProperties>("Security conditions not fulfilled (PIN code " \
451 "not presented, AES key forbidding the " \
452 "compatibility mode, encryption required).",
453 typeid(CardSecurityContextException))});
454 m.insert({0x6985,
455 std::make_shared<StatusProperties>("Access forbidden (Never access mode, Session " \
456 "already opened).",
457 typeid(CardAccessForbiddenException))});
458 m.insert({0x6986,
459 std::make_shared<StatusProperties>("Command not allowed (read requested and no " \
460 "current EF).",
461 typeid(CardDataAccessException))});
462 m.insert({0x6A81,
463 std::make_shared<StatusProperties>("Wrong key index.",
464 typeid(CardIllegalParameterException))});
465 m.insert({0x6A82,
466 std::make_shared<StatusProperties>("File not found.",
467 typeid(CardDataAccessException))});
468 m.insert({0x6A83,
469 std::make_shared<StatusProperties>("Record not found (record index is above NumRec).",
470 typeid(CardDataAccessException))});
471 m.insert({0x6B00,
472 std::make_shared<StatusProperties>("P1 or P2 value not supported (key index " \
473 "incorrect, wrong P2).",
474 typeid(CardIllegalParameterException))});
475 m.insert({0x61FF,
476 std::make_shared<StatusProperties>("Correct execution (ISO7816 T=0).",
477 typeid(nullptr))});
478
479 return m;
480}
481
482const std::map<const int, const std::shared_ptr<StatusProperties>>&
484{
485 return STATUS_TABLE;
486}
487
488}
489}
490}
static const std::map< const int, const std::shared_ptr< StatusProperties > > STATUS_TABLE
virtual void addSubName(const std::string &subName) final
virtual const std::shared_ptr< ApduResponseApi > getApduResponse() const final
virtual void setApduRequest(const std::shared_ptr< ApduRequestAdapter > apduRequest) final
AbstractCardCommand & setApduResponse(const std::shared_ptr< ApduResponseApi > apduResponse) override
static const CalypsoCardClass LEGACY
static const CalypsoCardClass ISO
static const CalypsoCardCommand OPEN_SESSION
void createRev24(const uint8_t keyIndex, const std::vector< uint8_t > &samChallenge, const uint8_t sfi, const uint8_t recordNumber)
const std::vector< uint8_t > & getRecordDataRead() const
const std::vector< uint8_t > & getCardChallenge() const
void createRev3(const uint8_t keyIndex, const std::vector< uint8_t > &samChallenge, const uint8_t sfi, const uint8_t recordNumber, const std::shared_ptr< CalypsoCard > calypsoCard)
const std::map< const int, const std::shared_ptr< StatusProperties > > & getStatusTable() const override
void parseRev24(const std::vector< uint8_t > &apduResponseData)
CmdCardOpenSession & setApduResponse(const std::shared_ptr< ApduResponseApi > apduResponse) override
void buildLegacyApduRequest(const uint8_t keyIndex, const std::vector< uint8_t > &samChallenge, const uint8_t sfi, const uint8_t recordNumber, const uint8_t p1)
const std::shared_ptr< uint8_t > getSelectedKif() const
const std::shared_ptr< uint8_t > getSelectedKvc() const
void parseRev3(const std::vector< uint8_t > &apduResponseData)
void createRev10(const uint8_t keyIndex, const std::vector< uint8_t > &samChallenge, const uint8_t sfi, const uint8_t recordNumber)
void parseRev10(const std::vector< uint8_t > &apduResponseData)