add gc_menu, add progress, icon, time remaining to progress bar (see full commit message).
- fix ignore distribution bit doing nothing. - fix yati failing to parse control nca causing the transfer to abort. - yati now uses ncm rather than ns to get the latest app version. - improve ui::list input handling (it handles directional buttons now). - progress bar displays speed and time remaining. - added gc menu (taken from my gc installer nx and gci).
This commit is contained in:
@@ -215,4 +215,6 @@ Result DecryptKeak(const keys::Keys& keys, Header& header);
|
||||
Result EncryptKeak(const keys::Keys& keys, Header& header, u8 key_generation);
|
||||
Result VerifyFixedKey(const Header& header);
|
||||
|
||||
auto GetKeyGenStr(u8 key_gen) -> const char*;
|
||||
|
||||
} // namespace sphaira::nca
|
||||
|
||||
@@ -19,7 +19,7 @@ static_assert(sizeof(PackagedContentMeta) == 0x20);
|
||||
|
||||
struct ContentStorageRecord {
|
||||
NcmContentMetaKey key;
|
||||
u8 storage_id;
|
||||
u8 storage_id; // NcmStorageId
|
||||
u8 padding[0x7];
|
||||
};
|
||||
|
||||
@@ -31,7 +31,9 @@ union ExtendedHeader {
|
||||
NcmDataPatchMetaExtendedHeader data_patch;
|
||||
};
|
||||
|
||||
auto GetAppId(u8 meta_type, u64 id) -> u64;
|
||||
auto GetAppId(const NcmContentMetaKey& key) -> u64;
|
||||
auto GetAppId(const PackagedContentMeta& meta) -> u64;
|
||||
|
||||
Result Delete(NcmContentStorage* cs, const NcmContentId *content_id);
|
||||
Result Register(NcmContentStorage* cs, const NcmContentId *content_id, const NcmPlaceHolderId *placeholder_id);
|
||||
|
||||
@@ -1,265 +0,0 @@
|
||||
/*
|
||||
* tik.h
|
||||
*
|
||||
* Copyright (c) 2020-2024, DarkMatterCore <pabloacurielz@gmail.com>.
|
||||
*
|
||||
* This file is part of nxdumptool (https://github.com/DarkMatterCore/nxdumptool).
|
||||
*
|
||||
* nxdumptool is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* nxdumptool is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#ifndef __TIK_H__
|
||||
#define __TIK_H__
|
||||
|
||||
#include "signature.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#define SIGNED_TIK_MIN_SIZE sizeof(TikSigHmac160) /* Assuming no ESV1/ESV2 records are available. */
|
||||
#define SIGNED_TIK_MAX_SIZE 0x400 /* Max ticket entry size in the ES ticket system savedata file. */
|
||||
|
||||
#define TIK_FORMAT_VERSION 2
|
||||
|
||||
#define GENERATE_TIK_STRUCT(sigtype, tiksize) \
|
||||
typedef struct { \
|
||||
SignatureBlock##sigtype sig_block; \
|
||||
TikCommonBlock tik_common_block; \
|
||||
u8 es_section_record_data[]; \
|
||||
} TikSig##sigtype; \
|
||||
NXDT_ASSERT(TikSig##sigtype, tiksize);
|
||||
|
||||
typedef enum {
|
||||
TikTitleKeyType_Common = 0,
|
||||
TikTitleKeyType_Personalized = 1,
|
||||
TikTitleKeyType_Count = 2 ///< Total values supported by this enum.
|
||||
} TikTitleKeyType;
|
||||
|
||||
typedef enum {
|
||||
TikLicenseType_Permanent = 0,
|
||||
TikLicenseType_Demo = 1,
|
||||
TikLicenseType_Trial = 2,
|
||||
TikLicenseType_Rental = 3,
|
||||
TikLicenseType_Subscription = 4,
|
||||
TikLicenseType_Service = 5,
|
||||
TikLicenseType_Count = 6 ///< Total values supported by this enum.
|
||||
} TikLicenseType;
|
||||
|
||||
typedef enum {
|
||||
TikPropertyMask_None = 0,
|
||||
TikPropertyMask_PreInstallation = BIT(0), ///< Determines if the title comes pre-installed on the device. Most likely unused -- a remnant from previous ticket formats.
|
||||
TikPropertyMask_SharedTitle = BIT(1), ///< Determines if the title holds shared contents only. Most likely unused -- a remnant from previous ticket formats.
|
||||
TikPropertyMask_AllContents = BIT(2), ///< Determines if the content index mask shall be bypassed. Most likely unused -- a remnant from previous ticket formats.
|
||||
TikPropertyMask_DeviceLinkIndepedent = BIT(3), ///< Determines if the console should *not* connect to the Internet to verify if the title's being used by the primary console.
|
||||
TikPropertyMask_Volatile = BIT(4), ///< Determines if the ticket copy inside ticket.bin is available after reboot. Can be encrypted.
|
||||
TikPropertyMask_ELicenseRequired = BIT(5), ///< Determines if the console should connect to the Internet to perform license verification.
|
||||
TikPropertyMask_Count = 6 ///< Total values supported by this enum.
|
||||
} TikPropertyMask;
|
||||
|
||||
/// Placed after the ticket signature block.
|
||||
typedef struct {
|
||||
char issuer[0x40];
|
||||
u8 titlekey_block[0x100];
|
||||
u8 format_version; ///< Always matches TIK_FORMAT_VERSION.
|
||||
u8 titlekey_type; ///< TikTitleKeyType.
|
||||
u16 ticket_version;
|
||||
u8 license_type; ///< TikLicenseType.
|
||||
u8 key_generation; ///< NcaKeyGeneration.
|
||||
u16 property_mask; ///< TikPropertyMask.
|
||||
u8 reserved[0x8];
|
||||
u64 ticket_id;
|
||||
u64 device_id;
|
||||
FsRightsId rights_id;
|
||||
u32 account_id;
|
||||
u32 sect_total_size;
|
||||
u32 sect_hdr_offset;
|
||||
u16 sect_hdr_count;
|
||||
u16 sect_hdr_entry_size;
|
||||
} TikCommonBlock;
|
||||
|
||||
NXDT_ASSERT(TikCommonBlock, 0x180);
|
||||
|
||||
/// ESV1/ESV2 section records are placed right after the ticket data. These aren't available in TikTitleKeyType_Common tickets.
|
||||
/// These are only used if the sect_* fields from the common block are non-zero (other than 'sect_hdr_offset').
|
||||
/// Each ESV2 section record is followed by a 'record_count' number of ESV1 records, each one of 'record_size' size.
|
||||
|
||||
typedef enum {
|
||||
TikSectionType_None = 0,
|
||||
TikSectionType_Permanent = 1,
|
||||
TikSectionType_Subscription = 2,
|
||||
TikSectionType_Content = 3,
|
||||
TikSectionType_ContentConsumption = 4,
|
||||
TikSectionType_AccessTitle = 5,
|
||||
TikSectionType_LimitedResource = 6,
|
||||
TikSectionType_Count = 7 ///< Total values supported by this enum.
|
||||
} TikSectionType;
|
||||
|
||||
typedef struct {
|
||||
u32 sect_offset;
|
||||
u32 record_size;
|
||||
u32 section_size;
|
||||
u16 record_count;
|
||||
u16 section_type; ///< TikSectionType.
|
||||
} TikESV2SectionRecord;
|
||||
|
||||
/// Used with TikSectionType_Permanent.
|
||||
typedef struct {
|
||||
u8 ref_id[0x10];
|
||||
u32 ref_id_attr;
|
||||
} TikESV1PermanentRecord;
|
||||
|
||||
/// Used with TikSectionType_Subscription.
|
||||
typedef struct {
|
||||
u32 limit;
|
||||
u8 ref_id[0x10];
|
||||
u32 ref_id_attr;
|
||||
} TikESV1SubscriptionRecord;
|
||||
|
||||
/// Used with TikSectionType_Content.
|
||||
typedef struct {
|
||||
u32 offset;
|
||||
u8 access_mask[0x80];
|
||||
} TikESV1ContentRecord;
|
||||
|
||||
/// Used with TikSectionType_ContentConsumption.
|
||||
typedef struct {
|
||||
u16 index;
|
||||
u16 code;
|
||||
u32 limit;
|
||||
} TikESV1ContentConsumptionRecord;
|
||||
|
||||
/// Used with TikSectionType_AccessTitle.
|
||||
typedef struct {
|
||||
u64 access_title_id;
|
||||
u64 access_title_mask;
|
||||
} TikESV1AccessTitleRecord;
|
||||
|
||||
/// Used with TikSectionType_LimitedResource.
|
||||
typedef struct {
|
||||
u32 limit;
|
||||
u8 ref_id[0x10];
|
||||
u32 ref_id_attr;
|
||||
} TikESV1LimitedResourceRecord;
|
||||
|
||||
/// All tickets generated below use a little endian sig_type field.
|
||||
GENERATE_TIK_STRUCT(Rsa4096, 0x3C0); /// RSA-4096 signature.
|
||||
GENERATE_TIK_STRUCT(Rsa2048, 0x2C0); /// RSA-2048 signature.
|
||||
GENERATE_TIK_STRUCT(Ecc480, 0x200); /// ECC signature.
|
||||
GENERATE_TIK_STRUCT(Hmac160, 0x1C0); /// HMAC signature.
|
||||
|
||||
/// Ticket type.
|
||||
typedef enum {
|
||||
TikType_None = 0,
|
||||
TikType_SigRsa4096 = 1,
|
||||
TikType_SigRsa2048 = 2,
|
||||
TikType_SigEcc480 = 3,
|
||||
TikType_SigHmac160 = 4,
|
||||
TikType_Count = 5 ///< Total values supported by this enum.
|
||||
} TikType;
|
||||
|
||||
/// Used to store ticket type, size and raw data, as well as titlekey data.
|
||||
typedef struct {
|
||||
u8 type; ///< TikType.
|
||||
u64 size; ///< Raw ticket size.
|
||||
u8 data[SIGNED_TIK_MAX_SIZE]; ///< Raw ticket data.
|
||||
u8 key_generation; ///< NcaKeyGeneration.
|
||||
u8 enc_titlekey[0x10]; ///< Titlekey with titlekek crypto (RSA-OAEP unwrapped if dealing with a TikTitleKeyType_Personalized ticket).
|
||||
char enc_titlekey_str[0x21]; ///< Character string representation of enc_titlekey.
|
||||
u8 dec_titlekey[0x10]; ///< Titlekey without titlekek crypto. Ready to use for NCA FS section decryption.
|
||||
char dec_titlekey_str[0x21]; ///< Character string representation of dec_titlekey.
|
||||
char rights_id_str[0x21]; ///< Character string representation of the rights ID from the ticket.
|
||||
} Ticket;
|
||||
|
||||
/// Retrieves a ticket from either the ES ticket system savedata file (eMMC BIS System partition) or the secure Hash FS partition from an inserted gamecard.
|
||||
/// Both the input rights ID and key generation values must have been retrieved from a NCA that depends on the desired ticket.
|
||||
/// Titlekey is also RSA-OAEP unwrapped (if needed) and titlekek-decrypted right away.
|
||||
bool tikRetrieveTicketByRightsId(Ticket *dst, const FsRightsId *id, u8 key_generation, bool use_gamecard);
|
||||
|
||||
/// Converts a TikTitleKeyType_Personalized ticket into a TikTitleKeyType_Common ticket and optionally generates a raw certificate chain for the new signature issuer.
|
||||
/// Bear in mind the 'size' member from the Ticket parameter will be updated by this function to remove any possible references to ESV1/ESV2 records.
|
||||
/// If both 'out_raw_cert_chain' and 'out_raw_cert_chain_size' pointers are provided, raw certificate chain data will be saved to them.
|
||||
/// certGenerateRawCertificateChainBySignatureIssuer() is used internally, so the output buffer must be freed by the user.
|
||||
bool tikConvertPersonalizedTicketToCommonTicket(Ticket *tik, u8 **out_raw_cert_chain, u64 *out_raw_cert_chain_size);
|
||||
|
||||
/// Helper inline functions for signed ticket blobs.
|
||||
|
||||
NX_INLINE TikCommonBlock *tikGetCommonBlockFromSignedTicketBlob(void *buf)
|
||||
{
|
||||
return (TikCommonBlock*)signatureGetPayloadFromSignedBlob(buf, false);
|
||||
}
|
||||
|
||||
NX_INLINE u64 tikGetSectionRecordsSizeFromSignedTicketBlob(void *buf)
|
||||
{
|
||||
TikCommonBlock *tik_common_block = tikGetCommonBlockFromSignedTicketBlob(buf);
|
||||
if (!tik_common_block) return 0;
|
||||
|
||||
u64 offset = sizeof(TikCommonBlock), out_size = 0;
|
||||
|
||||
for(u32 i = 0; i < tik_common_block->sect_hdr_count; i++)
|
||||
{
|
||||
TikESV2SectionRecord *rec = (TikESV2SectionRecord*)((u8*)tik_common_block + offset);
|
||||
offset += (sizeof(TikESV2SectionRecord) + ((u64)rec->record_count * (u64)rec->record_size));
|
||||
out_size += offset;
|
||||
}
|
||||
|
||||
return out_size;
|
||||
}
|
||||
|
||||
NX_INLINE bool tikIsValidSignedTicketBlob(void *buf)
|
||||
{
|
||||
u64 ticket_size = (signatureGetBlockSizeFromSignedBlob(buf, false) + sizeof(TikCommonBlock));
|
||||
return (ticket_size > sizeof(TikCommonBlock) && (ticket_size + tikGetSectionRecordsSizeFromSignedTicketBlob(buf)) <= SIGNED_TIK_MAX_SIZE);
|
||||
}
|
||||
|
||||
NX_INLINE u64 tikGetSignedTicketBlobSize(void *buf)
|
||||
{
|
||||
return (tikIsValidSignedTicketBlob(buf) ? (signatureGetBlockSizeFromSignedBlob(buf, false) + sizeof(TikCommonBlock) + tikGetSectionRecordsSizeFromSignedTicketBlob(buf)) : 0);
|
||||
}
|
||||
|
||||
NX_INLINE u64 tikGetSignedTicketBlobHashAreaSize(void *buf)
|
||||
{
|
||||
return (tikIsValidSignedTicketBlob(buf) ? (sizeof(TikCommonBlock) + tikGetSectionRecordsSizeFromSignedTicketBlob(buf)) : 0);
|
||||
}
|
||||
|
||||
/// Helper inline functions for Ticket elements.
|
||||
|
||||
NX_INLINE bool tikIsValidTicket(Ticket *tik)
|
||||
{
|
||||
return (tik && tik->type > TikType_None && tik->type < TikType_Count && tik->size >= SIGNED_TIK_MIN_SIZE && tik->size <= SIGNED_TIK_MAX_SIZE && tikIsValidSignedTicketBlob(tik->data));
|
||||
}
|
||||
|
||||
NX_INLINE TikCommonBlock *tikGetCommonBlockFromTicket(Ticket *tik)
|
||||
{
|
||||
return (tikIsValidTicket(tik) ? tikGetCommonBlockFromSignedTicketBlob(tik->data) : NULL);
|
||||
}
|
||||
|
||||
NX_INLINE bool tikIsPersonalizedTicket(Ticket *tik)
|
||||
{
|
||||
TikCommonBlock *tik_common_block = tikGetCommonBlockFromTicket(tik);
|
||||
return (tik_common_block ? (tik_common_block->titlekey_type == TikTitleKeyType_Personalized) : false);
|
||||
}
|
||||
|
||||
NX_INLINE u64 tikGetHashAreaSizeFromTicket(Ticket *tik)
|
||||
{
|
||||
return (tikIsValidTicket(tik) ? tikGetSignedTicketBlobHashAreaSize(tik->data) : 0);
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* __TIK_H__ */
|
||||
Reference in New Issue
Block a user