ホワイトリストphase3, phase4実装、

仮データベース登録 (2009/03/25時点で本物)
SYSM_IGNORE_DHT_PHASE3はバナーチェックでエラーにしない、
SYSM_IGNORE_DHT_EX_NOT_FOUNDは旧データベースでもエラーにしない、
という意味

git-svn-id: file:///Users/lillianskinner/Downloads/platinum/twl/TwlIPL/trunk@2767 b08762b0-b915-fc4b-9d8c-17b2551a87ff
This commit is contained in:
yutaka 2009-03-25 12:00:30 +00:00
parent 3ac6387837
commit a938401b08
13 changed files with 2764 additions and 1937 deletions

View File

@ -21,6 +21,8 @@ TWL_IPL_COMMONDEFS_ = TRUE
#FIRM_USE_PRODUCT_KEYS = TRUE #FIRM_USE_PRODUCT_KEYS = TRUE
#SYSM_BUILD_FOR_DEBUGGER = TRUE #SYSM_BUILD_FOR_DEBUGGER = TRUE
SYSM_DEV_WHITELIST_CHECK_SKIP ?= TRUE SYSM_DEV_WHITELIST_CHECK_SKIP ?= TRUE
#SYSM_IGNORE_DHT_PHASE_3 = TRUE
SYSM_IGNORE_DHT_EX_NOT_FOUND ?= TRUE
ifeq ($(TARGET_FIRM),SYSTEMMENU) ifeq ($(TARGET_FIRM),SYSTEMMENU)
include $(TWL_IPL_RED_ROOT)/build/buildtools/commondefs.sysmenu include $(TWL_IPL_RED_ROOT)/build/buildtools/commondefs.sysmenu

View File

