pk11: add proper support for newer (and mariko) package1

This commit is contained in:
Michael Scire 2020-06-01 02:19:40 -07:00
parent 55b13f0d67
commit c3415cf25e
6 changed files with 371 additions and 61 deletions

4
aes.c
View File

@ -70,7 +70,7 @@ void aes_encrypt(aes_ctx_t *ctx, void *dst, const void *src, size_t l) {
mbedtls_cipher_reset(&ctx->cipher_enc); mbedtls_cipher_reset(&ctx->cipher_enc);
/* XTS doesn't need per-block updating */ /* XTS doesn't need per-block updating */
if (mbedtls_cipher_get_cipher_mode(&ctx->cipher_enc) == MBEDTLS_MODE_XTS) if (mbedtls_cipher_get_cipher_mode(&ctx->cipher_enc) == MBEDTLS_MODE_XTS || mbedtls_cipher_get_cipher_mode(&ctx->cipher_enc) == MBEDTLS_MODE_CBC)
mbedtls_cipher_update(&ctx->cipher_enc, (const unsigned char * )src, l, (unsigned char *)dst, &out_len); mbedtls_cipher_update(&ctx->cipher_enc, (const unsigned char * )src, l, (unsigned char *)dst, &out_len);
else else
{ {
@ -110,7 +110,7 @@ void aes_decrypt(aes_ctx_t *ctx, void *dst, const void *src, size_t l)
mbedtls_cipher_reset(&ctx->cipher_dec); mbedtls_cipher_reset(&ctx->cipher_dec);
/* XTS doesn't need per-block updating */ /* XTS doesn't need per-block updating */
if (mbedtls_cipher_get_cipher_mode(&ctx->cipher_dec) == MBEDTLS_MODE_XTS) if (mbedtls_cipher_get_cipher_mode(&ctx->cipher_dec) == MBEDTLS_MODE_XTS || mbedtls_cipher_get_cipher_mode(&ctx->cipher_enc) == MBEDTLS_MODE_CBC)
mbedtls_cipher_update(&ctx->cipher_dec, (const unsigned char * )src, l, (unsigned char *)dst, &out_len); mbedtls_cipher_update(&ctx->cipher_dec, (const unsigned char * )src, l, (unsigned char *)dst, &out_len);
else else
{ {

View File

@ -284,7 +284,13 @@ void extkeys_initialize_settings(hactool_settings_t *settings, FILE *f) {
} else if (strcmp(key, "tsec_key") == 0) { } else if (strcmp(key, "tsec_key") == 0) {
parse_hex_key(keyset->tsec_key, value, sizeof(keyset->tsec_key)); parse_hex_key(keyset->tsec_key, value, sizeof(keyset->tsec_key));
matched_key = 1; matched_key = 1;
} else if (strcmp(key, "tsec_root_kek") == 0) { } else if (strcmp(key, "mariko_kek") == 0) {
parse_hex_key(keyset->mariko_kek, value, sizeof(keyset->mariko_kek));
matched_key = 1;
} else if (strcmp(key, "mariko_bek") == 0) {
parse_hex_key(keyset->mariko_bek, value, sizeof(keyset->mariko_bek));
matched_key = 1;
} else if (strcmp(key, "tsec_root_kek") == 0) {
parse_hex_key(keyset->tsec_root_kek, value, sizeof(keyset->tsec_root_kek)); parse_hex_key(keyset->tsec_root_kek, value, sizeof(keyset->tsec_root_kek));
matched_key = 1; matched_key = 1;
} else if (strcmp(key, "package1_mac_kek") == 0) { } else if (strcmp(key, "package1_mac_kek") == 0) {
@ -365,6 +371,16 @@ void extkeys_initialize_settings(hactool_settings_t *settings, FILE *f) {
break; break;
} }
} }
for (unsigned int i = 0; i < 0xC && !matched_key; i++) {
snprintf(test_name, sizeof(test_name), "mariko_aes_class_key_%02"PRIx32, i);
if (strcmp(key, test_name) == 0) {
parse_hex_key(keyset->mariko_aes_class_keys[i], value, sizeof(keyset->mariko_aes_class_keys[i]));
matched_key = 1;
break;
}
}
for (unsigned int i = 0; i < 0x20 && !matched_key; i++) { for (unsigned int i = 0; i < 0x20 && !matched_key; i++) {
snprintf(test_name, sizeof(test_name), "master_kek_%02"PRIx32, i); snprintf(test_name, sizeof(test_name), "master_kek_%02"PRIx32, i);
if (strcmp(key, test_name) == 0) { if (strcmp(key, test_name) == 0) {

View File

@ -5,6 +5,26 @@
#include "rsa.h" #include "rsa.h"
#include "sha.h" #include "sha.h"
static int pk11_is_mariko(pk11_ctx_t *ctx) {
fseeko64(ctx->file, 0, SEEK_SET);
if (fread(&ctx->mariko_oem_header, 1, sizeof(ctx->mariko_oem_header), ctx->file) != sizeof(ctx->mariko_oem_header)) {
fprintf(stderr, "Failed to read PK11 OEM Header!\n");
exit(EXIT_FAILURE);
}
for (int i = 0; i < 0x10; i++) {
if (ctx->mariko_oem_header.aes_mac[i] != 0 || ctx->mariko_oem_header._0x160[i] != 0) {
return 0;
}
}
return 1;
}
static int pk11_is_legacy(pk11_ctx_t *ctx) {
return ctx->metadata.version < 0x0E || memcmp(ctx->metadata.build_date, "20181107", 8) < 0;
}
void pk11_process(pk11_ctx_t *ctx) { void pk11_process(pk11_ctx_t *ctx) {
fseeko64(ctx->file, 0, SEEK_SET); fseeko64(ctx->file, 0, SEEK_SET);
if (fread(&ctx->stage1, 1, sizeof(ctx->stage1), ctx->file) != sizeof(ctx->stage1)) { if (fread(&ctx->stage1, 1, sizeof(ctx->stage1), ctx->file) != sizeof(ctx->stage1)) {
@ -12,50 +32,147 @@ void pk11_process(pk11_ctx_t *ctx) {
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
} }
/* Check if PK11 was built in 2016. */ // Detect mariko
/* This is a heuristic to detect an older layout for the PK11 binary. */ ctx->is_mariko = pk11_is_mariko(ctx);
if (ctx->stage1.build_date[0] == '2' && ctx->stage1.build_date[1] == '0' && ctx->stage1.build_date[2] == '1' && ctx->stage1.build_date[3] == '6') {
ctx->is_pilot = 1; if (ctx->is_mariko) {
fseeko64(ctx->file, sizeof(ctx->mariko_oem_header), SEEK_SET);
if (ctx->mariko_oem_header.bl_size < sizeof(ctx->metadata)) {
fprintf(stderr, "PK11 seems corrupt!\n");
exit(EXIT_FAILURE);
}
ctx->mariko_bl = calloc(1, ctx->mariko_oem_header.bl_size);
if (fread(ctx->mariko_bl, 1, ctx->mariko_oem_header.bl_size, ctx->file) != ctx->mariko_oem_header.bl_size) {
fprintf(stderr, "Failed to read Mariko PK11!\n");
exit(EXIT_FAILURE);
}
memcpy(&ctx->metadata, ctx->mariko_bl, sizeof(ctx->metadata));
uint32_t enc_size = ctx->mariko_oem_header.bl_size - sizeof(ctx->metadata);
if (enc_size > 0) {
aes_ctx_t *crypt_ctx = new_aes_ctx(ctx->tool_ctx->settings.keyset.mariko_bek, 0x10, AES_MODE_CBC);
aes_setiv(crypt_ctx, ctx->mariko_bl + 0x10, 0x10);
aes_decrypt(crypt_ctx, ctx->mariko_bl + 0x20, ctx->mariko_bl + 0x20, enc_size);
free_aes_ctx(crypt_ctx);
if (memcmp(&ctx->metadata, ctx->mariko_bl + 0x20, sizeof(ctx->metadata)) != 0) {
fprintf(stderr, "Failed to decrypt Mariko PK11! Is correct key present?\n");
exit(EXIT_FAILURE);
}
}
} else { } else {
ctx->is_pilot = 0; fseeko64(ctx->file, 0, SEEK_SET);
if (fread(&ctx->metadata, 1, sizeof(ctx->metadata), ctx->file) != sizeof(ctx->metadata)) {
fprintf(stderr, "Failed to read PK11 Metadata!\n");
exit(EXIT_FAILURE);
}
} }
ctx->pk11 = malloc(ctx->stage1.pk11_size); ctx->is_modern = !pk11_is_legacy(ctx);
if (ctx->is_mariko) {
if (ctx->is_modern) {
memcpy(&ctx->stage1.modern, ctx->mariko_bl + 0x20, sizeof(ctx->stage1.modern));
ctx->pk11_size = ctx->stage1.modern.pk11_size;
} else {
memcpy(&ctx->stage1.legacy, ctx->mariko_bl + 0x20, sizeof(ctx->stage1.legacy));
ctx->pk11_size = ctx->stage1.legacy.pk11_size;
}
} else {
if (ctx->is_modern) {
if (fread(&ctx->stage1.modern, 1, sizeof(ctx->stage1.modern), ctx->file) != sizeof(ctx->stage1.modern)) {
fprintf(stderr, "Failed to read PK11 Stage1!\n");
exit(EXIT_FAILURE);
}
ctx->pk11_size = ctx->stage1.modern.pk11_size;
} else {
if (fread(&ctx->stage1.legacy, 1, sizeof(ctx->stage1.legacy), ctx->file) != sizeof(ctx->stage1.legacy)) {
fprintf(stderr, "Failed to read PK11 Stage1!\n");
exit(EXIT_FAILURE);
}
ctx->pk11_size = ctx->stage1.legacy.pk11_size;
}
}
ctx->pk11 = malloc(ctx->pk11_size);
if (ctx->pk11 == NULL) { if (ctx->pk11 == NULL) {
fprintf(stderr, "Failed to allocate PK11!\n"); fprintf(stderr, "Failed to allocate PK11!\n");
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
} }
if (fread(ctx->pk11, 1, ctx->stage1.pk11_size, ctx->file) != ctx->stage1.pk11_size) { if (ctx->is_mariko) {
fprintf(stderr, "Failed to read PK11!\n"); if (ctx->is_modern) {
exit(EXIT_FAILURE); memcpy(ctx->pk11, ctx->mariko_bl + 0x20 + sizeof(ctx->stage1.modern), ctx->pk11_size);
} } else {
memcpy(ctx->pk11, ctx->mariko_bl + 0x20 + sizeof(ctx->stage1.legacy), ctx->pk11_size);
aes_ctx_t *crypt_ctx = NULL; }
pk11_t dec_header;
for (unsigned int i = 0; i < 0x20; i++) { } else {
ctx->key_rev = i; if (fread(ctx->pk11, 1, ctx->pk11_size, ctx->file) != ctx->pk11_size) {
crypt_ctx = new_aes_ctx(&ctx->tool_ctx->settings.keyset.package1_keys[i], 0x10, AES_MODE_CTR); fprintf(stderr, "Failed to read PK11!\n");
aes_setiv(crypt_ctx, ctx->stage1.ctr, 0x10); exit(EXIT_FAILURE);
aes_decrypt(crypt_ctx, &dec_header, ctx->pk11, sizeof(dec_header)); }
if (dec_header.magic == MAGIC_PK11) {
break; if (ctx->is_modern) {
if (fread(&ctx->pk11_mac, 1, sizeof(ctx->pk11_mac), ctx->file) != sizeof(ctx->pk11_mac)) {
fprintf(stderr, "Failed to read PK11 MAC!\n");
exit(EXIT_FAILURE);
}
} }
free_aes_ctx(crypt_ctx);
crypt_ctx = NULL;
} }
if (crypt_ctx == NULL) { int decrypted = 0;
if (ctx->is_mariko) {
decrypted = ctx->pk11->magic == MAGIC_PK11;
} else {
pk11_t dec_header;
aes_ctx_t *crypt_ctx = NULL;
if (ctx->is_modern) {
for (unsigned int i = 6; i < 0x20 && !decrypted; i++) {
ctx->key_rev = i;
crypt_ctx = new_aes_ctx(ctx->tool_ctx->settings.keyset.package1_keys[i], 0x10, AES_MODE_CBC);
aes_setiv(crypt_ctx, ctx->stage1.modern.iv, 0x10);
aes_decrypt(crypt_ctx, &dec_header, ctx->pk11, sizeof(dec_header));
if (dec_header.magic == MAGIC_PK11) {
aes_setiv(crypt_ctx, ctx->stage1.modern.iv, 0x10);
aes_decrypt(crypt_ctx, ctx->pk11, ctx->pk11, ctx->pk11_size);
decrypted = 1;
}
free_aes_ctx(crypt_ctx);
crypt_ctx = NULL;
}
} else {
for (unsigned int i = 0; i < 6 && !decrypted; i++) {
ctx->key_rev = i;
crypt_ctx = new_aes_ctx(ctx->tool_ctx->settings.keyset.package1_keys[i], 0x10, AES_MODE_CTR);
aes_setiv(crypt_ctx, ctx->stage1.legacy.ctr, 0x10);
aes_decrypt(crypt_ctx, &dec_header, ctx->pk11, sizeof(dec_header));
if (dec_header.magic == MAGIC_PK11) {
aes_setiv(crypt_ctx, ctx->stage1.legacy.ctr, 0x10);
aes_decrypt(crypt_ctx, ctx->pk11, ctx->pk11, ctx->pk11_size);
decrypted = 1;
}
free_aes_ctx(crypt_ctx);
crypt_ctx = NULL;
}
}
}
if (!decrypted) {
fprintf(stderr, "Failed to decrypt PK11! Is correct key present?\n"); fprintf(stderr, "Failed to decrypt PK11! Is correct key present?\n");
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
} }
aes_setiv(crypt_ctx, ctx->stage1.ctr, 0x10);
aes_decrypt(crypt_ctx, ctx->pk11, ctx->pk11, ctx->stage1.pk11_size);
uint64_t pk11_size = 0x20 + ctx->pk11->warmboot_size + ctx->pk11->nx_bootloader_size + ctx->pk11->secmon_size; uint64_t pk11_size = 0x20 + pk11_get_warmboot_bin_size(ctx) + pk11_get_nx_bootloader_size(ctx) + pk11_get_secmon_size(ctx);
pk11_size = align64(pk11_size, 0x10); pk11_size = align64(pk11_size, 0x10);
if (pk11_size != ctx->stage1.pk11_size) { if (pk11_size != ctx->pk11_size) {
fprintf(stderr, "PK11 seems corrupt!\n"); fprintf(stderr, "PK11 seems corrupt!\n");
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
} }
@ -71,13 +188,20 @@ void pk11_process(pk11_ctx_t *ctx) {
void pk11_print(pk11_ctx_t *ctx) { void pk11_print(pk11_ctx_t *ctx) {
printf("PK11:\n"); printf("PK11:\n");
printf(" Build Date: %s\n", ctx->stage1.build_date); {
memdump(stdout, " Build Hash: ", ctx->stage1.build_hash, 0x10); char build_date[sizeof(ctx->metadata.build_date) + 1] = {0};
memcpy(build_date, ctx->metadata.build_date, sizeof(ctx->metadata.build_date));
printf(" Build Date: %s\n", build_date);
}
memdump(stdout, " Package1ldr Hash: ", &ctx->metadata.ldr_hash, sizeof(uint32_t));
memdump(stdout, " Secure Monitor Hash: ", &ctx->metadata.sm_hash, sizeof(uint32_t));
memdump(stdout, " NX Bootloader Hash: ", &ctx->metadata.bl_hash, sizeof(uint32_t));
printf(" Version: %02"PRIx32"\n", ctx->metadata.version);
printf(" Key Revision: %02"PRIx32" (%s)\n", ctx->key_rev, get_key_revision_summary((uint8_t)ctx->key_rev)); printf(" Key Revision: %02"PRIx32" (%s)\n", ctx->key_rev, get_key_revision_summary((uint8_t)ctx->key_rev));
printf(" PK11 Size: %08"PRIx32"\n", ctx->stage1.pk11_size); printf(" PK11 Size: %08"PRIx32"\n", ctx->pk11_size);
printf(" Warmboot.bin Size: %08"PRIx32"\n", ctx->pk11->warmboot_size); printf(" Warmboot.bin Size: %08"PRIx32"\n", pk11_get_warmboot_bin_size(ctx));
printf(" NX_Bootloader.bin Size %08"PRIx32"\n", ctx->pk11->nx_bootloader_size); printf(" NX_Bootloader.bin Size %08"PRIx32"\n", pk11_get_nx_bootloader_size(ctx));
printf(" Secure_Monitor.bin Size: %08"PRIx32"\n", ctx->pk11->secmon_size); printf(" Secure_Monitor.bin Size: %08"PRIx32"\n", pk11_get_secmon_size(ctx));
printf("\n"); printf("\n");
} }
@ -95,27 +219,74 @@ void pk11_save(pk11_ctx_t *ctx) {
/* Save Decrypted.bin */ /* Save Decrypted.bin */
printf("Saving decrypted binary to %s/Decrypted.bin\n", dirpath->char_path); printf("Saving decrypted binary to %s/Decrypted.bin\n", dirpath->char_path);
char *decrypted_bin = malloc(sizeof(ctx->stage1) + ctx->stage1.pk11_size); if (ctx->is_mariko) {
if (decrypted_bin == NULL) { char *decrypted_bin = malloc(sizeof(ctx->mariko_oem_header) + ctx->mariko_oem_header.bl_size);
fprintf(stderr, "Failed to allocate buffer!\n"); if (decrypted_bin == NULL) {
exit(EXIT_FAILURE); fprintf(stderr, "Failed to allocate buffer!\n");
exit(EXIT_FAILURE);
}
memcpy(decrypted_bin, &ctx->mariko_oem_header, sizeof(ctx->mariko_oem_header));
memcpy(decrypted_bin + sizeof(ctx->mariko_oem_header), ctx->mariko_bl, ctx->mariko_oem_header.bl_size);
save_buffer_to_directory_file(decrypted_bin, sizeof(ctx->stage1) + ctx->pk11_size, dirpath, "Decrypted.bin");
free(decrypted_bin);
} else {
char *decrypted_bin = malloc(sizeof(ctx->stage1) + ctx->pk11_size);
if (decrypted_bin == NULL) {
fprintf(stderr, "Failed to allocate buffer!\n");
exit(EXIT_FAILURE);
}
memcpy(decrypted_bin, &ctx->stage1, sizeof(ctx->stage1));
memcpy(decrypted_bin + sizeof(ctx->stage1), ctx->pk11, ctx->pk11_size);
save_buffer_to_directory_file(decrypted_bin, sizeof(ctx->stage1) + ctx->pk11_size, dirpath, "Decrypted.bin");
free(decrypted_bin);
}
/* Save Mariko_OEM_Bootloader.bin */
if (ctx->is_mariko) {
printf("Saving Mariko_OEM_Bootloader.bin to %s/Mariko_OEM_Bootloader.bin...\n", dirpath->char_path);
save_buffer_to_directory_file(ctx->mariko_bl, ctx->mariko_oem_header.bl_size, dirpath, "Mariko_OEM_Bootloader.bin");
} }
memcpy(decrypted_bin, &ctx->stage1, sizeof(ctx->stage1));
memcpy(decrypted_bin + sizeof(ctx->stage1), ctx->pk11, ctx->stage1.pk11_size);
save_buffer_to_directory_file(decrypted_bin, sizeof(ctx->stage1) + ctx->stage1.pk11_size, dirpath, "Decrypted.bin");
free(decrypted_bin);
/* Save Warmboot.bin */ /* Save Warmboot.bin */
printf("Saving Warmboot.bin to %s/Warmboot.bin...\n", dirpath->char_path); printf("Saving Warmboot.bin to %s/Warmboot.bin...\n", dirpath->char_path);
save_buffer_to_directory_file(pk11_get_warmboot_bin(ctx), ctx->pk11->warmboot_size, dirpath, "Warmboot.bin"); save_buffer_to_directory_file(pk11_get_warmboot_bin(ctx), pk11_get_warmboot_bin_size(ctx), dirpath, "Warmboot.bin");
if (ctx->is_mariko) {
uint32_t wb_size = pk11_get_warmboot_bin_size(ctx);
unsigned char *wb_dec = malloc(wb_size);
if (wb_dec == NULL) {
fprintf(stderr, "Failed to allocate mariko warmboot binary!\n");
exit(EXIT_FAILURE);
}
memcpy(wb_dec, pk11_get_warmboot_bin(ctx), wb_size);
if (wb_size > 0x330) {
aes_ctx_t *crypt_ctx = new_aes_ctx(ctx->tool_ctx->settings.keyset.mariko_bek, 0x10, AES_MODE_CBC);
unsigned char iv[0x10] = {0};
aes_setiv(crypt_ctx, iv, 0x10);
aes_decrypt(crypt_ctx, wb_dec + 0x330, wb_dec + 0x330, wb_size - 0x330);
free_aes_ctx(crypt_ctx);
}
printf("Saving Warmboot_Decrypted.bin to %s/Warmboot_Decrypted.bin...\n", dirpath->char_path);
save_buffer_to_directory_file(wb_dec, wb_size, dirpath, "Warmboot_Decrypted.bin");
free(wb_dec);
}
/* Save NX_Bootloader.bin */ /* Save NX_Bootloader.bin */
printf("Saving NX_Bootloader.bin to %s/NX_Bootloader.bin...\n", dirpath->char_path); printf("Saving NX_Bootloader.bin to %s/NX_Bootloader.bin...\n", dirpath->char_path);
save_buffer_to_directory_file(pk11_get_nx_bootloader(ctx), ctx->pk11->nx_bootloader_size, dirpath, "NX_Bootloader.bin"); save_buffer_to_directory_file(pk11_get_nx_bootloader(ctx), pk11_get_nx_bootloader_size(ctx), dirpath, "NX_Bootloader.bin");
/* Save Secure_Monitor.bin */ /* Save Secure_Monitor.bin */
printf("Saving Secure_Monitor.bin to %s/Secure_Monitor.bin...\n", dirpath->char_path); printf("Saving Secure_Monitor.bin to %s/Secure_Monitor.bin...\n", dirpath->char_path);
save_buffer_to_directory_file(pk11_get_secmon(ctx), ctx->pk11->secmon_size, dirpath, "Secure_Monitor.bin"); save_buffer_to_directory_file(pk11_get_secmon(ctx), pk11_get_secmon_size(ctx), dirpath, "Secure_Monitor.bin");
} }
} }

View File

@ -11,46 +11,161 @@
#define MAGIC_KRNLLDR_STRCT_END 0xD51C403E #define MAGIC_KRNLLDR_STRCT_END 0xD51C403E
typedef struct { typedef struct {
unsigned char build_hash[0x10]; unsigned char aes_mac[0x10];
unsigned char build_date[0x10]; unsigned char rsa_sig[0x100];
unsigned char salt[0x20];
unsigned char hash[0x20];
uint32_t bl_version;
uint32_t bl_size;
uint32_t bl_load_addr;
uint32_t bl_entrypoint;
unsigned char _0x160[0x10];
} pk11_mariko_oem_header_t;
typedef struct {
uint32_t ldr_hash;
uint32_t sm_hash;
uint32_t bl_hash;
uint32_t _0xC;
char build_date[0xE];
unsigned char _0x1E;
unsigned char version;
} pk11_metadata_t;
typedef struct {
unsigned char stage1[0x3FC0]; unsigned char stage1[0x3FC0];
uint32_t pk11_size; uint32_t pk11_size;
unsigned char _0x3FE4[0xC]; unsigned char _0x3FC4[0xC];
unsigned char ctr[0x10]; unsigned char ctr[0x10];
} pk11_legacy_stage1_t;
typedef struct {
unsigned char stage1[0x6FC0];
uint32_t pk11_size;
unsigned char _0x6FC4[0xC];
unsigned char iv[0x10];
} pk11_modern_stage1_t;
typedef union {
pk11_legacy_stage1_t legacy;
pk11_modern_stage1_t modern;
} pk11_stage1_t; } pk11_stage1_t;
typedef struct { typedef struct {
uint32_t magic; uint32_t magic;
uint32_t warmboot_size; uint32_t wb_size;
uint32_t _0x8; uint32_t wb_ep;
uint32_t _0xC; uint32_t _0xC;
uint32_t nx_bootloader_size; uint32_t bl_size;
uint32_t _0x14; uint32_t bl_ep;
uint32_t secmon_size; uint32_t sm_size;
uint32_t _0x1C; uint32_t sm_ep;
unsigned char data[]; unsigned char data[];
} pk11_t; } pk11_t;
typedef struct { typedef struct {
FILE *file; FILE *file;
hactool_ctx_t *tool_ctx; hactool_ctx_t *tool_ctx;
int is_pilot; int is_modern;
int is_mariko;
unsigned int key_rev; unsigned int key_rev;
pk11_mariko_oem_header_t mariko_oem_header;
pk11_metadata_t metadata;
pk11_stage1_t stage1; pk11_stage1_t stage1;
uint32_t pk11_size;
uint8_t *mariko_bl;
pk11_t *pk11; pk11_t *pk11;
unsigned char pk11_mac[0x10];
} pk11_ctx_t; } pk11_ctx_t;
typedef enum {
PK11_SECTION_BL,
PK11_SECTION_SM,
PK11_SECTION_WB,
} pk11_section_id_t;
static inline int pk11_get_section_idx(pk11_ctx_t *ctx, pk11_section_id_t section_id) {
if (ctx->metadata.version >= 0x07) {
switch (section_id) {
case PK11_SECTION_BL: return 0;
case PK11_SECTION_SM: return 1;
case PK11_SECTION_WB: return 2;
}
} else if (ctx->metadata.version >= 0x02) {
switch (section_id) {
case PK11_SECTION_BL: return 1;
case PK11_SECTION_SM: return 2;
case PK11_SECTION_WB: return 0;
}
} else {
switch (section_id) {
case PK11_SECTION_BL: return 1;
case PK11_SECTION_SM: return 0;
case PK11_SECTION_WB: return 2;
}
}
return 0;
}
static inline pk11_section_id_t pk11_get_section_id(pk11_ctx_t *ctx, int id) {
if (pk11_get_section_idx(ctx, PK11_SECTION_BL) == id) {
return PK11_SECTION_BL;
} else if (pk11_get_section_idx(ctx, PK11_SECTION_SM) == id) {
return PK11_SECTION_SM;
} else {
return PK11_SECTION_WB;
}
}
static inline uint32_t pk11_get_section_size(pk11_ctx_t *ctx, pk11_section_id_t section_id) {
switch (section_id) {
case PK11_SECTION_BL: return ctx->pk11->bl_size;
case PK11_SECTION_SM: return ctx->pk11->sm_size;
case PK11_SECTION_WB: return ctx->pk11->wb_size;
}
return 0;
}
static inline uint32_t pk11_get_section_ofs(pk11_ctx_t *ctx, pk11_section_id_t section_id) {
switch (pk11_get_section_idx(ctx, section_id)) {
case 0:
default:
return 0;
case 1:
return pk11_get_section_size(ctx, pk11_get_section_id(ctx, 0));
case 2:
return pk11_get_section_size(ctx, pk11_get_section_id(ctx, 0)) + pk11_get_section_size(ctx, pk11_get_section_id(ctx, 1));
}
}
static inline unsigned char *pk11_get_section(pk11_ctx_t *ctx, pk11_section_id_t section_id) {
return &ctx->pk11->data[pk11_get_section_ofs(ctx, section_id)];
}
static inline unsigned char *pk11_get_warmboot_bin(pk11_ctx_t *ctx) { static inline unsigned char *pk11_get_warmboot_bin(pk11_ctx_t *ctx) {
return ctx->is_pilot ? &ctx->pk11->data[ctx->pk11->secmon_size + ctx->pk11->nx_bootloader_size] : &ctx->pk11->data[0]; return pk11_get_section(ctx, PK11_SECTION_WB);
} }
static inline unsigned char *pk11_get_secmon(pk11_ctx_t *ctx) { static inline unsigned char *pk11_get_secmon(pk11_ctx_t *ctx) {
return ctx->is_pilot ? &ctx->pk11->data[0] : &ctx->pk11->data[ctx->pk11->warmboot_size + ctx->pk11->nx_bootloader_size]; return pk11_get_section(ctx, PK11_SECTION_SM);
} }
static inline unsigned char *pk11_get_nx_bootloader(pk11_ctx_t *ctx) { static inline unsigned char *pk11_get_nx_bootloader(pk11_ctx_t *ctx) {
return ctx->is_pilot ? &ctx->pk11->data[ctx->pk11->secmon_size] : &ctx->pk11->data[ctx->pk11->warmboot_size]; return pk11_get_section(ctx, PK11_SECTION_BL);
}
static inline unsigned int pk11_get_warmboot_bin_size(pk11_ctx_t *ctx) {
return pk11_get_section_size(ctx, PK11_SECTION_WB);
}
static inline unsigned int pk11_get_secmon_size(pk11_ctx_t *ctx) {
return pk11_get_section_size(ctx, PK11_SECTION_SM);
}
static inline unsigned int pk11_get_nx_bootloader_size(pk11_ctx_t *ctx) {
return pk11_get_section_size(ctx, PK11_SECTION_BL);
} }

7
pki.c
View File

@ -65,7 +65,6 @@ const unsigned char *pki_get_beta_nca0_label_hash(void) {
return beta_nca0_label_hash; return beta_nca0_label_hash;
} }
static const nca_keyset_t nca_keys_retail = { static const nca_keyset_t nca_keys_retail = {
.nca_hdr_fixed_key_moduli = { /* Fixed RSA key used to validate NCA signature 0. */ .nca_hdr_fixed_key_moduli = { /* Fixed RSA key used to validate NCA signature 0. */
{ {
@ -509,6 +508,12 @@ void pki_print_keys(nca_keyset_t *keyset) {
PRINT_KEY_WITH_NAME_IDX(keyset->master_kek_sources[i], master_kek_source, i); PRINT_KEY_WITH_NAME_IDX(keyset->master_kek_sources[i], master_kek_source, i);
} }
printf("\n"); printf("\n");
PRINT_KEY_WITH_NAME(keyset->mariko_kek, mariko_kek);
PRINT_KEY_WITH_NAME(keyset->mariko_bek, mariko_bek);
for (unsigned int i = 0x0; i < 0xC; i++) {
PRINT_KEY_WITH_NAME_IDX(keyset->mariko_aes_class_keys[i], mariko_aes_class_key, i);
}
printf("\n");
for (unsigned int i = 0x0; i < 0x20; i++) { for (unsigned int i = 0x0; i < 0x20; i++) {
PRINT_KEY_WITH_NAME_IDX(keyset->master_keks[i], master_kek, i); PRINT_KEY_WITH_NAME_IDX(keyset->master_keks[i], master_kek, i);
} }

View File

@ -22,6 +22,9 @@ typedef struct {
unsigned char keyblob_keys[0x20][0x10]; /* Actual keys used to decrypt keyblobs. NOTE: CONSOLE UNIQUE.*/ unsigned char keyblob_keys[0x20][0x10]; /* Actual keys used to decrypt keyblobs. NOTE: CONSOLE UNIQUE.*/
unsigned char keyblob_mac_keys[0x20][0x10]; /* Keys used to validate keyblobs. NOTE: CONSOLE UNIQUE. */ unsigned char keyblob_mac_keys[0x20][0x10]; /* Keys used to validate keyblobs. NOTE: CONSOLE UNIQUE. */
unsigned char encrypted_keyblobs[0x20][0xB0]; /* Actual encrypted keyblobs (EKS). NOTE: CONSOLE UNIQUE. */ unsigned char encrypted_keyblobs[0x20][0xB0]; /* Actual encrypted keyblobs (EKS). NOTE: CONSOLE UNIQUE. */
unsigned char mariko_aes_class_keys[0xC][0x10]; /* AES Class Keys set by mariko bootrom. */
unsigned char mariko_kek[0x10]; /* Key Encryption Key for mariko. */
unsigned char mariko_bek[0x10]; /* Boot Encryption Key for mariko. */
unsigned char keyblobs[0x20][0x90]; /* Actual decrypted keyblobs (EKS). */ unsigned char keyblobs[0x20][0x90]; /* Actual decrypted keyblobs (EKS). */
unsigned char keyblob_key_sources[0x20][0x10]; /* Seeds for keyblob keys. */ unsigned char keyblob_key_sources[0x20][0x10]; /* Seeds for keyblob keys. */
unsigned char keyblob_mac_key_source[0x10]; /* Seed for keyblob MAC key derivation. */ unsigned char keyblob_mac_key_source[0x10]; /* Seed for keyblob MAC key derivation. */