Merge pull request #5646 from Starsam80/cert-import-fixes
NANDImporter: Improve certificate extraction
This commit is contained in:
commit
f65fe3efbd
|
@ -4,6 +4,7 @@
|
||||||
|
|
||||||
#include "DiscIO/NANDImporter.h"
|
#include "DiscIO/NANDImporter.h"
|
||||||
|
|
||||||
|
#include <algorithm>
|
||||||
#include <array>
|
#include <array>
|
||||||
#include <cinttypes>
|
#include <cinttypes>
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
|
@ -15,6 +16,7 @@
|
||||||
#include "Common/MsgHandler.h"
|
#include "Common/MsgHandler.h"
|
||||||
#include "Common/StringUtil.h"
|
#include "Common/StringUtil.h"
|
||||||
#include "Common/Swap.h"
|
#include "Common/Swap.h"
|
||||||
|
#include "Core/IOS/ES/Formats.h"
|
||||||
#include "DiscIO/NANDContentLoader.h"
|
#include "DiscIO/NANDContentLoader.h"
|
||||||
|
|
||||||
namespace DiscIO
|
namespace DiscIO
|
||||||
|
@ -188,40 +190,73 @@ void NANDImporter::ProcessFile(const NANDFSTEntry& entry, const std::string& par
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void NANDImporter::ExtractCertificates(const std::string& nand_root)
|
bool NANDImporter::ExtractCertificates(const std::string& nand_root)
|
||||||
{
|
{
|
||||||
const std::string title_contents_path =
|
const std::string content_dir = nand_root + "/title/00000001/0000000d/content/";
|
||||||
nand_root + "/title/00000001/0000000d/content/00000011.app";
|
|
||||||
File::IOFile file(title_contents_path, "rb");
|
File::IOFile tmd_file(content_dir + "title.tmd", "rb");
|
||||||
if (!file)
|
std::vector<u8> tmd_bytes(tmd_file.GetSize());
|
||||||
|
if (!tmd_file.ReadBytes(tmd_bytes.data(), tmd_bytes.size()))
|
||||||
{
|
{
|
||||||
PanicAlertT("Unable to open %s! Refer to "
|
ERROR_LOG(DISCIO, "ExtractCertificates: Could not read IOS13 TMD");
|
||||||
"https://dolphin-emu.org/docs/guides/wii-network-guide/ to set up "
|
return false;
|
||||||
"certificates.",
|
|
||||||
title_contents_path.c_str());
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
struct Certificate
|
IOS::ES::TMDReader tmd(std::move(tmd_bytes));
|
||||||
|
IOS::ES::Content content_metadata;
|
||||||
|
if (!tmd.GetContent(tmd.GetBootIndex(), &content_metadata))
|
||||||
|
{
|
||||||
|
ERROR_LOG(DISCIO, "ExtractCertificates: Could not get content ID from TMD");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
File::IOFile content_file(content_dir + StringFromFormat("%08x.app", content_metadata.id), "rb");
|
||||||
|
std::vector<u8> content_bytes(content_file.GetSize());
|
||||||
|
if (!content_file.ReadBytes(content_bytes.data(), content_bytes.size()))
|
||||||
|
{
|
||||||
|
ERROR_LOG(DISCIO, "ExtractCertificates: Could not read IOS13 contents");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct PEMCertificate
|
||||||
{
|
{
|
||||||
u32 offset;
|
|
||||||
u32 size;
|
|
||||||
std::string filename;
|
std::string filename;
|
||||||
|
std::array<u8, 4> search_bytes;
|
||||||
};
|
};
|
||||||
std::array<Certificate, 3> certificates = {{{0x92834, 1005, "/clientca.pem"},
|
|
||||||
{0x92d38, 609, "/clientcakey.pem"},
|
|
||||||
{0x92440, 897, "/rootca.pem"}}};
|
|
||||||
for (const Certificate& cert : certificates)
|
|
||||||
{
|
|
||||||
file.Seek(cert.offset, SEEK_SET);
|
|
||||||
std::vector<u8> pem_cert(cert.size);
|
|
||||||
file.ReadBytes(pem_cert.data(), pem_cert.size());
|
|
||||||
|
|
||||||
const std::string pem_file_path = nand_root + cert.filename;
|
std::array<PEMCertificate, 3> certificates = {{
|
||||||
|
{"/clientca.pem", {{0x30, 0x82, 0x03, 0xE9}}},
|
||||||
|
{"/clientcakey.pem", {{0x30, 0x82, 0x02, 0x5D}}},
|
||||||
|
{"/rootca.pem", {{0x30, 0x82, 0x03, 0x7D}}},
|
||||||
|
}};
|
||||||
|
|
||||||
|
for (const PEMCertificate& certificate : certificates)
|
||||||
|
{
|
||||||
|
const auto search_result =
|
||||||
|
std::search(content_bytes.begin(), content_bytes.end(), certificate.search_bytes.begin(),
|
||||||
|
certificate.search_bytes.end());
|
||||||
|
|
||||||
|
if (search_result == content_bytes.end())
|
||||||
|
{
|
||||||
|
ERROR_LOG(DISCIO, "ExtractCertificates: Could not find offset for certficate '%s'",
|
||||||
|
certificate.filename.c_str());
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
const std::string pem_file_path = nand_root + certificate.filename;
|
||||||
|
const ptrdiff_t certificate_offset = std::distance(content_bytes.begin(), search_result);
|
||||||
|
const u16 certificate_size = Common::swap16(&content_bytes[certificate_offset - 2]);
|
||||||
|
INFO_LOG(DISCIO, "ExtractCertificates: '%s' offset: 0x%tx size: 0x%x",
|
||||||
|
certificate.filename.c_str(), certificate_offset, certificate_size);
|
||||||
|
|
||||||
File::IOFile pem_file(pem_file_path, "wb");
|
File::IOFile pem_file(pem_file_path, "wb");
|
||||||
if (!pem_file.WriteBytes(pem_cert.data(), pem_cert.size()))
|
if (!pem_file.WriteBytes(&content_bytes[certificate_offset], certificate_size))
|
||||||
PanicAlertT("Unable to write to file %s", pem_file_path.c_str());
|
{
|
||||||
|
ERROR_LOG(DISCIO, "ExtractCertificates: Unable to write to file %s", pem_file_path.c_str());
|
||||||
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void NANDImporter::ExportKeys(const std::string& nand_root)
|
void NANDImporter::ExportKeys(const std::string& nand_root)
|
||||||
|
|
|
@ -19,7 +19,7 @@ public:
|
||||||
~NANDImporter();
|
~NANDImporter();
|
||||||
|
|
||||||
void ImportNANDBin(const std::string& path_to_bin, std::function<void()> update_callback);
|
void ImportNANDBin(const std::string& path_to_bin, std::function<void()> update_callback);
|
||||||
void ExtractCertificates(const std::string& nand_root);
|
bool ExtractCertificates(const std::string& nand_root);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
#pragma pack(push, 1)
|
#pragma pack(push, 1)
|
||||||
|
|
Loading…
Reference in New Issue