1 #include "channel.hpp"
2
3 #include "user_channel/channel_layer.hpp"
4
5 #include <arpa/inet.h>
6
7 #include <ipmid/types.hpp>
8 #include <ipmid/utils.hpp>
9 #include <phosphor-logging/elog-errors.hpp>
10 #include <phosphor-logging/lg2.hpp>
11 #include <xyz/openbmc_project/Common/error.hpp>
12
13 #include <fstream>
14 #include <set>
15 #include <string>
16
17 using namespace phosphor::logging;
18 using namespace sdbusplus::error::xyz::openbmc_project::common;
19
20 namespace ipmi
21 {
22 constexpr Cc ccPayloadTypeNotSupported = 0x80;
23
responsePayloadTypeNotSupported()24 static inline auto responsePayloadTypeNotSupported()
25 {
26 return response(ccPayloadTypeNotSupported);
27 }
28 } // namespace ipmi
29
30 namespace cipher
31 {
32
33 /** @brief Get the supported Cipher records
34 *
35 * The cipher records are read from the JSON file and converted into
36 * 1. cipher suite record format mentioned in the IPMI specification. The
37 * records can be either OEM or standard cipher. Each json entry is parsed and
38 * converted into the cipher record format and pushed into the vector.
39 * 2. Algorithms listed in vector format
40 *
41 * @return pair of vector containing 1. all the cipher suite records. 2.
42 * Algorithms supported
43 *
44 */
getCipherRecords()45 std::pair<std::vector<uint8_t>, std::vector<uint8_t>> getCipherRecords()
46 {
47 std::vector<uint8_t> cipherRecords;
48 std::vector<uint8_t> supportedAlgorithmRecords;
49 // create set to get the unique supported algorithms
50 std::set<uint8_t> supportedAlgorithmSet;
51
52 std::ifstream jsonFile(configFile);
53 if (!jsonFile.is_open())
54 {
55 lg2::error("Channel Cipher suites file not found");
56 elog<InternalFailure>();
57 }
58
59 auto data = Json::parse(jsonFile, nullptr, false);
60 if (data.is_discarded())
61 {
62 lg2::error("Parsing channel cipher suites JSON failed");
63 elog<InternalFailure>();
64 }
65
66 for (const auto& record : data)
67 {
68 if (record.find(oem) != record.end())
69 {
70 // OEM cipher suite - 0xC1
71 cipherRecords.push_back(oemCipherSuite);
72 // Cipher Suite ID
73 cipherRecords.push_back(record.value(cipher, 0));
74 // OEM IANA - 3 bytes
75 cipherRecords.push_back(record.value(oem, 0));
76 cipherRecords.push_back(record.value(oem, 0) >> 8);
77 cipherRecords.push_back(record.value(oem, 0) >> 16);
78 }
79 else
80 {
81 // Standard cipher suite - 0xC0
82 cipherRecords.push_back(stdCipherSuite);
83 // Cipher Suite ID
84 cipherRecords.push_back(record.value(cipher, 0));
85 }
86
87 // Authentication algorithm number
88 cipherRecords.push_back(record.value(auth, 0));
89 supportedAlgorithmSet.insert(record.value(auth, 0));
90
91 // Integrity algorithm number
92 cipherRecords.push_back(record.value(integrity, 0) | integrityTag);
93 supportedAlgorithmSet.insert(record.value(integrity, 0) | integrityTag);
94
95 // Confidentiality algorithm number
96 cipherRecords.push_back(record.value(conf, 0) | confTag);
97 supportedAlgorithmSet.insert(record.value(conf, 0) | confTag);
98 }
99
100 // copy the set to supportedAlgorithmRecord which is vector based.
101 std::copy(supportedAlgorithmSet.begin(), supportedAlgorithmSet.end(),
102 std::back_inserter(supportedAlgorithmRecords));
103
104 return std::make_pair(cipherRecords, supportedAlgorithmRecords);
105 }
106
107 } // namespace cipher
108
109 /** @brief this command is used to look up what authentication, integrity,
110 * confidentiality algorithms are supported.
111 *
112 * @ param ctx - context pointer
113 * @ param channelNumber - channel number
114 * @ param payloadType - payload type
115 * @ param listIndex - list index
116 * @ param algoSelectBit - list algorithms
117 *
118 * @returns ipmi completion code plus response data
119 * - rspChannel - channel number for authentication algorithm.
120 * - rspRecords - cipher suite records.
121 **/
122 ipmi::RspType<uint8_t, // Channel Number
123 std::vector<uint8_t> // Cipher Records
124 >
getChannelCipherSuites(ipmi::Context::ptr ctx,uint4_t channelNumber,uint4_t reserved1,uint8_t payloadType,uint6_t listIndex,uint1_t reserved2,uint1_t algoSelectBit)125 getChannelCipherSuites(ipmi::Context::ptr ctx, uint4_t channelNumber,
126 uint4_t reserved1, uint8_t payloadType,
127 uint6_t listIndex, uint1_t reserved2,
128 uint1_t algoSelectBit)
129 {
130 static std::vector<uint8_t> cipherRecords;
131 static std::vector<uint8_t> supportedAlgorithms;
132 static auto recordInit = false;
133
134 uint8_t rspChannel = ipmi::convertCurrentChannelNum(
135 static_cast<uint8_t>(channelNumber), ctx->channel);
136
137 if (!ipmi::isValidChannel(rspChannel) || reserved1 != 0 || reserved2 != 0)
138 {
139 return ipmi::responseInvalidFieldRequest();
140 }
141 if (!ipmi::isValidPayloadType(static_cast<ipmi::PayloadType>(payloadType)))
142 {
143 lg2::debug("Get channel cipher suites - Invalid payload type");
144 return ipmi::responsePayloadTypeNotSupported();
145 }
146
147 if (!recordInit)
148 {
149 try
150 {
151 std::tie(cipherRecords, supportedAlgorithms) =
152 cipher::getCipherRecords();
153 recordInit = true;
154 }
155 catch (const std::exception& e)
156 {
157 return ipmi::responseUnspecifiedError();
158 }
159 }
160
161 const std::vector<uint8_t>& records =
162 algoSelectBit ? cipherRecords : supportedAlgorithms;
163 static constexpr auto respSize = 16;
164
165 // Session support is available in active LAN channels.
166 if ((ipmi::getChannelSessionSupport(rspChannel) ==
167 ipmi::EChannelSessSupported::none) ||
168 !(ipmi::doesDeviceExist(rspChannel)))
169 {
170 lg2::debug("Get channel cipher suites - Device does not exist");
171 return ipmi::responseInvalidFieldRequest();
172 }
173
174 // List index(00h-3Fh), 0h selects the first set of 16, 1h selects the next
175 // set of 16 and so on.
176
177 // Calculate the number of record data bytes to be returned.
178 auto start =
179 std::min(static_cast<size_t>(listIndex) * respSize, records.size());
180 auto end = std::min((static_cast<size_t>(listIndex) * respSize) + respSize,
181 records.size());
182 auto size = end - start;
183
184 std::vector<uint8_t> rspRecords;
185 std::copy_n(records.data() + start, size, std::back_inserter(rspRecords));
186
187 return ipmi::responseSuccess(rspChannel, rspRecords);
188 }
189