content_archive.cpp 5.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199
  1. // SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
  2. // SPDX-License-Identifier: GPL-2.0-or-later
  3. #include <algorithm>
  4. #include <cstring>
  5. #include <optional>
  6. #include <utility>
  7. #include "common/logging/log.h"
  8. #include "common/polyfill_ranges.h"
  9. #include "core/crypto/aes_util.h"
  10. #include "core/crypto/ctr_encryption_layer.h"
  11. #include "core/crypto/key_manager.h"
  12. #include "core/file_sys/content_archive.h"
  13. #include "core/file_sys/partition_filesystem.h"
  14. #include "core/file_sys/vfs/vfs_offset.h"
  15. #include "core/loader/loader.h"
  16. #include "core/file_sys/fssystem/fssystem_compression_configuration.h"
  17. #include "core/file_sys/fssystem/fssystem_crypto_configuration.h"
  18. #include "core/file_sys/fssystem/fssystem_nca_file_system_driver.h"
  19. namespace FileSys {
  20. static u8 MasterKeyIdForKeyGeneration(u8 key_generation) {
  21. return std::max<u8>(key_generation, 1) - 1;
  22. }
  23. NCA::NCA(VirtualFile file_, const NCA* base_nca)
  24. : file(std::move(file_)), keys{Core::Crypto::KeyManager::Instance()} {
  25. if (file == nullptr) {
  26. status = Loader::ResultStatus::ErrorNullFile;
  27. return;
  28. }
  29. reader = std::make_shared<NcaReader>();
  30. if (Result rc =
  31. reader->Initialize(file, GetCryptoConfiguration(), GetNcaCompressionConfiguration());
  32. R_FAILED(rc)) {
  33. if (rc != ResultInvalidNcaSignature) {
  34. LOG_ERROR(Loader, "File reader errored out during header read: {:#x}",
  35. rc.GetInnerValue());
  36. }
  37. status = Loader::ResultStatus::ErrorBadNCAHeader;
  38. return;
  39. }
  40. // Ensure we have the proper key area keys to continue.
  41. const u8 master_key_id = MasterKeyIdForKeyGeneration(reader->GetKeyGeneration());
  42. if (!keys.HasKey(Core::Crypto::S128KeyType::KeyArea, master_key_id, reader->GetKeyIndex())) {
  43. status = Loader::ResultStatus::ErrorMissingKeyAreaKey;
  44. return;
  45. }
  46. RightsId rights_id{};
  47. reader->GetRightsId(rights_id.data(), rights_id.size());
  48. if (rights_id != RightsId{}) {
  49. // External decryption key required; provide it here.
  50. u128 rights_id_u128;
  51. std::memcpy(rights_id_u128.data(), rights_id.data(), sizeof(rights_id));
  52. auto titlekey =
  53. keys.GetKey(Core::Crypto::S128KeyType::Titlekey, rights_id_u128[1], rights_id_u128[0]);
  54. if (titlekey == Core::Crypto::Key128{}) {
  55. status = Loader::ResultStatus::ErrorMissingTitlekey;
  56. return;
  57. }
  58. if (!keys.HasKey(Core::Crypto::S128KeyType::Titlekek, master_key_id)) {
  59. status = Loader::ResultStatus::ErrorMissingTitlekek;
  60. return;
  61. }
  62. auto titlekek = keys.GetKey(Core::Crypto::S128KeyType::Titlekek, master_key_id);
  63. Core::Crypto::AESCipher<Core::Crypto::Key128> cipher(titlekek, Core::Crypto::Mode::ECB);
  64. cipher.Transcode(titlekey.data(), titlekey.size(), titlekey.data(),
  65. Core::Crypto::Op::Decrypt);
  66. reader->SetExternalDecryptionKey(titlekey.data(), titlekey.size());
  67. }
  68. const s32 fs_count = reader->GetFsCount();
  69. NcaFileSystemDriver fs(base_nca ? base_nca->reader : nullptr, reader);
  70. std::vector<VirtualFile> filesystems(fs_count);
  71. for (s32 i = 0; i < fs_count; i++) {
  72. NcaFsHeaderReader header_reader;
  73. const Result rc = fs.OpenStorage(&filesystems[i], &header_reader, i);
  74. if (R_FAILED(rc)) {
  75. LOG_ERROR(Loader, "File reader errored out during read of section {}: {:#x}", i,
  76. rc.GetInnerValue());
  77. status = Loader::ResultStatus::ErrorBadNCAHeader;
  78. return;
  79. }
  80. if (header_reader.GetFsType() == NcaFsHeader::FsType::RomFs) {
  81. files.push_back(filesystems[i]);
  82. romfs = files.back();
  83. }
  84. if (header_reader.GetFsType() == NcaFsHeader::FsType::PartitionFs) {
  85. auto npfs = std::make_shared<PartitionFilesystem>(filesystems[i]);
  86. if (npfs->GetStatus() == Loader::ResultStatus::Success) {
  87. dirs.push_back(npfs);
  88. if (IsDirectoryExeFS(npfs)) {
  89. exefs = dirs.back();
  90. } else if (IsDirectoryLogoPartition(npfs)) {
  91. logo = dirs.back();
  92. } else {
  93. continue;
  94. }
  95. }
  96. }
  97. if (header_reader.GetEncryptionType() == NcaFsHeader::EncryptionType::AesCtrEx) {
  98. is_update = true;
  99. }
  100. }
  101. if (is_update && base_nca == nullptr) {
  102. status = Loader::ResultStatus::ErrorMissingBKTRBaseRomFS;
  103. } else {
  104. status = Loader::ResultStatus::Success;
  105. }
  106. }
  107. NCA::~NCA() = default;
  108. Loader::ResultStatus NCA::GetStatus() const {
  109. return status;
  110. }
  111. std::vector<VirtualFile> NCA::GetFiles() const {
  112. if (status != Loader::ResultStatus::Success) {
  113. return {};
  114. }
  115. return files;
  116. }
  117. std::vector<VirtualDir> NCA::GetSubdirectories() const {
  118. if (status != Loader::ResultStatus::Success) {
  119. return {};
  120. }
  121. return dirs;
  122. }
  123. std::string NCA::GetName() const {
  124. return file->GetName();
  125. }
  126. VirtualDir NCA::GetParentDirectory() const {
  127. return file->GetContainingDirectory();
  128. }
  129. NCAContentType NCA::GetType() const {
  130. return static_cast<NCAContentType>(reader->GetContentType());
  131. }
  132. u64 NCA::GetTitleId() const {
  133. if (is_update) {
  134. return reader->GetProgramId() | 0x800;
  135. }
  136. return reader->GetProgramId();
  137. }
  138. RightsId NCA::GetRightsId() const {
  139. RightsId result;
  140. reader->GetRightsId(result.data(), result.size());
  141. return result;
  142. }
  143. u32 NCA::GetSDKVersion() const {
  144. return reader->GetSdkAddonVersion();
  145. }
  146. u8 NCA::GetKeyGeneration() const {
  147. return reader->GetKeyGeneration();
  148. }
  149. bool NCA::IsUpdate() const {
  150. return is_update;
  151. }
  152. VirtualFile NCA::GetRomFS() const {
  153. return romfs;
  154. }
  155. VirtualDir NCA::GetExeFS() const {
  156. return exefs;
  157. }
  158. VirtualFile NCA::GetBaseFile() const {
  159. return file;
  160. }
  161. VirtualDir NCA::GetLogoPartition() const {
  162. return logo;
  163. }
  164. } // namespace FileSys