IOSC: Reuse CertReader for cert imports

This commit is contained in:
Léo Lam 2018-05-18 21:43:26 +02:00
parent 90e86fa9a6
commit 964d00447d
4 changed files with 49 additions and 73 deletions

View File

@ -888,7 +888,7 @@ ReturnCode ES::WriteNewCertToStore(const IOS::ES::CertReader& cert)
ReturnCode ES::VerifyContainer(VerifyContainerType type, VerifyMode mode, ReturnCode ES::VerifyContainer(VerifyContainerType type, VerifyMode mode,
const IOS::ES::SignedBlobReader& signed_blob, const IOS::ES::SignedBlobReader& signed_blob,
const std::vector<u8>& cert_chain, u32 iosc_handle) const std::vector<u8>& cert_chain, u32* issuer_handle_out)
{ {
if (!SConfig::GetInstance().m_enable_signature_checks) if (!SConfig::GetInstance().m_enable_signature_checks)
return IPC_SUCCESS; return IPC_SUCCESS;
@ -927,7 +927,7 @@ ReturnCode ES::VerifyContainer(VerifyContainerType type, VerifyMode mode,
if (ret != IPC_SUCCESS) if (ret != IPC_SUCCESS)
return ret; return ret;
Common::ScopeGuard ca_guard{[&] { iosc.DeleteObject(handle, PID_ES); }}; 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) if (ret != IPC_SUCCESS)
{ {
ERROR_LOG(IOS_ES, "VerifyContainer: IOSC_ImportCertificate(ca) failed with error %d", ret); 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) if (ret != IPC_SUCCESS)
return ret; return ret;
Common::ScopeGuard issuer_guard{[&] { iosc.DeleteObject(issuer_handle, PID_ES); }}; 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) if (ret != IPC_SUCCESS)
{ {
ERROR_LOG(IOS_ES, "VerifyContainer: IOSC_ImportCertificate(issuer) failed with error %d", ret); 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. // Verify the signature.
const std::vector<u8> signature = signed_blob.GetSignatureData(); const std::vector<u8> 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) if (ret != IPC_SUCCESS)
{ {
ERROR_LOG(IOS_ES, "VerifyContainer: IOSC_VerifyPublicKeySign failed with error %d", ret); 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); 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 && issuer_handle_out)
if (ret == IPC_SUCCESS && iosc_handle)
{ {
ret = iosc.ImportCertificate(signed_blob.GetBytes().data(), issuer_handle, iosc_handle, PID_ES); *issuer_handle_out = issuer_handle;
ERROR_LOG(IOS_ES, "VerifyContainer: IOSC_ImportCertificate(final) failed with error %d", ret); issuer_guard.Dismiss();
} }
return ret; return ret;
} }
ReturnCode ES::VerifyContainer(VerifyContainerType type, VerifyMode mode,
const IOS::ES::CertReader& cert, const std::vector<u8>& 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 Device
} // namespace HLE } // namespace HLE
} // namespace IOS } // namespace IOS

View File

@ -323,9 +323,14 @@ private:
bool IsIssuerCorrect(VerifyContainerType type, const IOS::ES::CertReader& issuer_cert) const; bool IsIssuerCorrect(VerifyContainerType type, const IOS::ES::CertReader& issuer_cert) const;
ReturnCode ReadCertStore(std::vector<u8>* buffer) const; ReturnCode ReadCertStore(std::vector<u8>* buffer) const;
ReturnCode WriteNewCertToStore(const IOS::ES::CertReader& cert); 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, ReturnCode VerifyContainer(VerifyContainerType type, VerifyMode mode,
const IOS::ES::SignedBlobReader& signed_blob, const IOS::ES::SignedBlobReader& signed_blob,
const std::vector<u8>& cert_chain, u32 iosc_handle = 0); const std::vector<u8>& cert_chain, u32* issuer_handle = nullptr);
ReturnCode VerifyContainer(VerifyContainerType type, VerifyMode mode,
const IOS::ES::CertReader& certificate,
const std::vector<u8>& cert_chain, u32 certificate_iosc_handle);
// Start a title import. // Start a title import.
bool InitImport(const IOS::ES::TMDReader& tmd); bool InitImport(const IOS::ES::TMDReader& tmd);

View File

