diff --git a/libraries/libstratosphere/include/stratosphere/fssrv/fscreator/fssrv_storage_on_nca_creator.hpp b/libraries/libstratosphere/include/stratosphere/fssrv/fscreator/fssrv_storage_on_nca_creator.hpp index 973cfff3e..a4bdb41e2 100644 --- a/libraries/libstratosphere/include/stratosphere/fssrv/fscreator/fssrv_storage_on_nca_creator.hpp +++ b/libraries/libstratosphere/include/stratosphere/fssrv/fscreator/fssrv_storage_on_nca_creator.hpp @@ -51,6 +51,8 @@ namespace ams::fssrv::fscreator { #if !defined(ATMOSPHERE_BOARD_NINTENDO_NX) Result CreateWithContext(std::shared_ptr *out, std::shared_ptr *out_splitter, fssystem::NcaFsHeaderReader *out_header_reader, void *ctx, std::shared_ptr nca_reader, s32 index); Result CreateWithPatchWithContext(std::shared_ptr *out, std::shared_ptr *out_splitter, fssystem::NcaFsHeaderReader *out_header_reader, void *ctx, std::shared_ptr original_nca_reader, std::shared_ptr current_nca_reader, s32 index); + + Result CreateByRawStorage(std::shared_ptr *out, std::shared_ptr *out_splitter, const fssystem::NcaFsHeaderReader *header_reader, std::shared_ptr raw_storage, void *ctx, std::shared_ptr nca_reader); #endif }; diff --git a/libraries/libstratosphere/include/stratosphere/fssystem/fssystem_nca_file_system_driver.hpp b/libraries/libstratosphere/include/stratosphere/fssystem/fssystem_nca_file_system_driver.hpp index 80bf9d442..527198bd2 100644 --- a/libraries/libstratosphere/include/stratosphere/fssystem/fssystem_nca_file_system_driver.hpp +++ b/libraries/libstratosphere/include/stratosphere/fssystem/fssystem_nca_file_system_driver.hpp @@ -58,6 +58,10 @@ namespace ams::fssystem { DecryptAesCtrFunction decrypt_aes_ctr; DecryptAesCtrFunction decrypt_aes_ctr_external; bool is_plaintext_header_available; + + #if !defined(ATMOSPHERE_BOARD_NINTENDO_NX) + bool is_unsigned_header_available_for_host_tool; + #endif }; static_assert(util::is_pod::value); @@ -103,6 +107,7 @@ namespace ams::fssystem { DecryptAesCtrFunction m_decrypt_aes_ctr_external; bool m_is_software_aes_prioritized; NcaHeader::EncryptionType m_header_encryption_type; + bool m_is_header_sign1_signature_valid; GetDecompressorFunction m_get_decompressor; IHash256GeneratorFactory *m_hash_generator_factory; public: @@ -149,8 +154,10 @@ namespace ams::fssystem { GetDecompressorFunction GetDecompressor() const; IHash256GeneratorFactory *GetHashGeneratorFactory() const; - void GetHeaderSign2(void *dst, size_t size); - void GetHeaderSign2TargetHash(void *dst, size_t size); + bool GetHeaderSign1Valid() const; + + void GetHeaderSign2(void *dst, size_t size) const; + void GetHeaderSign2TargetHash(void *dst, size_t size) const; }; class NcaFsHeaderReader : public ::ams::fs::impl::Newable { @@ -252,6 +259,13 @@ namespace ams::fssystem { /* Open the storage. */ R_RETURN(OpenStorageWithContext(out, out_splitter, out_header_reader, fs_index, std::addressof(ctx))); } + + #if defined(ATMOSPHERE_BOARD_NINTENDO_NX) + private: + #else + public: + #endif + Result CreateStorageByRawStorage(std::shared_ptr *out, const NcaFsHeaderReader *header_reader, std::shared_ptr raw_storage, StorageContext *ctx); private: Result OpenStorageImpl(std::shared_ptr *out, NcaFsHeaderReader *out_header_reader, s32 fs_index, StorageContext *ctx); diff --git a/libraries/libstratosphere/source/fssrv/fscreator/fssrv_storage_on_nca_creator.cpp b/libraries/libstratosphere/source/fssrv/fscreator/fssrv_storage_on_nca_creator.cpp index 926b8902e..f2b2cd3bc 100644 --- a/libraries/libstratosphere/source/fssrv/fscreator/fssrv_storage_on_nca_creator.cpp +++ b/libraries/libstratosphere/source/fssrv/fscreator/fssrv_storage_on_nca_creator.cpp @@ -90,6 +90,22 @@ namespace ams::fssrv::fscreator { *out_splitter = std::move(splitter); return ResultSuccess(); } + + Result StorageOnNcaCreator::CreateByRawStorage(std::shared_ptr *out, std::shared_ptr *out_splitter, const fssystem::NcaFsHeaderReader *header_reader, std::shared_ptr raw_storage, void *ctx, std::shared_ptr nca_reader) { + /* Create a fs driver. */ + fssystem::NcaFileSystemDriver nca_fs_driver(nca_reader, m_allocator, m_buffer_manager, m_hash_generator_factory_selector); + + /* Open the storage. */ + auto *storage_ctx = static_cast(ctx); + R_TRY(nca_fs_driver.CreateStorageByRawStorage(out, header_reader, std::move(raw_storage), storage_ctx)); + + /* Update the splitter. */ + if (storage_ctx->compressed_storage != nullptr) { + *out_splitter = storage_ctx->compressed_storage; + } + + R_SUCCEED(); + } #endif } diff --git a/libraries/libstratosphere/source/fssystem/fssystem_crypto_configuration.cpp b/libraries/libstratosphere/source/fssystem/fssystem_crypto_configuration.cpp index 05c2db6c5..daefff14a 100644 --- a/libraries/libstratosphere/source/fssystem/fssystem_crypto_configuration.cpp +++ b/libraries/libstratosphere/source/fssystem/fssystem_crypto_configuration.cpp @@ -180,6 +180,11 @@ namespace ams::fssystem { cfg->decrypt_aes_ctr_external = DecryptAesCtrForPreparedKey; cfg->is_plaintext_header_available = !prod; + /* TODO: Should this default to false for host tools with api to set explicitly? */ + #if !defined(ATMOSPHERE_BOARD_NINTENDO_NX) + cfg->is_unsigned_header_available_for_host_tool = true; + #endif + return cfg; } diff --git a/libraries/libstratosphere/source/fssystem/fssystem_nca_file_system_driver.cpp b/libraries/libstratosphere/source/fssystem/fssystem_nca_file_system_driver.cpp index 85142c933..1976133f3 100644 --- a/libraries/libstratosphere/source/fssystem/fssystem_nca_file_system_driver.cpp +++ b/libraries/libstratosphere/source/fssystem/fssystem_nca_file_system_driver.cpp @@ -292,14 +292,6 @@ namespace ams::fssystem { using IntegrityLevelInfo = NcaFsHeader::HashData::IntegrityMetaInfo::LevelHashInfo; using IntegrityDataInfo = IntegrityLevelInfo::HierarchicalIntegrityVerificationLevelInformation; - // inline const Sha256DataRegion &GetSha256DataRegion(const NcaFsHeader::HashData &hash_data) { - // return hash_data.hierarchical_sha256_data.hash_layer_region[1]; - // } - - // inline const IntegrityDataInfo &GetIntegrityDataInfo(const NcaFsHeader::HashData &hash_data) { - // return hash_data.integrity_meta_info.level_hash_info.info[hash_data.integrity_meta_info.level_hash_info.max_layers - 2]; - // } - } Result NcaFileSystemDriver::OpenStorageWithContext(std::shared_ptr *out, std::shared_ptr *out_splitter, NcaFsHeaderReader *out_header_reader, s32 fs_index, StorageContext *ctx) { @@ -308,7 +300,7 @@ namespace ams::fssystem { /* If we have a compressed storage, use it as splitter. */ if (ctx->compressed_storage != nullptr) { - *out_splitter = std::move(ctx->compressed_storage); + *out_splitter = ctx->compressed_storage; } else { /* Otherwise, allocate a default splitter. */ *out_splitter = fssystem::AllocateShared(); @@ -447,21 +439,29 @@ namespace ams::fssystem { return ResultSuccess(); } + /* Create the non-raw storage. */ + R_RETURN(this->CreateStorageByRawStorage(out, out_header_reader, std::move(storage), ctx)); + } + + Result NcaFileSystemDriver::CreateStorageByRawStorage(std::shared_ptr *out, const NcaFsHeaderReader *header_reader, std::shared_ptr raw_storage, StorageContext *ctx) { + /* Initialize storage as raw storage. */ + std::shared_ptr storage = std::move(raw_storage); + /* Process hash/integrity layer. */ - switch (out_header_reader->GetHashType()) { + switch (header_reader->GetHashType()) { case NcaFsHeader::HashType::HierarchicalSha256Hash: - R_TRY(this->CreateSha256Storage(std::addressof(storage), std::move(storage), out_header_reader->GetHashData().hierarchical_sha256_data)); + R_TRY(this->CreateSha256Storage(std::addressof(storage), std::move(storage), header_reader->GetHashData().hierarchical_sha256_data)); break; case NcaFsHeader::HashType::HierarchicalIntegrityHash: - R_TRY(this->CreateIntegrityVerificationStorage(std::addressof(storage), std::move(storage), out_header_reader->GetHashData().integrity_meta_info)); + R_TRY(this->CreateIntegrityVerificationStorage(std::addressof(storage), std::move(storage), header_reader->GetHashData().integrity_meta_info)); break; default: return fs::ResultInvalidNcaFsHeaderHashType(); } /* Process compression layer. */ - if (out_header_reader->ExistsCompressionLayer()) { - R_TRY(this->CreateCompressedStorage(std::addressof(storage), ctx != nullptr ? std::addressof(ctx->compressed_storage) : nullptr, ctx != nullptr ? std::addressof(ctx->compressed_storage_meta_storage) : nullptr, std::move(storage), out_header_reader->GetCompressionInfo())); + if (header_reader->ExistsCompressionLayer()) { + R_TRY(this->CreateCompressedStorage(std::addressof(storage), ctx != nullptr ? std::addressof(ctx->compressed_storage) : nullptr, ctx != nullptr ? std::addressof(ctx->compressed_storage_meta_storage) : nullptr, std::move(storage), header_reader->GetCompressionInfo())); } /* Set output storage. */ diff --git a/libraries/libstratosphere/source/fssystem/fssystem_nca_reader.cpp b/libraries/libstratosphere/source/fssystem/fssystem_nca_reader.cpp index 60fd98c82..3a2608514 100644 --- a/libraries/libstratosphere/source/fssystem/fssystem_nca_reader.cpp +++ b/libraries/libstratosphere/source/fssystem/fssystem_nca_reader.cpp @@ -103,8 +103,13 @@ namespace ams::fssystem { const u8 *msg = static_cast(static_cast(std::addressof(m_header.magic))); const size_t msg_size = NcaHeader::Size - NcaHeader::HeaderSignSize * NcaHeader::HeaderSignCount; - const bool is_signature_valid = crypto::VerifyRsa2048PssSha256(sig, sig_size, mod, mod_size, exp, exp_size, msg, msg_size); - R_UNLESS(is_signature_valid, fs::ResultNcaHeaderSignature1VerificationFailed()); + m_is_header_sign1_signature_valid = crypto::VerifyRsa2048PssSha256(sig, sig_size, mod, mod_size, exp, exp_size, msg, msg_size); + + #if defined(ATMOSPHERE_BOARD_NINTENDO_NX) + R_UNLESS(m_is_header_sign1_signature_valid, fs::ResultNcaHeaderSignature1VerificationFailed()); + #else + R_UNLESS(m_is_header_sign1_signature_valid || crypto_cfg.is_unsigned_header_available_for_host_tool, fs::ResultNcaHeaderSignature1VerificationFailed()); + #endif } /* Validate the sdk version. */ @@ -363,14 +368,22 @@ namespace ams::fssystem { return m_header_storage->Read(offset, dst, sizeof(NcaFsHeader)); } - void NcaReader::GetHeaderSign2(void *dst, size_t size) { + bool NcaReader::GetHeaderSign1Valid() const { + #if defined(ATMOSPHERE_BOARD_NINTENDO_NX) + AMS_ABORT_UNLESS(m_is_header_sign1_signature_valid); + #endif + + return m_is_header_sign1_signature_valid; + } + + void NcaReader::GetHeaderSign2(void *dst, size_t size) const { AMS_ASSERT(dst != nullptr); AMS_ASSERT(size == NcaHeader::HeaderSignSize); std::memcpy(dst, m_header.header_sign_2, size); } - void NcaReader::GetHeaderSign2TargetHash(void *dst, size_t size) { + void NcaReader::GetHeaderSign2TargetHash(void *dst, size_t size) const { AMS_ASSERT(m_hash_generator_factory != nullptr); AMS_ASSERT(dst != nullptr); AMS_ASSERT(size == IHash256Generator::HashSize);