From e9ea226e309431198ff2970e225a774da22e7f26 Mon Sep 17 00:00:00 2001 From: msuih Date: Mon, 7 Oct 2019 18:04:30 +0300 Subject: [PATCH] Validate firmware before installing --- rpcs3/Crypto/key_vault.h | 7 +++++++ rpcs3/Loader/PUP.cpp | 25 +++++++++++++++++++++++++ rpcs3/Loader/PUP.h | 1 + rpcs3/rpcs3qt/main_window.cpp | 25 +++++++++++++++++++++++++ 4 files changed, 58 insertions(+) diff --git a/rpcs3/Crypto/key_vault.h b/rpcs3/Crypto/key_vault.h index e1015063be..9b6ef84c26 100644 --- a/rpcs3/Crypto/key_vault.h +++ b/rpcs3/Crypto/key_vault.h @@ -152,6 +152,13 @@ static u8 SCEPKG_ERK[0x20] = { 0x4D, 0xBC, 0xB2, 0xCB, 0x52, 0xC5, 0xA2, 0xF8, 0xB0, 0x2B, 0x10, 0x31 }; +static u8 PUP_KEY[0x40] = { + 0xF4, 0x91, 0xAD, 0x94, 0xC6, 0x81, 0x10, 0x96, 0x91, 0x5F, 0xD5, 0xD2, 0x44, 0x81, 0xAE, 0xDC, 0xED, 0xED, 0xBE, 0x6B, + 0xE5, 0x13, 0x72, 0x4D, 0xD8, 0xF7, 0xB6, 0x91, 0xE8, 0x8A, 0x38, 0xF4, 0xB5, 0x16, 0x2B, 0xFB, 0xEC, 0xBE, 0x3A, 0x62, + 0x18, 0x5D, 0xD7, 0xC9, 0x4D, 0xA2, 0x22, 0x5A, 0xDA, 0x3F, 0xBF, 0xCE, 0x55, 0x5B, 0x9E, 0xA9, 0x64, 0x98, 0x29, 0xEB, + 0x30, 0xCE, 0x83, 0x66 +}; + class KeyVault { std::vector sk_LV0_arr; diff --git a/rpcs3/Loader/PUP.cpp b/rpcs3/Loader/PUP.cpp index f2722ea41c..9da738f99c 100644 --- a/rpcs3/Loader/PUP.cpp +++ b/rpcs3/Loader/PUP.cpp @@ -1,5 +1,8 @@ #include "stdafx.h" +#include "Crypto/sha1.h" +#include "Crypto/key_vault.h" + #include "PUP.h" pup_object::pup_object(const fs::file& file): m_file(file) @@ -10,6 +13,7 @@ pup_object::pup_object(const fs::file& file): m_file(file) return; } + m_file.seek(0); PUPHeader m_header; m_file.read(m_header); if (m_header.magic != "SCEUF\0\0\0"_u64) @@ -40,3 +44,24 @@ fs::file pup_object::get_file(u64 entry_id) } return fs::file(); } + +bool pup_object::validate_hashes() +{ + for (size_t i = 0; i < m_file_tbl.size(); i++) + { + u8 *hash = m_hash_tbl[i].hash; + PUPFileEntry file = m_file_tbl[i]; + + std::vector buffer(file.data_length); + m_file.seek(file.data_offset); + m_file.read(buffer.data(), file.data_length); + + u8 output[20] = {}; + sha1_hmac(PUP_KEY, sizeof(PUP_KEY), buffer.data(), buffer.size(), output); + if (memcmp(output, hash, 20) != 0) + { + return false; + } + } + return true; +} diff --git a/rpcs3/Loader/PUP.h b/rpcs3/Loader/PUP.h index 2f70e4f6ea..4f28580030 100644 --- a/rpcs3/Loader/PUP.h +++ b/rpcs3/Loader/PUP.h @@ -44,4 +44,5 @@ public: explicit operator bool() const { return isValid; } fs::file get_file(u64 entry_id); + bool validate_hashes(); }; diff --git a/rpcs3/rpcs3qt/main_window.cpp b/rpcs3/rpcs3qt/main_window.cpp index 0b1790ea92..0a05bd47d4 100644 --- a/rpcs3/rpcs3qt/main_window.cpp +++ b/rpcs3/rpcs3qt/main_window.cpp @@ -506,6 +506,24 @@ void main_window::InstallPup(const QString& dropPath) return; } + if (pup_f.size() < sizeof(PUPHeader)) + { + LOG_ERROR(GENERAL, "Too small PUP file: %llu", pup_f.size()); + QMessageBox::critical(this, tr("Failure!"), tr("Error while installing firmware: PUP file size is invalid.")); + return; + } + + struct PUPHeader header = {}; + pup_f.seek(0); + pup_f.read(header); + + if (header.header_length + header.data_length != pup_f.size()) + { + LOG_ERROR(GENERAL, "Firmware size mismatch, expected: %llu, actual: %llu + %llu", pup_f.size(), header.header_length, header.data_length); + QMessageBox::critical(this, tr("Failure!"), tr("Error while installing firmware: PUP file is corrupted.")); + return; + } + pup_object pup(pup_f); if (!pup) { @@ -514,6 +532,13 @@ void main_window::InstallPup(const QString& dropPath) return; } + if (!pup.validate_hashes()) + { + LOG_ERROR(GENERAL, "Error while installing firmware: Hash check failed. "); + QMessageBox::critical(this, tr("Failure!"), tr("Error while installing firmware: PUP file contents are invalid.")); + return; + } + fs::file update_files_f = pup.get_file(0x300); tar_object update_files(update_files_f); auto updatefilenames = update_files.get_filenames();