Fix verification for TMD from NUS/CDN

This commit is contained in:
d0k3 2017-02-06 02:57:21 +01:00
parent d9e9455be3
commit 4082b4fa00

View File

@ -205,22 +205,32 @@ u32 LoadNcchMeta(CiaMeta* meta, const char* path, u64 offset) {
u32 LoadTmdFile(TitleMetaData* tmd, const char* path) { u32 LoadTmdFile(TitleMetaData* tmd, const char* path) {
const u8 magic[] = { TMD_SIG_TYPE }; const u8 magic[] = { TMD_SIG_TYPE };
FIL file; UINT br;
UINT btr;
if (fvx_open(&file, path, FA_READ | FA_OPEN_EXISTING) != FR_OK)
return 1;
// full TMD file // full TMD file
fvx_lseek(&file, 0); if ((fvx_qread(path, tmd, 0, TMD_SIZE_MAX, &br) != FR_OK) ||
if ((fvx_read(&file, tmd, TMD_SIZE_MAX, &btr) != FR_OK) ||
(memcmp(tmd->sig_type, magic, sizeof(magic)) != 0) || (memcmp(tmd->sig_type, magic, sizeof(magic)) != 0) ||
(btr < TMD_SIZE_N(getbe16(tmd->content_count)))) { (br < TMD_SIZE_N(getbe16(tmd->content_count))))
fvx_close(&file);
return 1; return 1;
}
fvx_close(&file); return 0;
}
u32 LoadCdnTicketFile(Ticket* ticket, const char* path) {
// path may be to any file in dir
char path_cetk[256];
char* name_cetk;
strncpy(path_cetk, path, 256);
name_cetk = strrchr(path_cetk, '/');
if (!name_cetk) return 1; // will not happen
name_cetk++;
snprintf(name_cetk, 256 - (name_cetk - path_cetk), "cetk");
// load and check ticket
UINT br;
if ((fvx_qread(path_cetk, ticket, 0, TICKET_SIZE, &br) != FR_OK) || (br != TICKET_SIZE) ||
(ValidateTicket(ticket) != 0)) return 1;
return 0; return 0;
} }
@ -425,10 +435,12 @@ u32 VerifyCiaFile(const char* path) {
return 0; return 0;
} }
u32 VerifyTmdFile(const char* path) { u32 VerifyTmdFile(const char* path, bool cdn) {
const u8 dlc_tid_high[] = { DLC_TID_HIGH }; const u8 dlc_tid_high[] = { DLC_TID_HIGH };
TitleMetaData* tmd = (TitleMetaData*) TEMP_BUFFER; TitleMetaData* tmd = (TitleMetaData*) TEMP_BUFFER;
TmdContentChunk* content_list = (TmdContentChunk*) (tmd + 1); TmdContentChunk* content_list = (TmdContentChunk*) (tmd + 1);
Ticket* ticket = (Ticket*) (TEMP_BUFFER + TMD_SIZE_MAX);
u8 titlekey[0x10];
// path string // path string
char pathstr[32 + 1]; char pathstr[32 + 1];
@ -448,16 +460,26 @@ u32 VerifyTmdFile(const char* path) {
return 1; return 1;
} }
if (cdn) { // load / build ticket (for titlekey / CDN only)
if (!((LoadCdnTicketFile(ticket, path) == 0) ||
((BuildFakeTicket(ticket, tmd->title_id) == 0) &&
(FindTitleKey(ticket, tmd->title_id) == 0))) ||
(GetTitleKey(titlekey, ticket) != 0)) {
ShowPrompt(false, "%s\nError: CDN titlekey not found", pathstr);
return 1;
}
}
// verify contents // verify contents
u32 content_count = getbe16(tmd->content_count); u32 content_count = getbe16(tmd->content_count);
bool dlc = (memcmp(tmd->title_id, dlc_tid_high, sizeof(dlc_tid_high)) == 0); bool dlc = !cdn && (memcmp(tmd->title_id, dlc_tid_high, sizeof(dlc_tid_high)) == 0);
for (u32 i = 0; (i < content_count) && (i < TMD_MAX_CONTENTS); i++) { for (u32 i = 0; (i < content_count) && (i < TMD_MAX_CONTENTS); i++) {
TmdContentChunk* chunk = &(content_list[i]); TmdContentChunk* chunk = &(content_list[i]);
chunk->type[1] &= ~0x01; // remove crypto flag if (!cdn) chunk->type[1] &= ~0x01; // remove crypto flag
snprintf(name_content, 256 - (name_content - path_content), snprintf(name_content, 256 - (name_content - path_content),
(dlc) ? "00000000/%08lx.app" : "%08lx.app", getbe32(chunk->id)); (cdn) ? "%08lx" : (dlc) ? "00000000/%08lx.app" : "%08lx.app", getbe32(chunk->id));
TruncateString(pathstr, path_content, 32, 8); TruncateString(pathstr, path_content, 32, 8);
if (VerifyTmdContent(path_content, 0, chunk, NULL) != 0) { if (VerifyTmdContent(path_content, 0, chunk, titlekey) != 0) {
ShowPrompt(false, "%s\nVerification failed", pathstr); ShowPrompt(false, "%s\nVerification failed", pathstr);
return 1; return 1;
} }
@ -579,7 +601,7 @@ u32 VerifyGameFile(const char* path) {
else if (filetype & GAME_NCCH) else if (filetype & GAME_NCCH)
return VerifyNcchFile(path, 0, 0); return VerifyNcchFile(path, 0, 0);
else if (filetype & GAME_TMD) else if (filetype & GAME_TMD)
return VerifyTmdFile(path); return VerifyTmdFile(path, filetype & FLAG_NUSCDN);
else if (filetype & GAME_BOSS) else if (filetype & GAME_BOSS)
return VerifyBossFile(path); return VerifyBossFile(path);
else if (filetype & SYS_FIRM) else if (filetype & SYS_FIRM)