updater: don't overwrite custom-public-key BCTs

This commit is contained in:
Michael Scire 2020-11-10 16:53:19 -08:00 committed by SciresM
parent b8c3128d16
commit 29facf6141
3 changed files with 111 additions and 13 deletions

View file

@ -158,9 +158,16 @@ namespace ams::updater {
R_TRY(boot0_accessor.Initialize());
ON_SCOPE_EXIT { boot0_accessor.Finalize(); };
/* Detect the use of custom public key. */
/* If custom public key is present, we want to validate BCT Sub but not Main */
bool custom_public_key = false;
R_TRY(boot0_accessor.DetectCustomPublicKey(std::addressof(custom_public_key), work_buffer, boot_image_update_type));
/* Compare BCT hashes. */
R_TRY(boot0_accessor.GetHash(nand_hash, BctSize, work_buffer, work_buffer_size, Boot0Partition::BctNormalMain));
R_TRY(ValidateBctFileHash(boot0_accessor, Boot0Partition::BctNormalMain, nand_hash, work_buffer, work_buffer_size, boot_image_update_type));
if (!custom_public_key) {
R_TRY(boot0_accessor.GetHash(nand_hash, BctSize, work_buffer, work_buffer_size, Boot0Partition::BctNormalMain));
R_TRY(ValidateBctFileHash(boot0_accessor, Boot0Partition::BctNormalMain, nand_hash, work_buffer, work_buffer_size, boot_image_update_type));
}
/* Compare BCT Sub hashes. */
R_TRY(boot0_accessor.GetHash(nand_hash, BctSize, work_buffer, work_buffer_size, Boot0Partition::BctNormalSub));
@ -213,10 +220,16 @@ namespace ams::updater {
R_TRY(boot1_accessor.Initialize());
ON_SCOPE_EXIT { boot1_accessor.Finalize(); };
/* Detect the use of custom public key. */
/* If custom public key is present, we want to validate BCT Sub but not Main */
bool custom_public_key = false;
R_TRY(boot0_accessor.DetectCustomPublicKey(std::addressof(custom_public_key), work_buffer, boot_image_update_type));
/* Compare BCT hashes. */
R_TRY(boot0_accessor.GetHash(nand_hash, BctSize, work_buffer, work_buffer_size, Boot0Partition::BctSafeMain));
R_TRY(ValidateBctFileHash(boot0_accessor, Boot0Partition::BctSafeMain, nand_hash, work_buffer, work_buffer_size, boot_image_update_type));
if (!custom_public_key) {
R_TRY(boot0_accessor.GetHash(nand_hash, BctSize, work_buffer, work_buffer_size, Boot0Partition::BctSafeMain));
R_TRY(ValidateBctFileHash(boot0_accessor, Boot0Partition::BctSafeMain, nand_hash, work_buffer, work_buffer_size, boot_image_update_type));
}
/* Compare BCT Sub hashes. */
R_TRY(boot0_accessor.GetHash(nand_hash, BctSize, work_buffer, work_buffer_size, Boot0Partition::BctSafeSub));
@ -260,6 +273,11 @@ namespace ams::updater {
R_TRY(boot0_accessor.Initialize());
ON_SCOPE_EXIT { boot0_accessor.Finalize(); };
/* Detect the use of custom public key. */
/* If custom public key is present, we want to update BCT Sub but not Main */
bool custom_public_key = false;
R_TRY(boot0_accessor.DetectCustomPublicKey(std::addressof(custom_public_key), work_buffer, boot_image_update_type));
/* Write Package1 sub. */
R_TRY(boot0_accessor.Clear(work_buffer, work_buffer_size, Boot0Partition::Package1NormalSub));
R_TRY(boot0_accessor.Write(GetPackage1Path(boot_image_update_type), work_buffer, work_buffer_size, Boot0Partition::Package1NormalSub));
@ -282,11 +300,15 @@ namespace ams::updater {
if (HasAutoRcmPreserve(boot_image_update_type) && !exosphere::IsRcmBugPatched()) {
R_TRY(boot0_accessor.PreserveAutoRcm(bct, work, Boot0Partition::BctNormalSub));
R_TRY(boot0_accessor.Write(bct, BctSize, Boot0Partition::BctNormalSub));
R_TRY(boot0_accessor.PreserveAutoRcm(bct, work, Boot0Partition::BctNormalMain));
R_TRY(boot0_accessor.Write(bct, BctSize, Boot0Partition::BctNormalMain));
if (!custom_public_key) {
R_TRY(boot0_accessor.PreserveAutoRcm(bct, work, Boot0Partition::BctNormalMain));
R_TRY(boot0_accessor.Write(bct, BctSize, Boot0Partition::BctNormalMain));
}
} else {
R_TRY(boot0_accessor.Write(bct, BctSize, Boot0Partition::BctNormalSub));
R_TRY(boot0_accessor.Write(bct, BctSize, Boot0Partition::BctNormalMain));
if (!custom_public_key) {
R_TRY(boot0_accessor.Write(bct, BctSize, Boot0Partition::BctNormalMain));
}
}
}
@ -321,6 +343,10 @@ namespace ams::updater {
R_TRY(boot1_accessor.Initialize());
ON_SCOPE_EXIT { boot1_accessor.Finalize(); };
/* Detect the use of custom public key. */
/* If custom public key is present, we want to update BCT Sub but not Main */
bool custom_public_key = false;
R_TRY(boot0_accessor.DetectCustomPublicKey(std::addressof(custom_public_key), work_buffer, boot_image_update_type));
/* Write Package1 sub. */
R_TRY(boot1_accessor.Clear(work_buffer, work_buffer_size, Boot1Partition::Package1SafeSub));
@ -343,11 +369,15 @@ namespace ams::updater {
if (HasAutoRcmPreserve(boot_image_update_type) && !exosphere::IsRcmBugPatched()) {
R_TRY(boot0_accessor.PreserveAutoRcm(bct, work, Boot0Partition::BctSafeSub));
R_TRY(boot0_accessor.Write(bct, BctSize, Boot0Partition::BctSafeSub));
R_TRY(boot0_accessor.PreserveAutoRcm(bct, work, Boot0Partition::BctSafeMain));
R_TRY(boot0_accessor.Write(bct, BctSize, Boot0Partition::BctSafeMain));
if (!custom_public_key) {
R_TRY(boot0_accessor.PreserveAutoRcm(bct, work, Boot0Partition::BctSafeMain));
R_TRY(boot0_accessor.Write(bct, BctSize, Boot0Partition::BctSafeMain));
}
} else {
R_TRY(boot0_accessor.Write(bct, BctSize, Boot0Partition::BctSafeSub));
R_TRY(boot0_accessor.Write(bct, BctSize, Boot0Partition::BctSafeMain));
if (!custom_public_key) {
R_TRY(boot0_accessor.Write(bct, BctSize, Boot0Partition::BctSafeMain));
}
}
}

View file

@ -18,6 +18,36 @@
namespace ams::updater {
namespace {
/* Recognize special public key (https://gist.github.com/SciresM/16b63ac1d80494522bdba2c57995257c). */
/* P = 19 */
/* Q = 1696986749729493925354392349339746171297507422986462747526968361144447230710192316397327889522451749459854070558277878297255552508603806832852079596337539247651161831569525505882103311631577368514276343192042634740927726070847704397913856975832811679847928433261678072951551065705680482548543833651752439700272736498378724153330763357721354498194000536297732323628263256733931353143625854828275237159155585342783077681713929284136658773985266864804093157854331138230313706015557050002740810464618031715670281442110238274404626065924786185264268216336867948322976979393032640085259926883014490947373494538254895109731 */
/* N = 0xFF696969696969696969696969696969696969696969696969696969696969696969696969696969696969696969696969696969696969696969696969696969696969696969696969696969696969696969696969696969696969696969696969696969696969696969696969696969696969696969696969696969696969696969696969696969696969696969696969696969696969696969696969696969696969696969696969696969696969696969696969696969696969696969696969696969696969696969696969696969696969696969696969696969696969696969696969696969696969696969696969696969696969696969696969696959 */
/* E = 0x10001 */
/* D = 6512128715229088976470211610075969347035078304643231077895577077900787352712063823560162578441773733649014439616165727455431015055675770987914713980812453585413988983206576233689754710500864883529402371292948326392791238474661859182717295176679567362482790015587820446999760239570255254879359445627372805817473978644067558931078225451477635089763009580492462097185005355990612929951162366081631888011031830742459571000203341001926135389508196521518687349554188686396554248868403128728646457247197407637887195043486221295751496667162366700477934591694110831002874992896076061627516220934290742867397720103040314639313 */
constexpr const u8 CustomPublicKey[0x100] = {
0x59, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69,
0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69,
0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69,
0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69,
0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69,
0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69,
0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69,
0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69,
0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69,
0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69,
0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69,
0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69,
0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69,
0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69,
0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69,
0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0xFF,
};
}
Result BisAccessor::Initialize() {
return fs::OpenBisPartition(std::addressof(this->storage), this->partition_id);
}
@ -133,11 +163,36 @@ namespace ams::updater {
size_t read_size;
R_TRY(this->Read(&read_size, work_buffer, BctSize, which));
void *dst_pubk = reinterpret_cast<void *>(reinterpret_cast<uintptr_t>(dst_bct) + BctPubkOffset);
void *src_pubk = reinterpret_cast<void *>(reinterpret_cast<uintptr_t>(work_buffer) + BctPubkOffset);
/* NOTE: AutoRcm is only viable on Erista, so hardcode erista offsets. */
void *dst_pubk = reinterpret_cast<void *>(reinterpret_cast<uintptr_t>(dst_bct) + BctPubkOffsetErista);
void *src_pubk = reinterpret_cast<void *>(reinterpret_cast<uintptr_t>(work_buffer) + BctPubkOffsetErista);
std::memcpy(dst_pubk, src_pubk, BctPubkSize);
return ResultSuccess();
}
Result Boot0Accessor::DetectCustomPublicKey(bool *out, void *work_buffer, BootImageUpdateType boot_image_update_type) {
std::memset(work_buffer, 0, BctSize);
const size_t pubk_offset = GetBctPubkOffset(boot_image_update_type);
size_t read_size;
R_TRY(this->Read(&read_size, work_buffer, BctSize, Boot0Partition::BctNormalMain));
if (std::memcmp(reinterpret_cast<void *>(reinterpret_cast<uintptr_t>(work_buffer) + pubk_offset), CustomPublicKey, sizeof(CustomPublicKey)) != 0) {
*out = false;
return ResultSuccess();
}
R_TRY(this->Read(&read_size, work_buffer, BctSize, Boot0Partition::BctSafeMain));
if (std::memcmp(reinterpret_cast<void *>(reinterpret_cast<uintptr_t>(work_buffer) + pubk_offset), CustomPublicKey, sizeof(CustomPublicKey)) != 0) {
*out = false;
return ResultSuccess();
}
*out = true;
return ResultSuccess();
}
}

View file

@ -199,7 +199,8 @@ namespace ams::updater {
class Boot0Accessor : public PartitionAccessor<Boot0Meta> {
public:
static constexpr fs::BisPartitionId PartitionId = fs::BisPartitionId::BootPartition1Root;
static constexpr size_t BctPubkOffset = 0x210;
static constexpr size_t BctPubkOffsetErista = 0x210;
static constexpr size_t BctPubkOffsetMariko = 0x10;
static constexpr size_t BctPubkSize = 0x100;
static constexpr size_t BctEksOffset = 0x450;
static constexpr size_t BctVersionOffset = 0x2330;
@ -210,10 +211,22 @@ namespace ams::updater {
static size_t GetBootloaderVersion(void *bct);
static size_t GetEksIndex(size_t bootloader_version);
static void CopyEks(void *dst_bct, const void *src_eks, size_t eks_index);
static size_t GetBctPubkOffset(BootImageUpdateType boot_image_update_type) {
switch (boot_image_update_type) {
case BootImageUpdateType::Erista:
return BctPubkOffsetErista;
case BootImageUpdateType::Mariko:
return BctPubkOffsetMariko;
AMS_UNREACHABLE_DEFAULT_CASE();
}
}
public:
Result UpdateEks(void *dst_bct, void *eks_work_buffer);
Result UpdateEksManually(void *dst_bct, const void *src_eks);
Result PreserveAutoRcm(void *dst_bct, void *work_buffer, Boot0Partition which);
Result DetectCustomPublicKey(bool *out, void *work_buffer, BootImageUpdateType boot_image_update_type);
};
class Boot1Accessor : public PartitionAccessor<Boot1Meta> {