core: Add CMAKE option to disable built-in keyblob

This commit is contained in:
PabloMK7 2026-04-10 18:04:58 +02:00
parent b2faa299d5
commit a6caff24d8
7 changed files with 63 additions and 11 deletions

View file

@ -137,6 +137,8 @@ option(ENABLE_SSE42 "Enable SSE4.2 optimizations on x86_64" ON)
option(ENABLE_DEVELOPER_OPTIONS "Enable functionality targeted at emulator developers" OFF)
option(ENABLE_BUILTIN_KEYBLOB "Enable the inclusion of the default crypto keys blob" ON)
# Compile options
CMAKE_DEPENDENT_OPTION(COMPILE_WITH_DWARF "Add DWARF debugging information" ${IS_DEBUG_BUILD} "MINGW" OFF)
option(ENABLE_LTO "Enable link time optimization" ${DEFAULT_ENABLE_LTO})

View file

@ -183,6 +183,9 @@ endif()
if(ENABLE_DEVELOPER_OPTIONS)
add_compile_definitions(ENABLE_DEVELOPER_OPTIONS)
endif()
if(ENABLE_BUILTIN_KEYBLOB)
add_compile_definitions(ENABLE_BUILTIN_KEYBLOB)
endif()
add_subdirectory(common)
add_subdirectory(core)

View file

@ -670,12 +670,16 @@ void ConfigureSystem::RefreshSecureDataStatus() {
return tr("Status: Loaded (Invalid Signature)");
case HW::UniqueData::SecureDataLoadStatus::RegionChanged:
return tr("Status: Loaded (Region Changed)");
case HW::UniqueData::SecureDataLoadStatus::CannotValidateSignature:
return tr("Status: Loaded (Cannot Validate Signature)");
case HW::UniqueData::SecureDataLoadStatus::NotFound:
return tr("Status: Not Found");
case HW::UniqueData::SecureDataLoadStatus::Invalid:
return tr("Status: Invalid");
case HW::UniqueData::SecureDataLoadStatus::IOError:
return tr("Status: IO Error");
case HW::UniqueData::SecureDataLoadStatus::NoCryptoKeys:
return tr("Status: Missing Crypto Keys");
default:
return QString();
}

View file

