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