@ -27,6 +27,7 @@
#include "Common/StringUtil.h" #include "Common/StringUtil.h"
#include "Common/Swap.h" #include "Common/Swap.h"
#include "Core/IOS/Device.h" #include "Core/IOS/Device.h"
#include "Core/IOS/ES/Formats.h"
namespace 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<u8, 20>& sha1, Handle signer_handle, ReturnCode IOSC::VerifyPublicKeySign(const std::array<u8, 20>& sha1, Handle signer_handle,
const u8* signature, u32 pid) const const std::vector<u8>& signature, u32 pid) const
{ {
if (!HasOwnership(signer_handle, pid)) if (!HasOwnership(signer_handle, pid))
return IOSC_EACCES; return IOSC_EACCES;
@ -325,7 +326,7 @@ ReturnCode IOSC::VerifyPublicKeySign(const std::array<u8, 20>& sha1, Handle sign
rsa.len = entry->data.size(); rsa.len = entry->data.size();
const int ret = mbedtls_rsa_pkcs1_verify(&rsa, nullptr, nullptr, MBEDTLS_RSA_PUBLIC, 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) if (ret != 0)
{ {
WARN_LOG(IOS, "VerifyPublicKeySign: RSA verification failed (error %d)", ret); WARN_LOG(IOS, "VerifyPublicKeySign: RSA verification failed (error %d)", ret);
@ -342,53 +343,8 @@ ReturnCode IOSC::VerifyPublicKeySign(const std::array<u8, 20>& sha1, Handle sign
} }
} }
struct ImportCertParameters ReturnCode IOSC::ImportCertificate(const IOS::ES::CertReader& cert, Handle signer_handle,
{ Handle dest_handle, u32 pid)
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<SignatureType>(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<PublicKeyType>(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)
{ {
if (!HasOwnership(signer_handle, pid) || !HasOwnership(dest_handle, pid)) if (!HasOwnership(signer_handle, pid) || !HasOwnership(dest_handle, pid))
return IOSC_EACCES; 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) if (signer_entry->type != TYPE_PUBLIC_KEY || dest_entry->type != TYPE_PUBLIC_KEY)
return IOSC_INVALID_OBJTYPE; return IOSC_INVALID_OBJTYPE;
ImportCertParameters parameters; if (!cert.IsValid())
const ReturnCode ret = GetImportCertParameters(cert, &parameters); return IOSC_INVALID_FORMAT;
if (ret != IPC_SUCCESS)
return ret;
std::array<u8, 20> sha1; const std::vector<u8> signature = cert.GetSignatureData();
mbedtls_sha1(cert + parameters.offset, parameters.size, sha1.data()); if (VerifyPublicKeySign(cert.GetSha1(), signer_handle, signature, pid) != IPC_SUCCESS)
if (VerifyPublicKeySign(sha1, signer_handle, cert + parameters.signature_offset, pid) !=
IPC_SUCCESS)
{
return IOSC_FAIL_CHECKVALUE; return IOSC_FAIL_CHECKVALUE;
}
return ImportPublicKey(dest_handle, cert + parameters.public_key_offset, const std::vector<u8> public_key = cert.GetPublicKey();
cert + parameters.public_key_exponent_offset, pid); 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 ReturnCode IOSC::GetOwnership(Handle handle, u32* owner) const

View File

@ -18,6 +18,11 @@ class PointerWrap;
namespace IOS namespace IOS
{ {
namespace ES
{
class CertReader;
} // namespace ES
enum class SignatureType : u32 enum class SignatureType : u32
{ {
RSA4096 = 0x00010000, RSA4096 = 0x00010000,
@ -192,9 +197,10 @@ public:
u32 pid) const; u32 pid) const;
ReturnCode VerifyPublicKeySign(const std::array<u8, 20>& sha1, Handle signer_handle, ReturnCode VerifyPublicKeySign(const std::array<u8, 20>& sha1, Handle signer_handle,
const u8* signature, u32 pid) const; const std::vector<u8>& signature, u32 pid) const;
// Import a certificate (signed by the certificate in signer_handle) into dest_handle. // 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 // Ownership
ReturnCode GetOwnership(Handle handle, u32* owner) const; ReturnCode GetOwnership(Handle handle, u32* owner) const;