From a9dc5a3c1058d22873a201c08bd6d095405789ae Mon Sep 17 00:00:00 2001 From: Zach Hilman Date: Thu, 16 Aug 2018 16:57:00 -0400 Subject: xci: Fix error masking issue Prevents NCA-related errors from being masked into MissingProgramNCA or MissingKeyFile --- src/core/loader/xci.cpp | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) (limited to 'src/core/loader') diff --git a/src/core/loader/xci.cpp b/src/core/loader/xci.cpp index 4c4979545..9dc4d1f35 100644 --- a/src/core/loader/xci.cpp +++ b/src/core/loader/xci.cpp @@ -61,11 +61,12 @@ ResultStatus AppLoader_XCI::Load(Kernel::SharedPtr& process) { if (xci->GetStatus() != ResultStatus::Success) return xci->GetStatus(); - if (xci->GetNCAFileByType(FileSys::NCAContentType::Program) == nullptr) { - if (!Core::Crypto::KeyManager::KeyFileExists(false)) - return ResultStatus::ErrorMissingProductionKeyFile; - return ResultStatus::ErrorXCIMissingProgramNCA; - } + if (xci->GetProgramNCAStatus() != ResultStatus::Success) + return xci->GetProgramNCAStatus(); + + const auto nca = xci->GetNCAFileByType(FileSys::NCAContentType::Program); + if (nca == nullptr && !Core::Crypto::KeyManager::KeyFileExists(false)) + return ResultStatus::ErrorMissingProductionKeyFile; auto result = nca_loader->Load(process); if (result != ResultStatus::Success) -- cgit v1.2.3 From 2164702cf7f878c84a1f148daca2416911e6e939 Mon Sep 17 00:00:00 2001 From: Zach Hilman Date: Thu, 16 Aug 2018 17:02:31 -0400 Subject: nax: Add AppLoader_NAX and update loader to support it --- src/core/loader/loader.cpp | 14 ++++++++-- src/core/loader/loader.h | 1 + src/core/loader/nax.cpp | 65 ++++++++++++++++++++++++++++++++++++++++++++++ src/core/loader/nax.h | 43 ++++++++++++++++++++++++++++++ 4 files changed, 121 insertions(+), 2 deletions(-) create mode 100644 src/core/loader/nax.cpp create mode 100644 src/core/loader/nax.h (limited to 'src/core/loader') diff --git a/src/core/loader/loader.cpp b/src/core/loader/loader.cpp index 70ef5d240..fe5d71f68 100644 --- a/src/core/loader/loader.cpp +++ b/src/core/loader/loader.cpp @@ -11,6 +11,7 @@ #include "core/hle/kernel/process.h" #include "core/loader/deconstructed_rom_directory.h" #include "core/loader/elf.h" +#include "core/loader/nax.h" #include "core/loader/nca.h" #include "core/loader/nro.h" #include "core/loader/nso.h" @@ -32,6 +33,7 @@ FileType IdentifyFile(FileSys::VirtualFile file) { CHECK_TYPE(NRO) CHECK_TYPE(NCA) CHECK_TYPE(XCI) + CHECK_TYPE(NAX) #undef CHECK_TYPE @@ -73,6 +75,8 @@ std::string GetFileTypeString(FileType type) { return "NCA"; case FileType::XCI: return "XCI"; + case FileType::NAX: + return "NAX"; case FileType::DeconstructedRomDirectory: return "Directory"; case FileType::Error: @@ -150,13 +154,18 @@ static std::unique_ptr GetFileLoader(FileSys::VirtualFile file, FileT case FileType::NRO: return std::make_unique(std::move(file)); - // NX NCA file format. + // NX NCA (Nintendo Content Archive) file format. case FileType::NCA: return std::make_unique(std::move(file)); + // NX XCI (nX Card Image) file format. case FileType::XCI: return std::make_unique(std::move(file)); + // NX NAX (NintendoAesXts) file format. + case FileType::NAX: + return std::make_unique(std::move(file)); + // NX deconstructed ROM directory. case FileType::DeconstructedRomDirectory: return std::make_unique(std::move(file)); @@ -170,7 +179,8 @@ std::unique_ptr GetLoader(FileSys::VirtualFile file) { FileType type = IdentifyFile(file); FileType filename_type = GuessFromFilename(file->GetName()); - if (type != filename_type) { + // Special case: 00 is either a NCA or NAX. + if (type != filename_type && !(file->GetName() == "00" && type == FileType::NAX)) { LOG_WARNING(Loader, "File {} has a different type than its extension.", file->GetName()); if (FileType::Unknown == type) type = filename_type; diff --git a/src/core/loader/loader.h b/src/core/loader/loader.h index b74cfbf8a..d132fb4e8 100644 --- a/src/core/loader/loader.h +++ b/src/core/loader/loader.h @@ -32,6 +32,7 @@ enum class FileType { NRO, NCA, XCI, + NAX, DeconstructedRomDirectory, }; diff --git a/src/core/loader/nax.cpp b/src/core/loader/nax.cpp new file mode 100644 index 000000000..76390bf46 --- /dev/null +++ b/src/core/loader/nax.cpp @@ -0,0 +1,65 @@ +// Copyright 2018 yuzu emulator team +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#include "common/logging/log.h" +#include "core/core.h" +#include "core/file_sys/content_archive.h" +#include "core/file_sys/romfs.h" +#include "core/hle/kernel/process.h" +#include "core/loader/nax.h" + +namespace Loader { + +AppLoader_NAX::AppLoader_NAX(FileSys::VirtualFile file) + : AppLoader(file), nax(std::make_unique(file)), + nca_loader(std::make_unique(nax->GetDecrypted())) {} + +AppLoader_NAX::~AppLoader_NAX() = default; + +FileType AppLoader_NAX::IdentifyType(const FileSys::VirtualFile& file) { + FileSys::NAX nax(file); + + if (nax.GetStatus() == ResultStatus::Success && nax.AsNCA() != nullptr && + nax.AsNCA()->GetStatus() == ResultStatus::Success) { + return FileType::NAX; + } + + return FileType::Error; +} + +ResultStatus AppLoader_NAX::Load(Kernel::SharedPtr& process) { + if (is_loaded) { + return ResultStatus::ErrorAlreadyLoaded; + } + + if (nax->GetStatus() != ResultStatus::Success) + return nax->GetStatus(); + + const auto nca = nax->AsNCA(); + if (nca == nullptr) { + if (!Core::Crypto::KeyManager::KeyFileExists(false)) + return ResultStatus::ErrorMissingProductionKeyFile; + return ResultStatus::ErrorNAXInconvertibleToNCA; + } + + if (nca->GetStatus() != ResultStatus::Success) + return nca->GetStatus(); + + const auto result = nca_loader->Load(process); + if (result != ResultStatus::Success) + return result; + + is_loaded = true; + + return ResultStatus::Success; +} + +ResultStatus AppLoader_NAX::ReadRomFS(FileSys::VirtualFile& dir) { + return nca_loader->ReadRomFS(dir); +} + +ResultStatus AppLoader_NAX::ReadProgramId(u64& out_program_id) { + return nca_loader->ReadProgramId(out_program_id); +} +} // namespace Loader diff --git a/src/core/loader/nax.h b/src/core/loader/nax.h new file mode 100644 index 000000000..08d6ef346 --- /dev/null +++ b/src/core/loader/nax.h @@ -0,0 +1,43 @@ +// Copyright 2018 yuzu emulator team +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#pragma once + +#include +#include "common/common_types.h" +#include "core/file_sys/card_image.h" +#include "core/file_sys/xts_archive.h" +#include "core/loader/loader.h" +#include "core/loader/nca.h" + +namespace Loader { + +/// Loads a NAX file +class AppLoader_NAX final : public AppLoader { +public: + explicit AppLoader_NAX(FileSys::VirtualFile file); + ~AppLoader_NAX(); + + /** + * Returns the type of the file + * @param file std::shared_ptr open file + * @return FileType found, or FileType::Error if this loader doesn't know it + */ + static FileType IdentifyType(const FileSys::VirtualFile& file); + + FileType GetFileType() override { + return IdentifyType(file); + } + + ResultStatus Load(Kernel::SharedPtr& process) override; + + ResultStatus ReadRomFS(FileSys::VirtualFile& dir) override; + ResultStatus ReadProgramId(u64& out_program_id) override; + +private: + std::unique_ptr nax; + std::unique_ptr nca_loader; +}; + +} // namespace Loader -- cgit v1.2.3 From b247e0cab0e01476d8bf56e989d34483782b7cae Mon Sep 17 00:00:00 2001 From: Zach Hilman Date: Thu, 16 Aug 2018 17:02:50 -0400 Subject: loader: Add new NAX-specific errors and messages --- src/core/loader/loader.cpp | 15 ++++++++++++++- src/core/loader/loader.h | 13 +++++++++++++ 2 files changed, 27 insertions(+), 1 deletion(-) (limited to 'src/core/loader') diff --git a/src/core/loader/loader.cpp b/src/core/loader/loader.cpp index fe5d71f68..c13fb49b8 100644 --- a/src/core/loader/loader.cpp +++ b/src/core/loader/loader.cpp @@ -87,7 +87,7 @@ std::string GetFileTypeString(FileType type) { return "unknown"; } -constexpr std::array RESULT_MESSAGES{ +constexpr std::array RESULT_MESSAGES{ "The operation completed successfully.", "The loader requested to load is already loaded.", "The operation is not implemented.", @@ -124,6 +124,19 @@ constexpr std::array RESULT_MESSAGES{ "There was a general error loading the NRO into emulated memory.", "There is no icon available.", "There is no control data available.", + "The NAX file has a bad header.", + "The NAX file has incorrect size as determined by the header.", + "The HMAC to generated the NAX decryption keys failed.", + "The HMAC to validate the NAX decryption keys failed.", + "The NAX key derivation failed.", + "The NAX file cannot be interpreted as an NCA file.", + "The NAX file has an incorrect path.", + "The SD seed could not be found or derived.", + "The SD KEK Source could not be found.", + "The AES KEK Generation Source could not be found.", + "The AES Key Generation Source could not be found.", + "The SD Save Key Source could not be found.", + "The SD NCA Key Source could not be found.", }; std::ostream& operator<<(std::ostream& os, ResultStatus status) { diff --git a/src/core/loader/loader.h b/src/core/loader/loader.h index d132fb4e8..885fee84c 100644 --- a/src/core/loader/loader.h +++ b/src/core/loader/loader.h @@ -94,6 +94,19 @@ enum class ResultStatus : u16 { ErrorLoadingNRO, ErrorNoIcon, ErrorNoControl, + ErrorBadNAXHeader, + ErrorIncorrectNAXFileSize, + ErrorNAXKeyHMACFailed, + ErrorNAXValidationHMACFailed, + ErrorNAXKeyDerivationFailed, + ErrorNAXInconvertibleToNCA, + ErrorBadNAXFilePath, + ErrorMissingSDSeed, + ErrorMissingSDKEKSource, + ErrorMissingAESKEKGenerationSource, + ErrorMissingAESKeyGenerationSource, + ErrorMissingSDSaveKeySource, + ErrorMissingSDNCAKeySource, }; std::ostream& operator<<(std::ostream& os, ResultStatus status); -- cgit v1.2.3 From a7e8d10969f280cd5a869b3525c3339357a958a6 Mon Sep 17 00:00:00 2001 From: Zach Hilman Date: Sat, 18 Aug 2018 21:16:20 -0400 Subject: file_sys: Cut down on includes and copies --- src/core/crypto/key_manager.cpp | 22 +++++++++++----------- src/core/crypto/key_manager.h | 6 ++---- src/core/file_sys/registered_cache.cpp | 2 ++ src/core/file_sys/registered_cache.h | 1 + src/core/file_sys/sdmc_factory.h | 3 +++ src/core/loader/nax.cpp | 2 ++ src/core/loader/nax.h | 13 +++++++++---- 7 files changed, 30 insertions(+), 19 deletions(-) (limited to 'src/core/loader') diff --git a/src/core/crypto/key_manager.cpp b/src/core/crypto/key_manager.cpp index acf635a65..1cb3fce00 100644 --- a/src/core/crypto/key_manager.cpp +++ b/src/core/crypto/key_manager.cpp @@ -199,7 +199,7 @@ Key256 KeyManager::GetKey(S256KeyType id, u64 field1, u64 field2) const { template void KeyManager::WriteKeyToFile(bool title_key, std::string_view keyname, - std::array key) { + const std::array& key) { const std::string yuzu_keys_dir = FileUtil::GetUserPath(FileUtil::UserPath::KeysDir); std::string filename = "title.keys_autogenerated"; if (!title_key) @@ -209,11 +209,10 @@ void KeyManager::WriteKeyToFile(bool title_key, std::string_view keyname, if (!file.is_open()) return; if (add_info_text) { - file << "# This file is autogenerated by Yuzu" << std::endl - << "# It serves to store keys that were automatically generated from the normal keys" - << std::endl - << "# If you are experiencing issues involving keys, it may help to delete this file" - << std::endl; + file + << "# This file is autogenerated by Yuzu\n" + << "# It serves to store keys that were automatically generated from the normal keys\n" + << "# If you are experiencing issues involving keys, it may help to delete this file\n"; } file << std::endl @@ -263,11 +262,12 @@ bool KeyManager::KeyFileExists(bool title) { } void KeyManager::DeriveSDSeedLazy() { - if (!HasKey(S128KeyType::SDSeed)) { - const auto res = DeriveSDSeed(); - if (res != boost::none) - SetKey(S128KeyType::SDSeed, res.get()); - } + if (HasKey(S128KeyType::SDSeed)) + return; + + const auto res = DeriveSDSeed(); + if (res != boost::none) + SetKey(S128KeyType::SDSeed, res.get()); } const boost::container::flat_map> KeyManager::s128_file_id = { diff --git a/src/core/crypto/key_manager.h b/src/core/crypto/key_manager.h index 78d0b64e0..7a8728f76 100644 --- a/src/core/crypto/key_manager.h +++ b/src/core/crypto/key_manager.h @@ -74,9 +74,7 @@ struct KeyIndex { // boost flat_map requires operator< for O(log(n)) lookups. template bool operator<(const KeyIndex& lhs, const KeyIndex& rhs) { - return (static_cast(lhs.type) < static_cast(rhs.type)) || - (lhs.type == rhs.type && lhs.field1 < rhs.field1) || - (lhs.type == rhs.type && lhs.field1 == rhs.field1 && lhs.field2 < rhs.field2); + return std::tie(lhs.type, lhs.field1, lhs.field2) < std::tie(rhs.type, rhs.field1, rhs.field2); } class KeyManager { @@ -107,7 +105,7 @@ private: void AttemptLoadKeyFile(const std::string& dir1, const std::string& dir2, const std::string& filename, bool title); template - void WriteKeyToFile(bool title_key, std::string_view keyname, std::array key); + void WriteKeyToFile(bool title_key, std::string_view keyname, const std::array& key); static const boost::container::flat_map> s128_file_id; static const boost::container::flat_map> s256_file_id; diff --git a/src/core/file_sys/registered_cache.cpp b/src/core/file_sys/registered_cache.cpp index a128fa33d..a02efc71e 100644 --- a/src/core/file_sys/registered_cache.cpp +++ b/src/core/file_sys/registered_cache.cpp @@ -254,6 +254,8 @@ RegisteredCache::RegisteredCache(VirtualDir dir_, RegisteredCacheParsingFunction Refresh(); } +RegisteredCache::~RegisteredCache() = default; + bool RegisteredCache::HasEntry(u64 title_id, ContentRecordType type) const { return GetEntryRaw(title_id, type) != nullptr; } diff --git a/src/core/file_sys/registered_cache.h b/src/core/file_sys/registered_cache.h index f48cf3146..7b8955dfa 100644 --- a/src/core/file_sys/registered_cache.h +++ b/src/core/file_sys/registered_cache.h @@ -63,6 +63,7 @@ public: explicit RegisteredCache(VirtualDir dir, RegisteredCacheParsingFunction parsing_function = [](const VirtualFile& file, const NcaID& id) { return file; }); + ~RegisteredCache(); void Refresh(); diff --git a/src/core/file_sys/sdmc_factory.h b/src/core/file_sys/sdmc_factory.h index bb579472c..4eac92621 100644 --- a/src/core/file_sys/sdmc_factory.h +++ b/src/core/file_sys/sdmc_factory.h @@ -4,11 +4,14 @@ #pragma once +#include #include "core/file_sys/vfs.h" #include "core/hle/result.h" namespace FileSys { +class RegisteredCache; + /// File system interface to the SDCard archive class SDMCFactory { public: diff --git a/src/core/loader/nax.cpp b/src/core/loader/nax.cpp index 76390bf46..b35fdc3f8 100644 --- a/src/core/loader/nax.cpp +++ b/src/core/loader/nax.cpp @@ -6,8 +6,10 @@ #include "core/core.h" #include "core/file_sys/content_archive.h" #include "core/file_sys/romfs.h" +#include "core/file_sys/xts_archive.h" #include "core/hle/kernel/process.h" #include "core/loader/nax.h" +#include "core/loader/nca.h" namespace Loader { diff --git a/src/core/loader/nax.h b/src/core/loader/nax.h index 08d6ef346..4dbae2918 100644 --- a/src/core/loader/nax.h +++ b/src/core/loader/nax.h @@ -6,18 +6,23 @@ #include #include "common/common_types.h" -#include "core/file_sys/card_image.h" -#include "core/file_sys/xts_archive.h" #include "core/loader/loader.h" -#include "core/loader/nca.h" + +namespace FileSys { + +class NAX; + +} // namespace FileSys namespace Loader { +class AppLoader_NCA; + /// Loads a NAX file class AppLoader_NAX final : public AppLoader { public: explicit AppLoader_NAX(FileSys::VirtualFile file); - ~AppLoader_NAX(); + ~AppLoader_NAX() override; /** * Returns the type of the file -- cgit v1.2.3 From 6314a799aa7e20789562d2e877949dfebb6194ce Mon Sep 17 00:00:00 2001 From: Zach Hilman Date: Fri, 24 Aug 2018 22:15:32 -0400 Subject: file_sys/crypto: Fix missing/unnecessary includes --- src/core/crypto/key_manager.cpp | 5 ++--- src/core/crypto/key_manager.h | 1 + src/core/crypto/xts_encryption_layer.cpp | 1 + src/core/crypto/xts_encryption_layer.h | 1 - src/core/file_sys/sdmc_factory.cpp | 2 ++ src/core/file_sys/sdmc_factory.h | 1 + src/core/file_sys/xts_archive.cpp | 2 ++ src/core/file_sys/xts_archive.h | 1 + src/core/loader/nax.cpp | 1 - 9 files changed, 10 insertions(+), 5 deletions(-) (limited to 'src/core/loader') diff --git a/src/core/crypto/key_manager.cpp b/src/core/crypto/key_manager.cpp index 0b14bf15c..0b6c07de8 100644 --- a/src/core/crypto/key_manager.cpp +++ b/src/core/crypto/key_manager.cpp @@ -133,7 +133,7 @@ KeyManager::KeyManager() { } AttemptLoadKeyFile(yuzu_keys_dir, hactool_keys_dir, "title.keys", true); - AttemptLoadKeyFile(yuzu_keys_dir, yuzu_keys_dir, "title.keys_autogenerated", false); + AttemptLoadKeyFile(yuzu_keys_dir, yuzu_keys_dir, "title.keys_autogenerated", true); } void KeyManager::LoadFromFile(const std::string& filename, bool is_title_keys) { @@ -223,8 +223,7 @@ void KeyManager::WriteKeyToFile(bool title_key, std::string_view keyname, << "# If you are experiencing issues involving keys, it may help to delete this file\n"; } - file << std::endl - << fmt::format("{} = {}", keyname, Common::HexArrayToString(key)) << std::endl; + file << fmt::format("\n{} = {}", keyname, Common::HexArrayToString(key)); AttemptLoadKeyFile(yuzu_keys_dir, yuzu_keys_dir, filename, title_key); } diff --git a/src/core/crypto/key_manager.h b/src/core/crypto/key_manager.h index 7a8728f76..7ca3e6cbc 100644 --- a/src/core/crypto/key_manager.h +++ b/src/core/crypto/key_manager.h @@ -6,6 +6,7 @@ #include #include +#include #include #include #include diff --git a/src/core/crypto/xts_encryption_layer.cpp b/src/core/crypto/xts_encryption_layer.cpp index c6e5df1ce..c10832cfe 100644 --- a/src/core/crypto/xts_encryption_layer.cpp +++ b/src/core/crypto/xts_encryption_layer.cpp @@ -2,6 +2,7 @@ // Licensed under GPLv2 or any later version // Refer to the license.txt file included. +#include #include #include "common/assert.h" #include "core/crypto/xts_encryption_layer.h" diff --git a/src/core/crypto/xts_encryption_layer.h b/src/core/crypto/xts_encryption_layer.h index 1e1acaf4a..7a1f1dc64 100644 --- a/src/core/crypto/xts_encryption_layer.h +++ b/src/core/crypto/xts_encryption_layer.h @@ -4,7 +4,6 @@ #pragma once -#include #include "core/crypto/aes_util.h" #include "core/crypto/encryption_layer.h" #include "core/crypto/key_manager.h" diff --git a/src/core/file_sys/sdmc_factory.cpp b/src/core/file_sys/sdmc_factory.cpp index e4df5c4d0..d66a9c9a4 100644 --- a/src/core/file_sys/sdmc_factory.cpp +++ b/src/core/file_sys/sdmc_factory.cpp @@ -16,6 +16,8 @@ SDMCFactory::SDMCFactory(VirtualDir dir_) return std::make_shared(file, id)->GetDecrypted(); })) {} +SDMCFactory::~SDMCFactory() = default; + ResultVal SDMCFactory::Open() { return MakeResult(dir); } diff --git a/src/core/file_sys/sdmc_factory.h b/src/core/file_sys/sdmc_factory.h index 4eac92621..ea12149de 100644 --- a/src/core/file_sys/sdmc_factory.h +++ b/src/core/file_sys/sdmc_factory.h @@ -16,6 +16,7 @@ class RegisteredCache; class SDMCFactory { public: explicit SDMCFactory(VirtualDir dir); + ~SDMCFactory(); ResultVal Open(); std::shared_ptr GetSDMCContents() const; diff --git a/src/core/file_sys/xts_archive.cpp b/src/core/file_sys/xts_archive.cpp index 605c1a283..552835738 100644 --- a/src/core/file_sys/xts_archive.cpp +++ b/src/core/file_sys/xts_archive.cpp @@ -2,7 +2,9 @@ // Licensed under GPLv2 or any later version // Refer to the license.txt file included. +#include #include +#include #include #include #include diff --git a/src/core/file_sys/xts_archive.h b/src/core/file_sys/xts_archive.h index 5249ad026..55d2154a6 100644 --- a/src/core/file_sys/xts_archive.h +++ b/src/core/file_sys/xts_archive.h @@ -8,6 +8,7 @@ #include #include "common/common_types.h" #include "common/swap.h" +#include "core/crypto/key_manager.h" #include "core/file_sys/content_archive.h" #include "core/file_sys/vfs.h" #include "core/loader/loader.h" diff --git a/src/core/loader/nax.cpp b/src/core/loader/nax.cpp index b35fdc3f8..b46d81c02 100644 --- a/src/core/loader/nax.cpp +++ b/src/core/loader/nax.cpp @@ -3,7 +3,6 @@ // Refer to the license.txt file included. #include "common/logging/log.h" -#include "core/core.h" #include "core/file_sys/content_archive.h" #include "core/file_sys/romfs.h" #include "core/file_sys/xts_archive.h" -- cgit v1.2.3