Skip to content

Commit

Permalink
Merge pull request #5601 from leoetlino/esformats-additions
Browse files Browse the repository at this point in the history
ESFormats additions and fixes
  • Loading branch information
leoetlino committed Jun 15, 2017
2 parents 743284d + a370ad5 commit 9bc1b65
Show file tree
Hide file tree
Showing 10 changed files with 258 additions and 90 deletions.
2 changes: 1 addition & 1 deletion Source/Core/Core/IOS/DI/DI.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -110,7 +110,7 @@ IPCCommandResult DI::IOCtlV(const IOCtlVRequest& request)

// Read TMD to the buffer
const IOS::ES::TMDReader tmd = DVDThread::GetTMD(partition);
const std::vector<u8> raw_tmd = tmd.GetRawTMD();
const std::vector<u8>& raw_tmd = tmd.GetBytes();
Memory::CopyToEmu(request.io_vectors[0].address, raw_tmd.data(), raw_tmd.size());
ES::DIVerify(tmd, DVDThread::GetTicket(partition));

Expand Down
2 changes: 1 addition & 1 deletion Source/Core/Core/IOS/ES/ES.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -610,7 +610,7 @@ s32 ES::DIVerify(const IOS::ES::TMDReader& tmd, const IOS::ES::TicketReader& tic
if (!File::Exists(tmd_path))
{
File::IOFile tmd_file(tmd_path, "wb");
const std::vector<u8>& tmd_bytes = tmd.GetRawTMD();
const std::vector<u8>& tmd_bytes = tmd.GetBytes();
if (!tmd_file.WriteBytes(tmd_bytes.data(), tmd_bytes.size()))
ERROR_LOG(IOS_ES, "DIVerify failed to write disc TMD to NAND.");
}
Expand Down
248 changes: 193 additions & 55 deletions Source/Core/Core/IOS/ES/Formats.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
#include <cstddef>
#include <cstring>
#include <locale>
#include <map>
#include <optional>
#include <string>
#include <utility>
Expand Down Expand Up @@ -59,31 +60,124 @@ bool Content::IsShared() const
return (type & 0x8000) != 0;
}

bool IsValidTMDSize(size_t size)
SignedBlobReader::SignedBlobReader(const std::vector<u8>& bytes) : m_bytes(bytes)
{
return size <= 0x49e4;
}

TMDReader::TMDReader(const std::vector<u8>& bytes) : m_bytes(bytes)
SignedBlobReader::SignedBlobReader(std::vector<u8>&& bytes) : m_bytes(std::move(bytes))
{
}

TMDReader::TMDReader(std::vector<u8>&& bytes) : m_bytes(std::move(bytes))
const std::vector<u8>& SignedBlobReader::GetBytes() const
{
return m_bytes;
}

void TMDReader::SetBytes(const std::vector<u8>& bytes)
void SignedBlobReader::SetBytes(const std::vector<u8>& bytes)
{
m_bytes = bytes;
}

void TMDReader::SetBytes(std::vector<u8>&& bytes)
void SignedBlobReader::SetBytes(std::vector<u8>&& bytes)
{
m_bytes = std::move(bytes);
}

bool SignedBlobReader::IsSignatureValid() const
{
// Too small for the certificate type.
if (m_bytes.size() < sizeof(Cert::type))
return false;

// Too small to contain the whole signature data.
const size_t signature_size = GetSignatureSize();
if (signature_size == 0 || m_bytes.size() < signature_size)
return false;

return true;
}

SignatureType SignedBlobReader::GetSignatureType() const
{
return static_cast<SignatureType>(Common::swap32(m_bytes.data()));
}

std::vector<u8> SignedBlobReader::GetSignatureData() const
{
switch (GetSignatureType())
{
case SignatureType::RSA4096:
{
const auto signature_begin = m_bytes.begin() + offsetof(SignatureRSA4096, sig);
return std::vector<u8>(signature_begin, signature_begin + sizeof(SignatureRSA4096::sig));
}
case SignatureType::RSA2048:
{
const auto signature_begin = m_bytes.begin() + offsetof(SignatureRSA2048, sig);
return std::vector<u8>(signature_begin, signature_begin + sizeof(SignatureRSA2048::sig));
}
default:
return {};
}
}

