Keyple Card Calypso C++ Library 2.2.5.6
Reference Terminal Reader API for C++
CmdCardOpenSession.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
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<CalypsoCardAdapter> calypsoCard,
107 const uint8_t keyIndex,
108 const std::vector<uint8_t>& samChallenge,
109 const uint8_t sfi,
110 const uint8_t recordNumber,
111 const uint8_t recordSize,
112 const bool isExtendedModeAllowed)
113: AbstractCardCommand(CalypsoCardCommand::OPEN_SESSION, -1, calypsoCard),
114 mRecordSize(recordSize),
115 mIsExtendedModeAllowed(isExtendedModeAllowed)
116{
117 switch (getCalypsoCard()->getProductType()) {
118
119 case CalypsoCard::ProductType::PRIME_REVISION_1:
120 createRev10(keyIndex, samChallenge, sfi, recordNumber);
121 break;
122
123 case CalypsoCard::ProductType::PRIME_REVISION_2:
124 createRev24(keyIndex, samChallenge, sfi, recordNumber);
125 break;
126
127 case CalypsoCard::ProductType::PRIME_REVISION_3:
128 case CalypsoCard::ProductType::LIGHT:
129 case CalypsoCard::ProductType::BASIC:
130 createRev3(keyIndex, samChallenge, sfi, recordNumber);
131 break;
132
133 default:
134 std::stringstream ss;
135 ss << "Product type " << getCalypsoCard()->getProductType() << " isn't supported";
136 throw IllegalArgumentException(ss.str());
137 }
138}
139
140void CmdCardOpenSession::createRev3(const uint8_t keyIndex,
141 const std::vector<uint8_t>& samChallenge,
142 const uint8_t sfi,
143 const uint8_t recordNumber)
144{
145 mSfi = sfi;
146 mRecordNumber = recordNumber;
147
148 const uint8_t p1 = static_cast<uint8_t>(recordNumber * 8 + keyIndex);
149 uint8_t p2;
150 std::vector<uint8_t> dataIn;
151
152 if (mIsExtendedModeAllowed) {
153
154 p2 = static_cast<uint8_t>(sfi * 8 + 2);
155 dataIn = std::vector<uint8_t>(samChallenge.size() + 1);
156 System::arraycopy(samChallenge, 0, dataIn, 1, samChallenge.size());
157
158 } else {
159
160 p2 = static_cast<uint8_t>(sfi * 8 + 1);
161 dataIn = samChallenge;
162 }
163
164 /*
165 * Case 4: this command contains incoming and outgoing data. We define le = 0, the actual
166 * length will be processed by the lower layers.
167 */
169 std::make_shared<ApduRequestAdapter>(
170 ApduUtil::build(CalypsoCardClass::ISO.getValue(),
171 CalypsoCardCommand::OPEN_SESSION.getInstructionByte(),
172 p1,
173 p2,
174 dataIn,
175 0)));
176
177 std::stringstream extraInfo;
178 extraInfo << "KEYINDEX:" << keyIndex << ", "
179 << "SFI:" << sfi << "h, "
180 << "REC:" << recordNumber;
181
182 addSubName(extraInfo.str());
183}
184
185void CmdCardOpenSession::createRev24(const uint8_t keyIndex,
186 const std::vector<uint8_t>& samChallenge,
187 const uint8_t sfi,
188 const uint8_t recordNumber)
189{
190 if (keyIndex == 0x00) {
191 throw IllegalArgumentException("Key index can't be zero for rev 2.4!");
192 }
193
194 mSfi = sfi;
195 mRecordNumber = recordNumber;
196
197 const uint8_t p1 = static_cast<uint8_t>(0x80 + recordNumber * 8 + keyIndex);
198
199 buildLegacyApduRequest(keyIndex, samChallenge, sfi, recordNumber, p1);
200}
201
202void CmdCardOpenSession::createRev10(const uint8_t keyIndex,
203 const std::vector<uint8_t>& samChallenge,
204 const uint8_t sfi,
205 const uint8_t recordNumber)
206{
207 if (keyIndex == 0x00) {
208 throw IllegalArgumentException("Key index can't be zero for rev 1.0!");
209 }
210
211 mSfi = sfi;
212 mRecordNumber = recordNumber;
213
214 const uint8_t p1 = static_cast<uint8_t>(recordNumber * 8 + keyIndex);
215
216 buildLegacyApduRequest(keyIndex, samChallenge, sfi, recordNumber, p1);
217}
218
220 const std::vector<uint8_t>& samChallenge,
221 const uint8_t sfi,
222 const uint8_t recordNumber,
223 const uint8_t p1)
224{
225 const uint8_t p2 = static_cast<uint8_t>(sfi * 8);
226
227 /*
228 * Case 4: this command contains incoming and outgoing data. We define le = 0, the actual
229 * length will be processed by the lower layers.
230 */
232 std::make_shared<ApduRequestAdapter>(
233 ApduUtil::build(CalypsoCardClass::LEGACY.getValue(),
234 CalypsoCardCommand::OPEN_SESSION.getInstructionByte(),
235 p1,
236 p2,
237 samChallenge,
238 0)));
239
240 std::stringstream extraInfo;
241 extraInfo << "KEYINDEX:" << keyIndex << ", "
242 << "SFI:" << sfi << "h, "
243 << "REC:" << recordNumber;
244
245 addSubName(extraInfo.str());
246}
247
249{
250 return false;
251}
252
254{
255 return mSfi;
256}
257
259{
260 return mRecordNumber;
261}
262
263void CmdCardOpenSession::parseApduResponse(const std::shared_ptr<ApduResponseApi> apduResponse)
264{
266
267 const std::vector<uint8_t> dataOut = getApduResponse()->getDataOut();
268
269 switch (getCalypsoCard()->getProductType()) {
270
271 case CalypsoCard::ProductType::PRIME_REVISION_1:
272 parseRev10(dataOut);
273 break;
274
275 case CalypsoCard::ProductType::PRIME_REVISION_2:
276 parseRev24(dataOut);
277 break;
278
279 default:
280 parseRev3(dataOut);
281 }
282
283 /* CL-CSS-INFORAT.1 */
284 getCalypsoCard()->setDfRatified(mSecureSession->isPreviousSessionRatified());
285
286 /* CL-CSS-INFOTCNT.1 */
287 getCalypsoCard()->setTransactionCounter(
288 ByteArrayUtil::extractInt(mSecureSession->getChallengeTransactionCounter(), 0, 3, false));
289
290 if (mSecureSession->getOriginalData().size() > 0) {
291
292 getCalypsoCard()->setContent(mSfi, mRecordNumber, mSecureSession->getOriginalData());
293 }
294}
295
296void CmdCardOpenSession::parseRev3(const std::vector<uint8_t>& apduResponseData)
297{
298 bool previousSessionRatified;
299 bool manageSecureSessionAuthorized;
300 int offset;
301
302 /* CL-CSS-OSSRFU.1 */
303 if (mIsExtendedModeAllowed) {
304 offset = 4;
305 previousSessionRatified = (apduResponseData[8] & 0x01) == 0x00;
306 manageSecureSessionAuthorized = (apduResponseData[8] & 0x02) == 0x02;
307 } else {
308 offset = 0;
309 previousSessionRatified = apduResponseData[4] == 0x00;
310 manageSecureSessionAuthorized = false;
311 }
312
313 const auto kif = std::make_shared<uint8_t>(apduResponseData[5 + offset]);
314 const auto kvc = std::make_shared<uint8_t>(apduResponseData[6 + offset]);
315 const int dataLength = apduResponseData[7 + offset];
316
317 if (dataLength != static_cast<int>(apduResponseData.size() - 8 - offset)) {
318 throw IllegalStateException("Inconsistent response length for Open Secure Session.");
319 }
320
321 const std::vector<uint8_t> data =
322 Arrays::copyOfRange(apduResponseData, 8 + offset, 8 + offset + dataLength);
323
324 mSecureSession = std::shared_ptr<SecureSession>(
325 new SecureSession(
326 Arrays::copyOfRange(apduResponseData, 0, 3),
327 Arrays::copyOfRange(apduResponseData, 3, 4 + offset),
328 previousSessionRatified,
329 manageSecureSessionAuthorized,
330 kif,
331 kvc,
332 data,
333 apduResponseData));
334}
335
336void CmdCardOpenSession::parseRev24(const std::vector<uint8_t>& apduResponseData)
337{
338 bool previousSessionRatified;
339 std::vector<uint8_t> data;
340
341 switch (apduResponseData.size()) {
342 case 5:
343 previousSessionRatified = true;
344 data = std::vector<uint8_t>(0);
345 break;
346 case 34:
347 if (mRecordSize != 29) {
348 throw IllegalStateException("Inconsistent response length for Open Secure Session.");
349 }
350 previousSessionRatified = true;
351 data = Arrays::copyOfRange(apduResponseData, 5, 34);
352 break;
353 case 7:
354 previousSessionRatified = false;
355 data = std::vector<uint8_t>(0);
356 break;
357 case 36:
358 if (mRecordSize != 29) {
359 throw IllegalStateException("Inconsistent response length for Open Secure Session.");
360 }
361 previousSessionRatified = false;
362 data = Arrays::copyOfRange(apduResponseData, 7, 36);
363 break;
364 default:
365 throw IllegalStateException("Bad response length to Open Secure Session: " +
366 std::to_string(apduResponseData.size()));
367 }
368
369 const auto kvc = std::make_shared<uint8_t>(apduResponseData[0]);
370
371 mSecureSession = std::shared_ptr<SecureSession>(
372 new SecureSession(
373 Arrays::copyOfRange(apduResponseData, 1, 4),
374 Arrays::copyOfRange(apduResponseData, 4, 5),
375 previousSessionRatified,
376 false,
377 nullptr,
378 kvc,
379 data,
380 apduResponseData));
381}
382
383void CmdCardOpenSession::parseRev10(const std::vector<uint8_t>& apduResponseData) {
384
385 bool previousSessionRatified;
386 std::vector<uint8_t> data;
387
388 switch (apduResponseData.size()) {
389 case 4:
390 previousSessionRatified = true;
391 data = std::vector<uint8_t>(0);
392 break;
393 case 33:
394 if (mRecordSize != 29) {
395 throw IllegalStateException("Inconsistent response length for Open Secure Session.");
396 }
397 previousSessionRatified = true;
398 data = Arrays::copyOfRange(apduResponseData, 4, 33);
399 break;
400 case 6:
401 previousSessionRatified = false;
402 data = std::vector<uint8_t>(0);
403 break;
404 case 35:
405 if (mRecordSize != 29) {
406 throw IllegalStateException("Inconsistent response length for Open Secure Session.");
407 }
408 previousSessionRatified = false;
409 data = Arrays::copyOfRange(apduResponseData, 6, 35);
410 break;
411 default:
412 throw IllegalStateException("Bad response length to Open Secure Session: " +
413 std::to_string(apduResponseData.size()));
414 }
415
416 /* KVC doesn't exist and is set to null for this type of card */
417 mSecureSession = std::shared_ptr<SecureSession>(
418 new SecureSession(
419 Arrays::copyOfRange(apduResponseData, 0, 3),
420 Arrays::copyOfRange(apduResponseData, 3, 4),
421 previousSessionRatified,
422 false,
423 nullptr,
424 nullptr,
425 data,
426 apduResponseData));
427}
428
429const std::vector<uint8_t>& CmdCardOpenSession::getCardChallenge() const
430{
431 return mSecureSession->getChallengeRandomNumber();
432}
433
435{
436 return mSecureSession->isManageSecureSessionAuthorized();
437}
438
439const std::shared_ptr<uint8_t> CmdCardOpenSession::getSelectedKif() const
440{
441 return mSecureSession->getKIF();
442}
443
444const std::shared_ptr<uint8_t> CmdCardOpenSession::getSelectedKvc() const
445{
446 return mSecureSession->getKVC();
447}
448
449const std::map<const int, const std::shared_ptr<StatusProperties>>
450 CmdCardOpenSession::initStatusTable()
451{
452 std::map<const int, const std::shared_ptr<StatusProperties>> m =
454
455 m.insert({0x6700,
456 std::make_shared<StatusProperties>("Lc value not supported.",
458 m.insert({0x6900,
459 std::make_shared<StatusProperties>("Transaction Counter is 0",
460 typeid(CardTerminatedException))});
461 m.insert({0x6981,
462 std::make_shared<StatusProperties>("Command forbidden (read requested and current " \
463 "EF is a Binary file).",
464 typeid(CardDataAccessException))});
465 m.insert({0x6982,
466 std::make_shared<StatusProperties>("Security conditions not fulfilled (PIN code " \
467 "not presented, AES key forbidding the " \
468 "compatibility mode, encryption required).",
469 typeid(CardSecurityContextException))});
470 m.insert({0x6985,
471 std::make_shared<StatusProperties>("Access forbidden (Never access mode, Session " \
472 "already opened).",
473 typeid(CardAccessForbiddenException))});
474 m.insert({0x6986,
475 std::make_shared<StatusProperties>("Command not allowed (read requested and no " \
476 "current EF).",
477 typeid(CardDataAccessException))});
478 m.insert({0x6A81,
479 std::make_shared<StatusProperties>("Wrong key index.",
480 typeid(CardIllegalParameterException))});
481 m.insert({0x6A82,
482 std::make_shared<StatusProperties>("File not found.",
483 typeid(CardDataAccessException))});
484 m.insert({0x6A83,
485 std::make_shared<StatusProperties>("Record not found (record index is above NumRec).",
486 typeid(CardDataAccessException))});
487 m.insert({0x6B00,
488 std::make_shared<StatusProperties>("P1 or P2 value not supported (key index " \
489 "incorrect, wrong P2).",
490 typeid(CardIllegalParameterException))});
491 m.insert({0x61FF,
492 std::make_shared<StatusProperties>("Correct execution (ISO7816 T=0).",
493 typeid(nullptr))});
494
495 return m;
496}
497
498const std::map<const int, const std::shared_ptr<StatusProperties>>&
500{
501 return STATUS_TABLE;
502}
503
504}
505}
506}
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
void parseApduResponse(const std::shared_ptr< ApduResponseApi > apduResponse) override
std::shared_ptr< CalypsoCardAdapter > getCalypsoCard() const
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)
void createRev3(const uint8_t keyIndex, const std::vector< uint8_t > &samChallenge, const uint8_t sfi, const uint8_t recordNumber)
const std::vector< uint8_t > & getCardChallenge() const
const std::map< const int, const std::shared_ptr< StatusProperties > > & getStatusTable() const override
void parseRev24(const std::vector< uint8_t > &apduResponseData)
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
void parseApduResponse(const std::shared_ptr< ApduResponseApi > apduResponse) override
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)