From 7cbe22866c633d8e5b427503e1b1a363f45641a3 Mon Sep 17 00:00:00 2001 From: Tom Joseph Date: Wed, 21 Mar 2018 21:17:33 +0530 Subject: Implement Get Channel Cipher Suites command Change-Id: I8c808ce7e2bbd3ae5e225573138d7e04871f1643 Signed-off-by: Tom Joseph --- app/channel.cpp | 139 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ app/channel.hpp | 64 ++++++++++++++++++++++++++ 2 files changed, 203 insertions(+) (limited to 'app') diff --git a/app/channel.cpp b/app/channel.cpp index 000c11e..3134683 100644 --- a/app/channel.cpp +++ b/app/channel.cpp @@ -4,6 +4,7 @@ #include "utils.hpp" #include "net.hpp" +#include #include #include @@ -118,3 +119,141 @@ ipmi_ret_t ipmi_app_channel_info(ipmi_netfn_t netfn, ipmi_cmd_t cmd, return rc; } + +namespace cipher +{ + +/** @brief Get the supported Cipher records + * + * The cipher records are read from the JSON file and converted into cipher + * suite record format mentioned in the IPMI specification. The records can be + * either OEM or standard cipher. Each json entry is parsed and converted into + * the cipher record format and pushed into the vector. + * + * @return vector containing all the cipher suite records. + * + */ +std::vector getCipherRecords() +{ + std::vector records; + + std::ifstream jsonFile(configFile); + if (!jsonFile.is_open()) + { + log("Channel Cipher suites file not found"); + elog(); + } + + auto data = Json::parse(jsonFile, nullptr, false); + if (data.is_discarded()) + { + log("Parsing channel cipher suites JSON failed"); + elog(); + } + + for (const auto& record : data) + { + if (record.find(oem) != record.end()) + { + // OEM cipher suite - 0xC1 + records.push_back(oemCipherSuite); + // Cipher Suite ID + records.push_back(record.value(cipher, 0)); + // OEM IANA - 3 bytes + records.push_back(record.value(oem, 0)); + records.push_back(record.value(oem, 0) >> 8); + records.push_back(record.value(oem, 0) >> 16); + + } + else + { + // OEM cipher suite - 0xC0 + records.push_back(stdCipherSuite); + // Cipher Suite ID + records.push_back(record.value(cipher, 0)); + } + + // Authentication algorithm number + records.push_back(record.value(auth, 0)); + // Integrity algorithm number + records.push_back(record.value(integrity, 0) | integrityTag); + // Confidentiality algorithm number + records.push_back(record.value(conf, 0) | confTag); + } + + return records; +} + +} //namespace cipher + +ipmi_ret_t getChannelCipherSuites(ipmi_netfn_t netfn, + ipmi_cmd_t cmd, + ipmi_request_t request, + ipmi_response_t response, + ipmi_data_len_t data_len, + ipmi_context_t context) +{ + static std::vector records; + static auto recordInit = false; + + auto requestData = + reinterpret_cast(request); + + + if (*data_len < sizeof(GetChannelCipherRequest)) + { + *data_len = 0; + return IPMI_CC_REQ_DATA_LEN_INVALID; + } + + *data_len = 0; + + // Support only for list algorithms by cipher suite + if (cipher::listCipherSuite != + (requestData->listIndex & cipher::listTypeMask)) + { + return IPMI_CC_INVALID_FIELD_REQUEST; + } + + if (!recordInit) + { + try + { + records = cipher::getCipherRecords(); + recordInit = true; + } + catch (const std::exception &e) + { + return IPMI_CC_UNSPECIFIED_ERROR; + } + } + + // List index(00h-3Fh), 0h selects the first set of 16, 1h selects the next + // set of 16 and so on. + auto index = static_cast( + requestData->listIndex & cipher::listIndexMask); + + // Calculate the number of record data bytes to be returned. + auto start = std::min(index * cipher::respSize, records.size()); + auto end = std::min((index * cipher::respSize) + cipher::respSize, + records.size()); + auto size = end - start; + + auto responseData = reinterpret_cast + (response); + responseData->channelNumber = cipher::defaultChannelNumber; + + if (!size) + { + *data_len = sizeof(GetChannelCipherRespHeader); + } + else + { + std::copy_n(records.data() + start, + size, + static_cast(response) + 1); + *data_len = size + sizeof(GetChannelCipherRespHeader); + } + + return IPMI_CC_OK; +} diff --git a/app/channel.hpp b/app/channel.hpp index 1391d62..79522e4 100644 --- a/app/channel.hpp +++ b/app/channel.hpp @@ -1,4 +1,5 @@ #include "ipmid.hpp" +#include "nlohmann/json.hpp" /** @brief The set channel access IPMI command. * @@ -57,3 +58,66 @@ ipmi_ret_t ipmi_app_channel_info( ipmi_data_len_t data_len, ipmi_context_t context); +/** @brief Implementation of get channel cipher suites command + * + * @param[in] netfn - Net Function + * @param[in] cmd - Command + * @param[in] request - Request pointer + * @param[in,out] response - Response pointer + * @param[in,out] data_len - Data Length + * @param[in] context - Context + * + * @return IPMI_CC_OK on success, non-zero otherwise. + */ +ipmi_ret_t getChannelCipherSuites(ipmi_netfn_t netfn, + ipmi_cmd_t cmd, + ipmi_request_t request, + ipmi_response_t response, + ipmi_data_len_t data_len, + ipmi_context_t context); + +namespace cipher +{ + +static constexpr auto defaultChannelNumber = 1; +static constexpr auto listTypeMask = 0x80; +static constexpr auto listCipherSuite = 0x80; +static constexpr auto listIndexMask = 0x3F; +static constexpr auto respSize = 16; + +using Json = nlohmann::json; +static constexpr auto configFile = + "/usr/share/ipmi-providers/cipher_list.json"; +static constexpr auto cipher = "cipher"; +static constexpr auto stdCipherSuite = 0xC0; +static constexpr auto oemCipherSuite = 0xC1; +static constexpr auto oem = "oemiana"; +static constexpr auto auth = "authentication"; +static constexpr auto integrity = "integrity"; +static constexpr auto integrityTag = 0x40; +static constexpr auto conf = "confidentiality"; +static constexpr auto confTag = 0x80; + +} //namespace cipher + +/** @struct GetChannelCipherRequest + * + * IPMI payload for Get Channel Cipher Suites command request + */ +struct GetChannelCipherRequest +{ + uint8_t channelNumber; //!< Channel Number + uint8_t payloadType; //!< Payload type number + uint8_t listIndex; //!< List Index +} __attribute__((packed)); + +/** @struct GetChannelCipherRespHeader + * + * IPMI payload for Get Channel Cipher Suites command response header + */ +struct GetChannelCipherRespHeader +{ + uint8_t channelNumber; //!< Channel Number +} __attribute__((packed)); + + -- cgit v1.2.1