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/log.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         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
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         log<level::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,
144                      supportedAlgorithms) = 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 = algoSelectBit ? cipherRecords
154                                                         : 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         log<level::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 = std::min(static_cast<size_t>(listIndex) * respSize,
171                           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