diff --git a/Makefile b/Makefile index d7c3120..0128e21 100644 --- a/Makefile +++ b/Makefile @@ -158,7 +158,7 @@ ifneq ($(ROMFS),) export NROFLAGS += --romfsdir=$(CURDIR)/$(ROMFS) endif -.PHONY: $(BUILD) clean all +.PHONY: $(BUILD) clean clean_all all #--------------------------------------------------------------------------------- all: $(BUILD) @@ -173,9 +173,10 @@ $(BUILD): usbhsfs #--------------------------------------------------------------------------------- clean: @echo clean ... - @$(MAKE) --no-print-directory -C libusbhsfs clean @rm -fr $(BUILD) *.pfs0 *.nso *.nro *.nacp *.elf +clean_all: clean + @$(MAKE) --no-print-directory -C libusbhsfs clean #--------------------------------------------------------------------------------- else diff --git a/source/aes.h b/source/aes.h index 880aa20..d56beaa 100644 --- a/source/aes.h +++ b/source/aes.h @@ -20,13 +20,13 @@ #pragma once +#ifndef __AES_H__ +#define __AES_H__ + #ifdef __cplusplus extern "C" { #endif -#ifndef __AES_H__ -#define __AES_H__ - /// Performs an AES-128-XTS crypto operation using the non-standard Nintendo XTS tweak. /// The Aes128XtsContext element should have been previously initialized with aes128XtsContextCreate(). 'encrypt' should match the value of 'is_encryptor' used with that call. /// 'dst' and 'src' can both point to the same address. @@ -84,8 +84,8 @@ NX_INLINE void aes128CtrUpdatePartialCtrEx(u8 *ctr, u32 ctr_val, u64 offset) } } -#endif /* __AES_H__ */ - #ifdef __cplusplus } -#endif \ No newline at end of file +#endif + +#endif /* __AES_H__ */ diff --git a/source/bfttf.h b/source/bfttf.h index f574afe..add1700 100644 --- a/source/bfttf.h +++ b/source/bfttf.h @@ -21,13 +21,13 @@ #pragma once +#ifndef __BFTTF_H__ +#define __BFTTF_H__ + #ifdef __cplusplus extern "C" { #endif -#ifndef __BFTTF_H__ -#define __BFTTF_H__ - /// Loosely based on PlSharedFontType. typedef enum { BfttfFontType_Standard = 0, ///< Japan, US and Europe @@ -56,8 +56,8 @@ void bfttfExit(void); /// Returns a specific BFTTF font using the provided BfttfFontType. bool bfttfGetFontByType(BfttfFontData *font, u8 font_type); -#endif /* __BFTTF_H__ */ - #ifdef __cplusplus } -#endif \ No newline at end of file +#endif + +#endif /* __BFTTF_H__ */ diff --git a/source/bktr.h b/source/bktr.h index 83ec386..1d95ea3 100644 --- a/source/bktr.h +++ b/source/bktr.h @@ -21,15 +21,15 @@ #pragma once -#ifdef __cplusplus -extern "C" { -#endif - #ifndef __BKTR_H__ #define __BKTR_H__ #include "romfs.h" +#ifdef __cplusplus +extern "C" { +#endif + typedef enum { BktrIndirectStorageIndex_Original = 0, BktrIndirectStorageIndex_Patch = 1 @@ -43,6 +43,8 @@ typedef struct { } BktrIndirectStorageEntry; #pragma pack(pop) +NXDT_ASSERT(BktrIndirectStorageEntry, 0x14); + typedef struct { u32 index; u32 entry_count; @@ -51,6 +53,8 @@ typedef struct { u8 reserved[0x3FF0 % sizeof(BktrIndirectStorageEntry)]; } BktrIndirectStorageBucket; +NXDT_ASSERT(BktrIndirectStorageBucket, 0x4000); + typedef struct { u32 index; u32 bucket_count; @@ -59,12 +63,16 @@ typedef struct { BktrIndirectStorageBucket indirect_storage_buckets[]; } BktrIndirectStorageBlock; +NXDT_ASSERT(BktrIndirectStorageBlock, 0x4000); + typedef struct { u64 offset; u32 size; u32 generation; } BktrAesCtrExStorageEntry; +NXDT_ASSERT(BktrAesCtrExStorageEntry, 0x10); + typedef struct { u32 index; u32 entry_count; @@ -72,6 +80,8 @@ typedef struct { BktrAesCtrExStorageEntry aes_ctr_ex_storage_entries[0x3FF]; } BktrAesCtrExStorageBucket; +NXDT_ASSERT(BktrAesCtrExStorageBucket, 0x4000); + typedef struct { u32 index; u32 bucket_count; @@ -80,6 +90,8 @@ typedef struct { BktrAesCtrExStorageBucket aes_ctr_ex_storage_buckets[]; } BktrAesCtrExStorageBlock; +NXDT_ASSERT(BktrAesCtrExStorageBlock, 0x4000); + typedef struct { RomFileSystemContext base_romfs_ctx; ///< Base NCA RomFS context. RomFileSystemContext patch_romfs_ctx; ///< Update NCA RomFS context. Must be used with RomFS directory/file entry functions, because it holds the updated directory/file tables. @@ -157,8 +169,8 @@ NX_INLINE bool bktrGeneratePathFromFileEntry(BktrContext *ctx, RomFileSystemFile return (ctx ? romfsGeneratePathFromFileEntry(&(ctx->patch_romfs_ctx), file_entry, out_path, out_path_size, illegal_char_replace_type) : false); } -#endif /* __BKTR_H__ */ - #ifdef __cplusplus } -#endif \ No newline at end of file +#endif + +#endif /* __BKTR_H__ */ diff --git a/source/cert.h b/source/cert.h index e2f2e71..7a2a2db 100644 --- a/source/cert.h +++ b/source/cert.h @@ -20,18 +20,93 @@ #pragma once -#ifdef __cplusplus -extern "C" { -#endif - #ifndef __CERT_H__ #define __CERT_H__ #include "signature.h" +#ifdef __cplusplus +extern "C" { +#endif + #define SIGNED_CERT_MAX_SIZE sizeof(CertSigRsa4096PubKeyRsa4096) #define SIGNED_CERT_MIN_SIZE sizeof(CertSigHmac160PubKeyEcc480) +#define GENERATE_CERT_STRUCT(sigtype, pubkeytype, certsize) \ +\ +typedef struct { \ + SignatureBlock##sigtype sig_block; \ + CertCommonBlock cert_common_block; \ + CertPublicKeyBlock##pubkeytype pub_key_block; \ +} CertSig##sigtype##PubKey##pubkeytype; \ +\ +NXDT_ASSERT(CertSig##sigtype##PubKey##pubkeytype, certsize); + +typedef enum { + CertPubKeyType_Rsa4096 = 0, + CertPubKeyType_Rsa2048 = 1, + CertPubKeyType_Ecc480 = 2 +} CertPubKeyType; + +/// Placed after the certificate signature block. +typedef struct { + char issuer[0x40]; + u32 pub_key_type; ///< CertPubKeyType. Always stored using big endian byte order. + char name[0x40]; + u32 date; ///< Stored using big endian byte order. +} CertCommonBlock; + +NXDT_ASSERT(CertCommonBlock, 0x88); + +/// RSA-4096 public key block. Placed after the certificate common block. +typedef struct { + u8 public_key[0x200]; + u32 public_exponent; + u8 padding[0x34]; +} CertPublicKeyBlockRsa4096; + +NXDT_ASSERT(CertPublicKeyBlockRsa4096, 0x238); + +/// RSA-2048 public key block. Placed after the certificate common block. +typedef struct { + u8 public_key[0x100]; + u32 public_exponent; + u8 padding[0x34]; +} CertPublicKeyBlockRsa2048; + +NXDT_ASSERT(CertPublicKeyBlockRsa2048, 0x138); + +/// ECC public key block. Placed after the certificate common block. +typedef struct { + u8 public_key[0x3C]; + u8 padding[0x3C]; +} CertPublicKeyBlockEcc480; + +NXDT_ASSERT(CertPublicKeyBlockEcc480, 0x78); + +/// All certificates generated below use a big endian sig_type field. + +/// Certificates with RSA-4096 signatures. +GENERATE_CERT_STRUCT(Rsa4096, Rsa4096, 0x500); /// pub_key_type field must be CertPubKeyType_Rsa4096. +GENERATE_CERT_STRUCT(Rsa4096, Rsa2048, 0x400); /// pub_key_type field must be CertPubKeyType_Rsa2048. +GENERATE_CERT_STRUCT(Rsa4096, Ecc480, 0x340); /// pub_key_type field must be CertPubKeyType_Ecc480. + +/// Certificates with RSA-2048 signatures. +GENERATE_CERT_STRUCT(Rsa2048, Rsa4096, 0x400); /// pub_key_type field must be CertPubKeyType_Rsa4096. +GENERATE_CERT_STRUCT(Rsa2048, Rsa2048, 0x300); /// pub_key_type field must be CertPubKeyType_Rsa2048. +GENERATE_CERT_STRUCT(Rsa2048, Ecc480, 0x240); /// pub_key_type field must be CertPubKeyType_Ecc480. + +/// Certificates with ECC signatures. +GENERATE_CERT_STRUCT(Ecc480, Rsa4096, 0x340); /// pub_key_type field must be CertPubKeyType_Rsa4096. +GENERATE_CERT_STRUCT(Ecc480, Rsa2048, 0x240); /// pub_key_type field must be CertPubKeyType_Rsa2048. +GENERATE_CERT_STRUCT(Ecc480, Ecc480, 0x180); /// pub_key_type field must be CertPubKeyType_Ecc480. + +/// Certificates with HMAC signatures. +GENERATE_CERT_STRUCT(Hmac160, Rsa4096, 0x300); /// pub_key_type field must be CertPubKeyType_Rsa4096. +GENERATE_CERT_STRUCT(Hmac160, Rsa2048, 0x200); /// pub_key_type field must be CertPubKeyType_Rsa2048. +GENERATE_CERT_STRUCT(Hmac160, Ecc480, 0x140); /// pub_key_type field must be CertPubKeyType_Ecc480. + +/// Certificate type. typedef enum { CertType_None = 0, CertType_SigRsa4096_PubKeyRsa4096 = 1, @@ -48,110 +123,6 @@ typedef enum { CertType_SigHmac160_PubKeyEcc480 = 12 } CertType; -/// Always stored using big endian byte order. -typedef enum { - CertPubKeyType_Rsa4096 = 0, - CertPubKeyType_Rsa2048 = 1, - CertPubKeyType_Ecc480 = 2 -} CertPubKeyType; - -/// Placed after the certificate signature block. -typedef struct { - char issuer[0x40]; - u32 pub_key_type; ///< CertPubKeyType. Stored using big endian byte order. - char name[0x40]; - u32 date; ///< Stored using big endian byte order. -} CertCommonBlock; - -typedef struct { - u8 public_key[0x200]; - u32 public_exponent; - u8 padding[0x34]; -} CertPublicKeyBlockRsa4096; - -typedef struct { - u8 public_key[0x100]; - u32 public_exponent; - u8 padding[0x34]; -} CertPublicKeyBlockRsa2048; - -typedef struct { - u8 public_key[0x3C]; - u8 padding[0x3C]; -} CertPublicKeyBlockEcc480; - -typedef struct { - SignatureBlockRsa4096 sig_block; ///< sig_type field is stored using big endian byte order. - CertCommonBlock cert_common_block; ///< pub_key_type field must be CertPubKeyType_Rsa4096. - CertPublicKeyBlockRsa4096 pub_key_block; -} CertSigRsa4096PubKeyRsa4096; - -typedef struct { - SignatureBlockRsa4096 sig_block; ///< sig_type field is stored using big endian byte order. - CertCommonBlock cert_common_block; ///< pub_key_type field must be CertPubKeyType_Rsa2048. - CertPublicKeyBlockRsa2048 pub_key_block; -} CertSigRsa4096PubKeyRsa2048; - -typedef struct { - SignatureBlockRsa4096 sig_block; ///< sig_type field is stored using big endian byte order. - CertCommonBlock cert_common_block; ///< pub_key_type field must be CertPubKeyType_Ecc480. - CertPublicKeyBlockEcc480 pub_key_block; -} CertSigRsa4096PubKeyEcc480; - -typedef struct { - SignatureBlockRsa2048 sig_block; ///< sig_type field is stored using big endian byte order. - CertCommonBlock cert_common_block; ///< pub_key_type field must be CertPubKeyType_Rsa4096. - CertPublicKeyBlockRsa4096 pub_key_block; -} CertSigRsa2048PubKeyRsa4096; - -typedef struct { - SignatureBlockRsa2048 sig_block; ///< sig_type field is stored using big endian byte order. - CertCommonBlock cert_common_block; ///< pub_key_type field must be CertPubKeyType_Rsa2048. - CertPublicKeyBlockRsa2048 pub_key_block; -} CertSigRsa2048PubKeyRsa2048; - -typedef struct { - SignatureBlockRsa2048 sig_block; ///< sig_type field is stored using big endian byte order. - CertCommonBlock cert_common_block; ///< pub_key_type field must be CertPubKeyType_Ecc480. - CertPublicKeyBlockEcc480 pub_key_block; -} CertSigRsa2048PubKeyEcc480; - -typedef struct { - SignatureBlockEcc480 sig_block; ///< sig_type field is stored using big endian byte order. - CertCommonBlock cert_common_block; ///< pub_key_type field must be CertPubKeyType_Rsa4096. - CertPublicKeyBlockRsa4096 pub_key_block; -} CertSigEcc480PubKeyRsa4096; - -typedef struct { - SignatureBlockEcc480 sig_block; ///< sig_type field is stored using big endian byte order. - CertCommonBlock cert_common_block; ///< pub_key_type field must be CertPubKeyType_Rsa2048. - CertPublicKeyBlockRsa2048 pub_key_block; -} CertSigEcc480PubKeyRsa2048; - -typedef struct { - SignatureBlockEcc480 sig_block; ///< sig_type field is stored using big endian byte order. - CertCommonBlock cert_common_block; ///< pub_key_type field must be CertPubKeyType_Ecc480. - CertPublicKeyBlockEcc480 pub_key_block; -} CertSigEcc480PubKeyEcc480; - -typedef struct { - SignatureBlockHmac160 sig_block; ///< sig_type field is stored using big endian byte order. - CertCommonBlock cert_common_block; ///< pub_key_type field must be CertPubKeyType_Rsa4096. - CertPublicKeyBlockRsa4096 pub_key_block; -} CertSigHmac160PubKeyRsa4096; - -typedef struct { - SignatureBlockHmac160 sig_block; ///< sig_type field is stored using big endian byte order. - CertCommonBlock cert_common_block; ///< pub_key_type field must be CertPubKeyType_Rsa2048. - CertPublicKeyBlockRsa2048 pub_key_block; -} CertSigHmac160PubKeyRsa2048; - -typedef struct { - SignatureBlockHmac160 sig_block; ///< sig_type field is stored using big endian byte order. - CertCommonBlock cert_common_block; ///< pub_key_type field must be CertPubKeyType_Ecc480. - CertPublicKeyBlockEcc480 pub_key_block; -} CertSigHmac160PubKeyEcc480; - /// Used to store certificate type, size and raw data. typedef struct { u8 type; ///< CertType. @@ -244,8 +215,8 @@ NX_INLINE u64 certGetSignedCertificateHashAreaSize(void *buf) return ((u64)sizeof(CertCommonBlock) + certGetPublicKeyBlockSize(__builtin_bswap32(cert_common_block->pub_key_type))); } -#endif /* __CERT_H__ */ - #ifdef __cplusplus } -#endif \ No newline at end of file +#endif + +#endif /* __CERT_H__ */ diff --git a/source/cnmt.h b/source/cnmt.h index e5b2116..7a28b00 100644 --- a/source/cnmt.h +++ b/source/cnmt.h @@ -20,15 +20,15 @@ #pragma once -#ifdef __cplusplus -extern "C" { -#endif - #ifndef __CNMT_H__ #define __CNMT_H__ #include "pfs.h" +#ifdef __cplusplus +extern "C" { +#endif + #define CNMT_DIGEST_SIZE SHA256_HASH_SIZE /// Equivalent to NcmContentMetaAttribute. @@ -64,12 +64,16 @@ typedef struct { u8 reserved_2[0x4]; } ContentMetaPackagedContentMetaHeader; +NXDT_ASSERT(ContentMetaPackagedContentMetaHeader, 0x20); + /// Extended header for the SystemUpdate title. /// Equivalent to NcmSystemUpdateMetaExtendedHeader. typedef struct { u32 extended_data_size; } ContentMetaSystemUpdateMetaExtendedHeader; +NXDT_ASSERT(ContentMetaSystemUpdateMetaExtendedHeader, 0x4); + /// Extended header for Application titles. /// Equivalent to NcmApplicationMetaExtendedHeader, but using VersionType1 structs. typedef struct { @@ -78,6 +82,8 @@ typedef struct { VersionType1 required_application_version; } ContentMetaApplicationMetaExtendedHeader; +NXDT_ASSERT(ContentMetaApplicationMetaExtendedHeader, 0x10); + /// Extended header for Patch titles. /// Equivalent to NcmPatchMetaExtendedHeader, but using a VersionType1 struct. typedef struct { @@ -87,6 +93,8 @@ typedef struct { u8 reserved[0x8]; } ContentMetaPatchMetaExtendedHeader; +NXDT_ASSERT(ContentMetaPatchMetaExtendedHeader, 0x18); + /// Extended header for AddOnContent titles. /// Equivalent to NcmAddOnContentMetaExtendedHeader, but using a VersionType1 struct. typedef struct { @@ -95,6 +103,8 @@ typedef struct { u8 reserved[0x4]; } ContentMetaAddOnContentMetaExtendedHeader; +NXDT_ASSERT(ContentMetaAddOnContentMetaExtendedHeader, 0x10); + /// Extended header for Delta titles. typedef struct { u64 application_id; @@ -102,6 +112,8 @@ typedef struct { u8 reserved[0x4]; } ContentMetaDeltaMetaExtendedHeader; +NXDT_ASSERT(ContentMetaDeltaMetaExtendedHeader, 0x10); + typedef enum { ContentMetaFirmwareVariationVersion_Invalid = 0, ContentMetaFirmwareVariationVersion_V1 = 1, @@ -120,12 +132,16 @@ typedef struct { u32 variation_count; ///< Determines how many firmware variation entries are available after this header. } ContentMetaSystemUpdateMetaExtendedDataHeader; +NXDT_ASSERT(ContentMetaSystemUpdateMetaExtendedDataHeader, 0x8); + /// Used if the firmware variation version matches ContentMetaFirmwareVariationVersion_V1. typedef struct { u32 firmware_variation_id; u8 reserved[0x1C]; } ContentMetaFirmwareVariationInfoV1; +NXDT_ASSERT(ContentMetaFirmwareVariationInfoV1, 0x20); + /// Used if the firmware variation version matches ContentMetaFirmwareVariationVersion_V2. typedef struct { bool refer_to_base; @@ -134,6 +150,8 @@ typedef struct { u8 reserved_2[0x18]; } ContentMetaFirmwareVariationInfoV2; +NXDT_ASSERT(ContentMetaFirmwareVariationInfoV2, 0x20); + /// Header for the extended data region in Patch titles, pointed to by the extended header. /// This is followed by: /// * 'history_count' ContentMetaPatchHistoryHeader entries. @@ -153,6 +171,8 @@ typedef struct { u8 reserved[0x4]; } ContentMetaPatchMetaExtendedDataHeader; +NXDT_ASSERT(ContentMetaPatchMetaExtendedDataHeader, 0x1C); + typedef struct { NcmContentMetaKey content_meta_key; u8 digest[CNMT_DIGEST_SIZE]; @@ -160,6 +180,8 @@ typedef struct { u8 reserved[0x6]; } ContentMetaPatchHistoryHeader; +NXDT_ASSERT(ContentMetaPatchHistoryHeader, 0x38); + typedef struct { u64 source_patch_id; u64 destination_patch_id; @@ -169,6 +191,8 @@ typedef struct { u8 reserved[0x8]; } ContentMetaPatchDeltaHistory; +NXDT_ASSERT(ContentMetaPatchDeltaHistory, 0x28); + typedef struct { u64 source_patch_id; u64 destination_patch_id; @@ -180,6 +204,8 @@ typedef struct { u8 reserved_2[0x6]; } ContentMetaPatchDeltaHeader; +NXDT_ASSERT(ContentMetaPatchDeltaHeader, 0x28); + typedef enum { ContentMetaUpdateType_ApplyAsDelta = 0, ContentMetaUpdateType_Overwrite = 1, @@ -201,11 +227,15 @@ typedef struct { } ContentMetaFragmentSet; #pragma pack(pop) +NXDT_ASSERT(ContentMetaFragmentSet, 0x34); + typedef struct { u16 content_info_index; u16 fragment_index; } ContentMetaFragmentIndicator; +NXDT_ASSERT(ContentMetaFragmentIndicator, 0x4); + /// Header for the extended data region in Delta titles, pointed to by the extended header. /// This is followed by: /// * 'fragment_set_count' ContentMetaFragmentSet entries. @@ -219,6 +249,8 @@ typedef struct { u8 reserved[0x6]; } ContentMetaDeltaMetaExtendedDataHeader; +NXDT_ASSERT(ContentMetaDeltaMetaExtendedDataHeader, 0x20); + typedef struct { NcaContext *nca_ctx; ///< Pointer to the NCA context for the Meta NCA from which CNMT data is retrieved. PartitionFileSystemContext pfs_ctx; ///< PartitionFileSystemContext for the Meta NCA FS section #0, which is where the CNMT is stored. @@ -293,8 +325,8 @@ NX_INLINE u32 cnmtGetRequiredTitleVersion(ContentMetaContext *cnmt_ctx) ((VersionType1*)(cnmt_ctx->extended_header + sizeof(u64)))->value : 0); } -#endif /* __CNMT_H__ */ - #ifdef __cplusplus } -#endif \ No newline at end of file +#endif + +#endif /* __CNMT_H__ */ diff --git a/source/common.h b/source/common.h index 607be9a..0ab4d3c 100644 --- a/source/common.h +++ b/source/common.h @@ -23,13 +23,6 @@ #ifndef __COMMON_H__ #define __COMMON_H__ -#ifndef __cplusplus -# include -#else -# include -# define _Atomic(X) std::atomic< X > -#endif - #include #include #include @@ -45,6 +38,13 @@ #include #include +#ifndef __cplusplus +#include +#else +#include +#define _Atomic(X) std::atomic< X > +#endif + #include "log.h" #include "ums.h" @@ -56,6 +56,8 @@ #define FAT32_FILESIZE_LIMIT (u64)0xFFFFFFFF /* 4 GiB - 1 (4294967295 bytes). */ +#define NXDT_ASSERT(name, size) static_assert(sizeof(name) == (size), "Bad size for " #name "! Expected " #size ".") + /// Used to store version numbers expressed in dot notation: "{major}.{minor}.{micro}-{major_relstep}.{minor_relstep}". /// Referenced by multiple header files. typedef struct { @@ -71,6 +73,8 @@ typedef struct { }; } VersionType1; +NXDT_ASSERT(VersionType1, 0x4); + /// Used to store version numbers expressed in dot notation: "{major}.{minor}.{micro}-{relstep}". /// Only used by GameCardFwMode and NcaSdkAddOnVersion. typedef struct { @@ -85,6 +89,8 @@ typedef struct { }; } VersionType2; +NXDT_ASSERT(VersionType2, 0x4); + /// These are set in main(). extern int g_argc; extern char **g_argv; diff --git a/source/crc32_fast.h b/source/crc32_fast.h index 1b4b7f2..6fd5a86 100644 --- a/source/crc32_fast.h +++ b/source/crc32_fast.h @@ -23,19 +23,19 @@ #pragma once +#ifndef __CRC32_FAST_H__ +#define __CRC32_FAST_H__ + #ifdef __cplusplus extern "C" { #endif -#ifndef __CRC32_FAST_H__ -#define __CRC32_FAST_H__ - /// Calculates a CRC32 checksum over the provided input buffer. Checksum calculation in chunks is supported. /// CRC32 calculation state is both read from and saved to 'crc', which should be zero during the first call to this function. void crc32FastCalculate(const void *data, u64 n_bytes, u32 *crc); -#endif /* __CRC32_FAST_H__ */ - #ifdef __cplusplus } -#endif \ No newline at end of file +#endif + +#endif /* __CRC32_FAST_H__ */ diff --git a/source/elf_symbol.h b/source/elf_symbol.h index 976a620..6a48063 100644 --- a/source/elf_symbol.h +++ b/source/elf_symbol.h @@ -79,6 +79,8 @@ typedef struct { u16 st_shndx; ///< Holds the relevant section header table index. } Elf32Symbol; +NXDT_ASSERT(Elf32Symbol, 0x10); + typedef struct { u32 st_name; ///< Symbol name offset within dynamic string table. u8 st_info; ///< Symbol type (lower nibble) and binding attributes (upper nibble). @@ -88,4 +90,6 @@ typedef struct { u64 st_size; ///< Symbol size. } Elf64Symbol; +NXDT_ASSERT(Elf64Symbol, 0x18); + #endif /* __ELF_SYMBOL_H__ */ diff --git a/source/es.h b/source/es.h index 677b564..ebb55db 100644 --- a/source/es.h +++ b/source/es.h @@ -21,13 +21,13 @@ #pragma once +#ifndef __ES_H__ +#define __ES_H__ + #ifdef __cplusplus extern "C" { #endif -#ifndef __ES_H__ -#define __ES_H__ - Result esInitialize(void); void esExit(void); @@ -36,8 +36,8 @@ Result esCountPersonalizedTicket(s32 *out_count); Result esListCommonTicket(s32 *out_entries_written, FsRightsId *out_ids, s32 count); Result esListPersonalizedTicket(s32 *out_entries_written, FsRightsId *out_ids, s32 count); -#endif /* __ES_H__ */ - #ifdef __cplusplus } -#endif \ No newline at end of file +#endif + +#endif /* __ES_H__ */ diff --git a/source/fs_ext.h b/source/fs_ext.h index 631941a..431c25c 100644 --- a/source/fs_ext.h +++ b/source/fs_ext.h @@ -20,13 +20,13 @@ #pragma once +#ifndef __FS_EXT_H__ +#define __FS_EXT_H__ + #ifdef __cplusplus extern "C" { #endif -#ifndef __FS_EXT_H__ -#define __FS_EXT_H__ - #define GAMECARD_CERT_MAGIC 0x43455254 /* "CERT". */ /// Located at offset 0x7000 in the gamecard image. @@ -41,6 +41,8 @@ typedef struct { u8 encrypted_data[0xD0]; } FsGameCardCertificate; +NXDT_ASSERT(FsGameCardCertificate, 0x200); + /// IFileSystemProxy. Result fsOpenGameCardStorage(FsStorage *out, const FsGameCardHandle *handle, u32 partition); Result fsOpenGameCardDetectionEventNotifier(FsEventNotifier *out); @@ -49,8 +51,8 @@ Result fsOpenGameCardDetectionEventNotifier(FsEventNotifier *out); Result fsDeviceOperatorUpdatePartitionInfo(FsDeviceOperator *d, const FsGameCardHandle *handle, u32 *out_title_version, u64 *out_title_id); Result fsDeviceOperatorGetGameCardDeviceCertificate(FsDeviceOperator *d, const FsGameCardHandle *handle, FsGameCardCertificate *out); -#endif /* __FS_EXT_H__ */ - #ifdef __cplusplus } -#endif \ No newline at end of file +#endif + +#endif /* __FS_EXT_H__ */ diff --git a/source/gamecard.c b/source/gamecard.c index 335fbf0..785e604 100644 --- a/source/gamecard.c +++ b/source/gamecard.c @@ -61,6 +61,8 @@ typedef struct { GameCardInitialData initial_data; } GameCardSecurityInformation; +NXDT_ASSERT(GameCardSecurityInformation, 0x600); + /* Global variables. */ static Mutex g_gameCardMutex = 0; diff --git a/source/gamecard.h b/source/gamecard.h index 18ce29d..7ca09e4 100644 --- a/source/gamecard.h +++ b/source/gamecard.h @@ -20,16 +20,16 @@ #pragma once -#ifdef __cplusplus -extern "C" { -#endif - #ifndef __GAMECARD_H__ #define __GAMECARD_H__ #include "fs_ext.h" #include "hfs.h" +#ifdef __cplusplus +extern "C" { +#endif + #define GAMECARD_HEAD_MAGIC 0x48454144 /* "HEAD". */ #define GAMECARD_MEDIA_UNIT_SIZE 0x200 @@ -45,6 +45,8 @@ typedef struct { u8 reserved[0x8]; ///< Just zeroes. } GameCardKeySource; +NXDT_ASSERT(GameCardKeySource, 0x10); + /// Plaintext area. Dumped from FS program memory. typedef struct { GameCardKeySource key_source; @@ -54,12 +56,16 @@ typedef struct { u8 reserved[0x1C4]; } GameCardInitialData; +NXDT_ASSERT(GameCardInitialData, 0x200); + /// Encrypted using AES-128-CTR with the key and IV/counter from the `GameCardTitleKeyEncryption` section. Assumed to be all zeroes in retail gamecards. typedef struct { u8 titlekey[0x10]; ///< Decrypted titlekey from the `GameCardInitialData` section. u8 reserved[0xCF0]; } GameCardTitleKey; +NXDT_ASSERT(GameCardTitleKey, 0xD00); + /// Encrypted using RSA-2048-OAEP and a private OAEP key from AuthoringTool. Assumed to be all zeroes in retail gamecards. typedef struct { u8 titlekey_encryption_key[0x10]; ///< Used as the AES-128-CTR key for the `GameCardTitleKey` section. Randomly generated during XCI creation by AuthoringTool. @@ -67,6 +73,8 @@ typedef struct { u8 reserved[0xE0]; } GameCardTitleKeyEncryption; +NXDT_ASSERT(GameCardTitleKeyEncryption, 0x100); + /// Used to secure communications between the Lotus and the inserted gamecard. /// Precedes the gamecard header. typedef struct { @@ -75,6 +83,8 @@ typedef struct { GameCardTitleKeyEncryption titlekey_encryption; } GameCardKeyArea; +NXDT_ASSERT(GameCardKeyArea, 0x1000); + typedef enum { GameCardKekIndex_Version0 = 0, GameCardKekIndex_VersionForDev = 1 @@ -85,6 +95,8 @@ typedef struct { u8 titlekey_dec_index : 4; } GameCardKeyIndex; +NXDT_ASSERT(GameCardKeyIndex, 0x1); + typedef enum { GameCardRomSize_1GiB = 0xFA, GameCardRomSize_2GiB = 0xF8, @@ -144,6 +156,8 @@ typedef struct { u8 reserved_2[0x38]; } GameCardHeaderEncryptedArea; +NXDT_ASSERT(GameCardHeaderEncryptedArea, 0x70); + /// Placed after the `GameCardKeyArea` section. typedef struct { u8 signature[0x100]; ///< RSA-2048-PSS with SHA-256 signature over the rest of the header. @@ -169,6 +183,8 @@ typedef struct { GameCardHeaderEncryptedArea encrypted_area; } GameCardHeader; +NXDT_ASSERT(GameCardHeader, 0x200); + typedef enum { GameCardStatus_NotInserted = 0, GameCardStatus_InsertedAndInfoNotLoaded = 1, ///< Most likely related to the "nogc" patch being enabled. Means nothing at all can be done with the inserted gamecard. @@ -238,8 +254,8 @@ bool gamecardGetHashFileSystemContext(u8 hfs_partition_type, HashFileSystemConte /// If you need to get entry information by index, just retrieve the Hash FS context for the target partition and use Hash FS functions on it. bool gamecardGetHashFileSystemEntryInfoByName(u8 hfs_partition_type, const char *entry_name, u64 *out_offset, u64 *out_size); -#endif /* __GAMECARD_H__ */ - #ifdef __cplusplus } -#endif \ No newline at end of file +#endif + +#endif /* __GAMECARD_H__ */ diff --git a/source/hfs.h b/source/hfs.h index 1a11192..fde7d85 100644 --- a/source/hfs.h +++ b/source/hfs.h @@ -20,13 +20,13 @@ #pragma once +#ifndef __HFS_H__ +#define __HFS_H__ + #ifdef __cplusplus extern "C" { #endif -#ifndef __HFS_H__ -#define __HFS_H__ - #define HFS0_MAGIC 0x48465330 /* "HFS0". */ typedef struct { @@ -36,6 +36,8 @@ typedef struct { u8 reserved[0x4]; } HashFileSystemHeader; +NXDT_ASSERT(HashFileSystemHeader, 0x10); + typedef struct { u64 offset; u64 size; @@ -45,6 +47,8 @@ typedef struct { u8 hash[SHA256_HASH_SIZE]; } HashFileSystemEntry; +NXDT_ASSERT(HashFileSystemEntry, 0x40); + /// Internally used by gamecard functions. /// Use gamecardGetHashFileSystemContext() to retrieve a Hash FS context. typedef struct { @@ -121,8 +125,8 @@ NX_INLINE HashFileSystemEntry *hfsGetEntryByName(HashFileSystemContext *ctx, con return hfsGetEntryByIndex(ctx, idx); } -#endif /* __HFS_H__ */ - #ifdef __cplusplus } -#endif \ No newline at end of file +#endif + +#endif /* __HFS_H__ */ diff --git a/source/keys.h b/source/keys.h index d68092c..7333cee 100644 --- a/source/keys.h +++ b/source/keys.h @@ -22,13 +22,13 @@ #pragma once +#ifndef __KEYS_H__ +#define __KEYS_H__ + #ifdef __cplusplus extern "C" { #endif -#ifndef __KEYS_H__ -#define __KEYS_H__ - bool keysLoadNcaKeyset(void); const u8 *keysGetNcaHeaderKey(void); @@ -37,8 +37,8 @@ const u8 *keysGetEticketRsaKek(bool personalized); const u8 *keysGetTitlekek(u8 key_generation); const u8 *keysGetKeyAreaEncryptionKey(u8 key_generation, u8 kaek_index); -#endif /* __KEYS_H__ */ - #ifdef __cplusplus } -#endif \ No newline at end of file +#endif + +#endif /* __KEYS_H__ */ diff --git a/source/legal_info.h b/source/legal_info.h index d5d29ce..542a3ee 100644 --- a/source/legal_info.h +++ b/source/legal_info.h @@ -20,15 +20,15 @@ #pragma once -#ifdef __cplusplus -extern "C" { -#endif - #ifndef __LEGAL_INFO_H__ #define __LEGAL_INFO_H__ #include "nca.h" +#ifdef __cplusplus +extern "C" { +#endif + typedef struct { NcaContext *nca_ctx; ///< Pointer to the NCA context for the LegalInformation NCA from which XML data is retrieved. char *authoring_tool_xml; ///< Pointer to a dynamically allocated, NULL-terminated buffer that holds AuthoringTool-like XML data. @@ -47,8 +47,8 @@ NX_INLINE void legalInfoFreeContext(LegalInfoContext *legal_info_ctx) memset(legal_info_ctx, 0, sizeof(LegalInfoContext)); } -#endif /* __LEGAL_INFO_H__ */ - #ifdef __cplusplus } -#endif \ No newline at end of file +#endif + +#endif /* __LEGAL_INFO_H__ */ diff --git a/source/log.h b/source/log.h index 9884842..bcbddd7 100644 --- a/source/log.h +++ b/source/log.h @@ -20,13 +20,13 @@ #pragma once +#ifndef __LOG_H__ +#define __LOG_H__ + #ifdef __cplusplus extern "C" { #endif -#ifndef __LOG_H__ -#define __LOG_H__ - /// Helper macros. #define LOG_MSG(fmt, ...) logWriteFormattedStringToLogFile(__func__, fmt, ##__VA_ARGS__) #define LOG_MSG_BUF(dst, dst_size, fmt, ...) logWriteFormattedStringToBuffer(dst, dst_size, __func__, fmt, ##__VA_ARGS__) @@ -58,8 +58,8 @@ void logGetLastMessage(char *dst, size_t dst_size); /// Use with caution. void logControlMutex(bool lock); -#endif /* __LOG_H__ */ - #ifdef __cplusplus } -#endif \ No newline at end of file +#endif + +#endif /* __LOG_H__ */ diff --git a/source/mem.h b/source/mem.h index f512df3..f90bb7c 100644 --- a/source/mem.h +++ b/source/mem.h @@ -21,13 +21,13 @@ #pragma once +#ifndef __MEM_H__ +#define __MEM_H__ + #ifdef __cplusplus extern "C" { #endif -#ifndef __MEM_H__ -#define __MEM_H__ - typedef enum { MemoryProgramSegmentType_Text = BIT(0), MemoryProgramSegmentType_Rodata = BIT(1), @@ -59,8 +59,8 @@ NX_INLINE void memFreeMemoryLocation(MemoryLocation *location) location->data_size = 0; } -#endif /* __MEM_H__ */ - #ifdef __cplusplus } -#endif \ No newline at end of file +#endif + +#endif /* __MEM_H__ */ diff --git a/source/nacp.h b/source/nacp.h index 1e3edb3..00d2956 100644 --- a/source/nacp.h +++ b/source/nacp.h @@ -20,15 +20,15 @@ #pragma once -#ifdef __cplusplus -extern "C" { -#endif - #ifndef __NACP_H__ #define __NACP_H__ #include "romfs.h" +#ifdef __cplusplus +extern "C" { +#endif + #define NACP_MAX_ICON_SIZE 0x20000 /* 128 KiB. */ typedef struct { @@ -36,6 +36,8 @@ typedef struct { char publisher[0x100]; } NacpTitle; +NXDT_ASSERT(NacpTitle, 0x300); + typedef enum { NacpStartupUserAccount_None = 0, NacpStartupUserAccount_Required = 1, @@ -180,6 +182,8 @@ typedef struct { s8 reserved[0x13]; } NacpRatingAge; +NXDT_ASSERT(NacpRatingAge, 0x20); + typedef enum { NacpLogoType_LicensedByNintendo = 0, NacpLogoType_DistributedByNintendo = 1, ///< Removed. @@ -252,15 +256,21 @@ typedef struct { u64 memory_size; } NacpJitConfiguration; +NXDT_ASSERT(NacpJitConfiguration, 0x10); + typedef struct { u16 index : 15; u16 continue_set : 1; ///< Called "flag" by Nintendo, which isn't really great. } NacpDescriptors; +NXDT_ASSERT(NacpDescriptors, 0x2); + typedef struct { NacpDescriptors descriptors[0x20]; } NacpRequiredAddOnContentsSetBinaryDescriptor; +NXDT_ASSERT(NacpRequiredAddOnContentsSetBinaryDescriptor, 0x40); + typedef enum { NacpPlayReportPermission_None = 0, NacpPlayReportPermission_TargetMarketing = 1, @@ -283,6 +293,8 @@ typedef struct { u64 application_id[8]; } NacpAccessibleLaunchRequiredVersion; +NXDT_ASSERT(NacpAccessibleLaunchRequiredVersion, 0x40); + typedef struct { NacpTitle title[0x10]; char isbn[0x25]; @@ -346,6 +358,8 @@ typedef struct { u8 reserved_6[0xBB8]; } _NacpStruct; +NXDT_ASSERT(_NacpStruct, 0x4000); + typedef struct { u8 language; ///< NacpLanguage. u64 icon_size; ///< JPG icon size. Must not exceed NACP_MAX_ICON_SIZE. @@ -455,8 +469,8 @@ NX_INLINE bool nacpIsValidContext(NacpContext *nacp_ctx) return true; } -#endif /* __NACP_H__ */ - #ifdef __cplusplus } -#endif \ No newline at end of file +#endif + +#endif /* __NACP_H__ */ diff --git a/source/nca.h b/source/nca.h index f62de90..8eeddd0 100644 --- a/source/nca.h +++ b/source/nca.h @@ -20,15 +20,15 @@ #pragma once -#ifdef __cplusplus -extern "C" { -#endif - #ifndef __NCA_H__ #define __NCA_H__ #include "tik.h" +#ifdef __cplusplus +extern "C" { +#endif + #define NCA_FS_HEADER_COUNT 4 #define NCA_FULL_HEADER_LENGTH (sizeof(NcaHeader) + (sizeof(NcaFsHeader) * NCA_FS_HEADER_COUNT)) @@ -100,10 +100,14 @@ typedef struct { u8 reserved[0x4]; } NcaFsInfo; +NXDT_ASSERT(NcaFsInfo, 0x10); + typedef struct { u8 hash[SHA256_HASH_SIZE]; } NcaFsHeaderHash; +NXDT_ASSERT(NcaFsHeaderHash, 0x20); + /// Encrypted NCA key area used to hold NCA FS section encryption keys. Zeroed out if the NCA uses titlekey crypto. /// Only the first 4 key entries are encrypted. /// If a particular key entry is unused, it is zeroed out before this area is encrypted. @@ -116,6 +120,8 @@ typedef struct { u8 reserved[0xB0]; } NcaEncryptedKeyArea; +NXDT_ASSERT(NcaEncryptedKeyArea, 0x100); + /// First 0x400 bytes from every NCA. typedef struct { u8 main_signature[0x100]; ///< RSA-2048-PSS with SHA-256 signature over header using a fixed key. @@ -138,6 +144,8 @@ typedef struct { NcaEncryptedKeyArea encrypted_key_area; } NcaHeader; +NXDT_ASSERT(NcaHeader, 0x400); + typedef enum { NcaFsType_RomFs = 0, NcaFsType_PartitionFs = 1 @@ -163,6 +171,8 @@ typedef struct { u64 size; } NcaRegion; +NXDT_ASSERT(NcaRegion, 0x10); + /// Used by NcaFsType_PartitionFs and NCA0 NcaFsType_RomFs. typedef struct { u8 master_hash[SHA256_HASH_SIZE]; @@ -171,6 +181,8 @@ typedef struct { NcaRegion hash_region[NCA_HIERARCHICAL_SHA256_MAX_REGION_COUNT]; } NcaHierarchicalSha256Data; +NXDT_ASSERT(NcaHierarchicalSha256Data, 0x78); + typedef struct { u64 offset; u64 size; @@ -178,10 +190,14 @@ typedef struct { u8 reserved[0x4]; } NcaHierarchicalIntegrityVerificationLevelInformation; +NXDT_ASSERT(NcaHierarchicalIntegrityVerificationLevelInformation, 0x18); + typedef struct { u8 value[0x20]; } NcaSignatureSalt; +NXDT_ASSERT(NcaSignatureSalt, 0x20); + #pragma pack(push, 1) typedef struct { u32 max_level_count; ///< Always NCA_IVFC_MAX_LEVEL_COUNT. @@ -190,6 +206,8 @@ typedef struct { } NcaInfoLevelHash; #pragma pack(pop) +NXDT_ASSERT(NcaInfoLevelHash, 0xB4); + /// Used by NcaFsType_RomFs. typedef struct { u32 magic; ///< "IVFC". @@ -199,6 +217,8 @@ typedef struct { u8 master_hash[SHA256_HASH_SIZE]; } NcaIntegrityMetaInfo; +NXDT_ASSERT(NcaIntegrityMetaInfo, 0xE0); + typedef struct { union { struct { @@ -214,6 +234,8 @@ typedef struct { }; } NcaHashData; +NXDT_ASSERT(NcaHashData, 0xF8); + typedef struct { u32 magic; ///< "BKTR". u32 version; ///< offset_count / node_count ? @@ -221,18 +243,24 @@ typedef struct { u8 reserved[0x4]; } NcaBucketTreeHeader; +NXDT_ASSERT(NcaBucketTreeHeader, 0x10); + typedef struct { u64 offset; u64 size; NcaBucketTreeHeader header; } NcaBucketInfo; +NXDT_ASSERT(NcaBucketInfo, 0x20); + /// Only used for NcaEncryptionType_AesCtrEx (PatchRomFs). typedef struct { NcaBucketInfo indirect_bucket; NcaBucketInfo aes_ctr_ex_bucket; } NcaPatchInfo; +NXDT_ASSERT(NcaPatchInfo, 0x40); + typedef struct { union { u8 value[0x8]; @@ -243,6 +271,8 @@ typedef struct { }; } NcaAesCtrUpperIv; +NXDT_ASSERT(NcaAesCtrUpperIv, 0x8); + /// Used in NCAs with sparse storage. typedef struct { NcaBucketInfo sparse_bucket; @@ -251,6 +281,8 @@ typedef struct { u8 reserved[0x6]; } NcaSparseInfo; +NXDT_ASSERT(NcaSparseInfo, 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. typedef struct { @@ -266,6 +298,8 @@ typedef struct { u8 reserved_2[0x88]; } NcaFsHeader; +NXDT_ASSERT(NcaFsHeader, 0x200); + typedef enum { NcaFsSectionType_PartitionFs = 0, ///< NcaFsType_PartitionFs + NcaHashType_HierarchicalSha256. NcaFsSectionType_RomFs = 1, ///< NcaFsType_RomFs + NcaHashType_HierarchicalIntegrity. @@ -307,6 +341,8 @@ typedef struct { u8 aes_ctr_ex[AES_128_KEY_SIZE]; ///< AES-128-CTR key used for NCA FS sections with NcaEncryptionType_AesCtrEx crypto. } NcaDecryptedKeyArea; +NXDT_ASSERT(NcaDecryptedKeyArea, 0x40); + typedef struct { u8 storage_id; ///< NcmStorageId. NcmContentStorage *ncm_storage; ///< Pointer to a NcmContentStorage instance. Used to read NCA data from eMMC/SD. @@ -497,8 +533,8 @@ NX_INLINE void ncaFreeHierarchicalIntegrityPatch(NcaHierarchicalIntegrityPatch * memset(patch, 0, sizeof(NcaHierarchicalIntegrityPatch)); } -#endif /* __NCA_H__ */ - #ifdef __cplusplus } -#endif \ No newline at end of file +#endif + +#endif /* __NCA_H__ */ diff --git a/source/npdm.h b/source/npdm.h index 1eb440e..42392d1 100644 --- a/source/npdm.h +++ b/source/npdm.h @@ -20,15 +20,15 @@ #pragma once -#ifdef __cplusplus -extern "C" { -#endif - #ifndef __NPDM_H__ #define __NPDM_H__ #include "pfs.h" +#ifdef __cplusplus +extern "C" { +#endif + #define NPDM_META_MAGIC 0x4D455441 /* "META". */ #define NPDM_ACID_MAGIC 0x41434944 /* "ACID". */ #define NPDM_ACI0_MAGIC 0x41434930 /* "ACI0". */ @@ -53,6 +53,8 @@ typedef struct { u8 reserved : 2; } NpdmMetaFlags; +NXDT_ASSERT(NpdmMetaFlags, 0x1); + /// This is the start of every NPDM file. /// This is followed by ACID and ACI0 sections, both with variable offsets and sizes. typedef struct { @@ -76,6 +78,8 @@ typedef struct { u32 acid_size; } NpdmMetaHeader; +NXDT_ASSERT(NpdmMetaHeader, 0x80); + typedef enum { NpdmMemoryRegion_Application = 0, NpdmMemoryRegion_Applet = 1, @@ -94,6 +98,8 @@ typedef struct { u32 reserved : 28; } NpdmAcidFlags; +NXDT_ASSERT(NpdmAcidFlags, 0x4); + /// This is the start of an ACID section. /// This is followed by FsAccessControl, SrvAccessControl and KernelCapability descriptors, each one aligned to a 0x10 byte boundary using zero padding (if needed). typedef struct { @@ -114,6 +120,8 @@ typedef struct { u8 reserved_2[0x8]; } NpdmAcidHeader; +NXDT_ASSERT(NpdmAcidHeader, 0x240); + /// This is the start of an ACI0 section. /// This is followed by a FsAccessControl data block, as well as SrvAccessControl and KernelCapability descriptors, each one aligned to a 0x10 byte boundary using zero padding (if needed). typedef struct { @@ -130,6 +138,8 @@ typedef struct { u8 reserved_3[0x8]; } NpdmAciHeader; +NXDT_ASSERT(NpdmAciHeader, 0x40); + typedef enum { NpdmFsAccessControlFlags_ApplicationInfo = BIT_LONG(0), NpdmFsAccessControlFlags_BootModeControl = BIT_LONG(1), @@ -190,6 +200,8 @@ typedef struct { } NpdmFsAccessControlDescriptor; #pragma pack(pop) +NXDT_ASSERT(NpdmFsAccessControlDescriptor, 0x2C); + /// FsAccessControl data. Part of the ACI0 section body. /// This is followed by: /// * A NpdmFsAccessControlDataContentOwnerBlock if 'content_owner_info_size' is greater than zero. @@ -207,11 +219,17 @@ typedef struct { } NpdmFsAccessControlData; #pragma pack(pop) +NXDT_ASSERT(NpdmFsAccessControlData, 0x1C); + /// Placed after NpdmFsAccessControlData if its 'content_owner_info_size' member is greater than zero. +#pragma pack(push, 1) typedef struct { u32 content_owner_id_count; u64 content_owner_id[]; ///< 'content_owner_id_count' content owned IDs. } NpdmFsAccessControlDataContentOwnerBlock; +#pragma pack(pop) + +NXDT_ASSERT(NpdmFsAccessControlDataContentOwnerBlock, 0x4); typedef enum { NpdmAccessibility_Read = BIT(0), @@ -225,6 +243,8 @@ typedef struct { u8 accessibility[]; ///< 'save_data_owner_id_count' NpdmAccessibility fields. } NpdmFsAccessControlDataSaveDataOwnerBlock; +NXDT_ASSERT(NpdmFsAccessControlDataSaveDataOwnerBlock, 0x4); + /// SrvAccessControl descriptor. Part of the ACID and ACI0 section bodies. /// This descriptor is composed of a variable number of NpdmSrvAccessControlDescriptorEntry elements, each one with a variable size. /// Since the total number of services isn't stored anywhere, this descriptor must be parsed until its total size is reached. @@ -235,6 +255,8 @@ typedef struct { char name[]; ///< Service name, stored without a NULL terminator. Supports the "*" wildcard character. } NpdmSrvAccessControlDescriptorEntry; +NXDT_ASSERT(NpdmSrvAccessControlDescriptorEntry, 0x1); + typedef enum { NpdmKernelCapabilityEntryNumber_ThreadInfo = 3, NpdmKernelCapabilityEntryNumber_EnableSystemCalls = 4, @@ -271,6 +293,8 @@ typedef struct { u32 max_core_number : 8; } NpdmThreadInfo; +NXDT_ASSERT(NpdmThreadInfo, 0x4); + /// System call table. typedef enum { ///< System calls for index 0. @@ -423,6 +447,8 @@ typedef struct { u32 index : 3; ///< System calls index. } NpdmEnableSystemCalls; +NXDT_ASSERT(NpdmEnableSystemCalls, 0x4); + typedef enum { NpdmPermissionType_RW = 0, NpdmPermissionType_RO = 1 @@ -440,6 +466,8 @@ typedef struct { u32 permission_type : 1; ///< NpdmPermissionType. } NpdmMemoryMapType1; +NXDT_ASSERT(NpdmMemoryMapType1, 0x4); + typedef struct { u32 entry_value : NpdmKernelCapabilityEntryNumber_MemoryMap; ///< Always set to NpdmKernelCapabilityEntryValue_MemoryMap. u32 padding : 1; ///< Always set to zero. @@ -448,6 +476,8 @@ typedef struct { u32 mapping_type : 1; ///< NpdmMappingType. } NpdmMemoryMapType2; +NXDT_ASSERT(NpdmMemoryMapType2, 0x4); + /// MemoryMap entry for the KernelCapability descriptor. /// These are always stored in pairs of MemoryMapType1 + MemoryMapType2 entries. typedef struct { @@ -457,6 +487,8 @@ typedef struct { }; } NpdmMemoryMap; +NXDT_ASSERT(NpdmMemoryMap, 0x4); + /// IoMemoryMap entry for the KernelCapability descriptor. typedef struct { u32 entry_value : NpdmKernelCapabilityEntryNumber_IoMemoryMap; ///< Always set to NpdmKernelCapabilityEntryValue_IoMemoryMap. @@ -464,6 +496,8 @@ typedef struct { u32 begin_address : 24; ///< begin_address << 12. } NpdmIoMemoryMap; +NXDT_ASSERT(NpdmIoMemoryMap, 0x4); + typedef enum { NpdmRegionType_NoMapping = 0, NpdmRegionType_KernelTraceBuffer = 1, @@ -483,6 +517,8 @@ typedef struct { u32 permission_type_3 : 1; ///< NpdmPermissionType. } NpdmMemoryRegionMap; +NXDT_ASSERT(NpdmMemoryRegionMap, 0x4); + /// EnableInterrupts entry for the KernelCapability descriptor. typedef struct { u32 entry_value : NpdmKernelCapabilityEntryNumber_EnableInterrupts; ///< Always set to NpdmKernelCapabilityEntryValue_EnableInterrupts. @@ -491,6 +527,8 @@ typedef struct { u32 interrupt_number_2 : 10; ///< 0x3FF means empty. } NpdmEnableInterrupts; +NXDT_ASSERT(NpdmEnableInterrupts, 0x4); + typedef enum { NpdmProgramType_System = 0, NpdmProgramType_Application = 1, @@ -506,6 +544,8 @@ typedef struct { u32 reserved : 15; } NpdmMiscParams; +NXDT_ASSERT(NpdmMiscParams, 0x4); + /// KernelVersion entry for the KernelCapability descriptor. typedef struct { u32 entry_value : NpdmKernelCapabilityEntryNumber_KernelVersion; ///< Always set to NpdmKernelCapabilityEntryValue_KernelVersion. @@ -514,6 +554,8 @@ typedef struct { u32 major_version : 13; } NpdmKernelVersion; +NXDT_ASSERT(NpdmKernelVersion, 0x4); + /// HandleTableSize entry for the KernelCapability descriptor. typedef struct { u32 entry_value : NpdmKernelCapabilityEntryNumber_HandleTableSize; ///< Always set to NpdmKernelCapabilityEntryValue_HandleTableSize. @@ -522,6 +564,8 @@ typedef struct { u32 reserved : 6; } NpdmHandleTableSize; +NXDT_ASSERT(NpdmHandleTableSize, 0x4); + /// MiscFlags entry for the KernelCapability descriptor. typedef struct { u32 entry_value : NpdmKernelCapabilityEntryNumber_MiscFlags; ///< Always set to NpdmKernelCapabilityEntryValue_MiscFlags. @@ -531,6 +575,8 @@ typedef struct { u32 reserved : 13; } NpdmMiscFlags; +NXDT_ASSERT(NpdmMiscFlags, 0x4); + /// KernelCapability descriptor. Part of the ACID and ACI0 section bodies. /// This descriptor is composed of a variable number of u32 entries. Thus, the entry count can be calculated by dividing the KernelCapability descriptor size by 4. /// The entry type is identified by a pattern of "01...11" (zero followed by ones) in the low u16, counting from the LSB. The variable number of ones must never exceed 16 (entirety of the low u16). @@ -538,6 +584,8 @@ typedef struct { u32 value; } NpdmKernelCapabilityDescriptorEntry; +NXDT_ASSERT(NpdmKernelCapabilityDescriptorEntry, 0x4); + typedef struct { NcaContext *nca_ctx; ///< Pointer to the NCA context for the Program NCA from which NPDM data is retrieved. PartitionFileSystemContext *pfs_ctx; ///< PartitionFileSystemContext for the Program NCA FS section #0, which is where the NPDM is stored. @@ -592,8 +640,8 @@ NX_INLINE u32 npdmGetKernelCapabilityDescriptorEntryValue(NpdmKernelCapabilityDe return (entry ? (((entry->value + 1) & ~entry->value) - 1) : 0); } -#endif /* __NPDM_H__ */ - #ifdef __cplusplus } -#endif \ No newline at end of file +#endif + +#endif /* __NPDM_H__ */ diff --git a/source/nso.h b/source/nso.h index 8708add..ac8f4fe 100644 --- a/source/nso.h +++ b/source/nso.h @@ -20,15 +20,15 @@ #pragma once -#ifdef __cplusplus -extern "C" { -#endif - #ifndef __NSO_H__ #define __NSO_H__ #include "pfs.h" +#ifdef __cplusplus +extern "C" { +#endif + #define NSO_HEADER_MAGIC 0x4E534F30 /* "NSO0". */ #define NSO_MOD_MAGIC 0x4D4F4430 /* "MOD0". */ @@ -47,11 +47,15 @@ typedef struct { u32 size; ///< Decompressed segment size. } NsoSegmentInfo; +NXDT_ASSERT(NsoSegmentInfo, 0xC); + typedef struct { u32 offset; ///< Relative to the .rodata segment start. u32 size; } NsoSectionInfo; +NXDT_ASSERT(NsoSectionInfo, 0x8); + /// This is the start of every NSO. /// This is always followed by a NsoModuleName block. typedef struct { @@ -73,11 +77,13 @@ typedef struct { NsoSectionInfo api_info_section_info; NsoSectionInfo dynstr_section_info; NsoSectionInfo dynsym_section_info; - u8 text_segment_hash[0x20]; ///< Decompressed .text segment SHA-256 checksum. - u8 rodata_segment_hash[0x20]; ///< Decompressed .rodata segment SHA-256 checksum. - u8 data_segment_hash[0x20]; ///< Decompressed .data segment SHA-256 checksum. + u8 text_segment_hash[SHA256_HASH_SIZE]; ///< Decompressed .text segment SHA-256 checksum. + u8 rodata_segment_hash[SHA256_HASH_SIZE]; ///< Decompressed .rodata segment SHA-256 checksum. + u8 data_segment_hash[SHA256_HASH_SIZE]; ///< Decompressed .data segment SHA-256 checksum. } NsoHeader; +NXDT_ASSERT(NsoHeader, 0x100); + /// Usually placed right after NsoHeader, but it's actual offset may vary. /// If the 'module_name_size' member from NsoHeader is greater than 1 and the 'name_length' element from NsoModuleName is greater than 0, 'name' will hold the module name. typedef struct { @@ -85,12 +91,16 @@ typedef struct { char name[]; } NsoModuleName; +NXDT_ASSERT(NsoModuleName, 0x1); + /// Placed at the very start of the decompressed .text segment. typedef struct { u32 entry_point; u32 mod_offset; ///< NsoModHeader block offset (relative to the start of this header). Almost always set to 0x8 (the size of this struct). } NsoModStart; +NXDT_ASSERT(NsoModStart, 0x8); + /// This is essentially a replacement for the PT_DYNAMIC program header available in ELF binaries. /// All offsets are signed 32-bit values relative to the start of this header. /// This is usually placed at the start of the decompressed .text segment, right after a NsoModStart block. @@ -106,6 +116,8 @@ typedef struct { s32 module_object_offset; ///< Typically equal to bss_start_offset. } NsoModHeader; +NXDT_ASSERT(NsoModHeader, 0x1C); + /// Placed at the start of the decompressed .rodata segment + 0x4. /// If the 'name_length' element is greater than 0, 'name' will hold the module name. typedef struct { @@ -113,6 +125,8 @@ typedef struct { char name[]; } NsoModuleInfo; +NXDT_ASSERT(NsoModuleInfo, 0x4); + typedef struct { PartitionFileSystemContext *pfs_ctx; ///< PartitionFileSystemContext for the Program NCA FS section #0, which is where this NSO is stored. PartitionFileSystemEntry *pfs_entry; ///< PartitionFileSystemEntry for this NSO in the Program NCA FS section #0. Used to read NSO data. @@ -145,8 +159,8 @@ NX_INLINE void nsoFreeContext(NsoContext *nso_ctx) memset(nso_ctx, 0, sizeof(NsoContext)); } -#endif /* __NSO_H__ */ - #ifdef __cplusplus } -#endif \ No newline at end of file +#endif + +#endif /* __NSO_H__ */ diff --git a/source/pfs.h b/source/pfs.h index c8acb8c..6c5d60c 100644 --- a/source/pfs.h +++ b/source/pfs.h @@ -20,15 +20,15 @@ #pragma once -#ifdef __cplusplus -extern "C" { -#endif - #ifndef __PFS_H__ #define __PFS_H__ #include "nca.h" +#ifdef __cplusplus +extern "C" { +#endif + #define PFS0_MAGIC 0x50465330 /* "PFS0". */ typedef struct { @@ -38,6 +38,8 @@ typedef struct { u8 reserved[0x4]; } PartitionFileSystemHeader; +NXDT_ASSERT(PartitionFileSystemHeader, 0x10); + typedef struct { u64 offset; u64 size; @@ -45,6 +47,8 @@ typedef struct { u8 reserved[0x4]; } PartitionFileSystemEntry; +NXDT_ASSERT(PartitionFileSystemEntry, 0x18); + /// Used with Partition FS sections from NCAs. typedef struct { NcaFsSectionContext *nca_fs_ctx; ///< Used to read NCA FS section data. @@ -190,8 +194,8 @@ NX_INLINE char *pfsGetEntryNameByIndexFromFileContext(PartitionFileSystemFileCon return (ctx->name_table + fs_entry->name_offset); } -#endif /* __PFS_H__ */ - #ifdef __cplusplus } -#endif \ No newline at end of file +#endif + +#endif /* __PFS_H__ */ diff --git a/source/program_info.h b/source/program_info.h index 9d64c78..3e43017 100644 --- a/source/program_info.h +++ b/source/program_info.h @@ -20,16 +20,16 @@ #pragma once -#ifdef __cplusplus -extern "C" { -#endif - #ifndef __PROGRAM_INFO_H__ #define __PROGRAM_INFO_H__ #include "npdm.h" #include "nso.h" +#ifdef __cplusplus +extern "C" { +#endif + typedef struct { NcaContext *nca_ctx; ///< Pointer to the NCA context for the Program NCA from which program data (NPDM / NSO) is retrieved. PartitionFileSystemContext pfs_ctx; ///< PartitionFileSystemContext for the Program NCA ExeFS, which is where program data (NPDM / NSO) is stored. @@ -84,8 +84,8 @@ NX_INLINE void programInfoWriteNcaPatch(ProgramInfoContext *program_info_ctx, vo if (program_info_ctx) npdmWriteNcaPatch(&(program_info_ctx->npdm_ctx), buf, buf_size, buf_offset); } -#endif /* __PROGRAM_INFO_H__ */ - #ifdef __cplusplus } -#endif \ No newline at end of file +#endif + +#endif /* __PROGRAM_INFO_H__ */ diff --git a/source/romfs.h b/source/romfs.h index 5d16540..9698e0f 100644 --- a/source/romfs.h +++ b/source/romfs.h @@ -20,15 +20,15 @@ #pragma once -#ifdef __cplusplus -extern "C" { -#endif - #ifndef __ROMFS_H__ #define __ROMFS_H__ #include "nca.h" +#ifdef __cplusplus +extern "C" { +#endif + #define ROMFS_OLD_HEADER_SIZE 0x28 #define ROMFS_HEADER_SIZE 0x50 @@ -48,6 +48,8 @@ typedef struct { u32 body_offset; ///< File data body offset. } RomFileSystemInformationOld; +NXDT_ASSERT(RomFileSystemInformationOld, ROMFS_OLD_HEADER_SIZE); + /// Header used by NCA2/NCA3 RomFS sections. typedef struct { u64 header_size; ///< Header size. Must be equal to ROMFS_HEADER_SIZE. @@ -62,6 +64,8 @@ typedef struct { u64 body_offset; ///< File data body offset. } RomFileSystemInformation; +NXDT_ASSERT(RomFileSystemInformation, ROMFS_HEADER_SIZE); + /// Header union. typedef struct { union { @@ -73,6 +77,8 @@ typedef struct { }; } RomFileSystemHeader; +NXDT_ASSERT(RomFileSystemHeader, ROMFS_HEADER_SIZE); + /// Directory entry. Always aligned to a 4-byte boundary past the directory name. typedef struct { u32 parent_offset; ///< Parent directory offset. @@ -84,6 +90,8 @@ typedef struct { char name[]; ///< Name (UTF-8). } RomFileSystemDirectoryEntry; +NXDT_ASSERT(RomFileSystemDirectoryEntry, 0x18); + /// Directory entry. Always aligned to a 4-byte boundary past the file name. typedef struct { u32 parent_offset; ///< Parent directory offset. @@ -95,6 +103,8 @@ typedef struct { char name[]; ///< Name (UTF-8). } RomFileSystemFileEntry; +NXDT_ASSERT(RomFileSystemFileEntry, 0x20); + typedef struct { NcaFsSectionContext *nca_fs_ctx; ///< Used to read NCA FS section data. u64 offset; ///< RomFS offset (relative to the start of the NCA FS section). @@ -203,8 +213,8 @@ NX_INLINE void romfsFreeFileEntryPatch(RomFileSystemFileEntryPatch *patch) memset(patch, 0, sizeof(RomFileSystemFileEntryPatch)); } -#endif /* __ROMFS_H__ */ - #ifdef __cplusplus } -#endif \ No newline at end of file +#endif + +#endif /* __ROMFS_H__ */ diff --git a/source/rsa.h b/source/rsa.h index 4017754..1f33b1c 100644 --- a/source/rsa.h +++ b/source/rsa.h @@ -22,13 +22,13 @@ #pragma once +#ifndef __RSA_H__ +#define __RSA_H__ + #ifdef __cplusplus extern "C" { #endif -#ifndef __RSA_H__ -#define __RSA_H__ - #define RSA2048_SIG_SIZE 0x100 #define RSA2048_PUBKEY_SIZE RSA2048_SIG_SIZE @@ -44,8 +44,8 @@ const u8 *rsa2048GetCustomPublicKey(void); /// Performs RSA-2048-OAEP decryption and verification. Used to decrypt the titlekey block from tickets with personalized crypto. bool rsa2048OaepDecryptAndVerify(void *dst, size_t dst_size, const void *signature, const void *modulus, const void *exponent, size_t exponent_size, const void *label_hash, size_t *out_size); -#endif /* __RSA_H__ */ - #ifdef __cplusplus } -#endif \ No newline at end of file +#endif + +#endif /* __RSA_H__ */ diff --git a/source/save.h b/source/save.h index c921bd6..8ecc1cc 100644 --- a/source/save.h +++ b/source/save.h @@ -21,15 +21,15 @@ #pragma once -#ifdef __cplusplus -extern "C" { -#endif - #ifndef __SAVE_H__ #define __SAVE_H__ #include "fatfs/ff.h" +#ifdef __cplusplus +extern "C" { +#endif + #define IVFC_MAX_LEVEL 6 #define SAVE_HEADER_SIZE 0x4000 @@ -106,6 +106,8 @@ typedef struct { u8 _0x190[0x70]; } fs_layout_t; +NXDT_ASSERT(fs_layout_t, 0x200); + #pragma pack(push, 1) typedef struct { u64 offset; @@ -114,12 +116,16 @@ typedef struct { } duplex_info_t; #pragma pack(pop) +NXDT_ASSERT(duplex_info_t, 0x14); + typedef struct { u32 magic; /* "DPFS". */ u32 version; duplex_info_t layers[3]; } duplex_header_t; +NXDT_ASSERT(duplex_header_t, 0x44); + typedef struct { u32 version; u32 main_data_block_count; @@ -127,6 +133,8 @@ typedef struct { u32 _0x0C; } journal_map_header_t; +NXDT_ASSERT(journal_map_header_t, 0x10); + typedef struct { u32 magic; /* "JNGL". */ u32 version; @@ -135,6 +143,8 @@ typedef struct { u64 block_size; } journal_header_t; +NXDT_ASSERT(journal_header_t, 0x20); + typedef struct { u32 magic; /* "SAVE". */ u32 version; @@ -142,6 +152,8 @@ typedef struct { u64 block_size; } save_fs_header_t; +NXDT_ASSERT(save_fs_header_t, 0x18); + typedef struct { u64 block_size; u64 allocation_table_offset; @@ -154,6 +166,8 @@ typedef struct { u32 file_table_block; } fat_header_t; +NXDT_ASSERT(fat_header_t, 0x30); + typedef struct { u32 magic; /* "RMAP". */ u32 version; @@ -163,6 +177,8 @@ typedef struct { u8 _0x14[0x2C]; } remap_header_t; +NXDT_ASSERT(remap_header_t, 0x40); + typedef struct remap_segment_ctx_t remap_segment_ctx_t; typedef struct remap_entry_ctx_t remap_entry_ctx_t; @@ -232,6 +248,8 @@ typedef struct { u64 commit_id; } extra_data_t; +NXDT_ASSERT(extra_data_t, 0x70); + typedef struct { u64 logical_offset; u64 hash_data_size; @@ -239,6 +257,8 @@ typedef struct { u32 reserved; } ivfc_level_hdr_t; +NXDT_ASSERT(ivfc_level_hdr_t, 0x18); + typedef struct { u32 magic; u32 id; @@ -248,6 +268,8 @@ typedef struct { u8 salt_source[0x20]; } ivfc_save_hdr_t; +NXDT_ASSERT(ivfc_save_hdr_t, 0xC0); + #pragma pack(push, 1) typedef struct { u8 cmac[0x10]; @@ -270,6 +292,8 @@ typedef struct { } save_header_t; #pragma pack(pop) +NXDT_ASSERT(save_header_t, 0x4000); + typedef struct { duplex_storage_ctx_t layers[2]; duplex_storage_ctx_t data_layer; @@ -294,6 +318,8 @@ typedef struct { u32 virtual_index; } journal_map_entry_t; +NXDT_ASSERT(journal_map_entry_t, 0x8); + typedef struct { journal_map_header_t *header; journal_map_entry_t *entries; @@ -387,6 +413,8 @@ typedef struct { } save_file_info_t; #pragma pack(pop) +NXDT_ASSERT(save_file_info_t, 0x14); + #pragma pack(push, 1) typedef struct { u32 next_directory; @@ -395,6 +423,8 @@ typedef struct { } save_find_position_t; #pragma pack(pop) +NXDT_ASSERT(save_find_position_t, 0x14); + #pragma pack(push, 1) typedef struct { u32 next_sibling; @@ -405,6 +435,8 @@ typedef struct { } save_table_entry_t; #pragma pack(pop) +NXDT_ASSERT(save_table_entry_t, 0x18); + #pragma pack(push, 1) typedef struct { u32 parent; @@ -414,6 +446,8 @@ typedef struct { } save_fs_list_entry_t; #pragma pack(pop) +NXDT_ASSERT(save_fs_list_entry_t, 0x60); + typedef struct { u32 free_list_head_index; u32 used_list_head_index; @@ -517,8 +551,8 @@ save_ctx_t *save_open_savefile(const char *path, u32 action); void save_close_savefile(save_ctx_t *ctx); bool save_get_fat_storage_from_file_entry_by_path(save_ctx_t *ctx, const char *path, allocation_table_storage_ctx_t *out_fat_storage, u64 *out_file_entry_size); -#endif /* __SAVE_H__ */ - #ifdef __cplusplus } -#endif \ No newline at end of file +#endif + +#endif /* __SAVE_H__ */ diff --git a/source/services.h b/source/services.h index 281406e..4a9c3c9 100644 --- a/source/services.h +++ b/source/services.h @@ -20,13 +20,13 @@ #pragma once +#ifndef __SERVICES_H__ +#define __SERVICES_H__ + #ifdef __cplusplus extern "C" { #endif -#ifndef __SERVICES_H__ -#define __SERVICES_H__ - /* Hardware clocks expressed in MHz. */ #define CPU_CLKRT_NORMAL 1020 #define CPU_CLKRT_OVERCLOCKED 1785 @@ -53,8 +53,8 @@ void servicesChangeHardwareClockRates(u32 cpu_rate, u32 mem_rate); /// Perfectly safe under development units. Not available in older Atmosphère releases. Result servicesHasService(bool *out, const char *name); -#endif /* __SERVICES_H__ */ - #ifdef __cplusplus } -#endif \ No newline at end of file +#endif + +#endif /* __SERVICES_H__ */ diff --git a/source/signature.h b/source/signature.h index 06214ab..609a6a9 100644 --- a/source/signature.h +++ b/source/signature.h @@ -23,6 +23,10 @@ #ifndef __SIGNATURE_H__ #define __SIGNATURE_H__ +#ifdef __cplusplus +extern "C" { +#endif + typedef enum { SignatureType_Rsa4096Sha1 = 0x10000, SignatureType_Rsa2048Sha1 = 0x10001, @@ -39,24 +43,32 @@ typedef struct { u8 padding[0x3C]; } SignatureBlockRsa4096; +NXDT_ASSERT(SignatureBlockRsa4096, 0x240); + typedef struct { u32 sig_type; ///< SignatureType_Rsa2048Sha1, SignatureType_Rsa2048Sha256. u8 signature[0x100]; u8 padding[0x3C]; } SignatureBlockRsa2048; +NXDT_ASSERT(SignatureBlockRsa2048, 0x140); + typedef struct { u32 sig_type; ///< SignatureType_Ecc480Sha1, SignatureType_Ecc480Sha256. u8 signature[0x3C]; u8 padding[0x40]; } SignatureBlockEcc480; +NXDT_ASSERT(SignatureBlockEcc480, 0x80); + typedef struct { u32 sig_type; ///< SignatureType_Hmac160Sha1. u8 signature[0x14]; u8 padding[0x28]; } SignatureBlockHmac160; +NXDT_ASSERT(SignatureBlockHmac160, 0x40); + /// Helper inline functions. NX_INLINE u32 signatureGetSigType(void *buf, bool byteswap) @@ -100,4 +112,8 @@ NX_INLINE void *signatureGetPayload(void *buf, bool big_endian_sig_type) return (signatureIsValidSigType(sig_type) ? (void*)((u8*)buf + signatureGetBlockSize(sig_type)) : NULL); } +#ifdef __cplusplus +} +#endif + #endif /* __SIGNATURE_H__ */ diff --git a/source/tik.c b/source/tik.c index 1ebd9a6..d442366 100644 --- a/source/tik.c +++ b/source/tik.c @@ -50,6 +50,8 @@ typedef struct { u8 reserved[0x04]; } TikListEntry; +NXDT_ASSERT(TikListEntry, 0x20); + /// 9.x+ CTR key entry in ES .data segment. Used to store CTR key/IV data for encrypted volatile tickets in ticket.bin and/or encrypted entries in ticket_list.bin. /// This is always stored in pairs. The first entry holds the key/IV for the encrypted volatile ticket, while the second entry holds the key/IV for the encrypted entry in ticket_list.bin. /// First index in this list is always 0, and it's aligned to ES_CTRKEY_ENTRY_ALIGNMENT. @@ -59,6 +61,8 @@ typedef struct { u8 ctr[AES_BLOCK_SIZE]; ///< AES-128-CTR counter/IV. Always zeroed out. } TikEsCtrKeyEntry9x; +NXDT_ASSERT(TikEsCtrKeyEntry9x, 0x24); + /// Lookup pattern for TikEsCtrKeyEntry9x. typedef struct { u32 idx1; ///< Always set to 0 (first entry). @@ -66,6 +70,8 @@ typedef struct { u32 idx2; ///< Always set to 1 (second entry). } TikEsCtrKeyPattern9x; +NXDT_ASSERT(TikEsCtrKeyPattern9x, 0x28); + /// Used to parse the eTicket device key retrieved from PRODINFO via setcalGetEticketDeviceKey(). /// Everything after the AES CTR is encrypted. typedef struct { @@ -78,6 +84,8 @@ typedef struct { u8 ghash[0x10]; } TikEticketDeviceKeyData; +NXDT_ASSERT(TikEticketDeviceKeyData, 0x240); + /* Global variables. */ static SetCalRsa2048DeviceKey g_eTicketDeviceKey = {0}; @@ -380,7 +388,7 @@ static bool tikGetTitleKekEncryptedTitleKeyFromTicket(Ticket *tik) switch(tik_common_block->titlekey_type) { case TikTitleKeyType_Common: - /* No titlekek crypto used. */ + /* No console-specific crypto used. Copy titlekek-encrypted titlekey right away. */ memcpy(tik->enc_titlekey, tik_common_block->titlekey_block, 0x10); break; case TikTitleKeyType_Personalized: @@ -393,7 +401,7 @@ static bool tikGetTitleKekEncryptedTitleKeyFromTicket(Ticket *tik) eticket_devkey = (TikEticketDeviceKeyData*)g_eTicketDeviceKey.key; - /* Perform a RSA-OAEP decrypt operation to get the titlekey. */ + /* Perform a RSA-OAEP decrypt operation to get the titlekek-encrypted titlekey. */ if (!rsa2048OaepDecryptAndVerify(out_keydata, 0x100, tik_common_block->titlekey_block, eticket_devkey->modulus, eticket_devkey->exponent, 0x100, g_nullHash, &out_keydata_size) || \ out_keydata_size < 0x10) { @@ -401,7 +409,7 @@ static bool tikGetTitleKekEncryptedTitleKeyFromTicket(Ticket *tik) return false; } - /* Copy decrypted titlekey. */ + /* Copy titlekek-encrypted titlekey. */ memcpy(tik->enc_titlekey, out_keydata, 0x10); break; @@ -589,7 +597,7 @@ static bool tikGetTicketEntryOffsetFromTicketList(save_ctx_t *save_ctx, u8 *buf, if (!memcmp(entry->rights_id.c, id->c, sizeof(id->c))) { /* Jackpot. */ - *out_offset = (entry_offset << 5); /* (entry_offset / 0x20) * 0x400 */ + *out_offset = (entry_offset << 5); /* (entry_offset / sizeof(TikListEntry)) * SIGNED_TIK_MAX_SIZE */ success = true; break; } diff --git a/source/tik.h b/source/tik.h index d211991..d4c8aff 100644 --- a/source/tik.h +++ b/source/tik.h @@ -20,25 +20,27 @@ #pragma once -#ifdef __cplusplus -extern "C" { -#endif - #ifndef __TIK_H__ #define __TIK_H__ #include "signature.h" +#ifdef __cplusplus +extern "C" { +#endif + #define SIGNED_TIK_MAX_SIZE 0x400 /* Max ticket entry size in the ES ticket system savedata file. */ #define SIGNED_TIK_MIN_SIZE sizeof(TikSigHmac160) /* Assuming no ESV1/ESV2 records are available. */ -typedef enum { - TikType_None = 0, - TikType_SigRsa4096 = 1, - TikType_SigRsa2048 = 2, - TikType_SigEcc480 = 3, - TikType_SigHmac160 = 4 -} TikType; +#define GENERATE_TIK_STRUCT(sigtype, tiksize) \ +\ +typedef struct { \ + SignatureBlock##sigtype sig_block; \ + TikCommonBlock tik_common_block; \ + u8 es_section_record_data[]; \ +} TikSig##sigtype; \ +\ +NXDT_ASSERT(TikSig##sigtype, tiksize); typedef enum { TikTitleKeyType_Common = 0, @@ -84,25 +86,7 @@ typedef struct { u16 sect_hdr_entry_size; } TikCommonBlock; -typedef struct { - SignatureBlockRsa4096 sig_block; ///< sig_type field is stored using little endian byte order. - TikCommonBlock tik_common_block; -} TikSigRsa4096; - -typedef struct { - SignatureBlockRsa2048 sig_block; ///< sig_type field is stored using little endian byte order. - TikCommonBlock tik_common_block; -} TikSigRsa2048; - -typedef struct { - SignatureBlockEcc480 sig_block; ///< sig_type field is stored using little endian byte order. - TikCommonBlock tik_common_block; -} TikSigEcc480; - -typedef struct { - SignatureBlockHmac160 sig_block; ///< sig_type field is stored using little endian byte order. - TikCommonBlock tik_common_block; -} TikSigHmac160; +NXDT_ASSERT(TikCommonBlock, 0x180); /// ESV1/ESV2 section records are placed right after the ticket data. These aren't available in TikTitleKeyType_Common tickets. /// These are only used if the sect_* fields from the common block are non-zero (other than 'sect_hdr_offset'). @@ -164,6 +148,21 @@ typedef struct { u32 ref_id_attr; } TikESV1LimitedResourceRecord; +/// All tickets generated below use a little endian sig_type field. +GENERATE_TIK_STRUCT(Rsa4096, 0x3C0); /// RSA-4096 signature. +GENERATE_TIK_STRUCT(Rsa2048, 0x2C0); /// RSA-2048 signature. +GENERATE_TIK_STRUCT(Ecc480, 0x200); /// ECC signature. +GENERATE_TIK_STRUCT(Hmac160, 0x1C0); /// HMAC signature. + +/// Ticket type. +typedef enum { + TikType_None = 0, + TikType_SigRsa4096 = 1, + TikType_SigRsa2048 = 2, + TikType_SigEcc480 = 3, + TikType_SigHmac160 = 4 +} TikType; + /// Used to store ticket type, size and raw data, as well as titlekey data. typedef struct { u8 type; ///< TikType. @@ -228,8 +227,8 @@ NX_INLINE bool tikIsPersonalizedTicket(Ticket *tik) return (tik_common_block != NULL && tik_common_block->titlekey_type == TikTitleKeyType_Personalized); } -#endif /* __TIK_H__ */ - #ifdef __cplusplus } -#endif \ No newline at end of file +#endif + +#endif /* __TIK_H__ */ diff --git a/source/title.h b/source/title.h index 5952517..2fff565 100644 --- a/source/title.h +++ b/source/title.h @@ -20,13 +20,13 @@ #pragma once +#ifndef __TITLE_H__ +#define __TITLE_H__ + #ifdef __cplusplus extern "C" { #endif -#ifndef __TITLE_H__ -#define __TITLE_H__ - #define TITLE_PATCH_TYPE_VALUE (u64)0x800 #define TITLE_ADDONCONTENT_TYPE_VALUE (u64)0x1000 @@ -268,8 +268,8 @@ NX_INLINE u32 titleGetCountFromInfoBlock(TitleInfo *title_info) return count; } -#endif /* __TITLE_H__ */ - #ifdef __cplusplus } -#endif \ No newline at end of file +#endif + +#endif /* __TITLE_H__ */ diff --git a/source/ums.h b/source/ums.h index aae933f..f3177cf 100644 --- a/source/ums.h +++ b/source/ums.h @@ -20,15 +20,15 @@ #pragma once -#ifdef __cplusplus -extern "C" { -#endif - #ifndef __UMS_H__ #define __UMS_H__ #include +#ifdef __cplusplus +extern "C" { +#endif + /// Initializes the USB Mass Storage interface. bool umsInitialize(void); @@ -42,8 +42,8 @@ bool umsIsDeviceInfoUpdated(void); /// Returns NULL if an error occurs. UsbHsFsDevice *umsGetDevices(u32 *out_count); -#endif /* __UMS_H__ */ - #ifdef __cplusplus } -#endif \ No newline at end of file +#endif + +#endif /* __UMS_H__ */ diff --git a/source/usb.c b/source/usb.c index 0cfc973..b26f145 100644 --- a/source/usb.c +++ b/source/usb.c @@ -75,6 +75,8 @@ typedef struct { u8 reserved[0x4]; } UsbCommandHeader; +NXDT_ASSERT(UsbCommandHeader, 0x10); + typedef struct { u8 app_ver_major; u8 app_ver_minor; @@ -84,6 +86,8 @@ typedef struct { u8 reserved[0x4]; } UsbCommandStartSession; +NXDT_ASSERT(UsbCommandStartSession, 0x10); + typedef struct { u64 file_size; u32 filename_length; @@ -92,6 +96,8 @@ typedef struct { u8 reserved_2[0xF]; } UsbCommandSendFileProperties; +NXDT_ASSERT(UsbCommandSendFileProperties, 0x320); + typedef enum { ///< Expected response code. UsbStatusType_Success = 0, @@ -116,6 +122,8 @@ typedef struct { u8 reserved[0x6]; } UsbStatus; +NXDT_ASSERT(UsbStatus, 0x10); + /// Imported from libusb, with some adjustments. enum usb_bos_type { USB_BT_WIRELESS_USB_DEVICE_CAPABILITY = 1, @@ -150,6 +158,8 @@ struct usb_bos_descriptor { u8 bNumDeviceCaps; ///< The number of separate device capability descriptors in the BOS. } PACKED; +NXDT_ASSERT(struct usb_bos_descriptor, 0x5); + /// Imported from libusb, with some adjustments. struct usb_2_0_extension_descriptor { u8 bLength; @@ -158,6 +168,8 @@ struct usb_2_0_extension_descriptor { u32 bmAttributes; ///< usb_2_0_extension_attributes. } PACKED; +NXDT_ASSERT(struct usb_2_0_extension_descriptor, 0x7); + /// Imported from libusb, with some adjustments. struct usb_ss_usb_device_capability_descriptor { u8 bLength; @@ -170,6 +182,8 @@ struct usb_ss_usb_device_capability_descriptor { u16 bU2DevExitLat; ///< U2 Device Exit Latency. } PACKED; +NXDT_ASSERT(struct usb_ss_usb_device_capability_descriptor, 0xA); + /* Global variables. */ static RwLock g_usbDeviceLock = {0}; diff --git a/source/usb.h b/source/usb.h index 05d3957..283911c 100644 --- a/source/usb.h +++ b/source/usb.h @@ -23,13 +23,13 @@ #pragma once +#ifndef __USB_H__ +#define __USB_H__ + #ifdef __cplusplus extern "C" { #endif -#ifndef __USB_H__ -#define __USB_H__ - #define USB_TRANSFER_BUFFER_SIZE 0x800000 /* 8 MiB. */ /// Initializes the USB interface, input and output endpoints and allocates an internal transfer buffer. @@ -73,8 +73,8 @@ NX_INLINE bool usbSendFilePropertiesCommon(u64 file_size, const char *filename) return usbSendFileProperties(file_size, filename, 0); } -#endif /* __USB_H__ */ - #ifdef __cplusplus } -#endif \ No newline at end of file +#endif + +#endif /* __USB_H__ */ diff --git a/source/utils.h b/source/utils.h index 1c9d63c..8669f50 100644 --- a/source/utils.h +++ b/source/utils.h @@ -145,4 +145,4 @@ NX_INLINE void utilsSleep(u64 seconds) } #endif -#endif /* __UTILS_H__ */ \ No newline at end of file +#endif /* __UTILS_H__ */