Move the ticket code to ESFormats

This moves some parsing code for tickets and ticket views to ESFormats
instead of duplicating it over DiscIO and Core.
This commit is contained in:
Léo Lam
2017-02-09 14:07:36 +01:00
parent a62711de55
commit bf1f70db0a
12 changed files with 254 additions and 230 deletions

View File

@ -9,7 +9,6 @@
#include <cstring>
#include <functional>
#include <map>
#include <mbedtls/aes.h>
#include <string>
#include <utility>
#include <vector>
@ -29,50 +28,6 @@
namespace DiscIO
{
namespace
{
// Strips the signature part of a ticket, which has variable size based on
// signature type. Returns a new vector which has only the ticket structure
// itself.
std::vector<u8> SignedTicketToTicket(const std::vector<u8>& signed_ticket)
{
u32 signature_type = Common::swap32(signed_ticket.data());
u32 entry_offset;
if (signature_type == 0x10000) // RSA4096
{
entry_offset = 576;
}
else if (signature_type == 0x10001) // RSA2048
{
entry_offset = 320;
}
else if (signature_type == 0x10002) // ECDSA
{
entry_offset = 128;
}
else
{
ERROR_LOG(DISCIO, "Invalid ticket signature type: %08x", signature_type);
return std::vector<u8>();
}
std::vector<u8> ticket(signed_ticket.size() - entry_offset);
std::copy(signed_ticket.begin() + entry_offset, signed_ticket.end(), ticket.begin());
return ticket;
}
std::vector<u8> AESDecode(const u8* key, u8* iv, const u8* src, u32 size)
{
mbedtls_aes_context aes_ctx;
std::vector<u8> buffer(size);
mbedtls_aes_setkey_dec(&aes_ctx, key, 128);
mbedtls_aes_crypt_cbc(&aes_ctx, MBEDTLS_AES_DECRYPT, size, iv, src, buffer.data());
return buffer;
}
}
CNANDContentData::~CNANDContentData() = default;
CSharedContent::CSharedContent(Common::FromWhichRoot root) : m_root(root)
@ -222,13 +177,11 @@ bool CNANDContentLoader::Initialize(const std::string& name)
WiiWAD wad(name);
std::vector<u8> data_app;
std::vector<u8> tmd;
std::vector<u8> decrypted_title_key;
if (wad.IsValid())
{
m_IsWAD = true;
m_Ticket = wad.GetTicket();
decrypted_title_key = GetKeyFromTicket(m_Ticket);
m_ticket = wad.GetTicket();
tmd = wad.GetTMD();
data_app = wad.GetDataApp();
}
@ -265,12 +218,14 @@ bool CNANDContentLoader::Initialize(const std::string& name)
if (m_Country == 2) // SYSMENU
m_Country = GetSysMenuRegion(m_TitleVersion);
InitializeContentEntries(tmd, decrypted_title_key, data_app);
if (!m_IsWAD)
m_ticket = FindSignedTicket(m_TitleID);
InitializeContentEntries(tmd, data_app);
return true;
}
void CNANDContentLoader::InitializeContentEntries(const std::vector<u8>& tmd,
const std::vector<u8>& decrypted_title_key,
const std::vector<u8>& data_app)
{
m_Content.resize(m_NumEntries);
@ -305,8 +260,8 @@ void CNANDContentLoader::InitializeContentEntries(const std::vector<u8>& tmd,
iv.fill(0);
std::copy(&tmd[entry_offset + 0x01E8], &tmd[entry_offset + 0x01E8 + 2], iv.begin());
content.m_Data = std::make_unique<CNANDContentDataBuffer>(AESDecode(
decrypted_title_key.data(), iv.data(), &data_app[data_app_offset], rounded_size));
content.m_Data = std::make_unique<CNANDContentDataBuffer>(ES::AESDecode(
m_ticket.GetTitleKey().data(), iv.data(), &data_app[data_app_offset], rounded_size));
data_app_offset += rounded_size;
continue;
@ -533,14 +488,14 @@ u64 CNANDContentManager::Install_WiiWAD(const std::string& filename)
return title_id;
}
bool AddTicket(const std::vector<u8>& signed_ticket)
bool AddTicket(const ES::TicketReader& signed_ticket)
{
std::vector<u8> ticket = SignedTicketToTicket(signed_ticket);
if (ticket.empty())
if (!signed_ticket.IsValid())
{
return false;
}
u64 title_id = Common::swap64(ticket.data() + 0x9c);
u64 title_id = signed_ticket.GetTitleId();
std::string ticket_filename = Common::GetTicketFileName(title_id, Common::FROM_CONFIGURED_ROOT);
File::CreateFullPath(ticket_filename);
@ -549,46 +504,25 @@ bool AddTicket(const std::vector<u8>& signed_ticket)
if (!ticket_file)
return false;
return ticket_file.WriteBytes(signed_ticket.data(), signed_ticket.size());
const std::vector<u8>& raw_ticket = signed_ticket.GetRawTicket();
return ticket_file.WriteBytes(raw_ticket.data(), raw_ticket.size());
}
std::vector<u8> FindSignedTicket(u64 title_id)
ES::TicketReader FindSignedTicket(u64 title_id)
{
std::string ticket_filename = Common::GetTicketFileName(title_id, Common::FROM_CONFIGURED_ROOT);
File::IOFile ticket_file(ticket_filename, "rb");
if (!ticket_file)
{
return std::vector<u8>();
return ES::TicketReader{};
}
std::vector<u8> signed_ticket(ticket_file.GetSize());
if (!ticket_file.ReadBytes(signed_ticket.data(), signed_ticket.size()))
{
return std::vector<u8>();
return ES::TicketReader{};
}
return signed_ticket;
return ES::TicketReader{std::move(signed_ticket)};
}
std::vector<u8> FindTicket(u64 title_id)
{
std::vector<u8> signed_ticket = FindSignedTicket(title_id);
if (signed_ticket.empty())
{
return std::vector<u8>();
}
return SignedTicketToTicket(signed_ticket);
}
std::vector<u8> GetKeyFromTicket(const std::vector<u8>& signed_ticket)
{
const u8 common_key[16] = {0xeb, 0xe4, 0x2a, 0x22, 0x5e, 0x85, 0x93, 0xe4,
0x48, 0xd9, 0xc5, 0x45, 0x73, 0x81, 0xaa, 0xf7};
u8 iv[16] = {};
std::copy(&signed_ticket[0x01DC], &signed_ticket[0x01DC + 8], iv);
return AESDecode(common_key, iv, &signed_ticket[0x01BF], 16);
}
} // namespace end

