1
0
Fork 0
mirror of https://github.com/DarkMatterCore/nxdumptool.git synced 2024-11-22 18:26:39 +00:00

More NCA parsing changes.

This commit is contained in:
Pablo Curiel 2022-06-24 02:22:01 +02:00
parent b8992d1fdc
commit 37b63aee60
8 changed files with 92 additions and 41 deletions

View file

@ -260,7 +260,7 @@ typedef enum {
} NacpRuntimeUpgrade;
typedef enum {
NacpSupportingLimitedLicenses_Demo = BIT(1),
NacpSupportingLimitedLicenses_Demo = BIT(0),
NacpSupportingLimitedLicenses_Count = 1 ///< Total values supported by this enum.
} NacpSupportingLimitedLicenses;
@ -368,7 +368,7 @@ typedef struct {
s64 device_save_data_journal_size;
s64 bcat_delivery_cache_storage_size;
char application_error_code_category[0x8];
u64 local_communication_id[8];
u64 local_communication_id[0x8];
u8 logo_type; ///< NacpLogoType.
u8 logo_handling; ///< NacpLogoHandling.
u8 runtime_add_on_content_install; ///< NacpRuntimeAddOnContentInstall.
@ -390,7 +390,7 @@ typedef struct {
s64 cache_storage_journal_size;
s64 cache_storage_data_and_journal_size_max;
u16 cache_storage_index_max;
u8 reserved_1[0x1];
u8 reserved_1;
u8 runtime_upgrade; ///< NacpRuntimeUpgrade.
u32 supporting_limited_licenses; ///< NacpSupportingLimitedLicenses.
u64 play_log_queryable_application_id[0x10];

View file

@ -85,7 +85,7 @@ typedef enum {
NcaKeyGeneration_Since910NUP = 11, ///< 9.1.0 - 12.0.3.
NcaKeyGeneration_Since1210NUP = 12, ///< 12.1.0.
NcaKeyGeneration_Since1300NUP = 13, ///< 13.0.0 - 13.2.1.
NcaKeyGeneration_Since1400NUP = 14, ///< 14.0.0 - 14.1.0.
NcaKeyGeneration_Since1400NUP = 14, ///< 14.0.0 - 14.1.2.
NcaKeyGeneration_Current = NcaKeyGeneration_Since1400NUP,
NcaKeyGeneration_Max = 32
} NcaKeyGeneration;
@ -100,7 +100,7 @@ typedef enum {
/// 'NcaSignatureKeyGeneration_Current' will always point to the last known key generation value.
typedef enum {
NcaSignatureKeyGeneration_Since100NUP = 0, ///< 1.0.0 - 8.1.1.
NcaSignatureKeyGeneration_Since900NUP = 1, ///< 9.0.0 - 14.1.0.
NcaSignatureKeyGeneration_Since900NUP = 1, ///< 9.0.0 - 14.1.2.
NcaSignatureKeyGeneration_Current = NcaSignatureKeyGeneration_Since900NUP,
NcaSignatureKeyGeneration_Max = (NcaSignatureKeyGeneration_Current + 1)
} NcaSignatureKeyGeneration;
@ -164,18 +164,23 @@ typedef enum {
} NcaFsType;
typedef enum {
NcaHashType_Auto = 0,
NcaHashType_None = 1,
NcaHashType_HierarchicalSha256 = 2, ///< Used by NcaFsType_PartitionFs.
NcaHashType_HierarchicalIntegrity = 3 ///< Used by NcaFsType_RomFs.
NcaHashType_Auto = 0,
NcaHashType_None = 1,
NcaHashType_HierarchicalSha256 = 2, ///< Used by NcaFsType_PartitionFs.
NcaHashType_HierarchicalIntegrity = 3, ///< Used by NcaFsType_RomFs.
NcaHashType_AutoSha3 = 4,
NcaHashType_HierarchicalSha3256 = 5,
NcaHashType_HierarchicalIntegritySha3 = 6
} NcaHashType;
typedef enum {
NcaEncryptionType_Auto = 0,
NcaEncryptionType_None = 1,
NcaEncryptionType_AesXts = 2,
NcaEncryptionType_AesCtr = 3,
NcaEncryptionType_AesCtrEx = 4
NcaEncryptionType_Auto = 0,
NcaEncryptionType_None = 1,
NcaEncryptionType_AesXts = 2,
NcaEncryptionType_AesCtr = 3,
NcaEncryptionType_AesCtrEx = 4,
NcaEncryptionType_AesCtrSkipLayerHash = 5,
NcaEncryptionType_AesCtrExSkipLayerHash = 6
} NcaEncryptionType;
typedef struct {
@ -298,9 +303,18 @@ NXDT_ASSERT(NcaSparseInfo, 0x30);
/// Used in NCAs with LZ4-compressed sections.
typedef struct {
NcaBucketInfo bucket;
u8 reserved[0x8];
} NcaCompressionInfo;
NXDT_ASSERT(NcaCompressionInfo, 0x20);
NXDT_ASSERT(NcaCompressionInfo, 0x28);
typedef struct {
u64 offset;
u64 size;
u8 hash[SHA256_HASH_SIZE];
} NcaMetaDataHashDataInfo;
NXDT_ASSERT(NcaMetaDataHashDataInfo, 0x30);
/// Four NCA FS headers are placed right after the 0x400 byte long NCA header in NCA2 and NCA3.
/// NCA0 place the FS headers at the start sector from the NcaFsInfo entries.
@ -315,7 +329,8 @@ typedef struct {
NcaAesCtrUpperIv aes_ctr_upper_iv;
NcaSparseInfo sparse_info;
NcaCompressionInfo compression_info;
u8 reserved_2[0x68];
NcaMetaDataHashDataInfo hash_data_info;
u8 reserved_2[0x30];
} NcaFsHeader;
NXDT_ASSERT(NcaFsHeader, 0x200);
@ -340,8 +355,9 @@ typedef struct {
u8 section_num;
u64 section_offset;
u64 section_size;
u8 section_type; ///< NcaFsSectionType.
u8 hash_type; ///< NcaHashType.
u8 encryption_type; ///< NcaEncryptionType.
u8 section_type; ///< NcaFsSectionType.
u8 ctr[AES_BLOCK_SIZE]; ///< Used to update the AES CTR context IV based on the desired offset.
Aes128CtrContext ctr_ctx;
Aes128XtsContext xts_decrypt_ctx;

View file

@ -42,7 +42,7 @@ extern "C" {
/// 'NpdmSignatureKeyGeneration_Current' will always point to the last known key generation value.
typedef enum {
NpdmSignatureKeyGeneration_Since100NUP = 0, ///< 1.0.0 - 8.1.1.
NpdmSignatureKeyGeneration_Since900NUP = 1, ///< 9.0.0 - 14.1.0.
NpdmSignatureKeyGeneration_Since900NUP = 1, ///< 9.0.0 - 14.1.2.
NpdmSignatureKeyGeneration_Current = NpdmSignatureKeyGeneration_Since900NUP,
NpdmSignatureKeyGeneration_Max = (NpdmSignatureKeyGeneration_Current + 1)
} NpdmSignatureKeyGeneration;
@ -92,8 +92,8 @@ NXDT_ASSERT(NpdmMetaHeader, 0x80);
typedef enum {
NpdmMemoryRegion_Application = 0,
NpdmMemoryRegion_Applet = 1,
NpdmMemoryRegion_SystemSecure = 2,
NpdmMemoryRegion_SystemNonSecure = 3,
NpdmMemoryRegion_SecureSystem = 2,
NpdmMemoryRegion_NonSecureSystem = 3,
/// Old.
NpdmMemoryRegion_NonSecure = NpdmMemoryRegion_Application,
@ -103,8 +103,8 @@ typedef enum {
typedef struct {
u32 production : 1;
u32 unqualified_approval : 1;
u32 memory_region : 2; ///< NpdmMemoryRegion.
u32 reserved : 28;
u32 memory_region : 5; ///< NpdmMemoryRegion.
u32 reserved : 25;
} NpdmAcidFlags;
NXDT_ASSERT(NpdmAcidFlags, 0x4);

View file

@ -148,7 +148,7 @@ NX_INLINE void gamecardCloseHandle(void);
static bool gamecardOpenStorageArea(u8 area);
static bool gamecardReadStorageArea(void *out, u64 read_size, u64 offset);
static void gamecardCloseStorageArea(void);
static void gamecardCloseStorageArea(bool switch_to_normal);
static bool gamecardGetStorageAreasSizes(void);
NX_INLINE u64 gamecardGetCapacityFromRomSizeValue(u8 rom_size);
@ -864,7 +864,7 @@ static void gamecardFreeInfo(bool clear_status)
g_gameCardHfsCount = 0;
gamecardCloseStorageArea();
gamecardCloseStorageArea(true);
if (clear_status) g_gameCardStatus = GameCardStatus_NotInserted;
}
@ -1033,9 +1033,6 @@ static bool gamecardGetHandleAndStorage(u32 partition)
NX_INLINE void gamecardCloseHandle(void)
{
/* TODO: find a way to properly close a gamecard handle. */
if (!g_gameCardHandle.value) return;
svcCloseHandle(g_gameCardHandle.value);
g_gameCardHandle.value = 0;
}
@ -1051,7 +1048,7 @@ static bool gamecardOpenStorageArea(u8 area)
if (g_gameCardHandle.value && serviceIsActive(&(g_gameCardStorage.s)) && g_gameCardCurrentStorageArea == area) return true;
/* Close both gamecard handle and open storage area. */
gamecardCloseStorageArea();
gamecardCloseStorageArea(false);
/* Retrieve both a new gamecard handle and a storage area handle. */
if (!gamecardGetHandleAndStorage(area - 1)) /* Zero-based index. */
@ -1143,8 +1140,22 @@ end:
return success;
}
static void gamecardCloseStorageArea(void)
static void gamecardCloseStorageArea(bool switch_to_normal)
{
if (g_gameCardCurrentStorageArea == GameCardStorageArea_None) return;
/* Workaround: try to reset the Lotus driver by switching to the normal storage area before closing all gamecard comms. */
if (switch_to_normal && g_gameCardCurrentStorageArea == GameCardStorageArea_Secure)
{
LOG_MSG("Switching to normal area before shutting down.");
if (gamecardOpenStorageArea(GameCardStorageArea_Normal))
{
/* Perform a bogus read (just one page). */
u8 bogus[GAMECARD_PAGE_SIZE] = {0};
gamecardReadStorageArea(bogus, sizeof(bogus), 0);
}
}
if (serviceIsActive(&(g_gameCardStorage.s)))
{
fsStorageClose(&g_gameCardStorage);
@ -1172,7 +1183,7 @@ static bool gamecardGetStorageAreasSizes(void)
rc = fsStorageGetSize(&g_gameCardStorage, (s64*)&area_size);
gamecardCloseStorageArea();
gamecardCloseStorageArea(false);
if (R_FAILED(rc) || !area_size)
{

View file

@ -573,14 +573,14 @@ static bool keysDeriveNcaHeaderKey(void)
rc = splCryptoGenerateAesKey(g_ncaKeyset.nca_header_kek_sealed, g_ncaKeyset.nca_header_key_source, g_ncaKeyset.nca_header_key);
if (R_FAILED(rc))
{
LOG_MSG("splCryptoGenerateAesKey failed! (0x%08X) (nca_header_key, part 1).", rc);
LOG_MSG("splCryptoGenerateAesKey failed! (0x%08X) (nca_header_key) (#1).", rc);
return false;
}
rc = splCryptoGenerateAesKey(g_ncaKeyset.nca_header_kek_sealed, g_ncaKeyset.nca_header_key_source + AES_128_KEY_SIZE, g_ncaKeyset.nca_header_key + AES_128_KEY_SIZE);
if (R_FAILED(rc))
{
LOG_MSG("splCryptoGenerateAesKey failed! (0x%08X) (nca_header_key, part 2).", rc);
LOG_MSG("splCryptoGenerateAesKey failed! (0x%08X) (nca_header_key) (#2).", rc);
return false;
}

View file

@ -194,7 +194,26 @@ bool ncaInitializeContext(NcaContext *out, u8 storage_id, u8 hfs_partition_type,
/* Check if we're dealing with an invalid start offset or an empty size. */
if (fs_ctx->section_offset < sizeof(NcaHeader) || !fs_ctx->section_size) continue;
/* Determine encryption type. */
/* Determine hash and encryption types. */
fs_ctx->hash_type = fs_ctx->header.hash_type;
if (fs_ctx->hash_type == NcaHashType_Auto || fs_ctx->hash_type == NcaHashType_AutoSha3)
{
switch(fs_ctx->section_num)
{
case 0: /* ExeFS Partition FS. */
fs_ctx->hash_type = (fs_ctx->hash_type == NcaHashType_Auto ? NcaHashType_HierarchicalSha256 : NcaHashType_HierarchicalSha3256);
break;
case 1: /* RomFS. */
fs_ctx->hash_type = (fs_ctx->hash_type == NcaHashType_Auto ? NcaHashType_HierarchicalIntegrity : NcaHashType_HierarchicalIntegritySha3);
break;
case 2: /* Logo Partition FS. */
fs_ctx->hash_type = NcaHashType_None;
break;
default:
break;
}
}
fs_ctx->encryption_type = (out->format_version == NcaVersion_Nca0 ? NcaEncryptionType_AesXts : fs_ctx->header.encryption_type);
if (fs_ctx->encryption_type == NcaEncryptionType_Auto)
{
@ -212,19 +231,21 @@ bool ncaInitializeContext(NcaContext *out, u8 storage_id, u8 hfs_partition_type,
}
}
/* Check if we're dealing with an invalid encryption type value. */
if (fs_ctx->encryption_type == NcaEncryptionType_Auto || fs_ctx->encryption_type > NcaEncryptionType_AesCtrEx) continue;
/* Check if we're dealing with invalid hash/encryption type values. */
if (fs_ctx->hash_type == NcaHashType_Auto || fs_ctx->hash_type == NcaHashType_AutoSha3 || fs_ctx->hash_type > NcaHashType_HierarchicalIntegritySha3 || \
fs_ctx->encryption_type == NcaEncryptionType_Auto || fs_ctx->encryption_type > NcaEncryptionType_AesCtrExSkipLayerHash) continue;
/* Determine FS section type. */
if (fs_ctx->header.fs_type == NcaFsType_PartitionFs && fs_ctx->header.hash_type == NcaHashType_HierarchicalSha256)
if (fs_ctx->header.fs_type == NcaFsType_PartitionFs && (fs_ctx->hash_type == NcaHashType_HierarchicalSha256 || fs_ctx->hash_type == NcaHashType_HierarchicalSha3256))
{
fs_ctx->section_type = NcaFsSectionType_PartitionFs;
} else
if (fs_ctx->header.fs_type == NcaFsType_RomFs && fs_ctx->header.hash_type == NcaHashType_HierarchicalIntegrity)
if (fs_ctx->header.fs_type == NcaFsType_RomFs && (fs_ctx->hash_type == NcaHashType_HierarchicalIntegrity || fs_ctx->hash_type == NcaHashType_HierarchicalIntegritySha3))
{
fs_ctx->section_type = (fs_ctx->encryption_type == NcaEncryptionType_AesCtrEx ? NcaFsSectionType_PatchRomFs : NcaFsSectionType_RomFs);
fs_ctx->section_type = ((fs_ctx->encryption_type == NcaEncryptionType_AesCtrEx || fs_ctx->encryption_type == NcaEncryptionType_AesCtrExSkipLayerHash) ? \
NcaFsSectionType_PatchRomFs : NcaFsSectionType_RomFs);
} else
if (fs_ctx->header.fs_type == NcaFsType_RomFs && fs_ctx->header.hash_type == NcaHashType_HierarchicalSha256 && out->format_version == NcaVersion_Nca0)
if (fs_ctx->header.fs_type == NcaFsType_RomFs && fs_ctx->hash_type == NcaHashType_HierarchicalSha256 && out->format_version == NcaVersion_Nca0)
{
fs_ctx->section_type = NcaFsSectionType_Nca0RomFs;
}
@ -753,7 +774,7 @@ static bool ncaEncryptKeyArea(NcaContext *ctx)
}
/* Clear encrypted key area. */
memset(&(ctx->header.encrypted_key_area), 0, NCA_USED_KEY_AREA_SIZE);
memset(&(ctx->header.encrypted_key_area), 0, sizeof(NcaEncryptedKeyArea));
/* Initialize AES-128-ECB encryption context using the retrieved KAEK. */
aes128ContextCreate(&key_area_ctx, kaek, true);

View file

@ -341,7 +341,7 @@ static u32 save_journal_storage_read(journal_storage_ctx_t *ctx, remap_storage_c
static bool save_ivfc_storage_init(hierarchical_integrity_verification_storage_ctx_t *ctx, u64 master_hash_offset, ivfc_save_hdr_t *ivfc)
{
if (!ctx || !ctx->levels || !ivfc || !ivfc->num_levels)
if (!ctx || !ivfc || !ivfc->num_levels)
{
LOG_MSG("Invalid parameters!");
return false;

View file

@ -238,6 +238,7 @@ static const TitleSystemEntry g_systemTitles[] = {
{ 0x0100000000001014, "PlayReport" },
{ 0x0100000000001015, "MaintenanceMenu" },
{ 0x0100000000001016, "application_install" }, ///< Placeholder.
{ 0x0100000000001017, "nn.am.SystemReportTask" }, ///< Placeholder.
{ 0x0100000000001018, "systemupdate_dl_throughput" }, ///< Placeholder.
{ 0x0100000000001019, "volume_update"}, ///< Placeholder.
{ 0x010000000000101A, "gift" },
@ -256,6 +257,7 @@ static const TitleSystemEntry g_systemTitles[] = {
{ 0x0100000000001028, "ns_unknown_1" }, ///< Placeholder.
{ 0x010000000000102A, "am_unknown_2" }, ///< Placeholder.
{ 0x010000000000102B, "glue_unknown_1" }, ///< Placeholder.
{ 0x010000000000102C, "am_unknown_3" }, ///< Placeholder.
{ 0x010000000000102E, "blacklist" },
{ 0x010000000000102F, "content_delivery" },
{ 0x0100000000001031, "ns_unknown_2" }, ///< Placeholder.
@ -264,6 +266,7 @@ static const TitleSystemEntry g_systemTitles[] = {
{ 0x0100000000001034, "ngct_unknown" }, ///< Placeholder.
{ 0x0100000000001037, "nim_unknown" }, ///< Placeholder.
{ 0x0100000000001038, "sample" },
{ 0x010000000000103C, "mnpp" }, ///< Placeholder.
{ 0x0100000000001FFF, "EndOceanProgramId" },
/* Development system applets. */