size_t SignedBlobReader::GetSignatureSize() const
{
switch (GetSignatureType())
{
case SignatureType::RSA4096:
return sizeof(SignatureRSA4096);
case SignatureType::RSA2048:
return sizeof(SignatureRSA2048);
default:
return 0;
}
}

std::string SignedBlobReader::GetIssuer() const
{
switch (GetSignatureType())
{
case SignatureType::RSA4096:
{
const char* issuer =
reinterpret_cast<const char*>(m_bytes.data() + offsetof(SignatureRSA4096, issuer));
return std::string(issuer, strnlen(issuer, sizeof(SignatureRSA4096::issuer)));
}
case SignatureType::RSA2048:
{
const char* issuer =
reinterpret_cast<const char*>(m_bytes.data() + offsetof(SignatureRSA2048, issuer));
return std::string(issuer, strnlen(issuer, sizeof(SignatureRSA2048::issuer)));
}
default:
return "";
}
}

void SignedBlobReader::DoState(PointerWrap& p)
{
p.Do(m_bytes);
}

bool IsValidTMDSize(size_t size)
{
return size <= 0x49e4;
}

TMDReader::TMDReader(const std::vector<u8>& bytes) : SignedBlobReader(bytes)
{
}

TMDReader::TMDReader(std::vector<u8>&& bytes) : SignedBlobReader(std::move(bytes))
{
}

bool TMDReader::IsValid() const
{
if (!IsSignatureValid())
return false;

if (m_bytes.size() < sizeof(TMDHeader))
{
// TMD is too small to contain its base fields.
Expand All @@ -99,16 +193,6 @@ bool TMDReader::IsValid() const
return true;
}

const std::vector<u8>& TMDReader::GetRawTMD() const
{
return m_bytes;
}

std::vector<u8> TMDReader::GetRawHeader() const
{
return std::vector<u8>(m_bytes.begin(), m_bytes.begin() + sizeof(TMDHeader));
}

std::vector<u8> TMDReader::GetRawView() const
{
// Base fields
Expand Down Expand Up @@ -231,49 +315,24 @@ bool TMDReader::FindContentById(u32 id, Content* content) const
return false;
}

void TMDReader::DoState(PointerWrap& p)
{
p.Do(m_bytes);
}

TicketReader::TicketReader(const std::vector<u8>& bytes) : m_bytes(bytes)
TicketReader::TicketReader(const std::vector<u8>& bytes) : SignedBlobReader(bytes)
{
}

TicketReader::TicketReader(std::vector<u8>&& bytes) : m_bytes(std::move(bytes))
TicketReader::TicketReader(std::vector<u8>&& bytes) : SignedBlobReader(std::move(bytes))
{
}

void TicketReader::SetBytes(const std::vector<u8>& bytes)
{
m_bytes = bytes;
}

void TicketReader::SetBytes(std::vector<u8>&& bytes)
{
m_bytes = std::move(bytes);
}

bool TicketReader::IsValid() const
{
return !m_bytes.empty() && m_bytes.size() % sizeof(Ticket) == 0;
}

void TicketReader::DoState(PointerWrap& p)
{
p.Do(m_bytes);
return IsSignatureValid() && !m_bytes.empty() && m_bytes.size() % sizeof(Ticket) == 0;
}

size_t TicketReader::GetNumberOfTickets() const
{
return m_bytes.size() / sizeof(Ticket);
}

const std::vector<u8>& TicketReader::GetRawTicket() const
{
return m_bytes;
}

std::vector<u8> TicketReader::GetRawTicket(u64 ticket_id_to_find) const
{
for (size_t i = 0; i < GetNumberOfTickets(); ++i)
Expand Down Expand Up @@ -304,13 +363,6 @@ std::vector<u8> TicketReader::GetRawTicketView(u32 ticket_num) const
return view;
}

std::string TicketReader::GetIssuer() const
{
const char* bytes =
reinterpret_cast<const char*>(m_bytes.data() + offsetof(Ticket, signature.issuer));
return std::string(bytes, strnlen(bytes, sizeof(Ticket::signature.issuer)));
}

u32 TicketReader::GetDeviceId() const
{
return Common::swap32(m_bytes.data() + offsetof(Ticket, device_id));
Expand Down Expand Up @@ -481,10 +533,12 @@ bool SharedContentMap::WriteEntries() const
File::CreateFullPath(temp_path);

// Atomically write the new content map.
File::IOFile file(temp_path, "w+b");
if (!file.WriteArray(m_entries.data(), m_entries.size()))
return false;
File::CreateFullPath(m_file_path);
{
File::IOFile file(temp_path, "w+b");
if (!file.WriteArray(m_entries.data(), m_entries.size()))
return false;
File::CreateFullPath(m_file_path);
}
return File::RenameSync(temp_path, m_file_path);
}

Expand Down Expand Up @@ -563,5 +617,89 @@ u32 UIDSys::GetOrInsertUIDForTitle(const u64 title_id)

return uid;
}

