2010-12-08 08:26:18 +01:00
|
|
|
#ifndef TIKTMD_H
|
|
|
|
#define TIKTMD_H
|
|
|
|
|
|
|
|
#include "includes.h"
|
|
|
|
|
|
|
|
#define ES_SIG_RSA4096 0x10000
|
|
|
|
#define ES_SIG_RSA2048 0x10001
|
|
|
|
#define ES_SIG_ECDSA 0x10002
|
|
|
|
|
|
|
|
typedef quint32 sigtype;
|
|
|
|
typedef sigtype sig_header;
|
|
|
|
typedef sig_header signed_blob;
|
|
|
|
|
|
|
|
typedef quint8 sha1[20];
|
|
|
|
typedef quint8 aeskey[16];
|
|
|
|
|
|
|
|
typedef struct _sig_rsa2048 {
|
|
|
|
sigtype type;
|
|
|
|
quint8 sig[256];
|
|
|
|
quint8 fill[60];
|
|
|
|
} __attribute__((packed)) sig_rsa2048;
|
|
|
|
|
|
|
|
typedef struct _sig_rsa4096 {
|
|
|
|
sigtype type;
|
|
|
|
quint8 sig[512];
|
|
|
|
quint8 fill[60];
|
|
|
|
} __attribute__((packed)) sig_rsa4096;
|
|
|
|
|
|
|
|
typedef struct _sig_ecdsa {
|
|
|
|
sigtype type;
|
|
|
|
quint8 sig[60];
|
|
|
|
quint8 fill[64];
|
|
|
|
} __attribute__((packed)) sig_ecdsa;
|
|
|
|
|
|
|
|
typedef char sig_issuer[0x40];
|
|
|
|
|
|
|
|
typedef struct _tiklimit {
|
|
|
|
quint32 tag;
|
|
|
|
quint32 value;
|
|
|
|
} __attribute__((packed)) tiklimit;
|
2010-12-08 19:07:57 +01:00
|
|
|
|
2010-12-08 08:26:18 +01:00
|
|
|
typedef struct _tik {
|
|
|
|
sig_issuer issuer;
|
|
|
|
quint8 fill[63]; //TODO: not really fill
|
|
|
|
aeskey cipher_title_key;
|
|
|
|
quint8 fill2;
|
|
|
|
quint64 ticketid;
|
|
|
|
quint32 devicetype;
|
|
|
|
quint64 titleid;
|
|
|
|
quint16 access_mask;
|
|
|
|
quint8 reserved[0x3c];
|
|
|
|
quint8 cidx_mask[0x40];
|
|
|
|
quint16 padding;
|
|
|
|
tiklimit limits[8];
|
|
|
|
} __attribute__((packed)) tik;
|
|
|
|
|
|
|
|
typedef struct _tmd_content {
|
|
|
|
quint32 cid;
|
|
|
|
quint16 index;
|
|
|
|
quint16 type;
|
|
|
|
quint64 size;
|
|
|
|
sha1 hash;
|
|
|
|
} __attribute__((packed)) tmd_content;
|
|
|
|
|
|
|
|
typedef struct _tmd {
|
|
|
|
sig_issuer issuer; //0x140
|
|
|
|
quint8 version; //0x180
|
|
|
|
quint8 ca_crl_version; //0x181
|
|
|
|
quint8 signer_crl_version; //0x182
|
|
|
|
quint8 fill2; //0x183
|
|
|
|
quint64 sys_version; //0x184
|
|
|
|
quint64 title_id; //0x18c
|
|
|
|
quint32 title_type; //0x194
|
|
|
|
quint16 group_id; //0x198
|
|
|
|
quint16 zero; //0x19a
|
|
|
|
quint16 region; //0x19c
|
|
|
|
quint8 ratings[16]; //0x19e
|
|
|
|
quint8 reserved[12]; //0x1ae
|
|
|
|
quint8 ipc_mask[12];
|
|
|
|
quint8 reserved2[18];
|
|
|
|
quint32 access_rights;
|
|
|
|
quint16 title_version;
|
|
|
|
quint16 num_contents;
|
|
|
|
quint16 boot_index;
|
|
|
|
quint16 fill3;
|
|
|
|
// content records follow
|
|
|
|
// C99 flexible array
|
|
|
|
tmd_content contents[];
|
|
|
|
} __attribute__((packed)) tmd;
|
2011-01-02 07:15:26 +01:00
|
|
|
/*
|
2010-12-08 08:26:18 +01:00
|
|
|
typedef struct _tmd_view_content
|
|
|
|
{
|
2011-01-02 07:15:26 +01:00
|
|
|
quint32 cid;
|
|
|
|
quint16 index;
|
|
|
|
quint16 type;
|
|
|
|
quint64 size;
|
2010-12-08 08:26:18 +01:00
|
|
|
} __attribute__((packed)) tmd_view_content;
|
|
|
|
|
|
|
|
typedef struct _cert_header {
|
|
|
|
sig_issuer issuer;
|
|
|
|
quint32 cert_type;
|
|
|
|
char cert_name[64];
|
|
|
|
quint32 cert_id; //???
|
|
|
|
} __attribute__((packed)) cert_header;
|
|
|
|
|
|
|
|
typedef struct _cert_rsa2048 {
|
|
|
|
sig_issuer issuer;
|
|
|
|
quint32 cert_type;
|
|
|
|
char cert_name[64];
|
|
|
|
quint32 cert_id;
|
|
|
|
quint8 modulus[256];
|
|
|
|
quint32 exponent;
|
|
|
|
quint8 pad[0x34];
|
|
|
|
} __attribute__((packed)) cert_rsa2048;
|
|
|
|
|
|
|
|
typedef struct _cert_rsa4096 {
|
|
|
|
sig_issuer issuer;
|
|
|
|
quint32 cert_type;
|
|
|
|
char cert_name[64];
|
|
|
|
quint32 cert_id;
|
|
|
|
quint8 modulus[512];
|
|
|
|
quint32 exponent;
|
|
|
|
quint8 pad[0x34];
|
|
|
|
} __attribute__((packed)) cert_rsa4096;
|
|
|
|
|
|
|
|
typedef struct _cert_ecdsa {
|
|
|
|
sig_issuer issuer;
|
|
|
|
quint32 cert_type;
|
|
|
|
char cert_name[64];
|
|
|
|
quint32 cert_id; // ng key id
|
|
|
|
quint8 r[30];
|
|
|
|
quint8 s[30];
|
|
|
|
quint8 pad[0x3c];
|
|
|
|
} __attribute__((packed)) cert_ecdsa;
|
2011-01-02 07:15:26 +01:00
|
|
|
*/
|
2010-12-08 08:26:18 +01:00
|
|
|
//just a quick class to try to keep the rest of the code from getting full of the same shit over and over
|
|
|
|
class Ticket
|
|
|
|
{
|
|
|
|
public:
|
2011-01-13 17:43:49 +01:00
|
|
|
Ticket( const QByteArray &stuff = QByteArray(), bool fixKeyIndex = true );
|
2010-12-08 08:26:18 +01:00
|
|
|
|
|
|
|
//expose the tik data to the rest of the code so it cas read directly from the p_tmd instead of having to add a function to access all the data
|
|
|
|
//the pointer should be good until "data" is changed
|
|
|
|
const tik *payload(){ return p_tik; }
|
|
|
|
|
|
|
|
quint64 Tid();
|
2010-12-09 12:30:25 +01:00
|
|
|
bool SetTid( quint64 tid );
|
2010-12-08 08:26:18 +01:00
|
|
|
|
|
|
|
QByteArray DecryptedKey();
|
|
|
|
quint32 SignedSize();
|
2010-12-09 12:30:25 +01:00
|
|
|
bool FakeSign();
|
|
|
|
|
|
|
|
//get the ticket data
|
|
|
|
const QByteArray Data(){ return data; }
|
2010-12-08 08:26:18 +01:00
|
|
|
|
|
|
|
private:
|
|
|
|
quint32 payLoadOffset;
|
|
|
|
|
|
|
|
//let data hold the entire tik data
|
|
|
|
QByteArray data;
|
2010-12-22 20:19:12 +01:00
|
|
|
QByteArray decKey;
|
2010-12-08 08:26:18 +01:00
|
|
|
|
|
|
|
//point the p_tik to the spot in "data" we want
|
|
|
|
void SetPointer();
|
|
|
|
|
|
|
|
//this is just a pointer to the actual good stuff in "data".
|
|
|
|
//whenever data is changes, this pointer will become invalid and needs to be reset
|
|
|
|
tik *p_tik;
|
|
|
|
};
|
|
|
|
|
|
|
|
class Tmd
|
|
|
|
{
|
|
|
|
public:
|
2010-12-23 17:17:46 +01:00
|
|
|
Tmd( const QByteArray &stuff = QByteArray() );
|
2010-12-08 08:26:18 +01:00
|
|
|
|
|
|
|
//expose the tmd data to the rest of the code so it cas read directly from the p_tmd instead of having to add a function to access all the data
|
|
|
|
//the pointer should be good until "data" is changed
|
|
|
|
const tmd *payload(){ return p_tmd; }
|
|
|
|
|
|
|
|
//get a string containing the u32 of cid i
|
|
|
|
QString Cid( quint16 i );
|
|
|
|
|
|
|
|
//get a btyearray with the hosh of the given conten
|
|
|
|
QByteArray Hash( quint16 i );
|
|
|
|
|
|
|
|
//returned in host endian
|
2011-01-13 17:43:49 +01:00
|
|
|
quint64 Size( quint16 i );
|
|
|
|
quint16 Type( quint16 i );
|
2011-01-21 07:21:28 +01:00
|
|
|
quint16 BootIndex();
|
|
|
|
quint16 Index( quint16 i );
|
2010-12-08 08:26:18 +01:00
|
|
|
quint64 Tid();
|
2010-12-18 22:07:58 +01:00
|
|
|
quint64 IOS();
|
|
|
|
quint16 Gid();
|
2011-01-13 17:43:49 +01:00
|
|
|
quint32 AccessFlags();
|
2010-12-18 22:07:58 +01:00
|
|
|
|
2010-12-08 08:26:18 +01:00
|
|
|
|
2010-12-08 19:07:57 +01:00
|
|
|
//gets the number of contents
|
|
|
|
quint16 Count();
|
|
|
|
|
|
|
|
//title version
|
|
|
|
quint16 Version();
|
|
|
|
|
2010-12-09 12:30:25 +01:00
|
|
|
//functions to edit the TMD
|
2010-12-10 04:50:08 +01:00
|
|
|
//you probably want to call FakeSign() after using these
|
2010-12-09 12:30:25 +01:00
|
|
|
bool SetTid( quint64 tid );
|
|
|
|
bool SetVersion( quint16 v );
|
2010-12-10 04:50:08 +01:00
|
|
|
bool SetType( quint16 i, quint16 type );
|
|
|
|
bool SetSize( quint16 i, quint32 size );
|
2010-12-23 17:17:46 +01:00
|
|
|
bool SetHash( quint16 i, const QByteArray &hash );
|
2010-12-18 22:07:58 +01:00
|
|
|
bool SetIOS( quint64 ios );
|
2010-12-23 08:32:10 +01:00
|
|
|
bool SetAhb( bool remove = true );
|
|
|
|
bool SetDiskAccess( bool allow = true );
|
2010-12-09 12:30:25 +01:00
|
|
|
|
|
|
|
bool FakeSign();
|
|
|
|
|
2010-12-10 04:50:08 +01:00
|
|
|
//returns a qbytearray containing the tmd, from the rsa signature through the last content
|
2010-12-09 12:30:25 +01:00
|
|
|
const QByteArray Data(){ return data; }
|
|
|
|
|
2010-12-10 04:50:08 +01:00
|
|
|
//print some tmd info to qDebug()
|
2010-12-09 12:30:25 +01:00
|
|
|
void Dbg();
|
|
|
|
|
|
|
|
|
2010-12-08 08:26:18 +01:00
|
|
|
quint32 SignedSize();
|
|
|
|
private:
|
|
|
|
quint32 payLoadOffset;
|
|
|
|
|
|
|
|
//let data hold the entire tmd data
|
|
|
|
QByteArray data;
|
|
|
|
|
|
|
|
//point the p_tmd to the spot in "data" we want
|
|
|
|
void SetPointer();
|
|
|
|
|
|
|
|
//this is just a pointer to the actual good stuff in "data".
|
2010-12-10 04:50:08 +01:00
|
|
|
//whenever data is changed, this pointer will become invalid and needs to be reset
|
2010-12-08 08:26:18 +01:00
|
|
|
tmd *p_tmd;
|
|
|
|
};
|
|
|
|
|
2010-12-18 22:07:58 +01:00
|
|
|
enum
|
|
|
|
{
|
2011-01-02 07:15:26 +01:00
|
|
|
ERROR_SUCCESS = 0,
|
|
|
|
ERROR_SIG_TYPE,
|
|
|
|
ERROR_SUB_TYPE,
|
|
|
|
ERROR_RSA_FAKESIGNED,
|
|
|
|
ERROR_RSA_HASH,
|
|
|
|
ERROR_RSA_TYPE_UNKNOWN,
|
|
|
|
ERROR_RSA_TYPE_MISMATCH,
|
|
|
|
ERROR_CERT_NOT_FOUND,
|
|
|
|
ERROR_COUNT
|
2010-12-18 22:07:58 +01:00
|
|
|
};
|
|
|
|
|
|
|
|
//checks the signatures in a tmd/ticket
|
|
|
|
//returns 1 of the above enums
|
2010-12-23 17:17:46 +01:00
|
|
|
int check_cert_chain( const QByteArray &data );
|
2010-12-18 22:07:58 +01:00
|
|
|
|
2010-12-08 08:26:18 +01:00
|
|
|
#endif // TIKTMD_H
|