diff --git a/app/CMakeLists.txt b/app/CMakeLists.txt index 541eb51c..d5d41dbe 100644 --- a/app/CMakeLists.txt +++ b/app/CMakeLists.txt @@ -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 diff --git a/app/src/main/cpp/skyline/crypto/key_store.cpp b/app/src/main/cpp/skyline/crypto/key_store.cpp index 71b04929..b69b1c9c 100644 --- a/app/src/main/cpp/skyline/crypto/key_store.cpp +++ b/app/src/main/cpp/skyline/crypto/key_store.cpp @@ -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)}; diff --git a/app/src/main/cpp/skyline/crypto/key_store.h b/app/src/main/cpp/skyline/crypto/key_store.h index cad786fa..635827d6 100644 --- a/app/src/main/cpp/skyline/crypto/key_store.h +++ b/app/src/main/cpp/skyline/crypto/key_store.h @@ -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); }; } diff --git a/app/src/main/cpp/skyline/loader/nsp.cpp b/app/src/main/cpp/skyline/loader/nsp.cpp index 15eef529..60d2e349 100644 --- a/app/src/main/cpp/skyline/loader/nsp.cpp +++ b/app/src/main/cpp/skyline/loader/nsp.cpp @@ -2,13 +2,30 @@ // Copyright © 2020 Skyline Team and Contributors (https://github.com/skyline-emu/) #include +#include #include "nca.h" #include "nsp.h" namespace skyline::loader { - NspLoader::NspLoader(const std::shared_ptr &backing, const std::shared_ptr &keyStore) : nsp(std::make_shared(backing)) { - auto root{nsp->OpenDirectory("", {false, true})}; + static void ExtractTickets(const std::shared_ptr& dir, const std::shared_ptr &keyStore) { + std::vector 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()}; + keyStore->PopulateTitleKey(ticket.rightsId, titleKey); + } + } + + NspLoader::NspLoader(const std::shared_ptr &backing, const std::shared_ptr &keyStore) : nsp(std::make_shared(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; diff --git a/app/src/main/cpp/skyline/vfs/ticket.cpp b/app/src/main/cpp/skyline/vfs/ticket.cpp new file mode 100644 index 00000000..09e3f9d1 --- /dev/null +++ b/app/src/main/cpp/skyline/vfs/ticket.cpp @@ -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 &backing) { + auto type{backing->Read()}; + + 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(offset); + } +} \ No newline at end of file diff --git a/app/src/main/cpp/skyline/vfs/ticket.h b/app/src/main/cpp/skyline/vfs/ticket.h new file mode 100644 index 00000000..7cb22b19 --- /dev/null +++ b/app/src/main/cpp/skyline/vfs/ticket.h @@ -0,0 +1,38 @@ +// SPDX-License-Identifier: MPL-2.0 +// Copyright © 2021 Skyline Team and Contributors (https://github.com/skyline-emu/) + +#pragma once + +#include +#include + +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 issuer; + std::array 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 &backing); + }; + static_assert(sizeof(Ticket) == 0x180); +} \ No newline at end of file