@ -18,7 +18,9 @@
#include "core/hle/service/fs/archive.h"
#include "core/hw/aes/arithmetic128.h"
#include "core/hw/aes/key.h"
#ifdef ENABLE_BUILTIN_KEYBLOB
#include "core/hw/default_keys.h"
#endif // ENABLE_BUILTIN_KEYBLOB
#include "core/hw/rsa/rsa.h"
#include "core/loader/loader.h"
@ -130,8 +132,8 @@ std::array<std::optional<AESKey>, NumDlpNfcKeyYs> dlp_nfc_key_y_slots;
std::array<NfcSecret, NumNfcSecrets> nfc_secrets;
AESIV nfc_iv;
AESKey otp_key;
AESIV otp_iv;
AESKey otp_key{};
AESIV otp_iv{};
// gets xor'd with the mac address to produce the final iv
AESIV dlp_checksum_mod_iv;
@ -297,6 +299,7 @@ std::istringstream GetKeysStream() {
if (file.is_open()) {
return std::istringstream(std::string(std::istreambuf_iterator<char>(file), {}));
} else {
#ifdef ENABLE_BUILTIN_KEYBLOB
// The key data is encrypted in the source to prevent easy access to it for unintended
// purposes.
std::vector<u8> kiv(16);
@ -304,6 +307,9 @@ std::istringstream GetKeysStream() {
CryptoPP::CBC_Mode<CryptoPP::AES>::Decryption(kiv.data(), kiv.size(), kiv.data())
.ProcessData(reinterpret_cast<u8*>(s.data()), default_keys_enc, s.size());
return std::istringstream(s);
#else
return std::istringstream("");
#endif // ENABLE_BUILTIN_KEYBLOB
}
}

View file

@ -1,4 +1,4 @@
// Copyright 2020 Citra Emulator Project
// Copyright Citra Emulator Project / Azahar Emulator Project
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
@ -14,7 +14,8 @@ class RsaSlot {
public:
RsaSlot() = default;
RsaSlot(std::vector<u8> exponent, std::vector<u8> modulus)
: init(true), exponent(std::move(exponent)), modulus(std::move(modulus)) {}
: init_exponent(true), init_modulus(true), exponent(std::move(exponent)),
modulus(std::move(modulus)) {}
std::vector<u8> ModularExponentiation(std::span<const u8> message,
int out_size_bytes = -1) const;
@ -25,11 +26,12 @@ public:
explicit operator bool() const {
// TODO(B3N30): Maybe check if exponent and modulus are vailid
return init;
return init_exponent && init_modulus;
}
void SetExponent(const std::vector<u8>& e) {
exponent = e;
init_exponent = true;
}
const std::vector<u8>& GetExponent() const {
@ -38,6 +40,7 @@ public:
void SetModulus(const std::vector<u8>& m) {
modulus = m;
init_modulus = true;
}
const std::vector<u8>& GetModulus() const {
@ -46,6 +49,7 @@ public:
void SetPrivateD(const std::vector<u8>& d) {
private_d = d;
init_private_d = true;
}
const std::vector<u8>& GetPrivateD() const {
@ -53,7 +57,9 @@ public:
}
private:
bool init = false;
bool init_exponent = false;
bool init_modulus = false;
bool init_private_d = false;
std::vector<u8> exponent;
std::vector<u8> modulus;
std::vector<u8> private_d;

View file

@ -27,13 +27,17 @@ static MovableSedFull movable;
static bool movable_signature_valid = false;
bool SecureInfoA::VerifySignature() const {
return HW::RSA::GetSecureInfoSlot().Verify(
std::span<const u8>(reinterpret_cast<const u8*>(&body), sizeof(body)), signature);
auto sec_info_slot = HW::RSA::GetSecureInfoSlot();
return sec_info_slot &&
sec_info_slot.Verify(
std::span<const u8>(reinterpret_cast<const u8*>(&body), sizeof(body)), signature);
}
bool LocalFriendCodeSeedB::VerifySignature() const {
return HW::RSA::GetLocalFriendCodeSeedSlot().Verify(
std::span<const u8>(reinterpret_cast<const u8*>(&body), sizeof(body)), signature);
auto lfcs_slot = HW::RSA::GetLocalFriendCodeSeedSlot();
return lfcs_slot &&
HW::RSA::GetLocalFriendCodeSeedSlot().Verify(
std::span<const u8>(reinterpret_cast<const u8*>(&body), sizeof(body)), signature);
}
bool MovableSed::VerifySignature() const {
@ -42,6 +46,9 @@ bool MovableSed::VerifySignature() const {
SecureDataLoadStatus LoadSecureInfoA() {
if (secure_info_a.IsValid()) {
if (!HW::RSA::GetSecureInfoSlot()) {
return SecureDataLoadStatus::CannotValidateSignature;
}
return secure_info_a_signature_valid
? SecureDataLoadStatus::Loaded
: (secure_info_a_region_changed ? SecureDataLoadStatus::RegionChanged
@ -63,8 +70,11 @@ SecureDataLoadStatus LoadSecureInfoA() {
return SecureDataLoadStatus::IOError;
}
HW::AES::InitKeys();
secure_info_a_region_changed = false;
HW::AES::InitKeys();
if (!HW::RSA::GetSecureInfoSlot()) {
return SecureDataLoadStatus::CannotValidateSignature;
}
secure_info_a_signature_valid = secure_info_a.VerifySignature();
if (!secure_info_a_signature_valid) {
// Check if the file has been region changed
@ -93,6 +103,9 @@ SecureDataLoadStatus LoadSecureInfoA() {
SecureDataLoadStatus LoadLocalFriendCodeSeedB() {
if (local_friend_code_seed_b.IsValid()) {
if (!HW::RSA::GetLocalFriendCodeSeedSlot()) {
return SecureDataLoadStatus::CannotValidateSignature;
}
return local_friend_code_seed_b_signature_valid ? SecureDataLoadStatus::Loaded
: SecureDataLoadStatus::InvalidSignature;
}
@ -114,6 +127,9 @@ SecureDataLoadStatus LoadLocalFriendCodeSeedB() {
}
HW::AES::InitKeys();
if (!HW::RSA::GetLocalFriendCodeSeedSlot()) {
return SecureDataLoadStatus::CannotValidateSignature;
}
local_friend_code_seed_b_signature_valid = local_friend_code_seed_b.VerifySignature();
if (!local_friend_code_seed_b_signature_valid) {
LOG_WARNING(HW, "LocalFriendCodeSeed_B signature check failed");
@ -128,10 +144,17 @@ SecureDataLoadStatus LoadOTP() {
return SecureDataLoadStatus::Loaded;
}
auto is_all_zero = [](const auto& arr) {
return std::all_of(arr.begin(), arr.end(), [](auto x) { return x == 0; });
};
const std::string filepath = GetOTPPath();
HW::AES::InitKeys();
auto otp_keyiv = HW::AES::GetOTPKeyIV();
if (is_all_zero(otp_keyiv.first) || is_all_zero(otp_keyiv.second)) {
return SecureDataLoadStatus::NoCryptoKeys;
}
auto loader_status = otp.Load(filepath, otp_keyiv.first, otp_keyiv.second);
if (loader_status != Loader::ResultStatus::Success) {
@ -169,6 +192,9 @@ SecureDataLoadStatus LoadOTP() {
SecureDataLoadStatus LoadMovable() {
if (movable.IsValid()) {
if (!HW::RSA::GetLocalFriendCodeSeedSlot()) {
return SecureDataLoadStatus::CannotValidateSignature;
}
return movable_signature_valid ? SecureDataLoadStatus::Loaded
: SecureDataLoadStatus::InvalidSignature;
}
@ -193,6 +219,9 @@ SecureDataLoadStatus LoadMovable() {
}
HW::AES::InitKeys();
if (!HW::RSA::GetLocalFriendCodeSeedSlot()) {
return SecureDataLoadStatus::CannotValidateSignature;
}
movable_signature_valid = movable.VerifySignature();
if (!movable_signature_valid) {
LOG_WARNING(HW, "movable.sed signature check failed");

View file

@ -136,10 +136,12 @@ enum class SecureDataLoadStatus {
Loaded = 0,
InvalidSignature = 1,
RegionChanged = 2,
CannotValidateSignature = 3,
NotFound = -1,
Invalid = -2,
IOError = -3,
NoCryptoKeys = -4,
};
SecureDataLoadStatus LoadSecureInfoA();