exosphere: update to support 10.0.0

This commit is contained in:
Michael Scire 2020-04-13 23:30:54 -07:00
parent 6719abec65
commit aa4c79cd9c
15 changed files with 344 additions and 149 deletions

View file

@ -263,19 +263,20 @@ uint32_t fuse_get_5x_key_generation(void) {
/* Returns the fuse version expected for the firmware. */ /* Returns the fuse version expected for the firmware. */
uint32_t fuse_get_expected_fuse_version(uint32_t target_firmware) { uint32_t fuse_get_expected_fuse_version(uint32_t target_firmware) {
static const uint8_t expected_versions[ATMOSPHERE_TARGET_FIRMWARE_COUNT+1] = { static const uint8_t expected_versions[ATMOSPHERE_TARGET_FIRMWARE_COUNT+1] = {
[ATMOSPHERE_TARGET_FIRMWARE_100] = 1, [ATMOSPHERE_TARGET_FIRMWARE_100] = 1,
[ATMOSPHERE_TARGET_FIRMWARE_200] = 2, [ATMOSPHERE_TARGET_FIRMWARE_200] = 2,
[ATMOSPHERE_TARGET_FIRMWARE_300] = 3, [ATMOSPHERE_TARGET_FIRMWARE_300] = 3,
/* [ATMOSPHERE_TARGET_FIRMWARE_302] = 4, */ /* [ATMOSPHERE_TARGET_FIRMWARE_302] = 4, */
[ATMOSPHERE_TARGET_FIRMWARE_400] = 5, [ATMOSPHERE_TARGET_FIRMWARE_400] = 5,
[ATMOSPHERE_TARGET_FIRMWARE_500] = 6, [ATMOSPHERE_TARGET_FIRMWARE_500] = 6,
[ATMOSPHERE_TARGET_FIRMWARE_600] = 7, [ATMOSPHERE_TARGET_FIRMWARE_600] = 7,
[ATMOSPHERE_TARGET_FIRMWARE_620] = 8, [ATMOSPHERE_TARGET_FIRMWARE_620] = 8,
[ATMOSPHERE_TARGET_FIRMWARE_700] = 9, [ATMOSPHERE_TARGET_FIRMWARE_700] = 9,
[ATMOSPHERE_TARGET_FIRMWARE_800] = 9, [ATMOSPHERE_TARGET_FIRMWARE_800] = 9,
[ATMOSPHERE_TARGET_FIRMWARE_810] = 10, [ATMOSPHERE_TARGET_FIRMWARE_810] = 10,
[ATMOSPHERE_TARGET_FIRMWARE_900] = 11, [ATMOSPHERE_TARGET_FIRMWARE_900] = 11,
[ATMOSPHERE_TARGET_FIRMWARE_910] = 12, [ATMOSPHERE_TARGET_FIRMWARE_910] = 12,
[ATMOSPHERE_TARGET_FIRMWARE_1000] = 13,
}; };
if (target_firmware > ATMOSPHERE_TARGET_FIRMWARE_COUNT) { if (target_firmware > ATMOSPHERE_TARGET_FIRMWARE_COUNT) {

View file

@ -149,6 +149,7 @@ static void setup_se(void) {
case ATMOSPHERE_TARGET_FIRMWARE_810: case ATMOSPHERE_TARGET_FIRMWARE_810:
case ATMOSPHERE_TARGET_FIRMWARE_900: case ATMOSPHERE_TARGET_FIRMWARE_900:
case ATMOSPHERE_TARGET_FIRMWARE_910: case ATMOSPHERE_TARGET_FIRMWARE_910:
case ATMOSPHERE_TARGET_FIRMWARE_1000:
derive_new_device_keys(KEYSLOT_SWITCH_5XNEWDEVICEKEYGENKEY); derive_new_device_keys(KEYSLOT_SWITCH_5XNEWDEVICEKEYGENKEY);
break; break;
} }
@ -338,7 +339,7 @@ static bool validate_package2_metadata(package2_meta_t *metadata) {
/* Perform version checks. */ /* Perform version checks. */
/* We will be compatible with all package2s released before current, but not newer ones. */ /* We will be compatible with all package2s released before current, but not newer ones. */
if (metadata->version_max >= PACKAGE2_MINVER_THEORETICAL && metadata->version_min < PACKAGE2_MAXVER_910_CURRENT) { if (metadata->version_max >= PACKAGE2_MINVER_THEORETICAL && metadata->version_min < PACKAGE2_MAXVER_1000_CURRENT) {
return true; return true;
} }
@ -466,6 +467,7 @@ static void copy_warmboot_bin_to_dram() {
case ATMOSPHERE_TARGET_FIRMWARE_810: case ATMOSPHERE_TARGET_FIRMWARE_810:
case ATMOSPHERE_TARGET_FIRMWARE_900: case ATMOSPHERE_TARGET_FIRMWARE_900:
case ATMOSPHERE_TARGET_FIRMWARE_910: case ATMOSPHERE_TARGET_FIRMWARE_910:
case ATMOSPHERE_TARGET_FIRMWARE_1000:
warmboot_src = (uint8_t *)0x4003E000; warmboot_src = (uint8_t *)0x4003E000;
break; break;
} }
@ -551,6 +553,9 @@ void load_package2(coldboot_crt0_reloc_list_t *reloc_list) {
case ATMOSPHERE_TARGET_FIRMWARE_910: case ATMOSPHERE_TARGET_FIRMWARE_910:
MAKE_REG32(PMC_BASE + 0x360) = 0x18C; MAKE_REG32(PMC_BASE + 0x360) = 0x18C;
break; break;
case ATMOSPHERE_TARGET_FIRMWARE_1000:
MAKE_REG32(PMC_BASE + 0x360) = 0x1AD;
break;
} }
} }

View file

@ -73,7 +73,8 @@ static inline uintptr_t get_nx_bootloader_mailbox_base(unsigned int targetfw) {
#define PACKAGE2_MAXVER_700_800 0xA #define PACKAGE2_MAXVER_700_800 0xA
#define PACKAGE2_MAXVER_810 0xB #define PACKAGE2_MAXVER_810 0xB
#define PACKAGE2_MAXVER_900 0xC #define PACKAGE2_MAXVER_900 0xC
#define PACKAGE2_MAXVER_910_CURRENT 0xD #define PACKAGE2_MAXVER_910_920 0xD
#define PACKAGE2_MAXVER_1000_CURRENT 0xE
#define PACKAGE2_MINVER_100 0x3 #define PACKAGE2_MINVER_100 0x3
#define PACKAGE2_MINVER_200 0x4 #define PACKAGE2_MINVER_200 0x4
@ -86,7 +87,8 @@ static inline uintptr_t get_nx_bootloader_mailbox_base(unsigned int targetfw) {
#define PACKAGE2_MINVER_700_800 0xB #define PACKAGE2_MINVER_700_800 0xB
#define PACKAGE2_MINVER_810 0xC #define PACKAGE2_MINVER_810 0xC
#define PACKAGE2_MINVER_900 0xD #define PACKAGE2_MINVER_900 0xD
#define PACKAGE2_MINVER_910_CURRENT 0xE #define PACKAGE2_MINVER_910_920 0xE
#define PACKAGE2_MINVER_1000_CURRENT 0xF
typedef struct { typedef struct {
union { union {

View file

@ -0,0 +1,20 @@
/*
* Copyright (c) 2018-2020 Atmosphère-NX
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "rsa_common.h"
/* Instantiate the shared RSA data inside a single translation unit. */
rsa_shared_data_t g_rsa_shared_data = {};

View file

@ -0,0 +1,36 @@
/*
* Copyright (c) 2018-2020 Atmosphère-NX
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef EXOSPHERE_RSA_COMMON_H
#define EXOSPHERE_RSA_COMMON_H
#include <stdint.h>
typedef union {
struct {
uint8_t user_data[0x100];
} storage_exp_mod;
struct {
uint32_t master_key_rev;
uint32_t type;
uint64_t expected_label_hash[4];
} unwrap_titlekey;
} rsa_shared_data_t __attribute__((aligned(4)));
_Static_assert(sizeof(rsa_shared_data_t) == 0x100);
extern rsa_shared_data_t g_rsa_shared_data;
#endif

View file

@ -338,7 +338,7 @@ void se_aes_cbc_decrypt_insecure(unsigned int keyslot, uint32_t out_ll_paddr, ui
se_aes_crypt_insecure_internal(keyslot, out_ll_paddr, in_ll_paddr, size, 0x66, false, callback); se_aes_crypt_insecure_internal(keyslot, out_ll_paddr, in_ll_paddr, size, 0x66, false, callback);
} }
void se_exp_mod(unsigned int keyslot, void *buf, size_t size, unsigned int (*callback)(void)) { void se_exp_mod(unsigned int keyslot, const void *buf, size_t size, unsigned int (*callback)(void)) {
volatile tegra_se_t *se = se_get_regs(); volatile tegra_se_t *se = se_get_regs();
uint8_t stack_buf[KEYSIZE_RSA_MAX]; uint8_t stack_buf[KEYSIZE_RSA_MAX];
@ -348,7 +348,7 @@ void se_exp_mod(unsigned int keyslot, void *buf, size_t size, unsigned int (*cal
/* Endian swap the input. */ /* Endian swap the input. */
for (size_t i = 0; i < size; i++) { for (size_t i = 0; i < size; i++) {
stack_buf[i] = *((uint8_t *)buf + size - i - 1); stack_buf[i] = *((const uint8_t *)buf + size - i - 1);
} }
se->SE_CONFIG = (ALG_RSA | DST_RSAREG); se->SE_CONFIG = (ALG_RSA | DST_RSAREG);

View file

@ -213,7 +213,7 @@ void se_aes_256_cbc_encrypt(unsigned int keyslot, void *dst, size_t dst_size, co
void se_calculate_sha256(void *dst, const void *src, size_t src_size); void se_calculate_sha256(void *dst, const void *src, size_t src_size);
/* RSA API */ /* RSA API */
void se_exp_mod(unsigned int keyslot, void *buf, size_t size, unsigned int (*callback)(void)); void se_exp_mod(unsigned int keyslot, const void *buf, size_t size, unsigned int (*callback)(void));
void se_get_exp_mod_output(void *buf, size_t size); void se_get_exp_mod_output(void *buf, size_t size);
void se_synchronous_exp_mod(unsigned int keyslot, void *dst, size_t dst_size, const void *src, size_t src_size); void se_synchronous_exp_mod(unsigned int keyslot, void *dst, size_t dst_size, const void *src, size_t src_size);
bool se_rsa2048_pss_verify(const void *signature, size_t signature_size, const void *modulus, size_t modulus_size, const void *data, size_t data_size); bool se_rsa2048_pss_verify(const void *signature, size_t signature_size, const void *modulus, size_t modulus_size, const void *data, size_t data_size);

View file

@ -188,6 +188,7 @@ void set_version_specific_smcs(void) {
case ATMOSPHERE_TARGET_FIRMWARE_810: case ATMOSPHERE_TARGET_FIRMWARE_810:
case ATMOSPHERE_TARGET_FIRMWARE_900: case ATMOSPHERE_TARGET_FIRMWARE_900:
case ATMOSPHERE_TARGET_FIRMWARE_910: case ATMOSPHERE_TARGET_FIRMWARE_910:
case ATMOSPHERE_TARGET_FIRMWARE_1000:
/* No more LoadSecureExpModKey. */ /* No more LoadSecureExpModKey. */
g_smc_user_table[0xE].handler = NULL; g_smc_user_table[0xE].handler = NULL;
g_smc_user_table[0xC].id = 0xC300D60C; g_smc_user_table[0xC].id = 0xC300D60C;
@ -433,19 +434,18 @@ uint32_t smc_get_result(smc_args_t *args) {
} }
uint32_t smc_exp_mod_get_result(void *buf, uint64_t size) { uint32_t smc_exp_mod_get_result(void *buf, uint64_t size) {
if (get_exp_mod_done() != 1) { uint32_t res = get_exp_mod_result();
return 3; if (res == 0) {
if (size == 0x100) {
se_get_exp_mod_output(buf, 0x100);
/* smc_exp_mod is done now. */
clear_user_smc_in_progress();
res = 0;
} else {
res = 2;
}
} }
return res;
if (size != 0x100) {
return 2;
}
se_get_exp_mod_output(buf, 0x100);
/* smc_exp_mod is done now. */
clear_user_smc_in_progress();
return 0;
} }
uint32_t smc_exp_mod(smc_args_t *args) { uint32_t smc_exp_mod(smc_args_t *args) {
@ -508,30 +508,31 @@ uint32_t smc_unwrap_rsa_oaep_wrapped_titlekey_get_result(void *buf, uint64_t siz
uint8_t aes_wrapped_titlekey[0x10]; uint8_t aes_wrapped_titlekey[0x10];
uint8_t titlekey[0x10]; uint8_t titlekey[0x10];
uint64_t sealed_titlekey[2]; uint64_t sealed_titlekey[2];
if (get_exp_mod_done() != 1) { uint32_t res = get_exp_mod_result();
return 3; if (res == 0) {
if (size == 0x10) {
se_get_exp_mod_output(rsa_wrapped_titlekey, 0x100);
if (tkey_rsa_oaep_unwrap(aes_wrapped_titlekey, 0x10, rsa_wrapped_titlekey, 0x100) == 0x10) {
tkey_aes_unwrap(titlekey, 0x10, aes_wrapped_titlekey, 0x10);
seal_titlekey(sealed_titlekey, 0x10, titlekey, 0x10);
p_sealed_key[0] = sealed_titlekey[0];
p_sealed_key[1] = sealed_titlekey[1];
res = 0;
} else {
/* Failed to extract RSA OAEP wrapped key. */
res = 2;
}
/* smc_unwrap_rsa_oaep_wrapped_titlekey is done now. */
clear_user_smc_in_progress();
} else {
res = 2;
}
} }
if (size != 0x10) { return res;
return 2;
}
se_get_exp_mod_output(rsa_wrapped_titlekey, 0x100);
if (tkey_rsa_oaep_unwrap(aes_wrapped_titlekey, 0x10, rsa_wrapped_titlekey, 0x100) != 0x10) {
/* Failed to extract RSA OAEP wrapped key. */
clear_user_smc_in_progress();
return 2;
}
tkey_aes_unwrap(titlekey, 0x10, aes_wrapped_titlekey, 0x10);
seal_titlekey(sealed_titlekey, 0x10, titlekey, 0x10);
p_sealed_key[0] = sealed_titlekey[0];
p_sealed_key[1] = sealed_titlekey[1];
/* smc_unwrap_rsa_oaep_wrapped_titlekey is done now. */
clear_user_smc_in_progress();
return 0;
} }
uint32_t smc_unwrap_rsa_oaep_wrapped_titlekey(smc_args_t *args) { uint32_t smc_unwrap_rsa_oaep_wrapped_titlekey(smc_args_t *args) {

View file

@ -34,12 +34,93 @@
/* Globals. */ /* Globals. */
static bool g_crypt_aes_done = false; static bool g_crypt_aes_done = false;
static bool g_exp_mod_done = false; static uint32_t g_exp_mod_result = 0;
static uint8_t g_imported_exponents[4][0x100]; static uint8_t g_imported_exponents[4][0x100];
static uint8_t g_imported_moduli[4][0x100];
static bool g_is_modulus_verified[4];
static const uint8_t g_rsa_public_key[4] = { 0x00, 0x01, 0x00, 0x01 };
static const uint8_t g_rsa_test_vector[0x100] = {
'D', 'D', 'D', 'D', 'D', 'D', 'D', 'D', 'D', 'D', 'D', 'D', 'D', 'D', 'D', 'D',
'D', 'D', 'D', 'D', 'D', 'D', 'D', 'D', 'D', 'D', 'D', 'D', 'D', 'D', 'D', 'D',
'D', 'D', 'D', 'D', 'D', 'D', 'D', 'D', 'D', 'D', 'D', 'D', 'D', 'D', 'D', 'D',
'D', 'D', 'D', 'D', 'D', 'D', 'D', 'D', 'D', 'D', 'D', 'D', 'D', 'D', 'D', 'D',
'D', 'D', 'D', 'D', 'D', 'D', 'D', 'D', 'D', 'D', 'D', 'D', 'D', 'D', 'D', 'D',
'D', 'D', 'D', 'D', 'D', 'D', 'D', 'D', 'D', 'D', 'D', 'D', 'D', 'D', 'D', 'D',
'D', 'D', 'D', 'D', 'D', 'D', 'D', 'D', 'D', 'D', 'D', 'D', 'D', 'D', 'D', 'D',
'D', 'D', 'D', 'D', 'D', 'D', 'D', 'D', 'D', 'D', 'D', 'D', 'D', 'D', 'D', 'D',
'D', 'D', 'D', 'D', 'D', 'D', 'D', 'D', 'D', 'D', 'D', 'D', 'D', 'D', 'D', 'D',
'D', 'D', 'D', 'D', 'D', 'D', 'D', 'D', 'D', 'D', 'D', 'D', 'D', 'D', 'D', 'D',
'D', 'D', 'D', 'D', 'D', 'D', 'D', 'D', 'D', 'D', 'D', 'D', 'D', 'D', 'D', 'D',
'D', 'D', 'D', 'D', 'D', 'D', 'D', 'D', 'D', 'D', 'D', 'D', 'D', 'D', 'D', 'D',
'D', 'D', 'D', 'D', 'D', 'D', 'D', 'D', 'D', 'D', 'D', 'D', 'D', 'D', 'D', 'D',
'D', 'D', 'D', 'D', 'D', 'D', 'D', 'D', 'D', 'D', 'D', 'D', 'D', 'D', 'D', 'D',
'D', 'D', 'D', 'D', 'D', 'D', 'D', 'D', 'D', 'D', 'D', 'D', 'D', 'D', 'D', 'D',
'D', 'D', 'D', 'D', 'D', 'D', 'D', 'D', 'D', 'D', 'D', 'D', 'D', 'D', 'D', 'D'
};
static uint32_t g_test_exp_mod_keyslot = 0;
static uint32_t g_test_exp_mod_usecase = 0;
static bool g_test_exp_mod_in_progress = false;
static uint8_t g_rsausecase_to_cryptousecase[5] = {1, 2, 3, 5, 6}; static uint8_t g_rsausecase_to_cryptousecase[5] = {1, 2, 3, 5, 6};
static void import_rsa_exponent(unsigned int which, const uint8_t *exponent, uint64_t size) {
g_is_modulus_verified[which] = false;
for (unsigned int i = 0; i < 0x100; i++) {
g_imported_exponents[which][i] = exponent[i];
g_imported_moduli[which][i] = 0;
}
}
static void import_rsa_modulus(unsigned int which, const uint8_t *modulus, uint64_t size) {
uint64_t clamped_size = 0x100;
if (size <= 0x100) {
clamped_size = size;
}
if (clamped_size != 0) {
/* The official secure monitor implements this via bit-fiddling, */
/* and to prevent accidental inaccuracy we will too. */
/* It's probably done to prevent errors on negative sizes. */
uint64_t remaining = 0x100;
if (size != 0x100 && (~size >= ~0xFFFFFFFFFFFFFEFFULL)) {
remaining = size;
}
memcpy(&g_imported_moduli[which][0], modulus, remaining);
}
}
static bool load_imported_rsa_keypair(unsigned int keyslot, unsigned int which) {
if (!g_is_modulus_verified[which]) {
return false;
}
set_rsa_keyslot(keyslot, g_imported_moduli[which], 0x100, g_imported_exponents[which], 0x100);
return true;
}
static void test_rsa_modulus_public(unsigned int which, unsigned int keyslot, const uint8_t *modulus, uint64_t modulus_size, unsigned int (*callback)(void)) {
import_rsa_modulus(which, modulus, modulus_size);
set_rsa_keyslot(keyslot, modulus, modulus_size, g_rsa_public_key, 0x4);
se_exp_mod(keyslot, g_rsa_test_vector, 0x100, callback);
}
static void test_rsa_modulus_private(unsigned int which, unsigned int keyslot, unsigned int (*callback)(void)) {
uint8_t exponentiated_data[0x100];
se_get_exp_mod_output(exponentiated_data, sizeof(exponentiated_data));
set_rsa_keyslot(keyslot, g_imported_moduli[which], 0x100, g_imported_exponents[which], 0x100);
se_exp_mod(keyslot, exponentiated_data, 0x100, callback);
}
static void validate_rsa_result(unsigned int which) {
char result[0x100];
se_get_exp_mod_output(result, sizeof(result));
if (memcmp(result, g_rsa_test_vector, sizeof(result)) == 0) {
g_is_modulus_verified[which] = true;
}
}
static bool is_user_keyslot_valid(unsigned int keyslot) { static bool is_user_keyslot_valid(unsigned int keyslot) {
switch (exosphere_get_target_firmware()) { switch (exosphere_get_target_firmware()) {
case ATMOSPHERE_TARGET_FIRMWARE_100: case ATMOSPHERE_TARGET_FIRMWARE_100:
@ -55,27 +136,45 @@ static bool is_user_keyslot_valid(unsigned int keyslot) {
case ATMOSPHERE_TARGET_FIRMWARE_810: case ATMOSPHERE_TARGET_FIRMWARE_810:
case ATMOSPHERE_TARGET_FIRMWARE_900: case ATMOSPHERE_TARGET_FIRMWARE_900:
case ATMOSPHERE_TARGET_FIRMWARE_910: case ATMOSPHERE_TARGET_FIRMWARE_910:
case ATMOSPHERE_TARGET_FIRMWARE_1000:
default: default:
return keyslot <= 5; return keyslot <= 5;
} }
} }
void set_exp_mod_done(bool done) { void set_exp_mod_result(uint32_t result) {
g_exp_mod_done = done; g_exp_mod_result = result;
} }
bool get_exp_mod_done(void) { uint32_t get_exp_mod_result(void) {
return g_exp_mod_done; return g_exp_mod_result;
} }
uint32_t exp_mod_done_handler(void) { uint32_t exp_mod_done_handler(void) {
set_exp_mod_done(true); set_exp_mod_result(0);
se_trigger_interrupt(); se_trigger_interrupt();
return 0; return 0;
} }
static uint32_t test_exp_mod_done_handler(void) {
if (g_test_exp_mod_in_progress) {
g_test_exp_mod_in_progress = false;
test_rsa_modulus_private(g_test_exp_mod_usecase, g_test_exp_mod_keyslot, test_exp_mod_done_handler);
} else {
validate_rsa_result(g_test_exp_mod_usecase);
if (load_imported_rsa_keypair(g_test_exp_mod_keyslot, g_test_exp_mod_usecase)) {
se_exp_mod(g_test_exp_mod_keyslot, g_rsa_shared_data.storage_exp_mod.user_data, 0x100, exp_mod_done_handler);
} else {
set_exp_mod_result(2);
se_trigger_interrupt();
}
}
return 0;
}
uint32_t user_exp_mod(smc_args_t *args) { uint32_t user_exp_mod(smc_args_t *args) {
uint8_t modulus[0x100]; uint8_t modulus[0x100];
uint8_t exponent[0x100]; uint8_t exponent[0x100];
@ -108,7 +207,8 @@ uint32_t user_exp_mod(smc_args_t *args) {
return 2; return 2;
} }
set_exp_mod_done(false); set_exp_mod_result(3);
/* Hardcode RSA keyslot 0. */ /* Hardcode RSA keyslot 0. */
set_rsa_keyslot(0, modulus, 0x100, exponent, exponent_size); set_rsa_keyslot(0, modulus, 0x100, exponent, exponent_size);
se_exp_mod(0, input, 0x100, exp_mod_done_handler); se_exp_mod(0, input, 0x100, exp_mod_done_handler);
@ -650,10 +750,21 @@ uint32_t user_secure_exp_mod(smc_args_t *args) {
return 2; return 2;
} }
set_exp_mod_done(false); set_exp_mod_result(3);
/* Hardcode RSA keyslot 0. */ /* Hardcode RSA keyslot 0. */
set_rsa_keyslot(0, modulus, 0x100, g_imported_exponents[exponent_id], 0x100); if (exosphere_get_target_firmware() < ATMOSPHERE_TARGET_FIRMWARE_1000) {
se_exp_mod(0, input, 0x100, exp_mod_done_handler); set_rsa_keyslot(0, modulus, 0x100, g_imported_exponents[exponent_id], 0x100);
se_exp_mod(0, input, 0x100, exp_mod_done_handler);
} else if (load_imported_rsa_keypair(0, exponent_id)) {
se_exp_mod(0, input, 0x100, exp_mod_done_handler);
} else {
memcpy(g_rsa_shared_data.storage_exp_mod.user_data, input, 0x100);
g_test_exp_mod_keyslot = 0;
g_test_exp_mod_usecase = exponent_id;
g_test_exp_mod_in_progress = true;
test_rsa_modulus_public(exponent_id, 0, modulus, 0x100, test_exp_mod_done_handler);
}
return 0; return 0;
} }
@ -700,7 +811,7 @@ uint32_t user_unwrap_rsa_oaep_wrapped_titlekey(smc_args_t *args) {
return 2; return 2;
} }
set_exp_mod_done(false); set_exp_mod_result(3);
/* Expected label_hash occupies args->X[3] to args->X[6]. */ /* Expected label_hash occupies args->X[3] to args->X[6]. */
tkey_set_expected_label_hash(&args->X[3]); tkey_set_expected_label_hash(&args->X[3]);
@ -879,6 +990,7 @@ uint32_t user_decrypt_or_import_rsa_key(smc_args_t *args) {
} }
unsigned int exponent_id; unsigned int exponent_id;
bool import_modulus;
switch (usecase) { switch (usecase) {
case 0: case 0:
@ -888,22 +1000,33 @@ uint32_t user_decrypt_or_import_rsa_key(smc_args_t *args) {
return 0; return 0;
case 1: case 1:
exponent_id = 1; exponent_id = 1;
import_modulus = false;
break; break;
case 2: case 2:
exponent_id = 0; exponent_id = 0;
import_modulus = true;
break; break;
case 3: case 3:
exponent_id = 2; exponent_id = 2;
import_modulus = false;
break; break;
case 4: case 4:
exponent_id = 3; exponent_id = 3;
import_modulus = true;
break; break;
default: default:
generic_panic(); generic_panic();
} }
/* Copy key to global. */ /* Modulus import isn't implemented on < 10.0.0. */
memcpy(g_imported_exponents[exponent_id], user_data, 0x100); import_modulus &= (exosphere_get_target_firmware() >= ATMOSPHERE_TARGET_FIRMWARE_1000);
/* Import the key. */
import_rsa_exponent(exponent_id, user_data, 0x100);
if (import_modulus) {
import_rsa_modulus(exponent_id, user_data + 0x100, 0x100);
g_is_modulus_verified[exponent_id] = true;
}
return 0; return 0;
} }

View file

@ -41,7 +41,7 @@ uint32_t user_decrypt_or_import_rsa_key(smc_args_t *args);
void set_crypt_aes_done(bool done); void set_crypt_aes_done(bool done);
bool get_crypt_aes_done(void); bool get_crypt_aes_done(void);
void set_exp_mod_done(bool done); void set_exp_mod_result(uint32_t result);
bool get_exp_mod_done(void); uint32_t get_exp_mod_result(void);
#endif #endif

View file

@ -1,4 +1,4 @@
/* /*expected_label_hash
* Copyright (c) 2018-2020 Atmosphère-NX * Copyright (c) 2018-2020 Atmosphère-NX
* *
* This program is free software; you can redistribute it and/or modify it * This program is free software; you can redistribute it and/or modify it
@ -25,14 +25,10 @@
#include "masterkey.h" #include "masterkey.h"
#include "se.h" #include "se.h"
static uint64_t g_tkey_expected_label_hash[4];
static unsigned int g_tkey_master_key_rev = MASTERKEY_REVISION_MAX;
static unsigned int g_tkey_type = 0;
/* Set the expected db prefix. */ /* Set the expected db prefix. */
void tkey_set_expected_label_hash(uint64_t *label_hash) { void tkey_set_expected_label_hash(uint64_t *label_hash) {
for (unsigned int i = 0; i < 4; i++) { for (unsigned int i = 0; i < 4; i++) {
g_tkey_expected_label_hash[i] = label_hash[i]; g_rsa_shared_data.unwrap_titlekey.expected_label_hash[i] = label_hash[i];
} }
} }
@ -40,7 +36,7 @@ void tkey_set_master_key_rev(unsigned int master_key_rev) {
if (master_key_rev >= MASTERKEY_REVISION_MAX) { if (master_key_rev >= MASTERKEY_REVISION_MAX) {
generic_panic(); generic_panic();
} }
g_tkey_master_key_rev = master_key_rev; g_rsa_shared_data.unwrap_titlekey.master_key_rev = master_key_rev;
} }
static void tkey_validate_type(unsigned int type) { static void tkey_validate_type(unsigned int type) {
@ -51,7 +47,7 @@ static void tkey_validate_type(unsigned int type) {
void tkey_set_type(unsigned int type) { void tkey_set_type(unsigned int type) {
tkey_validate_type(type); tkey_validate_type(type);
g_tkey_type = type; g_rsa_shared_data.unwrap_titlekey.type = type;
} }
/* Reference for MGF1 can be found here: https://en.wikipedia.org/wiki/Mask_generation_function#MGF1 */ /* Reference for MGF1 can be found here: https://en.wikipedia.org/wiki/Mask_generation_function#MGF1 */
@ -116,7 +112,7 @@ size_t tkey_rsa_oaep_unwrap(void *dst, size_t dst_size, void *src, size_t src_si
uint8_t *db = message + 0x21; uint8_t *db = message + 0x21;
/* This will be passed to smc_unwrap_rsa_oaep_wrapped_titlekey. */ /* This will be passed to smc_unwrap_rsa_oaep_wrapped_titlekey. */
uint8_t *expected_label_hash = (uint8_t *)(&g_tkey_expected_label_hash[0]); uint8_t *expected_label_hash = (uint8_t *)(&g_rsa_shared_data.unwrap_titlekey.expected_label_hash[0]);
/* Unmask the salt. */ /* Unmask the salt. */
calculate_mgf1_and_xor(salt, 0x20, db, 0xDF); calculate_mgf1_and_xor(salt, 0x20, db, 0xDF);
@ -171,13 +167,13 @@ static const uint8_t titlekek_sources[TITLEKEY_TYPE_MAX+1][0x10] = {
}; };
void tkey_aes_unwrap(void *dst, size_t dst_size, const void *src, size_t src_size) { void tkey_aes_unwrap(void *dst, size_t dst_size, const void *src, size_t src_size) {
if (g_tkey_master_key_rev >= MASTERKEY_REVISION_MAX || dst_size != 0x10 || src_size != 0x10) { if (g_rsa_shared_data.unwrap_titlekey.master_key_rev >= MASTERKEY_REVISION_MAX || dst_size != 0x10 || src_size != 0x10) {
generic_panic(); generic_panic();
} }
/* Generate the appropriate titlekek into keyslot 9. */ /* Generate the appropriate titlekek into keyslot 9. */
unsigned int master_keyslot = mkey_get_keyslot(g_tkey_master_key_rev); unsigned int master_keyslot = mkey_get_keyslot(g_rsa_shared_data.unwrap_titlekey.master_key_rev);
decrypt_data_into_keyslot(KEYSLOT_SWITCH_TEMPKEY, master_keyslot, titlekek_sources[g_tkey_type], 0x10); decrypt_data_into_keyslot(KEYSLOT_SWITCH_TEMPKEY, master_keyslot, titlekek_sources[g_rsa_shared_data.unwrap_titlekey.type], 0x10);
/* Unwrap the titlekey using the titlekek. */ /* Unwrap the titlekey using the titlekek. */
se_aes_ecb_decrypt_block(KEYSLOT_SWITCH_TEMPKEY, dst, 0x10, src, 0x10); se_aes_ecb_decrypt_block(KEYSLOT_SWITCH_TEMPKEY, dst, 0x10, src, 0x10);

View file

@ -18,6 +18,7 @@
#define EXOSPHERE_TITLEKEY_H #define EXOSPHERE_TITLEKEY_H
#include <stdint.h> #include <stdint.h>
#include "rsa_common.h"
#define TITLEKEY_TYPE_MAX 0x1 #define TITLEKEY_TYPE_MAX 0x1

View file

@ -66,9 +66,13 @@ namespace ams::hos {
break; break;
case exosphere::TargetFirmware_900: case exosphere::TargetFirmware_900:
g_hos_version = hos::Version_9_0_0; g_hos_version = hos::Version_9_0_0;
break;
case exosphere::TargetFirmware_910: case exosphere::TargetFirmware_910:
g_hos_version = hos::Version_9_1_0; g_hos_version = hos::Version_9_1_0;
break; break;
case exosphere::TargetFirmware_1000:
g_hos_version = hos::Version_10_0_0;
break;
AMS_UNREACHABLE_DEFAULT_CASE(); AMS_UNREACHABLE_DEFAULT_CASE();
} }
@ -139,6 +143,11 @@ namespace ams::hos {
minor = 1; minor = 1;
micro = 0; micro = 0;
break; break;
case hos::Version_10_0_0:
major = 10;
minor = 0;
micro = 0;
break;
AMS_UNREACHABLE_DEFAULT_CASE(); AMS_UNREACHABLE_DEFAULT_CASE();
} }
hosversionSet(MAKEHOSVERSION(major, minor, micro)); hosversionSet(MAKEHOSVERSION(major, minor, micro));

View file

@ -17,10 +17,10 @@
#define ATMOSPHERE_RELEASE_VERSION_MAJOR 0 #define ATMOSPHERE_RELEASE_VERSION_MAJOR 0
#define ATMOSPHERE_RELEASE_VERSION_MINOR 10 #define ATMOSPHERE_RELEASE_VERSION_MINOR 10
#define ATMOSPHERE_RELEASE_VERSION_MICRO 5 #define ATMOSPHERE_RELEASE_VERSION_MICRO 6
#define ATMOSPHERE_RELEASE_VERSION ATMOSPHERE_RELEASE_VERSION_MAJOR, ATMOSPHERE_RELEASE_VERSION_MINOR, ATMOSPHERE_RELEASE_VERSION_MICRO #define ATMOSPHERE_RELEASE_VERSION ATMOSPHERE_RELEASE_VERSION_MAJOR, ATMOSPHERE_RELEASE_VERSION_MINOR, ATMOSPHERE_RELEASE_VERSION_MICRO
#define ATMOSPHERE_SUPPORTED_HOS_VERSION_MAJOR 9 #define ATMOSPHERE_SUPPORTED_HOS_VERSION_MAJOR 10
#define ATMOSPHERE_SUPPORTED_HOS_VERSION_MINOR 2 #define ATMOSPHERE_SUPPORTED_HOS_VERSION_MINOR 0
#define ATMOSPHERE_SUPPORTED_HOS_VERSION_MICRO 0 #define ATMOSPHERE_SUPPORTED_HOS_VERSION_MICRO 0

View file

@ -15,20 +15,21 @@
*/ */
#pragma once #pragma once
#define ATMOSPHERE_TARGET_FIRMWARE_100 1 #define ATMOSPHERE_TARGET_FIRMWARE_100 1
#define ATMOSPHERE_TARGET_FIRMWARE_200 2 #define ATMOSPHERE_TARGET_FIRMWARE_200 2
#define ATMOSPHERE_TARGET_FIRMWARE_300 3 #define ATMOSPHERE_TARGET_FIRMWARE_300 3
#define ATMOSPHERE_TARGET_FIRMWARE_400 4 #define ATMOSPHERE_TARGET_FIRMWARE_400 4
#define ATMOSPHERE_TARGET_FIRMWARE_500 5 #define ATMOSPHERE_TARGET_FIRMWARE_500 5
#define ATMOSPHERE_TARGET_FIRMWARE_600 6 #define ATMOSPHERE_TARGET_FIRMWARE_600 6
#define ATMOSPHERE_TARGET_FIRMWARE_620 7 #define ATMOSPHERE_TARGET_FIRMWARE_620 7
#define ATMOSPHERE_TARGET_FIRMWARE_700 8 #define ATMOSPHERE_TARGET_FIRMWARE_700 8
#define ATMOSPHERE_TARGET_FIRMWARE_800 9 #define ATMOSPHERE_TARGET_FIRMWARE_800 9
#define ATMOSPHERE_TARGET_FIRMWARE_810 10 #define ATMOSPHERE_TARGET_FIRMWARE_810 10
#define ATMOSPHERE_TARGET_FIRMWARE_900 11 #define ATMOSPHERE_TARGET_FIRMWARE_900 11
#define ATMOSPHERE_TARGET_FIRMWARE_910 12 #define ATMOSPHERE_TARGET_FIRMWARE_910 12
#define ATMOSPHERE_TARGET_FIRMWARE_1000 13
#define ATMOSPHERE_TARGET_FIRMWARE_CURRENT ATMOSPHERE_TARGET_FIRMWARE_910 #define ATMOSPHERE_TARGET_FIRMWARE_CURRENT ATMOSPHERE_TARGET_FIRMWARE_1000
#define ATMOSPHERE_TARGET_FIRMWARE_MIN ATMOSPHERE_TARGET_FIRMWARE_100 #define ATMOSPHERE_TARGET_FIRMWARE_MIN ATMOSPHERE_TARGET_FIRMWARE_100
#define ATMOSPHERE_TARGET_FIRMWARE_MAX ATMOSPHERE_TARGET_FIRMWARE_CURRENT #define ATMOSPHERE_TARGET_FIRMWARE_MAX ATMOSPHERE_TARGET_FIRMWARE_CURRENT