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 */ 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 > 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