From d770c602052a9016f4577ed8c993a8f78f8e5507 Mon Sep 17 00:00:00 2001 From: Zach Hilman Date: Sat, 25 Aug 2018 11:43:27 -0400 Subject: key_manager: Avoid autogeneration if key exists --- src/core/crypto/key_manager.cpp | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) (limited to 'src/core/crypto') diff --git a/src/core/crypto/key_manager.cpp b/src/core/crypto/key_manager.cpp index f768533da..bd4b3d7c7 100644 --- a/src/core/crypto/key_manager.cpp +++ b/src/core/crypto/key_manager.cpp @@ -231,18 +231,28 @@ void KeyManager::WriteKeyToFile(bool title_key, std::string_view keyname, } void KeyManager::SetKey(S128KeyType id, Key128 key, u64 field1, u64 field2) { - const auto iter = std::find_if( + if (s128_keys.find({id, field1, field2}) != s128_keys.end()) + return; + if (id == S128KeyType::Titlekey) { + Key128 rights_id; + std::memcpy(rights_id.data(), &field2, sizeof(u64)); + std::memcpy(rights_id.data() + sizeof(u64), &field1, sizeof(u64)); + WriteKeyToFile(true, fmt::format("{}", Common::HexArrayToString(rights_id)), key); + } + const auto iter2 = std::find_if( s128_file_id.begin(), s128_file_id.end(), [&id, &field1, &field2](const std::pair> elem) { return std::tie(elem.second.type, elem.second.field1, elem.second.field2) == std::tie(id, field1, field2); }); - if (iter != s128_file_id.end()) - WriteKeyToFile(id == S128KeyType::Titlekey, iter->first, key); + if (iter2 != s128_file_id.end()) + WriteKeyToFile(false, iter2->first, key); s128_keys[{id, field1, field2}] = key; } void KeyManager::SetKey(S256KeyType id, Key256 key, u64 field1, u64 field2) { + if (s256_keys.find({id, field1, field2}) != s256_keys.end()) + return; const auto iter = std::find_if( s256_file_id.begin(), s256_file_id.end(), [&id, &field1, &field2](const std::pair> elem) { -- cgit v1.2.3 From 5c8aff984e47c0f471e9eafd071031bc49ad8efc Mon Sep 17 00:00:00 2001 From: Zach Hilman Date: Sat, 25 Aug 2018 11:48:23 -0400 Subject: card_image: Parse XCI secure partition with NSP Eliminated duplicate code and adds support for Rev1+ carts --- src/core/crypto/key_manager.h | 2 ++ src/core/file_sys/card_image.cpp | 33 ++++++++++++++++++++++++++------- src/core/file_sys/card_image.h | 7 +++++++ src/core/loader/xci.cpp | 7 +++---- 4 files changed, 38 insertions(+), 11 deletions(-) (limited to 'src/core/crypto') diff --git a/src/core/crypto/key_manager.h b/src/core/crypto/key_manager.h index bf51bf31f..ce67913bb 100644 --- a/src/core/crypto/key_manager.h +++ b/src/core/crypto/key_manager.h @@ -17,6 +17,8 @@ enum class ResultStatus : u16; namespace Core::Crypto { +constexpr u64 TICKET_FILE_TITLEKEY_OFFSET = 0x180; + using Key128 = std::array; using Key256 = std::array; using SHA256Hash = std::array; diff --git a/src/core/file_sys/card_image.cpp b/src/core/file_sys/card_image.cpp index ce4423fa6..d0f1afac0 100644 --- a/src/core/file_sys/card_image.cpp +++ b/src/core/file_sys/card_image.cpp @@ -10,6 +10,7 @@ #include "common/logging/log.h" #include "core/file_sys/card_image.h" #include "core/file_sys/content_archive.h" +#include "core/file_sys/nca_metadata.h" #include "core/file_sys/partition_filesystem.h" #include "core/file_sys/vfs_offset.h" #include "core/loader/loader.h" @@ -44,15 +45,19 @@ XCI::XCI(VirtualFile file_) : file(std::move(file_)), partitions(0x4) { partitions[static_cast(partition)] = std::make_shared(raw); } - program_nca_status = Loader::ResultStatus::ErrorXCIMissingProgramNCA; + secure_partition = std::make_shared( + main_hfs.GetFile(partition_names[static_cast(XCIPartition::Secure)])); - auto result = AddNCAFromPartition(XCIPartition::Secure); - if (result != Loader::ResultStatus::Success) { - status = result; - return; - } + const auto secure_ncas = secure_partition->GetNCAsCollapsed(); + std::copy(secure_ncas.begin(), secure_ncas.end(), std::back_inserter(ncas)); + + program_nca_status = Loader::ResultStatus::ErrorXCIMissingProgramNCA; + program = + secure_partition->GetNCA(secure_partition->GetProgramTitleID(), ContentRecordType::Program); + if (program != nullptr) + program_nca_status = program->GetStatus(); - result = AddNCAFromPartition(XCIPartition::Update); + auto result = AddNCAFromPartition(XCIPartition::Update); if (result != Loader::ResultStatus::Success) { status = result; return; @@ -89,6 +94,10 @@ VirtualDir XCI::GetPartition(XCIPartition partition) const { return partitions[static_cast(partition)]; } +std::shared_ptr XCI::GetSecurePartitionNSP() const { + return secure_partition; +} + VirtualDir XCI::GetSecurePartition() const { return GetPartition(XCIPartition::Secure); } @@ -105,6 +114,16 @@ VirtualDir XCI::GetLogoPartition() const { return GetPartition(XCIPartition::Logo); } +std::shared_ptr XCI::GetProgramNCA() const { + return program; +} + +VirtualFile XCI::GetProgramNCAFile() const { + if (GetProgramNCA() == nullptr) + return nullptr; + return GetProgramNCA()->GetBaseFile(); +} + const std::vector>& XCI::GetNCAs() const { return ncas; } diff --git a/src/core/file_sys/card_image.h b/src/core/file_sys/card_image.h index 4f104d18a..b73f1d900 100644 --- a/src/core/file_sys/card_image.h +++ b/src/core/file_sys/card_image.h @@ -10,6 +10,8 @@ #include "common/common_types.h" #include "common/swap.h" #include "core/file_sys/vfs.h" +#include "core/loader/loader.h" +#include "submission_package.h" namespace Loader { enum class ResultStatus : u16; @@ -71,11 +73,14 @@ public: u8 GetFormatVersion() const; VirtualDir GetPartition(XCIPartition partition) const; + std::shared_ptr GetSecurePartitionNSP() const; VirtualDir GetSecurePartition() const; VirtualDir GetNormalPartition() const; VirtualDir GetUpdatePartition() const; VirtualDir GetLogoPartition() const; + std::shared_ptr GetProgramNCA() const; + VirtualFile GetProgramNCAFile() const; const std::vector>& GetNCAs() const; std::shared_ptr GetNCAByType(NCAContentType type) const; VirtualFile GetNCAFileByType(NCAContentType type) const; @@ -101,6 +106,8 @@ private: Loader::ResultStatus program_nca_status; std::vector partitions; + std::shared_ptr secure_partition; + std::shared_ptr program; std::vector> ncas; }; } // namespace FileSys diff --git a/src/core/loader/xci.cpp b/src/core/loader/xci.cpp index 9dc4d1f35..75b998faa 100644 --- a/src/core/loader/xci.cpp +++ b/src/core/loader/xci.cpp @@ -17,8 +17,7 @@ namespace Loader { AppLoader_XCI::AppLoader_XCI(FileSys::VirtualFile file) : AppLoader(file), xci(std::make_unique(file)), - nca_loader(std::make_unique( - xci->GetNCAFileByType(FileSys::NCAContentType::Program))) { + nca_loader(std::make_unique(xci->GetProgramNCAFile())) { if (xci->GetStatus() != ResultStatus::Success) return; const auto control_nca = xci->GetNCAByType(FileSys::NCAContentType::Control); @@ -64,11 +63,11 @@ ResultStatus AppLoader_XCI::Load(Kernel::SharedPtr& process) { if (xci->GetProgramNCAStatus() != ResultStatus::Success) return xci->GetProgramNCAStatus(); - const auto nca = xci->GetNCAFileByType(FileSys::NCAContentType::Program); + const auto nca = xci->GetProgramNCA(); if (nca == nullptr && !Core::Crypto::KeyManager::KeyFileExists(false)) return ResultStatus::ErrorMissingProductionKeyFile; - auto result = nca_loader->Load(process); + const auto result = nca_loader->Load(process); if (result != ResultStatus::Success) return result; -- cgit v1.2.3 From e4e55d064edd71fbf359dec9d6b5efad4f0d6c91 Mon Sep 17 00:00:00 2001 From: Zach Hilman Date: Sat, 25 Aug 2018 22:42:54 -0400 Subject: nsp: Comply with style and performance guidelines --- src/core/crypto/key_manager.cpp | 2 +- src/core/file_sys/card_image.cpp | 1 + src/core/file_sys/card_image.h | 2 +- src/core/file_sys/submission_package.cpp | 57 ++++++++++++++++++-------------- src/core/file_sys/submission_package.h | 2 ++ src/core/loader/nsp.cpp | 11 ++++-- src/core/loader/nsp.h | 2 +- 7 files changed, 48 insertions(+), 29 deletions(-) (limited to 'src/core/crypto') diff --git a/src/core/crypto/key_manager.cpp b/src/core/crypto/key_manager.cpp index bd4b3d7c7..6f27f990b 100644 --- a/src/core/crypto/key_manager.cpp +++ b/src/core/crypto/key_manager.cpp @@ -237,7 +237,7 @@ void KeyManager::SetKey(S128KeyType id, Key128 key, u64 field1, u64 field2) { Key128 rights_id; std::memcpy(rights_id.data(), &field2, sizeof(u64)); std::memcpy(rights_id.data() + sizeof(u64), &field1, sizeof(u64)); - WriteKeyToFile(true, fmt::format("{}", Common::HexArrayToString(rights_id)), key); + WriteKeyToFile(true, Common::HexArrayToString(rights_id), key); } const auto iter2 = std::find_if( s128_file_id.begin(), s128_file_id.end(), diff --git a/src/core/file_sys/card_image.cpp b/src/core/file_sys/card_image.cpp index d0f1afac0..e07ac8503 100644 --- a/src/core/file_sys/card_image.cpp +++ b/src/core/file_sys/card_image.cpp @@ -12,6 +12,7 @@ #include "core/file_sys/content_archive.h" #include "core/file_sys/nca_metadata.h" #include "core/file_sys/partition_filesystem.h" +#include "core/file_sys/submission_package.h" #include "core/file_sys/vfs_offset.h" #include "core/loader/loader.h" diff --git a/src/core/file_sys/card_image.h b/src/core/file_sys/card_image.h index b73f1d900..4d07d3d05 100644 --- a/src/core/file_sys/card_image.h +++ b/src/core/file_sys/card_image.h @@ -11,7 +11,6 @@ #include "common/swap.h" #include "core/file_sys/vfs.h" #include "core/loader/loader.h" -#include "submission_package.h" namespace Loader { enum class ResultStatus : u16; @@ -21,6 +20,7 @@ namespace FileSys { class NCA; enum class NCAContentType : u8; +class NSP; enum class GamecardSize : u8 { S_1GB = 0xFA, diff --git a/src/core/file_sys/submission_package.cpp b/src/core/file_sys/submission_package.cpp index 660771cf8..ce05a5845 100644 --- a/src/core/file_sys/submission_package.cpp +++ b/src/core/file_sys/submission_package.cpp @@ -72,21 +72,21 @@ NSP::NSP(VirtualFile file_) ncas_title[ContentRecordType::Meta] = nca; for (const auto& rec : cnmt.GetContentRecords()) { - const auto next_file = pfs->GetFile( - fmt::format("{}.nca", Common::HexArrayToString(rec.nca_id, false))); + const auto id_string = Common::HexArrayToString(rec.nca_id, false); + const auto next_file = pfs->GetFile(fmt::format("{}.nca", id_string)); if (next_file == nullptr) { LOG_WARNING(Service_FS, "NCA with ID {}.nca is listed in content metadata, but cannot " "be found in PFS. NSP appears to be corrupted.", - Common::HexArrayToString(rec.nca_id, false)); + id_string); continue; } - const auto next_nca = std::make_shared(next_file); + auto next_nca = std::make_shared(next_file); if (next_nca->GetType() == NCAContentType::Program) program_status[cnmt.GetTitleID()] = next_nca->GetStatus(); if (next_nca->GetStatus() == Loader::ResultStatus::Success) - ncas_title[rec.type] = next_nca; + ncas_title[rec.type] = std::move(next_nca); } break; @@ -95,14 +95,17 @@ NSP::NSP(VirtualFile file_) } } +NSP::~NSP() = default; + Loader::ResultStatus NSP::GetStatus() const { return status; } Loader::ResultStatus NSP::GetProgramStatus(u64 title_id) const { - if (program_status.find(title_id) != program_status.end()) - return program_status.at(title_id); - return Loader::ResultStatus::ErrorNSPMissingProgramNCA; + const auto iter = program_status.find(title_id); + if (iter == program_status.end()) + return Loader::ResultStatus::ErrorNSPMissingProgramNCA; + return iter->second; } u64 NSP::GetFirstTitleID() const { @@ -112,16 +115,19 @@ u64 NSP::GetFirstTitleID() const { } u64 NSP::GetProgramTitleID() const { - auto out = GetFirstTitleID(); - for (const auto other_tid : GetTitleIDs()) { - if ((out & 0x800) != 0) - out = other_tid; - } - return out; + const auto out = GetFirstTitleID(); + if ((out & 0x800) == 0) + return out; + + const auto ids = GetTitleIDs(); + const auto iter = + std::find_if(ids.begin(), ids.end(), [](u64 tid) { return (tid & 0x800) == 0; }); + return iter == ids.end() ? out : *iter; } std::vector NSP::GetTitleIDs() const { std::vector out; + out.reserve(ncas.size()); for (const auto& kv : ncas) out.push_back(kv.first); return out; @@ -156,7 +162,7 @@ std::multimap> NSP::GetNCAsByTitleID() const { std::multimap> out; for (const auto& map : ncas) { for (const auto& inner_map : map.second) - out.insert({map.first, inner_map.second}); + out.emplace(map.first, inner_map.second); } return out; } @@ -168,13 +174,16 @@ std::map>> NSP::GetNCAs() std::shared_ptr NSP::GetNCA(u64 title_id, ContentRecordType type) const { if (extracted) LOG_WARNING(Service_FS, "called on an NSP that is of type extracted."); - if (ncas.find(title_id) != ncas.end()) { - const auto& inner_map = ncas.at(title_id); - if (inner_map.find(type) != inner_map.end()) - return inner_map.at(type); - } - return nullptr; + const auto title_id_iter = ncas.find(title_id); + if (title_id_iter == ncas.end()) + return nullptr; + + const auto type_iter = title_id_iter->second.find(type); + if (type_iter == title_id_iter->second.end()) + return nullptr; + + return type_iter->second; } VirtualFile NSP::GetNCAFile(u64 title_id, ContentRecordType type) const { @@ -197,9 +206,9 @@ std::vector NSP::GetTitlekey() const { continue; } - Core::Crypto::Key128 key{}; - ticket_file->Read(key.data(), key.size(), Core::Crypto::TICKET_FILE_TITLEKEY_OFFSET); - out.push_back(key); + out.emplace_back(); + ticket_file->Read(out.back().data(), out.back().size(), + Core::Crypto::TICKET_FILE_TITLEKEY_OFFSET); } return out; } diff --git a/src/core/file_sys/submission_package.h b/src/core/file_sys/submission_package.h index 7b520df57..482a8b71f 100644 --- a/src/core/file_sys/submission_package.h +++ b/src/core/file_sys/submission_package.h @@ -10,6 +10,7 @@ #include "common/common_types.h" #include "common/swap.h" #include "core/file_sys/content_archive.h" +#include "core/file_sys/romfs_factory.h" #include "core/file_sys/vfs.h" #include "core/loader/loader.h" #include "romfs_factory.h" @@ -19,6 +20,7 @@ namespace FileSys { class NSP : public ReadOnlyVfsDirectory { public: explicit NSP(VirtualFile file); + ~NSP(); Loader::ResultStatus GetStatus() const; Loader::ResultStatus GetProgramStatus(u64 title_id) const; diff --git a/src/core/loader/nsp.cpp b/src/core/loader/nsp.cpp index 75d9fc1bc..b59d40052 100644 --- a/src/core/loader/nsp.cpp +++ b/src/core/loader/nsp.cpp @@ -21,22 +21,27 @@ namespace Loader { AppLoader_NSP::AppLoader_NSP(FileSys::VirtualFile file) : AppLoader(file), nsp(std::make_unique(file)), title_id(nsp->GetProgramTitleID()) { + if (nsp->GetStatus() != ResultStatus::Success) return; if (nsp->IsExtractedType()) return; + const auto control_nca = nsp->GetNCA(nsp->GetFirstTitleID(), FileSys::ContentRecordType::Control); if (control_nca == nullptr || control_nca->GetStatus() != ResultStatus::Success) return; + const auto romfs = FileSys::ExtractRomFS(control_nca->GetRomFS()); if (romfs == nullptr) return; + for (const auto& language : FileSys::LANGUAGE_NAMES) { icon_file = romfs->GetFile("icon_" + std::string(language) + ".dat"); if (icon_file != nullptr) break; } + const auto nacp_raw = romfs->GetFile("control.nacp"); if (nacp_raw == nullptr) return; @@ -51,15 +56,17 @@ FileType AppLoader_NSP::IdentifyType(const FileSys::VirtualFile& file) { if (nsp.GetStatus() == ResultStatus::Success) { // Extracted Type case if (nsp.IsExtractedType() && nsp.GetExeFS() != nullptr && - FileSys::IsDirectoryExeFS(nsp.GetExeFS()) && nsp.GetRomFS() != nullptr) + FileSys::IsDirectoryExeFS(nsp.GetExeFS()) && nsp.GetRomFS() != nullptr) { return FileType::NSP; + } // Non-Ectracted Type case if (!nsp.IsExtractedType() && nsp.GetNCA(nsp.GetFirstTitleID(), FileSys::ContentRecordType::Program) != nullptr && AppLoader_NCA::IdentifyType(nsp.GetNCAFile( - nsp.GetFirstTitleID(), FileSys::ContentRecordType::Program)) == FileType::NCA) + nsp.GetFirstTitleID(), FileSys::ContentRecordType::Program)) == FileType::NCA) { return FileType::NSP; + } } return FileType::Error; diff --git a/src/core/loader/nsp.h b/src/core/loader/nsp.h index 785feaf37..7ef810499 100644 --- a/src/core/loader/nsp.h +++ b/src/core/loader/nsp.h @@ -22,7 +22,7 @@ class AppLoader_NCA; class AppLoader_NSP final : public AppLoader { public: explicit AppLoader_NSP(FileSys::VirtualFile file); - ~AppLoader_NSP(); + ~AppLoader_NSP() override; /** * Returns the type of the file -- cgit v1.2.3