diff --git a/include/firmwriter.h b/include/firmwriter.h index 6ddfe31..08bc5ee 100644 --- a/include/firmwriter.h +++ b/include/firmwriter.h @@ -24,4 +24,12 @@ #define FIRMWRITER_BLK_SIZE (0x20000) // 128 KB blocks +#define UPDATE_ERR_INVALID_FIRM (-2) // Corrupted FIRM +#define UPDATE_ERR_INVALID_SIG (-3) // Signature verification error +#define UPDATE_ERR_DOWNGRADE (-5) // Update file is a lower version than installed +#define UPDATE_ERR_NOT_INSTALLED (-10) // fastboot3DS is not installed in firm0:/ + + + s32 writeFirmPartition(const char *const part); +s32 loadVerifyUpdate(const char *const path, u32 *const version); diff --git a/include/ipc_handler.h b/include/ipc_handler.h index d4542c9..8f326ac 100644 --- a/include/ipc_handler.h +++ b/include/ipc_handler.h @@ -64,9 +64,9 @@ IPC_CMD9_FVERIFY_NAND_IMG = CMD_ID(26) | CMD_IN_BUFS(1) | CMD_OUT_BUFS(0) | CMD_PARAMS(0), IPC_CMD9_FSET_NAND_PROT = CMD_ID(27) | CMD_IN_BUFS(0) | CMD_OUT_BUFS(0) | CMD_PARAMS(1), IPC_CMD9_WRITE_FIRM_PART = CMD_ID(28) | CMD_IN_BUFS(1) | CMD_OUT_BUFS(0) | CMD_PARAMS(0), - IPC_CMD9_UPDATE_FASTBOOT = CMD_ID(29) | CMD_IN_BUFS(15) | CMD_OUT_BUFS(15) | CMD_PARAMS(15), - IPC_CMD9_LOAD_VERIFY_FIRM = CMD_ID(30) | CMD_IN_BUFS(1) | CMD_OUT_BUFS(0) | CMD_PARAMS(1), - IPC_CMD9_FIRM_LAUNCH = CMD_ID(31) | CMD_IN_BUFS(0) | CMD_OUT_BUFS(0) | CMD_PARAMS(0), + IPC_CMD9_LOAD_VERIFY_FIRM = CMD_ID(29) | CMD_IN_BUFS(1) | CMD_OUT_BUFS(0) | CMD_PARAMS(1), + IPC_CMD9_FIRM_LAUNCH = CMD_ID(30) | CMD_IN_BUFS(0) | CMD_OUT_BUFS(0) | CMD_PARAMS(0), + IPC_CMD9_LOAD_VERIFY_UPDATE = CMD_ID(31) | CMD_IN_BUFS(1) | CMD_OUT_BUFS(1) | CMD_PARAMS(0), IPC_CMD9_PREPARE_POWER = CMD_ID(32) | CMD_IN_BUFS(0) | CMD_OUT_BUFS(0) | CMD_PARAMS(0), IPC_CMD9_PANIC = CMD_ID(33) | CMD_IN_BUFS(0) | CMD_OUT_BUFS(0) | CMD_PARAMS(0), IPC_CMD9_EXCEPTION = CMD_ID(34) | CMD_IN_BUFS(0) | CMD_OUT_BUFS(0) | CMD_PARAMS(0) diff --git a/source/arm11/firmwriter.c b/source/arm11/firmwriter.c index d1caf90..488bb21 100644 --- a/source/arm11/firmwriter.c +++ b/source/arm11/firmwriter.c @@ -31,3 +31,14 @@ return PXI_sendCmd(IPC_CMD9_WRITE_FIRM_PART, cmdBuf, 2); } + +s32 loadVerifyUpdate(const char *const path, u32 *const version) +{ + u32 cmdBuf[4]; + cmdBuf[0] = (u32)path; + cmdBuf[1] = strlen(path) + 1; + cmdBuf[2] = (u32)version; + cmdBuf[3] = sizeof(u32); + + return PXI_sendCmd(IPC_CMD9_LOAD_VERIFY_UPDATE, cmdBuf, 4); +} diff --git a/source/arm9/firmwriter.c b/source/arm9/firmwriter.c index 13955f2..1d34a29 100644 --- a/source/arm9/firmwriter.c +++ b/source/arm9/firmwriter.c @@ -25,6 +25,8 @@ #include "arm9/firm.h" #include "arm9/dev.h" #include "util.h" +#include "arm9/hardware/crypto.h" +#include "fastboot3DS_pubkey_bin.h" @@ -65,3 +67,49 @@ return 0; } + +s32 loadVerifyUpdate(const char *const path, u32 *const version) +{ + if(!dev_decnand->is_active()) return -1; + if(loadVerifyFirm(path, false, true) < 0) return UPDATE_ERR_INVALID_FIRM; + + u32 *updateBuffer = (u32*)FIRM_LOAD_ADDR; +#ifdef NDEBUG + // Verify signature + if(!RSA_setKey2048(3, fastboot3DS_pubkey_bin, 0x01000100) || + !RSA_verify2048(updateBuffer + 0x40, updateBuffer, 0x100)) + return UPDATE_ERR_INVALID_SIG; +#endif + + // verify fastboot magic + if(memcmp((void*)updateBuffer + 0x200, "FASTBOOT 3DS ", 16) != 0) + return -4; + + // Check version + const u32 vers = *(u32*)((void*)updateBuffer + 0x210); + if(vers < ((u32)VERS_MAJOR<<16 | VERS_MINOR)) return UPDATE_ERR_DOWNGRADE; + + size_t partInd, sector; + if(!partitionGetIndex("firm0", &partInd)) return -6; + if(!partitionGetSectorOffset(partInd, §or)) return -7; + + u8 *firm0Buf = (u8*)malloc(0x200); + if(!firm0Buf) return -8; + if(!dev_decnand->read_sector(sector + 1, 1, firm0Buf)) + { + free(firm0Buf); + return -9; + } + + // verify fastboot is installed to firm0:/ + if(memcmp(firm0Buf, "FASTBOOT 3DS ", 16) != 0) + { + free(firm0Buf); + return UPDATE_ERR_NOT_INSTALLED; + } + + free(firm0Buf); + if(version) *version = vers; + + return 0; +} diff --git a/source/arm9/ipc_handler.c b/source/arm9/ipc_handler.c index 6f55d15..0f28a37 100644 --- a/source/arm9/ipc_handler.c +++ b/source/arm9/ipc_handler.c @@ -125,8 +125,6 @@ case IPC_CMD_ID_MASK(IPC_CMD9_WRITE_FIRM_PART): result = writeFirmPartition((const char *const)buf[0]); break; - case IPC_CMD_ID_MASK(IPC_CMD9_UPDATE_FASTBOOT): - break; case IPC_CMD_ID_MASK(IPC_CMD9_LOAD_VERIFY_FIRM): result = loadVerifyFirm((const char *const)buf[0], buf[2], false); break; @@ -136,6 +134,9 @@ g_startFirmLaunch = true; } break; + case IPC_CMD_ID_MASK(IPC_CMD9_LOAD_VERIFY_UPDATE): + result = loadVerifyUpdate((const char *const)buf[0], (u32 *const)buf[2]); + break; case IPC_CMD_ID_MASK(IPC_CMD9_PREPARE_POWER): case IPC_CMD_ID_MASK(IPC_CMD9_PANIC): case IPC_CMD_ID_MASK(IPC_CMD9_EXCEPTION):