Put everything back.

This commit is contained in:
jakcron
2022-04-16 21:27:49 +08:00
parent 5d62e839e7
commit bc04de6d09
844 changed files with 114383 additions and 29 deletions
@@ -0,0 +1,7 @@
#pragma once
// definitions
#include <brd/es/es_sign.h>
#include <brd/es/es_cert.h>
#include <brd/es/es_ticket.h>
#include <brd/es/es_tmd.h>
@@ -0,0 +1,101 @@
#pragma once
#include <brd/es/es_sign.h>
namespace brd { namespace es {
/**
@enum ESCertPubKeyType
@brief ES Certificate public key type definition
*/
enum class ESCertPubKeyType : uint32_t
{
RSA4096 = 0, /* RSA 4096 bit key */
RSA2048 = 1, /* RSA 2048 bit key */
ECC = 2, /* ECC pub key 512 bits */
};
static const size_t ES_CERT_NAME_SIZE = 64;
using ESCertName = tc::bn::string<ES_CERT_NAME_SIZE>;
using ESServerId = ESCertName;
using ESDeviceId = ESCertName;
template <size_t _size>
using ESPubKeyPad = std::array<byte_t, _size>;
/* pack to 4 byte boundaries */
#pragma pack(push,4)
struct ESCertHeader
{
tc::bn::be32<ESCertPubKeyType> pubKeyType; // ESCertPubKeyType
union {
ESServerId serverId;
ESDeviceId deviceId;
} name;
tc::bn::be32<uint32_t> date; // unix time-stamp
};
static_assert(sizeof(ESCertHeader) == 72, "ESCertHeader size");
struct ESCertRsa2048PublicKey
{
Rsa2048PublicKey pubKey;
ESPubKeyPad<52> pad;
};
static_assert(sizeof(ESCertRsa2048PublicKey) == 312, "ESCertRsa2048PublicKey size");
struct ESCertRsa4096PublicKey
{
Rsa4096PublicKey pubKey;
ESPubKeyPad<52> pad;
};
static_assert(sizeof(ESCertRsa4096PublicKey) == 568, "ESCertRsa4096PublicKey size");
struct ESCertEcc233PublicKey
{
Ecc233PublicKey pubKey;
ESPubKeyPad<60> pad;
};
static_assert(sizeof(ESCertEcc233PublicKey) == 120, "ESCertEcc233PublicKey size");
struct ESRootCert
{
ESSigRsa4096 sig;
ESCertHeader head;
ESCertRsa4096PublicKey body;
};
static_assert(sizeof(ESRootCert) == 1280, "ESRootCert size");
struct ESCACert
{
ESSigRsa4096 sig;
ESCertHeader head;
ESCertRsa2048PublicKey body;
};
static_assert(sizeof(ESCACert) == 1024, "ESCACert size");
struct ESCASignedCert
{
ESSigRsa2048 sig;
ESCertHeader head;
ESCertRsa2048PublicKey body;
};
static_assert(sizeof(ESCASignedCert) == 768, "ESCASignedCert size");
struct ESDeviceCert
{
ESSigRsa2048 sig;
ESCertHeader head;
ESCertEcc233PublicKey body;
};
static_assert(sizeof(ESDeviceCert) == 576, "ESDeviceCert size");
struct ESDeviceSignedCert
{
ESSigEcc233 sig;
ESCertHeader head;
ESCertEcc233PublicKey body;
};
static_assert(sizeof(ESDeviceSignedCert) == 384, "ESDeviceSignedCert size");
#pragma pack(pop)
}} // namespace brd::es
@@ -0,0 +1,73 @@
#pragma once
#include <brd/es/types.h>
namespace brd { namespace es {
/**
@enum ESSigType
@brief ES Signature type definition
*/
enum class ESSigType : uint32_t
{
RSA4096_SHA1 = 0x00010000, /* RSA 4096 bit signature */
RSA2048_SHA1 = 0x00010001, /* RSA 2048 bit signature */
ECC_SHA1 = 0x00010002, /* ECC signature 512 bits */
RSA4096_SHA256 = 0x00010003, /* RSA 4096 bit sig using SHA-256 */
RSA2048_SHA256 = 0x00010004, /* RSA 2048 bit sig using SHA-256 */ // note that Switch Ticket has this word swapped
ECC_SHA256 = 0x00010005, /* ECC sig 512 bits using SHA-256 */
HMAC_SHA1 = 0x00010006, /* HMAC-SHA1 160 bit signature */
};
static const size_t ES_ISSUER_SIZE = 64;
/**
* @class ESIssuer
* @brief The signature issuer ASCII encoded certificate hierarchy. Padded with nulls.
*
* Examples:
* Root (issued by Root)
* Root-CAxxxxxxxx (issued by Certifcate Authority server xxxxxxxx)
* Root-CAxxxxxxxx-XSxxxxxxxx (issued by Ticket/Transaction server xxxxxxxx)
* Root-CAxxxxxxxx-CPxxxxxxxx (issued by Content Publishing server xxxxxxxx)
* Root-CAxxxxxxxx-MSxxxxxxxx (issued by Manufacturing server xxxxxxxx)
* Root-CAxxxxxxxx-MSxxxxxxxx-YYxxxxxxxx (issued by Device with of type YY and serial number xxxxxxxx)
*
* xxxxxxxx represents the server/device serial number encoded in hex. (e.g. XS0000000f is ticket server 15).
*/
using ESIssuer = tc::bn::string<ES_ISSUER_SIZE>;
template <size_t _size>
using ESSigPad = tc::bn::pad<_size>;
/* pack to 4 byte boundaries */
#pragma pack(push,4)
struct ESSigRsa2048
{
tc::bn::be32<ESSigType> sigType;
Rsa2048Sig sig;
ESSigPad<60> pad;
ESIssuer issuer;
};
static_assert(sizeof(ESSigRsa2048) == 384, "ESSigRsa2048 size");
struct ESSigRsa4096
{
tc::bn::be32<ESSigType> sigType;
Rsa4096Sig sig;
ESSigPad<60> pad;
ESIssuer issuer;
};
static_assert(sizeof(ESSigRsa4096) == 640, "ESSigRsa4096 size");
struct ESSigEcc233
{
tc::bn::be32<ESSigType> sigType;
Ecc233Sig sig;
ESSigPad<64> pad;
ESIssuer issuer;
};
static_assert(sizeof(ESSigEcc233) == 192, "ESSigEcc233 size");
#pragma pack(pop)
}} // namespace brd::es
@@ -0,0 +1,232 @@
#pragma once
#include <brd/es/es_sign.h>
namespace brd { namespace es {
// ES license types
enum class ESLicenseType : uint8_t
{
PERMANENT = 0,
DEMO = 1,
TRIAL = 2,
RENTAL = 3,
SUBSCRIPTION = 4,
SERVICE = 5,
};
static const uint8_t ES_LICENSE_MASK = 0xf;
// ES title-level limit codes
enum class ESLimitCode : uint32_t
{
DURATION_TIME = 1,
ABSOLUTE_TIME = 2,
NUM_TITLES = 3,
NUM_LAUNCH = 4,
ELAPSED_TIME = 5,
};
static const uint32_t ES_MAX_LIMIT_TYPE = 8;
// ES item-level rights
enum class ESItemType : uint32_t
{
PERMANENT = 1,
SUBSCRIPTION = 2,
CONTENT = 3,
CONTENT_CONSUMPTION = 4,
ACCESS_TITLE = 5,
LIMITED_RESOURCE = 6,
};
enum class ESPropertyMaskFlag : uint16_t
{
PRE_INSTALL = 0x1, // bit0
SHARED_TITLE = 0x2, // bit1
ALLOW_ALL_CONTENT = 0x4, // bit2
DEVICE_LINK_INDEPENDENT = 0x8, // bit3
VOLATILE = 0x10, // bit4
ELICENSE_REQUIRED = 0x20, // bit5
};
enum class ESV1SectionHeaderFlag : uint16_t
{
COMPRESSED = 0x1 // ironically this is defined but not supported, probably for future use
};
enum class ESV2TitleKekType : byte_t
{
AES128_CBC,
RSA2048
};
#pragma pack(push, 4)
#ifdef _WIN32
#pragma warning(disable : 4200) // silence warnings for usage of empty arrays in stucts
#endif
struct ESLimitedPlayEntry
{
tc::bn::be32<uint32_t> code; //ESLimitCode
tc::bn::be32<uint32_t> limit;
};
static_assert(sizeof(ESLimitedPlayEntry) == 8, "ESLimitedPlayEntry size");
using ESSysAccessMask = std::array<byte_t, 2>;
using ESTicketCustomData = std::array<byte_t, 20>;
using ESTicketReserved = std::array<byte_t, 25>;
using ESCidxMask = std::array<byte_t, 64>;
using ESLimitedPlayArray = std::array<ESLimitedPlayEntry, 8>;
using ESReferenceId = std::array<byte_t, 16>;
using ESV1CidxMask = std::array<byte_t, 128>;
using ESV2TitleKey = std::array<byte_t, kRsa2048Size>;
using ESRightsId = std::array<byte_t, 16>;
using ESV2TicketReserved = std::array<byte_t, 8>;
struct ESTicket
{
ESSigRsa2048 sig; // RSA 2048-bit sign of the ticket
Ecc233PublicKey serverPubKey; // Ticketing server public key
uint8_t version; // Ticket data structure version number
uint8_t caCrlVersion; // CA CRL version number
uint8_t signerCrlVersion; // Signer CRL version number
Aes128Key titleKey; // Published title key
/* 1 byte alignment padding */
tc::bn::be64<uint64_t> ticketId; // Unique 64bit ticket ID
tc::bn::be32<uint32_t> deviceId; // Unique 32bit device ID
tc::bn::be64<uint64_t> titleId; // Unique 64bit title ID
ESSysAccessMask sysAccessMask; // 16-bit cidx mask to indicate which
// of the first 16 pieces of contents
// can be accessed by the system app
tc::bn::be16<uint16_t> ticketVersion; // 16-bit ticket version
tc::bn::be32<uint32_t> accessTitleId; // 32-bit title ID for access control
tc::bn::be32<uint32_t> accessTitleMask; // 32-bit title ID mask
uint8_t licenseType; //
uint8_t keyId; // Common key ID
tc::bn::be16<uint16_t> propertyMask; // 16-bit property mask
ESTicketCustomData customData; // 20-byte custom data
ESTicketReserved reserved; // 25-byte reserved info
uint8_t audit; //
ESCidxMask cidxMask; // Bit-mask of the content indices
/* 2 bytes alignment padding */
ESLimitedPlayArray limits; // Limited play entries
};
static_assert(sizeof(ESTicket) == 676, "ESTicket size");
struct ESV1TicketHeader
{
tc::bn::be16<uint16_t> hdrVersion; // Version of the ticket header
tc::bn::be16<uint16_t> hdrSize; // Size of ticket header
tc::bn::be32<uint32_t> ticketSize; // Size of the v1 portion of the ticket
tc::bn::be32<uint32_t> sectHdrOfst; // Offset of the section header table
tc::bn::be16<uint16_t> nSectHdrs; // Number of section headers
tc::bn::be16<uint16_t> sectHdrEntrySize; // Size of each section header
tc::bn::be32<uint32_t> flags; // Miscellaneous attributes
};
static_assert(sizeof(ESV1TicketHeader) == 20, "ESV1TicketHeader size");
struct ESV1SectionHeader
{
tc::bn::be32<uint32_t> sectOfst; // Offset of this section
tc::bn::be32<uint32_t> nRecords; // Number of records in this section
tc::bn::be32<uint32_t> recordSize; // Size of each record
tc::bn::be32<uint32_t> sectionSize; // Total size of this section
tc::bn::be16<uint16_t> sectionType; // Type code of this section
tc::bn::be16<uint16_t> flags; // Miscellaneous attributes
};
static_assert(sizeof(ESV1SectionHeader) == 20, "ESV1SectionHeader size");
struct ESV1Ticket
{
ESTicket head;
ESV1TicketHeader v1Head;
ESV1SectionHeader sectHdrs[];
};
static_assert(sizeof(ESV1Ticket) == 696, "ESV1Ticket size");
struct ESV1PermanentRecord
{
ESReferenceId referenceId; // Reference ID
tc::bn::be32<uint32_t> referenceIdAttr; // Reference ID attributes
};
static_assert(sizeof(ESV1PermanentRecord) == 20, "ESV1PermanentRecord size");
struct ESV1SubscriptionRecord
{
tc::bn::be32<uint32_t> limit; // Expiration time
ESReferenceId referenceId; // Reference ID
tc::bn::be32<uint32_t> referenceIdAttr; // Reference ID attributes
};
static_assert(sizeof(ESV1SubscriptionRecord) == 24, "ESV1SubscriptionRecord size");
struct ESV1ContentRecord
{
tc::bn::be32<uint32_t> offset; // Offset content index
ESV1CidxMask accessMask; // Access mask
};
static_assert(sizeof(ESV1ContentRecord) == 132, "ESV1ContentRecord size");
struct ESV1ContentConsumptionRecord
{
tc::bn::be16<uint16_t> index; // Content index
tc::bn::be16<uint16_t> code; // Limit code
tc::bn::be32<uint32_t> limit; // Limit value
};
static_assert(sizeof(ESV1ContentConsumptionRecord) == 8, "ESV1ContentConsumptionRecord size");
struct ESV1AccessTitleRecord
{
tc::bn::be64<uint64_t> accessTitleId; // Access title ID
tc::bn::be64<uint64_t> accessTitleMask; // Access title mask
};
static_assert(sizeof(ESV1AccessTitleRecord) == 16, "ESV1AccessTitleRecord size");
struct ESV1LimitedResourceRecord
{
tc::bn::be32<uint32_t> limit; // Expiration time
ESReferenceId referenceId; // Reference ID
tc::bn::be32<uint32_t> referenceIdAttr; // Reference ID attributes
};
static_assert(sizeof(ESV1LimitedResourceRecord) == 24, "ESV1LimitedResourceRecord size");
struct ESV2Ticket
{
ESSigRsa2048 sig; // RSA 2048-bit sign of the ticket
ESV2TitleKey titleKey; // Published title key
uint8_t version; // Ticket data structure version number
uint8_t keyType; // Title key encryption key type
tc::bn::le16<uint16_t> ticketVersion; // 16-bit ticket version
uint8_t licenseType;
uint8_t keyId; // Common key ID
tc::bn::le16<uint16_t> propertyMask; // 16-bit property mask
ESV2TicketReserved reservedRegion; // probably the accessTitleId & mask
tc::bn::le64<uint64_t> ticketId; // Unique 64bit ticket ID
tc::bn::le64<uint64_t> deviceId; // Unique 64bit device ID
ESRightsId rightsId; // Unique 128bit rights ID
tc::bn::le32<uint32_t> accountId; // Unique 32bit account ID
tc::bn::le32<uint32_t> sectTotalSize; // Total size of sections
tc::bn::le32<uint32_t> sectHdrOffset; // Offset of the section header table
tc::bn::le16<uint16_t> nSectHdrs; // Number of section headers
tc::bn::le16<uint16_t> nSectHdrEntrySize; // Size of each section header
};
static_assert(sizeof(ESV2Ticket) == 704, "ESV2Ticket size");
struct ESV2SectionHeader
{
tc::bn::le32<uint32_t> sectOfst; // Offset of this section
tc::bn::le32<uint32_t> recordSize; // Size of each record
tc::bn::le32<uint32_t> sectionSize; // Total size of this section
tc::bn::le16<uint16_t> nRecords; // Number of records in this section
tc::bn::le16<uint16_t> sectionType; // Type code of this section
};
static_assert(sizeof(ESV2SectionHeader) == 16, "ESV2SectionHeader size");
#ifdef _WIN32
#pragma warning(default : 4200)
#endif
#pragma pack(pop)
}} // namespace brd::es
@@ -0,0 +1,129 @@
#pragma once
#include <brd/es/es_sign.h>
namespace brd { namespace es {
// ES title type
enum class ESTitleType : uint32_t
{
NC_TITLE = 0x1, // bit0 NetCard - End-of-life
NG_TITLE = 0x2, // bit1 Wii/NDEV
DS_TITLE = 0x4, // bit2 TWL/DSi
DATA = 0x8, // bit3 boring data title
CT_TITLE = 0x40, // bit6 CTR/3DS
GVM_TITLE = 0x80, // bit7 GVM = ? (from BroadOn libraries)
CAFE_TITLE = 0x100, // bit8 WiiU (from WiiU sdk)
};
// ES content type
enum ESContentType : uint16_t
{
ESContentType_ENCRYPTED = 0x1, // bit0 (from broadOn & b4)
ESContentType_DISC = 0x2, // bit1 (from broadOn & b4)
ESContentType_HASHED = 0x2, // bit1 (from b4)
ESContentType_CFM = 0x4, // bit3 (from broadOn & b4)
ESContentType_SHA1_HASH = 0x2000, // bit13 from b4 (wiiu sdk)
ESContentType_OPTIONAL = 0x4000, // bit14 (from broadOn & b4)
ESContentType_SHARED = 0x8000, // bit15 (from broadOn & b4)
};
//
// Maximum possible content index value is 64K - 2, since
// the maximum number of contents per title is 64K - 1
//
static const size_t ES_CONTENT_INDEX_MAX = 65534;
// There are a maximum of 64 CMD groups, each with a maximum of 1K CMDs
static const size_t ES_MAX_CMDS_IN_GROUP = 1024;
static const size_t ES_MAX_CMD_GROUPS = 64;
#pragma pack(push, 4)
#ifdef _WIN32
#pragma warning(disable : 4200) // silence warnings for usage of empty arrays in stucts
#endif
struct ESContentMeta
{
tc::bn::be32<uint32_t> cid; // 32-bit content ID
tc::bn::be16<uint16_t> index; // Content index, unique per title
tc::bn::be16<uint16_t> type; // Content type
tc::bn::be64<uint64_t> size; // Unencrypted content size in bytes
Sha1Hash hash; // Hash of the content
};
static_assert(sizeof(ESContentMeta) == 36, "ESContentMeta size");
struct ESV1ContentMeta
{
tc::bn::be32<uint32_t> cid; // 32-bit content ID
tc::bn::be16<uint16_t> index; // Content index, unique per title
tc::bn::be16<uint16_t> type; // Content type
tc::bn::be64<uint64_t> size; // Unencrypted content size in bytes
Sha256Hash hash; // Hash of the content
};
static_assert(sizeof(ESV1ContentMeta) == 48, "ESV1ContentMeta size");
struct ESTitleMetaHeader
{
using ESTmdCustomData = std::array<uint8_t, 32>;
using ESTmdReserved = std::array<uint8_t, 30>;
uint8_t version; // TMD version number
uint8_t caCrlVersion; // CA CRL version number
uint8_t signerCrlVersion; // Signer CRL version number
tc::bn::be64<uint64_t> sysVersion; // System software version number
tc::bn::be64<uint64_t> titleId; // 64-bit title id
tc::bn::be32<ESTitleType> type; // 32-bit title type
tc::bn::be16<uint16_t> groupId;
ESTmdCustomData customData; // 32-byte custom data
ESTmdReserved reserved; // 30-byte reserved info
tc::bn::be32<uint32_t> accessRights; // Rights to system resources
tc::bn::be16<uint16_t> titleVersion; // 16-bit title version
tc::bn::be16<uint16_t> numContents; // Number of contents
tc::bn::be16<uint16_t> bootIndex; // Boot content index
tc::bn::be16<uint16_t> minorTitleVersion; // 16-bit minor title version
};
static_assert(sizeof(ESTitleMetaHeader) == 100, "ESTitleMetaHeader size");
struct ESV1ContentMetaGroup
{
tc::bn::be16<uint16_t> offset; // Offset content index
tc::bn::be16<uint16_t> nCmds; // Number of CMDs in this group
Sha256Hash groupHash; // Hash for this group of CMDs
};
static_assert(sizeof(ESV1ContentMetaGroup) == 36, "ESV1ContentMetaGroup size");
struct ESV1TitleMetaHeader
{
using ESV1ContentMetaGroupArray = std::array<ESV1ContentMetaGroup, ES_MAX_CMD_GROUPS>;
Sha256Hash hash; // Hash for the CMD groups
ESV1ContentMetaGroupArray cmdGroups;
};
static_assert(sizeof(ESV1TitleMetaHeader) == 2336, "ESV1TitleMetaHeader size");
struct ESTitleMeta
{
ESSigRsa2048 sig; // RSA 2048-bit sign of the TMD header
ESTitleMetaHeader head;
ESContentMeta contents[]; // CMD array sorted by content index
};
static_assert(sizeof(ESTitleMeta) == 484, "ESTitleMeta size");
struct ESV1TitleMeta
{
ESSigRsa2048 sig; // RSA 2048-bit sign of the TMD header
ESTitleMetaHeader head;
ESV1TitleMetaHeader v1Head; // Extension to the v0 TMD header
ESV1ContentMeta contents[]; // CMD array sorted by content index
};
static_assert(sizeof(ESV1TitleMeta) == 2820, "ESV1TitleMeta size");
#ifdef _WIN32
#pragma warning(default : 4200)
#endif
#pragma pack(pop)
}} // namespace brd::es
@@ -0,0 +1,73 @@
#pragma once
#include <tc/types.h>
namespace brd { namespace es {
#pragma pack(push,4)
static const size_t kAes128KeySize = 16;
using Aes128Key = std::array<uint8_t, kAes128KeySize>;
static const size_t kAes192KeySize = 24;
using Aes192Key = std::array<uint8_t, kAes192KeySize>;
static const size_t kAes256KeySize = 32;
using Aes256Key = std::array<uint8_t, kAes256KeySize>;
static const size_t kSha1Size = 20;
using Sha1Hash = std::array<uint8_t, kSha1Size>;
using Sha1Hmac = std::array<uint8_t, kSha1Size>;
static const size_t kSha256Size = 32;
using Sha256Hash = std::array<uint8_t, kSha256Size>;
using Sha256Hmac = std::array<uint8_t, kSha256Size>;
static const size_t kRsaPublicExponentSize = 4;
using RsaPublicExponent = std::array<uint8_t, kRsaPublicExponentSize>;
static const size_t kRsa2048Size = 0x100;
using Rsa2048Integer = std::array<uint8_t, kRsa2048Size>;
struct Rsa2048PublicKey
{
Rsa2048Integer m; // modulus
RsaPublicExponent e; // public_exponent
};
struct Rsa2048PrivateKey
{
Rsa2048Integer m; // modulus
Rsa2048Integer d; // private_exponent
};
using Rsa2048Sig = Rsa2048Integer;
static const size_t kRsa4096Size = 0x200;
using Rsa4096Integer = std::array<uint8_t, kRsa4096Size>;
struct Rsa4096PublicKey
{
Rsa4096Integer m; // modulus
RsaPublicExponent e; // public_exponent
};
struct Rsa4096PrivateKey
{
Rsa4096Integer m; // modulus
Rsa4096Integer d; // private_exponent
};
using Rsa4096Sig = Rsa4096Integer;
static const size_t kEcc233Size = 60;
using Ecc233Integer = std::array<uint8_t, kEcc233Size / 2>;
struct Ecc233Point
{
Ecc233Integer x;
Ecc233Integer y;
};
using Ecc233PrivateKey = Ecc233Integer;
using Ecc233PublicKey = Ecc233Point;
struct Ecc233Sig
{
Ecc233Integer r;
Ecc233Integer s;
};
#pragma pack(pop)
}} // namespace brd::es