Keyple Card Calypso C++ Library - 3.2.2
Component of the Keyple C++ middleware
CommandWriteRecord.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/CommandWriteRecord.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 CommandWriteRecord::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 "Wrong EF type (not a Linear EF, or Cyclic EF with Record "
59 "Number 01h)",
60 typeid(CardDataAccessException))},
61 {0x6982,
62 std::make_shared<Command::StatusProperties>(
63 "Security conditions not fulfilled (no session, wrong key, "
64 "encryption required)",
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 "Command not allowed (no current EF)",
74 typeid(CardDataAccessException))},
75 {0x6A82,
76 std::make_shared<Command::StatusProperties>(
77 "File not found", typeid(CardDataAccessException))},
78 {0x6A83,
79 std::make_shared<Command::StatusProperties>(
80 "Record is not found (record index is 0 or above NumRec)",
81 typeid(CardDataAccessException))},
82 {0x6B00,
83 std::make_shared<Command::StatusProperties>(
84 "P2 value not supported",
85 typeid(CardIllegalParameterException))}});
86 return m;
87 }();
88
89CommandWriteRecord::CommandWriteRecord(
90 const std::shared_ptr<DtoAdapters::TransactionContextDto>&
91 transactionContext,
92 const std::shared_ptr<DtoAdapters::CommandContextDto>& commandContext,
93 std::uint8_t sfi,
94 std::uint8_t recordNumber,
95 const std::vector<std::uint8_t>& newRecordData)
96: Command(
97 CardCommandRef::WRITE_RECORD,
98 std::unique_ptr<int>(new int(0)),
99 transactionContext,
100 commandContext)
101, mSfi(sfi)
102, mRecordNumber(recordNumber)
103, mData(newRecordData)
104{
105 const std::uint8_t p2 = (sfi == 0) ? 0x04 : sfi * 8 + 4;
106
107 // APDU Case 3
108 setApduRequest(
109 std::make_shared<DtoAdapters::ApduRequestAdapter>(ApduUtil::build(
110 transactionContext->getCard()->getCardClass().getValue(),
111 getCommandRef().getInstructionByte(),
112 mRecordNumber,
113 p2,
114 newRecordData)));
115
116 std::stringstream extraInfo;
117 extraInfo << "SFI:" << sfi << "h, "
118 << "REC:" << recordNumber;
119
120 addSubName(extraInfo.str());
121}
122
123void
124CommandWriteRecord::finalizeRequest()
125{
126 encryptRequestAndUpdateTerminalSessionMacIfNeeded();
127}
128
129bool
130CommandWriteRecord::isCryptoServiceRequiredToFinalizeRequest() const
131{
132 return getCommandContext()->isEncryptionActive();
133}
134
135bool
136CommandWriteRecord::synchronizeCryptoServiceBeforeCardProcessing()
137{
138 if (getCommandContext()->isEncryptionActive()) {
139 return false;
140 }
141
142 updateTerminalSessionIfNeeded(APDU_RESPONSE_9000);
143
144 return true;
145}
146
147void
148CommandWriteRecord::parseResponse(std::shared_ptr<ApduResponseApi> apduResponse)
149{
150 decryptResponseAndUpdateTerminalSessionMacIfNeeded(apduResponse);
151 Command::setApduResponseAndCheckStatus(apduResponse);
152 getTransactionContext()->getCard()->fillContent(
153 mSfi, mRecordNumber, mData, 0);
154 updateTerminalSessionIfNeeded();
155}
156
157const std::map<int, const std::shared_ptr<Command::StatusProperties>>&
158CommandWriteRecord::getStatusTable() const
159{
160 return STATUS_TABLE;
161}
162
163} /* namespace calypso */
164} /* namespace card */
165} /* namespace keyple */