@ -49,7 +49,8 @@ static const u8 g_pubkey_DER[ 0xa2 ] = {
0x00, 0x01 0x00, 0x01
}; };
static const u8 hmac_key[] = DHT_HMAC_KEY; static const u8 hmac_key[] = DHT_HMAC_KEY; // for phase1, phase2
static const u8 hmac_key2[] = DHT_HMAC_KEY2; // for phase3, phase4
static DHTReadFunc imageReadFunc; static DHTReadFunc imageReadFunc;
static void* imageBuffer; static void* imageBuffer;
@ -114,6 +115,25 @@ u32 DHT_GetDatabaseLength(const DHTFile* pDHT)
} }
return sizeof(DHTHeader) + pDHT->header.nums * sizeof(DHTDatabase); return sizeof(DHTHeader) + pDHT->header.nums * sizeof(DHTDatabase);
} }
u32 DHT_GetDatabaseExLength(const DHTFileEx* pDHT)
{
if ( pDHT->header.magic_code != DHT_MAGIC_CODE_EX ) // magic codeチェック
{
OS_TPrintf("Invalid magic code (magic=0x%08X) [EX].\n", pDHT->header.magic_code);
return 0;
}
return sizeof(DHTHeader) + pDHT->header.nums * sizeof(DHTDatabaseEx);
}
u32 DHT_GetDatabaseAdHocLength(const DHTFileAdHoc* pDHT)
{
if ( pDHT->header.magic_code != DHT_MAGIC_CODE_ADHOC ) // magic codeチェック
{
OS_TPrintf("Invalid magic code (magic=0x%08X) [AdHoc].\n", pDHT->header.magic_code);
return 0;
}
return sizeof(DHTHeader) + pDHT->header.nums * sizeof(DHTDatabaseAdHoc);
}
static BOOL DHT_CheckDatabase(const DHTFile* pDHT) static BOOL DHT_CheckDatabase(const DHTFile* pDHT)
{ {
SVCSignHeapContext pool; SVCSignHeapContext pool;
@ -216,6 +236,219 @@ const DHTDatabase* DHT_GetDatabase(const DHTFile* pDHT, const ROM_Header_Short*
#endif #endif
return db; return db;
} }
/*
()
*/
static BOOL DHT_CheckDatabaseEx(const DHTFileEx* pDHT)
{
SVCSignHeapContext pool;
static u8 heap[4*1024]; // avoid stack overflow
u8 md1[20];
u8 md2[20];
s32 result;
// ファイル署名取り出し
SVC_InitSignHeap(&pool, heap, sizeof(heap));
SVC_DecryptSign(&pool, md1, pDHT->header.sign, &g_pubkey_DER[29]);
// ハッシュ計算
SVC_CalcSHA1(md2, DHT_GET_SIGN_TARGET_ADDR(&pDHT->header), DHT_GET_SIGN_TARGET_SIZE_EX(&pDHT->header));
// 検証
result = SVC_CompareSHA1(md1, md2);
if ( !result )
{
OS_TPrintf("\n");
OS_TPrintfEx("SIGN = % 20B [EX]\n", md1);
OS_TPrintfEx("HASH = % 20B [EX]\n", md2);
OS_TPrintf("Signature is not valid. [EX]\n");
return FALSE;
}
return TRUE;
}
BOOL DHT_PrepareDatabaseEx(DHTFileEx* pDHT, FSFile* fp)
{
s32 result;
s32 length;
PROFILE_INIT();
if ( fp )
{
// ヘッダ読み込み
PROFILE_COUNT();
result = FS_ReadFile(fp, &pDHT->header, sizeof(DHTHeader));
if ( result != sizeof(DHTHeader) )
{
OS_TPrintf("Cannot read the DHT header (result=%d). [EX]\n", result);
return FALSE;
}
// 拡張データベース読み込み
PROFILE_COUNT();
length = (s32)DHT_GetDatabaseExLength(pDHT) - (s32)sizeof(DHTHeader); // ヘッダを除く
if ( length < 0 )
{
OS_TPrintf("Invalid DHT header. [EX]\n");
return FALSE;
}
result = FS_ReadFile(fp, pDHT->database, length);
if ( result != length )
{
OS_TPrintf("Cannot read the DHT database (result=%d). [EX]\n", result);
return FALSE;
}
}
else
{
PROFILE_COUNT();
PROFILE_COUNT();
}
// 拡張データベースの検証
PROFILE_COUNT();
result = DHT_CheckDatabaseEx(pDHT);
// 結果報告
#ifdef PRINT_PROFILE
PROFILE_COUNT();
OS_TPrintf("\nDone to prepare the database. [EX]\n");
OS_TPrintf("%10d msec for reading header. [EX]\n", (int)OS_TicksToMilliSeconds(profile[1]-profile[0]));
OS_TPrintf("%10d msec for reading database. [EX]\n", (int)OS_TicksToMilliSeconds(profile[2]-profile[1]));
OS_TPrintf("%10d msec for comparing hash. [EX]\n", (int)OS_TicksToMilliSeconds(profile[3]-profile[2]));
OS_TPrintf("\nTotal: %10d msec. [EX]\n", (int)OS_TicksToMilliSeconds(profile[3]-profile[0]));
#endif
return result;
}
/*
ROMヘッダに対応する拡張データベースを手に入れる
*/
const DHTDatabaseEx* DHT_GetDatabaseEx(const DHTFileEx* pDHT, const ROM_Header_Short* pROMHeader)
{
u8 data[5];
DHTDatabaseEx* db;
PROFILE_INIT();
// 準備
PROFILE_COUNT();
MI_CpuCopy8( pROMHeader->game_code, data, 4 );
data[4] = pROMHeader->rom_version;
db = (DHTDatabaseEx*)bsearch(data, pDHT->database, pDHT->header.nums, sizeof(DHTDatabaseEx), CompareGameCodeAndVersion);
if ( !db )
{
OS_TPrintf("Cannot find the database. [EX]\n");
}
#ifdef PRINT_PROFILE
PROFILE_COUNT();
OS_TPrintf("%10d msec for searching database. [EX]\n", (int)OS_TicksToMilliSeconds(profile[1]-profile[0]));
#endif
return db;
}
/*
()
*/
static BOOL DHT_CheckDatabaseAdHoc(const DHTFileAdHoc* pDHT)
{
SVCSignHeapContext pool;
static u8 heap[4*1024]; // avoid stack overflow
u8 md1[20];
u8 md2[20];
s32 result;
// ファイル署名取り出し
SVC_InitSignHeap(&pool, heap, sizeof(heap));
SVC_DecryptSign(&pool, md1, pDHT->header.sign, &g_pubkey_DER[29]);
// ハッシュ計算
SVC_CalcSHA1(md2, DHT_GET_SIGN_TARGET_ADDR(&pDHT->header), DHT_GET_SIGN_TARGET_SIZE_EX(&pDHT->header));
// 検証
result = SVC_CompareSHA1(md1, md2);
if ( !result )
{
OS_TPrintf("\n");
OS_TPrintfEx("SIGN = % 20B [AdHoc]\n", md1);
OS_TPrintfEx("HASH = % 20B [AdHoc]\n", md2);
OS_TPrintf("Signature is not valid. [AdHoc]\n");
return FALSE;
}
return TRUE;
}
BOOL DHT_PrepareDatabaseAdHoc(DHTFileAdHoc* pDHT, FSFile* fp)
{
s32 result;
s32 length;
PROFILE_INIT();
if ( fp )
{
// ヘッダ読み込み
PROFILE_COUNT();
result = FS_ReadFile(fp, &pDHT->header, sizeof(DHTHeader));
if ( result != sizeof(DHTHeader) )
{
OS_TPrintf("Cannot read the DHT header (result=%d). [AdHoc]\n", result);
return FALSE;
}
// 拡張データベース読み込み
PROFILE_COUNT();
length = (s32)DHT_GetDatabaseAdHocLength(pDHT) - (s32)sizeof(DHTHeader); // ヘッダを除く
if ( length < 0 )
{
OS_TPrintf("Invalid DHT header. [AdHoc]\n");
return FALSE;
}
result = FS_ReadFile(fp, pDHT->database, length);
if ( result != length )
{
OS_TPrintf("Cannot read the DHT database (result=%d). [AdHoc]\n", result);
return FALSE;
}
}
else
{
PROFILE_COUNT();
PROFILE_COUNT();
}
// 拡張データベースの検証
PROFILE_COUNT();
result = DHT_CheckDatabaseAdHoc(pDHT);
// 結果報告
#ifdef PRINT_PROFILE
PROFILE_COUNT();
OS_TPrintf("\nDone to prepare the database. [AdHoc]\n");
OS_TPrintf("%10d msec for reading header. [AdHoc]\n", (int)OS_TicksToMilliSeconds(profile[1]-profile[0]));
OS_TPrintf("%10d msec for reading database. [AdHoc]\n", (int)OS_TicksToMilliSeconds(profile[2]-profile[1]));
OS_TPrintf("%10d msec for comparing hash. [AdHoc]\n", (int)OS_TicksToMilliSeconds(profile[3]-profile[2]));
OS_TPrintf("\nTotal: %10d msec. [AdHoc]\n", (int)OS_TicksToMilliSeconds(profile[3]-profile[0]));
#endif
return result;
}
/*
ROMヘッダに対応する拡張データベースを手に入れる
*/
static const DHTDatabaseAdHoc* DHT_GetDatabaseAdHoc(const DHTFileAdHoc* pDHT, const ROM_Header_Short* pROMHeader)
{
u8 data[5];
DHTDatabaseAdHoc* db;
PROFILE_INIT();
// 準備
PROFILE_COUNT();
MI_CpuCopy8( pROMHeader->game_code, data, 4 );
data[4] = pROMHeader->rom_version;
db = (DHTDatabaseAdHoc*)bsearch(data, pDHT->database, pDHT->header.nums, sizeof(DHTDatabaseAdHoc), CompareGameCodeAndVersion);
if ( !db )
{
OS_TPrintf("Cannot find the database. [AdHoc]\n");
}
#ifdef PRINT_PROFILE
PROFILE_COUNT();
OS_TPrintf("%10d msec for searching database. [AdHoc]\n", (int)OS_TicksToMilliSeconds(profile[1]-profile[0]));
#endif
return db;
}
/* /*
(1) (1)
@ -468,3 +701,141 @@ void DHT_CheckHashPhase2ExUpdate(SVCHMACSHA1Context* ctx, const void* ptr, s32 l
SVC_HMACSHA1Update(ctx, ptr, (u32)length); SVC_HMACSHA1Update(ctx, ptr, (u32)length);
} }
} }
/*
(3)
*/
BOOL DHT_CheckHashPhase3(const u8 *hash, const NTRBannerFile* pBanner)
{
SVCHMACSHA1Context ctx;
u8 md[20];
PROFILE_INIT();
PROFILE_COUNT();
SVC_HMACSHA1Init(&ctx, hmac_key2, sizeof(hmac_key2));
// バナーの読み込み (ヘッダ)
PROFILE_COUNT();
SVC_HMACSHA1Update(&ctx, &pBanner->h, sizeof(BannerHeader));
// バナーの読み込み (ボディ)
if (pBanner->h.version == 0)
{
OS_TPrintf("Invalid banner format.\n");
return FALSE;
}
PROFILE_COUNT();
if ( pBanner->h.version >= 1 )
{
SVC_HMACSHA1Update(&ctx, &pBanner->v1, sizeof(BannerFileV1));
}
PROFILE_COUNT();
if ( pBanner->h.version >= 2 )
{
SVC_HMACSHA1Update(&ctx, &pBanner->v2, sizeof(BannerFileV2));
}
PROFILE_COUNT();
if ( pBanner->h.version >= 3 )
{
SVC_HMACSHA1Update(&ctx, &pBanner->v3, sizeof(BannerFileV3));
}
// 検証
PROFILE_COUNT();
SVC_HMACSHA1GetHash(&ctx, md);
if ( !SVC_CompareSHA1(md, hash) )
{
OS_TPrintf("\n");
OS_TPrintfEx("DB = % 20B\n", hash);
OS_TPrintfEx("HASH = % 20B\n", md);
OS_TPrintf("%s: banner_hash is not valid.\n", __func__);
return FALSE;
}
// 結果報告
#ifdef PRINT_PROFILE
PROFILE_COUNT();
OS_TPrintf("\nDone to check the hash (phase 3).\n");
OS_TPrintf("%10d msec for preparing hash.\n", (int)OS_TicksToMilliSeconds(profile[1]-profile[0]));
OS_TPrintf("%10d msec for scanning header.\n", (int)OS_TicksToMilliSeconds(profile[2]-profile[1]));
OS_TPrintf("%10d msec for scanning V1 body.\n", (int)OS_TicksToMilliSeconds(profile[3]-profile[2]));
OS_TPrintf("%10d msec for scanning V2 body.\n", (int)OS_TicksToMilliSeconds(profile[4]-profile[3]));
OS_TPrintf("%10d msec for scanning V3 body.\n", (int)OS_TicksToMilliSeconds(profile[5]-profile[4]));
OS_TPrintf("%10d msec for comparing hash.\n", (int)OS_TicksToMilliSeconds(profile[6]-profile[5]));
OS_TPrintf("\nTotal: %10d msec.\n", (int)OS_TicksToMilliSeconds(profile[6]-profile[0]));
#endif
return TRUE;
}
/*
(4)
*/
BOOL DHT_CheckHashPhase4(const DHTFileAdHoc* pDHT, const ROM_Header_Short* pROMHeader, DHTPhase4Work* work, DHTReadFunc func, void* arg)
{
imageBuffer = work->buffer;
imageReadFunc = func;
return DHT_CheckHashPhase4Ex(pDHT, pROMHeader, ImageHMACSHA1Update, arg);
}
BOOL DHT_CheckHashPhase4Ex(const DHTFileAdHoc* pDHT, const ROM_Header_Short* pROMHeader, DHTReadFuncEx funcEx, void* arg)
{
const DHTDatabaseAdHoc* plist;
SVCHMACSHA1Context ctx;
int i;
u8 md[20];
PROFILE_INIT();
if ( !funcEx || !pDHT || !pROMHeader )
{
return FALSE;
}
plist = DHT_GetDatabaseAdHoc(pDHT, pROMHeader);
if ( !plist )
{
return TRUE; // not found in individual list
}
// 準備
PROFILE_COUNT();
SVC_HMACSHA1Init(&ctx, hmac_key2, sizeof(hmac_key2));
for (i = 0; i < DHT_INDIVIDUAL_ENTRY_MAX; i++)
{
if (plist->entry[i].offset == 0)
{
break;
}
if ( !funcEx(&ctx, (s32)plist->entry[i].offset, (s32)plist->entry[i].length, arg) )
{
OS_TPrintf("Cannot read the phase 3 for %.4s(%x).\n", pROMHeader->game_code, pROMHeader->rom_version);
return FALSE;
}
}
// 検証
PROFILE_COUNT();
SVC_HMACSHA1GetHash(&ctx, md);
if ( !SVC_CompareSHA1(md, plist->hash) )
{
OS_TPrintf("\n");
OS_TPrintfEx("DB = % 20B\n", plist->hash);
OS_TPrintfEx("HASH = % 20B\n", md);
OS_TPrintf("%s: phase4list->hash is not valid.\n", __func__);
return FALSE;
}
// 結果報告
#ifdef PRINT_PROFILE
PROFILE_COUNT();
OS_TPrintf("\nDone to check the hash (phase 3).\n");
OS_TPrintf("%10d msec for preparing hash.\n", (int)OS_TicksToMilliSeconds(profile[1]-profile[0]));
OS_TPrintf("%10d msec for scanning regions.\n", (int)OS_TicksToMilliSeconds(profile[2]-profile[1]));
OS_TPrintf("%10d msec for comparing hash.\n", (int)OS_TicksToMilliSeconds(profile[3]-profile[2]));
OS_TPrintf("\nTotal: %10d msec.\n", (int)OS_TicksToMilliSeconds(profile[3]-profile[0]));
#endif
return TRUE;
}

View File

@ -62,6 +62,16 @@ include $(TWL_IPL_RED_ROOT)/build/buildtools/commondefs
ifeq ($(SYSM_DEV_WHITELIST_CHECK_SKIP),TRUE) ifeq ($(SYSM_DEV_WHITELIST_CHECK_SKIP),TRUE)
MACRO_FLAGS += -DDEV_WHITELIST_CHECK_SKIP MACRO_FLAGS += -DDEV_WHITELIST_CHECK_SKIP
else
ifeq ($(SYSM_IGNORE_DHT_PHASE_3),TRUE)
MACRO_FLAGS += -DSYSM_IGNORE_DHT_PHASE_3
endif
ifeq ($(SYSM_IGNORE_DHT_EX_NOT_FOUND),TRUE)
MACRO_FLAGS += -DSYSM_IGNORE_DHT_EX_NOT_FOUND
endif
endif endif
INSTALL_TARGETS = $(TARGETS) INSTALL_TARGETS = $(TARGETS)

View File

@ -59,7 +59,7 @@
#endif #endif
#include <sysmenu/dht/dht.h> #include <sysmenu/dht/dht.h>
#define DS_HASH_TABLE_SIZE (256*1024) #define DS_HASH_TABLE_SIZE (512*1024)
#define SYSM_TITLE_MESSAGE_ARRAY_MAX 1 #define SYSM_TITLE_MESSAGE_ARRAY_MAX 1
@ -120,9 +120,17 @@ static u8 *s_calc_hash = NULL;
static BOOL s_b_dev = FALSE; static BOOL s_b_dev = FALSE;
static BOOL s_result_phase1 = FALSE; static BOOL s_result_phase1 = FALSE;
static DHTFile *dht = NULL; static struct
static const u8* hash0 = NULL; {
static const u8* hash1 = NULL; void* buffer;
DHTFile* dht; // in buffer
DHTFileEx* dhtex; // in buffer
DHTFileAdHoc* dhtah; // in buffer
const u8* hash1;
const u8* hash2;
const u8* hash3;
}
s_dht;
// const data------------------------------------------------------------------ // const data------------------------------------------------------------------
static const OSBootType s_launcherToOSBootType[ LAUNCHER_BOOTTYPE_MAX ] = { static const OSBootType s_launcherToOSBootType[ LAUNCHER_BOOTTYPE_MAX ] = {
@ -218,35 +226,159 @@ static BOOL GetDatabaseFilepath(char *path)
return TRUE; return TRUE;
} }
static void PrepareDHTDatabase(void) // open and read every database (フェーズ4があるので常に実行すること)
static BOOL PrepareDHTDatabase(void)
{ {
char path[256]; char path[256];
if ( GetDatabaseFilepath( path ) ) int length;
{
FSFile file; FSFile file;
if ( FS_OpenFileEx(&file, path, FS_FILEMODE_R) )
if ( s_dht.buffer )
{ {
#if 0 // 1 if using attach_dummyromheader return TRUE; // already done !?
if ( FS_SeekFile(&file, sizeof(ROM_Header), FS_SEEK_SET) )
#endif
{
dht = SYSM_Alloc( DS_HASH_TABLE_SIZE );
if( dht != NULL )
{
if( DHT_PrepareDatabase(dht, &file) )
{
DC_FlushRange(dht, DHT_GetDatabaseLength(dht));
FS_CloseFile(&file);
return;
}
}
}
FS_CloseFile(&file);
}
} }
MI_CpuClear8(dht, sizeof(DHTHeader)); if ( !GetDatabaseFilepath( path ) )
dht = NULL; {
OS_TPrintf("PrepareDHTDatabase failed: DHT file is not found.\n");
if(!s_b_dev) {
ERRORLOG_Printf( "WHITELIST_INITDB_FAILED (sub info): DHT file is not found.\n" );
}
return FALSE; // database was not found
}
if ( !FS_OpenFileEx(&file, path, FS_FILEMODE_R) )
{
OS_TPrintf("PrepareDHTDatabase failed: DHT file cannot open.\n");
if(!s_b_dev) {
ERRORLOG_Printf( "WHITELIST_INITDB_FAILED (sub info): DHT file cannot open.\n" );
}
return FALSE; // cannot open the file
}
length = (int)FS_GetFileLength(&file);
if ( length > DS_HASH_TABLE_SIZE )
{
OS_TPrintf("PrepareDHTDatabase failed: DHT file size (%d) is too large.\n", length );
if(!s_b_dev) {
ERRORLOG_Printf( "WHITELIST_INITDB_FAILED (sub info): DHT file size (%d) is too large.\n", length );
}
FS_CloseFile(&file);
return FALSE; // too large
}
#if 0 // 1 if using attach_dummyromheader
if ( FS_SeekFile(&file, sizeof(ROM_Header), FS_SEEK_SET) )
{
OS_TPrintf("PrepareDHTDatabase failed: DHT file size (%d) is too small.\n", length );
if(!s_b_dev) {
ERRORLOG_Printf( "WHITELIST_INITDB_FAILED (sub info): DHT file size (%d) is too small.\n", length );
}
SYSM_Free( s_dht.buffer );
s_dht.buffer = NULL;
FS_CloseFile(&file);
return FALSE;
}
#endif
s_dht.buffer = SYSM_Alloc( (u32)length );
if ( !s_dht.buffer )
{
OS_TPrintf("PrepareDHTDatabase failed: cannot allocate %d bytes for buffer.\n", length );
if(!s_b_dev) {
ERRORLOG_Printf( "WHITELIST_INITDB_FAILED (sub info): cannot allocate %d bytes for buffer.\n", length );
}
FS_CloseFile(&file);
return FALSE; // cannot allocate the memory
}
// 基本データベース
s_dht.dht = s_dht.buffer;
if ( sizeof(DHTHeader) != FS_ReadFile(&file, &s_dht.dht->header, sizeof(DHTHeader)) )
{
OS_TPrintf("PrepareDHTDatabase failed: cannot read DHTHeader for phase 1/2.\n" );
if(!s_b_dev) {
ERRORLOG_Printf( "WHITELIST_INITDB_FAILED (sub info): cannot read DHTHeader for phase 1/2.\n" );
}
SYSM_Free( s_dht.buffer );
s_dht.buffer = NULL;
FS_CloseFile(&file);
return FALSE; // cannot read the file
}
length = (int)DHT_GetDatabaseLength(s_dht.dht) - (int)sizeof(DHTHeader);
if ( length < 0 || length != FS_ReadFile(&file, &s_dht.dht->database, length) )
{
OS_TPrintf("PrepareDHTDatabase failed: cannot read DHTDatabase for phase 1/2.\n" );
if(!s_b_dev) {
ERRORLOG_Printf( "WHITELIST_INITDB_FAILED (sub info): cannot read DHTDatabase for phase 1/2.\n" );
}
s_dht.dht = NULL;
SYSM_Free( s_dht.buffer );
s_dht.buffer = NULL;
FS_CloseFile(&file);
return FALSE; // cannot read the file
}
// 拡張データベース
s_dht.dhtex = (void*)((u32)s_dht.buffer + DHT_GetDatabaseLength(s_dht.dht));
if ( sizeof(DHTHeader) != FS_ReadFile(&file, &s_dht.dhtex->header, sizeof(DHTHeader)) )
{
s_dht.dhtex = NULL;
OS_TPrintf("PrepareDHTDatabase failed: cannot read DHTHeader for phase 3.\n" );
FS_CloseFile(&file);
#ifndef SYSM_IGNORE_DHT_EX_NOT_FOUND
if(!s_b_dev) {
ERRORLOG_Printf( "WHITELIST_INITDB_FAILED (sub info): cannot read DHTHeader for phase 3.\n" );
}
SYSM_Free( s_dht.buffer );
s_dht.buffer = NULL;
return FALSE; // cannot read the file
#else
return TRUE;
#endif
}
length = (int)DHT_GetDatabaseExLength(s_dht.dhtex) - (int)sizeof(DHTHeader);
if ( length < 0 || length != FS_ReadFile(&file, &s_dht.dhtex->database, length) )
{
s_dht.dhtex = NULL;
OS_TPrintf("PrepareDHTDatabase failed: cannot read DHTDatabaseEx for phase 3.\n" );
FS_CloseFile(&file);
#ifndef SYSM_IGNORE_DHT_EX_NOT_FOUND
if(!s_b_dev) {
ERRORLOG_Printf( "WHITELIST_INITDB_FAILED (sub info): cannot read DHTDatabaseEx for phase 3.\n" );
}
SYSM_Free( s_dht.buffer );
s_dht.buffer = NULL;
return FALSE; // cannot read the file
#else
return TRUE;
#endif
}
// 個別対応データベース
s_dht.dhtah = (void*)((u32)s_dht.buffer + DHT_GetDatabaseExLength(s_dht.dhtex));
if ( sizeof(DHTHeader) != FS_ReadFile(&file, &s_dht.dhtah->header, sizeof(DHTHeader)) )
{
s_dht.dhtah = NULL;
OS_TPrintf("PrepareDHTDatabase failed: cannot read DHTHeader for phase 4.\n" );
FS_CloseFile(&file);
if(!s_b_dev) {
ERRORLOG_Printf( "WHITELIST_INITDB_FAILED (sub info): cannot read DHTHeader for phase 4.\n" );
}
SYSM_Free( s_dht.buffer );
s_dht.buffer = NULL;
return FALSE; // phase 3が読めてphase4が読めないことはあり得ない
}
length = (int)DHT_GetDatabaseAdHocLength(s_dht.dhtah) - (int)sizeof(DHTHeader);
if ( length < 0 || length != FS_ReadFile(&file, &s_dht.dhtah->database, length) )
{
s_dht.dhtah = NULL;
OS_TPrintf("PrepareDHTDatabase failed: cannot read DHTDatabaseAdHoc for phase 4.\n" );
FS_CloseFile(&file);
if(!s_b_dev) {
ERRORLOG_Printf( "WHITELIST_INITDB_FAILED (sub info): cannot read DHTDatabaseAdHoc for phase 4.\n" );
}
SYSM_Free( s_dht.buffer );
s_dht.buffer = NULL;
return FALSE; // phase 3が読めてphase4が読めないことはあり得ない
}
FS_CloseFile(&file);
return TRUE;
} }
static BOOL WrapperFunc_ReadCardData(void* dest, s32 offset, s32 length, void* arg) static BOOL WrapperFunc_ReadCardData(void* dest, s32 offset, s32 length, void* arg)
@ -1422,49 +1554,101 @@ static BOOL SYSMi_AuthenticateNTRCardAppHeader( TitleProperty *pBootTitle, ROM_H
OS_TPrintf( "Authenticate_Header : header TitleID check succeed.\n" ); OS_TPrintf( "Authenticate_Header : header TitleID check succeed.\n" );
} }
// phase 4があるので常に読み込む
if ( !PrepareDHTDatabase() )
{
OS_TPrintf(" SYSMi_AuthenticateNTRCardAppHeader failed : database init error.\n");
if(!s_b_dev)
{
UTL_SetFatalError(FATAL_ERROR_WHITELIST_INITDB_FAILED);
return FALSE;
}
}
// マスタリングの有無
if( head->s.exFlags.enable_nitro_whitelist_signature ) if( head->s.exFlags.enable_nitro_whitelist_signature )
{ {
// マスタリング済みNTRカードアプリの署名チェック実はTWLアプリと同じ // マスタリング済みNTRカードアプリの署名チェック実はTWLアプリと同じ
ret = SYSMi_AuthenticateHeaderWithSign( pBootTitle, head ); ret = SYSMi_AuthenticateHeaderWithSign( pBootTitle, head );
if( ret == TRUE ) if( ret == TRUE )
{ {
hash0 = head->s.nitro_whitelist_phase1_digest; s_dht.hash1 = head->s.nitro_whitelist_phase1_digest;
hash1 = head->s.nitro_whitelist_phase2_diegst; s_dht.hash2 = head->s.nitro_whitelist_phase2_diegst;
// 新マスタリングの有無
if( head->s.exFlags.enable_nitro_extra_whitelist )
{
s_dht.hash3 = head->s.banner_digest;
}
} }
}else }else
{ {
// ホワイトリスト検索 // ホワイトリスト検索
const DHTDatabase* db; const DHTDatabase* db;
PrepareDHTDatabase();// 60msくらいなので、ここでやってしまってOKとする。 if(!s_dht.dht)
if(!dht)
{ {
OS_TPrintf(" Search DHT : database init Failed.\n"); OS_TPrintf(" Search DHT : database init Failed.\n");
if(!s_b_dev) if(!s_b_dev)
{ {
ERRORLOG_Printf( "WHITELIST_INITDB_FAILED (sub info): whitelist for phase 1/2 was not loaded.\n" );
UTL_SetFatalError(FATAL_ERROR_WHITELIST_INITDB_FAILED); UTL_SetFatalError(FATAL_ERROR_WHITELIST_INITDB_FAILED);
ret = FALSE; ret = FALSE;
} }
}else }else
{ {
OS_TPrintf("Searching DHT for %.4s(%02X)...", head->s.game_code, head->s.rom_version); OS_TPrintf("Searching DHT for %.4s(%02X)...", head->s.game_code, head->s.rom_version);
db = DHT_GetDatabase(dht, &head->s); db = DHT_GetDatabase(s_dht.dht, &head->s);
if ( !db ) if ( !db )
{ {
OS_TPrintf(" Search DHT : Failed.\n"); OS_TPrintf(" Search DHT : Failed.\n");
if(!s_b_dev) if(!s_b_dev)
{ {
ERRORLOG_Printf( "WHITELIST_NOTFOUND (sub info): no entry for phase 1/2.\n" );
UTL_SetFatalError(FATAL_ERROR_WHITELIST_NOTFOUND); UTL_SetFatalError(FATAL_ERROR_WHITELIST_NOTFOUND);
ret = FALSE; ret = FALSE;
} }
}else }else
{ {
hash0 = db->hash[0]; s_dht.hash1 = db->hash[0];
hash1 = db->hash[1]; s_dht.hash2 = db->hash[1];
ret = TRUE;
}
}
}
// ROMヘッダにバナーハッシュがない (マスタリング自体とは別枠)
if( !s_dht.hash3 )
{
// 拡張ホワイトリスト検索
const DHTDatabaseEx* db;
if(!s_dht.dhtex)
{
OS_TPrintf(" Search DHT Ex: database init Failed.\n");
if(!s_b_dev)
{
#ifndef SYSM_IGNORE_DHT_EX_NOT_FOUND
ERRORLOG_Printf( "WHITELIST_INITDB_FAILED (sub info): whitelist for phase 3 was not loaded.\n" );
UTL_SetFatalError(FATAL_ERROR_WHITELIST_INITDB_FAILED);
ret = FALSE;
#endif
}
}else
{
OS_TPrintf("Searching DHT Ex for %.4s(%02X)...", head->s.game_code, head->s.rom_version);
db = DHT_GetDatabaseEx(s_dht.dhtex, &head->s);
if ( !db )
{
OS_TPrintf(" Search DHT Ex: Failed.\n");
if(!s_b_dev)
{
ERRORLOG_Printf( "WHITELIST_NOTFOUND (sub info): no entry for phase 3.\n" );
UTL_SetFatalError(FATAL_ERROR_WHITELIST_NOTFOUND);
ret = FALSE;
}
}else
{
s_dht.hash3 = db->banner_hash;
ret = TRUE; ret = TRUE;
} }
} }
} }
return ret; return ret;
} }
@ -1475,21 +1659,23 @@ static BOOL SYSMi_AuthenticateNTRCardTitle( TitleProperty *pBootTitle)
DHTPhase2Work* p2work = NULL; DHTPhase2Work* p2work = NULL;
ROM_Header_Short *hs = ( ROM_Header_Short *)SYSM_APP_ROM_HEADER_BUF; ROM_Header_Short *hs = ( ROM_Header_Short *)SYSM_APP_ROM_HEADER_BUF;
// phase1最終検証 // DHTチェックphase1
if(s_calc_hash) if(s_calc_hash)
{ {
// アプリをロードする時に計算したハッシュを検証 // アプリをロードする時に計算したハッシュを検証
if( !hash0 || !SVC_CompareSHA1( (const void *)hash0, (const void *)&s_calc_hash[1 * SVC_SHA1_DIGEST_SIZE] ) ) if( !s_dht.hash1 || !SVC_CompareSHA1( (const void *)s_dht.hash1, (const void *)&s_calc_hash[1 * SVC_SHA1_DIGEST_SIZE] ) )
{ {
OS_TPrintf("DHT Phase1 failed: hash check failed.\n"); OS_TPrintf("DHT Phase1 failed: hash check failed.\n");
if(!s_b_dev) { if(!s_b_dev) {
// デバグ用。ERRORLOG_Init()がすでに呼ばれている事前提 // デバグ用。ERRORLOG_Init()がすでに呼ばれている事前提
ERRORLOG_Printf( "DHT_PAHSE1_FAILED (sub info): hash0Addr-%08x\n", hash0 ); ERRORLOG_Printf( "DHT_PAHSE1_FAILED (sub info): hash1Addr-%08x\n", s_dht.hash1 );
if(hash0) if(s_dht.hash1)
{ {
ERRORLOG_Printf( "DHT_PAHSE1_FAILED (sub info): hash0 - %02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x\n", ERRORLOG_Printf( "DHT_PAHSE1_FAILED (sub info): hash1 - %02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x\n",
hash0[0], hash0[1], hash0[2], hash0[3], hash0[4], hash0[5], hash0[6], hash0[7], hash0[8], hash0[9], s_dht.hash1[0], s_dht.hash1[1], s_dht.hash1[2], s_dht.hash1[3], s_dht.hash1[4],
hash0[10], hash0[11], hash0[12], hash0[13], hash0[14], hash0[15], hash0[16], hash0[17], hash0[18], hash0[19]); s_dht.hash1[5], s_dht.hash1[6], s_dht.hash1[7], s_dht.hash1[8], s_dht.hash1[9],
s_dht.hash1[10], s_dht.hash1[11], s_dht.hash1[12], s_dht.hash1[13], s_dht.hash1[14],
s_dht.hash1[15], s_dht.hash1[16], s_dht.hash1[17], s_dht.hash1[18], s_dht.hash1[19]);
ERRORLOG_Printf( "DHT_PAHSE1_FAILED (sub info): calc_hash - %02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x\n", ERRORLOG_Printf( "DHT_PAHSE1_FAILED (sub info): calc_hash - %02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x\n",
s_calc_hash[0], s_calc_hash[1], s_calc_hash[2], s_calc_hash[3], s_calc_hash[4], s_calc_hash[0], s_calc_hash[1], s_calc_hash[2], s_calc_hash[3], s_calc_hash[4],
s_calc_hash[5], s_calc_hash[6], s_calc_hash[7], s_calc_hash[8], s_calc_hash[9], s_calc_hash[5], s_calc_hash[6], s_calc_hash[7], s_calc_hash[8], s_calc_hash[9],
@ -1515,18 +1701,75 @@ static BOOL SYSMi_AuthenticateNTRCardTitle( TitleProperty *pBootTitle)
// DHTチェックphase2 // DHTチェックphase2
OS_TPrintf("DHT Phase2..."); OS_TPrintf("DHT Phase2...");
p2work = SYSM_Alloc( sizeof(DHTPhase2Work) ); p2work = SYSM_Alloc( sizeof(DHTPhase2Work) );
if ( !p2work || !hash1 || !DHT_CheckHashPhase2(hash1, hs, p2work, WrapperFunc_ReadCardData, NULL) ) if ( !p2work )
{
OS_TPrintf(" Cannot allocate DHT work area.\n");
if (!s_b_dev){
// デバグ用。ERRORLOG_Init()がすでに呼ばれている事前提
ERRORLOG_Printf( "DHT_PAHSE2_FAILED (sub info): p2workAddr-%08x hash2Addr-%08x\n", p2work, s_dht.hash2 );
UTL_SetFatalError(FATAL_ERROR_DHT_PHASE2_FAILED);
return FALSE;
}
return TRUE;
}
if ( !s_dht.hash2 || !DHT_CheckHashPhase2(s_dht.hash2, hs, p2work, WrapperFunc_ReadCardData, NULL) )
{ {
OS_TPrintf(" DHT Phase2 : Failed.\n"); OS_TPrintf(" DHT Phase2 : Failed.\n");
if(!s_b_dev){ if(!s_b_dev){
// デバグ用。ERRORLOG_Init()がすでに呼ばれている事前提 // デバグ用。ERRORLOG_Init()がすでに呼ばれている事前提
ERRORLOG_Printf( "DHT_PAHSE2_FAILED (sub info): p2workAddr-%08x hash1Addr-%08x\n", p2work, hash1 ); ERRORLOG_Printf( "DHT_PAHSE2_FAILED (sub info): p2workAddr-%08x hash2Addr-%08x\n", p2work, s_dht.hash2 );
if( p2work ) SYSM_Free(p2work); SYSM_Free(p2work);
UTL_SetFatalError(FATAL_ERROR_DHT_PHASE2_FAILED); UTL_SetFatalError(FATAL_ERROR_DHT_PHASE2_FAILED);
return FALSE; return FALSE;
} }
} }
if( p2work ) SYSM_Free(p2work);
// DHTチェックphase3 (バナーチェック)
OS_TPrintf("DHT Phase3...");
if ( !s_dht.hash3 || !DHT_CheckHashPhase3(s_dht.hash3, (NTRBannerFile*)&s_card_bannerBuf) )
{
OS_TPrintf(" DHT Phase3 : Failed.\n");
if(!s_b_dev){
// デバグ用。ERRORLOG_Init()がすでに呼ばれている事前提
ERRORLOG_Printf( "DHT_PAHSE3_FAILED (sub info): hash3Addr-%08x\n", s_dht.hash3 );
#ifndef SYSM_IGNORE_DHT_EX_NOT_FOUND
#ifndef SYSM_IGNORE_DHT_PHASE_3
SYSM_Free(p2work);
UTL_SetFatalError(FATAL_ERROR_DHT_PHASE3_FAILED);
return FALSE;
#endif
#endif
}
}
// DHTチェックphase4 (個別チェック)
OS_TPrintf("DHT Phase4...");
if ( !s_dht.dhtah )
{
OS_TPrintf(" DHT Phase4 : No database.\n");
if(!s_b_dev){
// デバグ用。ERRORLOG_Init()がすでに呼ばれている事前提
ERRORLOG_Printf( "DHT_PAHSE4_FAILED (sub info): no database\n" );
#ifndef SYSM_IGNORE_DHT_EX_NOT_FOUND
SYSM_Free(p2work);
UTL_SetFatalError(FATAL_ERROR_DHT_PHASE4_FAILED);
return FALSE;
#endif
}
}
else if ( !DHT_CheckHashPhase4(s_dht.dhtah, hs, (DHTPhase4Work*)p2work, WrapperFunc_ReadCardData, NULL) )
{
OS_TPrintf(" DHT Phase4 : Failed.\n");
if(!s_b_dev){
// デバグ用。ERRORLOG_Init()がすでに呼ばれている事前提
ERRORLOG_Printf( "DHT_PAHSE4_FAILED (sub info): p2workAddr-%08x\n", p2work );
SYSM_Free(p2work);
UTL_SetFatalError(FATAL_ERROR_DHT_PHASE4_FAILED);
return FALSE;
}
}
SYSM_Free(p2work);
return TRUE; return TRUE;
} }
@ -1678,9 +1921,9 @@ static void SYSMi_AuthenticateTitleThreadFunc( TitleProperty *pBootTitle )
// ロード成功? // ロード成功?
if( SYSMi_GetWork()->flags.arm9.isLoadSucceeded == FALSE ) if( SYSMi_GetWork()->flags.arm9.isLoadSucceeded == FALSE )
{ {
UTL_SetFatalError(FATAL_ERROR_TITLE_LOAD_FAILED);
// デバグ用。ERRORLOG_Init()がすでに呼ばれている事前提 // デバグ用。ERRORLOG_Init()がすでに呼ばれている事前提
ERRORLOG_Printf( "SYSMi_AuthenticateTitleThreadFunc: loaded %d times.\n", s_loadTimes ); ERRORLOG_Printf( "SYSMi_AuthenticateTitleThreadFunc: loaded %d times.\n", s_loadTimes );
UTL_SetFatalError(FATAL_ERROR_TITLE_LOAD_FAILED);
return; return;
} }
// パラメータチェック // パラメータチェック
@ -1831,11 +2074,11 @@ void SYSM_TryToBootTitle( TitleProperty *pBootTitle )
s_calc_hash = NULL; s_calc_hash = NULL;
} }
if(dht) if(s_dht.buffer)
{ {
// dht用バッファが確保されていたら解放 // DHT用バッファが確保されていたら解放
SYSM_Free( dht ); SYSM_Free( s_dht.buffer );
dht = NULL; s_dht.buffer = NULL;
} }
// ダイレクトブート時など、まだSystemMenuVersionのデータがセットされていない場合は、ここでセットする。 // ダイレクトブート時など、まだSystemMenuVersionのデータがセットされていない場合は、ここでセットする。

Binary file not shown.

Binary file not shown.

View File

@ -27,6 +27,8 @@ include $(TWL_IPL_RED_ROOT)/build/buildtools/commondefs
include ./commondefs.DSHashTable include ./commondefs.DSHashTable
MY_DATA = $(DS_HASH_TABLE_DATA) MY_DATA = $(DS_HASH_TABLE_DATA)
MY_DATA_EX = $(DS_HASH_TABLE_EX_DATA)
MY_DATA_ADHOC = $(DS_HASH_TABLE_ADHOC_DATA)
MY_APPEND = revision.bin MY_APPEND = revision.bin
MY_DATA2 = data.bin MY_DATA2 = data.bin
@ -49,8 +51,8 @@ do-build : $(MY_TAD)
$(MY_TAD): $(MY_DATA2) $(MY_TAD): $(MY_DATA2)
$(MAKETAD) $(call empath,$<) $(DS_HASH_TABLE_MAKETAD_OPTION) -o $@ $(MAKETAD) $(call empath,$<) $(DS_HASH_TABLE_MAKETAD_OPTION) -o $@
$(MY_DATA2): $(MY_DATA) $(MY_APPEND) $(MY_DATA2): $(MY_DATA) $(MY_DATA_EX) $(MY_DATA_ADHOC) $(MY_APPEND)
cat $(MY_DATA) $(MY_APPEND) > $@ cat $(MY_DATA) $(MY_DATA_EX) $(MY_DATA_ADHOC) $(MY_APPEND) > $@
$(MY_APPEND):: $(MY_APPEND)::
@if test -e $(SYSMENU_ROOT)/.svn; then \ @if test -e $(SYSMENU_ROOT)/.svn; then \

View File

@ -17,8 +17,12 @@
#---------------------------------------------------------------------------- #----------------------------------------------------------------------------
DS_HASH_TABLE_TITLE_NAME := DSHashTable DS_HASH_TABLE_TITLE_NAME := DSHashTable
DS_HASH_TABLE_EX_TITLE_NAME := DSHashTableEx
DS_HASH_TABLE_ADHOC_TITLE_NAME:= DSHashTableAdHoc
DS_HASH_TABLE_DATA_DIR := $(SYSMENU_ROOT)/build/systemMenu_RED/DSHashTable DS_HASH_TABLE_DATA_DIR := $(SYSMENU_ROOT)/build/systemMenu_RED/DSHashTable
DS_HASH_TABLE_DATA := $(DS_HASH_TABLE_DATA_DIR)/$(DS_HASH_TABLE_TITLE_NAME).bin DS_HASH_TABLE_DATA := $(DS_HASH_TABLE_DATA_DIR)/$(DS_HASH_TABLE_TITLE_NAME).bin
DS_HASH_TABLE_EX_DATA := $(DS_HASH_TABLE_DATA_DIR)/$(DS_HASH_TABLE_EX_TITLE_NAME).bin
DS_HASH_TABLE_ADHOC_DATA := $(DS_HASH_TABLE_DATA_DIR)/$(DS_HASH_TABLE_ADHOC_TITLE_NAME).bin
DS_HASH_TABLE_TITLE := HNHA DS_HASH_TABLE_TITLE := HNHA
DS_HASH_TABLE_TITLE_ID_HI := 0003000F DS_HASH_TABLE_TITLE_ID_HI := 0003000F
DS_HASH_TABLE_TITLE_ID_LO := $(shell perl -e 'printf "%02X%02X%02X%02X", unpack("C4", "'$(DS_HASH_TABLE_TITLE)'")') DS_HASH_TABLE_TITLE_ID_LO := $(shell perl -e 'printf "%02X%02X%02X%02X", unpack("C4", "'$(DS_HASH_TABLE_TITLE)'")')
@ -32,7 +36,7 @@ DS_HASH_TABLE_VERSION := $(shell perl -e 'open IN, "$(DS_HASH_TABLE_D
#DS_HASH_TABLE_MINOR_VERSION := $(shell expr $(DS_HASH_TABLE_VERSION) % 256) #DS_HASH_TABLE_MINOR_VERSION := $(shell expr $(DS_HASH_TABLE_VERSION) % 256)
DS_HASH_TABLE_MAJOR_VERSION := 0 DS_HASH_TABLE_MAJOR_VERSION := 0
DS_HASH_TABLE_MINOR_VERSION := 0 DS_HASH_TABLE_MINOR_VERSION := 1
DS_HASH_TABLE_MAKETAD_OPTION := -s -d $(DS_HASH_TABLE_TITLE_ID) $(DS_HASH_TABLE_GROUP_ID) $(DS_HASH_TABLE_MAJOR_VERSION) $(DS_HASH_TABLE_TITLE_NAME) \ DS_HASH_TABLE_MAKETAD_OPTION := -s -d $(DS_HASH_TABLE_TITLE_ID) $(DS_HASH_TABLE_GROUP_ID) $(DS_HASH_TABLE_MAJOR_VERSION) $(DS_HASH_TABLE_TITLE_NAME) \
-v $(DS_HASH_TABLE_MINOR_VERSION) -p -v $(DS_HASH_TABLE_MINOR_VERSION) -p

View File

@ -123,7 +123,9 @@ static const char *fatal_error_msg[FATAL_ERROR_MAX] =
"LOAD_AUTH_HEADER_FAILED", "LOAD_AUTH_HEADER_FAILED",
"LOAD_NEVER_STARTED", "LOAD_NEVER_STARTED",
"EJECT_CARD_AFTER_LOAD_START", "EJECT_CARD_AFTER_LOAD_START",
"TITLEID_COMPARE_FAILED_NTR" "TITLEID_COMPARE_FAILED_NTR",
"DHT_PHASE3_FAILED",
"DHT_PHASE4_FAILED"
}; };
//#define DEBUG_LAUNCHER_DUMP //#define DEBUG_LAUNCHER_DUMP

View File

@ -2,7 +2,7 @@
Project: TwlIPL - DHT Project: TwlIPL - DHT
File: dht.h File: dht.h
Copyright 2008 Nintendo. All rights reserved. Copyright 2008,2009 Nintendo. All rights reserved.
These coded instructions, statements, and computer programs contain These coded instructions, statements, and computer programs contain
proprietary information of Nintendo of America Inc. and/or Nintendo proprietary information of Nintendo of America Inc. and/or Nintendo
@ -17,13 +17,28 @@
#ifndef SYSMENU_DHT_H_ #ifndef SYSMENU_DHT_H_
#define SYSMENU_DHT_H_ #define SYSMENU_DHT_H_
/*
Phase
Phase1 DHTDatabase->hash[0] ROM_Header_Short->nitro_whitelist_phase1_digest
Phase2 DHTDatabase->hash[1] ROM_Header_Short->nitro_whitelist_phase2_digest
Phase3 DHTDatabaseEx->banner_hash ROM_Header_Short->banner_digest
Phase4 - -
Phase4のハッシュ値はdht_phase4_list.cに含まれる
*/
#include <twl/types.h> #include <twl/types.h>
#include <twl/os/common/format_rom.h> #include <twl/os/common/format_rom.h>
#include <sysmenu/dht/dht_format.h> #include <sysmenu/dht/dht_format.h>
#define nitro_whitelist_phase2_digest nitro_whitelist_phase2_diegst // for spell miss
#define DHT_FAT_PAGE_SIZE 512 #define DHT_FAT_PAGE_SIZE 512
#define DHT_FAT_CACHE_SIZE (DHT_FAT_PAGE_SIZE * 2) #define DHT_FAT_CACHE_SIZE (DHT_FAT_PAGE_SIZE * 2)
#define DHT_PHASE3_MAX DHT_OVERLAY_MAX
/* /*
DHT_CheckHashPhase2で必要なワークメモリ DHT_CheckHashPhase2で必要なワークメモリ
*/ */
@ -34,6 +49,17 @@ typedef struct DHTPhase2Work
} }
DHTPhase2Work; DHTPhase2Work;
/*
DHT_CheckHashPhase4で必要なワークメモリ
(DHTPhase4Work <= DHTPhase2Workが必ず成り立つ)
*/
typedef struct DHTPhase4Work
{
u32 buffer[DHT_PHASE3_MAX/sizeof(u32)];
}
DHTPhase4Work;
/* /*
DHT_CheckHashPhase2Exで必要なワークメモリ DHT_CheckHashPhase2Exで必要なワークメモリ
*/ */
@ -48,7 +74,7 @@ extern "C" {
#endif #endif
/* /*
DHT_CheckHashPhase2/DHT_CheckHashPhase2Exで使用するRead関数 DHT_CheckHashPhase2/DHT_CheckHashPhase2Ex/DHT_CheckHashPhase4で使用するRead関数
dest dest
offset ROMオフセット offset ROMオフセット
length length
@ -59,7 +85,7 @@ extern "C" {
typedef BOOL (*DHTReadFunc)(void* dest, s32 offset, s32 length, void* arg); typedef BOOL (*DHTReadFunc)(void* dest, s32 offset, s32 length, void* arg);
/* /*
DHT_CheckHashPhase2Exで使用するRead関数 DHT_CheckHashPhase2Ex/DHT_CheckHashPhase4Exで使用するRead関数
DHT_CheckHashPhase2ExUpdateを呼び出すこと() DHT_CheckHashPhase2ExUpdateを呼び出すこと()
ctx DHT_CheckHashPhase2ExUpdateに渡す引数 ctx DHT_CheckHashPhase2ExUpdateに渡す引数
@ -71,7 +97,7 @@ typedef BOOL (*DHTReadFunc)(void* dest, s32 offset, s32 length, void* arg);
*/ */
typedef BOOL (*DHTReadFuncEx)(SVCHMACSHA1Context* ctx, s32 offset, s32 length, void* arg); typedef BOOL (*DHTReadFuncEx)(SVCHMACSHA1Context* ctx, s32 offset, s32 length, void* arg);
/*---------------------------------------------------------------------------* /*---------------------------------------------------------------------------*
Name: DHT_PrepareDatabase Name: DHT_GetDatabaseLength
Description: Description:
@ -81,12 +107,34 @@ typedef BOOL (*DHTReadFuncEx)(SVCHMACSHA1Context* ctx, s32 offset, s32 length
*---------------------------------------------------------------------------*/ *---------------------------------------------------------------------------*/
u32 DHT_GetDatabaseLength(const DHTFile* pDHT); u32 DHT_GetDatabaseLength(const DHTFile* pDHT);
/*---------------------------------------------------------------------------*
Name: DHT_GetDatabaseExLength
Description:
Arguments: pDHT
Returns: 0
*---------------------------------------------------------------------------*/
u32 DHT_GetDatabaseExLength(const DHTFileEx* pDHT);
/*---------------------------------------------------------------------------*
Name: DHT_GetDatabaseAdHocLength
Description:
Arguments: pDHT
Returns: 0
*---------------------------------------------------------------------------*/
u32 DHT_GetDatabaseAdHocLength(const DHTFileAdHoc* pDHT);
/*---------------------------------------------------------------------------* /*---------------------------------------------------------------------------*
Name: DHT_PrepareDatabase Name: DHT_PrepareDatabase
Description: FS関数を利用して全データベースを読み込みと検証を行う Description: FS関数を利用してデータベースを読み込みと検証を行う
Arguments: pDHT Arguments: pDHT
fp fp
DHTHeaderの先頭までシーク済みである必要がある DHTHeaderの先頭までシーク済みである必要がある
@ -94,18 +142,56 @@ u32 DHT_GetDatabaseLength(const DHTFile* pDHT);
*---------------------------------------------------------------------------*/ *---------------------------------------------------------------------------*/
BOOL DHT_PrepareDatabase(DHTFile* pDHT, FSFile* fp); BOOL DHT_PrepareDatabase(DHTFile* pDHT, FSFile* fp);
/*---------------------------------------------------------------------------*
Name: DHT_PrepareDatabaseEx
Description: FS関数を利用して拡張データベースを読み込みと検証を行う
Arguments: pDHT
fp
DHTHeaderの先頭までシーク済みである必要がある
Returns: TRUE
*---------------------------------------------------------------------------*/
BOOL DHT_PrepareDatabaseEx(DHTFileEx* pDHT, FSFile* fp);
/*---------------------------------------------------------------------------*
Name: DHT_PrepareDatabaseAdHoc
Description: FS関数を利用して個別対応データベースを読み込みと検証を行う
Arguments: pDHT
fp
DHTHeaderの先頭までシーク済みである必要がある
Returns: TRUE
*---------------------------------------------------------------------------*/
BOOL DHT_PrepareDatabaseAdHoc(DHTFileAdHoc* pDHT, FSFile* fp);
/*---------------------------------------------------------------------------* /*---------------------------------------------------------------------------*
Name: DHT_GetDatabase Name: DHT_GetDatabase
Description: ROMヘッダに対応するデータベースを検索する Description: ROMヘッダに対応するデータベースを検索する
Arguments: pDHT Arguments: pDHT
pROMHeader ROMヘッダ格納先 pROMHeader ROMヘッダ格納先
Returns: Returns: NULL
*---------------------------------------------------------------------------*/ *---------------------------------------------------------------------------*/
const DHTDatabase* DHT_GetDatabase(const DHTFile* pDHT, const ROM_Header_Short* pROMHeader); const DHTDatabase* DHT_GetDatabase(const DHTFile* pDHT, const ROM_Header_Short* pROMHeader);
/*---------------------------------------------------------------------------*
Name: DHT_GetDatabaseEx
Description: ROMヘッダに対応する拡張データベースを検索する
Arguments: pDHT
pROMHeader ROMヘッダ格納先
Returns: NULL
*---------------------------------------------------------------------------*/
const DHTDatabaseEx* DHT_GetDatabaseEx(const DHTFileEx* pDHT, const ROM_Header_Short* pROMHeader);
/*---------------------------------------------------------------------------* /*---------------------------------------------------------------------------*
Name: DHT_CheckHashPhase1Init Name: DHT_CheckHashPhase1Init
@ -178,7 +264,6 @@ BOOL DHT_CheckHashPhase2(const u8* hash, const ROM_Header_Short* pROMHeader, DHT
Name: DHT_CheckHashPhase2Ex Name: DHT_CheckHashPhase2Ex
Description: Description:
(Read APIを登録できるべき)
Arguments: hash (db->hash[1]) Arguments: hash (db->hash[1])
pROMHeader ROMヘッダ格納先 pROMHeader ROMヘッダ格納先
@ -193,10 +278,11 @@ BOOL DHT_CheckHashPhase2(const u8* hash, const ROM_Header_Short* pROMHeader, DHT
BOOL DHT_CheckHashPhase2Ex(const u8* hash, const ROM_Header_Short* pROMHeader, DHTPhase2ExWork* work, DHTReadFunc func, DHTReadFuncEx funcEx, void* arg); BOOL DHT_CheckHashPhase2Ex(const u8* hash, const ROM_Header_Short* pROMHeader, DHTPhase2ExWork* work, DHTReadFunc func, DHTReadFuncEx funcEx, void* arg);
/*---------------------------------------------------------------------------* /*---------------------------------------------------------------------------*
Name: DHT_CheckHashPhase2ExUpdate Name: DHT_CheckHashPhase2ExUpdate / DHT_CheckHashPhase4ExUpdate
Description: Description:
DHTReadFuncExから呼び出すこと() DHTReadFuncExから呼び出すこと()
: Phase4でも流用している
Arguments: ctx SVCHMACSHA1コンテキスト Arguments: ctx SVCHMACSHA1コンテキスト
ptr ptr
@ -205,6 +291,51 @@ BOOL DHT_CheckHashPhase2Ex(const u8* hash, const ROM_Header_Short* pROMHeader, D
Returns: None Returns: None
*---------------------------------------------------------------------------*/ *---------------------------------------------------------------------------*/
void DHT_CheckHashPhase2ExUpdate(SVCHMACSHA1Context* ctx, const void* ptr, s32 length); void DHT_CheckHashPhase2ExUpdate(SVCHMACSHA1Context* ctx, const void* ptr, s32 length);
#define DHT_CheckHashPhase4ExUpdate DHT_CheckHashPhase2ExUpdate
/*---------------------------------------------------------------------------*
Name: DHT_CheckHashPhase3
Description:
(使)
Arguments: hash (dbex->banner_hash)
pBanner
Returns: TRUE
*---------------------------------------------------------------------------*/
BOOL DHT_CheckHashPhase3(const u8* hash, const NTRBannerFile* pBanner);
/*---------------------------------------------------------------------------*
Name: DHT_CheckHashPhase4
Description:
Arguments: pDHT
pROMHeader ROMヘッダ格納先
work APIで使用するワーク (512KB)
phase2の使い回しでOK
func Read関数
arg Read関数に渡される引数
Returns: TRUE
*---------------------------------------------------------------------------*/
BOOL DHT_CheckHashPhase4(const DHTFileAdHoc* pDHT, const ROM_Header_Short* pROMHeader, DHTPhase4Work* work, DHTReadFunc func, void* arg);
/*---------------------------------------------------------------------------*
Name: DHT_CheckHashPhase4Ex
Description:
Arguments: pDHT
pROMHeader ROMヘッダ格納先
funcEx
DHT_CheckHashPhase2ExUpdateを呼び出す必要がある
arg Read関数に渡される引数
Returns: TRUE
*---------------------------------------------------------------------------*/
BOOL DHT_CheckHashPhase4Ex(const DHTFileAdHoc* pDHT, const ROM_Header_Short* pROMHeader, DHTReadFuncEx funcEx, void* arg);
#ifdef __cplusplus #ifdef __cplusplus
} /* extern "C" */ } /* extern "C" */

View File

@ -21,7 +21,12 @@
#define DHT_DS_HEADER_SIZE 0x160 #define DHT_DS_HEADER_SIZE 0x160
#define DHT_OVERLAY_MAX (512*1024) #define DHT_OVERLAY_MAX (512*1024)
#define DHT_MAGIC_CODE_EX (('N' << 0)|('D' << 8)|('H' << 16)|('X' << 24))
#define DHT_MAGIC_CODE_ADHOC (('N' << 0)|('D' << 8)|('H' << 16)|('I' << 24))
#include <twl/types.h> #include <twl/types.h>
#include <twl/os/common/banner.h>
#ifdef __cplusplus #ifdef __cplusplus
extern "C" { extern "C" {
@ -35,6 +40,8 @@ typedef struct DHTHeader
} }
DHTHeader; DHTHeader;
#define DHTHeaderEx DHTHeader
typedef struct DHTDatabase typedef struct DHTDatabase
{ {
u8 game_code[4]; u8 game_code[4];
@ -44,6 +51,33 @@ typedef struct DHTDatabase
} }
DHTDatabase; DHTDatabase;
typedef struct DHTDatabaseEx
{
u8 game_code[4];
u8 rom_version;
u8 reserved[3]; // for 4B alignment DHTDatabase array
u8 banner_hash[20];
}
DHTDatabaseEx;
/*
ad-hoc対処用
*/
#define DHT_INDIVIDUAL_ENTRY_MAX 8
typedef struct DHTDatabaseAdHoc
{
u8 game_code[4];
u8 rom_version;
u8 reserved[3]; // for 4B alignment DHTDatabase array
struct
{
u32 offset;
u32 length;
} entry[DHT_INDIVIDUAL_ENTRY_MAX];
u8 hash[20];
}
DHTDatabaseAdHoc;
typedef struct DHTFile typedef struct DHTFile
{ {
DHTHeader header; DHTHeader header;
@ -51,6 +85,20 @@ typedef struct DHTFile
} }
DHTFile; DHTFile;
typedef struct DHTFileEx
{
DHTHeader header;
DHTDatabaseEx database[];
}
DHTFileEx;
typedef struct DHTFileAdHoc
{
DHTHeader header;
DHTDatabaseAdHoc database[];
}
DHTFileAdHoc;
#define DHT_HMAC_KEY { \ #define DHT_HMAC_KEY { \
0x61, 0xbd, 0xdd, 0x72, 0x7e, 0x72, 0xbe, 0xde, 0xad, 0x3a, 0xdf, 0x7f, 0x3d, 0x2d, 0xf7, 0xa5, \ 0x61, 0xbd, 0xdd, 0x72, 0x7e, 0x72, 0xbe, 0xde, 0xad, 0x3a, 0xdf, 0x7f, 0x3d, 0x2d, 0xf7, 0xa5, \
0x16, 0x7e, 0xb4, 0xc9, 0x7c, 0x6c, 0x00, 0x7c, 0x57, 0xbb, 0x94, 0x8a, 0x64, 0xcd, 0x4e, 0x1c, \ 0x16, 0x7e, 0xb4, 0xc9, 0x7c, 0x6c, 0x00, 0x7c, 0x57, 0xbb, 0x94, 0x8a, 0x64, 0xcd, 0x4e, 0x1c, \
@ -58,16 +106,28 @@ DHTFile;
0x7f, 0xd9, 0x7c, 0xe9, 0x92, 0x44, 0x0f, 0xef, 0x6b, 0xb6, 0x12, 0x21, 0x68, 0x88, 0xd8, 0xee \ 0x7f, 0xd9, 0x7c, 0xe9, 0x92, 0x44, 0x0f, 0xef, 0x6b, 0xb6, 0x12, 0x21, 0x68, 0x88, 0xd8, 0xee \
} }
#define DHT_HMAC_KEY2 { \
0x85, 0x29, 0x48, 0xf3, 0xa1, 0xbb, 0x13, 0x30, 0x93, 0x5d, 0xb8, 0xc9, 0xa5, 0x9a, 0xe8, 0x30, \
0xc4, 0xd0, 0x4a, 0xdd, 0xa4, 0x92, 0x81, 0xfd, 0x4f, 0xa1, 0x32, 0xfa, 0x46, 0x05, 0xde, 0x68, \
0x7b, 0xa7, 0xd7, 0x5b, 0xc9, 0x3a, 0xc8, 0x8d, 0xcd, 0x25, 0x3a, 0x17, 0x3c, 0xc2, 0xd6, 0xe0, \
0xd2, 0xe5, 0xb9, 0xfb, 0x49, 0xf9, 0x4d, 0x05, 0x70, 0x10, 0x29, 0x51, 0x7a, 0xc5, 0x89, 0x49, \
}
/* /*
ƒ<EFBFBD>[ƒeƒBƒŠƒeƒB ƒ<EFBFBD>[ƒeƒBƒŠƒeƒB
hp: hp:
*/ */
#define DHT_GET_SIGN_TARGET_ADDR(hp) (&((DHTHeader*)hp)->nums) #define DHT_GET_SIGN_TARGET_ADDR(hp) (&((DHTHeader*)hp)->nums)
#define DHT_GET_SIGN_TARGET_SIZE(hp) (((DHTHeader*)hp)->nums * sizeof(DHTDatabase) + sizeof(u32)) #define DHT_GET_SIGN_TARGET_SIZE(hp) (((DHTHeader*)hp)->nums * sizeof(DHTDatabase) + sizeof(u32))
#define DHT_GET_SIGN_TARGET_OFFSET (int)DHT_GET_SIGN_TARGET_ADDR(0) #define DHT_GET_SIGN_TARGET_OFFSET (int)DHT_GET_SIGN_TARGET_ADDR(0)
#define DHT_GET_SIGN_TARGET_ADDR_EX(hp) DHT_GET_SIGN_TARGET_ADDR(hp)
#define DHT_GET_SIGN_TARGET_SIZE_EX(hp) (((DHTHeader*)hp)->nums * sizeof(DHTDatabaseEx) + sizeof(u32))
#define DHT_GET_SIGN_TARGET_OFFSET_EX DHT_GET_SIGN_TARGET_OFFSET
#define DHT_GET_SIGN_TARGET_ADDR_ADHOC(hp) DHT_GET_SIGN_TARGET_ADDR(hp)
#define DHT_GET_SIGN_TARGET_SIZE_ADHOC(hp) (((DHTHeader*)hp)->nums * sizeof(DHTDatabaseAdHoc) + sizeof(u32))
#define DHT_GET_SIGN_TARGET_OFFSET_ADHOC DHT_GET_SIGN_TARGET_OFFSET
#ifdef __cplusplus #ifdef __cplusplus
} /* extern "C" */ } /* extern "C" */

