Line 5: |
Line 5: |
| A "title" is a standalone entity -- a game, a channel, etc. Titles can be made up of multiple "contents". (Don't ask me I just work here.) | | A "title" is a standalone entity -- a game, a channel, etc. Titles can be made up of multiple "contents". (Don't ask me I just work here.) |
| | | |
− | // Common labels used in this file:
| + | Many operations are done in terms of 64-byte blocks, which means you will often see padding out to the nearest 64-byte boundary at the end of a field. |
− | // magicnum - control ints or shorts found in all tmds
| |
− | // zeros - bytes all filled with zeros
| |
− | // undef - non-zero data of unknown purpose
| |
− | // sign - zero-terminated string padded to 64 bytes
| |
− | // probably used in the signing process
| |
− | // hash - probably 20, 512 or 1024 byte hashes
| |
− | //
| |
− | // # in front of a comment signifies entires that are
| |
− | // the same in each tmd-files the author checked
| |
| | | |
| typedef unsigned char u8; | | typedef unsigned char u8; |
Line 29: |
Line 20: |
| } content_record; // size: 0x30 bytes | | } content_record; // size: 0x30 bytes |
| | | |
− | typedef struct{ | + | enum sig_type { |
− | u32 magicnum0 [0x1]; // # 0x00010001
| + | RSA_2048 = 0x00010001, |
− | u8 hash0 [0x100]; // ?
| + | RSA_4096 = 0x00010000 |
− | u8 zeros0 [0x3C]; // # 0
| + | }; |
− | u8 sign0 [0x40]; // # Root-CA-CP
| + | |
− | u8 undef0 [0x10]; // # ?
| + | typedef struct { |
− | u8 code [0x4]; // game code in ascii
| + | u32 sig_type; |
− | u32 magicnum1 [0x1]; // # 0x00000001
| + | u8 sig[256]; |
− | u8 publ [0x2]; // publisher id
| + | u8 fill1[60]; |
− | u8 zeros1 [0x2]; // # 0
| + | u8 issuer[64]; // Root-CA%08x-CP%08x |
− | u8 undef1 [0x4]; // ?
| + | u8 version; |
− | u8 undef2 [0xE]; // ? 0x80
| + | u8 ca_crl_version; |
− | u8 zeros2 [0x2E]; // # 0
| + | u8 signer_crl_version; |
− | u8 undef3 [0x8]; // ?
| + | u8 fill2; |
− | VC_TMD_FILE files[7]; // 7 file entries
| + | u64 sys_version; |
− | u32 magicnum2 [0x1]; // # 0x00010001
| + | u64 title_id; |
− | u8 hash1 [0x100]; // # ?
| + | u32 title_type; |
− | u8 zeros3 [0x3C]; // # 0
| + | u16 group_id; // publisher |
− | u8 sign1 [0x40]; // # Root-CA
| + | u8 reserved[62]; |
− | u32 magicnum3 [0x1]; // # 0x00000001
| + | u32 access_rights; |
− | u8 sign2 [0x40]; // # CP
| + | u16 title_version; |
− | u8 hash2 [0x104]; // # ?
| + | u16 num_contents; |
− | u32 magicnum4 [0x1]; // # 0x00010001
| + | u16 boot_index; |
− | u8 zeros4 [0x34]; // # 0
| + | u16 fill3; |
− | u32 magicnum5 [0x1]; // # 0x00100000
| + | content_record contents[num_contents]; |
− | u8 hash3 [0x200]; // # ?
| + | } tmd; |
− | u8 zeros5 [0x3C]; // # 0
| + | |
− | u8 sign3 [0x40]; // # Root
| + | The tmd is then followed by a chain of certificates, where each certificate is of the general form |
− | u32 magicnum6 [0x1]; // # 0x00000001
| + | |
− | u8 sign4 [0x40]; // # CA
| + | u32 sig_type; // |
− | u8 hash4 [0x104]; // # ?
| + | u8 sig[256]; // 256 for RSA_2048, 512 for RSA_4096 |
− | u32 magicnum7 [0x1]; // # 0x00010001
| + | u8 issuer[32]; |
− | u8 zeros6 [0x34]; // # 0
| + | u32 tag; // identifies what is being signed |
− | }VC_TMD; // size: 09E0 bytes
| + | u8 name[64]; // name of thing being signed |
| + | u8 key[...]; |