diff --git a/Source/Core/Core/IOS/ES/ES.cpp b/Source/Core/Core/IOS/ES/ES.cpp index 569d130389..e75bdfb77d 100644 --- a/Source/Core/Core/IOS/ES/ES.cpp +++ b/Source/Core/Core/IOS/ES/ES.cpp @@ -888,7 +888,7 @@ ReturnCode ES::WriteNewCertToStore(const IOS::ES::CertReader& cert) ReturnCode ES::VerifyContainer(VerifyContainerType type, VerifyMode mode, const IOS::ES::SignedBlobReader& signed_blob, - const std::vector& cert_chain, u32 iosc_handle) + const std::vector& cert_chain, u32* issuer_handle_out) { if (!SConfig::GetInstance().m_enable_signature_checks) return IPC_SUCCESS; @@ -927,7 +927,7 @@ ReturnCode ES::VerifyContainer(VerifyContainerType type, VerifyMode mode, if (ret != IPC_SUCCESS) return ret; Common::ScopeGuard ca_guard{[&] { iosc.DeleteObject(handle, PID_ES); }}; - ret = iosc.ImportCertificate(ca_cert.GetBytes().data(), IOSC::HANDLE_ROOT_KEY, handle, PID_ES); + ret = iosc.ImportCertificate(ca_cert, IOSC::HANDLE_ROOT_KEY, handle, PID_ES); if (ret != IPC_SUCCESS) { ERROR_LOG(IOS_ES, "VerifyContainer: IOSC_ImportCertificate(ca) failed with error %d", ret); @@ -941,7 +941,7 @@ ReturnCode ES::VerifyContainer(VerifyContainerType type, VerifyMode mode, if (ret != IPC_SUCCESS) return ret; Common::ScopeGuard issuer_guard{[&] { iosc.DeleteObject(issuer_handle, PID_ES); }}; - ret = iosc.ImportCertificate(issuer_cert.GetBytes().data(), handle, issuer_handle, PID_ES); + ret = iosc.ImportCertificate(issuer_cert, handle, issuer_handle, PID_ES); if (ret != IPC_SUCCESS) { ERROR_LOG(IOS_ES, "VerifyContainer: IOSC_ImportCertificate(issuer) failed with error %d", ret); @@ -950,7 +950,7 @@ ReturnCode ES::VerifyContainer(VerifyContainerType type, VerifyMode mode, // Verify the signature. const std::vector signature = signed_blob.GetSignatureData(); - ret = iosc.VerifyPublicKeySign(signed_blob.GetSha1(), issuer_handle, signature.data(), PID_ES); + ret = iosc.VerifyPublicKeySign(signed_blob.GetSha1(), issuer_handle, signature, PID_ES); if (ret != IPC_SUCCESS) { ERROR_LOG(IOS_ES, "VerifyContainer: IOSC_VerifyPublicKeySign failed with error %d", ret); @@ -968,15 +968,29 @@ ReturnCode ES::VerifyContainer(VerifyContainerType type, VerifyMode mode, ERROR_LOG(IOS_ES, "VerifyContainer: Writing the CA cert failed with return code %d", ret); } - // Import the signed blob to iosc_handle (if a handle was passed to us). - if (ret == IPC_SUCCESS && iosc_handle) + if (ret == IPC_SUCCESS && issuer_handle_out) { - ret = iosc.ImportCertificate(signed_blob.GetBytes().data(), issuer_handle, iosc_handle, PID_ES); - ERROR_LOG(IOS_ES, "VerifyContainer: IOSC_ImportCertificate(final) failed with error %d", ret); + *issuer_handle_out = issuer_handle; + issuer_guard.Dismiss(); } return ret; } + +ReturnCode ES::VerifyContainer(VerifyContainerType type, VerifyMode mode, + const IOS::ES::CertReader& cert, const std::vector& cert_chain, + u32 certificate_iosc_handle) +{ + IOSC::Handle issuer_handle; + ReturnCode ret = VerifyContainer(type, mode, cert, cert_chain, &issuer_handle); + // Import the signed blob. + if (ret == IPC_SUCCESS) + { + ret = m_ios.GetIOSC().ImportCertificate(cert, issuer_handle, certificate_iosc_handle, PID_ES); + m_ios.GetIOSC().DeleteObject(issuer_handle, PID_ES); + } + return ret; +} } // namespace Device } // namespace HLE } // namespace IOS diff --git a/Source/Core/Core/IOS/ES/ES.h b/Source/Core/Core/IOS/ES/ES.h index 9e31ae83b7..dd1050c6e6 100644 --- a/Source/Core/Core/IOS/ES/ES.h +++ b/Source/Core/Core/IOS/ES/ES.h @@ -323,9 +323,14 @@ private: bool IsIssuerCorrect(VerifyContainerType type, const IOS::ES::CertReader& issuer_cert) const; ReturnCode ReadCertStore(std::vector* buffer) const; ReturnCode WriteNewCertToStore(const IOS::ES::CertReader& cert); + // On success, if issuer_handle is non-null, the IOSC object for the issuer will be written to it. + // The caller is responsible for using IOSC_DeleteObject. ReturnCode VerifyContainer(VerifyContainerType type, VerifyMode mode, const IOS::ES::SignedBlobReader& signed_blob, - const std::vector& cert_chain, u32 iosc_handle = 0); + const std::vector& cert_chain, u32* issuer_handle = nullptr); + ReturnCode VerifyContainer(VerifyContainerType type, VerifyMode mode, + const IOS::ES::CertReader& certificate, + const std::vector& cert_chain, u32 certificate_iosc_handle); // Start a title import. bool InitImport(const IOS::ES::TMDReader& tmd); diff --git a/Source/Core/Core/IOS/IOSC.cpp b/Source/Core/Core/IOS/IOSC.cpp index 5df9f49672..c2bbb292f3 100644 --- a/Source/Core/Core/IOS/IOSC.cpp +++ b/Source/Core/Core/IOS/IOSC.cpp @@ -27,6 +27,7 @@ #include "Common/StringUtil.h" #include "Common/Swap.h" #include "Core/IOS/Device.h" +#include "Core/IOS/ES/Formats.h" namespace { @@ -295,7 +296,7 @@ ReturnCode IOSC::Decrypt(Handle key_handle, u8* iv, const u8* input, size_t size } ReturnCode IOSC::VerifyPublicKeySign(const std::array& sha1, Handle signer_handle, - const u8* signature, u32 pid) const + const std::vector& signature, u32 pid) const { if (!HasOwnership(signer_handle, pid)) return IOSC_EACCES; @@ -325,7 +326,7 @@ ReturnCode IOSC::VerifyPublicKeySign(const std::array& sha1, Handle sign rsa.len = entry->data.size(); const int ret = mbedtls_rsa_pkcs1_verify(&rsa, nullptr, nullptr, MBEDTLS_RSA_PUBLIC, - MBEDTLS_MD_SHA1, 0, sha1.data(), signature); + MBEDTLS_MD_SHA1, 0, sha1.data(), signature.data()); if (ret != 0) { WARN_LOG(IOS, "VerifyPublicKeySign: RSA verification failed (error %d)", ret); @@ -342,53 +343,8 @@ ReturnCode IOSC::VerifyPublicKeySign(const std::array& sha1, Handle sign } } -struct ImportCertParameters -{ - size_t offset; - size_t size; - size_t signature_offset; - size_t public_key_offset; - size_t public_key_exponent_offset; -}; - -static ReturnCode GetImportCertParameters(const u8* cert, ImportCertParameters* parameters) -{ - // TODO: Add support for ECC signature type. - const u32 signature_type = Common::swap32(cert + offsetof(Cert, type)); - switch (static_cast(signature_type)) - { - case SignatureType::RSA2048: - { - const u32 key_type = Common::swap32(cert + offsetof(Cert, rsa2048.header.public_key_type)); - - // TODO: Add support for ECC public key type. - if (static_cast(key_type) != PublicKeyType::RSA2048) - return IOSC_INVALID_FORMAT; - - parameters->offset = offsetof(Cert, rsa2048.signature.issuer); - parameters->size = sizeof(Cert::rsa2048) - parameters->offset; - parameters->signature_offset = offsetof(Cert, rsa2048.signature.sig); - parameters->public_key_offset = offsetof(Cert, rsa2048.public_key); - parameters->public_key_exponent_offset = offsetof(Cert, rsa2048.exponent); - return IPC_SUCCESS; - } - case SignatureType::RSA4096: - { - parameters->offset = offsetof(Cert, rsa4096.signature.issuer); - parameters->size = sizeof(Cert::rsa4096) - parameters->offset; - parameters->signature_offset = offsetof(Cert, rsa4096.signature.sig); - parameters->public_key_offset = offsetof(Cert, rsa4096.public_key); - parameters->public_key_exponent_offset = offsetof(Cert, rsa4096.exponent); - return IPC_SUCCESS; - } - default: - WARN_LOG(IOS, "Unknown signature type: %08x", signature_type); - return IOSC_INVALID_FORMAT; - } -} - -ReturnCode IOSC::ImportCertificate(const u8* cert, Handle signer_handle, Handle dest_handle, - u32 pid) +ReturnCode IOSC::ImportCertificate(const IOS::ES::CertReader& cert, Handle signer_handle, + Handle dest_handle, u32 pid) { if (!HasOwnership(signer_handle, pid) || !HasOwnership(dest_handle, pid)) return IOSC_EACCES; @@ -401,22 +357,17 @@ ReturnCode IOSC::ImportCertificate(const u8* cert, Handle signer_handle, Handle if (signer_entry->type != TYPE_PUBLIC_KEY || dest_entry->type != TYPE_PUBLIC_KEY) return IOSC_INVALID_OBJTYPE; - ImportCertParameters parameters; - const ReturnCode ret = GetImportCertParameters(cert, ¶meters); - if (ret != IPC_SUCCESS) - return ret; + if (!cert.IsValid()) + return IOSC_INVALID_FORMAT; - std::array sha1; - mbedtls_sha1(cert + parameters.offset, parameters.size, sha1.data()); - - if (VerifyPublicKeySign(sha1, signer_handle, cert + parameters.signature_offset, pid) != - IPC_SUCCESS) - { + const std::vector signature = cert.GetSignatureData(); + if (VerifyPublicKeySign(cert.GetSha1(), signer_handle, signature, pid) != IPC_SUCCESS) return IOSC_FAIL_CHECKVALUE; - } - return ImportPublicKey(dest_handle, cert + parameters.public_key_offset, - cert + parameters.public_key_exponent_offset, pid); + const std::vector public_key = cert.GetPublicKey(); + const bool is_rsa = cert.GetSignatureType() != SignatureType::ECC; + const u8* exponent = is_rsa ? (public_key.data() + public_key.size() - 4) : nullptr; + return ImportPublicKey(dest_handle, public_key.data(), exponent, pid); } ReturnCode IOSC::GetOwnership(Handle handle, u32* owner) const diff --git a/Source/Core/Core/IOS/IOSC.h b/Source/Core/Core/IOS/IOSC.h index ce56921937..c397b85a5c 100644 --- a/Source/Core/Core/IOS/IOSC.h +++ b/Source/Core/Core/IOS/IOSC.h @@ -18,6 +18,11 @@ class PointerWrap; namespace IOS { +namespace ES +{ +class CertReader; +} // namespace ES + enum class SignatureType : u32 { RSA4096 = 0x00010000, @@ -192,9 +197,10 @@ public: u32 pid) const; ReturnCode VerifyPublicKeySign(const std::array& sha1, Handle signer_handle, - const u8* signature, u32 pid) const; + const std::vector& signature, u32 pid) const; // Import a certificate (signed by the certificate in signer_handle) into dest_handle. - ReturnCode ImportCertificate(const u8* cert, Handle signer_handle, Handle dest_handle, u32 pid); + ReturnCode ImportCertificate(const IOS::ES::CertReader& cert, Handle signer_handle, + Handle dest_handle, u32 pid); // Ownership ReturnCode GetOwnership(Handle handle, u32* owner) const;