View File

@ -80,8 +80,10 @@ typedef enum FatalErrorCode {
FATAL_ERROR_LOAD_NEVER_STARTED = 48, // ロードが開始されていないのに、認証が開始された FATAL_ERROR_LOAD_NEVER_STARTED = 48, // ロードが開始されていないのに、認証が開始された
FATAL_ERROR_EJECT_CARD_AFTER_LOAD_START = 49, // カードが抜かれているのに、カードアプリのロードが開始された FATAL_ERROR_EJECT_CARD_AFTER_LOAD_START = 49, // カードが抜かれているのに、カードアプリのロードが開始された
FATAL_ERROR_TITLEID_COMPARE_FAILED_NTR = 50, // ブート要求されたNTRアプリと実際にロードしたアプリのTitleIDが不一致 FATAL_ERROR_TITLEID_COMPARE_FAILED_NTR = 50, // ブート要求されたNTRアプリと実際にロードしたアプリのTitleIDが不一致
FATAL_ERROR_DHT_PHASE3_FAILED = 51, // アプリのNTRホワイトリスト認証失敗フェーズ
FATAL_ERROR_DHT_PHASE4_FAILED = 52, // アプリのNTRホワイトリスト認証失敗フェーズ
FATAL_ERROR_MAX = 51 FATAL_ERROR_MAX = 53
}FatalErrorCode; }FatalErrorCode;