From aa4c79cd9c77cecd2f14a31927e9fe5f060ee73e Mon Sep 17 00:00:00 2001 From: Michael Scire Date: Mon, 13 Apr 2020 23:30:54 -0700 Subject: [PATCH] exosphere: update to support 10.0.0 --- exosphere/src/fuse.c | 27 ++-- exosphere/src/package2.c | 7 +- exosphere/src/package2.h | 6 +- exosphere/src/rsa_common.c | 20 +++ exosphere/src/rsa_common.h | 36 +++++ exosphere/src/se.c | 100 ++++++------ exosphere/src/se.h | 4 +- exosphere/src/smc_api.c | 69 ++++---- exosphere/src/smc_user.c | 149 ++++++++++++++++-- exosphere/src/smc_user.h | 6 +- exosphere/src/titlekey.c | 24 ++- exosphere/src/titlekey.h | 3 +- .../source/hos/hos_version_api.cpp | 9 ++ .../include/vapours/ams/ams_api_version.h | 6 +- .../include/vapours/ams/ams_target_firmware.h | 27 ++-- 15 files changed, 344 insertions(+), 149 deletions(-) create mode 100644 exosphere/src/rsa_common.c create mode 100644 exosphere/src/rsa_common.h 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