diff --git a/exosphere/src/fuse.c b/exosphere/src/fuse.c
index 0d546415c..0ea888598 100644
--- a/exosphere/src/fuse.c
+++ b/exosphere/src/fuse.c
@@ -263,19 +263,20 @@ uint32_t fuse_get_5x_key_generation(void) {
/* Returns the fuse version expected for the firmware. */
uint32_t fuse_get_expected_fuse_version(uint32_t target_firmware) {
static const uint8_t expected_versions[ATMOSPHERE_TARGET_FIRMWARE_COUNT+1] = {
- [ATMOSPHERE_TARGET_FIRMWARE_100] = 1,
- [ATMOSPHERE_TARGET_FIRMWARE_200] = 2,
- [ATMOSPHERE_TARGET_FIRMWARE_300] = 3,
- /* [ATMOSPHERE_TARGET_FIRMWARE_302] = 4, */
- [ATMOSPHERE_TARGET_FIRMWARE_400] = 5,
- [ATMOSPHERE_TARGET_FIRMWARE_500] = 6,
- [ATMOSPHERE_TARGET_FIRMWARE_600] = 7,
- [ATMOSPHERE_TARGET_FIRMWARE_620] = 8,
- [ATMOSPHERE_TARGET_FIRMWARE_700] = 9,
- [ATMOSPHERE_TARGET_FIRMWARE_800] = 9,
- [ATMOSPHERE_TARGET_FIRMWARE_810] = 10,
- [ATMOSPHERE_TARGET_FIRMWARE_900] = 11,
- [ATMOSPHERE_TARGET_FIRMWARE_910] = 12,
+ [ATMOSPHERE_TARGET_FIRMWARE_100] = 1,
+ [ATMOSPHERE_TARGET_FIRMWARE_200] = 2,
+ [ATMOSPHERE_TARGET_FIRMWARE_300] = 3,
+ /* [ATMOSPHERE_TARGET_FIRMWARE_302] = 4, */
+ [ATMOSPHERE_TARGET_FIRMWARE_400] = 5,
+ [ATMOSPHERE_TARGET_FIRMWARE_500] = 6,
+ [ATMOSPHERE_TARGET_FIRMWARE_600] = 7,
+ [ATMOSPHERE_TARGET_FIRMWARE_620] = 8,
+ [ATMOSPHERE_TARGET_FIRMWARE_700] = 9,
+ [ATMOSPHERE_TARGET_FIRMWARE_800] = 9,
+ [ATMOSPHERE_TARGET_FIRMWARE_810] = 10,
+ [ATMOSPHERE_TARGET_FIRMWARE_900] = 11,
+ [ATMOSPHERE_TARGET_FIRMWARE_910] = 12,
+ [ATMOSPHERE_TARGET_FIRMWARE_1000] = 13,
};
if (target_firmware > ATMOSPHERE_TARGET_FIRMWARE_COUNT) {
diff --git a/exosphere/src/package2.c b/exosphere/src/package2.c
index c5eb8f877..fc3070e76 100644
--- a/exosphere/src/package2.c
+++ b/exosphere/src/package2.c
@@ -149,6 +149,7 @@ static void setup_se(void) {
case ATMOSPHERE_TARGET_FIRMWARE_810:
case ATMOSPHERE_TARGET_FIRMWARE_900:
case ATMOSPHERE_TARGET_FIRMWARE_910:
+ case ATMOSPHERE_TARGET_FIRMWARE_1000:
derive_new_device_keys(KEYSLOT_SWITCH_5XNEWDEVICEKEYGENKEY);
break;
}
@@ -338,7 +339,7 @@ static bool validate_package2_metadata(package2_meta_t *metadata) {
/* Perform version checks. */
/* 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;
}
@@ -466,6 +467,7 @@ static void copy_warmboot_bin_to_dram() {
case ATMOSPHERE_TARGET_FIRMWARE_810:
case ATMOSPHERE_TARGET_FIRMWARE_900:
case ATMOSPHERE_TARGET_FIRMWARE_910:
+ case ATMOSPHERE_TARGET_FIRMWARE_1000:
warmboot_src = (uint8_t *)0x4003E000;
break;
}
@@ -551,6 +553,9 @@ void load_package2(coldboot_crt0_reloc_list_t *reloc_list) {
case ATMOSPHERE_TARGET_FIRMWARE_910:
MAKE_REG32(PMC_BASE + 0x360) = 0x18C;
break;
+ case ATMOSPHERE_TARGET_FIRMWARE_1000:
+ MAKE_REG32(PMC_BASE + 0x360) = 0x1AD;
+ break;
}
}
diff --git a/exosphere/src/package2.h b/exosphere/src/package2.h
index cdf6599d3..ee2546cef 100644
--- a/exosphere/src/package2.h
+++ b/exosphere/src/package2.h
@@ -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_810 0xB
#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_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_810 0xC
#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 {
union {
diff --git a/exosphere/src/rsa_common.c b/exosphere/src/rsa_common.c
new file mode 100644
index 000000000..2dfbb3c1b
--- /dev/null
+++ b/exosphere/src/rsa_common.c
@@ -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 .
+ */
+
+#include "rsa_common.h"
+
+/* Instantiate the shared RSA data inside a single translation unit. */
+rsa_shared_data_t g_rsa_shared_data = {};
\ No newline at end of file
diff --git a/exosphere/src/rsa_common.h b/exosphere/src/rsa_common.h
new file mode 100644
index 000000000..41be75c30
--- /dev/null
+++ b/exosphere/src/rsa_common.h
@@ -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 .
+ */
+
+#ifndef EXOSPHERE_RSA_COMMON_H
+#define EXOSPHERE_RSA_COMMON_H
+#include
+
+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
diff --git a/exosphere/src/se.c b/exosphere/src/se.c
index 6529932f9..d487ee005 100644
--- a/exosphere/src/se.c
+++ b/exosphere/src/se.c
@@ -13,7 +13,7 @@
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*/
-
+
#include
#include "utils.h"
@@ -47,7 +47,7 @@ void ll_init(volatile se_ll_t *ll, void *buffer, size_t size) {
ll->addr_info.address = 0;
ll->addr_info.size = 0;
}
-
+
flush_dcache_range((uint8_t *)ll, (uint8_t *)ll + sizeof(*ll));
}
@@ -103,7 +103,7 @@ void se_validate_stored_vector(void) {
uint8_t calc_vector[0x10];
se_generate_test_vector(calc_vector);
-
+
/* Ensure nobody's messed with the security engine while we slept. */
if (memcmp(calc_vector, g_se_stored_test_vector, 0x10) != 0) {
generic_panic();
@@ -122,7 +122,7 @@ void se_generate_stored_vector(void) {
/* Set the flags for an AES keyslot. */
void set_aes_keyslot_flags(unsigned int keyslot, unsigned int flags) {
volatile tegra_se_t *se = se_get_regs();
-
+
if (keyslot >= KEYSLOT_AES_MAX) {
generic_panic();
}
@@ -141,7 +141,7 @@ void set_aes_keyslot_flags(unsigned int keyslot, unsigned int flags) {
/* Set the flags for an RSA keyslot. */
void set_rsa_keyslot_flags(unsigned int keyslot, unsigned int flags) {
volatile tegra_se_t *se = se_get_regs();
-
+
if (keyslot >= KEYSLOT_RSA_MAX) {
generic_panic();
}
@@ -160,7 +160,7 @@ void set_rsa_keyslot_flags(unsigned int keyslot, unsigned int flags) {
void clear_aes_keyslot(unsigned int keyslot) {
volatile tegra_se_t *se = se_get_regs();
-
+
if (keyslot >= KEYSLOT_AES_MAX) {
generic_panic();
}
@@ -174,7 +174,7 @@ void clear_aes_keyslot(unsigned int keyslot) {
void clear_rsa_keyslot(unsigned int keyslot) {
volatile tegra_se_t *se = se_get_regs();
-
+
if (keyslot >= KEYSLOT_RSA_MAX) {
generic_panic();
}
@@ -194,7 +194,7 @@ void clear_rsa_keyslot(unsigned int keyslot) {
void set_aes_keyslot(unsigned int keyslot, const void *key, size_t key_size) {
volatile tegra_se_t *se = se_get_regs();
-
+
if (keyslot >= KEYSLOT_AES_MAX || key_size > KEYSIZE_AES_MAX) {
generic_panic();
}
@@ -207,7 +207,7 @@ void set_aes_keyslot(unsigned int keyslot, const void *key, size_t key_size) {
void set_rsa_keyslot(unsigned int keyslot, const void *modulus, size_t modulus_size, const void *exponent, size_t exp_size) {
volatile tegra_se_t *se = se_get_regs();
-
+
if (keyslot >= KEYSLOT_RSA_MAX || modulus_size > KEYSIZE_RSA_MAX || exp_size > KEYSIZE_RSA_MAX) {
generic_panic();
}
@@ -228,7 +228,7 @@ void set_rsa_keyslot(unsigned int keyslot, const void *modulus, size_t modulus_
void set_aes_keyslot_iv(unsigned int keyslot, const void *iv, size_t iv_size) {
volatile tegra_se_t *se = se_get_regs();
-
+
if (keyslot >= KEYSLOT_AES_MAX || iv_size > 0x10) {
generic_panic();
}
@@ -241,7 +241,7 @@ void set_aes_keyslot_iv(unsigned int keyslot, const void *iv, size_t iv_size) {
void clear_aes_keyslot_iv(unsigned int keyslot) {
volatile tegra_se_t *se = se_get_regs();
-
+
if (keyslot >= KEYSLOT_AES_MAX) {
generic_panic();
}
@@ -260,7 +260,7 @@ void set_se_ctr(const void *ctr) {
void decrypt_data_into_keyslot(unsigned int keyslot_dst, unsigned int keyslot_src, const void *wrapped_key, size_t wrapped_key_size) {
volatile tegra_se_t *se = se_get_regs();
-
+
if (keyslot_dst >= KEYSLOT_AES_MAX || keyslot_src >= KEYSIZE_AES_MAX || wrapped_key_size > KEYSIZE_AES_MAX) {
generic_panic();
}
@@ -276,7 +276,7 @@ void decrypt_data_into_keyslot(unsigned int keyslot_dst, unsigned int keyslot_sr
void se_aes_crypt_insecure_internal(unsigned int keyslot, uint32_t out_ll_paddr, uint32_t in_ll_paddr, size_t size, unsigned int crypt_config, bool encrypt, unsigned int (*callback)(void)) {
volatile tegra_se_t *se = se_get_regs();
-
+
if (keyslot >= KEYSLOT_AES_MAX) {
generic_panic();
}
@@ -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);
}
-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();
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. */
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);
@@ -468,7 +468,7 @@ bool se_rsa2048_pss_verify(const void *signature, size_t signature_size, const v
void trigger_se_rsa_op(void *buf, size_t size) {
volatile tegra_se_t *se = se_get_regs();
se_ll_t in_ll;
-
+
ll_init(&in_ll, (void *)buf, size);
/* Set the input LL. */
@@ -491,19 +491,19 @@ void trigger_se_blocking_op(unsigned int op, void *dst, size_t dst_size, const v
ll_init(&in_ll, (void *)src, src_size);
ll_init(&out_ll, dst, dst_size);
-
+
__dsb_sy();
/* Set the LLs. */
se->SE_IN_LL_ADDR = (uint32_t) get_physical_address(&in_ll);
se->SE_OUT_LL_ADDR = (uint32_t) get_physical_address(&out_ll);
-
+
/* Set registers for operation. */
se->SE_ERR_STATUS = se->SE_ERR_STATUS;
se->SE_INT_STATUS = se->SE_INT_STATUS;
se->SE_OPERATION = op;
(void)(se->SE_OPERATION);
-
+
__dsb_ish();
while (!(se->SE_INT_STATUS & 0x10)) { /* Wait a while */ }
@@ -538,7 +538,7 @@ void se_perform_aes_block_operation(void *dst, size_t dst_size, const void *src,
void se_aes_ctr_crypt(unsigned int keyslot, void *dst, size_t dst_size, const void *src, size_t src_size, const void *ctr, size_t ctr_size) {
volatile tegra_se_t *se = se_get_regs();
-
+
if (keyslot >= KEYSLOT_AES_MAX || ctr_size != 0x10) {
generic_panic();
}
@@ -548,7 +548,7 @@ void se_aes_ctr_crypt(unsigned int keyslot, void *dst, size_t dst_size, const vo
}
if (dst_size) {
flush_dcache_range((uint8_t *)dst, (uint8_t *)dst + dst_size);
- }
+ }
unsigned int num_blocks = src_size >> 4;
@@ -576,12 +576,12 @@ void se_aes_ctr_crypt(unsigned int keyslot, void *dst, size_t dst_size, const vo
if (dst_size) {
flush_dcache_range((uint8_t *)dst, (uint8_t *)dst + dst_size);
- }
+ }
}
void se_aes_ecb_encrypt_block(unsigned int keyslot, void *dst, size_t dst_size, const void *src, size_t src_size, unsigned int config_high) {
volatile tegra_se_t *se = se_get_regs();
-
+
if (keyslot >= KEYSLOT_AES_MAX || dst_size != 0x10 || src_size != 0x10) {
generic_panic();
}
@@ -606,7 +606,7 @@ void se_aes_256_ecb_encrypt_block(unsigned int keyslot, void *dst, size_t dst_si
void se_aes_ecb_decrypt_block(unsigned int keyslot, void *dst, size_t dst_size, const void *src, size_t src_size) {
volatile tegra_se_t *se = se_get_regs();
-
+
if (keyslot >= KEYSLOT_AES_MAX || dst_size != 0x10 || src_size != 0x10) {
generic_panic();
}
@@ -632,15 +632,15 @@ void shift_left_xor_rb(uint8_t *key) {
void se_compute_aes_cmac(unsigned int keyslot, void *cmac, size_t cmac_size, const void *data, size_t data_size, unsigned int config_high) {
volatile tegra_se_t *se = se_get_regs();
-
+
if (keyslot >= KEYSLOT_AES_MAX) {
generic_panic();
}
-
+
if (data_size) {
flush_dcache_range((uint8_t *)data, (uint8_t *)data + data_size);
}
-
+
/* Generate the derived key, to be XOR'd with final output block. */
uint8_t derived_key[0x10] = {0};
se_aes_ecb_encrypt_block(keyslot, derived_key, sizeof(derived_key), derived_key, sizeof(derived_key), config_high);
@@ -652,7 +652,7 @@ void se_compute_aes_cmac(unsigned int keyslot, void *cmac, size_t cmac_size, con
se->SE_CONFIG = (ALG_AES_ENC | DST_HASHREG) | (config_high << 16);
se->SE_CRYPTO_CONFIG = (keyslot << 24) | (0x145);
clear_aes_keyslot_iv(keyslot);
-
+
unsigned int num_blocks = (data_size + 0xF) >> 4;
/* Handle aligned blocks. */
if (num_blocks > 1) {
@@ -660,7 +660,7 @@ void se_compute_aes_cmac(unsigned int keyslot, void *cmac, size_t cmac_size, con
trigger_se_blocking_op(OP_START, NULL, 0, data, data_size);
se->SE_CRYPTO_CONFIG |= 0x80;
}
-
+
/* Create final block. */
uint8_t last_block[0x10] = {0};
if (data_size & 0xF) {
@@ -669,11 +669,11 @@ void se_compute_aes_cmac(unsigned int keyslot, void *cmac, size_t cmac_size, con
} else if (data_size >= 0x10) {
memcpy(last_block, data + data_size - 0x10, 0x10);
}
-
+
for (unsigned int i = 0; i < 0x10; i++) {
last_block[i] ^= derived_key[i];
}
-
+
/* Perform last operation. */
se->SE_CRYPTO_LAST_BLOCK = 0;
flush_dcache_range(last_block, last_block + sizeof(last_block));
@@ -694,11 +694,11 @@ void se_compute_aes_256_cmac(unsigned int keyslot, void *cmac, size_t cmac_size,
void se_aes_256_cbc_encrypt(unsigned int keyslot, void *dst, size_t dst_size, const void *src, size_t src_size, const void *iv) {
volatile tegra_se_t *se = se_get_regs();
-
+
if (keyslot >= KEYSLOT_AES_MAX || src_size < 0x10) {
generic_panic();
}
-
+
se->SE_CONFIG = (ALG_AES_ENC | DST_MEMORY) | (0x202 << 16);
se->SE_CRYPTO_CONFIG = (keyslot << 24) | 0x144;
set_aes_keyslot_iv(keyslot, iv, 0x10);
@@ -709,7 +709,7 @@ void se_aes_256_cbc_encrypt(unsigned int keyslot, void *dst, size_t dst_size, co
/* SHA256 Implementation. */
void se_calculate_sha256(void *dst, const void *src, size_t src_size) {
volatile tegra_se_t *se = se_get_regs();
-
+
/* Setup config for SHA256, size = BITS(src_size) */
se->SE_CONFIG = (ENCMODE_SHA256 | ALG_SHA | DST_HASHREG);
se->SE_SHA_CONFIG = 1;
@@ -721,7 +721,7 @@ void se_calculate_sha256(void *dst, const void *src, size_t src_size) {
se->SE_SHA_MSG_LEFT[1] = 0;
se->SE_SHA_MSG_LEFT[2] = 0;
se->SE_SHA_MSG_LEFT[3] = 0;
-
+
/* Trigger the operation. */
trigger_se_blocking_op(OP_START, NULL, 0, src, src_size);
@@ -734,7 +734,7 @@ void se_calculate_sha256(void *dst, const void *src, size_t src_size) {
/* RNG API */
void se_initialize_rng(unsigned int keyslot) {
volatile tegra_se_t *se = se_get_regs();
-
+
if (keyslot >= KEYSLOT_AES_MAX) {
generic_panic();
}
@@ -754,7 +754,7 @@ void se_initialize_rng(unsigned int keyslot) {
void se_generate_random(unsigned int keyslot, void *dst, size_t size) {
volatile tegra_se_t *se = se_get_regs();
-
+
if (keyslot >= KEYSLOT_AES_MAX) {
generic_panic();
}
@@ -777,7 +777,7 @@ void se_generate_random(unsigned int keyslot, void *dst, size_t size) {
/* SE context save API. */
void se_set_in_context_save_mode(bool is_context_save_mode) {
volatile tegra_se_t *se = se_get_regs();
-
+
uint32_t val = se->SE_SE_SECURITY;
if (is_context_save_mode) {
val |= 0x10000;
@@ -791,7 +791,7 @@ void se_set_in_context_save_mode(bool is_context_save_mode) {
void se_generate_random_key(unsigned int dst_keyslot, unsigned int rng_keyslot) {
volatile tegra_se_t *se = se_get_regs();
-
+
if (dst_keyslot >= KEYSLOT_AES_MAX || rng_keyslot >= KEYSLOT_AES_MAX) {
generic_panic();
}
@@ -801,7 +801,7 @@ void se_generate_random_key(unsigned int dst_keyslot, unsigned int rng_keyslot)
se->SE_CRYPTO_CONFIG = (rng_keyslot << 24) | 0x108;
se->SE_RNG_CONFIG = 4;
se->SE_CRYPTO_LAST_BLOCK = 0;
-
+
/* Generate low part of key. */
se->SE_CRYPTO_KEYTABLE_DST = (dst_keyslot << 8);
trigger_se_blocking_op(OP_START, NULL, 0, NULL, 0);
@@ -812,7 +812,7 @@ void se_generate_random_key(unsigned int dst_keyslot, unsigned int rng_keyslot)
void se_generate_srk(unsigned int srkgen_keyslot) {
volatile tegra_se_t *se = se_get_regs();
-
+
se->SE_CONFIG = (ALG_RNG | DST_SRK);
se->SE_CRYPTO_CONFIG = (srkgen_keyslot << 24) | 0x108;
se->SE_RNG_CONFIG = 6;
@@ -847,24 +847,24 @@ void se_save_context(unsigned int srkgen_keyslot, unsigned int rng_keyslot, void
/* Generate the SRK (context save encryption key). */
se_generate_random_key(srkgen_keyslot, rng_keyslot);
se_generate_srk(srkgen_keyslot);
-
+
flush_dcache_range(work_buf, work_buf + 0x10);
se_generate_random(rng_keyslot, work_buf, 0x10);
flush_dcache_range(work_buf, work_buf + 0x10);
-
+
/* Save random initial block. */
se->SE_CONFIG = (ALG_AES_ENC | DST_MEMORY);
se->SE_CTX_SAVE_CONFIG = (CTX_SAVE_SRC_MEM);
se->SE_CRYPTO_LAST_BLOCK = 0;
se_encrypt_with_srk(dst, 0x10, work_buf, 0x10);
-
+
/* Save Sticky Bits. */
for (unsigned int i = 0; i < 0x2; i++) {
se->SE_CTX_SAVE_CONFIG = (CTX_SAVE_SRC_STICKY_BITS) | (i << CTX_SAVE_STICKY_BIT_INDEX_SHIFT);
se->SE_CRYPTO_LAST_BLOCK = 0;
se_encrypt_with_srk(dst + 0x10 + (i * 0x10), 0x10, NULL, 0);
}
-
+
/* Save AES Key Table. */
for (unsigned int i = 0; i < KEYSLOT_AES_MAX; i++) {
se->SE_CTX_SAVE_CONFIG = (CTX_SAVE_SRC_KEYTABLE_AES) | (i << CTX_SAVE_KEY_INDEX_SHIFT) | (CTX_SAVE_KEY_LOW_BITS);
@@ -874,21 +874,21 @@ void se_save_context(unsigned int srkgen_keyslot, unsigned int rng_keyslot, void
se->SE_CRYPTO_LAST_BLOCK = 0;
se_encrypt_with_srk(dst + 0x40 + (i * 0x20), 0x10, NULL, 0);
}
-
+
/* Save AES Original IVs. */
for (unsigned int i = 0; i < KEYSLOT_AES_MAX; i++) {
se->SE_CTX_SAVE_CONFIG = (CTX_SAVE_SRC_KEYTABLE_AES) | (i << CTX_SAVE_KEY_INDEX_SHIFT) | (CTX_SAVE_KEY_ORIGINAL_IV);
se->SE_CRYPTO_LAST_BLOCK = 0;
se_encrypt_with_srk(dst + 0x230 + (i * 0x10), 0x10, NULL, 0);
}
-
+
/* Save AES Updated IVs */
for (unsigned int i = 0; i < KEYSLOT_AES_MAX; i++) {
se->SE_CTX_SAVE_CONFIG = (CTX_SAVE_SRC_KEYTABLE_AES) | (i << CTX_SAVE_KEY_INDEX_SHIFT) | (CTX_SAVE_KEY_UPDATED_IV);
se->SE_CRYPTO_LAST_BLOCK = 0;
se_encrypt_with_srk(dst + 0x330 + (i * 0x10), 0x10, NULL, 0);
}
-
+
/* Save RSA Keytable. */
uint8_t *rsa_ctx_out = (uint8_t *)dst + 0x430;
for (unsigned int rsa_key = 0; rsa_key < KEYSLOT_RSA_MAX; rsa_key++) {
@@ -901,13 +901,13 @@ void se_save_context(unsigned int srkgen_keyslot, unsigned int rng_keyslot, void
}
}
}
-
+
/* Save "Known Pattern. " */
static const uint8_t context_save_known_pattern[0x10] = {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f};
se->SE_CTX_SAVE_CONFIG = (CTX_SAVE_SRC_MEM);
se->SE_CRYPTO_LAST_BLOCK = 0;
se_encrypt_with_srk(dst + 0x830, 0x10, context_save_known_pattern, 0x10);
-
+
/* Save SRK into PMC registers. */
se->SE_CTX_SAVE_CONFIG = (CTX_SAVE_SRC_SRK);
se->SE_CRYPTO_LAST_BLOCK = 0;
diff --git a/exosphere/src/se.h b/exosphere/src/se.h
index 0532b8cd7..a429caef7 100644
--- a/exosphere/src/se.h
+++ b/exosphere/src/se.h
@@ -13,7 +13,7 @@
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*/
-
+
#ifndef EXOSPHERE_SE_H
#define EXOSPHERE_SE_H
@@ -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);
/* 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_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);
diff --git a/exosphere/src/smc_api.c b/exosphere/src/smc_api.c
index 6cea446ec..499928451 100644
--- a/exosphere/src/smc_api.c
+++ b/exosphere/src/smc_api.c
@@ -188,6 +188,7 @@ void set_version_specific_smcs(void) {
case ATMOSPHERE_TARGET_FIRMWARE_810:
case ATMOSPHERE_TARGET_FIRMWARE_900:
case ATMOSPHERE_TARGET_FIRMWARE_910:
+ case ATMOSPHERE_TARGET_FIRMWARE_1000:
/* No more LoadSecureExpModKey. */
g_smc_user_table[0xE].handler = NULL;
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) {
- if (get_exp_mod_done() != 1) {
- return 3;
+ uint32_t res = get_exp_mod_result();
+ 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;
+ }
}
-
- 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;
+ return res;
}
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 titlekey[0x10];
uint64_t sealed_titlekey[2];
- if (get_exp_mod_done() != 1) {
- return 3;
+ uint32_t res = get_exp_mod_result();
+ 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 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;
+ return res;
}
uint32_t smc_unwrap_rsa_oaep_wrapped_titlekey(smc_args_t *args) {
diff --git a/exosphere/src/smc_user.c b/exosphere/src/smc_user.c
index ae6667a25..f2e83629b 100644
--- a/exosphere/src/smc_user.c
+++ b/exosphere/src/smc_user.c
@@ -34,12 +34,93 @@
/* Globals. */
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_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 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) {
switch (exosphere_get_target_firmware()) {
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_900:
case ATMOSPHERE_TARGET_FIRMWARE_910:
+ case ATMOSPHERE_TARGET_FIRMWARE_1000:
default:
return keyslot <= 5;
}
}
-void set_exp_mod_done(bool done) {
- g_exp_mod_done = done;
+void set_exp_mod_result(uint32_t result) {
+ g_exp_mod_result = result;
}
-bool get_exp_mod_done(void) {
- return g_exp_mod_done;
+uint32_t get_exp_mod_result(void) {
+ return g_exp_mod_result;
}
uint32_t exp_mod_done_handler(void) {
- set_exp_mod_done(true);
+ set_exp_mod_result(0);
se_trigger_interrupt();
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) {
uint8_t modulus[0x100];
uint8_t exponent[0x100];
@@ -108,7 +207,8 @@ uint32_t user_exp_mod(smc_args_t *args) {
return 2;
}
- set_exp_mod_done(false);
+ set_exp_mod_result(3);
+
/* Hardcode RSA keyslot 0. */
set_rsa_keyslot(0, modulus, 0x100, exponent, exponent_size);
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;
}
- set_exp_mod_done(false);
+ set_exp_mod_result(3);
+
/* Hardcode RSA keyslot 0. */
- set_rsa_keyslot(0, modulus, 0x100, g_imported_exponents[exponent_id], 0x100);
- se_exp_mod(0, input, 0x100, exp_mod_done_handler);
+ if (exosphere_get_target_firmware() < ATMOSPHERE_TARGET_FIRMWARE_1000) {
+ 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;
}
@@ -700,7 +811,7 @@ uint32_t user_unwrap_rsa_oaep_wrapped_titlekey(smc_args_t *args) {
return 2;
}
- set_exp_mod_done(false);
+ set_exp_mod_result(3);
/* Expected label_hash occupies args->X[3] to args->X[6]. */
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;
+ bool import_modulus;
switch (usecase) {
case 0:
@@ -888,22 +1000,33 @@ uint32_t user_decrypt_or_import_rsa_key(smc_args_t *args) {
return 0;
case 1:
exponent_id = 1;
+ import_modulus = false;
break;
case 2:
exponent_id = 0;
+ import_modulus = true;
break;
case 3:
exponent_id = 2;
+ import_modulus = false;
break;
case 4:
exponent_id = 3;
+ import_modulus = true;
break;
default:
generic_panic();
}
- /* Copy key to global. */
- memcpy(g_imported_exponents[exponent_id], user_data, 0x100);
+ /* Modulus import isn't implemented on < 10.0.0. */
+ 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;
}
diff --git a/exosphere/src/smc_user.h b/exosphere/src/smc_user.h
index d44cf82ae..b100f6618 100644
--- a/exosphere/src/smc_user.h
+++ b/exosphere/src/smc_user.h
@@ -13,7 +13,7 @@
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*/
-
+
#ifndef EXOSPHERE_SMC_USER_H
#define EXOSPHERE_SMC_USER_H
@@ -41,7 +41,7 @@ uint32_t user_decrypt_or_import_rsa_key(smc_args_t *args);
void set_crypt_aes_done(bool done);
bool get_crypt_aes_done(void);
-void set_exp_mod_done(bool done);
-bool get_exp_mod_done(void);
+void set_exp_mod_result(uint32_t result);
+uint32_t get_exp_mod_result(void);
#endif
\ No newline at end of file
diff --git a/exosphere/src/titlekey.c b/exosphere/src/titlekey.c
index bda39d2fe..6324eaf30 100644
--- a/exosphere/src/titlekey.c
+++ b/exosphere/src/titlekey.c
@@ -1,4 +1,4 @@
-/*
+/*expected_label_hash
* Copyright (c) 2018-2020 Atmosphère-NX
*
* This program is free software; you can redistribute it and/or modify it
@@ -13,7 +13,7 @@
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*/
-
+
#include
#include
@@ -25,14 +25,10 @@
#include "masterkey.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. */
void tkey_set_expected_label_hash(uint64_t *label_hash) {
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) {
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) {
@@ -51,7 +47,7 @@ static void tkey_validate_type(unsigned int type) {
void tkey_set_type(unsigned int 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 */
@@ -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;
/* 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. */
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) {
- 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();
}
-
+
/* Generate the appropriate titlekek into keyslot 9. */
- unsigned int master_keyslot = mkey_get_keyslot(g_tkey_master_key_rev);
- decrypt_data_into_keyslot(KEYSLOT_SWITCH_TEMPKEY, master_keyslot, titlekek_sources[g_tkey_type], 0x10);
+ 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_rsa_shared_data.unwrap_titlekey.type], 0x10);
/* Unwrap the titlekey using the titlekek. */
se_aes_ecb_decrypt_block(KEYSLOT_SWITCH_TEMPKEY, dst, 0x10, src, 0x10);
diff --git a/exosphere/src/titlekey.h b/exosphere/src/titlekey.h
index 7590abea0..4d33783dc 100644
--- a/exosphere/src/titlekey.h
+++ b/exosphere/src/titlekey.h
@@ -13,11 +13,12 @@
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*/
-
+
#ifndef EXOSPHERE_TITLEKEY_H
#define EXOSPHERE_TITLEKEY_H
#include
+#include "rsa_common.h"
#define TITLEKEY_TYPE_MAX 0x1
diff --git a/libraries/libstratosphere/source/hos/hos_version_api.cpp b/libraries/libstratosphere/source/hos/hos_version_api.cpp
index 4f9530ead..d295250af 100644
--- a/libraries/libstratosphere/source/hos/hos_version_api.cpp
+++ b/libraries/libstratosphere/source/hos/hos_version_api.cpp
@@ -66,9 +66,13 @@ namespace ams::hos {
break;
case exosphere::TargetFirmware_900:
g_hos_version = hos::Version_9_0_0;
+ break;
case exosphere::TargetFirmware_910:
g_hos_version = hos::Version_9_1_0;
break;
+ case exosphere::TargetFirmware_1000:
+ g_hos_version = hos::Version_10_0_0;
+ break;
AMS_UNREACHABLE_DEFAULT_CASE();
}
@@ -139,6 +143,11 @@ namespace ams::hos {
minor = 1;
micro = 0;
break;
+ case hos::Version_10_0_0:
+ major = 10;
+ minor = 0;
+ micro = 0;
+ break;
AMS_UNREACHABLE_DEFAULT_CASE();
}
hosversionSet(MAKEHOSVERSION(major, minor, micro));
diff --git a/libraries/libvapours/include/vapours/ams/ams_api_version.h b/libraries/libvapours/include/vapours/ams/ams_api_version.h
index 986ac169d..8134c40e3 100644
--- a/libraries/libvapours/include/vapours/ams/ams_api_version.h
+++ b/libraries/libvapours/include/vapours/ams/ams_api_version.h
@@ -17,10 +17,10 @@
#define ATMOSPHERE_RELEASE_VERSION_MAJOR 0
#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_SUPPORTED_HOS_VERSION_MAJOR 9
-#define ATMOSPHERE_SUPPORTED_HOS_VERSION_MINOR 2
+#define ATMOSPHERE_SUPPORTED_HOS_VERSION_MAJOR 10
+#define ATMOSPHERE_SUPPORTED_HOS_VERSION_MINOR 0
#define ATMOSPHERE_SUPPORTED_HOS_VERSION_MICRO 0
diff --git a/libraries/libvapours/include/vapours/ams/ams_target_firmware.h b/libraries/libvapours/include/vapours/ams/ams_target_firmware.h
index 9ff187d90..25764523f 100644
--- a/libraries/libvapours/include/vapours/ams/ams_target_firmware.h
+++ b/libraries/libvapours/include/vapours/ams/ams_target_firmware.h
@@ -15,20 +15,21 @@
*/
#pragma once
-#define ATMOSPHERE_TARGET_FIRMWARE_100 1
-#define ATMOSPHERE_TARGET_FIRMWARE_200 2
-#define ATMOSPHERE_TARGET_FIRMWARE_300 3
-#define ATMOSPHERE_TARGET_FIRMWARE_400 4
-#define ATMOSPHERE_TARGET_FIRMWARE_500 5
-#define ATMOSPHERE_TARGET_FIRMWARE_600 6
-#define ATMOSPHERE_TARGET_FIRMWARE_620 7
-#define ATMOSPHERE_TARGET_FIRMWARE_700 8
-#define ATMOSPHERE_TARGET_FIRMWARE_800 9
-#define ATMOSPHERE_TARGET_FIRMWARE_810 10
-#define ATMOSPHERE_TARGET_FIRMWARE_900 11
-#define ATMOSPHERE_TARGET_FIRMWARE_910 12
+#define ATMOSPHERE_TARGET_FIRMWARE_100 1
+#define ATMOSPHERE_TARGET_FIRMWARE_200 2
+#define ATMOSPHERE_TARGET_FIRMWARE_300 3
+#define ATMOSPHERE_TARGET_FIRMWARE_400 4
+#define ATMOSPHERE_TARGET_FIRMWARE_500 5
+#define ATMOSPHERE_TARGET_FIRMWARE_600 6
+#define ATMOSPHERE_TARGET_FIRMWARE_620 7
+#define ATMOSPHERE_TARGET_FIRMWARE_700 8
+#define ATMOSPHERE_TARGET_FIRMWARE_800 9
+#define ATMOSPHERE_TARGET_FIRMWARE_810 10
+#define ATMOSPHERE_TARGET_FIRMWARE_900 11
+#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_MAX ATMOSPHERE_TARGET_FIRMWARE_CURRENT