Keyple Card Calypso C++ Library - 3.2.2
Component of the Keyple C++ middleware
CommandUpdateOrWriteBinary.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/CommandUpdateOrWriteBinary.hpp"
15
16#include <map>
17#include <memory>
18#include <sstream>
19#include <vector>
20
21#include "keyple/card/calypso/CalypsoCardAdapter.hpp"
22#include "keyple/card/calypso/CalypsoCardClass.hpp"
23#include "keyple/card/calypso/CardAccessForbiddenException.hpp"
24#include "keyple/card/calypso/CardCommandRef.hpp"
25#include "keyple/card/calypso/CardDataAccessException.hpp"
26#include "keyple/card/calypso/CardIllegalParameterException.hpp"
27#include "keyple/card/calypso/CardSecurityContextException.hpp"
28#include "keyple/card/calypso/CardSessionBufferOverflowException.hpp"
29#include "keyple/core/util/ApduUtil.hpp"
30#include "keyple/core/util/HexUtil.hpp"
31#include "keyple/core/util/cpp/Arrays.hpp"
32#include "keyple/core/util/cpp/System.hpp"
33
34namespace keyple {
35namespace card {
36namespace calypso {
37
38using keyple::core::util::ApduUtil;
39using keyple::core::util::HexUtil;
40using keyple::core::util::cpp::Arrays;
41using keyple::core::util::cpp::System;
42
43const std::map<int, const std::shared_ptr<Command::StatusProperties>>
44 CommandUpdateOrWriteBinary::STATUS_TABLE = [] {
45 std::map<int, const std::shared_ptr<Command::StatusProperties>> m(
46 Command::STATUS_TABLE);
47
48 m.insert(
49 {{0x6400,
50 std::make_shared<Command::StatusProperties>(
51 "Too many modifications in session",
52 typeid(CardSessionBufferOverflowException))},
53 {0x6700,
54 std::make_shared<Command::StatusProperties>(
55 "Lc value not supported", typeid(CardDataAccessException))},
56 {0x6981,
57 std::make_shared<Command::StatusProperties>(
58 "Incorrect EF type: not a Binary EF",
59 typeid(CardDataAccessException))},
60 {0x6982,
61 std::make_shared<Command::StatusProperties>(
62 "Security conditions not fulfilled (no secure session, "
63 "incorrect key, encryption required, PKI mode and not Always "
64 "access mode)",
65 typeid(CardSecurityContextException))},
66 {0x6985,
67 std::make_shared<Command::StatusProperties>(
68 "Access forbidden (Never access mode, DF is invalidated, "
69 "etc..)",
70 typeid(CardSecurityContextException))},
71 {0x6986,
72 std::make_shared<Command::StatusProperties>(
73 "Incorrect file type: the Current File is not an EF. "
74 "Supersedes 6981h",
75 typeid(CardDataAccessException))},
76 {0x6A82,
77 std::make_shared<Command::StatusProperties>(
78 "File not found", typeid(CardDataAccessException))},
79 {0x6A83,
80 std::make_shared<Command::StatusProperties>(
81 "Offset not in the file (offset overflow)",
82 typeid(CardDataAccessException))},
83 {0x6B00,
84 std::make_shared<Command::StatusProperties>(
85 "P1 value not supported",
86 typeid(CardIllegalParameterException))}});
87 return m;
88 }();
89
90CommandUpdateOrWriteBinary::CommandUpdateOrWriteBinary(
91 bool isUpdateCommand,
92 const std::shared_ptr<DtoAdapters::TransactionContextDto>&
93 transactionContext,
94 const std::shared_ptr<DtoAdapters::CommandContextDto>& commandContext,
95 std::uint8_t sfi,
96 int offset,
97 const std::vector<uint8_t>& data)
98: Command(
99 isUpdateCommand ? CardCommandRef::UPDATE_BINARY
100 : CardCommandRef::WRITE_BINARY,
101 std::unique_ptr<int>(new int(0)),
102 transactionContext,
103 commandContext)
104, mSfi(sfi)
105, mOffset(offset)
106, mData(data)
107{
108 const std::uint8_t msb
109 = static_cast<std::uint8_t>((offset & 0x0000FF00) >> 8);
110 const std::uint8_t lsb = static_cast<std::uint8_t>((offset & 0x000000FF));
111
112 /*
113 * 100xxxxx : 'xxxxx' = SFI of the EF to select.
114 * 0xxxxxxx : 'xxxxxxx' = MSB of the offset of the first byte.
115 */
116 const std::uint8_t p1 = msb > 0 ? msb : (0x80 + sfi);
117
118 // APDU Case 3
119 setApduRequest(
120 std::make_shared<DtoAdapters::ApduRequestAdapter>(ApduUtil::build(
121 transactionContext->getCard()->getCardClass().getValue(),
122 getCommandRef().getInstructionByte(),
123 p1,
124 lsb,
125 data)));
126
127 std::stringstream extraInfo;
128 extraInfo << "SFI:" << sfi << "h, "
129 << "Offset:" << offset;
130
131 addSubName(extraInfo.str());
132}
133
134void
135CommandUpdateOrWriteBinary::finalizeRequest()
136{
137 encryptRequestAndUpdateTerminalSessionMacIfNeeded();
138}
139
140bool
141CommandUpdateOrWriteBinary::isCryptoServiceRequiredToFinalizeRequest() const
142{
143 return getCommandContext()->isEncryptionActive();
144}
145
146bool
147CommandUpdateOrWriteBinary::synchronizeCryptoServiceBeforeCardProcessing()
148{
149 if (getCommandContext()->isEncryptionActive()) {
150 return false;
151 }
152
153 updateTerminalSessionIfNeeded(APDU_RESPONSE_9000);
154
155 return true;
156}
157
158void
159CommandUpdateOrWriteBinary::parseResponse(
160 std::shared_ptr<ApduResponseApi> apduResponse)
161{
162 decryptResponseAndUpdateTerminalSessionMacIfNeeded(apduResponse);
163 Command::setApduResponseAndCheckStatus(apduResponse);
164
165 if (getCommandRef() == CardCommandRef::UPDATE_BINARY) {
166 getTransactionContext()->getCard()->setContent(mSfi, 1, mData, mOffset);
167
168 } else {
169 getTransactionContext()->getCard()->fillContent(
170 mSfi, 1, mData, mOffset);
171 }
172
173 updateTerminalSessionIfNeeded();
174}
175
176const std::map<int, const std::shared_ptr<Command::StatusProperties>>&
177CommandUpdateOrWriteBinary::getStatusTable() const
178{
179 return STATUS_TABLE;
180}
181
182} /* namespace calypso */
183} /* namespace card */
184} /* namespace keyple */