View File

@ -12,6 +12,7 @@
#include "Common/CommonTypes.h"
#include "Common/NandPaths.h"
#include "Core/IOS/ES/Formats.h"
namespace File
{
@ -22,10 +23,8 @@ namespace DiscIO
{
enum class Region;
bool AddTicket(const std::vector<u8>& signed_ticket);
std::vector<u8> FindSignedTicket(u64 title_id);
std::vector<u8> FindTicket(u64 title_id);
std::vector<u8> GetKeyFromTicket(const std::vector<u8>& ticket);
bool AddTicket(const ES::TicketReader& signed_ticket);
ES::TicketReader FindSignedTicket(u64 title_id);
class CNANDContentData
{
@ -93,7 +92,7 @@ public:
const SNANDContent* GetContentByIndex(int index) const;
const u8* GetTMDView() const { return m_TMDView; }
const u8* GetTMDHeader() const { return m_TMDHeader; }
const std::vector<u8>& GetTicket() const { return m_Ticket; }
const ES::TicketReader& GetTicket() const { return m_ticket; }
const std::vector<SNANDContent>& GetContent() const { return m_Content; }
u16 GetTitleVersion() const { return m_TitleVersion; }
u16 GetNumEntries() const { return m_NumEntries; }
@ -104,14 +103,11 @@ public:
TMD_VIEW_SIZE = 0x58,
TMD_HEADER_SIZE = 0x1E4,
CONTENT_HEADER_SIZE = 0x24,
TICKET_SIZE = 0x2A4
};
private:
bool Initialize(const std::string& name);
void InitializeContentEntries(const std::vector<u8>& tmd,
const std::vector<u8>& decrypted_title_key,
const std::vector<u8>& data_app);
void InitializeContentEntries(const std::vector<u8>& tmd, const std::vector<u8>& data_app);
bool m_Valid;
bool m_IsWAD;
@ -123,7 +119,7 @@ private:
u16 m_TitleVersion;
u8 m_TMDView[TMD_VIEW_SIZE];
u8 m_TMDHeader[TMD_HEADER_SIZE];
std::vector<u8> m_Ticket;
ES::TicketReader m_ticket;
u8 m_Country;
std::vector<SNANDContent> m_Content;

View File

@ -88,7 +88,7 @@ bool WiiWAD::ParseWAD(IBlobReader& reader)
u32 offset = 0x40;
m_certificate_chain = CreateWADEntry(reader, certificate_chain_size, offset);
offset += Common::AlignUp(certificate_chain_size, 0x40);
m_ticket = CreateWADEntry(reader, ticket_size, offset);
m_ticket.SetBytes(CreateWADEntry(reader, ticket_size, offset));
offset += Common::AlignUp(ticket_size, 0x40);
m_tmd = CreateWADEntry(reader, tmd_size, offset);
offset += Common::AlignUp(tmd_size, 0x40);

View File

@ -8,6 +8,7 @@
#include <vector>
#include "Common/CommonTypes.h"
#include "Core/IOS/ES/Formats.h"
namespace DiscIO
{
@ -22,7 +23,7 @@ public:
bool IsValid() const { return m_valid; }
const std::vector<u8>& GetCertificateChain() const { return m_certificate_chain; }
const std::vector<u8>& GetTicket() const { return m_ticket; }
const ES::TicketReader& GetTicket() const { return m_ticket; }
const std::vector<u8>& GetTMD() const { return m_tmd; }
const std::vector<u8>& GetDataApp() const { return m_data_app; }
const std::vector<u8>& GetFooter() const { return m_footer; }
@ -32,7 +33,7 @@ private:
bool m_valid;
std::vector<u8> m_certificate_chain;
std::vector<u8> m_ticket;
ES::TicketReader m_ticket;
std::vector<u8> m_tmd;
std::vector<u8> m_data_app;
std::vector<u8> m_footer;