From 5c8aff984e47c0f471e9eafd071031bc49ad8efc Mon Sep 17 00:00:00 2001
From: Zach Hilman <zachhilman@gmail.com>
Date: Sat, 25 Aug 2018 11:48:23 -0400
Subject: [PATCH] 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(-)

diff --git a/src/core/crypto/key_manager.h b/src/core/crypto/key_manager.h
index bf51bf31f7..ce67913bb6 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<u8, 0x10>;
 using Key256 = std::array<u8, 0x20>;
 using SHA256Hash = std::array<u8, 0x20>;
diff --git a/src/core/file_sys/card_image.cpp b/src/core/file_sys/card_image.cpp
index ce4423fa6f..d0f1afac00 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<size_t>(partition)] = std::make_shared<PartitionFilesystem>(raw);
     }
 
+    secure_partition = std::make_shared<NSP>(
+        main_hfs.GetFile(partition_names[static_cast<size_t>(XCIPartition::Secure)]));
+
+    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();
 
-    auto result = AddNCAFromPartition(XCIPartition::Secure);
-    if (result != Loader::ResultStatus::Success) {
-        status = result;
-        return;
-    }
-
-    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<size_t>(partition)];
 }
 
+std::shared_ptr<NSP> 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<NCA> XCI::GetProgramNCA() const {
+    return program;
+}
+
+VirtualFile XCI::GetProgramNCAFile() const {
+    if (GetProgramNCA() == nullptr)
+        return nullptr;
+    return GetProgramNCA()->GetBaseFile();
+}
+
 const std::vector<std::shared_ptr<NCA>>& XCI::GetNCAs() const {
     return ncas;
 }
diff --git a/src/core/file_sys/card_image.h b/src/core/file_sys/card_image.h
index 4f104d18a4..b73f1d9009 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<NSP> GetSecurePartitionNSP() const;
     VirtualDir GetSecurePartition() const;
     VirtualDir GetNormalPartition() const;
     VirtualDir GetUpdatePartition() const;
     VirtualDir GetLogoPartition() const;
 
+    std::shared_ptr<NCA> GetProgramNCA() const;
+    VirtualFile GetProgramNCAFile() const;
     const std::vector<std::shared_ptr<NCA>>& GetNCAs() const;
     std::shared_ptr<NCA> GetNCAByType(NCAContentType type) const;
     VirtualFile GetNCAFileByType(NCAContentType type) const;
@@ -101,6 +106,8 @@ private:
     Loader::ResultStatus program_nca_status;
 
     std::vector<VirtualDir> partitions;
+    std::shared_ptr<NSP> secure_partition;
+    std::shared_ptr<NCA> program;
     std::vector<std::shared_ptr<NCA>> ncas;
 };
 } // namespace FileSys
diff --git a/src/core/loader/xci.cpp b/src/core/loader/xci.cpp
index 9dc4d1f358..75b998faaa 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<FileSys::XCI>(file)),
-      nca_loader(std::make_unique<AppLoader_NCA>(
-          xci->GetNCAFileByType(FileSys::NCAContentType::Program))) {
+      nca_loader(std::make_unique<AppLoader_NCA>(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<Kernel::Process>& 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;