CertReader::CertReader(std::vector<u8>&& bytes) : SignedBlobReader(std::move(bytes))
{
if (!IsSignatureValid())
return;

switch (GetSignatureType())
{
case SignatureType::RSA4096:
if (m_bytes.size() < sizeof(CertRSA4096))
return;
m_bytes.resize(sizeof(CertRSA4096));
break;

case SignatureType::RSA2048:
if (m_bytes.size() < sizeof(CertRSA2048))
return;
m_bytes.resize(sizeof(CertRSA2048));
break;

default:
return;
}

m_is_valid = true;
}

bool CertReader::IsValid() const
{
return m_is_valid;
}

u32 CertReader::GetId() const
{
const size_t offset = GetSignatureSize() + offsetof(CertHeader, id);
return Common::swap32(m_bytes.data() + offset);
}

std::string CertReader::GetName() const
{
const char* name = reinterpret_cast<const char*>(m_bytes.data() + GetSignatureSize() +
offsetof(CertHeader, name));
return std::string(name, strnlen(name, sizeof(CertHeader::name)));
}

PublicKeyType CertReader::GetPublicKeyType() const
{
const size_t offset = GetSignatureSize() + offsetof(CertHeader, public_key_type);
return static_cast<PublicKeyType>(Common::swap32(m_bytes.data() + offset));
}

std::vector<u8> CertReader::GetPublicKey() const
{
static const std::map<SignatureType, std::pair<size_t, size_t>> type_to_key_info = {{
{SignatureType::RSA4096,
{offsetof(CertRSA4096, public_key),
sizeof(CertRSA4096::public_key) + sizeof(CertRSA4096::exponent)}},
{SignatureType::RSA2048,
{offsetof(CertRSA2048, public_key),
sizeof(CertRSA2048::public_key) + sizeof(CertRSA2048::exponent)}},
}};

const auto info = type_to_key_info.at(GetSignatureType());
const auto key_begin = m_bytes.begin() + info.first;
return std::vector<u8>(key_begin, key_begin + info.second);
}

std::map<std::string, CertReader> ParseCertChain(const std::vector<u8>& chain)
{
std::map<std::string, CertReader> certs;

size_t processed = 0;
while (processed != chain.size())
{
CertReader cert_reader{std::vector<u8>(chain.begin() + processed, chain.end())};
if (!cert_reader.IsValid())
return certs;

processed += cert_reader.GetBytes().size();
const std::string name = cert_reader.GetName();
certs.emplace(std::move(name), std::move(cert_reader));
}
return certs;
}
} // namespace ES
} // namespace IOS

0 comments on commit 9bc1b65

Please sign in to comment.