fs: add indirection to raw storage open, for hac2l

This commit is contained in:
Michael Scire 2022-03-13 20:58:02 -07:00
parent 09a44fa680
commit 76910e8954
6 changed files with 70 additions and 20 deletions

View file

@ -51,6 +51,8 @@ namespace ams::fssrv::fscreator {
#if !defined(ATMOSPHERE_BOARD_NINTENDO_NX) #if !defined(ATMOSPHERE_BOARD_NINTENDO_NX)
Result CreateWithContext(std::shared_ptr<fs::IStorage> *out, std::shared_ptr<fssystem::IAsynchronousAccessSplitter> *out_splitter, fssystem::NcaFsHeaderReader *out_header_reader, void *ctx, std::shared_ptr<fssystem::NcaReader> nca_reader, s32 index); Result CreateWithContext(std::shared_ptr<fs::IStorage> *out, std::shared_ptr<fssystem::IAsynchronousAccessSplitter> *out_splitter, fssystem::NcaFsHeaderReader *out_header_reader, void *ctx, std::shared_ptr<fssystem::NcaReader> nca_reader, s32 index);
Result CreateWithPatchWithContext(std::shared_ptr<fs::IStorage> *out, std::shared_ptr<fssystem::IAsynchronousAccessSplitter> *out_splitter, fssystem::NcaFsHeaderReader *out_header_reader, void *ctx, std::shared_ptr<fssystem::NcaReader> original_nca_reader, std::shared_ptr<fssystem::NcaReader> current_nca_reader, s32 index); Result CreateWithPatchWithContext(std::shared_ptr<fs::IStorage> *out, std::shared_ptr<fssystem::IAsynchronousAccessSplitter> *out_splitter, fssystem::NcaFsHeaderReader *out_header_reader, void *ctx, std::shared_ptr<fssystem::NcaReader> original_nca_reader, std::shared_ptr<fssystem::NcaReader> current_nca_reader, s32 index);
Result CreateByRawStorage(std::shared_ptr<fs::IStorage> *out, std::shared_ptr<fssystem::IAsynchronousAccessSplitter> *out_splitter, const fssystem::NcaFsHeaderReader *header_reader, std::shared_ptr<fs::IStorage> raw_storage, void *ctx, std::shared_ptr<fssystem::NcaReader> nca_reader);
#endif #endif
}; };

View file

@ -58,6 +58,10 @@ namespace ams::fssystem {
DecryptAesCtrFunction decrypt_aes_ctr; DecryptAesCtrFunction decrypt_aes_ctr;
DecryptAesCtrFunction decrypt_aes_ctr_external; DecryptAesCtrFunction decrypt_aes_ctr_external;
bool is_plaintext_header_available; 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<NcaCryptoConfiguration>::value); static_assert(util::is_pod<NcaCryptoConfiguration>::value);
@ -103,6 +107,7 @@ namespace ams::fssystem {
DecryptAesCtrFunction m_decrypt_aes_ctr_external; DecryptAesCtrFunction m_decrypt_aes_ctr_external;
bool m_is_software_aes_prioritized; bool m_is_software_aes_prioritized;
NcaHeader::EncryptionType m_header_encryption_type; NcaHeader::EncryptionType m_header_encryption_type;
bool m_is_header_sign1_signature_valid;
GetDecompressorFunction m_get_decompressor; GetDecompressorFunction m_get_decompressor;
IHash256GeneratorFactory *m_hash_generator_factory; IHash256GeneratorFactory *m_hash_generator_factory;
public: public:
@ -149,8 +154,10 @@ namespace ams::fssystem {
GetDecompressorFunction GetDecompressor() const; GetDecompressorFunction GetDecompressor() const;
IHash256GeneratorFactory *GetHashGeneratorFactory() const; IHash256GeneratorFactory *GetHashGeneratorFactory() const;
void GetHeaderSign2(void *dst, size_t size); bool GetHeaderSign1Valid() const;
void GetHeaderSign2TargetHash(void *dst, size_t size);
void GetHeaderSign2(void *dst, size_t size) const;
void GetHeaderSign2TargetHash(void *dst, size_t size) const;
}; };
class NcaFsHeaderReader : public ::ams::fs::impl::Newable { class NcaFsHeaderReader : public ::ams::fs::impl::Newable {
@ -252,6 +259,13 @@ namespace ams::fssystem {
/* Open the storage. */ /* Open the storage. */
R_RETURN(OpenStorageWithContext(out, out_splitter, out_header_reader, fs_index, std::addressof(ctx))); 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<fs::IStorage> *out, const NcaFsHeaderReader *header_reader, std::shared_ptr<fs::IStorage> raw_storage, StorageContext *ctx);
private: private:
Result OpenStorageImpl(std::shared_ptr<fs::IStorage> *out, NcaFsHeaderReader *out_header_reader, s32 fs_index, StorageContext *ctx); Result OpenStorageImpl(std::shared_ptr<fs::IStorage> *out, NcaFsHeaderReader *out_header_reader, s32 fs_index, StorageContext *ctx);

View file

@ -90,6 +90,22 @@ namespace ams::fssrv::fscreator {
*out_splitter = std::move(splitter); *out_splitter = std::move(splitter);
return ResultSuccess(); return ResultSuccess();
} }
Result StorageOnNcaCreator::CreateByRawStorage(std::shared_ptr<fs::IStorage> *out, std::shared_ptr<fssystem::IAsynchronousAccessSplitter> *out_splitter, const fssystem::NcaFsHeaderReader *header_reader, std::shared_ptr<fs::IStorage> raw_storage, void *ctx, std::shared_ptr<fssystem::NcaReader> 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<fssystem::NcaFileSystemDriver::StorageContext *>(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 #endif
} }

View file

@ -180,6 +180,11 @@ namespace ams::fssystem {
cfg->decrypt_aes_ctr_external = DecryptAesCtrForPreparedKey; cfg->decrypt_aes_ctr_external = DecryptAesCtrForPreparedKey;
cfg->is_plaintext_header_available = !prod; 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; return cfg;
} }

