ES: Implement VerifySign
This implements ES_VerifySign which is notably used by the system menu when importing saves. Now *all* ES commands that are actually used by titles are implemented.
This commit is contained in:
parent
cec7fded60
commit
4b0f8d9f85
|
@ -524,6 +524,8 @@ IPCCommandResult ES::IOCtlV(const IOCtlVRequest& request)
|
|||
return GetDeviceCertificate(request);
|
||||
case IOCTL_ES_SIGN:
|
||||
return Sign(request);
|
||||
case IOCTL_ES_VERIFYSIGN:
|
||||
return VerifySign(request);
|
||||
case IOCTL_ES_GETBOOT2VERSION:
|
||||
return GetBoot2Version(request);
|
||||
|
||||
|
@ -539,7 +541,6 @@ IPCCommandResult ES::IOCtlV(const IOCtlVRequest& request)
|
|||
case IOCTL_ES_DELETE_STREAM_KEY:
|
||||
return DeleteStreamKey(request);
|
||||
|
||||
case IOCTL_ES_VERIFYSIGN:
|
||||
case IOCTL_ES_UNKNOWN_41:
|
||||
case IOCTL_ES_UNKNOWN_42:
|
||||
PanicAlert("IOS-ES: Unimplemented ioctlv 0x%x (%zu in vectors, %zu io vectors)",
|
||||
|
|
|
@ -132,6 +132,9 @@ public:
|
|||
ReturnCode GetDeviceId(u32* device_id) const;
|
||||
ReturnCode GetTitleId(u64* device_id) const;
|
||||
|
||||
ReturnCode VerifySign(const std::vector<u8>& hash, const std::vector<u8>& ecc_signature,
|
||||
const std::vector<u8>& certs);
|
||||
|
||||
// Views
|
||||
ReturnCode GetV0TicketFromView(const u8* ticket_view, u8* ticket) const;
|
||||
ReturnCode GetTicketFromView(const u8* ticket_view, u8* ticket, u32* ticket_size) const;
|
||||
|
@ -243,6 +246,7 @@ private:
|
|||
IPCCommandResult GetDeviceCertificate(const IOCtlVRequest& request);
|
||||
IPCCommandResult CheckKoreaRegion(const IOCtlVRequest& request);
|
||||
IPCCommandResult Sign(const IOCtlVRequest& request);
|
||||
IPCCommandResult VerifySign(const IOCtlVRequest& request);
|
||||
IPCCommandResult Encrypt(u32 uid, const IOCtlVRequest& request);
|
||||
IPCCommandResult Decrypt(u32 uid, const IOCtlVRequest& request);
|
||||
|
||||
|
|
|
@ -4,10 +4,14 @@
|
|||
|
||||
#include "Core/IOS/ES/ES.h"
|
||||
|
||||
#include <cstring>
|
||||
#include <vector>
|
||||
|
||||
#include <mbedtls/sha1.h>
|
||||
|
||||
#include "Common/Logging/Log.h"
|
||||
#include "Common/ScopeGuard.h"
|
||||
#include "Common/StringUtil.h"
|
||||
#include "Core/ConfigManager.h"
|
||||
#include "Core/HW/Memmap.h"
|
||||
#include "Core/IOS/ES/Formats.h"
|
||||
#include "Core/IOS/Uids.h"
|
||||
|
@ -114,6 +118,99 @@ IPCCommandResult ES::Sign(const IOCtlVRequest& request)
|
|||
m_ios.GetIOSC().Sign(sig_out, ap_cert_out, m_title_context.tmd.GetTitleId(), data, data_size);
|
||||
return GetDefaultReply(IPC_SUCCESS);
|
||||
}
|
||||
|
||||
ReturnCode ES::VerifySign(const std::vector<u8>& hash, const std::vector<u8>& ecc_signature,
|
||||
const std::vector<u8>& certs_bytes)
|
||||
{
|
||||
if (!SConfig::GetInstance().m_enable_signature_checks)
|
||||
{
|
||||
WARN_LOG(IOS_ES, "VerifySign: signature checks are disabled. Skipping.");
|
||||
return IPC_SUCCESS;
|
||||
}
|
||||
|
||||
const std::map<std::string, IOS::ES::CertReader> certs = IOS::ES::ParseCertChain(certs_bytes);
|
||||
if (certs.empty())
|
||||
return ES_EINVAL;
|
||||
|
||||
const auto ap_iterator = std::find_if(certs.begin(), certs.end(), [](const auto& entry) {
|
||||
return entry.first.length() > 2 && entry.first.compare(0, 2, "AP") == 0;
|
||||
});
|
||||
if (ap_iterator == certs.end())
|
||||
return ES_UNKNOWN_ISSUER;
|
||||
const IOS::ES::CertReader& ap = ap_iterator->second;
|
||||
|
||||
const auto ap_issuers = SplitString(ap.GetIssuer(), '-');
|
||||
const auto ng_iterator = ap_issuers.size() > 1 ? certs.find(*ap_issuers.rbegin()) : certs.end();
|
||||
if (ng_iterator == certs.end())
|
||||
return ES_UNKNOWN_ISSUER;
|
||||
const IOS::ES::CertReader& ng = ng_iterator->second;
|
||||
|
||||
IOSC& iosc = m_ios.GetIOSC();
|
||||
IOSC::Handle ng_cert;
|
||||
ReturnCode ret = iosc.CreateObject(&ng_cert, IOSC::TYPE_PUBLIC_KEY, IOSC::SUBTYPE_ECC233, PID_ES);
|
||||
if (ret != IPC_SUCCESS)
|
||||
return ret;
|
||||
Common::ScopeGuard handle_guard{[&] { iosc.DeleteObject(ng_cert, PID_ES); }};
|
||||
|
||||
ret = VerifyContainer(VerifyContainerType::Device, VerifyMode::DoNotUpdateCertStore, ng,
|
||||
certs_bytes, ng_cert);
|
||||
if (ret != IPC_SUCCESS)
|
||||
{
|
||||
ERROR_LOG(IOS_ES, "VerifySign: VerifyContainer(ng) failed with error %d", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = iosc.VerifyPublicKeySign(ap.GetSha1(), ng_cert, ap.GetSignatureData(), PID_ES);
|
||||
if (ret != IPC_SUCCESS)
|
||||
{
|
||||
ERROR_LOG(IOS_ES, "VerifySign: IOSC_VerifyPublicKeySign(ap) failed with error %d", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
IOSC::Handle ap_cert;
|
||||
ret = iosc.CreateObject(&ap_cert, IOSC::TYPE_PUBLIC_KEY, IOSC::SUBTYPE_ECC233, PID_ES);
|
||||
if (ret != IPC_SUCCESS)
|
||||
return ret;
|
||||
Common::ScopeGuard handle2_guard{[&] { iosc.DeleteObject(ap_cert, PID_ES); }};
|
||||
|
||||
ret = iosc.ImportPublicKey(ap_cert, ap.GetPublicKey().data(), nullptr, PID_ES);
|
||||
if (ret != IPC_SUCCESS)
|
||||
{
|
||||
ERROR_LOG(IOS_ES, "VerifySign: IOSC_ImportPublicKey(ap) failed with error %d", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
std::array<u8, 20> sha1;
|
||||
mbedtls_sha1(hash.data(), hash.size(), sha1.data());
|
||||
ret = iosc.VerifyPublicKeySign(sha1, ap_cert, ecc_signature, PID_ES);
|
||||
if (ret != IPC_SUCCESS)
|
||||
{
|
||||
ERROR_LOG(IOS_ES, "VerifySign: IOSC_VerifyPublicKeySign(data) failed with error %d", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
INFO_LOG(IOS_ES, "VerifySign: all checks passed");
|
||||
return IPC_SUCCESS;
|
||||
}
|
||||
|
||||
IPCCommandResult ES::VerifySign(const IOCtlVRequest& request)
|
||||
{
|
||||
if (!request.HasNumberOfValidVectors(3, 0))
|
||||
return GetDefaultReply(ES_EINVAL);
|
||||
if (request.in_vectors[1].size != sizeof(IOS::ECCSignature))
|
||||
return GetDefaultReply(ES_EINVAL);
|
||||
|
||||
std::vector<u8> hash(request.in_vectors[0].size);
|
||||
Memory::CopyFromEmu(hash.data(), request.in_vectors[0].address, hash.size());
|
||||
|
||||
std::vector<u8> ecc_signature(request.in_vectors[1].size);
|
||||
Memory::CopyFromEmu(ecc_signature.data(), request.in_vectors[1].address, ecc_signature.size());
|
||||
|
||||
std::vector<u8> certs(request.in_vectors[2].size);
|
||||
Memory::CopyFromEmu(certs.data(), request.in_vectors[2].address, certs.size());
|
||||
|
||||
return GetDefaultReply(VerifySign(hash, ecc_signature, certs));
|
||||
}
|
||||
} // namespace Device
|
||||
} // namespace HLE
|
||||
} // namespace IOS
|
||||
|
|
Loading…
Reference in New Issue