Skip to content

Commit

Permalink
pk11: add proper support for newer (and mariko) package1
Browse files Browse the repository at this point in the history
  • Loading branch information
SciresM committed Jun 1, 2020
1 parent 55b13f0 commit c3415cf
Show file tree
Hide file tree
Showing 6 changed files with 369 additions and 59 deletions.
4 changes: 2 additions & 2 deletions aes.c
Expand Up @@ -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);

/* 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);
else
{
Expand Down Expand Up @@ -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);

/* 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);
else
{
Expand Down
18 changes: 17 additions & 1 deletion extkeys.c
Expand Up @@ -284,7 +284,13 @@ void extkeys_initialize_settings(hactool_settings_t *settings, FILE *f) {
} else if (strcmp(key, "tsec_key") == 0) {
parse_hex_key(keyset->tsec_key, value, sizeof(keyset->tsec_key));
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));
matched_key = 1;
} else if (strcmp(key, "package1_mac_kek") == 0) {
Expand Down Expand Up @@ -365,6 +371,16 @@ void extkeys_initialize_settings(hactool_settings_t *settings, FILE *f) {
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++) {
snprintf(test_name, sizeof(test_name), "master_kek_%02"PRIx32, i);
if (strcmp(key, test_name) == 0) {
Expand Down
255 changes: 213 additions & 42 deletions packages.c
Expand Up @@ -5,57 +5,174 @@
#include "rsa.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) {
fseeko64(ctx->file, 0, SEEK_SET);
if (fread(&ctx->stage1, 1, sizeof(ctx->stage1), ctx->file) != sizeof(ctx->stage1)) {
fprintf(stderr, "Failed to read PK11 Stage 1!\n");
exit(EXIT_FAILURE);
}

/* Check if PK11 was built in 2016. */
/* This is a heuristic to detect an older layout for the PK11 binary. */
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;
// Detect mariko
ctx->is_mariko = pk11_is_mariko(ctx);

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 {
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->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 {
ctx->is_pilot = 0;
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->stage1.pk11_size);
ctx->pk11 = malloc(ctx->pk11_size);
if (ctx->pk11 == NULL) {
fprintf(stderr, "Failed to allocate PK11!\n");
exit(EXIT_FAILURE);
}

if (fread(ctx->pk11, 1, ctx->stage1.pk11_size, ctx->file) != ctx->stage1.pk11_size) {
fprintf(stderr, "Failed to read PK11!\n");
exit(EXIT_FAILURE);
if (ctx->is_mariko) {
if (ctx->is_modern) {
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);
}

} else {
if (fread(ctx->pk11, 1, ctx->pk11_size, ctx->file) != ctx->pk11_size) {
fprintf(stderr, "Failed to read PK11!\n");
exit(EXIT_FAILURE);
}

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);
}
}
}

aes_ctx_t *crypt_ctx = NULL;
pk11_t dec_header;
for (unsigned int i = 0; i < 0x20; 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.ctr, 0x10);
aes_decrypt(crypt_ctx, &dec_header, ctx->pk11, sizeof(dec_header));
if (dec_header.magic == MAGIC_PK11) {
break;
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;
}
}
free_aes_ctx(crypt_ctx);
crypt_ctx = NULL;
}

if (crypt_ctx == NULL) {
if (!decrypted) {
fprintf(stderr, "Failed to decrypt PK11! Is correct key present?\n");
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);
if (pk11_size != ctx->stage1.pk11_size) {
if (pk11_size != ctx->pk11_size) {
fprintf(stderr, "PK11 seems corrupt!\n");
exit(EXIT_FAILURE);
}
Expand All @@ -71,13 +188,20 @@ void pk11_process(pk11_ctx_t *ctx) {

void pk11_print(pk11_ctx_t *ctx) {
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(" PK11 Size: %08"PRIx32"\n", ctx->stage1.pk11_size);
printf(" Warmboot.bin Size: %08"PRIx32"\n", ctx->pk11->warmboot_size);
printf(" NX_Bootloader.bin Size %08"PRIx32"\n", ctx->pk11->nx_bootloader_size);
printf(" Secure_Monitor.bin Size: %08"PRIx32"\n", ctx->pk11->secmon_size);
printf(" PK11 Size: %08"PRIx32"\n", ctx->pk11_size);
printf(" Warmboot.bin Size: %08"PRIx32"\n", pk11_get_warmboot_bin_size(ctx));
printf(" NX_Bootloader.bin Size %08"PRIx32"\n", pk11_get_nx_bootloader_size(ctx));
printf(" Secure_Monitor.bin Size: %08"PRIx32"\n", pk11_get_secmon_size(ctx));
printf("\n");
}

Expand All @@ -95,27 +219,74 @@ void pk11_save(pk11_ctx_t *ctx) {

/* Save Decrypted.bin */
printf("Saving decrypted binary to %s/Decrypted.bin\n", dirpath->char_path);
char *decrypted_bin = malloc(sizeof(ctx->stage1) + ctx->stage1.pk11_size);
if (decrypted_bin == NULL) {
fprintf(stderr, "Failed to allocate buffer!\n");
exit(EXIT_FAILURE);
if (ctx->is_mariko) {
char *decrypted_bin = malloc(sizeof(ctx->mariko_oem_header) + ctx->mariko_oem_header.bl_size);
if (decrypted_bin == NULL) {
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 */
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 */
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 */
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");
}
}

Expand Down

0 comments on commit c3415cf

Please sign in to comment.