| /* |
| * SPDX-FileCopyrightText: Copyright (c) 2023-2024 NVIDIA CORPORATION & |
| * AFFILIATES. All rights reserved. SPDX-License-Identifier: Apache-2.0 |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| |
| #include "nsm_firmware_cmd.hpp" |
| |
| #include "base.h" |
| #include "firmware-utils.h" |
| |
| #include "cmd_helper.hpp" |
| #include "utils.hpp" |
| |
| #include <CLI/CLI.hpp> |
| |
| namespace nsmtool::firmware |
| { |
| |
| using namespace nsmtool::helper; |
| std::vector<std::unique_ptr<CommandInterface>> commands; |
| |
| class GetRotInformation : public CommandInterface |
| { |
| public: |
| ~GetRotInformation() = default; |
| GetRotInformation() = delete; |
| GetRotInformation(const GetRotInformation&) = delete; |
| GetRotInformation(GetRotInformation&&) = default; |
| GetRotInformation& operator=(const GetRotInformation&) = delete; |
| GetRotInformation& operator=(GetRotInformation&&) = default; |
| |
| explicit GetRotInformation(const char* type, const char* name, |
| CLI::App* app) : |
| CommandInterface(type, name, app) |
| { |
| auto ccOptionGroup = app->add_option_group( |
| "Required", |
| "Get information about a particular firmware set installed on an endpoint"); |
| ccOptionGroup |
| ->add_option("-c,--classification", classification, |
| "Component classification") |
| ->required(); |
| ccOptionGroup |
| ->add_option("-i,--identifier", identifier, "Component identifier") |
| ->required(); |
| ccOptionGroup->add_option("-d,--index", index, "Component index") |
| ->required(); |
| } |
| |
| std::pair<int, std::vector<uint8_t>> createRequestMsg() override |
| { |
| std::vector<uint8_t> requestMsg( |
| sizeof(nsm_msg_hdr) + sizeof(nsm_firmware_get_erot_state_info_req)); |
| nsm_firmware_erot_state_info_req nsm_req; |
| nsm_req.component_classification = classification; |
| nsm_req.component_classification_index = index; |
| nsm_req.component_identifier = identifier; |
| auto request = reinterpret_cast<nsm_msg*>(requestMsg.data()); |
| auto rc = encode_nsm_query_get_erot_state_parameters_req( |
| instanceId, &nsm_req, request); |
| return std::make_pair(rc, requestMsg); |
| } |
| |
| void parseResponseMsg(nsm_msg* responsePtr, size_t payloadLength) override |
| { |
| uint8_t cc = NSM_SUCCESS; |
| uint16_t reason_code = ERR_NULL; |
| nsm_firmware_erot_state_info_resp erot_info = {}; |
| |
| auto rc = decode_nsm_query_get_erot_state_parameters_resp( |
| responsePtr, payloadLength, &cc, &reason_code, &erot_info); |
| if (rc != NSM_SW_SUCCESS || cc != NSM_SUCCESS) |
| { |
| std::cerr << "Response message error: " |
| << "rc=" << rc << ", cc=" << (int)cc |
| << ", reasonCode=" << (int)reason_code << "\n"; |
| free(erot_info.slot_info); |
| return; |
| } |
| |
| ordered_json result; |
| result["Completion code"] = cc; |
| result["Reason code"] = reason_code; |
| result["Background copy policy"] = mapEnumToString( |
| static_cast<uint32_t>(erot_info.fq_resp_hdr.background_copy_policy), |
| bgCopyPolicyMap); |
| result["Active Slot"] = |
| static_cast<uint32_t>(erot_info.fq_resp_hdr.active_slot); |
| result["Active Keyset"] = |
| static_cast<uint32_t>(erot_info.fq_resp_hdr.active_keyset); |
| result["Minimum security version"] = static_cast<uint32_t>( |
| erot_info.fq_resp_hdr.minimum_security_version); |
| result["Update policy"] = |
| static_cast<uint32_t>(erot_info.fq_resp_hdr.inband_update_policy); |
| result["Boot status code"] = |
| static_cast<uint64_t>(erot_info.fq_resp_hdr.boot_status_code); |
| result["Firmware slot count"] = |
| static_cast<uint32_t>(erot_info.fq_resp_hdr.firmware_slot_count); |
| |
| std::vector<ordered_json> slots; |
| for (int i = 0; i < erot_info.fq_resp_hdr.firmware_slot_count; i++) |
| { |
| ordered_json slot_info; |
| slot_info["Slot ID"] = |
| static_cast<uint32_t>(erot_info.slot_info[i].slot_id); |
| slot_info["Fw version string"] = |
| (char*)(&(erot_info.slot_info[i].firmware_version_string[0])); |
| slot_info["Version comp stamp"] = static_cast<uint32_t>( |
| erot_info.slot_info[i].version_comparison_stamp); |
| slot_info["Build type"] = mapEnumToString( |
| static_cast<uint32_t>(erot_info.slot_info[i].build_type), |
| buildTypeMap); |
| slot_info["Signing type"] = mapEnumToString( |
| static_cast<uint32_t>(erot_info.slot_info[i].signing_type), |
| signingTypeMap); |
| slot_info["WR Protect State"] = |
| mapEnumToString(static_cast<uint32_t>( |
| erot_info.slot_info[i].write_protect_state), |
| writeProtectMap); |
| slot_info["Firmware state"] = mapEnumToString( |
| static_cast<uint32_t>(erot_info.slot_info[i].firmware_state), |
| firmwareStateMap); |
| slot_info["Security version number"] = static_cast<uint32_t>( |
| erot_info.slot_info[i].security_version_number); |
| slot_info["Signing key index"] = |
| static_cast<uint32_t>(erot_info.slot_info[i].signing_key_index); |
| |
| slots.push_back(std::move(slot_info)); |
| } |
| |
| result["Slot information"] = std::move(slots); |
| |
| DisplayInJson(result); |
| |
| free(erot_info.slot_info); |
| } |
| |
| private: |
| uint16_t classification{}; |
| uint16_t identifier{}; |
| uint8_t index{}; |
| |
| const std::unordered_map<uint32_t, std::string> bgCopyPolicyMap = { |
| {0, "Disabled"}, {1, "Enabled"}}; |
| |
| const std::unordered_map<uint32_t, std::string> buildTypeMap = { |
| {0, "Development"}, {1, "Release"}}; |
| |
| const std::unordered_map<uint32_t, std::string> signingTypeMap = { |
| {0, "Debug"}, {1, "Production"}, {2, "External"}, {4, "DOT"}}; |
| |
| const std::unordered_map<uint32_t, std::string> writeProtectMap = { |
| {0, "Disabled"}, {1, "Enabled"}}; |
| |
| const std::unordered_map<uint32_t, std::string> firmwareStateMap = { |
| {0, "Unknown"}, |
| {1, "Activated"}, |
| {2, "Pending Activation"}, |
| {3, "Staged"}, |
| {4, "Write in progress"}, |
| {5, "Inactive"}, |
| {6, "Failed authentication"}}; |
| |
| std::string mapEnumToString( |
| uint32_t value, |
| const std::unordered_map<uint32_t, std::string>& mapping) const |
| { |
| auto it = mapping.find(value); |
| return it != mapping.end() ? it->second : "Not Defined"; |
| } |
| }; |
| |
| class QueryCodeAuthKeyPerm : public CommandInterface |
| { |
| public: |
| ~QueryCodeAuthKeyPerm() = default; |
| QueryCodeAuthKeyPerm() = delete; |
| QueryCodeAuthKeyPerm(const QueryCodeAuthKeyPerm&) = delete; |
| QueryCodeAuthKeyPerm(QueryCodeAuthKeyPerm&&) = default; |
| QueryCodeAuthKeyPerm& operator=(const QueryCodeAuthKeyPerm&) = delete; |
| QueryCodeAuthKeyPerm& operator=(QueryCodeAuthKeyPerm&&) = default; |
| |
| using CommandInterface::CommandInterface; |
| |
| explicit QueryCodeAuthKeyPerm(const char* type, const char* name, |
| CLI::App* app) : |
| CommandInterface(type, name, app) |
| { |
| auto optionGroup = app->add_option_group( |
| "Required", "Query firmware code authentication key permissions"); |
| optionGroup |
| ->add_option("-c,--classification", classification, |
| "Component classification") |
| ->required(); |
| optionGroup |
| ->add_option("-i,--identifier", identifier, "Component identifier") |
| ->required(); |
| optionGroup->add_option("-d,--index", index, "Component index") |
| ->required(); |
| } |
| |
| std::pair<int, std::vector<uint8_t>> createRequestMsg() override |
| { |
| std::vector<uint8_t> requestMsg( |
| sizeof(nsm_msg_hdr) + sizeof(nsm_code_auth_key_perm_query_req)); |
| auto request = reinterpret_cast<nsm_msg*>(requestMsg.data()); |
| auto rc = encode_nsm_code_auth_key_perm_query_req( |
| instanceId, classification, identifier, index, request); |
| return std::make_pair(rc, requestMsg); |
| } |
| |
| void parseResponseMsg(nsm_msg* responsePtr, size_t payloadLength) override |
| { |
| uint8_t cc = NSM_SUCCESS; |
| uint16_t reasonCode = ERR_NULL; |
| uint16_t activeComponentKeyIndex; |
| uint16_t pendingComponentKeyIndex; |
| uint8_t permissionBitmapLength; |
| auto rc = decode_nsm_code_auth_key_perm_query_resp( |
| responsePtr, payloadLength, &cc, &reasonCode, |
| &activeComponentKeyIndex, &pendingComponentKeyIndex, |
| &permissionBitmapLength, NULL, NULL, NULL, NULL); |
| if (rc != NSM_SW_SUCCESS || cc != NSM_SUCCESS) |
| { |
| std::cerr << "Response message error: " |
| << "rc=" << rc << ", cc=" << (int)cc |
| << ", reasonCode=" << (int)reasonCode << "\n"; |
| return; |
| } |
| |
| std::vector<uint8_t> activeComponentKeyPermBitmap( |
| permissionBitmapLength); |
| std::vector<uint8_t> pendingComponentKeyPermBitmap( |
| permissionBitmapLength); |
| std::vector<uint8_t> efuseKeyPermBitmap(permissionBitmapLength); |
| std::vector<uint8_t> pendingEfuseKeyPermBitmap(permissionBitmapLength); |
| |
| rc = decode_nsm_code_auth_key_perm_query_resp( |
| responsePtr, payloadLength, &cc, &reasonCode, |
| &activeComponentKeyIndex, &pendingComponentKeyIndex, |
| &permissionBitmapLength, activeComponentKeyPermBitmap.data(), |
| pendingComponentKeyPermBitmap.data(), efuseKeyPermBitmap.data(), |
| pendingEfuseKeyPermBitmap.data()); |
| if (rc != NSM_SW_SUCCESS || cc != NSM_SUCCESS) |
| { |
| std::cerr << "Response message error: " |
| << "rc=" << rc << ", cc=" << (int)cc |
| << ", reasonCode=" << (int)reasonCode << "\n"; |
| return; |
| } |
| |
| nlohmann::ordered_json result; |
| result["Completion code"] = cc; |
| result["Reason code"] = reasonCode; |
| result["Active component key index"] = activeComponentKeyIndex; |
| result["Pending component key index"] = pendingComponentKeyIndex; |
| result["Permission bitmap length"] = permissionBitmapLength; |
| |
| auto activeComponentKeyPermIndices = |
| utils::bitmapToIndices(activeComponentKeyPermBitmap); |
| auto pendingComponentKeyPermIndices = |
| utils::bitmapToIndices(pendingComponentKeyPermBitmap); |
| auto efuseKeyPermIndices = utils::bitmapToIndices(efuseKeyPermBitmap); |
| auto pendingEfuseKeyPermIndices = |
| utils::bitmapToIndices(pendingEfuseKeyPermBitmap); |
| |
| result["Active component trusted key indices"] = |
| std::move(activeComponentKeyPermIndices.first); |
| result["Active component revoked key indices"] = |
| std::move(activeComponentKeyPermIndices.second); |
| result["Pending component trusted key indices"] = |
| std::move(pendingComponentKeyPermIndices.first); |
| result["Pending component revoked key indices"] = |
| std::move(pendingComponentKeyPermIndices.second); |
| result["EFUSE trusted key indices"] = |
| std::move(efuseKeyPermIndices.first); |
| result["EFUSE revoked key indices"] = |
| std::move(efuseKeyPermIndices.second); |
| result["Pending EFUSE trusted key indices"] = |
| std::move(pendingEfuseKeyPermIndices.first); |
| result["Pending EFUSE revoked key indices"] = |
| std::move(pendingEfuseKeyPermIndices.second); |
| |
| DisplayInJson(result); |
| } |
| |
| private: |
| uint16_t classification; |
| uint16_t identifier; |
| uint8_t index; |
| }; |
| |
| class UpdateCodeAuthKeyPerm : public CommandInterface |
| { |
| public: |
| ~UpdateCodeAuthKeyPerm() = default; |
| UpdateCodeAuthKeyPerm() = delete; |
| UpdateCodeAuthKeyPerm(const UpdateCodeAuthKeyPerm&) = delete; |
| UpdateCodeAuthKeyPerm(UpdateCodeAuthKeyPerm&&) = default; |
| UpdateCodeAuthKeyPerm& operator=(const UpdateCodeAuthKeyPerm&) = delete; |
| UpdateCodeAuthKeyPerm& operator=(UpdateCodeAuthKeyPerm&&) = default; |
| |
| using CommandInterface::CommandInterface; |
| |
| explicit UpdateCodeAuthKeyPerm(const char* type, const char* name, |
| CLI::App* app) : |
| CommandInterface(type, name, app) |
| { |
| auto optionGroup = app->add_option_group( |
| "Required", "Update firmware code authentication key permissions"); |
| optionGroup |
| ->add_option( |
| "-r,--requestType", requestType, |
| "Request type - " |
| "0 - most restrictive permitted value, 1 - specified value") |
| ->required(); |
| optionGroup |
| ->add_option("-c,--classification", classification, |
| "component classification") |
| ->required(); |
| optionGroup |
| ->add_option("-i,--identifier", identifier, "Component identifier") |
| ->required(); |
| optionGroup |
| ->add_option("-d,--index", index, "Component classification index") |
| ->required(); |
| optionGroup |
| ->add_option( |
| "-n,--nonce", nonce, |
| "Nonce obtained from Enable Irreversible Configuration command") |
| ->required(); |
| optionGroup->add_option( |
| "-k,--keys", revokedKeysString, |
| "Comma-separated list of indexes of keys to be revoked. " |
| "Cannot be used when request type is set to 0. " |
| "Required when request type is set to 1."); |
| optionGroup->add_option( |
| "-b,--bitmap", bitmapSize, |
| "Size of the permission bitmap to be sent. " |
| "If set to 0 or omitted, the size is calculated automatically " |
| "based on the provided indexes."); |
| } |
| |
| std::pair<int, std::vector<uint8_t>> createRequestMsg() override |
| { |
| std::vector<uint8_t> indices; |
| if (requestType == 0 && !revokedKeysString.empty()) |
| { |
| return std::make_pair(NSM_SW_ERROR, std::vector<uint8_t>()); |
| } |
| if (requestType == 1) |
| { |
| std::istringstream iss{revokedKeysString}; |
| std::string indexStr; |
| while (getline(iss, indexStr, ',')) |
| { |
| try |
| { |
| indices.emplace_back(static_cast<uint8_t>(stoul(indexStr))); |
| } |
| catch (const std::exception&) |
| { |
| return std::make_pair(NSM_SW_ERROR, std::vector<uint8_t>()); |
| } |
| } |
| } |
| std::vector<uint8_t> bitmap; |
| try |
| { |
| bitmap = utils::indicesToBitmap(indices, bitmapSize); |
| } |
| catch (const std::exception&) |
| { |
| return std::make_pair(NSM_SW_ERROR_LENGTH, std::vector<uint8_t>()); |
| } |
| std::vector<uint8_t> requestMsg( |
| sizeof(nsm_msg_hdr) + sizeof(nsm_code_auth_key_perm_update_req) + |
| bitmap.size()); |
| auto request = reinterpret_cast<nsm_msg*>(requestMsg.data()); |
| auto rc = encode_nsm_code_auth_key_perm_update_req( |
| 0, requestType, classification, identifier, index, nonce, |
| bitmap.size(), bitmap.data(), request); |
| return std::make_pair(rc, requestMsg); |
| } |
| |
| void parseResponseMsg(nsm_msg* responsePtr, size_t payloadLength) override |
| { |
| uint8_t cc = NSM_SUCCESS; |
| uint16_t reasonCode = ERR_NULL; |
| uint32_t updateMethod = 0; |
| |
| auto rc = decode_nsm_code_auth_key_perm_update_resp( |
| responsePtr, payloadLength, &cc, &reasonCode, &updateMethod); |
| if (rc != NSM_SW_SUCCESS || cc != NSM_SUCCESS) |
| { |
| std::cerr << "Response message error: " |
| << "rc=" << rc << ", cc=" << (int)cc |
| << ", reasonCode=" << (int)reasonCode << "\n"; |
| return; |
| } |
| |
| nlohmann::ordered_json result; |
| result["Completion code"] = cc; |
| result["Reason code"] = reasonCode; |
| // Fill update methods response |
| ordered_json updateMethods; |
| bitfield32_t updateMethodBits = {updateMethod}; |
| if (updateMethodBits.bits.bit0) |
| { |
| updateMethods.push_back("Automatic"); |
| } |
| if (updateMethodBits.bits.bit1) |
| { |
| updateMethods.push_back("Self-Contained"); |
| } |
| if (updateMethodBits.bits.bit2) |
| { |
| updateMethods.push_back("Medium-specific reset"); |
| } |
| if (updateMethodBits.bits.bit3) |
| { |
| updateMethods.push_back("System reboot"); |
| } |
| if (updateMethodBits.bits.bit4) |
| { |
| updateMethods.push_back("DC power cycle"); |
| } |
| if (updateMethodBits.bits.bit5) |
| { |
| updateMethods.push_back("AC power cycle"); |
| } |
| if (updateMethodBits.bits.bit16) |
| { |
| updateMethods.push_back("Warm Reset"); |
| } |
| if (updateMethodBits.bits.bit17) |
| { |
| updateMethods.push_back("Hot Reset"); |
| } |
| if (updateMethodBits.bits.bit18) |
| { |
| updateMethods.push_back("Function Level Reset"); |
| } |
| result["UpdateMethods"] = updateMethods; |
| |
| DisplayInJson(result); |
| } |
| |
| private: |
| nsm_code_auth_key_perm_request_type requestType; |
| uint16_t classification; |
| uint16_t identifier; |
| uint8_t index; |
| uint64_t nonce; |
| uint32_t bitmapSize; |
| std::string revokedKeysString; |
| }; |
| |
| class QueryFirmwareSecurityVersion : public CommandInterface |
| { |
| public: |
| ~QueryFirmwareSecurityVersion() = default; |
| QueryFirmwareSecurityVersion() = delete; |
| QueryFirmwareSecurityVersion(const QueryFirmwareSecurityVersion&) = delete; |
| QueryFirmwareSecurityVersion(QueryFirmwareSecurityVersion&&) = default; |
| QueryFirmwareSecurityVersion& |
| operator=(const QueryFirmwareSecurityVersion&) = delete; |
| QueryFirmwareSecurityVersion& |
| operator=(QueryFirmwareSecurityVersion&&) = default; |
| |
| explicit QueryFirmwareSecurityVersion(const char* type, const char* name, |
| CLI::App* app) : |
| CommandInterface(type, name, app) |
| { |
| auto ccOptionGroup = app->add_option_group( |
| "Required", "Parameters for Query Minimum Security Version"); |
| ccOptionGroup |
| ->add_option("-c,--classification", classification, |
| "Component classification") |
| ->required(); |
| ccOptionGroup |
| ->add_option("-i,--identifier", identifier, "Component identifier") |
| ->required(); |
| ccOptionGroup->add_option("-d,--index", index, "Component index") |
| ->required(); |
| } |
| |
| std::pair<int, std::vector<uint8_t>> createRequestMsg() override |
| { |
| printf("createRequestMsg() called"); |
| std::vector<uint8_t> requestMsg( |
| sizeof(nsm_msg_hdr) + |
| sizeof(nsm_firmware_security_version_number_req_command)); |
| nsm_firmware_security_version_number_req nsm_req; |
| nsm_req.component_classification = htole16(classification); |
| nsm_req.component_classification_index = index; |
| nsm_req.component_identifier = htole16(identifier); |
| auto request = reinterpret_cast<nsm_msg*>(requestMsg.data()); |
| auto rc = encode_nsm_query_firmware_security_version_number_req( |
| instanceId, &nsm_req, request); |
| return std::make_pair(rc, requestMsg); |
| } |
| |
| void parseResponseMsg(nsm_msg* responsePtr, size_t payloadLength) override |
| { |
| uint8_t cc = NSM_SUCCESS; |
| uint16_t reason_code = ERR_NULL; |
| struct nsm_firmware_security_version_number_resp sec_info; |
| |
| auto rc = decode_nsm_query_firmware_security_version_number_resp( |
| responsePtr, payloadLength, &cc, &reason_code, &sec_info); |
| if (rc != NSM_SW_SUCCESS || cc != NSM_SUCCESS) |
| { |
| std::cerr << "Response message error: " |
| << "rc=" << rc << ", cc=" << (int)cc |
| << ", reasonCode=" << (int)reason_code << "\n"; |
| return; |
| } |
| |
| ordered_json result; |
| result["Completion code"] = cc; |
| result["Reason code"] = reason_code; |
| result["Security Version"] = static_cast<uint16_t>( |
| htole16(sec_info.active_component_security_version)); |
| result["Pending Security Version"] = static_cast<uint16_t>( |
| htole16(sec_info.pending_component_security_version)); |
| result["Minimum Security Version"] = |
| static_cast<uint16_t>(htole16(sec_info.minimum_security_version)); |
| result["Pending Minimum Security Version"] = static_cast<uint16_t>( |
| htole16(sec_info.pending_minimum_security_version)); |
| |
| DisplayInJson(result); |
| } |
| |
| private: |
| uint16_t classification{}; |
| uint16_t identifier{}; |
| uint8_t index{}; |
| }; |
| |
| class UpdateMinSecurityVersion : public CommandInterface |
| { |
| public: |
| ~UpdateMinSecurityVersion() = default; |
| UpdateMinSecurityVersion() = delete; |
| UpdateMinSecurityVersion(const UpdateMinSecurityVersion&) = delete; |
| UpdateMinSecurityVersion(UpdateMinSecurityVersion&&) = default; |
| UpdateMinSecurityVersion& |
| operator=(const UpdateMinSecurityVersion&) = delete; |
| UpdateMinSecurityVersion& operator=(UpdateMinSecurityVersion&&) = default; |
| |
| explicit UpdateMinSecurityVersion(const char* type, const char* name, |
| CLI::App* app) : |
| CommandInterface(type, name, app) |
| { |
| auto ccOptionGroup = app->add_option_group( |
| "Required", "Parameters for Update Minimum Security Version"); |
| ccOptionGroup |
| ->add_option( |
| "-r,--requestType", requestType, |
| "Request Type. 0 - most restrictive permitted value, 1 - specified value") |
| ->required(); |
| ccOptionGroup->add_option("-c,--classification", classification, |
| "Component classification"); |
| ccOptionGroup->add_option("-i,--identifier", identifier, |
| "Component identifier"); |
| ccOptionGroup->add_option("-d,--index", index, "Component index"); |
| ccOptionGroup |
| ->add_option( |
| "-n,--nonce", nonce, |
| "Nonce obtained from Enable Irreversible Configuration command") |
| ->required(); |
| ccOptionGroup->add_option("--reqMinSecVersion", reqMinSecVersion, |
| "Required if request type is 1"); |
| } |
| |
| std::pair<int, std::vector<uint8_t>> createRequestMsg() override |
| { |
| std::vector<uint8_t> requestMsg( |
| sizeof(nsm_msg_hdr) + |
| sizeof(nsm_firmware_update_min_sec_ver_req_command)); |
| nsm_firmware_update_min_sec_ver_req nsm_req; |
| nsm_req.request_type = requestType; |
| nsm_req.component_classification = htole16(classification); |
| nsm_req.component_classification_index = index; |
| nsm_req.component_identifier = htole16(identifier); |
| nsm_req.nonce = nonce; |
| nsm_req.req_min_security_version = htole16(reqMinSecVersion); |
| auto request = reinterpret_cast<nsm_msg*>(requestMsg.data()); |
| auto rc = encode_nsm_firmware_update_sec_ver_req(instanceId, &nsm_req, |
| request); |
| return std::make_pair(rc, requestMsg); |
| } |
| |
| void parseResponseMsg(nsm_msg* responsePtr, size_t payloadLength) override |
| { |
| uint8_t cc = NSM_SUCCESS; |
| uint16_t reason_code = ERR_NULL; |
| struct nsm_firmware_update_min_sec_ver_resp sec_info; |
| |
| auto rc = decode_nsm_firmware_update_sec_ver_resp( |
| responsePtr, payloadLength, &cc, &reason_code, &sec_info); |
| if (rc != NSM_SW_SUCCESS || cc != NSM_SUCCESS) |
| { |
| std::cerr << "Response message error: " |
| << "rc=" << rc << ", cc=" << (int)cc |
| << ", reasonCode=" << (int)reason_code << "\n"; |
| return; |
| } |
| |
| ordered_json result; |
| result["Completion code"] = cc; |
| result["Reason code"] = reason_code; |
| // Fill update methods response |
| ordered_json updateMethods; |
| bitfield32_t updateMethodBits = {sec_info.update_methods}; |
| if (updateMethodBits.bits.bit0) |
| { |
| updateMethods.push_back("Automatic"); |
| } |
| if (updateMethodBits.bits.bit1) |
| { |
| updateMethods.push_back("Self-Contained"); |
| } |
| if (updateMethodBits.bits.bit2) |
| { |
| updateMethods.push_back("Medium-specific reset"); |
| } |
| if (updateMethodBits.bits.bit3) |
| { |
| updateMethods.push_back("System reboot"); |
| } |
| if (updateMethodBits.bits.bit4) |
| { |
| updateMethods.push_back("DC power cycle"); |
| } |
| if (updateMethodBits.bits.bit5) |
| { |
| updateMethods.push_back("AC power cycle"); |
| } |
| if (updateMethodBits.bits.bit16) |
| { |
| updateMethods.push_back("Warm Reset"); |
| } |
| if (updateMethodBits.bits.bit17) |
| { |
| updateMethods.push_back("Hot Reset"); |
| } |
| if (updateMethodBits.bits.bit17) |
| { |
| updateMethods.push_back("Function Level Reset"); |
| } |
| result["UpdateMethods"] = updateMethods; |
| |
| DisplayInJson(result); |
| } |
| |
| private: |
| uint16_t classification{}; |
| uint16_t identifier{}; |
| uint8_t index{}; |
| uint8_t requestType; |
| uint64_t nonce; |
| uint16_t reqMinSecVersion; |
| }; |
| |
| class IrreversibleConfig : public CommandInterface |
| { |
| public: |
| ~IrreversibleConfig() = default; |
| IrreversibleConfig() = delete; |
| IrreversibleConfig(const IrreversibleConfig&) = delete; |
| IrreversibleConfig(IrreversibleConfig&&) = default; |
| IrreversibleConfig& operator=(const IrreversibleConfig&) = delete; |
| IrreversibleConfig& operator=(IrreversibleConfig&&) = default; |
| |
| explicit IrreversibleConfig(const char* type, const char* name, |
| CLI::App* app) : |
| CommandInterface(type, name, app) |
| { |
| auto ccOptionGroup = app->add_option_group( |
| "Required", "Parameters for Irreversible Config Method"); |
| ccOptionGroup |
| ->add_option("-r,--requestType", requestType, |
| "Request Type. 0 - Query, 1 - Disable, 2 - Enable") |
| ->required(); |
| } |
| |
| std::pair<int, std::vector<uint8_t>> createRequestMsg() override |
| { |
| std::vector<uint8_t> requestMsg( |
| sizeof(nsm_msg_hdr) + |
| sizeof(nsm_firmware_irreversible_config_req_command)); |
| nsm_firmware_irreversible_config_req nsm_req; |
| nsm_req.request_type = requestType; |
| auto request = reinterpret_cast<nsm_msg*>(requestMsg.data()); |
| auto rc = encode_nsm_firmware_irreversible_config_req( |
| instanceId, &nsm_req, request); |
| return std::make_pair(rc, requestMsg); |
| } |
| |
| void parseResponseMsg(nsm_msg* responsePtr, size_t payloadLength) override |
| { |
| uint8_t cc = NSM_SUCCESS; |
| uint16_t reason_code = ERR_NULL; |
| ordered_json result; |
| switch (requestType) |
| { |
| case QUERY_IRREVERSIBLE_CFG: |
| { |
| struct nsm_firmware_irreversible_config_request_0_resp |
| cfg_0_resp{}; |
| auto rc = |
| decode_nsm_firmware_irreversible_config_request_0_resp( |
| responsePtr, payloadLength, &cc, &reason_code, |
| &cfg_0_resp); |
| if (rc != NSM_SW_SUCCESS || cc != NSM_SUCCESS) |
| { |
| std::cerr << "Response message error: " |
| << "rc=" << rc << ", cc=" << (int)cc |
| << ", reasonCode=" << (int)reason_code << "\n"; |
| return; |
| } |
| result["IrreversibleConfigurationState"] = |
| cfg_0_resp.irreversible_config_state; |
| break; |
| } |
| case DISABLE_IRREVERSIBLE_CFG: |
| { |
| auto rc = |
| decode_nsm_firmware_irreversible_config_request_1_resp( |
| responsePtr, payloadLength, &cc, &reason_code); |
| if (rc != NSM_SW_SUCCESS || cc != NSM_SUCCESS) |
| { |
| std::cerr << "Response message error: " |
| << "rc=" << rc << ", cc=" << (int)cc |
| << ", reasonCode=" << (int)reason_code << "\n"; |
| return; |
| } |
| break; |
| } |
| case ENABLE_IRREVERSIBLE_CFG: |
| { |
| struct nsm_firmware_irreversible_config_request_2_resp |
| cfg_2_resp{}; |
| auto rc = |
| decode_nsm_firmware_irreversible_config_request_2_resp( |
| responsePtr, payloadLength, &cc, &reason_code, |
| &cfg_2_resp); |
| if (rc != NSM_SW_SUCCESS || cc != NSM_SUCCESS) |
| { |
| std::cerr << "Response message error: " |
| << "rc=" << rc << ", cc=" << (int)cc |
| << ", reasonCode=" << (int)reason_code << "\n"; |
| return; |
| } |
| result["Nonce"] = static_cast<uint64_t>(cfg_2_resp.nonce); |
| break; |
| } |
| default: |
| std::cerr << "Unknown request type " << requestType << "\n"; |
| break; |
| } |
| result["Completion code"] = cc; |
| result["Reason code"] = reason_code; |
| DisplayInJson(result); |
| } |
| |
| private: |
| uint8_t requestType; |
| }; |
| |
| void registerCommand(CLI::App& app) |
| { |
| auto firmware = app.add_subcommand("firmware", |
| "Device firmware type commands"); |
| firmware->require_subcommand(1); |
| |
| auto getRotInformation = firmware->add_subcommand( |
| "GetRotInformation", |
| "Get information about a particular firmware set installed on an endpoint"); |
| commands.push_back(std::make_unique<GetRotInformation>( |
| "firmware", "QueryRoTStateInformation", getRotInformation)); |
| auto irreversibleConfig = firmware->add_subcommand( |
| "IrreversibleConfig", |
| "Query/Disable/Enable Irreversible Configuration"); |
| commands.push_back(std::make_unique<IrreversibleConfig>( |
| "firmware", "IrreversibleConfig", irreversibleConfig)); |
| auto queryCodeAuthKeyPerm = firmware->add_subcommand( |
| "QueryFWCodeAuthKey", |
| "Query firmware code authentication key permissions"); |
| commands.push_back(std::make_unique<QueryCodeAuthKeyPerm>( |
| "firmware", "QueryFWCodeAuthKey", queryCodeAuthKeyPerm)); |
| auto updateCodeAuthKeyPerm = firmware->add_subcommand( |
| "UpdateCodeAuthKeyPerm", |
| "Update firmware code authentication key permissions"); |
| commands.push_back(std::make_unique<UpdateCodeAuthKeyPerm>( |
| "firmware", "UpdateCodeAuthKeyPerm", updateCodeAuthKeyPerm)); |
| auto queryFirmwareSecurityVersion = firmware->add_subcommand( |
| "QueryFirmwareSecurityVersion", "Query Firmware Security Version"); |
| commands.push_back(std::make_unique<QueryFirmwareSecurityVersion>( |
| "firmware", "QueryFirmwareSecurityVersion", |
| queryFirmwareSecurityVersion)); |
| auto updateMinSecurityVersion = firmware->add_subcommand( |
| "UpdateMinSecurityVersion", "Update Minimum Firmware Security Version"); |
| commands.push_back(std::make_unique<UpdateMinSecurityVersion>( |
| "firmware", "UpdateMinSecurityVersion", updateMinSecurityVersion)); |
| } |
| } // namespace nsmtool::firmware |