exo2: implement SmcPrepareEsDeviceUniqueKey, SmcPrepareEsCommonTitleKey, SmcLoadPreparedAesKey

This commit is contained in:
Michael Scire 2020-05-20 06:03:07 -07:00 committed by SciresM
parent 985e97cf78
commit ccba70abfe
13 changed files with 461 additions and 50 deletions

View file

@ -155,6 +155,15 @@ namespace ams::secmon::smc {
0xE2, 0xD6, 0xB8, 0x7A, 0x11, 0x9C, 0xB8, 0x80, 0xE8, 0x22, 0x88, 0x8A, 0x46, 0xFB, 0xA1, 0x95
};
constexpr const u8 EsCommonKeySources[EsCommonKeyType_Count][AesKeySize] = {
[EsCommonKeyType_TitleKey] = { 0x1E, 0xDC, 0x7B, 0x3B, 0x60, 0xE6, 0xB4, 0xD8, 0x78, 0xB8, 0x17, 0x15, 0x98, 0x5E, 0x62, 0x9B },
[EsCommonKeyType_ArchiveKey] = { 0x3B, 0x78, 0xF2, 0x61, 0x0F, 0x9D, 0x5A, 0xE2, 0x7B, 0x4E, 0x45, 0xAF, 0xCB, 0x0B, 0x67, 0x4D },
};
constexpr const u8 EsSealKeySource[AesKeySize] = {
0xCB, 0xB7, 0x6E, 0x38, 0xA1, 0xCB, 0x77, 0x0F, 0xB2, 0xA5, 0xB2, 0x9D, 0xD8, 0x56, 0x9F, 0x76
};
constexpr const u8 SecureDataSource[AesKeySize] = {
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
};
@ -463,6 +472,51 @@ namespace ams::secmon::smc {
return SmcResult::Success;
}
SmcResult LoadPreparedAesKeyImpl(SmcArguments &args) {
/* Decode arguments. */
u8 access_key[AesKeySize];
const int slot = args.r[1];
std::memcpy(access_key, std::addressof(args.r[2]), sizeof(access_key));
/* Validate arguments. */
SMC_R_UNLESS(pkg1::IsUserAesKeySlot(slot), InvalidArgument);
/* Derive the seal key. */
se::SetEncryptedAesKey128(pkg1::AesKeySlot_Smc, pkg1::AesKeySlot_RandomForUserWrap, EsSealKeySource, sizeof(EsSealKeySource));
/* Unseal the key. */
se::SetEncryptedAesKey128(slot, pkg1::AesKeySlot_Smc, access_key, sizeof(access_key));
return SmcResult::Success;
}
SmcResult PrepareEsCommonTitleKeyImpl(SmcArguments &args) {
/* Declare variables. */
u8 key_source[se::AesBlockSize];
u8 key[se::AesBlockSize];
u8 access_key[se::AesBlockSize];
/* Decode arguments. */
std::memcpy(key_source, std::addressof(args.r[1]), sizeof(key_source));
const int generation = GetTargetFirmware() >= TargetFirmware_3_0_0 ? std::max(0, static_cast<int>(args.r[3]) - 1) : 0;
/* Validate arguments. */
SMC_R_UNLESS(pkg1::IsValidKeyGeneration(generation), InvalidArgument);
SMC_R_UNLESS(generation <= GetKeyGeneration(), InvalidArgument);
/* Derive the key. */
DecryptWithEsCommonKey(key, sizeof(key), key_source, sizeof(key_source), EsCommonKeyType_TitleKey, generation);
/* Prepare the aes key. */
PrepareEsAesKey(access_key, sizeof(access_key), key, sizeof(key));
/* Copy the access key to output. */
std::memcpy(std::addressof(args.r[1]), access_key, sizeof(access_key));
return SmcResult::Success;
}
SmcResult DecryptDeviceUniqueDataImpl(SmcArguments &args) {
/* Decode arguments. */
u8 access_key[se::AesBlockSize];
@ -530,6 +584,7 @@ namespace ams::secmon::smc {
case DeviceUniqueData_ImportEsClientCertKey:
ImportRsaKeyExponent(ConvertToImportRsaKey(mode), work_buffer, se::RsaSize);
ImportRsaKeyModulusProvisionally(ConvertToImportRsaKey(mode), work_buffer + se::RsaSize, se::RsaSize);
CommitRsaKeyModulus(ConvertToImportRsaKey(mode));
break;
AMS_UNREACHABLE_DEFAULT_CASE();
}
@ -579,8 +634,11 @@ namespace ams::secmon::smc {
}
SmcResult SmcLoadPreparedAesKey(SmcArguments &args) {
/* TODO */
return SmcResult::NotImplemented;
return LockSecurityEngineAndInvoke(args, LoadPreparedAesKeyImpl);
}
SmcResult SmcPrepareEsCommonTitleKey(SmcArguments &args) {
return LockSecurityEngineAndInvoke(args, PrepareEsCommonTitleKeyImpl);
}
/* Device unique data functionality. */
@ -604,6 +662,35 @@ namespace ams::secmon::smc {
return SmcResult::NotImplemented;
}
/* Es encryption utilities. */
void DecryptWithEsCommonKey(void *dst, size_t dst_size, const void *src, size_t src_size, EsCommonKeyType type, int generation) {
/* Validate pre-conditions. */
AMS_ABORT_UNLESS(dst_size == AesKeySize);
AMS_ABORT_UNLESS(src_size == AesKeySize);
AMS_ABORT_UNLESS(0 <= type && type < EsCommonKeyType_Count);
/* Prepare the master key for the generation. */
const int slot = PrepareMasterKey(generation);
/* Derive the es common key. */
se::SetEncryptedAesKey128(pkg1::AesKeySlot_Smc, slot, EsCommonKeySources[type], AesKeySize);
/* Decrypt the input using the common key. */
se::DecryptAes128(dst, dst_size, pkg1::AesKeySlot_Smc, src, src_size);
}
void PrepareEsAesKey(void *dst, size_t dst_size, const void *src, size_t src_size) {
/* Validate pre-conditions. */
AMS_ABORT_UNLESS(dst_size == AesKeySize);
AMS_ABORT_UNLESS(src_size == AesKeySize);
/* Derive the seal key. */
se::SetEncryptedAesKey128(pkg1::AesKeySlot_Smc, pkg1::AesKeySlot_RandomForUserWrap, EsSealKeySource, sizeof(EsSealKeySource));
/* Seal the key. */
se::EncryptAes128(dst, dst_size, pkg1::AesKeySlot_Smc, src, src_size);
}
/* 'Tis the last rose of summer, / Left blooming alone; */
/* Oh! who would inhabit / This bleak world alone? */
SmcResult SmcGetSecureData(SmcArguments &args) {

View file

@ -19,6 +19,13 @@
namespace ams::secmon::smc {
enum EsCommonKeyType {
EsCommonKeyType_TitleKey = 0,
EsCommonKeyType_ArchiveKey = 1,
EsCommonKeyType_Count,
};
/* General Aes functionality. */
SmcResult SmcGenerateAesKek(SmcArguments &args);
SmcResult SmcLoadAesKey(SmcArguments &args);
@ -26,6 +33,7 @@ namespace ams::secmon::smc {
SmcResult SmcGenerateSpecificAesKey(SmcArguments &args);
SmcResult SmcComputeCmac(SmcArguments &args);
SmcResult SmcLoadPreparedAesKey(SmcArguments &args);
SmcResult SmcPrepareEsCommonTitleKey(SmcArguments &args);
/* Device unique data functionality. */
SmcResult SmcDecryptDeviceUniqueData(SmcArguments &args);
@ -35,6 +43,10 @@ namespace ams::secmon::smc {
SmcResult SmcDecryptAndImportEsDeviceKey(SmcArguments &args);
SmcResult SmcDecryptAndImportLotusKey(SmcArguments &args);
/* Es encryption utilities. */
void DecryptWithEsCommonKey(void *dst, size_t dst_size, const void *src, size_t src_size, EsCommonKeyType type, int generation);
void PrepareEsAesKey(void *dst, size_t dst_size, const void *src, size_t src_size);
/* The last rose of summer. */
SmcResult SmcGetSecureData(SmcArguments &args);

View file

@ -1,32 +0,0 @@
/*
* Copyright (c) 2018-2020 Atmosphère-NX
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <exosphere.hpp>
#include "../secmon_error.hpp"
#include "secmon_smc_es.hpp"
namespace ams::secmon::smc {
SmcResult SmcPrepareEsDeviceUniqueKey(SmcArguments &args) {
/* TODO */
return SmcResult::NotImplemented;
}
SmcResult SmcPrepareEsCommonKey(SmcArguments &args) {
/* TODO */
return SmcResult::NotImplemented;
}
}

View file

@ -1,32 +0,0 @@
/*
* Copyright (c) 2018-2020 Atmosphère-NX
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once
#include <exosphere.hpp>
#include "secmon_smc_common.hpp"
namespace ams::secmon::smc {
enum EsKeyType {
EsKeyType_TitleKey = 0,
EsKeyType_ArchiveKey = 1,
EsKeyType_Count = 2,
};
SmcResult SmcPrepareEsDeviceUniqueKey(SmcArguments &args);
SmcResult SmcPrepareEsCommonKey(SmcArguments &args);
}

View file

@ -22,7 +22,6 @@
#include "secmon_smc_carveout.hpp"
#include "secmon_smc_device_unique_data.hpp"
#include "secmon_smc_error.hpp"
#include "secmon_smc_es.hpp"
#include "secmon_smc_info.hpp"
#include "secmon_smc_memory_access.hpp"
#include "secmon_smc_power_management.hpp"
@ -120,7 +119,7 @@ namespace ams::secmon::smc {
{ 0xC300060F, Restriction_DeviceUniqueDataNotAllowed, SmcModularExponentiateByStorageKey },
{ 0xC3000610, Restriction_SafeModeNotAllowed, SmcPrepareEsDeviceUniqueKey },
{ 0xC3000011, Restriction_SafeModeNotAllowed, SmcLoadPreparedAesKey },
{ 0xC3000012, Restriction_SafeModeNotAllowed, SmcPrepareEsCommonKey }
{ 0xC3000012, Restriction_SafeModeNotAllowed, SmcPrepareEsCommonTitleKey }
};
constinit HandlerInfo g_kern_handlers[] = {
@ -233,8 +232,8 @@ namespace ams::secmon::smc {
constinit std::atomic<int> g_logged = 0;
constexpr int LogMin = 0x4000;
constexpr int LogMax = 0x4200;
constexpr int LogMin = 0x1000000;
constexpr int LogMax = 0x1000000;
constexpr size_t LogBufSize = 0x5000;

View file

@ -15,10 +15,158 @@
*/
#include <exosphere.hpp>
#include "../secmon_error.hpp"
#include "../secmon_key_storage.hpp"
#include "secmon_smc_aes.hpp"
#include "secmon_smc_rsa.hpp"
#include "secmon_smc_se_lock.hpp"
#include "secmon_page_mapper.hpp"
namespace ams::secmon::smc {
namespace {
struct PrepareEsDeviceUniqueKeyOption {
using KeyGeneration = util::BitPack32::Field<0, 6, int>;
using Type = util::BitPack32::Field<6, 1, EsCommonKeyType>;
using Reserved = util::BitPack32::Field<7, 25, u32>;
};
class PrepareEsDeviceUniqueKeyAsyncArguments {
private:
int generation;
EsCommonKeyType type;
u8 label_digest[crypto::Sha256Generator::HashSize];
public:
void Set(int gen, EsCommonKeyType t, const u8 ld[crypto::Sha256Generator::HashSize]) {
this->generation = gen;
this->type = t;
std::memcpy(this->label_digest, ld, sizeof(this->label_digest));
}
int GetKeyGeneration() const { return this->generation; }
EsCommonKeyType GetCommonKeyType() const { return this->type; }
void GetLabelDigest(u8 dst[crypto::Sha256Generator::HashSize]) const { std::memcpy(dst, this->label_digest, sizeof(this->label_digest)); }
};
class ModularExponentiateByStorageKeyAsyncArguments {
private:
u8 msg[se::RsaSize];
public:
void Set(const void *m, size_t m_size) {
std::memcpy(this->msg, m, sizeof(this->msg));
}
void GetMessage(void *dst, size_t dst_size) const { std::memcpy(dst, this->msg, sizeof(this->msg)); }
};
constinit bool g_exp_mod_completed = false;
constinit union {
ModularExponentiateByStorageKeyAsyncArguments modular_exponentiate_by_storage_key;
PrepareEsDeviceUniqueKeyAsyncArguments prepare_es_device_unique_key;
} g_async_arguments;
ALWAYS_INLINE ModularExponentiateByStorageKeyAsyncArguments &GetModularExponentiateByStorageKeyAsyncArguments() {
return g_async_arguments.modular_exponentiate_by_storage_key;
}
ALWAYS_INLINE PrepareEsDeviceUniqueKeyAsyncArguments &GetPrepareEsDeviceUniqueKeyAsyncArguments() {
return g_async_arguments.prepare_es_device_unique_key;
}
void SecurityEngineDoneHandler() {
/* End the asynchronous operation. */
g_exp_mod_completed = true;
EndAsyncOperation();
}
SmcResult PrepareEsDeviceUniqueKeyImpl(SmcArguments &args) {
/* Decode arguments. */
u8 label_digest[crypto::Sha256Generator::HashSize];
const uintptr_t msg_address = args.r[1];
const uintptr_t mod_address = args.r[2];
std::memcpy(label_digest, std::addressof(args.r[3]), sizeof(label_digest));
const util::BitPack32 option = { static_cast<u32>(args.r[7]) };
const auto generation = GetTargetFirmware() >= TargetFirmware_3_0_0 ? std::max(0, option.Get<PrepareEsDeviceUniqueKeyOption::KeyGeneration>() - 1) : 0;
const auto type = option.Get<PrepareEsDeviceUniqueKeyOption::Type>();
const auto reserved = option.Get<PrepareEsDeviceUniqueKeyOption::Reserved>();
/* Validate arguments. */
SMC_R_UNLESS(reserved == 0, InvalidArgument);
SMC_R_UNLESS(pkg1::IsValidKeyGeneration(generation), InvalidArgument);
SMC_R_UNLESS(generation <= GetKeyGeneration(), InvalidArgument);
SMC_R_UNLESS(type < EsCommonKeyType_Count, InvalidArgument);
/* Copy the message and modulus from the user. */
alignas(8) u8 msg[se::RsaSize];
alignas(8) u8 mod[se::RsaSize];
{
UserPageMapper mapper(msg_address);
SMC_R_UNLESS(mapper.Map(), InvalidArgument);
SMC_R_UNLESS(mapper.CopyFromUser(msg, msg_address, sizeof(msg)), InvalidArgument);
SMC_R_UNLESS(mapper.CopyFromUser(mod, mod_address, sizeof(mod)), InvalidArgument);
}
/* We're performing an operation, so the operation is not completed. */
g_exp_mod_completed = false;
/* Set the async arguments. */
GetPrepareEsDeviceUniqueKeyAsyncArguments().Set(generation, type, label_digest);
/* Load the es drm key into the security engine. */
SMC_R_UNLESS(LoadRsaKey(pkg1::RsaKeySlot_Temporary, ImportRsaKey_EsDrmCert), NotInitialized);
/* Trigger the asynchronous modular exponentiation. */
se::ModularExponentiateAsync(pkg1::RsaKeySlot_Temporary, msg, sizeof(msg), SecurityEngineDoneHandler);
return SmcResult::Success;
}
SmcResult GetPrepareEsDeviceUniqueKeyResult(void *dst, size_t dst_size) {
/* Declare variables. */
u8 key_source[se::AesBlockSize];
u8 key[se::AesBlockSize];
u8 access_key[se::AesBlockSize];
/* Validate state. */
SMC_R_UNLESS(g_exp_mod_completed, Busy);
SMC_R_UNLESS(dst_size == sizeof(access_key), InvalidArgument);
/* We want to relinquish our security engine lock at the end of scope. */
ON_SCOPE_EXIT { UnlockSecurityEngine(); };
/* Get the async args. */
const auto &async_args = GetPrepareEsDeviceUniqueKeyAsyncArguments();
/* Get the exponentiation output. */
alignas(8) u8 msg[se::RsaSize];
se::GetRsaResult(msg, sizeof(msg));
/* Decode the key. */
{
/* Get the label digest. */
u8 label_digest[crypto::Sha256Generator::HashSize];
async_args.GetLabelDigest(label_digest);
/* Decode the key source. */
const size_t key_source_size = se::DecodeRsaOaepSha256(key_source, sizeof(key_source), msg, sizeof(msg), label_digest, sizeof(label_digest));
SMC_R_UNLESS(key_source_size == sizeof(key_source), InvalidArgument);
}
/* Decrypt the key. */
DecryptWithEsCommonKey(key, sizeof(key), key_source, sizeof(key_source), async_args.GetCommonKeyType(), async_args.GetKeyGeneration());
PrepareEsAesKey(access_key, sizeof(access_key), key, sizeof(key));
/* Copy the access key to output. */
std::memcpy(dst, access_key, sizeof(access_key));
return SmcResult::Success;
}
}
SmcResult SmcModularExponentiate(SmcArguments &args) {
/* TODO */
return SmcResult::NotImplemented;
@ -29,4 +177,8 @@ namespace ams::secmon::smc {
return SmcResult::NotImplemented;
}
SmcResult SmcPrepareEsDeviceUniqueKey(SmcArguments &args) {
return LockSecurityEngineAndInvokeAsync(args, PrepareEsDeviceUniqueKeyImpl, GetPrepareEsDeviceUniqueKeyResult);
}
}

View file

@ -22,4 +22,6 @@ namespace ams::secmon::smc {
SmcResult SmcModularExponentiate(SmcArguments &args);
SmcResult SmcModularExponentiateByStorageKey(SmcArguments &args);
SmcResult SmcPrepareEsDeviceUniqueKey(SmcArguments &args);
}