Add console unique secure data
This commit is contained in:
@@ -212,12 +212,39 @@ void Module::Interface::GetRegion(Kernel::HLERequestContext& ctx) {
|
||||
void Module::Interface::SecureInfoGetByte101(Kernel::HLERequestContext& ctx) {
|
||||
IPC::RequestParser rp(ctx);
|
||||
|
||||
LOG_DEBUG(Service_CFG, "(STUBBED) called");
|
||||
u8 ret = 0;
|
||||
if (cfg->secure_info_a_loaded) {
|
||||
ret = cfg->secure_info_a.unknown;
|
||||
}
|
||||
|
||||
IPC::RequestBuilder rb = rp.MakeBuilder(2, 0);
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
// According to 3dbrew this is normally 0.
|
||||
rb.Push<u8>(0);
|
||||
rb.Push<u8>(ret);
|
||||
}
|
||||
|
||||
void Module::Interface::SecureInfoGetSerialNo(Kernel::HLERequestContext& ctx) {
|
||||
IPC::RequestParser rp(ctx);
|
||||
[[maybe_unused]] u32 out_size = rp.Pop<u32>();
|
||||
auto out_buffer = rp.PopMappedBuffer();
|
||||
|
||||
if (out_buffer.GetSize() < sizeof(SecureInfoA::serial_number)) {
|
||||
IPC::RequestBuilder rb = rp.MakeBuilder(1, 0);
|
||||
rb.Push(ResultCode(ErrorDescription::InvalidSize, ErrorModule::Config,
|
||||
ErrorSummary::WrongArgument, ErrorLevel::Permanent));
|
||||
}
|
||||
// Never happens on real hardware, but may happen if user didn't supply a dump.
|
||||
// Always make sure to have available both secure data kinds or error otherwise.
|
||||
if (!cfg->secure_info_a_loaded || !cfg->local_friend_code_seed_b_loaded) {
|
||||
IPC::RequestBuilder rb = rp.MakeBuilder(1, 0);
|
||||
rb.Push(ResultCode(ErrorDescription::NotFound, ErrorModule::Config,
|
||||
ErrorSummary::InvalidState, ErrorLevel::Permanent));
|
||||
}
|
||||
|
||||
out_buffer.Write(&cfg->secure_info_a.serial_number, 0, sizeof(SecureInfoA::serial_number));
|
||||
|
||||
IPC::RequestBuilder rb = rp.MakeBuilder(1, 2);
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
rb.PushMappedBuffer(out_buffer);
|
||||
}
|
||||
|
||||
void Module::Interface::GetTransferableId(Kernel::HLERequestContext& ctx) {
|
||||
@@ -342,6 +369,43 @@ void Module::Interface::UpdateConfigNANDSavegame(Kernel::HLERequestContext& ctx)
|
||||
rb.Push(cfg->UpdateConfigNANDSavegame());
|
||||
}
|
||||
|
||||
void Module::Interface::GetLocalFriendCodeSeedData(Kernel::HLERequestContext& ctx) {
|
||||
IPC::RequestParser rp(ctx);
|
||||
[[maybe_unused]] u32 out_size = rp.Pop<u32>();
|
||||
auto out_buffer = rp.PopMappedBuffer();
|
||||
IPC::RequestBuilder rb = rp.MakeBuilder(1, 0);
|
||||
|
||||
if (out_buffer.GetSize() < sizeof(LocalFriendCodeSeedB)) {
|
||||
rb.Push(ResultCode(ErrorDescription::InvalidSize, ErrorModule::Config,
|
||||
ErrorSummary::WrongArgument, ErrorLevel::Permanent));
|
||||
}
|
||||
// Never happens on real hardware, but may happen if user didn't supply a dump.
|
||||
// Always make sure to have available both secure data kinds or error otherwise.
|
||||
if (!cfg->secure_info_a_loaded || !cfg->local_friend_code_seed_b_loaded) {
|
||||
rb.Push(ResultCode(ErrorDescription::NotFound, ErrorModule::Config,
|
||||
ErrorSummary::InvalidState, ErrorLevel::Permanent));
|
||||
}
|
||||
|
||||
out_buffer.Write(&cfg->local_friend_code_seed_b, 0, sizeof(LocalFriendCodeSeedB));
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
}
|
||||
|
||||
void Module::Interface::GetLocalFriendCodeSeed(Kernel::HLERequestContext& ctx) {
|
||||
IPC::RequestParser rp(ctx);
|
||||
|
||||
// Never happens on real hardware, but may happen if user didn't supply a dump.
|
||||
// Always make sure to have available both secure data kinds or error otherwise.
|
||||
if (!cfg->secure_info_a_loaded || !cfg->local_friend_code_seed_b_loaded) {
|
||||
IPC::RequestBuilder rb = rp.MakeBuilder(1, 0);
|
||||
rb.Push(ResultCode(ErrorDescription::NotFound, ErrorModule::Config,
|
||||
ErrorSummary::InvalidState, ErrorLevel::Permanent));
|
||||
}
|
||||
|
||||
IPC::RequestBuilder rb = rp.MakeBuilder(3, 0);
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
rb.Push<u64>(cfg->local_friend_code_seed_b.friend_code_seed);
|
||||
}
|
||||
|
||||
void Module::Interface::FormatConfig(Kernel::HLERequestContext& ctx) {
|
||||
IPC::RequestParser rp(ctx);
|
||||
IPC::RequestBuilder rb = rp.MakeBuilder(1, 0);
|
||||
@@ -484,6 +548,14 @@ ResultCode Module::UpdateConfigNANDSavegame() {
|
||||
return RESULT_SUCCESS;
|
||||
}
|
||||
|
||||
std::string Module::GetLocalFriendCodeSeedBPath() {
|
||||
return FileUtil::GetUserPath(FileUtil::UserPath::NANDDir) + "rw/sys/LocalFriendCodeSeed_B";
|
||||
}
|
||||
|
||||
std::string Module::GetSecureInfoAPath() {
|
||||
return FileUtil::GetUserPath(FileUtil::UserPath::NANDDir) + "rw/sys/SecureInfo_A";
|
||||
}
|
||||
|
||||
ResultCode Module::FormatConfig() {
|
||||
ResultCode res = DeleteConfigNANDSaveFile();
|
||||
// The delete command fails if the file doesn't exist, so we have to check that too
|
||||
@@ -557,6 +629,55 @@ ResultCode Module::LoadConfigNANDSaveFile() {
|
||||
return FormatConfig();
|
||||
}
|
||||
|
||||
void Module::InvalidateSecureData() {
|
||||
secure_info_a_loaded = local_friend_code_seed_b_loaded = false;
|
||||
}
|
||||
|
||||
SecureDataLoadStatus Module::LoadSecureInfoAFile() {
|
||||
if (secure_info_a_loaded) {
|
||||
return SecureDataLoadStatus::Loaded;
|
||||
}
|
||||
std::string file_path = GetSecureInfoAPath();
|
||||
if (!FileUtil::Exists(file_path)) {
|
||||
return SecureDataLoadStatus::NotFound;
|
||||
}
|
||||
FileUtil::IOFile file(file_path, "rb");
|
||||
if (!file.IsOpen()) {
|
||||
return SecureDataLoadStatus::IOError;
|
||||
}
|
||||
if (file.GetSize() != sizeof(SecureInfoA)) {
|
||||
return SecureDataLoadStatus::Invalid;
|
||||
}
|
||||
if (file.ReadBytes(&secure_info_a, sizeof(SecureInfoA)) != sizeof(SecureInfoA)) {
|
||||
return SecureDataLoadStatus::IOError;
|
||||
}
|
||||
secure_info_a_loaded = true;
|
||||
return SecureDataLoadStatus::Loaded;
|
||||
}
|
||||
|
||||
SecureDataLoadStatus Module::LoadLocalFriendCodeSeedBFile() {
|
||||
if (local_friend_code_seed_b_loaded) {
|
||||
return SecureDataLoadStatus::Loaded;
|
||||
}
|
||||
std::string file_path = GetLocalFriendCodeSeedBPath();
|
||||
if (!FileUtil::Exists(file_path)) {
|
||||
return SecureDataLoadStatus::NotFound;
|
||||
}
|
||||
FileUtil::IOFile file(file_path, "rb");
|
||||
if (!file.IsOpen()) {
|
||||
return SecureDataLoadStatus::IOError;
|
||||
}
|
||||
if (file.GetSize() != sizeof(LocalFriendCodeSeedB)) {
|
||||
return SecureDataLoadStatus::Invalid;
|
||||
}
|
||||
if (file.ReadBytes(&local_friend_code_seed_b, sizeof(LocalFriendCodeSeedB)) !=
|
||||
sizeof(LocalFriendCodeSeedB)) {
|
||||
return SecureDataLoadStatus::IOError;
|
||||
}
|
||||
local_friend_code_seed_b_loaded = true;
|
||||
return SecureDataLoadStatus::Loaded;
|
||||
}
|
||||
|
||||
Module::Module() {
|
||||
LoadConfigNANDSaveFile();
|
||||
// Check the config savegame EULA Version and update it to 0x7F7F if necessary
|
||||
@@ -569,6 +690,8 @@ Module::Module() {
|
||||
SetEULAVersion(default_version);
|
||||
UpdateConfigNANDSavegame();
|
||||
}
|
||||
LoadSecureInfoAFile();
|
||||
LoadLocalFriendCodeSeedBFile();
|
||||
}
|
||||
|
||||
Module::~Module() = default;
|
||||
|
||||
@@ -176,6 +176,28 @@ enum class AccessFlag : u16 {
|
||||
};
|
||||
DECLARE_ENUM_FLAG_OPERATORS(AccessFlag);
|
||||
|
||||
struct SecureInfoA {
|
||||
std::array<u8, 0x100> signature;
|
||||
u8 region;
|
||||
u8 unknown;
|
||||
std::array<u8, 0xF> serial_number;
|
||||
};
|
||||
static_assert(sizeof(SecureInfoA) == 0x111);
|
||||
|
||||
struct LocalFriendCodeSeedB {
|
||||
std::array<u8, 0x100> signature;
|
||||
u64 unknown;
|
||||
u64 friend_code_seed;
|
||||
};
|
||||
static_assert(sizeof(LocalFriendCodeSeedB) == 0x110);
|
||||
|
||||
enum class SecureDataLoadStatus {
|
||||
Loaded,
|
||||
NotFound,
|
||||
Invalid,
|
||||
IOError,
|
||||
};
|
||||
|
||||
class Module final {
|
||||
public:
|
||||
Module();
|
||||
@@ -230,6 +252,18 @@ public:
|
||||
*/
|
||||
void SecureInfoGetByte101(Kernel::HLERequestContext& ctx);
|
||||
|
||||
/**
|
||||
* CFG::SecureInfoGetSerialNo service function
|
||||
* Inputs:
|
||||
* 1 : Buffer Size
|
||||
* 2-3: Output mapped buffer
|
||||
* Outputs:
|
||||
* 0 : Result Header code
|
||||
* 1 : Result of function, 0 on success, otherwise error code
|
||||
* 2-3 : Output mapped buffer
|
||||
*/
|
||||
void SecureInfoGetSerialNo(Kernel::HLERequestContext& ctx);
|
||||
|
||||
/**
|
||||
* CFG::GetTransferableId service function
|
||||
* Inputs:
|
||||
@@ -324,6 +358,27 @@ public:
|
||||
*/
|
||||
void UpdateConfigNANDSavegame(Kernel::HLERequestContext& ctx);
|
||||
|
||||
/**
|
||||
* CFG::GetLocalFriendCodeSeedData service function
|
||||
* Inputs:
|
||||
* 1 : Buffer Size
|
||||
* 2-3: Output mapped buffer
|
||||
* Outputs:
|
||||
* 0 : Result Header code
|
||||
* 1 : Result of function, 0 on success, otherwise error code
|
||||
*/
|
||||
void GetLocalFriendCodeSeedData(Kernel::HLERequestContext& ctx);
|
||||
|
||||
/**
|
||||
* CFG::GetLocalFriendCodeSeed service function
|
||||
* Inputs:
|
||||
* Outputs:
|
||||
* 0 : Result Header code
|
||||
* 1 : Result of function, 0 on success, otherwise error code
|
||||
* 2-3 : Friend code seed
|
||||
*/
|
||||
void GetLocalFriendCodeSeed(Kernel::HLERequestContext& ctx);
|
||||
|
||||
/**
|
||||
* CFG::FormatConfig service function
|
||||
* Inputs:
|
||||
@@ -538,11 +593,43 @@ public:
|
||||
*/
|
||||
ResultCode UpdateConfigNANDSavegame();
|
||||
|
||||
/**
|
||||
* Invalidates the loaded secure data so that it is loaded again.
|
||||
*/
|
||||
void InvalidateSecureData();
|
||||
/**
|
||||
* Loads the LocalFriendCodeSeed_B file from NAND.
|
||||
* @returns LocalFriendCodeSeedBLoadStatus indicating the file load status.
|
||||
*/
|
||||
SecureDataLoadStatus LoadSecureInfoAFile();
|
||||
|
||||
/**
|
||||
* Loads the LocalFriendCodeSeed_B file from NAND.
|
||||
* @returns LocalFriendCodeSeedBLoadStatus indicating the file load status.
|
||||
*/
|
||||
SecureDataLoadStatus LoadLocalFriendCodeSeedBFile();
|
||||
|
||||
/**
|
||||
* Gets the SecureInfo_A path in the host filesystem
|
||||
* @returns std::string SecureInfo_A path in the host filesystem
|
||||
*/
|
||||
std::string GetSecureInfoAPath();
|
||||
|
||||
/**
|
||||
* Gets the LocalFriendCodeSeed_B path in the host filesystem
|
||||
* @returns std::string LocalFriendCodeSeed_B path in the host filesystem
|
||||
*/
|
||||
std::string GetLocalFriendCodeSeedBPath();
|
||||
|
||||
private:
|
||||
static constexpr u32 CONFIG_SAVEFILE_SIZE = 0x8000;
|
||||
std::array<u8, CONFIG_SAVEFILE_SIZE> cfg_config_file_buffer;
|
||||
std::unique_ptr<FileSys::ArchiveBackend> cfg_system_save_data_archive;
|
||||
u32 preferred_region_code = 0;
|
||||
bool secure_info_a_loaded = false;
|
||||
SecureInfoA secure_info_a;
|
||||
bool local_friend_code_seed_b_loaded = false;
|
||||
LocalFriendCodeSeedB local_friend_code_seed_b;
|
||||
|
||||
template <class Archive>
|
||||
void serialize(Archive& ar, const unsigned int);
|
||||
|
||||
@@ -28,11 +28,11 @@ CFG_I::CFG_I(std::shared_ptr<Module> cfg) : Module::Interface(std::move(cfg), "c
|
||||
{0x0401, &CFG_I::GetSystemConfig, "GetSystemConfig"},
|
||||
{0x0402, &CFG_I::SetSystemConfig, "SetSystemConfig"},
|
||||
{0x0403, &CFG_I::UpdateConfigNANDSavegame, "UpdateConfigNANDSavegame"},
|
||||
{0x0404, nullptr, "GetLocalFriendCodeSeedData"},
|
||||
{0x0405, nullptr, "GetLocalFriendCodeSeed"},
|
||||
{0x0404, &CFG_I::GetLocalFriendCodeSeedData, "GetLocalFriendCodeSeedData"},
|
||||
{0x0405, &CFG_I::GetLocalFriendCodeSeed, "GetLocalFriendCodeSeed"},
|
||||
{0x0406, &CFG_I::GetRegion, "GetRegion"},
|
||||
{0x0407, &CFG_I::SecureInfoGetByte101, "SecureInfoGetByte101"},
|
||||
{0x0408, nullptr, "SecureInfoGetSerialNo"},
|
||||
{0x0408, &CFG_I::SecureInfoGetSerialNo, "SecureInfoGetSerialNo"},
|
||||
{0x0409, nullptr, "UpdateConfigBlk00040003"},
|
||||
// cfg:i
|
||||
{0x0801, &CFG_I::GetSystemConfig, "GetSystemConfig"},
|
||||
|
||||
@@ -28,11 +28,11 @@ CFG_S::CFG_S(std::shared_ptr<Module> cfg) : Module::Interface(std::move(cfg), "c
|
||||
{0x0401, &CFG_S::GetSystemConfig, "GetSystemConfig"},
|
||||
{0x0402, &CFG_S::SetSystemConfig, "SetSystemConfig"},
|
||||
{0x0403, &CFG_S::UpdateConfigNANDSavegame, "UpdateConfigNANDSavegame"},
|
||||
{0x0404, nullptr, "GetLocalFriendCodeSeedData"},
|
||||
{0x0405, nullptr, "GetLocalFriendCodeSeed"},
|
||||
{0x0404, &CFG_S::GetLocalFriendCodeSeedData, "GetLocalFriendCodeSeedData"},
|
||||
{0x0405, &CFG_S::GetLocalFriendCodeSeed, "GetLocalFriendCodeSeed"},
|
||||
{0x0406, &CFG_S::GetRegion, "GetRegion"},
|
||||
{0x0407, &CFG_S::SecureInfoGetByte101, "SecureInfoGetByte101"},
|
||||
{0x0408, nullptr, "SecureInfoGetSerialNo"},
|
||||
{0x0408, &CFG_S::SecureInfoGetSerialNo, "SecureInfoGetSerialNo"},
|
||||
{0x0409, nullptr, "UpdateConfigBlk00040003"},
|
||||
// clang-format on
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user