blob: 6ea25c4247611ed611f2fc35f9d572fcee42c809 [file] [log] [blame]
Patrick Venture5794fcf2017-10-26 11:11:14 -07001#include "channel.hpp"
Patrick Venture5794fcf2017-10-26 11:11:14 -07002
Patrick Venture0b02be92018-08-31 11:55:55 -07003#include "transporthandler.hpp"
Johnathan Mantey74a21022018-12-13 13:17:56 -08004#include "user_channel/channel_layer.hpp"
Patrick Venture0b02be92018-08-31 11:55:55 -07005
Patrick Venture5794fcf2017-10-26 11:11:14 -07006#include <arpa/inet.h>
7
Tom Joseph13227682018-08-10 01:05:21 +05308#include <boost/process/child.hpp>
Patrick Venture0b02be92018-08-31 11:55:55 -07009#include <fstream>
Vernon Mauery33250242019-03-12 16:49:26 -070010#include <ipmid/types.hpp>
Vernon Mauery6a98fe72019-03-11 15:57:48 -070011#include <ipmid/utils.hpp>
Patrick Venture5794fcf2017-10-26 11:11:14 -070012#include <phosphor-logging/elog-errors.hpp>
Patrick Venture0b02be92018-08-31 11:55:55 -070013#include <phosphor-logging/log.hpp>
Richard Marian Thomaiyarf301f042019-01-16 15:56:16 +053014#include <set>
Patrick Venture0b02be92018-08-31 11:55:55 -070015#include <string>
16#include <xyz/openbmc_project/Common/error.hpp>
Patrick Venture5794fcf2017-10-26 11:11:14 -070017
18using namespace phosphor::logging;
19using namespace sdbusplus::xyz::openbmc_project::Common::Error;
20
Tom Joseph7cbe2282018-03-21 21:17:33 +053021namespace cipher
22{
23
24/** @brief Get the supported Cipher records
25 *
Richard Marian Thomaiyarf301f042019-01-16 15:56:16 +053026 * 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
Tom Joseph7cbe2282018-03-21 21:17:33 +053031 *
Richard Marian Thomaiyarf301f042019-01-16 15:56:16 +053032 * @return pair of vector containing 1. all the cipher suite records. 2.
33 * Algorithms supported
Tom Joseph7cbe2282018-03-21 21:17:33 +053034 *
35 */
Richard Marian Thomaiyarf301f042019-01-16 15:56:16 +053036std::pair<std::vector<uint8_t>, std::vector<uint8_t>> getCipherRecords()
Tom Joseph7cbe2282018-03-21 21:17:33 +053037{
Richard Marian Thomaiyarf301f042019-01-16 15:56:16 +053038 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;
Tom Joseph7cbe2282018-03-21 21:17:33 +053042
43 std::ifstream jsonFile(configFile);
44 if (!jsonFile.is_open())
45 {
46 log<level::ERR>("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 log<level::ERR>("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
Richard Marian Thomaiyarf301f042019-01-16 15:56:16 +053062 cipherRecords.push_back(oemCipherSuite);
Tom Joseph7cbe2282018-03-21 21:17:33 +053063 // Cipher Suite ID
Richard Marian Thomaiyarf301f042019-01-16 15:56:16 +053064 cipherRecords.push_back(record.value(cipher, 0));
Tom Joseph7cbe2282018-03-21 21:17:33 +053065 // OEM IANA - 3 bytes
Richard Marian Thomaiyarf301f042019-01-16 15:56:16 +053066 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);
Tom Joseph7cbe2282018-03-21 21:17:33 +053069 }
70 else
71 {
Richard Marian Thomaiyarf301f042019-01-16 15:56:16 +053072 // Standard cipher suite - 0xC0
73 cipherRecords.push_back(stdCipherSuite);
Tom Joseph7cbe2282018-03-21 21:17:33 +053074 // Cipher Suite ID
Richard Marian Thomaiyarf301f042019-01-16 15:56:16 +053075 cipherRecords.push_back(record.value(cipher, 0));
Tom Joseph7cbe2282018-03-21 21:17:33 +053076 }
77
78 // Authentication algorithm number
Richard Marian Thomaiyarf301f042019-01-16 15:56:16 +053079 cipherRecords.push_back(record.value(auth, 0));
80 supportedAlgorithmSet.insert(record.value(auth, 0));
81
Tom Joseph7cbe2282018-03-21 21:17:33 +053082 // Integrity algorithm number
Richard Marian Thomaiyarf301f042019-01-16 15:56:16 +053083 cipherRecords.push_back(record.value(integrity, 0) | integrityTag);
84 supportedAlgorithmSet.insert(record.value(integrity, 0) | integrityTag);
85
Tom Joseph7cbe2282018-03-21 21:17:33 +053086 // Confidentiality algorithm number
Richard Marian Thomaiyarf301f042019-01-16 15:56:16 +053087 cipherRecords.push_back(record.value(conf, 0) | confTag);
88 supportedAlgorithmSet.insert(record.value(conf, 0) | confTag);
Tom Joseph7cbe2282018-03-21 21:17:33 +053089 }
90
Richard Marian Thomaiyarf301f042019-01-16 15:56:16 +053091 // 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);
Tom Joseph7cbe2282018-03-21 21:17:33 +053096}
97
Patrick Venture0b02be92018-08-31 11:55:55 -070098} // namespace cipher
Tom Joseph7cbe2282018-03-21 21:17:33 +053099
Patrick Venture0b02be92018-08-31 11:55:55 -0700100ipmi_ret_t getChannelCipherSuites(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
Tom Joseph7cbe2282018-03-21 21:17:33 +0530101 ipmi_request_t request,
102 ipmi_response_t response,
103 ipmi_data_len_t data_len,
104 ipmi_context_t context)
105{
Richard Marian Thomaiyarf301f042019-01-16 15:56:16 +0530106 static std::vector<uint8_t> cipherRecords;
107 static std::vector<uint8_t> supportedAlgorithms;
Tom Joseph7cbe2282018-03-21 21:17:33 +0530108 static auto recordInit = false;
109
110 auto requestData =
111 reinterpret_cast<const GetChannelCipherRequest*>(request);
112
Tom Joseph7cbe2282018-03-21 21:17:33 +0530113 if (*data_len < sizeof(GetChannelCipherRequest))
114 {
115 *data_len = 0;
116 return IPMI_CC_REQ_DATA_LEN_INVALID;
117 }
118
119 *data_len = 0;
120
Tom Joseph7cbe2282018-03-21 21:17:33 +0530121 if (!recordInit)
122 {
123 try
124 {
Richard Marian Thomaiyarf301f042019-01-16 15:56:16 +0530125 std::tie(cipherRecords, supportedAlgorithms) =
126 cipher::getCipherRecords();
Tom Joseph7cbe2282018-03-21 21:17:33 +0530127 recordInit = true;
128 }
Patrick Venture0b02be92018-08-31 11:55:55 -0700129 catch (const std::exception& e)
Tom Joseph7cbe2282018-03-21 21:17:33 +0530130 {
131 return IPMI_CC_UNSPECIFIED_ERROR;
132 }
133 }
134
Richard Marian Thomaiyarf301f042019-01-16 15:56:16 +0530135 const auto& records = (cipher::listCipherSuite ==
136 (requestData->listIndex & cipher::listTypeMask))
137 ? cipherRecords
138 : supportedAlgorithms;
139
Tom Joseph7cbe2282018-03-21 21:17:33 +0530140 // List index(00h-3Fh), 0h selects the first set of 16, 1h selects the next
141 // set of 16 and so on.
Patrick Venture0b02be92018-08-31 11:55:55 -0700142 auto index =
143 static_cast<size_t>(requestData->listIndex & cipher::listIndexMask);
Tom Joseph7cbe2282018-03-21 21:17:33 +0530144
145 // Calculate the number of record data bytes to be returned.
146 auto start = std::min(index * cipher::respSize, records.size());
Patrick Venture0b02be92018-08-31 11:55:55 -0700147 auto end =
148 std::min((index * cipher::respSize) + cipher::respSize, records.size());
Tom Joseph7cbe2282018-03-21 21:17:33 +0530149 auto size = end - start;
150
Patrick Venture0b02be92018-08-31 11:55:55 -0700151 auto responseData = reinterpret_cast<GetChannelCipherRespHeader*>(response);
Tom Joseph7cbe2282018-03-21 21:17:33 +0530152 responseData->channelNumber = cipher::defaultChannelNumber;
153
154 if (!size)
155 {
156 *data_len = sizeof(GetChannelCipherRespHeader);
157 }
158 else
159 {
Patrick Venture0b02be92018-08-31 11:55:55 -0700160 std::copy_n(records.data() + start, size,
Tom Joseph7cbe2282018-03-21 21:17:33 +0530161 static_cast<uint8_t*>(response) + 1);
162 *data_len = size + sizeof(GetChannelCipherRespHeader);
163 }
164
165 return IPMI_CC_OK;
166}
Tom Joseph13227682018-08-10 01:05:21 +0530167
168template <typename... ArgTypes>
169static int executeCmd(const char* path, ArgTypes&&... tArgs)
170{
171 boost::process::child execProg(path, const_cast<char*>(tArgs)...);
172 execProg.wait();
173 return execProg.exit_code();
174}
175
176/** @brief Enable the network IPMI service on the specified ethernet interface.
177 *
178 * @param[in] intf - ethernet interface on which to enable IPMI
179 */
180void enableNetworkIPMI(const std::string& intf)
181{
182 // Check if there is a iptable filter to drop IPMI packets for the
183 // interface.
184 auto retCode =
185 executeCmd("/usr/sbin/iptables", "-C", "INPUT", "-p", "udp", "-i",
186 intf.c_str(), "--dport", "623", "-j", "DROP");
187
188 // If the iptable filter exists, delete the filter.
189 if (!retCode)
190 {
191 auto response =
192 executeCmd("/usr/sbin/iptables", "-D", "INPUT", "-p", "udp", "-i",
193 intf.c_str(), "--dport", "623", "-j", "DROP");
194
195 if (response)
196 {
197 log<level::ERR>("Dropping the iptables filter failed",
198 entry("INTF=%s", intf.c_str()),
199 entry("RETURN_CODE:%d", response));
200 }
201 }
202}
203
204/** @brief Disable the network IPMI service on the specified ethernet interface.
205 *
206 * @param[in] intf - ethernet interface on which to disable IPMI
207 */
208void disableNetworkIPMI(const std::string& intf)
209{
210 // Check if there is a iptable filter to drop IPMI packets for the
211 // interface.
212 auto retCode =
213 executeCmd("/usr/sbin/iptables", "-C", "INPUT", "-p", "udp", "-i",
214 intf.c_str(), "--dport", "623", "-j", "DROP");
215
216 // If the iptable filter does not exist, add filter to drop network IPMI
217 // packets
218 if (retCode)
219 {
220 auto response =
221 executeCmd("/usr/sbin/iptables", "-I", "INPUT", "-p", "udp", "-i",
222 intf.c_str(), "--dport", "623", "-j", "DROP");
223
224 if (response)
225 {
226 log<level::ERR>("Inserting iptables filter failed",
227 entry("INTF=%s", intf.c_str()),
228 entry("RETURN_CODE:%d", response));
229 }
230 }
231}