blob: 9d760f5b11727ee96fb8710fb17fc5231e4a0065 [file] [log] [blame] [edit]
/*
* 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 "firmware-utils.h"
#include "utils.hpp"
#include <mockupResponder.hpp>
#include <phosphor-logging/lg2.hpp>
namespace MockupResponder
{
class FirmwareStateMachine
{
public:
// global states to maintain the values for testing
static const uint64_t fixedNonce = 123456789;
uint8_t configState = 0;
struct nsm_firmware_security_version_number_resp sec_respEc{3, 4, 0, 0};
struct nsm_firmware_security_version_number_resp sec_respAp{3, 4, 1, 0};
uint16_t apActiveComponentKeyIndex = 6;
uint16_t apPendingComponentKeyIndex = 6;
std::vector<uint8_t> apActiveComponentKeyPerm{0xFE, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF};
std::vector<uint8_t> apPendingComponentKeyPerm{0xFE, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF};
std::vector<uint8_t> apEfuseKeyPerm{0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00};
std::vector<uint8_t> apPendingEfuseKeyPerm{0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00};
uint16_t ecActiveComponentKeyIndex = 2;
uint16_t ecPendingComponentKeyIndex = 2;
std::vector<uint8_t> ecActiveComponentKeyPerm{0x00};
std::vector<uint8_t> ecPendingComponentKeyPerm{0x00};
std::vector<uint8_t> ecEfuseKeyPerm{0x00};
std::vector<uint8_t> ecPendingEfuseKeyPerm{0x00};
};
static std::unique_ptr<FirmwareStateMachine> fwStateMachine = nullptr;
std::optional<std::vector<uint8_t>>
MockupResponder::getRotInformation(const nsm_msg* requestMsg,
size_t requestLen)
{
struct nsm_firmware_erot_state_info_req fq_req;
auto rc = decode_nsm_query_get_erot_state_parameters_req(
requestMsg, requestLen, &fq_req);
if (rc != NSM_SW_SUCCESS)
{
lg2::error(
"decode_nsm_query_get_erot_state_parameters_req failed: rc={RC}",
"RC", rc);
return std::nullopt;
}
/* Exact message size will be counted in the encode function,
just, make sure this buffer is big enough to cover
the above number of slots */
uint16_t msg_size = sizeof(struct nsm_msg_hdr) + 250;
std::vector<uint8_t> response(msg_size, 0);
auto responseMsg = reinterpret_cast<nsm_msg*>(response.data());
uint16_t reason_code = ERR_NULL;
// Example response with firmware state
struct nsm_firmware_erot_state_info_resp fq_resp = {};
if ((fq_req.component_classification == 0x000A) &&
(fq_req.component_identifier == 0xff00))
{
const char* firmware_version1 = "01.03.0210.0003";
const char* firmware_version2 = "01.03.0210.0004";
/* Emulate a real answer form EROT device */
fq_resp.fq_resp_hdr.active_slot = 0x0;
fq_resp.fq_resp_hdr.firmware_slot_count = 2;
fq_resp.fq_resp_hdr.background_copy_policy = 1;
fq_resp.fq_resp_hdr.active_keyset = 1;
fq_resp.fq_resp_hdr.inband_update_policy = 1;
fq_resp.fq_resp_hdr.minimum_security_version = 1;
fq_resp.fq_resp_hdr.boot_status_code = 1;
fq_resp.slot_info = (struct nsm_firmware_slot_info*)malloc(
fq_resp.fq_resp_hdr.firmware_slot_count *
sizeof(struct nsm_firmware_slot_info));
memset((char*)(fq_resp.slot_info), 0,
fq_resp.fq_resp_hdr.firmware_slot_count *
sizeof(struct nsm_firmware_slot_info));
fq_resp.slot_info[0].slot_id = 0;
strcpy((char*)(&(fq_resp.slot_info[0].firmware_version_string[0])),
firmware_version1);
fq_resp.slot_info[0].build_type = 0;
fq_resp.slot_info[0].version_comparison_stamp = 1;
fq_resp.slot_info[0].signing_type = 1;
fq_resp.slot_info[0].write_protect_state = 0;
fq_resp.slot_info[0].firmware_state = 1;
fq_resp.slot_info[0].security_version_number = 1;
fq_resp.slot_info[0].signing_key_index = 1;
fq_resp.slot_info[1].slot_id = 1;
strcpy((char*)(&(fq_resp.slot_info[1].firmware_version_string[0])),
firmware_version2);
fq_resp.slot_info[1].build_type = 1;
fq_resp.slot_info[1].version_comparison_stamp = 1;
fq_resp.slot_info[1].signing_type = 1;
fq_resp.slot_info[1].write_protect_state = 1;
fq_resp.slot_info[1].firmware_state = 1;
fq_resp.slot_info[1].security_version_number = 1;
fq_resp.slot_info[1].signing_key_index = 1;
rc = encode_nsm_query_get_erot_state_parameters_resp(
requestMsg->hdr.instance_id, NSM_SUCCESS, reason_code, &fq_resp,
responseMsg);
}
else if ((fq_req.component_classification == 0x000A) &&
(fq_req.component_identifier == 0x0010))
{
const char* firmware_version1 = "24.07-1-rc26";
const char* firmware_version2 = "24.07-1-rc27";
/* Emulate a real answer form EROT device */
fq_resp.fq_resp_hdr.active_slot = 0x1;
fq_resp.fq_resp_hdr.firmware_slot_count = 2;
fq_resp.fq_resp_hdr.background_copy_policy = 1;
fq_resp.fq_resp_hdr.active_keyset = 1;
fq_resp.fq_resp_hdr.inband_update_policy = 1;
fq_resp.fq_resp_hdr.minimum_security_version = 1;
fq_resp.fq_resp_hdr.boot_status_code = 1;
fq_resp.slot_info = (struct nsm_firmware_slot_info*)malloc(
fq_resp.fq_resp_hdr.firmware_slot_count *
sizeof(struct nsm_firmware_slot_info));
memset((char*)(fq_resp.slot_info), 0,
fq_resp.fq_resp_hdr.firmware_slot_count *
sizeof(struct nsm_firmware_slot_info));
fq_resp.slot_info[0].slot_id = 0;
strcpy((char*)(&(fq_resp.slot_info[0].firmware_version_string[0])),
firmware_version1);
fq_resp.slot_info[0].build_type = 0;
fq_resp.slot_info[0].version_comparison_stamp = 1;
fq_resp.slot_info[0].signing_type = 1;
fq_resp.slot_info[0].write_protect_state = 0;
fq_resp.slot_info[0].firmware_state = 1;
fq_resp.slot_info[0].security_version_number = 1;
fq_resp.slot_info[0].signing_key_index = 1;
fq_resp.slot_info[1].slot_id = 1;
strcpy((char*)(&(fq_resp.slot_info[1].firmware_version_string[0])),
firmware_version2);
fq_resp.slot_info[1].build_type = 1;
fq_resp.slot_info[1].version_comparison_stamp = 1;
fq_resp.slot_info[1].signing_type = 1;
fq_resp.slot_info[1].write_protect_state = 1;
fq_resp.slot_info[1].firmware_state = 1;
fq_resp.slot_info[1].security_version_number = 1;
fq_resp.slot_info[1].signing_key_index = 1;
rc = encode_nsm_query_get_erot_state_parameters_resp(
requestMsg->hdr.instance_id, NSM_SUCCESS, reason_code, &fq_resp,
responseMsg);
}
else if ((fq_req.component_classification == 0x000A) &&
(fq_req.component_identifier == 0x0050))
{
const char* firmware_version1 = "322e3044";
const char* firmware_version2 = "322e3045";
/* Emulate a real answer form EROT device */
fq_resp.fq_resp_hdr.active_slot = 0x0;
fq_resp.fq_resp_hdr.firmware_slot_count = 2;
fq_resp.fq_resp_hdr.background_copy_policy = 1;
fq_resp.fq_resp_hdr.active_keyset = 1;
fq_resp.fq_resp_hdr.inband_update_policy = 1;
fq_resp.fq_resp_hdr.minimum_security_version = 1;
fq_resp.slot_info = (struct nsm_firmware_slot_info*)malloc(
fq_resp.fq_resp_hdr.firmware_slot_count *
sizeof(struct nsm_firmware_slot_info));
memset((char*)(fq_resp.slot_info), 0,
fq_resp.fq_resp_hdr.firmware_slot_count *
sizeof(struct nsm_firmware_slot_info));
fq_resp.slot_info[0].slot_id = 0;
strcpy((char*)(&(fq_resp.slot_info[0].firmware_version_string[0])),
firmware_version1);
fq_resp.slot_info[0].build_type = 0;
fq_resp.slot_info[0].version_comparison_stamp = 1;
fq_resp.slot_info[0].signing_type = 1;
fq_resp.slot_info[0].write_protect_state = 0;
fq_resp.slot_info[0].firmware_state = 1;
fq_resp.slot_info[0].security_version_number = 1;
fq_resp.slot_info[0].signing_key_index = 1;
fq_resp.slot_info[1].slot_id = 1;
strcpy((char*)(&(fq_resp.slot_info[1].firmware_version_string[0])),
firmware_version2);
fq_resp.slot_info[1].build_type = 1;
fq_resp.slot_info[1].version_comparison_stamp = 1;
fq_resp.slot_info[1].signing_type = 1;
fq_resp.slot_info[1].write_protect_state = 1;
fq_resp.slot_info[1].firmware_state = 1;
fq_resp.slot_info[1].security_version_number = 1;
fq_resp.slot_info[1].signing_key_index = 1;
rc = encode_nsm_query_get_erot_state_parameters_resp(
requestMsg->hdr.instance_id, NSM_SUCCESS, reason_code, &fq_resp,
responseMsg);
}
else
{
const char* firmware_version1 = "Version ABCDE";
const char* firmware_version2 = "Version 12345";
/* Emulate an answer with all possible fields,
but random content */
fq_resp.fq_resp_hdr.background_copy_policy = 0x30;
fq_resp.fq_resp_hdr.active_slot = 0x1;
fq_resp.fq_resp_hdr.active_keyset = 0x32;
fq_resp.fq_resp_hdr.minimum_security_version = 0x3334;
fq_resp.fq_resp_hdr.inband_update_policy = 0x35;
fq_resp.fq_resp_hdr.firmware_slot_count = 2;
fq_resp.fq_resp_hdr.boot_status_code = 0x0102030405060708;
fq_resp.slot_info = (struct nsm_firmware_slot_info*)malloc(
fq_resp.fq_resp_hdr.firmware_slot_count *
sizeof(struct nsm_firmware_slot_info));
memset((char*)(fq_resp.slot_info), 0,
fq_resp.fq_resp_hdr.firmware_slot_count *
sizeof(struct nsm_firmware_slot_info));
fq_resp.slot_info[0].slot_id = 0x40;
strcpy((char*)(&(fq_resp.slot_info[0].firmware_version_string[0])),
firmware_version1);
fq_resp.slot_info[0].version_comparison_stamp = 0x09ABCDEF;
fq_resp.slot_info[0].build_type = 0x1;
fq_resp.slot_info[0].signing_type = 0x42;
fq_resp.slot_info[0].write_protect_state = 0x43;
fq_resp.slot_info[0].firmware_state = 0x44;
fq_resp.slot_info[0].security_version_number = 0x4546;
fq_resp.slot_info[0].signing_key_index = 0x4748;
fq_resp.slot_info[1].slot_id = 0x50;
strcpy((char*)(&(fq_resp.slot_info[1].firmware_version_string[0])),
firmware_version2);
fq_resp.slot_info[1].version_comparison_stamp = 0x23456789;
fq_resp.slot_info[1].build_type = 0x1;
fq_resp.slot_info[1].signing_type = 0x52;
fq_resp.slot_info[1].write_protect_state = 0x53;
fq_resp.slot_info[1].firmware_state = 0x54;
fq_resp.slot_info[1].security_version_number = 0x5556;
fq_resp.slot_info[1].signing_key_index = 0x5758;
rc = encode_nsm_query_get_erot_state_parameters_resp(
requestMsg->hdr.instance_id, NSM_SUCCESS, reason_code, &fq_resp,
responseMsg);
}
free(fq_resp.slot_info);
assert(rc == NSM_SW_SUCCESS);
if (rc)
{
lg2::error("encode_nsm_query_token_parameters_resp failed: rc={RC}",
"RC", rc);
return std::nullopt;
}
return response;
}
std::optional<std::vector<uint8_t>>
MockupResponder::irreversibleConfig(const nsm_msg* requestMsg,
size_t requestLen)
{
if (fwStateMachine == nullptr)
{
fwStateMachine = std::make_unique<FirmwareStateMachine>();
}
struct nsm_firmware_irreversible_config_req cfg_req;
auto rc = decode_nsm_firmware_irreversible_config_req(requestMsg,
requestLen, &cfg_req);
if (rc != NSM_SW_SUCCESS)
{
lg2::error(
"decode_nsm_firmware_irreversible_config_req failed: rc={RC}", "RC",
rc);
return std::nullopt;
}
// Sample Update Irreversible Config Response
uint16_t msg_size = sizeof(struct nsm_msg_hdr) + 250;
std::vector<uint8_t> response(msg_size, 0);
auto responseMsg = reinterpret_cast<nsm_msg*>(response.data());
uint16_t reason_code = ERR_NULL;
switch (cfg_req.request_type)
{
case QUERY_IRREVERSIBLE_CFG:
{
struct nsm_firmware_irreversible_config_request_0_resp cfg_0_resp{};
cfg_0_resp.irreversible_config_state = fwStateMachine->configState;
rc = encode_nsm_firmware_irreversible_config_request_0_resp(
requestMsg->hdr.instance_id, NSM_SUCCESS, reason_code,
&cfg_0_resp, responseMsg);
assert(rc == NSM_SW_SUCCESS);
if (rc)
{
lg2::error(
"nsm_firmware_irreversible_config_request_resp failed: rc={RC}",
"RC", rc);
return std::nullopt;
}
return response;
break;
}
case DISABLE_IRREVERSIBLE_CFG:
{
fwStateMachine->configState = 0;
rc = encode_nsm_firmware_irreversible_config_request_1_resp(
requestMsg->hdr.instance_id, NSM_SUCCESS, reason_code,
responseMsg);
break;
}
case ENABLE_IRREVERSIBLE_CFG:
{
fwStateMachine->configState = 1;
struct nsm_firmware_irreversible_config_request_2_resp cfg_2_resp{};
cfg_2_resp.nonce = fwStateMachine->fixedNonce;
rc = encode_nsm_firmware_irreversible_config_request_2_resp(
requestMsg->hdr.instance_id, NSM_SUCCESS, reason_code,
&cfg_2_resp, responseMsg);
break;
}
default:
lg2::error("Unknown request type {REQ_TYPE}", "REQ_TYPE",
cfg_req.request_type);
break;
}
assert(rc == NSM_SW_SUCCESS);
if (rc)
{
lg2::error(
"nsm_firmware_irreversible_config_request_resp failed: rc={RC}",
"RC", rc);
return std::nullopt;
}
return response;
}
std::optional<std::vector<uint8_t>>
MockupResponder::codeAuthKeyPermQueryHandler(const nsm_msg* requestMsg,
size_t requestLen)
{
if (fwStateMachine == nullptr)
{
fwStateMachine = std::make_unique<FirmwareStateMachine>();
}
uint16_t componentClassification;
uint16_t componentIdentifier;
uint8_t componentClassificationIndex;
auto rc = decode_nsm_code_auth_key_perm_query_req(
requestMsg, requestLen, &componentClassification, &componentIdentifier,
&componentClassificationIndex);
assert(rc == NSM_SW_SUCCESS);
if (rc != NSM_SW_SUCCESS)
{
lg2::error("decode_nsm_code_auth_key_perm_query_req failed: rc={RC}",
"RC", rc);
return std::nullopt;
}
if (componentClassification != 0x000A)
{
lg2::error("Invalid component classification value");
return std::nullopt;
}
if (componentClassificationIndex != 0)
{
lg2::error("Invalid component classification index value");
return std::nullopt;
}
if (componentIdentifier != 0x0010 && componentIdentifier != 0xFF00)
{
lg2::error("Invalid component identifier value");
return std::nullopt;
}
bool isAp = componentIdentifier == 0x0010;
uint8_t bitmapLength =
isAp ? fwStateMachine->apActiveComponentKeyPerm.size()
: fwStateMachine->ecActiveComponentKeyPerm.size();
std::vector<uint8_t> response(
sizeof(nsm_msg_hdr) + sizeof(nsm_code_auth_key_perm_query_resp) +
bitmapLength * 4u,
0);
auto responseMsg = reinterpret_cast<nsm_msg*>(response.data());
uint16_t reasonCode = ERR_NULL;
if (isAp)
{
rc = encode_nsm_code_auth_key_perm_query_resp(
requestMsg->hdr.instance_id, NSM_SUCCESS, reasonCode,
fwStateMachine->apActiveComponentKeyIndex,
fwStateMachine->apPendingComponentKeyIndex, bitmapLength,
fwStateMachine->apActiveComponentKeyPerm.data(),
fwStateMachine->apPendingComponentKeyPerm.data(),
fwStateMachine->apEfuseKeyPerm.data(),
fwStateMachine->apPendingEfuseKeyPerm.data(), responseMsg);
}
else
{
rc = encode_nsm_code_auth_key_perm_query_resp(
requestMsg->hdr.instance_id, NSM_SUCCESS, reasonCode,
fwStateMachine->ecActiveComponentKeyIndex,
fwStateMachine->ecPendingComponentKeyIndex, bitmapLength,
fwStateMachine->ecActiveComponentKeyPerm.data(),
fwStateMachine->ecPendingComponentKeyPerm.data(),
fwStateMachine->ecEfuseKeyPerm.data(),
fwStateMachine->ecPendingEfuseKeyPerm.data(), responseMsg);
}
assert(rc == NSM_SW_SUCCESS);
if (rc != NSM_SW_SUCCESS)
{
lg2::error("encode_nsm_code_auth_key_perm_query_resp failed: rc={RC}",
"RC", rc);
return std::nullopt;
}
return response;
}
std::optional<std::vector<uint8_t>>
MockupResponder::codeAuthKeyPermUpdateHandler(const nsm_msg* requestMsg,
size_t requestLen)
{
if (fwStateMachine == nullptr)
{
fwStateMachine = std::make_unique<FirmwareStateMachine>();
}
nsm_code_auth_key_perm_request_type requestType;
uint16_t componentClassification;
uint16_t componentIdentifier;
uint8_t componentClassificationIndex;
uint64_t nonce;
uint8_t bitmapLength;
std::vector<uint8_t> response(
sizeof(nsm_msg_hdr) + sizeof(nsm_code_auth_key_perm_update_resp), 0);
auto responseMsg = reinterpret_cast<nsm_msg*>(response.data());
uint16_t reasonCode = ERR_NULL;
uint32_t updateMethod = 0;
auto encodeResp = [&](uint8_t cc) -> std::optional<std::vector<uint8_t>> {
int rc = encode_nsm_code_auth_key_perm_update_resp(
requestMsg->hdr.instance_id, cc, reasonCode, updateMethod,
responseMsg);
assert(rc == NSM_SW_SUCCESS);
if (rc != NSM_SW_SUCCESS)
{
lg2::error(
"encode_nsm_code_auth_key_perm_update_resp failed: rc={RC}",
"RC", rc);
return std::nullopt;
}
return response;
};
auto rc = decode_nsm_code_auth_key_perm_update_req(
requestMsg, requestLen, &requestType, &componentClassification,
&componentIdentifier, &componentClassificationIndex, &nonce,
&bitmapLength, nullptr);
assert(rc == NSM_SW_SUCCESS);
if (rc != NSM_SW_SUCCESS)
{
lg2::error("decode_nsm_code_auth_key_perm_update_req failed: rc={RC}",
"RC", rc);
return std::nullopt;
}
if (requestType !=
NSM_CODE_AUTH_KEY_PERM_REQUEST_TYPE_MOST_RESTRICTIVE_VALUE &&
requestType != NSM_CODE_AUTH_KEY_PERM_REQUEST_TYPE_SPECIFIED_VALUE)
{
lg2::error("Invalid request type");
return encodeResp(NSM_ERR_INVALID_DATA);
}
if (requestType ==
NSM_CODE_AUTH_KEY_PERM_REQUEST_TYPE_MOST_RESTRICTIVE_VALUE &&
bitmapLength != 0)
{
lg2::error("Invalid request type and bitmap length");
return encodeResp(NSM_ERR_INVALID_DATA);
}
if (componentClassification != 0x000A)
{
lg2::error("Invalid component classification value");
return encodeResp(NSM_ERR_INVALID_DATA);
}
if (componentClassificationIndex != 0)
{
lg2::error("Invalid component classification index value");
return encodeResp(NSM_ERR_INVALID_DATA);
}
if (componentIdentifier != 0x0010 && componentIdentifier != 0xFF00)
{
lg2::error("Invalid component identifier value");
return encodeResp(NSM_ERR_INVALID_DATA);
}
if (fwStateMachine->configState == 0)
{
return encodeResp(0x87); // irreversible config disabled
}
else if (nonce != fwStateMachine->fixedNonce)
{
return encodeResp(0x88); // nonce mismatch
}
bool isAp = componentIdentifier == 0x0010;
std::vector<uint8_t> bitmap(bitmapLength);
rc = decode_nsm_code_auth_key_perm_update_req(
requestMsg, requestLen, &requestType, &componentClassification,
&componentIdentifier, &componentClassificationIndex, &nonce,
&bitmapLength, bitmap.data());
assert(rc == NSM_SW_SUCCESS);
if (rc != NSM_SW_SUCCESS)
{
lg2::error("decode_nsm_code_auth_key_perm_update_req failed: rc={RC}",
"RC", rc);
return std::nullopt;
}
if (isAp)
{
if (requestType ==
NSM_CODE_AUTH_KEY_PERM_REQUEST_TYPE_MOST_RESTRICTIVE_VALUE)
{
std::vector<uint8_t> indices;
for (auto i = 0; i < fwStateMachine->apActiveComponentKeyIndex; ++i)
{
indices.emplace_back(i);
}
try
{
bitmap = utils::indicesToBitmap(indices);
}
catch (const std::exception&)
{
return encodeResp(NSM_ERR_INVALID_DATA_LENGTH);
}
}
if (bitmapLength > fwStateMachine->apPendingEfuseKeyPerm.size())
{
return encodeResp(NSM_ERR_INVALID_DATA_LENGTH);
}
for (size_t i = 0; i < bitmap.size(); ++i)
{
fwStateMachine->apPendingEfuseKeyPerm[i] |= bitmap[i];
}
updateMethod = NSM_EFUSE_UPDATE_METHOD_DC_POWER_CYCLE;
}
else
{
if (requestType ==
NSM_CODE_AUTH_KEY_PERM_REQUEST_TYPE_MOST_RESTRICTIVE_VALUE)
{
std::vector<uint8_t> indices;
for (auto i = 0; i < fwStateMachine->ecActiveComponentKeyIndex; ++i)
{
indices.emplace_back(i);
}
try
{
bitmap = utils::indicesToBitmap(indices);
}
catch (const std::exception&)
{
return encodeResp(NSM_ERR_INVALID_DATA_LENGTH);
}
}
if (bitmapLength > fwStateMachine->ecEfuseKeyPerm.size())
{
return encodeResp(NSM_ERR_INVALID_DATA_LENGTH);
}
for (size_t i = 0; i < bitmap.size(); ++i)
{
fwStateMachine->ecEfuseKeyPerm[i] |= bitmap[i];
fwStateMachine->ecPendingEfuseKeyPerm[i] |= bitmap[i];
}
updateMethod = NSM_EFUSE_UPDATE_METHOD_AUTO;
}
return encodeResp(NSM_SUCCESS);
}
std::optional<std::vector<uint8_t>>
MockupResponder::queryFirmwareSecurityVersion(const nsm_msg* requestMsg,
size_t requestLen)
{
if (fwStateMachine == nullptr)
{
fwStateMachine = std::make_unique<FirmwareStateMachine>();
}
struct nsm_firmware_security_version_number_req sec_req;
auto rc = decode_nsm_query_firmware_security_version_number_req(
requestMsg, requestLen, &sec_req);
if (rc != NSM_SW_SUCCESS)
{
lg2::error(
"decode_nsm_query_firmware_security_version_number_req failed: rc={RC}",
"RC", rc);
return std::nullopt;
}
uint16_t msg_size =
sizeof(struct nsm_msg_hdr) +
sizeof(nsm_firmware_security_version_number_resp_command);
std::vector<uint8_t> response(msg_size, 0);
auto responseMsg = reinterpret_cast<nsm_msg*>(response.data());
uint16_t reason_code = ERR_NULL;
if (sec_req.component_identifier == 0xFF00) // EC FW
{
rc = encode_nsm_query_firmware_security_version_number_resp(
requestMsg->hdr.instance_id, NSM_SUCCESS, reason_code,
&fwStateMachine->sec_respEc, responseMsg);
}
else
{
rc = encode_nsm_query_firmware_security_version_number_resp(
requestMsg->hdr.instance_id, NSM_SUCCESS, reason_code,
&fwStateMachine->sec_respAp, responseMsg);
}
assert(rc == NSM_SW_SUCCESS);
if (rc)
{
lg2::error("nsm_firmware_security_version_number_resp failed: rc={RC}",
"RC", rc);
return std::nullopt;
}
return response;
}
std::optional<std::vector<uint8_t>>
MockupResponder::updateMinSecurityVersion(const nsm_msg* requestMsg,
size_t requestLen)
{
if (fwStateMachine == nullptr)
{
fwStateMachine = std::make_unique<FirmwareStateMachine>();
}
struct nsm_firmware_update_min_sec_ver_req sec_req;
auto rc = decode_nsm_firmware_update_sec_ver_req(requestMsg, requestLen,
&sec_req);
if (rc != NSM_SW_SUCCESS)
{
lg2::error("decode_nsm_firmware_update_sec_ver_req failed: rc={RC}",
"RC", rc);
return std::nullopt;
}
// Sample Update Min Security Version Response
struct nsm_firmware_update_min_sec_ver_resp sec_resp{};
uint16_t msg_size = sizeof(struct nsm_msg_hdr) +
sizeof(nsm_firmware_update_min_sec_ver_req_command);
std::vector<uint8_t> response(msg_size, 0);
auto responseMsg = reinterpret_cast<nsm_msg*>(response.data());
uint16_t reason_code = ERR_NULL;
if (sec_req.request_type == REQUEST_TYPE_SPECIFIED_VALUE &&
sec_req.req_min_security_version == 0)
{
// invalid data
rc = encode_nsm_firmware_update_sec_ver_resp(
requestMsg->hdr.instance_id, NSM_ERR_INVALID_DATA, reason_code,
&sec_resp, responseMsg);
return response;
}
if (sec_req.nonce != fwStateMachine->fixedNonce)
{
uint8_t cc = 0x88; // nonce mismatch
rc = encode_nsm_firmware_update_sec_ver_resp(
requestMsg->hdr.instance_id, cc, reason_code, &sec_resp,
responseMsg);
return response;
}
if (fwStateMachine->configState == 0)
{
uint8_t cc = 0x87; // irreversible config disabled
rc = encode_nsm_firmware_update_sec_ver_resp(
requestMsg->hdr.instance_id, cc, reason_code, &sec_resp,
responseMsg);
return response;
}
if (sec_req.request_type == REQUEST_TYPE_MOST_RESTRICTIVE_VALUE)
{
if (sec_req.component_identifier == 0xFF00)
{
fwStateMachine->sec_respEc.minimum_security_version =
fwStateMachine->sec_respEc.active_component_security_version;
sec_resp.update_methods = 0x1; // Automatic
}
else
{
fwStateMachine->sec_respAp.pending_minimum_security_version =
fwStateMachine->sec_respAp.active_component_security_version;
sec_resp.update_methods = 0x30; // DC Power cycle & AC Power cycle
}
}
else
{
if (sec_req.component_identifier == 0xFF00)
{
if (sec_req.req_min_security_version >=
fwStateMachine->sec_respEc.minimum_security_version &&
sec_req.req_min_security_version <=
fwStateMachine->sec_respEc
.active_component_security_version)
{
fwStateMachine->sec_respEc.minimum_security_version =
sec_req.req_min_security_version;
sec_resp.update_methods = 0x1; // Automatic
}
else
{
// invalid data
rc = encode_nsm_firmware_update_sec_ver_resp(
requestMsg->hdr.instance_id, NSM_ERR_INVALID_DATA,
reason_code, &sec_resp, responseMsg);
return response;
}
}
else
{
if (sec_req.req_min_security_version > 0 &&
sec_req.req_min_security_version <=
fwStateMachine->sec_respAp
.active_component_security_version)
{
fwStateMachine->sec_respAp.pending_minimum_security_version =
sec_req.req_min_security_version;
sec_resp.update_methods =
0x30; // DC Power cycle & AC Power cycle
}
else
{
// invalid data
rc = encode_nsm_firmware_update_sec_ver_resp(
requestMsg->hdr.instance_id, NSM_ERR_INVALID_DATA,
reason_code, &sec_resp, responseMsg);
return response;
}
}
}
rc = encode_nsm_firmware_update_sec_ver_resp(requestMsg->hdr.instance_id,
NSM_SUCCESS, reason_code,
&sec_resp, responseMsg);
assert(rc == NSM_SW_SUCCESS);
if (rc)
{
lg2::error("encode_nsm_firmware_update_sec_ver_resp failed: rc={RC}",
"RC", rc);
return std::nullopt;
}
return response;
}
} // namespace MockupResponder