mirror of
https://github.com/Atmosphere-NX/Atmosphere.git
synced 2025-05-31 14:58: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
|
@ -20,6 +20,7 @@
|
|||
#include <exosphere/se/se_management.hpp>
|
||||
#include <exosphere/se/se_aes.hpp>
|
||||
#include <exosphere/se/se_hash.hpp>
|
||||
#include <exosphere/se/se_oaep.hpp>
|
||||
#include <exosphere/se/se_rsa.hpp>
|
||||
#include <exosphere/se/se_rng.hpp>
|
||||
#include <exosphere/se/se_suspend.hpp>
|
||||
|
|
23
libraries/libexosphere/include/exosphere/se/se_oaep.hpp
Normal file
23
libraries/libexosphere/include/exosphere/se/se_oaep.hpp
Normal file
|
@ -0,0 +1,23 @@
|
|||
/*
|
||||
* 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 <vapours.hpp>
|
||||
|
||||
namespace ams::se {
|
||||
|
||||
size_t DecodeRsaOaepSha256(void *dst, size_t dst_size, void *src, size_t src_size, const void *label_digest, size_t label_digest_size);
|
||||
|
||||
}
|
|
@ -15,6 +15,7 @@
|
|||
*/
|
||||
#pragma once
|
||||
#include <vapours.hpp>
|
||||
#include <exosphere/se/se_common.hpp>
|
||||
|
||||
namespace ams::se {
|
||||
|
||||
|
@ -27,5 +28,8 @@ namespace ams::se {
|
|||
void SetRsaKey(int slot, const void *mod, size_t mod_size, const void *exp, size_t exp_size);
|
||||
|
||||
void ModularExponentiate(void *dst, size_t dst_size, int slot, const void *src, size_t src_size);
|
||||
void ModularExponentiateAsync(int slot, const void *src, size_t src_size, DoneHandler handler);
|
||||
|
||||
void GetRsaResult(void *dst, size_t dst_size);
|
||||
|
||||
}
|
||||
|
|
|
@ -131,6 +131,25 @@ namespace ams::se {
|
|||
std::memcpy(dst, aligned, dst_size);
|
||||
}
|
||||
|
||||
void StartInputOperation(volatile SecurityEngineRegisters *SE, const void *src, size_t src_size) {
|
||||
/* Set the linked list entry. */
|
||||
LinkedListEntry src_entry;
|
||||
SetLinkedListEntry(std::addressof(src_entry), src, src_size);
|
||||
|
||||
/* Ensure the linked list entry data is seen correctly. */
|
||||
hw::FlushDataCache(std::addressof(src_entry), sizeof(src_entry));
|
||||
hw::DataSynchronizationBarrierInnerShareable();
|
||||
|
||||
/* Configure the linked list addresses. */
|
||||
reg::Write(SE->SE_IN_LL_ADDR, static_cast<u32>(GetPhysicalAddress(std::addressof(src_entry))));
|
||||
|
||||
/* Start the operation. */
|
||||
StartOperation(SE, SE_OPERATION_OP_START);
|
||||
|
||||
/* Ensure the operation is started. */
|
||||
EnsureOperationStarted(SE);
|
||||
}
|
||||
|
||||
void StartOperationRaw(volatile SecurityEngineRegisters *SE, SE_OPERATION_OP op, u32 out_ll_address, u32 in_ll_address) {
|
||||
/* Configure the linked list addresses. */
|
||||
reg::Write(SE->SE_IN_LL_ADDR, in_ll_address);
|
||||
|
|
|
@ -23,6 +23,7 @@ namespace ams::se {
|
|||
void ExecuteOperation(volatile SecurityEngineRegisters *SE, SE_OPERATION_OP op, void *dst, size_t dst_size, const void *src, size_t src_size);
|
||||
void ExecuteOperationSingleBlock(volatile SecurityEngineRegisters *SE, void *dst, size_t dst_size, const void *src, size_t src_size);
|
||||
|
||||
void StartInputOperation(volatile SecurityEngineRegisters *SE, const void *src, size_t src_size);
|
||||
void StartOperationRaw(volatile SecurityEngineRegisters *SE, SE_OPERATION_OP op, u32 out_ll_address, u32 in_ll_address);
|
||||
void SetDoneHandler(volatile SecurityEngineRegisters *SE, DoneHandler handler);
|
||||
|
||||
|
|
122
libraries/libexosphere/source/se/se_oaep.cpp
Normal file
122
libraries/libexosphere/source/se/se_oaep.cpp
Normal file
|
@ -0,0 +1,122 @@
|
|||
/*
|
||||
* 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 "se_execute.hpp"
|
||||
|
||||
namespace ams::se {
|
||||
|
||||
/* NOTE: This implementation is mostly copy/pasted from crypto::impl::RsaOaepImpl. */
|
||||
|
||||
namespace {
|
||||
|
||||
constexpr inline size_t HashSize = sizeof(Sha256Hash);
|
||||
|
||||
constexpr inline u8 HeadMagic = 0x00;
|
||||
|
||||
void ApplyMGF1(u8 *dst, size_t dst_size, const void *src, size_t src_size) {
|
||||
/* Check our pre-conditions. */
|
||||
AMS_ABORT_UNLESS(src_size <= RsaSize - (1 + HashSize));
|
||||
|
||||
/* Create a buffer. */
|
||||
util::AlignedBuffer<hw::DataCacheLineSize, RsaSize - (1 + HashSize) + sizeof(u32)> buf;
|
||||
u32 counter = 0;
|
||||
|
||||
while (dst_size > 0) {
|
||||
/* Setup the current hash buffer. */
|
||||
const size_t cur_size = std::min(HashSize, dst_size);
|
||||
std::memcpy(static_cast<u8 *>(buf), src, src_size);
|
||||
{
|
||||
u32 counter_be;
|
||||
util::StoreBigEndian(std::addressof(counter_be), counter++);
|
||||
std::memcpy(static_cast<u8 *>(buf) + src_size, std::addressof(counter_be), sizeof(counter_be));
|
||||
}
|
||||
|
||||
/* Ensure se sees correct data. */
|
||||
hw::FlushDataCache(buf, src_size + sizeof(u32));
|
||||
hw::DataSynchronizationBarrierInnerShareable();
|
||||
|
||||
/* Calculate the hash. */
|
||||
Sha256Hash hash;
|
||||
se::CalculateSha256(std::addressof(hash), buf, src_size + sizeof(u32));
|
||||
|
||||
/* Mask the current output. */
|
||||
const u8 *mask = hash.bytes;
|
||||
for (size_t i = 0; i < cur_size; ++i) {
|
||||
*(dst++) ^= *(mask++);
|
||||
}
|
||||
|
||||
/* Advance. */
|
||||
dst_size -= cur_size;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
size_t DecodeRsaOaepSha256(void *dst, size_t dst_size, void *src, size_t src_size, const void *label_digest, size_t label_digest_size) {
|
||||
/* Check our preconditions. */
|
||||
AMS_ABORT_UNLESS(src_size == RsaSize);
|
||||
AMS_ABORT_UNLESS(label_digest_size == HashSize);
|
||||
|
||||
/* Get a byte-readable copy of the input. */
|
||||
u8 *buf = static_cast<u8 *>(src);
|
||||
|
||||
/* Validate sanity byte. */
|
||||
bool is_valid = buf[0] == HeadMagic;
|
||||
|
||||
/* Decrypt seed and masked db. */
|
||||
size_t db_len = src_size - HashSize - 1;
|
||||
u8 *seed = buf + 1;
|
||||
u8 *db = seed + HashSize;
|
||||
ApplyMGF1(seed, HashSize, db, db_len);
|
||||
ApplyMGF1(db, db_len, seed, HashSize);
|
||||
|
||||
/* Check the label digest. */
|
||||
is_valid &= crypto::IsSameBytes(label_digest, db, HashSize);
|
||||
|
||||
/* Skip past the label digest. */
|
||||
db += HashSize;
|
||||
db_len -= HashSize;
|
||||
|
||||
/* Verify that DB is of the form 0000...0001 < message > */
|
||||
s32 msg_ofs = 0;
|
||||
{
|
||||
int looking_for_one = 1;
|
||||
int invalid_db_padding = 0;
|
||||
int is_zero;
|
||||
int is_one;
|
||||
for (size_t i = 0; i < db_len; /* ... */) {
|
||||
is_zero = (db[i] == 0);
|
||||
is_one = (db[i] == 1);
|
||||
msg_ofs += (looking_for_one & is_one) * (static_cast<s32>(++i));
|
||||
looking_for_one &= ~is_one;
|
||||
invalid_db_padding |= (looking_for_one & ~is_zero);
|
||||
}
|
||||
|
||||
is_valid &= (invalid_db_padding == 0);
|
||||
}
|
||||
|
||||
/* If we're invalid, return zero size. */
|
||||
const size_t valid_msg_size = db_len - msg_ofs;
|
||||
const size_t msg_size = std::min(dst_size, static_cast<size_t>(is_valid) * valid_msg_size);
|
||||
|
||||
/* Copy to output. */
|
||||
std::memcpy(dst, db + msg_ofs, msg_size);
|
||||
|
||||
/* Return copied size. */
|
||||
return msg_size;
|
||||
}
|
||||
|
||||
}
|
|
@ -67,6 +67,10 @@ namespace ams::se {
|
|||
}
|
||||
}
|
||||
|
||||
void WaitForInputReadComplete(volatile SecurityEngineRegisters *SE) {
|
||||
while (reg::HasValue(SE->SE_INT_STATUS, SE_REG_BITS_ENUM(INT_STATUS_IN_DONE, CLEAR))) { /* ... */ }
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void ClearRsaKeySlot(int slot) {
|
||||
|
@ -174,4 +178,53 @@ namespace ams::se {
|
|||
GetRsaResult(SE, dst, dst_size);
|
||||
}
|
||||
|
||||
void ModularExponentiateAsync(int slot, const void *src, size_t src_size, DoneHandler handler) {
|
||||
/* Validate the slot and size. */
|
||||
AMS_ABORT_UNLESS(0 <= slot && slot < RsaKeySlotCount);
|
||||
AMS_ABORT_UNLESS(src_size <= RsaSize);
|
||||
|
||||
/* Get the engine. */
|
||||
auto *SE = GetRegisters();
|
||||
|
||||
/* Create a work buffer. */
|
||||
u8 work[RsaSize];
|
||||
util::ClearMemory(work, sizeof(work));
|
||||
|
||||
/* Copy the input into the work buffer (reversing endianness). */
|
||||
const u8 *src_u8 = static_cast<const u8 *>(src);
|
||||
for (size_t i = 0; i < src_size; ++i) {
|
||||
work[src_size - 1 - i] = src_u8[i];
|
||||
}
|
||||
|
||||
/* Flush the work buffer to ensure the SE sees correct results. */
|
||||
hw::FlushDataCache(work, sizeof(work));
|
||||
hw::DataSynchronizationBarrierInnerShareable();
|
||||
|
||||
/* Configure the engine to perform RSA encryption. */
|
||||
reg::Write(SE->SE_CONFIG, SE_REG_BITS_ENUM(CONFIG_ENC_MODE, AESMODE_KEY128),
|
||||
SE_REG_BITS_ENUM(CONFIG_DEC_MODE, AESMODE_KEY128),
|
||||
SE_REG_BITS_ENUM(CONFIG_ENC_ALG, RSA),
|
||||
SE_REG_BITS_ENUM(CONFIG_DEC_ALG, NOP),
|
||||
SE_REG_BITS_ENUM(CONFIG_DST, RSA_REG));
|
||||
|
||||
/* Configure the engine to use the keyslot and correct modulus/exp sizes. */
|
||||
const auto &info = g_rsa_key_infos[slot];
|
||||
reg::Write(SE->SE_RSA_CONFIG, SE_REG_BITS_VALUE(RSA_CONFIG_KEY_SLOT, slot));
|
||||
reg::Write(SE->SE_RSA_KEY_SIZE, info.modulus_size_val);
|
||||
reg::Write(SE->SE_RSA_EXP_SIZE, info.exponent_size_val);
|
||||
|
||||
/* Set the done handler. */
|
||||
SetDoneHandler(SE, handler);
|
||||
|
||||
/* Trigger the input operation. */
|
||||
StartInputOperation(SE, work, src_size);
|
||||
|
||||
/* Wait for input to be read by the se. */
|
||||
WaitForInputReadComplete(SE);
|
||||
}
|
||||
|
||||
void GetRsaResult(void *dst, size_t dst_size) {
|
||||
GetRsaResult(GetRegisters(), dst, dst_size);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue