From 306f7773ac12fb8c84a38cd010e05799849d45d7 Mon Sep 17 00:00:00 2001 From: d0k3 Date: Mon, 6 Feb 2017 03:16:35 +0100 Subject: [PATCH] Enable building NUS/CDN certs for TMD & Ticket --- source/game/gameutil.c | 2 +- source/game/ticket.c | 30 ++++++++++++++++++++++++++++++ source/game/ticket.h | 1 + source/game/tmd.c | 30 ++++++++++++++++++++++++++++++ source/game/tmd.h | 1 + 5 files changed, 63 insertions(+), 1 deletion(-) diff --git a/source/game/gameutil.c b/source/game/gameutil.c index d3a8307..1fc1232 100644 --- a/source/game/gameutil.c +++ b/source/game/gameutil.c @@ -440,7 +440,7 @@ u32 VerifyTmdFile(const char* path, bool cdn) { TitleMetaData* tmd = (TitleMetaData*) TEMP_BUFFER; TmdContentChunk* content_list = (TmdContentChunk*) (tmd + 1); Ticket* ticket = (Ticket*) (TEMP_BUFFER + TMD_SIZE_MAX); - u8 titlekey[0x10]; + u8 titlekey[0x10] = { 0xFF }; // path string char pathstr[32 + 1]; diff --git a/source/game/ticket.c b/source/game/ticket.c index 609f1d8..512669a 100644 --- a/source/game/ticket.c +++ b/source/game/ticket.c @@ -1,5 +1,6 @@ #include "ticket.h" #include "aes.h" +#include "sha.h" #include "ff.h" typedef struct { @@ -162,3 +163,32 @@ u32 BuildFakeTicket(Ticket* ticket, u8* title_id) { return 0; } + +u32 BuildTicketCert(u8* tickcert) { + const u8 cert_hash_expected[0x20] = { + 0xDC, 0x15, 0x3C, 0x2B, 0x8A, 0x0A, 0xC8, 0x74, 0xA9, 0xDC, 0x78, 0x61, 0x0E, 0x6A, 0x8F, 0xE3, + 0xE6, 0xB1, 0x34, 0xD5, 0x52, 0x88, 0x73, 0xC9, 0x61, 0xFB, 0xC7, 0x95, 0xCB, 0x47, 0xE6, 0x97 + }; + + // open certs.db file on SysNAND + FIL db; + UINT bytes_read; + if (f_open(&db, "1:/dbs/certs.db", FA_READ | FA_OPEN_EXISTING) != FR_OK) + return 1; + // grab Ticket cert from 3 offsets + f_lseek(&db, 0x3F10); + f_read(&db, tickcert + 0x000, 0x300, &bytes_read); + f_lseek(&db, 0x0C10); + f_read(&db, tickcert + 0x300, 0x1F0, &bytes_read); + f_lseek(&db, 0x3A00); + f_read(&db, tickcert + 0x4F0, 0x210, &bytes_read); + f_close(&db); + + // check the certificate hash + u8 cert_hash[0x20]; + sha_quick(cert_hash, tickcert, TICKET_CDNCERT_SIZE, SHA256_MODE); + if (memcmp(cert_hash, cert_hash_expected, 0x20) != 0) + return 1; + + return 0; +} diff --git a/source/game/ticket.h b/source/game/ticket.h index bf2c517..db6306f 100644 --- a/source/game/ticket.h +++ b/source/game/ticket.h @@ -59,3 +59,4 @@ u32 GetTitleKey(u8* titlekey, Ticket* ticket); u32 FindTicket(Ticket* ticket, u8* title_id, bool force_legit, bool emunand); u32 FindTitleKey(Ticket* ticket, u8* title_id); u32 BuildFakeTicket(Ticket* ticket, u8* title_id); +u32 BuildTicketCert(u8* tickcert); diff --git a/source/game/tmd.c b/source/game/tmd.c index 11afe6a..0363196 100644 --- a/source/game/tmd.c +++ b/source/game/tmd.c @@ -1,5 +1,6 @@ #include "tmd.h" #include "sha.h" +#include "ff.h" u32 GetTmdCtr(u8* ctr, TmdContentChunk* chunk) { memset(ctr, 0, 16); @@ -43,3 +44,32 @@ u32 BuildFakeTmd(TitleMetaData* tmd, u8* title_id, u32 n_contents, u32 save_size return 0; } + +u32 BuildTmdCert(u8* tmdcert) { + const u8 cert_hash_expected[0x20] = { + 0x91, 0x5F, 0x77, 0x3A, 0x07, 0x82, 0xD4, 0x27, 0xC4, 0xCE, 0xF5, 0x49, 0x25, 0x33, 0xE8, 0xEC, + 0xF6, 0xFE, 0xA1, 0xEB, 0x8C, 0xCF, 0x59, 0x6E, 0x69, 0xBA, 0x2A, 0x38, 0x8D, 0x73, 0x8A, 0xE1 + }; + + // open certs.db file on SysNAND + FIL db; + UINT bytes_read; + if (f_open(&db, "1:/dbs/certs.db", FA_READ | FA_OPEN_EXISTING) != FR_OK) + return 1; + // grab TMD cert from 3 offsets + f_lseek(&db, 0x3C10); + f_read(&db, tmdcert + 0x000, 0x300, &bytes_read); + f_lseek(&db, 0x0C10); + f_read(&db, tmdcert + 0x300, 0x1F0, &bytes_read); + f_lseek(&db, 0x3A00); + f_read(&db, tmdcert + 0x4F0, 0x210, &bytes_read); + f_close(&db); + + // check the certificate hash + u8 cert_hash[0x20]; + sha_quick(cert_hash, tmdcert, TMD_CDNCERT_SIZE, SHA256_MODE); + if (memcmp(cert_hash, cert_hash_expected, 0x20) != 0) + return 1; + + return 0; +} diff --git a/source/game/tmd.h b/source/game/tmd.h index 8678f4e..207c13c 100644 --- a/source/game/tmd.h +++ b/source/game/tmd.h @@ -59,3 +59,4 @@ typedef struct { u32 GetTmdCtr(u8* ctr, TmdContentChunk* chunk); u32 FixTmdHashes(TitleMetaData* tmd); u32 BuildFakeTmd(TitleMetaData* tmd, u8* title_id, u32 n_contents, u32 save_size); +u32 BuildTmdCert(u8* tmdcert);