Keyple Card Calypso C++ Library - 3.2.2
Component of the Keyple C++ middleware
CommandCloseSecureSession.cpp
Go to the documentation of this file.
1/******************************************************************************
2 * Copyright (c) 2025 Calypso Networks Association https://calypsonet.org/ *
3 * *
4 * See the NOTICE file(s) distributed with this work for additional *
5 * information regarding copyright ownership. *
6 * *
7 * This program and the accompanying materials are made available under the *
8 * terms of the Eclipse Public License 2.0 which is available at *
9 * http://www.eclipse.org/legal/epl-2.0 *
10 * *
11 * SPDX-License-Identifier: EPL-2.0 *
12 ******************************************************************************/
13
14#include "keyple/card/calypso/CommandCloseSecureSession.hpp"
15
16#include <map>
17#include <memory>
18#include <string>
19#include <vector>
20
21#include "keyple/card/calypso/CalypsoCardAdapter.hpp"
22#include "keyple/card/calypso/CardAccessForbiddenException.hpp"
23#include "keyple/card/calypso/CardIllegalParameterException.hpp"
24#include "keyple/card/calypso/CardSecurityDataException.hpp"
25#include "keyple/core/util/ApduUtil.hpp"
26#include "keyple/core/util/cpp/Arrays.hpp"
27#include "keypop/calypso/card/transaction/CardSignatureNotVerifiableException.hpp"
28#include "keypop/calypso/card/transaction/CryptoException.hpp"
29#include "keypop/calypso/card/transaction/CryptoIOException.hpp"
30#include "keypop/calypso/card/transaction/InvalidCardSignatureException.hpp"
31#include "keypop/calypso/crypto/asymmetric/AsymmetricCryptoException.hpp"
32#include "keypop/calypso/crypto/symmetric/SymmetricCryptoException.hpp"
33#include "keypop/calypso/crypto/symmetric/SymmetricCryptoIOException.hpp"
34
35namespace keyple {
36namespace card {
37namespace calypso {
38
39using keyple::core::util::ApduUtil;
40using keyple::core::util::cpp::Arrays;
41using keypop::calypso::card::transaction::CardSignatureNotVerifiableException;
42using keypop::calypso::card::transaction::CryptoException;
43using keypop::calypso::card::transaction::CryptoIOException;
44using keypop::calypso::card::transaction::InvalidCardSignatureException;
45using keypop::calypso::crypto::asymmetric::AsymmetricCryptoException;
46using keypop::calypso::crypto::symmetric::SymmetricCryptoException;
47using keypop::calypso::crypto::symmetric::SymmetricCryptoIOException;
48
49const std::string CommandCloseSecureSession::MSG_CARD_SESSION_MAC_NOT_VERIFIABLE
50 = "Unable to verify the card session MAC associated to the successfully "
51 "closed secure session";
52const std::string CommandCloseSecureSession::MSG_CARD_SV_MAC_NOT_VERIFIABLE
53 = "Unable to verify the card SV MAC associated to the SV operation";
54const std::string CommandCloseSecureSession::MSG_INVALID_CARD_SESSION_MAC
55 = "Invalid card session MAC";
56const std::string CommandCloseSecureSession::MSG_INVALID_CARD_SESSION_SIGNATURE
57 = "Invalid card session signature";
58
59const CardCommandRef CommandCloseSecureSession::mCommandRef
60 = CardCommandRef::CLOSE_SECURE_SESSION;
61
62const std::map<int, const std::shared_ptr<Command::StatusProperties>>
63 CommandCloseSecureSession::STATUS_TABLE = [] {
64 std::map<int, const std::shared_ptr<Command::StatusProperties>> m(
65 Command::STATUS_TABLE);
66
67 m.insert(
68 {{0x6700,
69 std::make_shared<StatusProperties>(
70 "Lc signatureLo not supported (e.g. Lc=4 with a Revision 3.2 "
71 "mode for Open Secure Session)",
72 typeid(CardIllegalParameterException))},
73 {0x6B00,
74 std::make_shared<StatusProperties>(
75 "P1 or P2 signatureLo not supported",
76 typeid(CardIllegalParameterException))},
77 {0x6985,
78 std::make_shared<StatusProperties>(
79 "No session was opened",
80 typeid(CardAccessForbiddenException))},
81 {0x6988,
82 std::make_shared<StatusProperties>(
83 "Incorrect signatureLo",
84 typeid(CardSecurityDataException))}});
85 return m;
86 }();
87
88CommandCloseSecureSession::CommandCloseSecureSession(
89 const std::shared_ptr<DtoAdapters::TransactionContextDto>&
90 transactionContext,
91 const std::shared_ptr<DtoAdapters::CommandContextDto>& commandContext,
92 bool isAutoRatificationAsked,
93 int svPostponedDataIndex)
94/* CL-CSS-RESPLE.1: the command is either case 1 (abort) or case 4 */
95: Command(mCommandRef, nullptr, transactionContext, commandContext)
96, mIsAutoRatificationAsked(isAutoRatificationAsked)
97, mIsAbortSecureSession(false)
98, mSvPostponedDataIndex(svPostponedDataIndex)
99{
100}
101
102CommandCloseSecureSession::CommandCloseSecureSession(
103 const std::shared_ptr<DtoAdapters::TransactionContextDto>&
104 transactionContext,
105 const std::shared_ptr<DtoAdapters::CommandContextDto>& commandContext,
106 bool isAbort)
107/* CL-CSS-RESPLE.1: the command is either case 1 (abort) or case 4 */
108: Command(
109 mCommandRef,
110 isAbort ? std::unique_ptr<int>(new int(0)) : nullptr,
111 transactionContext,
112 commandContext)
113, mIsAutoRatificationAsked(true)
114, mSvPostponedDataIndex(-1)
115{
116 if (transactionContext->isPkiMode()) {
117 /*
118 * This a close in PKI mode.
119 * In this case, set the APDU earlier since there is no call to
120 * finalizeRequest
121 * APDU Case 4
122 */
123 setApduRequest(
124 std::make_shared<DtoAdapters::ApduRequestAdapter>(ApduUtil::build(
125 getTransactionContext()->getCard()->getCardClass().getValue(),
126 mCommandRef.getInstructionByte(),
127 0x00,
128 0x00)));
129 mIsAbortSecureSession = isAbort;
130
131 } else {
132 /* This is a non PKI session abort */
133 mIsAbortSecureSession = true;
134 }
135}
136
137void
138CommandCloseSecureSession::finalizeRequest()
139{
140 if (mIsAbortSecureSession) {
141 /*
142 * Abort secure session
143 * CL-CSS-ABORTCMD.1
144 * APDU Case 1
145 */
146 setApduRequest(
147 std::make_shared<DtoAdapters::ApduRequestAdapter>(ApduUtil::build(
148 getTransactionContext()->getCard()->getCardClass().getValue(),
149 mCommandRef.getInstructionByte(),
150 0x00,
151 0x00,
152 0x00))); /* CL-C1-5BYTE.1 */
153 } else {
154 /* Close secure session */
155 std::vector<std::uint8_t> terminalSessionMac;
156 try {
157 terminalSessionMac
158 = getTransactionContext()
159 ->getSymmetricCryptoCardTransactionManagerSpi()
160 ->finalizeTerminalSessionMac();
161
162 } catch (const SymmetricCryptoException& e) {
163 throw CryptoException(e.what(), e);
164
165 } catch (const SymmetricCryptoIOException& e) {
166 throw CryptoIOException(e.what(), e);
167 }
168
169 /* APDU Case 4 */
170 setApduRequest(
171 std::make_shared<DtoAdapters::ApduRequestAdapter>(ApduUtil::build(
172 getTransactionContext()->getCard()->getCardClass().getValue(),
173 mCommandRef.getInstructionByte(),
174 mIsAutoRatificationAsked ? 0x80 : 0x00,
175 0x00,
176 terminalSessionMac,
177 0x00)));
178 }
179}
180
181bool
182CommandCloseSecureSession::isCryptoServiceRequiredToFinalizeRequest() const
183{
184 return !mIsAbortSecureSession;
185}
186
187bool
188CommandCloseSecureSession::synchronizeCryptoServiceBeforeCardProcessing()
189{
190 return mIsAbortSecureSession;
191}
192
193void
194CommandCloseSecureSession::parseResponse(
195 std::shared_ptr<ApduResponseApi> apduResponse)
196{
197 if (mIsAbortSecureSession) {
198 processAbort(apduResponse);
199 return;
200 }
201
202 Command::setApduResponseAndCheckStatus(apduResponse);
203 getTransactionContext()->setSecureSessionOpen(false);
204
205 const std::vector<std::uint8_t> responseData
206 = getApduResponse()->getDataOut();
207
208 if (getTransactionContext()->isPkiMode()) {
209 parseResponseInAsymmetricMode(responseData);
210 } else {
211 parseResponseInSymmetricMode(responseData);
212 }
213}
214
215void
216CommandCloseSecureSession::processAbort(
217 std::shared_ptr<ApduResponseApi> apduResponse)
218{
219 getTransactionContext()->setSecureSessionOpen(false);
220
221 try {
222 Command::setApduResponseAndCheckStatus(apduResponse);
223 mLogger->info("Secure session aborted\n");
224 getTransactionContext()->getCard()->restoreFiles();
225
226 } catch (const CardCommandException& e) {
227 mLogger->warn(
228 "Failed to abort secure session [reason=%]\n", e.getMessage());
229 }
230}
231
232void
233CommandCloseSecureSession::parseResponseInSymmetricMode(
234 const std::vector<std::uint8_t>& responseData)
235{
236 /* Retrieve the postponed data */
237 const int cardSessionMacLength
238 = getTransactionContext()->getCard()->isExtendedModeSupported() ? 8 : 4;
239 int i = 0;
240
241 while (i < static_cast<int>(responseData.size() - cardSessionMacLength)) {
242 const auto data
243 = Arrays::copyOfRange(responseData, i + 1, i + responseData[i]);
244 mPostponedData.push_back(data);
245 i += responseData[i];
246 }
247
248 /* Check the card session MAC (CL-CSS-MACVERIF.1) */
249 const auto cardSessionMac
250 = Arrays::copyOfRange(responseData, i, responseData.size());
251
252 try {
253 if (!getTransactionContext()
254 ->getSymmetricCryptoCardTransactionManagerSpi()
255 ->isCardSessionMacValid(cardSessionMac)) {
256 throw InvalidCardSignatureException(MSG_INVALID_CARD_SESSION_MAC);
257 }
258
259 } catch (const SymmetricCryptoIOException& e) {
260 throw CardSignatureNotVerifiableException(
261 MSG_CARD_SESSION_MAC_NOT_VERIFIABLE, e);
262
263 } catch (const SymmetricCryptoException& e) {
264 throw CryptoException(e.what(), e);
265 }
266
267 if (mSvPostponedDataIndex != -1) {
268 /* CL-SV-POSTPON.1 */
269 try {
270 if (!getTransactionContext()
271 ->getSymmetricCryptoCardTransactionManagerSpi()
272 ->isCardSvMacValid(
273 mPostponedData[mSvPostponedDataIndex])) {
274 throw InvalidCardSignatureException(
275 MSG_INVALID_CARD_SESSION_MAC);
276 }
277
278 } catch (const SymmetricCryptoIOException& e) {
279 throw CardSignatureNotVerifiableException(
280 MSG_CARD_SV_MAC_NOT_VERIFIABLE, e);
281
282 } catch (const SymmetricCryptoException& e) {
283 throw CryptoException(e.what(), e);
284 }
285 }
286}
287
288const std::map<int, const std::shared_ptr<Command::StatusProperties>>&
289CommandCloseSecureSession::getStatusTable() const
290{
291 return STATUS_TABLE;
292}
293
294void
295CommandCloseSecureSession::parseResponseInAsymmetricMode(
296 const std::vector<std::uint8_t>& responseData)
297{
298 try {
299 if (!getTransactionContext()
300 ->getAsymmetricCryptoCardTransactionManagerSpi()
301 ->isCardPkiSessionValid(responseData)) {
302 throw InvalidCardSignatureException(
303 MSG_INVALID_CARD_SESSION_SIGNATURE);
304 }
305
306 } catch (const AsymmetricCryptoException& e) {
307 throw CryptoException(e.what(), e);
308 }
309}
310
311void
312CommandCloseSecureSession::incrementSvPostponedDataIndex()
313{
314 mSvPostponedDataIndex++;
315}
316
317} /* namespace calypso */
318} /* namespace card */
319} /* namespace keyple */