mirror of
https://github.com/Atmosphere-NX/Atmosphere.git
synced 2025-05-24 19:54:22 -04:00
exo2: implement SmcPrepareEsDeviceUniqueKey, SmcPrepareEsCommonTitleKey, SmcLoadPreparedAesKey
This commit is contained in:
parent
985e97cf78
commit
ccba70abfe
13 changed files with 461 additions and 50 deletions
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue