mirror of
https://github.com/Atmosphere-NX/Atmosphere
synced 2024-12-03 06:49:10 +00:00
exo2: implement SmcReencryptDeviceUniqueData
This commit is contained in:
parent
95d38a1a94
commit
bb6671a94a
6 changed files with 163 additions and 30 deletions
|
@ -517,22 +517,7 @@ namespace ams::secmon::smc {
|
|||
return SmcResult::Success;
|
||||
}
|
||||
|
||||
SmcResult DecryptDeviceUniqueDataImpl(SmcArguments &args) {
|
||||
/* Decode arguments. */
|
||||
u8 access_key[se::AesBlockSize];
|
||||
u8 key_source[se::AesBlockSize];
|
||||
|
||||
std::memcpy(access_key, std::addressof(args.r[1]), sizeof(access_key));
|
||||
const util::BitPack32 option = { static_cast<u32>(args.r[3]) };
|
||||
const uintptr_t data_address = args.r[4];
|
||||
const size_t data_size = args.r[5];
|
||||
std::memcpy(key_source, std::addressof(args.r[6]), sizeof(key_source));
|
||||
|
||||
const auto mode = option.Get<DecryptDeviceUniqueDataOption::DeviceUniqueDataIndex>();
|
||||
const auto reserved = option.Get<DecryptDeviceUniqueDataOption::Reserved>();
|
||||
|
||||
/* Validate arguments. */
|
||||
SMC_R_UNLESS(reserved == 0, InvalidArgument);
|
||||
SmcResult ValidateDeviceUniqueDataSize(DeviceUniqueData mode, size_t data_size) {
|
||||
switch (mode) {
|
||||
case DeviceUniqueData_DecryptDeviceUniqueData:
|
||||
{
|
||||
|
@ -551,8 +536,29 @@ namespace ams::secmon::smc {
|
|||
return SmcResult::InvalidArgument;
|
||||
}
|
||||
|
||||
return SmcResult::Success;
|
||||
}
|
||||
|
||||
SmcResult DecryptDeviceUniqueDataImpl(SmcArguments &args) {
|
||||
/* Decode arguments. */
|
||||
u8 access_key[se::AesBlockSize];
|
||||
u8 key_source[se::AesBlockSize];
|
||||
|
||||
std::memcpy(access_key, std::addressof(args.r[1]), sizeof(access_key));
|
||||
const util::BitPack32 option = { static_cast<u32>(args.r[3]) };
|
||||
const uintptr_t data_address = args.r[4];
|
||||
const size_t data_size = args.r[5];
|
||||
std::memcpy(key_source, std::addressof(args.r[6]), sizeof(key_source));
|
||||
|
||||
const auto mode = option.Get<DecryptDeviceUniqueDataOption::DeviceUniqueDataIndex>();
|
||||
const auto reserved = option.Get<DecryptDeviceUniqueDataOption::Reserved>();
|
||||
|
||||
/* Validate arguments. */
|
||||
SMC_R_UNLESS(reserved == 0, InvalidArgument);
|
||||
SMC_R_TRY(ValidateDeviceUniqueDataSize(mode, data_size));
|
||||
|
||||
/* Decrypt the device unique data. */
|
||||
u8 work_buffer[DeviceUniqueDataSizeMax];
|
||||
alignas(8) u8 work_buffer[DeviceUniqueDataSizeMax];
|
||||
ON_SCOPE_EXIT { crypto::ClearMemory(work_buffer, sizeof(work_buffer)); };
|
||||
{
|
||||
/* Map and copy in the encrypted data. */
|
||||
|
@ -593,6 +599,69 @@ namespace ams::secmon::smc {
|
|||
return SmcResult::Success;
|
||||
}
|
||||
|
||||
SmcResult ReencryptDeviceUniqueDataImpl(SmcArguments &args) {
|
||||
/* Decode arguments. */
|
||||
u8 access_key_dec[se::AesBlockSize];
|
||||
u8 access_key_enc[se::AesBlockSize];
|
||||
u8 key_source_dec[se::AesBlockSize];
|
||||
u8 key_source_enc[se::AesBlockSize];
|
||||
|
||||
const uintptr_t access_key_dec_address = args.r[1];
|
||||
const uintptr_t access_key_enc_address = args.r[2];
|
||||
const util::BitPack32 option = { static_cast<u32>(args.r[3]) };
|
||||
const uintptr_t data_address = args.r[4];
|
||||
const size_t data_size = args.r[5];
|
||||
const uintptr_t key_source_dec_address = args.r[6];
|
||||
const uintptr_t key_source_enc_address = args.r[7];
|
||||
|
||||
const auto mode = option.Get<DecryptDeviceUniqueDataOption::DeviceUniqueDataIndex>();
|
||||
const auto reserved = option.Get<DecryptDeviceUniqueDataOption::Reserved>();
|
||||
|
||||
/* Validate arguments. */
|
||||
SMC_R_UNLESS(reserved == 0, InvalidArgument);
|
||||
SMC_R_TRY(ValidateDeviceUniqueDataSize(mode, data_size));
|
||||
|
||||
/* Decrypt the device unique data. */
|
||||
alignas(8) u8 work_buffer[DeviceUniqueDataSizeMax];
|
||||
ON_SCOPE_EXIT { crypto::ClearMemory(work_buffer, sizeof(work_buffer)); };
|
||||
{
|
||||
/* Map and copy in the encrypted data. */
|
||||
UserPageMapper mapper(data_address);
|
||||
SMC_R_UNLESS(mapper.Map(), InvalidArgument);
|
||||
SMC_R_UNLESS(mapper.CopyFromUser(work_buffer, data_address, data_size), InvalidArgument);
|
||||
SMC_R_UNLESS(mapper.CopyFromUser(access_key_dec, access_key_dec_address, sizeof(access_key_dec)), InvalidArgument);
|
||||
SMC_R_UNLESS(mapper.CopyFromUser(access_key_enc, access_key_enc_address, sizeof(access_key_enc)), InvalidArgument);
|
||||
SMC_R_UNLESS(mapper.CopyFromUser(key_source_dec, key_source_dec_address, sizeof(key_source_dec)), InvalidArgument);
|
||||
SMC_R_UNLESS(mapper.CopyFromUser(key_source_enc, key_source_enc_address, sizeof(key_source_enc)), InvalidArgument);
|
||||
|
||||
/* Decrypt the data. */
|
||||
u8 device_id_high;
|
||||
{
|
||||
/* Determine the seal key to use. */
|
||||
const u8 * const seal_key_source = SealKeySources[SealKey_ReencryptDeviceUniqueData];
|
||||
|
||||
if (!DecryptDeviceUniqueData(work_buffer, data_size, std::addressof(device_id_high), seal_key_source, se::AesBlockSize, access_key_dec, sizeof(access_key_dec), key_source_dec, sizeof(key_source_dec), work_buffer, data_size)) {
|
||||
return SmcResult::InvalidArgument;
|
||||
}
|
||||
}
|
||||
|
||||
/* Reencrypt the data. */
|
||||
{
|
||||
/* Determine the seal key to use. */
|
||||
const auto seal_key_type = DeviceUniqueDataToSealKey[mode];
|
||||
const u8 * const seal_key_source = SealKeySources[seal_key_type];
|
||||
|
||||
/* Encrypt the data. */
|
||||
EncryptDeviceUniqueData(work_buffer, data_size, seal_key_source, se::AesBlockSize, access_key_enc, sizeof(access_key_enc), key_source_enc, sizeof(key_source_enc), work_buffer, data_size - DeviceUniqueDataTotalMetaSize, device_id_high);
|
||||
}
|
||||
|
||||
/* Copy the reencrypted data back to user. */
|
||||
SMC_R_UNLESS(mapper.CopyToUser(data_address, work_buffer, data_size), InvalidArgument);
|
||||
}
|
||||
|
||||
return SmcResult::Success;
|
||||
}
|
||||
|
||||
SmcResult GetSecureDataImpl(SmcArguments &args) {
|
||||
/* Decode arguments. */
|
||||
const auto which = static_cast<SecureData>(args.r[1]);
|
||||
|
@ -647,8 +716,7 @@ namespace ams::secmon::smc {
|
|||
}
|
||||
|
||||
SmcResult SmcReencryptDeviceUniqueData(SmcArguments &args) {
|
||||
/* TODO */
|
||||
return SmcResult::NotImplemented;
|
||||
return LockSecurityEngineAndInvoke(args, ReencryptDeviceUniqueDataImpl);
|
||||
}
|
||||
|
||||
/* Legacy APIs. */
|
||||
|
|
|
@ -21,14 +21,19 @@ namespace ams::secmon::smc {
|
|||
|
||||
namespace {
|
||||
|
||||
constexpr inline size_t DeviceUniqueDataIvSize = se::AesBlockSize;
|
||||
constexpr inline size_t DeviceUniqueDataMacSize = se::AesBlockSize;
|
||||
constexpr inline size_t DeviceUniqueDataDeviceIdSize = sizeof(u64);
|
||||
constexpr inline size_t DeviceUniqueDataPaddingSize = se::AesBlockSize - DeviceUniqueDataDeviceIdSize;
|
||||
void GenerateIv(void *dst, size_t dst_size) {
|
||||
/* Flush the region we're about to fill to ensure consistency with the SE. */
|
||||
hw::FlushDataCache(dst, dst_size);
|
||||
hw::DataSynchronizationBarrierInnerShareable();
|
||||
|
||||
constexpr inline size_t DeviceUniqueDataOuterMetaSize = DeviceUniqueDataIvSize + DeviceUniqueDataMacSize;
|
||||
constexpr inline size_t DeviceUniqueDataInnerMetaSize = DeviceUniqueDataPaddingSize + DeviceUniqueDataDeviceIdSize;
|
||||
constexpr inline size_t DeviceUniqueDataTotalMetaSize = DeviceUniqueDataOuterMetaSize + DeviceUniqueDataInnerMetaSize;
|
||||
/* Generate random bytes. */
|
||||
se::GenerateRandomBytes(dst, dst_size);
|
||||
hw::DataSynchronizationBarrierInnerShareable();
|
||||
|
||||
/* Flush to ensure the CPU sees consistent data for the region. */
|
||||
hw::FlushDataCache(dst, dst_size);
|
||||
hw::DataSynchronizationBarrierInnerShareable();
|
||||
}
|
||||
|
||||
void PrepareDeviceUniqueDataKey(const void *seal_key_source, size_t seal_key_source_size, const void *access_key, size_t access_key_size, const void *key_source, size_t key_source_size) {
|
||||
/* Derive the seal key. */
|
||||
|
@ -79,6 +84,10 @@ namespace ams::secmon::smc {
|
|||
return static_cast<u8>(device_id >> (BITSIZEOF(u64) - BITSIZEOF(u8)));
|
||||
}
|
||||
|
||||
constexpr u64 EncodeDeviceId(u8 device_id_high, u64 device_id_low) {
|
||||
return (static_cast<u64>(device_id_high) << (BITSIZEOF(u64) - BITSIZEOF(u8))) | device_id_low;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
bool DecryptDeviceUniqueData(void *dst, size_t dst_size, u8 *out_device_id_high, const void *seal_key_source, size_t seal_key_source_size, const void *access_key, size_t access_key_size, const void *key_source, size_t key_source_size, const void *src, size_t src_size) {
|
||||
|
@ -143,4 +152,50 @@ namespace ams::secmon::smc {
|
|||
return true;
|
||||
}
|
||||
|
||||
void EncryptDeviceUniqueData(void *dst, size_t dst_size, const void *seal_key_source, size_t seal_key_source_size, const void *access_key, size_t access_key_size, const void *key_source, size_t key_source_size, const void *src, size_t src_size, u8 device_id_high) {
|
||||
/* Determine metadata locations. */
|
||||
u8 * const dst_iv = static_cast<u8 *>(dst);
|
||||
u8 * const dst_data = dst_iv + DeviceUniqueDataIvSize;
|
||||
u8 * const dst_pad = dst_data + src_size;
|
||||
u8 * const dst_did = dst_pad + DeviceUniqueDataPaddingSize;
|
||||
u8 * const dst_mac = dst_did + DeviceUniqueDataDeviceIdSize;
|
||||
|
||||
/* Verify that our sizes are okay. */
|
||||
const size_t enc_size = src_size + DeviceUniqueDataInnerMetaSize;
|
||||
const size_t res_size = src_size + DeviceUniqueDataTotalMetaSize;
|
||||
AMS_ABORT_UNLESS(res_size <= dst_size);
|
||||
|
||||
/* Layout the image as expected. */
|
||||
{
|
||||
/* Generate a random iv. */
|
||||
util::AlignedBuffer<hw::DataCacheLineSize, DeviceUniqueDataIvSize> iv;
|
||||
GenerateIv(iv, DeviceUniqueDataIvSize);
|
||||
|
||||
/* Move the data to the output image. */
|
||||
std::memmove(dst_data, src, src_size);
|
||||
|
||||
/* Copy the iv. */
|
||||
std::memcpy(dst_iv, iv, DeviceUniqueDataIvSize);
|
||||
|
||||
/* Clear the padding. */
|
||||
std::memset(dst_pad, 0, DeviceUniqueDataPaddingSize);
|
||||
|
||||
/* Store the device id. */
|
||||
util::StoreBigEndian(reinterpret_cast<u64 *>(dst_did), EncodeDeviceId(device_id_high, fuse::GetDeviceId()));
|
||||
}
|
||||
|
||||
/* Encrypt and mac. */
|
||||
{
|
||||
|
||||
/* Prepare the key used to encrypt the data. */
|
||||
PrepareDeviceUniqueDataKey(seal_key_source, seal_key_source_size, access_key, access_key_size, key_source, key_source_size);
|
||||
|
||||
/* Compute the gmac. */
|
||||
ComputeGmac(dst_mac, DeviceUniqueDataMacSize, dst_data, enc_size, dst_iv, DeviceUniqueDataIvSize);
|
||||
|
||||
/* Encrypt the data. */
|
||||
ComputeAes128Ctr(dst_data, enc_size, pkg1::AesKeySlot_Smc, dst_data, enc_size, dst_iv, DeviceUniqueDataIvSize);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -19,6 +19,16 @@
|
|||
|
||||
namespace ams::secmon::smc {
|
||||
|
||||
constexpr inline size_t DeviceUniqueDataIvSize = se::AesBlockSize;
|
||||
constexpr inline size_t DeviceUniqueDataMacSize = se::AesBlockSize;
|
||||
constexpr inline size_t DeviceUniqueDataDeviceIdSize = sizeof(u64);
|
||||
constexpr inline size_t DeviceUniqueDataPaddingSize = se::AesBlockSize - DeviceUniqueDataDeviceIdSize;
|
||||
|
||||
constexpr inline size_t DeviceUniqueDataOuterMetaSize = DeviceUniqueDataIvSize + DeviceUniqueDataMacSize;
|
||||
constexpr inline size_t DeviceUniqueDataInnerMetaSize = DeviceUniqueDataPaddingSize + DeviceUniqueDataDeviceIdSize;
|
||||
constexpr inline size_t DeviceUniqueDataTotalMetaSize = DeviceUniqueDataOuterMetaSize + DeviceUniqueDataInnerMetaSize;
|
||||
|
||||
bool DecryptDeviceUniqueData(void *dst, size_t dst_size, u8 *out_device_id_high, const void *seal_key_source, size_t seal_key_source_size, const void *access_key, size_t access_key_size, const void *key_source, size_t key_source_size, const void *src, size_t src_size);
|
||||
void EncryptDeviceUniqueData(void *dst, size_t dst_size, const void *seal_key_source, size_t seal_key_source_size, const void *access_key, size_t access_key_size, const void *key_source, size_t key_source_size, const void *src, size_t src_size, u8 device_id_high);
|
||||
|
||||
}
|
||||
|
|
|
@ -26,7 +26,7 @@ namespace ams::secmon::smc {
|
|||
}
|
||||
|
||||
SmcResult SmcWriteAddress(SmcArguments &args) {
|
||||
/* TODO */
|
||||
/* NOTE: This smc was deprecated in Atmosphère 0.13.0. */
|
||||
return SmcResult::NotImplemented;
|
||||
}
|
||||
|
||||
|
|
|
@ -8,7 +8,7 @@ include $(dir $(abspath $(lastword $(MAKEFILE_LIST))))/../common.mk
|
|||
#---------------------------------------------------------------------------------
|
||||
ifeq ($(strip $(ATMOSPHERE_ARCH_NAME)),arm64)
|
||||
DEFINES := $(ATMOSPHERE_DEFINES) -DATMOSPHERE_IS_EXOSPHERE
|
||||
SETTINGS := $(ATMOSPHERE_SETTINGS) -mgeneral-regs-only -ffixed-x18 -O2 -Werror -fno-non-call-exceptions
|
||||
SETTINGS := $(ATMOSPHERE_SETTINGS) -mgeneral-regs-only -ffixed-x18 -Os -Werror -fno-non-call-exceptions
|
||||
CFLAGS := $(ATMOSPHERE_CFLAGS) $(SETTINGS) $(DEFINES) $(INCLUDE)
|
||||
CXXFLAGS := $(CFLAGS) $(ATMOSPHERE_CXXFLAGS) -fno-use-cxa-atexit
|
||||
ASFLAGS := $(ATMOSPHERE_ASFLAGS) $(SETTINGS)
|
||||
|
@ -20,7 +20,7 @@ CXXFLAGS := $(CFLAGS) $(ATMOSPHERE_CXXFLAGS) -fno-use-cxa-atexit
|
|||
ASFLAGS := $(ATMOSPHERE_ASFLAGS) $(SETTINGS)
|
||||
endif
|
||||
|
||||
export LDFLAGS = -specs=$(TOPDIR)/$(notdir $(TOPDIR)).specs -nostdlib -nostartfiles -g $(SETTINGS) -Wl,-Map,$(notdir $*.map) -Wl,-z,relro,-z,now
|
||||
export LDFLAGS = -specs=$(TOPDIR)/$(notdir $(TOPDIR)).specs -fno-asynchronous-unwind-tables -fno-unwind-tables -fno-exceptions -fno-rtti -fno-use-cxa-atexit -nostdlib -nostartfiles -g $(SETTINGS) -Wl,-Map,$(notdir $*.map) -Wl,-z,relro,-z,now
|
||||
|
||||
export CXXWRAPS := -Wl,--wrap,__cxa_pure_virtual \
|
||||
-Wl,--wrap,__cxa_throw \
|
||||
|
|
|
@ -14,7 +14,7 @@ include $(dir $(abspath $(lastword $(MAKEFILE_LIST))))/../config/common.mk
|
|||
#---------------------------------------------------------------------------------
|
||||
|
||||
DEFINES := $(ATMOSPHERE_DEFINES) -DATMOSPHERE_IS_EXOSPHERE
|
||||
SETTINGS := $(ATMOSPHERE_SETTINGS) -mgeneral-regs-only -ffixed-x18 -O2 -Werror -fno-non-call-exceptions
|
||||
SETTINGS := $(ATMOSPHERE_SETTINGS) -mgeneral-regs-only -ffixed-x18 -Os -Werror -fno-non-call-exceptions
|
||||
CFLAGS := $(ATMOSPHERE_CFLAGS) $(SETTINGS) $(DEFINES) $(INCLUDE)
|
||||
CXXFLAGS := $(CFLAGS) $(ATMOSPHERE_CXXFLAGS) -fno-use-cxa-atexit
|
||||
ASFLAGS := $(ATMOSPHERE_ASFLAGS) $(SETTINGS)
|
||||
|
|
Loading…
Reference in a new issue