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