Difference between revisions of "Title metadata"

(note discrepancy in endianness)
 
(30 intermediate revisions by 9 users not shown)
Line 1: Line 1:
'''Title metadata''' is a format used to store information about a title (a single standalone game, channel, etc.) and all its installed contents, including which contents they consist of and their SHA1 hashes.
+
[[Category:File formats]]
 +
'''Title metadata''' is a format used to store information about a title (installed title, DLC, etc.) and all its installed contents, including which contents they consist of and their SHA256 hashes.
  
[http://git.daifukkat.su/?p=3dshax.git Code is available] by trap15 to parse the available information from the 3DS format of TMDs.
+
[https://bitbucket.org/trap15/3dshax Code is available] by trap15 to parse the available information from the 3DS format of TMDs.
  
 
== Structure ==
 
== Structure ==
 +
 +
All the data in the file represented in Big Endian, unless otherwise noted.
 +
 +
{| class="wikitable"
 +
| align="center" style="background:#f0f0f0;"|'''Offset'''
 +
| align="center" style="background:#f0f0f0;"|'''Size'''
 +
| align="center" style="background:#f0f0f0;"|'''Description'''
 +
|-
 +
| 0x0||Y||Signature Data
 +
|-
 +
| Y ||0xC4||Header
 +
|-
 +
| 0xC4 + Y||0x24*64||Content Info Records.
 +
|-
 +
| 0x9C4 + Y||0x30*ContentCount||Content Chunk Records.
 +
|}
 +
 +
Y denotes the total size of the "Signature Data" section and depends on the signature type.
 +
 +
=== Signature Data ===
 +
The signature is of the header of the TMD.
 +
{| class="wikitable"
 +
| align="center" style="background:#f0f0f0;"|'''Offset'''
 +
| align="center" style="background:#f0f0f0;"|'''Size'''
 +
| align="center" style="background:#f0f0f0;"|'''Description'''
 +
|-
 +
| 0x0||0x4||Signature Type
 +
|-
 +
| 0x4 ||X||Signature
 +
|-
 +
| 0x4 + X|| ||Padding Aligning the signature data to 0x40 bytes
 +
|}
 +
 +
==== Signature Type ====
 +
{{Signature Types}}
 +
The hash for the signature, is calculated over the header of the TMD
 +
 
=== Header ===
 
=== Header ===
 +
 
{| class="wikitable"
 
{| class="wikitable"
| align="center" style="background:#f0f0f0;"|'''Start'''
+
| align="center" style="background:#f0f0f0;"|'''Offset'''
| align="center" style="background:#f0f0f0;"|''' '''
+
| align="center" style="background:#f0f0f0;"|'''Size'''
| align="center" style="background:#f0f0f0;"|'''Length'''
 
 
| align="center" style="background:#f0f0f0;"|'''Description'''
 
| align="center" style="background:#f0f0f0;"|'''Description'''
 
|-
 
|-
| ''RSA 2048''||''RSA 4096''||||
+
| 0x0||0x40||Signature Issuer
 +
|-
 +
| 0x40||0x1||Version
 
|-
 
|-
| 0x000||0x000||4||Signature type
+
| 0x41||0x1||ca_crl_version
 
|-
 
|-
| 0x004||0x004||256 / 512||Signature
+
| 0x42||0x1||signer_crl_version
 
|-
 
|-
| 0x104||0x204||60||Padding modulo 64
+
| 0x43||0x1||Reserved
 
|-
 
|-
| 0x140||0x240||64||Issuer
+
| 0x44||0x8||System Version
 
|-
 
|-
| 0x180||0x280||1||Version
+
| 0x4C||0x8||Title ID
 
|-
 
|-
| 0x181||0x281||1||ca_crl_version
+
| 0x54||0x4||Title Type
 
|-
 
|-
| 0x182||0x282||1||signer_crl_version
+
| 0x58||0x2||Group ID
 
|-
 
|-
| 0x183||0x283||1||Padding modulo 64
+
| 0x5A||0x4||Save Data Size in Little Endian (Bytes) (Also SRL Public Save Data Size)
 
|-
 
|-
| 0x184||0x284||8||System Version
+
| 0x5E||0x4||SRL Private Save Data Size in Little Endian (Bytes)
 
|-
 
|-
| 0x18C||0x28C||8||Title ID
+
| 0x62||0x4||Reserved
 
|-
 
|-
| 0x194||0x294||4||Title type
+
| 0x66||0x1||SRL Flag
 
|-
 
|-
| 0x198||0x298||2||Group ID
+
| 0x67||0x31||Reserved
 
|-
 
|-
| 0x19A||0x29A||62||reserved
+
| 0x98||0x4||Access Rights
 
|-
 
|-
| 0x1D8||0x2D8||4||Access rights
+
| 0x9C||0x2||Title Version
 
|-
 
|-
| 0x1DC||0x2DC||2||Title version
+
| 0x9E||0x02||Content Count
 
|-
 
|-
| 0x1DE||0x2DE||2||Number of contents
+
| 0xA0||0x2||Boot Content
 
|-
 
|-
| 0x1E0||0x2E0||64||Content Records
+
| 0xA2||0x2||Padding
 
|-
 
|-
| 0x220||0x320||40||Padding modulo 64
+
| 0xA4||0x20||SHA-256 Hash of the Content Info Records
 +
|}
 +
 
 +
=== Content Info Records ===
 +
 
 +
There are 64 of these records, usually only the first is used.
 +
 
 +
{| class="wikitable"
 
|-
 
|-
| 0x248||0x348||4||Boot content
+
! Offset
 +
! Size
 +
! Description
 
|-
 
|-
| 0x24C||0x34C||4||Banner content
+
| 0x00
 +
| 2
 +
| Content index offset
 
|-
 
|-
| 0x250||0x350||4||Banner size
+
| 0x02
 +
| 2
 +
| Content command count [k]
 
|-
 
|-
| 0x254||0x354||32||Hash
+
| 0x04
 +
| 0x20
 +
| SHA-256 hash of the next k content records that have not been hashed yet
 
|}
 
|}
  
=== Content Records ===
+
=== Content chunk records ===
 +
There is one of these for each content contained in this title. (Determined by "Content Count" in the TMD Header).
 +
 
 
{| class="wikitable"
 
{| class="wikitable"
 
|-
 
|-
! Start
+
! Offset
! Length
+
! Size
 
! Description
 
! Description
 
|-
 
|-
 
| 0x00
 
| 0x00
 
| 4
 
| 4
| Content ID
+
| Content id
 
|-
 
|-
 
| 0x04
 
| 0x04
| 32
+
| 2
| SHA-256 Hash
+
| Content index
 +
|-
 +
| 0x06
 +
| 2
 +
| Content type
 +
|-
 +
| 0x08
 +
| 8
 +
| Content size
 +
|-
 +
| 0x10
 +
| 0x20
 +
| SHA-256 hash
 +
|}
 +
==== Content Index ====
 +
 
 +
This indicates the content type:
 +
 
 +
{| class="wikitable" border="1"
 +
|-
 +
!  Index
 +
!  Content Type
 +
|-
 +
|  0000
 +
|  Main Content (.[[NCCH#CXI|CXI]] for 3DS executable content/.[[NCCH#CFA|CFA]] for 3DS Data Archives/.SRL for TWL content)
 +
|-
 +
|  0001
 +
|  Home Menu Manual (.[[NCCH#CFA|CFA]])
 +
|-
 +
|  0002
 +
|  DLP Child Container (.[[NCCH#CFA|CFA]])
 
|}
 
|}
  
=== Certificates ===
+
This does not apply to DLC.
 +
 
 +
==== Content Type flags ====
 
{| class="wikitable"
 
{| class="wikitable"
 
|-
 
|-
! Start
+
! Flags
! Length
 
 
! Description
 
! Description
 
|-
 
|-
| 0x000
+
| 1
 +
| Encrypted
 +
|-
 +
| 2
 +
| Disc
 +
|-
 
| 4
 
| 4
| Signature type
+
| CFM (abbreviation for?)
 
|-
 
|-
| 0x004
+
| 0x4000
| *
+
| Optional
| Signature
 
 
|-
 
|-
| 0x104
+
| 0x8000
| 64
+
| Shared
| Issuer
+
|}
 +
 
 +
== Certificate Chain ==
 +
If the TMD file is obtained from Nintendo's CDN, then it will have two [[Certificates|certificates]] appended at the end of the file:
 +
 
 +
{| class="wikitable" border="1"
 
|-
 
|-
| 0x124
+
!  CERTIFICATE
| 4
+
!  SIGNATURE TYPE
| Tag
+
!  RETAIL CERT NAME
 +
!  DEBUG CERT NAME
 +
!  DESCRIPTION
 
|-
 
|-
| 0x128
+
| TMD
| 64
+
| RSA-2048
| Name
+
| CP0000000b
 +
|  CP0000000a
 +
|  Used to verify the TMD signature
 
|-
 
|-
| 0x168
+
| CA
|  
+
| RSA-4096
| Key
+
| CA00000003
 +
|  CA00000004
 +
|  Used to verify the TMD Certificate
 
|}
 
|}
 +
 +
The CA certificate is issued by 'Root', the public key for which is stored in NATIVE_FIRM.
  
 
== Example code application ==
 
== Example code application ==
 
<source lang="c">
 
<source lang="c">
typedef struct {
 
        u32 cid;        // content id
 
        u8  hash[0x20];  // SHA-256 hash
 
} content_record;        // size: 0x24 bytes
 
 
 
  enum sig_type {
 
  enum sig_type {
 
         RSA_2048_SHA256 = 0x00010004,
 
         RSA_2048_SHA256 = 0x00010004,
Line 119: Line 219:
 
         RSA_4096_SHA1  = 0x00010000
 
         RSA_4096_SHA1  = 0x00010000
 
  };
 
  };
 
typedef struct {
 
        u32 sig_type;
 
        u8 sig[*];    // * Signature size
 
        u8 fill1[60];
 
        u8 issuer[64]; // Root-CA%08x-CP%08x
 
        u8 version;
 
        u8 ca_crl_version;
 
        u8 signer_crl_version;
 
        u8 fill2;
 
        u64 sys_version;
 
        u64 title_id;
 
        u32 title_type;
 
        u16 group_id; // publisher
 
        u8 reserved[62];
 
        u32 access_rights;
 
        u16 title_version;
 
        u16 num_contents;
 
        content_record contents[0x40];
 
        u8 padding[0x28];
 
        u32 boot_content;
 
        u32 banner_content;
 
        u32 banner_size;
 
        u8 hash[0x20]; /* Huh? */
 
} tmd;
 
  
//The tmd is then followed by a chain of certificates, where each certificate is of the general form
+
// Sorry I removed the example struct because it is wrong.
typedef struct {
 
        u32 sig_type;
 
        u8 sig[*];        // * Signature size
 
        u8 issuer[64];
 
        u32 tag;          // identifies what is being signed
 
        u8 name[64];      // name of thing being signed
 
        u8 key[...];
 
} certificate;
 
 
</source>
 
</source>

Latest revision as of 13:22, 28 July 2020

Title metadata is a format used to store information about a title (installed title, DLC, etc.) and all its installed contents, including which contents they consist of and their SHA256 hashes.

Code is available by trap15 to parse the available information from the 3DS format of TMDs.

StructureEdit

All the data in the file represented in Big Endian, unless otherwise noted.

Offset Size Description
0x0 Y Signature Data
Y 0xC4 Header
0xC4 + Y 0x24*64 Content Info Records.
0x9C4 + Y 0x30*ContentCount Content Chunk Records.

Y denotes the total size of the "Signature Data" section and depends on the signature type.

Signature DataEdit

The signature is of the header of the TMD.

Offset Size Description
0x0 0x4 Signature Type
0x4 X Signature
0x4 + X Padding Aligning the signature data to 0x40 bytes

Signature TypeEdit

Value Signature Method Signature Size Padding Size
0x010000 RSA_4096 SHA1 (Unused for 3DS) 0x200 0x3C
0x010001 RSA_2048 SHA1 (Unused for 3DS) 0x100 0x3C
0x010002 Elliptic Curve with SHA1 (Unused for 3DS) 0x3C 0x40
0x010003 RSA_4096 SHA256 0x200 0x3C
0x010004 RSA_2048 SHA256 0x100 0x3C
0x010005 ECDSA with SHA256 0x3C 0x40

The hash for the signature, is calculated over the header of the TMD

HeaderEdit

Offset Size Description
0x0 0x40 Signature Issuer
0x40 0x1 Version
0x41 0x1 ca_crl_version
0x42 0x1 signer_crl_version
0x43 0x1 Reserved
0x44 0x8 System Version
0x4C 0x8 Title ID
0x54 0x4 Title Type
0x58 0x2 Group ID
0x5A 0x4 Save Data Size in Little Endian (Bytes) (Also SRL Public Save Data Size)
0x5E 0x4 SRL Private Save Data Size in Little Endian (Bytes)
0x62 0x4 Reserved
0x66 0x1 SRL Flag
0x67 0x31 Reserved
0x98 0x4 Access Rights
0x9C 0x2 Title Version
0x9E 0x02 Content Count
0xA0 0x2 Boot Content
0xA2 0x2 Padding
0xA4 0x20 SHA-256 Hash of the Content Info Records

Content Info RecordsEdit

There are 64 of these records, usually only the first is used.

Offset Size Description
0x00 2 Content index offset
0x02 2 Content command count [k]
0x04 0x20 SHA-256 hash of the next k content records that have not been hashed yet

Content chunk recordsEdit

There is one of these for each content contained in this title. (Determined by "Content Count" in the TMD Header).

Offset Size Description
0x00 4 Content id
0x04 2 Content index
0x06 2 Content type
0x08 8 Content size
0x10 0x20 SHA-256 hash

Content IndexEdit

This indicates the content type:

Index Content Type
0000 Main Content (.CXI for 3DS executable content/.CFA for 3DS Data Archives/.SRL for TWL content)
0001 Home Menu Manual (.CFA)
0002 DLP Child Container (.CFA)

This does not apply to DLC.

Content Type flagsEdit

Flags Description
1 Encrypted
2 Disc
4 CFM (abbreviation for?)
0x4000 Optional
0x8000 Shared

Certificate ChainEdit

If the TMD file is obtained from Nintendo's CDN, then it will have two certificates appended at the end of the file:

CERTIFICATE SIGNATURE TYPE RETAIL CERT NAME DEBUG CERT NAME DESCRIPTION
TMD RSA-2048 CP0000000b CP0000000a Used to verify the TMD signature
CA RSA-4096 CA00000003 CA00000004 Used to verify the TMD Certificate

The CA certificate is issued by 'Root', the public key for which is stored in NATIVE_FIRM.

Example code applicationEdit

 enum sig_type {
         RSA_2048_SHA256 = 0x00010004,
         RSA_4096_SHA256 = 0x00010003,
         RSA_2048_SHA1   = 0x00010001,
         RSA_4096_SHA1   = 0x00010000
 };

// Sorry I removed the example struct because it is wrong.