Add NSP ticket extraction support

This commit is contained in:
sspacelynx 2021-02-23 12:33:42 +01:00 committed by ◱ Mark
parent 77d8d1bee1
commit 75b769ca1d
6 changed files with 110 additions and 2 deletions

View File

@ -82,6 +82,7 @@ add_library(skyline SHARED
${source_DIR}/skyline/vfs/nacp.cpp
${source_DIR}/skyline/vfs/npdm.cpp
${source_DIR}/skyline/vfs/nca.cpp
${source_DIR}/skyline/vfs/ticket.cpp
${source_DIR}/skyline/services/serviceman.cpp
${source_DIR}/skyline/services/base_service.cpp
${source_DIR}/skyline/services/common/parcel.cpp

View File

@ -38,6 +38,11 @@ namespace skyline::crypto {
titleKeys.emplace(key, valueArray);
}
void KeyStore::PopulateTitleKey(Key128 keyName, Key128 value) {
if (!titleKeys.contains(keyName))
titleKeys.emplace(keyName, value);
}
void KeyStore::PopulateKeys(std::string_view keyName, std::string_view value) {
{
auto it{key256Names.find(keyName)};

View File

@ -53,5 +53,10 @@ namespace skyline::crypto {
return std::nullopt;
return it->second;
}
/**
* @note Any title keys which are already in the store will not have their values updated
*/
void PopulateTitleKey(Key128 keyName, Key128 value);
};
}

View File

@ -2,13 +2,30 @@
// Copyright © 2020 Skyline Team and Contributors (https://github.com/skyline-emu/)
#include <kernel/types/KProcess.h>
#include <vfs/ticket.h>
#include "nca.h"
#include "nsp.h"
namespace skyline::loader {
NspLoader::NspLoader(const std::shared_ptr<vfs::Backing> &backing, const std::shared_ptr<crypto::KeyStore> &keyStore) : nsp(std::make_shared<vfs::PartitionFileSystem>(backing)) {
auto root{nsp->OpenDirectory("", {false, true})};
static void ExtractTickets(const std::shared_ptr<vfs::PartitionFileSystem>& dir, const std::shared_ptr<crypto::KeyStore> &keyStore) {
std::vector<vfs::Ticket> tickets;
auto dirContent{dir->OpenDirectory("", {false, true})};
for (const auto &entry : dirContent->Read()) {
if (entry.name.substr(entry.name.find_last_of('.') + 1) == "tik")
tickets.emplace_back(dir->OpenFile(entry.name));
}
for (auto ticket : tickets) {
auto titleKey{span(ticket.titleKeyBlock).subspan(0, 16).as<crypto::KeyStore::Key128>()};
keyStore->PopulateTitleKey(ticket.rightsId, titleKey);
}
}
NspLoader::NspLoader(const std::shared_ptr<vfs::Backing> &backing, const std::shared_ptr<crypto::KeyStore> &keyStore) : nsp(std::make_shared<vfs::PartitionFileSystem>(backing)) {
ExtractTickets(nsp, keyStore);
auto root{nsp->OpenDirectory("", {false, true})};
for (const auto &entry : root->Read()) {
if (entry.name.substr(entry.name.find_last_of('.') + 1) != "nca")
continue;

View File

@ -0,0 +1,42 @@
// SPDX-License-Identifier: MPL-2.0
// Copyright © 2021 Skyline Team and Contributors (https://github.com/skyline-emu/)
#include "ticket.h"
namespace skyline::vfs {
/**
* @url https://switchbrew.org/wiki/Ticket#Signature_type
*/
enum class SignatureType : u32 {
Rsa4096Sha1 = 0x010000,
Rsa2048Sha1 = 0x010001,
EcdsaSha1 = 0x010002,
Rsa4096Sha256 = 0x010003,
Rsa2048Sha256 = 0x010004,
EcdsaSha256 = 0x010005,
};
Ticket::Ticket(const std::shared_ptr<vfs::Backing> &backing) {
auto type{backing->Read<SignatureType>()};
size_t offset;
switch (type) {
case SignatureType::Rsa4096Sha1:
case SignatureType::Rsa4096Sha256:
offset = 0x240;
break;
case SignatureType::Rsa2048Sha1:
case SignatureType::Rsa2048Sha256:
offset = 0x140;
break;
case SignatureType::EcdsaSha1:
case SignatureType::EcdsaSha256:
offset = 0x80;
break;
default:
throw exception("Could not find valid signature type 0x{:X}", type);
}
*this = backing->Read<Ticket>(offset);
}
}

View File

@ -0,0 +1,38 @@
// SPDX-License-Identifier: MPL-2.0
// Copyright © 2021 Skyline Team and Contributors (https://github.com/skyline-emu/)
#pragma once
#include <vfs/backing.h>
#include <crypto/key_store.h>
namespace skyline::vfs {
/**
* @brief The Ticket struct allows easy access to ticket files, a format used to store an encrypted title keys
* @url https://switchbrew.org/wiki/Ticket
*/
struct Ticket {
enum class TitleKeyType : u8 {
Common = 0x0, //!< The title key is stored as a 16-byte block
Personal = 0x1, //!< The title key is stored as a personalized RSA-2048 message
};
std::array<u8, 0x40> issuer;
std::array<u8, 0x100> titleKeyBlock;
u8 _pad0_[0x1];
TitleKeyType titleKeyType;
u8 _pad1_[0x3];
u8 masterKeyRevision;
u8 _pad2_[0xA];
u64 ticketId;
u64 deviceId;
crypto::KeyStore::Key128 rightsId;
u32 accountId;
u8 _pad3_[0xC];
Ticket() = default;
Ticket(const std::shared_ptr<vfs::Backing> &backing);
};
static_assert(sizeof(Ticket) == 0x180);
}