View file

@ -292,14 +292,6 @@ namespace ams::fssystem {
using IntegrityLevelInfo = NcaFsHeader::HashData::IntegrityMetaInfo::LevelHashInfo; using IntegrityLevelInfo = NcaFsHeader::HashData::IntegrityMetaInfo::LevelHashInfo;
using IntegrityDataInfo = IntegrityLevelInfo::HierarchicalIntegrityVerificationLevelInformation; 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<fs::IStorage> *out, std::shared_ptr<IAsynchronousAccessSplitter> *out_splitter, NcaFsHeaderReader *out_header_reader, s32 fs_index, StorageContext *ctx) { Result NcaFileSystemDriver::OpenStorageWithContext(std::shared_ptr<fs::IStorage> *out, std::shared_ptr<IAsynchronousAccessSplitter> *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 we have a compressed storage, use it as splitter. */
if (ctx->compressed_storage != nullptr) { if (ctx->compressed_storage != nullptr) {
*out_splitter = std::move(ctx->compressed_storage); *out_splitter = ctx->compressed_storage;
} else { } else {
/* Otherwise, allocate a default splitter. */ /* Otherwise, allocate a default splitter. */
*out_splitter = fssystem::AllocateShared<DefaultAsynchronousAccessSplitter>(); *out_splitter = fssystem::AllocateShared<DefaultAsynchronousAccessSplitter>();
@ -447,21 +439,29 @@ namespace ams::fssystem {
return ResultSuccess(); 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<fs::IStorage> *out, const NcaFsHeaderReader *header_reader, std::shared_ptr<fs::IStorage> raw_storage, StorageContext *ctx) {
/* Initialize storage as raw storage. */
std::shared_ptr<fs::IStorage> storage = std::move(raw_storage);
/* Process hash/integrity layer. */ /* Process hash/integrity layer. */
switch (out_header_reader->GetHashType()) { switch (header_reader->GetHashType()) {
case NcaFsHeader::HashType::HierarchicalSha256Hash: 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; break;
case NcaFsHeader::HashType::HierarchicalIntegrityHash: 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; break;
default: default:
return fs::ResultInvalidNcaFsHeaderHashType(); return fs::ResultInvalidNcaFsHeaderHashType();
} }
/* Process compression layer. */ /* Process compression layer. */
if (out_header_reader->ExistsCompressionLayer()) { 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), out_header_reader->GetCompressionInfo())); 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. */ /* Set output storage. */

View file

@ -103,8 +103,13 @@ namespace ams::fssystem {
const u8 *msg = static_cast<const u8 *>(static_cast<const void *>(std::addressof(m_header.magic))); const u8 *msg = static_cast<const u8 *>(static_cast<const void *>(std::addressof(m_header.magic)));
const size_t msg_size = NcaHeader::Size - NcaHeader::HeaderSignSize * NcaHeader::HeaderSignCount; 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); m_is_header_sign1_signature_valid = crypto::VerifyRsa2048PssSha256(sig, sig_size, mod, mod_size, exp, exp_size, msg, msg_size);
R_UNLESS(is_signature_valid, fs::ResultNcaHeaderSignature1VerificationFailed());
#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. */ /* Validate the sdk version. */
@ -363,14 +368,22 @@ namespace ams::fssystem {
return m_header_storage->Read(offset, dst, sizeof(NcaFsHeader)); 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(dst != nullptr);
AMS_ASSERT(size == NcaHeader::HeaderSignSize); AMS_ASSERT(size == NcaHeader::HeaderSignSize);
std::memcpy(dst, m_header.header_sign_2, size); 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(m_hash_generator_factory != nullptr);
AMS_ASSERT(dst != nullptr); AMS_ASSERT(dst != nullptr);
AMS_ASSERT(size == IHash256Generator::HashSize); AMS_ASSERT(size == IHash256Generator::HashSize);