mirror of
https://github.com/d0k3/GodMode9.git
synced 2025-06-26 21:52:48 +00:00
Load from certs.db more accordingly
Also extra cert handling code
This commit is contained in:
parent
236d2dc09c
commit
61c17e491f
@ -1,21 +1,313 @@
|
||||
#include "cert.h"
|
||||
#include "ff.h"
|
||||
#include "disadiff.h"
|
||||
|
||||
u32 LoadCertFromCertDb(u64 offset, Certificate* cert, u32* mod, u32* exp) {
|
||||
Certificate cert_local;
|
||||
FIL db;
|
||||
UINT bytes_read;
|
||||
typedef struct {
|
||||
char magic[4]; // "CERT"
|
||||
u8 unk[4]; // afaik, always 0
|
||||
u8 used_size[4]; // size used after this header
|
||||
u8 garbage[4]; // literally garbage values
|
||||
} PACKED_STRUCT CertsDbPartitionHeader;
|
||||
|
||||
// not much in terms of error checking here
|
||||
if (f_open(&db, "1:/dbs/certs.db", FA_READ | FA_OPEN_EXISTING) != FR_OK)
|
||||
static void GetCertDBPath(char* path, bool emunand) {
|
||||
path[0] = emunand ? '4' : '1';
|
||||
strcpy(&path[1], ":/dbs/certs.db");
|
||||
}
|
||||
|
||||
bool Certificate_IsValid(const Certificate* cert) {
|
||||
if (!cert || !cert->sig || !cert->data)
|
||||
return false;
|
||||
|
||||
u32 sig_type = getbe32(cert->sig->sig_type);
|
||||
if (sig_type < 0x10000 || sig_type > 0x10005)
|
||||
return false;
|
||||
|
||||
u32 keytype = getbe32(cert->data->keytype);
|
||||
if (keytype > 2)
|
||||
return false;
|
||||
|
||||
size_t issuer_len = strnlen(cert->data->issuer, 0x40);
|
||||
size_t name_len = strnlen(cert->data->name, 0x40);
|
||||
// if >= 0x40, cert can't fit as issuer for other objects later
|
||||
// since later objects using the certificate as their issuer will have them use it as certissuer-certname
|
||||
if (!issuer_len || !name_len || (issuer_len + name_len + 1) >= 0x40)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Certificate_IsRSA(const Certificate* cert) {
|
||||
if (!Certificate_IsValid(cert)) return false;
|
||||
if (getbe32(cert->data->keytype) >= 2) return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Certificate_IsECC(const Certificate* cert) {
|
||||
if (!Certificate_IsValid(cert)) return false;
|
||||
if (getbe32(cert->data->keytype) != 2) return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
u32 Certificate_GetSignatureSize(const Certificate* cert, u32* size) {
|
||||
if (!size || !Certificate_IsValid(cert)) return 1;
|
||||
|
||||
u32 sig_type = getbe32(cert->sig->sig_type);
|
||||
|
||||
if (sig_type == 0x10000 || sig_type == 0x10003)
|
||||
*size = 0x200;
|
||||
else if (sig_type == 0x10001 || sig_type == 0x10004)
|
||||
*size = 0x100;
|
||||
else if (sig_type == 0x10002 || sig_type == 0x10005)
|
||||
*size = 0x3C;
|
||||
else
|
||||
return 1;
|
||||
f_lseek(&db, offset);
|
||||
if (!cert) cert = &cert_local;
|
||||
f_read(&db, cert, CERT_SIZE, &bytes_read);
|
||||
f_close(&db);
|
||||
|
||||
if (mod) memcpy(mod, cert->mod, 0x100);
|
||||
if (exp) *exp = getle32(cert->exp);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
u32 Certificate_GetModulusSize(const Certificate* cert, u32* size) {
|
||||
if (!size || !Certificate_IsRSA(cert)) return 1;
|
||||
|
||||
u32 keytype = getbe32(cert->data->keytype);
|
||||
|
||||
if (keytype == 0)
|
||||
*size = 4096 / 8;
|
||||
else if (keytype == 1)
|
||||
*size = 2048 / 8;
|
||||
else return 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
u32 Certificate_GetModulus(const Certificate* cert, void* mod) {
|
||||
u32 size;
|
||||
if (!mod || Certificate_GetModulusSize(cert, &size)) return 1;
|
||||
|
||||
memcpy(mod, cert->data->pub_key_data, size);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
u32 Certificate_GetExponent(const Certificate* cert, void* exp) {
|
||||
u32 size;
|
||||
if (!exp || Certificate_GetModulusSize(cert, &size)) return 1;
|
||||
|
||||
memcpy(exp, &cert->data->pub_key_data[size], 4);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
u32 Certificate_GetEccSingleCoordinateSize(const Certificate* cert, u32* size) {
|
||||
if (!size || !Certificate_IsECC(cert)) return 1;
|
||||
|
||||
u32 keytype = getbe32(cert->data->keytype);
|
||||
|
||||
if (keytype == 2)
|
||||
*size = 0x3C / 2;
|
||||
else return 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
u32 Certificate_GetEccXY(const Certificate* cert, void* X, void* Y) {
|
||||
u32 size;
|
||||
if (!X || !Y || Certificate_GetEccSingleCoordinateSize(cert, &size)) return 1;
|
||||
|
||||
memcpy(X, cert->data->pub_key_data, size);
|
||||
memcpy(Y, &cert->data->pub_key_data[size], size);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline u32 _Certificate_GetSignatureChunkSizeFromType(u32 sig_type) {
|
||||
if (sig_type == 0x10000 || sig_type == 0x10003)
|
||||
return CERT_RSA4096_SIG_SIZE;
|
||||
else if (sig_type == 0x10001 || sig_type == 0x10004)
|
||||
return CERT_RSA2048_SIG_SIZE;
|
||||
else if (sig_type == 0x10002 || sig_type == 0x10005)
|
||||
return CERT_ECC_SIG_SIZE;
|
||||
return 0;
|
||||
}
|
||||
|
||||
u32 Certificate_GetSignatureChunkSize(const Certificate* cert, u32* size) {
|
||||
if (!size || !Certificate_IsValid(cert)) return 1;
|
||||
|
||||
u32 _size = _Certificate_GetSignatureChunkSizeFromType(getbe32(cert->sig->sig_type));
|
||||
|
||||
if (_size == 0) return 1;
|
||||
|
||||
*size = _size;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline u32 _Certificate_GetDataChunkSizeFromType(u32 keytype) {
|
||||
if (keytype == 0)
|
||||
return CERT_RSA4096_BODY_SIZE;
|
||||
else if (keytype == 1)
|
||||
return CERT_RSA2048_BODY_SIZE;
|
||||
else if (keytype == 2)
|
||||
return CERT_ECC_BODY_SIZE;
|
||||
return 0;
|
||||
}
|
||||
|
||||
u32 Certificate_GetDataChunkSize(const Certificate* cert, u32* size) {
|
||||
if (!size || !Certificate_IsValid(cert)) return 1;
|
||||
|
||||
u32 _size = _Certificate_GetDataChunkSizeFromType(getbe32(cert->data->keytype));
|
||||
|
||||
if (_size == 0) return 1;
|
||||
|
||||
*size = _size;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
u32 Certificate_GetFullSize(const Certificate* cert, u32* size) {
|
||||
if (!size || !Certificate_IsValid(cert)) return 1;
|
||||
|
||||
u32 sig_size = _Certificate_GetSignatureChunkSizeFromType(getbe32(cert->sig->sig_type));
|
||||
u32 data_size = _Certificate_GetDataChunkSizeFromType(getbe32(cert->data->keytype));
|
||||
|
||||
if (sig_size == 0 || data_size == 0)
|
||||
return 1;
|
||||
|
||||
*size = sig_size + data_size;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
u32 Certificate_RawCopy(const Certificate* cert, void* raw) {
|
||||
if (!raw || !Certificate_IsValid(cert)) return 1;
|
||||
|
||||
u32 sig_size = _Certificate_GetSignatureChunkSizeFromType(getbe32(cert->sig->sig_type));
|
||||
u32 data_size = _Certificate_GetDataChunkSizeFromType(getbe32(cert->data->keytype));
|
||||
|
||||
if (sig_size == 0 || data_size == 0)
|
||||
return 1;
|
||||
|
||||
memcpy(raw, cert->sig, sig_size);
|
||||
memcpy(&((u8*)raw)[sig_size], cert->data, data_size);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
u32 Certificate_Cleanup(Certificate* cert) {
|
||||
if (!cert) return 1;
|
||||
|
||||
free(cert->sig);
|
||||
free(cert->data);
|
||||
cert->sig = NULL;
|
||||
cert->data = NULL;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
u32 LoadCertFromCertDb(bool emunand, Certificate* cert, const char* issuer) {
|
||||
if (!issuer || !cert) return 1;
|
||||
|
||||
Certificate cert_local = {NULL, NULL};
|
||||
|
||||
char path[16];
|
||||
GetCertDBPath(path, emunand);
|
||||
|
||||
DisaDiffRWInfo info;
|
||||
u8* cache = NULL;
|
||||
if (GetDisaDiffRWInfo(path, &info, false) != 0) return 1;
|
||||
cache = malloc(info.size_dpfs_lvl2);
|
||||
if (!cache) return 1;
|
||||
if (BuildDisaDiffDpfsLvl2Cache(path, &info, cache, info.size_dpfs_lvl2) != 0) {
|
||||
free(cache);
|
||||
return 1;
|
||||
}
|
||||
|
||||
CertsDbPartitionHeader header;
|
||||
|
||||
if (ReadDisaDiffIvfcLvl4(path, &info, 0, sizeof(CertsDbPartitionHeader), &header) != sizeof(CertsDbPartitionHeader)) {
|
||||
free(cache);
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (getbe32(header.magic) != 0x43455254 /* 'CERT' */ ||
|
||||
getbe32(header.unk) != 0 ||
|
||||
getle32(header.used_size) & 0xFF) {
|
||||
free(cache);
|
||||
return 1;
|
||||
}
|
||||
|
||||
u32 offset = sizeof(CertsDbPartitionHeader);
|
||||
u32 max_offset = getle32(header.used_size) + sizeof(CertsDbPartitionHeader);
|
||||
|
||||
u32 ret = 1;
|
||||
|
||||
// certs.db has no filesystem.. its pretty plain, certificates after another
|
||||
// but also, certificates are not equally sized
|
||||
// so most cases of bad data, leads to giving up
|
||||
while (offset < max_offset) {
|
||||
char full_issuer[0x41];
|
||||
u8 sig_type_data[4];
|
||||
u8 keytype_data[4];
|
||||
|
||||
if (offset + 4 > max_offset) break;
|
||||
|
||||
if (ReadDisaDiffIvfcLvl4(path, &info, offset, 4, sig_type_data) != 4)
|
||||
break;
|
||||
|
||||
u32 sig_type = getbe32(sig_type_data);
|
||||
|
||||
if (sig_type == 0x10002 || sig_type == 0x10005) break; // ECC signs not allowed on db
|
||||
|
||||
u32 sig_size = _Certificate_GetSignatureChunkSizeFromType(sig_type);
|
||||
if (sig_size == 0) break;
|
||||
|
||||
u32 keytype_off = offset + sig_size + offsetof(CertificateBody, keytype);
|
||||
if (keytype_off + 4 > max_offset) break;
|
||||
|
||||
if (ReadDisaDiffIvfcLvl4(path, &info, keytype_off, 4, keytype_data) != 4)
|
||||
break;
|
||||
|
||||
u32 keytype = getbe32(keytype_data);
|
||||
|
||||
if (keytype == 2) break; // ECC keys not allowed on db
|
||||
|
||||
u32 data_size = _Certificate_GetDataChunkSizeFromType(keytype);
|
||||
if (data_size == 0) break;
|
||||
|
||||
u32 full_size = sig_size + data_size;
|
||||
if (offset + full_size > max_offset) break;
|
||||
|
||||
cert_local.sig = (CertificateSignature*)malloc(sig_size);
|
||||
cert_local.data = (CertificateBody*)malloc(data_size);
|
||||
if (!cert_local.sig || !cert_local.data)
|
||||
break;
|
||||
|
||||
if (ReadDisaDiffIvfcLvl4(path, &info, offset, sig_size, cert_local.sig) != sig_size)
|
||||
break;
|
||||
|
||||
if (ReadDisaDiffIvfcLvl4(path, &info, offset + sig_size, data_size, cert_local.data) != data_size)
|
||||
break;
|
||||
|
||||
if (!Certificate_IsValid(&cert_local))
|
||||
break;
|
||||
|
||||
if (snprintf(full_issuer, 0x41, "%s-%s", cert_local.data->issuer, cert_local.data->name) > 0x40)
|
||||
break;
|
||||
|
||||
if (!strcmp(full_issuer, issuer)) {
|
||||
ret = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
Certificate_Cleanup(&cert_local);
|
||||
|
||||
offset += full_size;
|
||||
}
|
||||
|
||||
if (ret) {
|
||||
Certificate_Cleanup(&cert_local);
|
||||
}
|
||||
|
||||
*cert = cert_local;
|
||||
|
||||
free(cache);
|
||||
return ret;
|
||||
}
|
||||
|
@ -2,21 +2,48 @@
|
||||
|
||||
#include "common.h"
|
||||
|
||||
#define CERT_SIZE sizeof(Certificate)
|
||||
#define CERT_MAX_SIZE (sizeof(CertificateSignature) + 0x23C + sizeof(CertificateBody) + 0x238)
|
||||
|
||||
#define CERT_RSA4096_SIG_SIZE (sizeof(CertificateSignature) + 0x23C)
|
||||
#define CERT_RSA2048_SIG_SIZE (sizeof(CertificateSignature) + 0x13C)
|
||||
#define CERT_ECC_SIG_SIZE (sizeof(CertificateSignature) + 0x7C)
|
||||
#define CERT_RSA4096_BODY_SIZE (sizeof(CertificateBody) + 0x238)
|
||||
#define CERT_RSA2048_BODY_SIZE (sizeof(CertificateBody) + 0x138)
|
||||
#define CERT_ECC_BODY_SIZE (sizeof(CertificateBody) + 0x78)
|
||||
|
||||
// from: http://3dbrew.org/wiki/Certificates
|
||||
// all numbers in big endian
|
||||
typedef struct {
|
||||
u8 sig_type[4]; // expected: 0x010004 / RSA_2048 SHA256
|
||||
u8 signature[0x100];
|
||||
u8 padding0[0x3C];
|
||||
u8 issuer[0x40];
|
||||
u8 keytype[4]; // expected: 0x01 / RSA_2048
|
||||
u8 name[0x40];
|
||||
u8 unknown[4];
|
||||
u8 mod[0x100];
|
||||
u8 exp[0x04];
|
||||
u8 padding1[0x34];
|
||||
} PACKED_STRUCT Certificate;
|
||||
u8 sig_type[4];
|
||||
u8 signature[];
|
||||
} PACKED_ALIGN(1) CertificateSignature;
|
||||
|
||||
u32 LoadCertFromCertDb(u64 offset, Certificate* cert, u32* mod, u32* exp);
|
||||
typedef struct {
|
||||
char issuer[0x40];
|
||||
u8 keytype[4];
|
||||
char name[0x40];
|
||||
u8 expiration[4];
|
||||
u8 pub_key_data[];
|
||||
} PACKED_ALIGN(1) CertificateBody;
|
||||
|
||||
typedef struct {
|
||||
CertificateSignature* sig;
|
||||
CertificateBody* data;
|
||||
} Certificate;
|
||||
|
||||
bool Certificate_IsValid(const Certificate* cert);
|
||||
bool Certificate_IsRSA(const Certificate* cert);
|
||||
bool Certificate_IsECC(const Certificate* cert);
|
||||
u32 Certificate_GetSignatureSize(const Certificate* cert, u32* size);
|
||||
u32 Certificate_GetModulusSize(const Certificate* cert, u32* size);
|
||||
u32 Certificate_GetModulus(const Certificate* cert, void* mod);
|
||||
u32 Certificate_GetExponent(const Certificate* cert, void* exp);
|
||||
u32 Certificate_GetEccSingleCoordinateSize(const Certificate* cert, u32* size);
|
||||
u32 Certificate_GetEccXY(const Certificate* cert, void* X, void* Y);
|
||||
u32 Certificate_GetSignatureChunkSize(const Certificate* cert, u32* size);
|
||||
u32 Certificate_GetDataChunkSize(const Certificate* cert, u32* size);
|
||||
u32 Certificate_GetFullSize(const Certificate* cert, u32* size);
|
||||
u32 Certificate_RawCopy(const Certificate* cert, void* raw);
|
||||
u32 Certificate_Cleanup(Certificate* cert);
|
||||
|
||||
u32 LoadCertFromCertDb(bool emunand, Certificate* cert, const char* issuer);
|
||||
|
@ -4,6 +4,7 @@
|
||||
#include "ff.h"
|
||||
#include "aes.h"
|
||||
#include "sha.h"
|
||||
#include "cert.h"
|
||||
|
||||
u32 ValidateCiaHeader(CiaHeader* header) {
|
||||
if ((header->size_header != CIA_HEADER_SIZE) ||
|
||||
@ -59,21 +60,49 @@ u32 BuildCiaCert(u8* ciacert) {
|
||||
0x18, 0x83, 0xAF, 0xE0, 0xF4, 0xE5, 0x62, 0xBA, 0x69, 0xEE, 0x72, 0x2A, 0xC2, 0x4E, 0x95, 0xB3
|
||||
};
|
||||
|
||||
// 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)
|
||||
const char* issuer_ca = !IS_DEVKIT ? "Root-CA00000003" : "Root-CA00000004";
|
||||
const char* issuer_xs = !IS_DEVKIT ? "Root-CA00000003-XS0000000c" : "Root-CA00000004-XS00000009";
|
||||
const char* issuer_cp = !IS_DEVKIT ? "Root-CA00000003-CP0000000b" : "Root-CA00000004-CP0000000a";
|
||||
|
||||
// open certs.db file on SysNAND or EmuNAND
|
||||
Certificate cert_ca;
|
||||
Certificate cert_xs;
|
||||
Certificate cert_cp;
|
||||
if (LoadCertFromCertDb(false, &cert_ca, issuer_ca) != 0 && LoadCertFromCertDb(true, &cert_ca, issuer_ca) != 0)
|
||||
return 1;
|
||||
// grab CIA cert from 4 offsets
|
||||
f_lseek(&db, 0x0C10);
|
||||
f_read(&db, ciacert + 0x000, 0x1F0, &bytes_read);
|
||||
f_lseek(&db, 0x3A00);
|
||||
f_read(&db, ciacert + 0x1F0, 0x210, &bytes_read);
|
||||
f_lseek(&db, 0x3F10);
|
||||
f_read(&db, ciacert + 0x400, 0x300, &bytes_read);
|
||||
f_lseek(&db, 0x3C10);
|
||||
f_read(&db, ciacert + 0x700, 0x300, &bytes_read);
|
||||
f_close(&db);
|
||||
|
||||
if (LoadCertFromCertDb(false, &cert_xs, issuer_xs) != 0 && LoadCertFromCertDb(true, &cert_xs, issuer_xs) != 0) {
|
||||
Certificate_Cleanup(&cert_ca);
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (LoadCertFromCertDb(false, &cert_cp, issuer_cp) != 0 && LoadCertFromCertDb(true, &cert_cp, issuer_cp) != 0) {
|
||||
Certificate_Cleanup(&cert_ca);
|
||||
Certificate_Cleanup(&cert_xs);
|
||||
return 1;
|
||||
}
|
||||
|
||||
u32 cert_size_ca;
|
||||
u32 cert_size_xs;
|
||||
u32 cert_size_cp;
|
||||
if (Certificate_GetFullSize(&cert_ca, &cert_size_ca) != 0 ||
|
||||
cert_size_ca != 0x400 ||
|
||||
Certificate_GetFullSize(&cert_xs, &cert_size_xs) != 0 ||
|
||||
cert_size_xs != 0x300 ||
|
||||
Certificate_GetFullSize(&cert_cp, &cert_size_cp) != 0 ||
|
||||
cert_size_cp != 0x300 ||
|
||||
Certificate_RawCopy(&cert_ca, ciacert) != 0 ||
|
||||
Certificate_RawCopy(&cert_xs, &ciacert[0x400]) != 0 ||
|
||||
Certificate_RawCopy(&cert_cp, &ciacert[0x700]) != 0) {
|
||||
Certificate_Cleanup(&cert_ca);
|
||||
Certificate_Cleanup(&cert_xs);
|
||||
Certificate_Cleanup(&cert_cp);
|
||||
return 1;
|
||||
}
|
||||
|
||||
Certificate_Cleanup(&cert_ca);
|
||||
Certificate_Cleanup(&cert_xs);
|
||||
Certificate_Cleanup(&cert_cp);
|
||||
|
||||
// check the certificate hash
|
||||
u8 cert_hash[0x20];
|
||||
|
@ -28,17 +28,26 @@ u32 ValidateTwlTicket(Ticket* ticket) {
|
||||
}
|
||||
|
||||
u32 ValidateTicketSignature(Ticket* ticket) {
|
||||
static bool got_modexp = false;
|
||||
static u32 mod[0x100 / 0x4] = { 0 };
|
||||
static u32 exp = 0;
|
||||
Certificate cert;
|
||||
u32 mod[2048/8];
|
||||
u32 exp = 0;
|
||||
|
||||
if (!got_modexp) {
|
||||
// grab mod/exp from cert from cert.db
|
||||
if (LoadCertFromCertDb(0x3F10, NULL, mod, &exp) == 0)
|
||||
got_modexp = true;
|
||||
else return 1;
|
||||
// grab mod/exp from cert from cert.db
|
||||
if (LoadCertFromCertDb(false, &cert, (char*)(ticket->issuer)) != 0 && LoadCertFromCertDb(true, &cert, (char*)(ticket->issuer)) != 0)
|
||||
return 1;
|
||||
|
||||
// current code only expects RSA2048
|
||||
u32 mod_size;
|
||||
if (Certificate_GetModulusSize(&cert, &mod_size) != 0 ||
|
||||
mod_size != 2048/8 ||
|
||||
Certificate_GetModulus(&cert, &mod) != 0 ||
|
||||
Certificate_GetExponent(&cert, &exp) != 0) {
|
||||
Certificate_Cleanup(&cert);
|
||||
return 1;
|
||||
}
|
||||
|
||||
Certificate_Cleanup(&cert);
|
||||
|
||||
if (!RSA_setKey2048(3, mod, exp) ||
|
||||
!RSA_verify2048((void*) &(ticket->signature), (void*) &(ticket->issuer), GetTicketSize(ticket) - 0x140))
|
||||
return 1;
|
||||
@ -89,19 +98,35 @@ u32 BuildTicketCert(u8* tickcert) {
|
||||
0xC6, 0x4B, 0xD4, 0x8F, 0xDF, 0x13, 0x21, 0x3D, 0xFC, 0x72, 0xFC, 0x8D, 0x9F, 0xDD, 0x01, 0x0E
|
||||
};
|
||||
|
||||
// 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)
|
||||
const char* issuer_xs = !IS_DEVKIT ? "Root-CA00000003-XS0000000c" : "Root-CA00000004-XS00000009";
|
||||
const char* issuer_ca = !IS_DEVKIT ? "Root-CA00000003" : "Root-CA00000004";
|
||||
|
||||
// open certs.db file on SysNAND or EmuNAND
|
||||
Certificate cert_xs;
|
||||
Certificate cert_ca;
|
||||
if (LoadCertFromCertDb(false, &cert_xs, issuer_xs) != 0 && LoadCertFromCertDb(true, &cert_xs, issuer_xs) != 0)
|
||||
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);
|
||||
|
||||
if (LoadCertFromCertDb(false, &cert_ca, issuer_ca) != 0 && LoadCertFromCertDb(true, &cert_ca, issuer_ca) != 0) {
|
||||
Certificate_Cleanup(&cert_xs);
|
||||
return 1;
|
||||
}
|
||||
|
||||
u32 cert_size_xs;
|
||||
u32 cert_size_ca;
|
||||
if (Certificate_GetFullSize(&cert_xs, &cert_size_xs) != 0 ||
|
||||
cert_size_xs != 0x300 ||
|
||||
Certificate_GetFullSize(&cert_ca, &cert_size_ca) != 0 ||
|
||||
cert_size_ca != 0x400 ||
|
||||
Certificate_RawCopy(&cert_xs, tickcert) != 0 ||
|
||||
Certificate_RawCopy(&cert_ca, &tickcert[0x300]) != 0) {
|
||||
Certificate_Cleanup(&cert_xs);
|
||||
Certificate_Cleanup(&cert_ca);
|
||||
return 1;
|
||||
}
|
||||
|
||||
Certificate_Cleanup(&cert_xs);
|
||||
Certificate_Cleanup(&cert_ca);
|
||||
|
||||
// check the certificate hash
|
||||
u8 cert_hash[0x20];
|
||||
|
@ -24,17 +24,26 @@ u32 ValidateTwlTmd(TitleMetaData* tmd) {
|
||||
}
|
||||
|
||||
u32 ValidateTmdSignature(TitleMetaData* tmd) {
|
||||
static bool got_modexp = false;
|
||||
static u32 mod[0x100 / 4] = { 0 };
|
||||
static u32 exp = 0;
|
||||
Certificate cert;
|
||||
u32 mod[2048/8];
|
||||
u32 exp = 0;
|
||||
|
||||
if (!got_modexp) {
|
||||
// grab mod/exp from cert from cert.db
|
||||
if (LoadCertFromCertDb(0x3C10, NULL, mod, &exp) == 0)
|
||||
got_modexp = true;
|
||||
else return 1;
|
||||
// grab mod/exp from cert from cert.db
|
||||
if (LoadCertFromCertDb(false, &cert, (char*)(tmd->issuer)) != 0 && LoadCertFromCertDb(true, &cert, (char*)(tmd->issuer)) != 0)
|
||||
return 1;
|
||||
|
||||
// current code only expects RSA2048
|
||||
u32 mod_size;
|
||||
if (Certificate_GetModulusSize(&cert, &mod_size) != 0 ||
|
||||
mod_size != 2048/8 ||
|
||||
Certificate_GetModulus(&cert, &mod) != 0 ||
|
||||
Certificate_GetExponent(&cert, &exp) != 0) {
|
||||
Certificate_Cleanup(&cert);
|
||||
return 1;
|
||||
}
|
||||
|
||||
Certificate_Cleanup(&cert);
|
||||
|
||||
if (!RSA_setKey2048(3, mod, exp) ||
|
||||
!RSA_verify2048((void*) &(tmd->signature), (void*) &(tmd->issuer), 0xC4))
|
||||
return 1;
|
||||
@ -121,19 +130,35 @@ u32 BuildTmdCert(u8* tmdcert) {
|
||||
0xC2, 0xE9, 0xCA, 0x93, 0x94, 0xF4, 0x29, 0xA0, 0x38, 0x54, 0x75, 0xFF, 0xAB, 0x6E, 0x8E, 0x71
|
||||
};
|
||||
|
||||
// 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)
|
||||
const char* issuer_cp = !IS_DEVKIT ? "Root-CA00000003-CP0000000b" : "Root-CA00000004-CP0000000a";
|
||||
const char* issuer_ca = !IS_DEVKIT ? "Root-CA00000003" : "Root-CA00000004";
|
||||
|
||||
// open certs.db file on SysNAND or EmuNAND
|
||||
Certificate cert_cp;
|
||||
Certificate cert_ca;
|
||||
if (LoadCertFromCertDb(false, &cert_cp, issuer_cp) != 0 && LoadCertFromCertDb(true, &cert_cp, issuer_cp) != 0)
|
||||
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);
|
||||
|
||||
if (LoadCertFromCertDb(false, &cert_ca, issuer_ca) != 0 && LoadCertFromCertDb(true, &cert_ca, issuer_ca) != 0) {
|
||||
Certificate_Cleanup(&cert_cp);
|
||||
return 1;
|
||||
}
|
||||
|
||||
u32 cert_size_cp;
|
||||
u32 cert_size_ca;
|
||||
if (Certificate_GetFullSize(&cert_cp, &cert_size_cp) != 0 ||
|
||||
cert_size_cp != 0x300 ||
|
||||
Certificate_GetFullSize(&cert_ca, &cert_size_ca) != 0 ||
|
||||
cert_size_ca != 0x400 ||
|
||||
Certificate_RawCopy(&cert_cp, tmdcert) != 0 ||
|
||||
Certificate_RawCopy(&cert_ca, &tmdcert[0x300]) != 0) {
|
||||
Certificate_Cleanup(&cert_cp);
|
||||
Certificate_Cleanup(&cert_ca);
|
||||
return 1;
|
||||
}
|
||||
|
||||
Certificate_Cleanup(&cert_cp);
|
||||
Certificate_Cleanup(&cert_ca);
|
||||
|
||||
// check the certificate hash
|
||||
u8 cert_hash[0x20];
|
||||
|
Loading…
x
Reference in New Issue
Block a user