Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
34 changes: 24 additions & 10 deletions gc/ogc/es.h
Original file line number Diff line number Diff line change
Expand Up @@ -50,8 +50,11 @@ distribution.
#define ES_CERT_RSA2048 1
#define ES_CERT_ECDSA 2

#define ES_KEY_NANDFS 2 /* !? */
#define ES_KEY_COMMON 4
#define ES_KEY_BACKUP 5
#define ES_KEY_SDCARD 6
#define ES_KEY_KOREAN 11

#ifdef __cplusplus
extern "C" {
Expand Down Expand Up @@ -269,7 +272,12 @@ s32 ES_GetStoredTMD(u64 titleID, signed_blob *stmd, u32 size);
s32 ES_GetTitleContentsCount(u64 titleID, u32 *num);
s32 ES_GetTitleContents(u64 titleID, u32 *contents, u32 num);
s32 ES_GetTMDViewSize(u64 titleID, u32 *size);
s32 ES_GetTMDView(u64 titleID, u8 *data, u32 size);
s32 ES_GetTMDView(u64 titleID, tmd_view *view, u32 size);
s32 ES_GetConsumptionCount(u64 ticketID, u32 *n_limits);
s32 ES_GetConsumption(u64 ticketID, tiklimit *limits, u32 n_limits);
s32 ES_DiGetTMDViewSize(const signed_blob *s_tmd, u32 tmd_size, u32 *view_size);
s32 ES_DiGetTMDView(const signed_blob *s_tmd, u32 tmd_size, tmd_view *view, u32 view_size);
s32 ES_DiGetTicketView(const signed_blob *s_tik, tikview *view);
s32 ES_GetNumSharedContents(u32 *cnt);
s32 ES_GetSharedContents(sha1 *contents, u32 cnt);
s32 ES_LaunchTitle(u64 titleID, const tikview *view);
Expand All @@ -278,29 +286,35 @@ s32 ES_Identify(const signed_blob *certificates, u32 certificates_size, const si
s32 ES_DiVerifyWithTicketView(const signed_blob *certificates, u32 certificates_size, const signed_blob *s_tmd, u32 tmd_size, const tikview *ticket_view, u32 *keynum);
s32 ES_AddTicket(const signed_blob *tik, u32 tik_size, const signed_blob *certificates, u32 certificates_size, const signed_blob *crl, u32 crl_size);
s32 ES_DeleteTicket(const tikview *view);
s32 ES_AddTitleTMD(const signed_blob *tmd, u32 tmd_size);
s32 ES_ExportTitleInit(u64 titleID, signed_blob *tmd_out, u32 tmd_size);
s32 ES_ExportContentBegin(u64 titleID, u32 cid);
s32 ES_ExportContentData(s32 cfd, void *data, u32 data_size);
s32 ES_ExportContentEnd(s32 cfd);
s32 ES_ExportTitleDone(void);
s32 ES_ReimportTitleInit(const signed_blob *tmd, u32 tmd_size);
s32 ES_AddTitleStart(const signed_blob *tmd, u32 tmd_size, const signed_blob *certificatess, u32 certificatess_size, const signed_blob *crl, u32 crl_size);
s32 ES_AddContentStart(u64 titleID, u32 cid);
s32 ES_AddContentData(s32 cid, u8 *data, u32 data_size);
s32 ES_AddContentData(s32 cid, const void *data, u32 data_size);
s32 ES_AddContentFinish(u32 cid);
s32 ES_AddTitleFinish(void);
s32 ES_AddTitleCancel(void);
s32 ES_ImportBoot(const signed_blob *tik, u32 tik_size,const signed_blob *tik_certs, u32 tik_certs_size,const signed_blob *tmd, u32 tmd_size,const signed_blob *tmd_certs, u32 tmd_certs_size,const u8 *content, u32 content_size);
s32 ES_OpenContent(u16 index);
s32 ES_OpenTitleContent(u64 titleID, tikview *views, u16 index);
s32 ES_ReadContent(s32 cfd, u8 *data, u32 data_size);
s32 ES_OpenTitleContent(u64 titleID, const tikview *views, u16 index);
s32 ES_ReadContent(s32 cfd, void *data, u32 data_size);
s32 ES_SeekContent(s32 cfd, s32 where, s32 whence);
s32 ES_CloseContent(s32 cfd);
s32 ES_DeleteTitle(u64 titleID);
s32 ES_DeleteTitleContent(u64 titleID);
s32 ES_Encrypt(u32 keynum, u32 *iv, void *source, u32 size, void *dest);
s32 ES_Decrypt(u32 keynum, u32 *iv, void *source, u32 size, void *dest);
s32 ES_Sign(void *source, u32 size, u8 *ap_signature, signed_blob *ap_certificate);
s32 ES_VerifySign(void *source, u32 size, u8 *ap_signature, signed_blob *certificates, u32 certificates_size);
s32 ES_Encrypt(u32 keynum, u32 *iv, const void *source, u32 size, void *dest);
s32 ES_Decrypt(u32 keynum, u32 *iv, const void *source, u32 size, void *dest);
s32 ES_Sign(const void *source, u32 size, u8 *ap_signature, signed_blob *ap_certificate);
s32 ES_VerifySign(const void *source, u32 size, const u8 *ap_signature, const signed_blob *certificates, u32 certificates_size);
s32 ES_GetDeviceCert(u8 *outbuf);
s32 ES_GetDeviceID(u32 *device_id);
s32 ES_GetBoot2Version(u32 *version);
signed_blob *ES_NextCert(const signed_blob *certs);
s32 ES_CheckHasKoreanKey(void);
const signed_blob *ES_NextCert(const signed_blob *certs);

#ifdef __cplusplus
}
Expand Down
110 changes: 89 additions & 21 deletions libogc/es.c
Original file line number Diff line number Diff line change
Expand Up @@ -67,12 +67,12 @@ distribution.
#define IOCTL_ES_GETVIEWS 0x13
#define IOCTL_ES_GETTMDVIEWCNT 0x14
#define IOCTL_ES_GETTMDVIEWS 0x15
//#define IOCTL_ES_GETCONSUMPTION 0x16
#define IOCTL_ES_GETCONSUMPTION 0x16
#define IOCTL_ES_DELETETITLE 0x17
#define IOCTL_ES_DELETETICKET 0x18
//#define IOCTL_ES_DIGETTMDVIEWSIZE 0x19
//#define IOCTL_ES_DIGETTMDVIEW 0x1A
//#define IOCTL_ES_DIGETTICKETVIEW 0x1B
#define IOCTL_ES_DIGETTMDVIEWSIZE 0x19
#define IOCTL_ES_DIGETTMDVIEW 0x1A
#define IOCTL_ES_DIGETTICKETVIEW 0x1B
#define IOCTL_ES_DIVERIFY 0x1C
#define IOCTL_ES_GETTITLEDIR 0x1D
#define IOCTL_ES_GETDEVICECERT 0x1E
Expand Down Expand Up @@ -102,6 +102,7 @@ distribution.
#define IOCTL_ES_GETSHAREDCONTENTCNT 0x36
#define IOCTL_ES_GETSHAREDCONTENTS 0x37
#define IOCTL_ES_DIVERIFYWITHTIKVIEW 0x3B
#define IOCTL_ES_CHECKHASKOREANKEY 0x45

#define ES_HEAP_SIZE 0x800

Expand Down Expand Up @@ -350,7 +351,7 @@ s32 ES_GetNumStoredTMDContents(const signed_blob *stmd, u32 tmd_size, u32 *cnt)
if(__es_fd<0) return ES_ENOTINIT;
if(!cnt) return ES_EINVAL;
if(!stmd || !IS_VALID_SIGNATURE(stmd)) return ES_EINVAL;
if(!ISALIGNED(stmd, 64)) return ES_EALIGN; /* !? passed directly to VerifyContainer */
if(!ISALIGNED(stmd, 64)) return ES_EALIGN; /* !? passed directly to VerifyContainer -> passed directly to IOSC_GenerateHash */

ret = IOS_IoctlvFormat(__es_hid,__es_fd,IOCTL_ES_GETSTOREDCONTENTCNT,"d:i",stmd,tmd_size,&cntct);

Expand Down Expand Up @@ -413,14 +414,74 @@ s32 ES_GetTMDViewSize(u64 titleID, u32 *size)
return ret;
}

s32 ES_GetTMDView(u64 titleID, u8 *data, u32 size)
s32 ES_GetTMDView(u64 titleID, tmd_view *view, u32 size)
{
if(__es_fd<0) return ES_ENOTINIT;
if(size <= 0) return ES_EINVAL;
if(!data) return ES_EINVAL;
if(!ISALIGNED(data, 4)) return ES_EALIGN;
if(!view) return ES_EINVAL;
if(!ISALIGNED(view, 4)) return ES_EALIGN;

return IOS_IoctlvFormat(__es_hid,__es_fd,IOCTL_ES_GETTMDVIEWS,"qi:d",titleID,size,view,size);
}

s32 ES_GetConsumptionCount(u64 ticketID, u32 *n_limits)
{
s32 ret;
u32 _n_limits = 0;

if (__es_fd < 0) return ES_ENOTINIT;
if (!n_limits) return ES_EINVAL;

ret = IOS_IoctlvFormat(__es_hid, __es_fd, IOCTL_ES_GETCONSUMPTION, "q:di", ticketID, NULL, 0, &_n_limits);
*n_limits = _n_limits;

return ret;
}

s32 ES_GetConsumption(u64 ticketID, tiklimit *limits, u32 n_limits)
{
if (__es_fd < 0) return ES_ENOTINIT;
if (!n_limits || !limits) return ES_EINVAL;
if (!ISALIGNED(limits, 4)) return ES_EALIGN;

return IOS_IoctlvFormat(__es_hid, __es_fd, IOCTL_ES_GETCONSUMPTION, "q:di", ticketID, limits, n_limits * sizeof(tiklimit), &n_limits);
}

s32 ES_DiGetTMDViewSize(const signed_blob *s_tmd, u32 tmd_size, u32 *view_size)
{
s32 ret;
u32 size = 0;

if (__es_fd < 0) return ES_ENOTINIT;
if (s_tmd && tmd_size != SIGNED_TMD_SIZE(s_tmd)) return ES_EINVAL;
if (!size) return ES_EINVAL;
if (!ISALIGNED(s_tmd, 4)) return ES_EALIGN;

if (!s_tmd) tmd_size = 0;

ret = IOS_IoctlvFormat(__es_hid, __es_fd, IOCTL_ES_DIGETTMDVIEWSIZE, "d:i", s_tmd, tmd_size, &size);
*view_size = size;

return ret;
}

s32 ES_DiGetTMDView(const signed_blob *s_tmd, u32 tmd_size, tmd_view *view, u32 view_size)
{
if (__es_fd < 0) return ES_ENOTINIT;
if (s_tmd && tmd_size != SIGNED_TMD_SIZE(s_tmd)) return ES_EINVAL;
if (view_size < sizeof(tmd_view)) return ES_EINVAL;
if (!ISALIGNED(s_tmd, 4) || !ISALIGNED(view, 4)) return ES_EALIGN;

return IOS_IoctlvFormat(__es_hid,__es_fd,IOCTL_ES_GETTMDVIEWS,"qi:d",titleID,size,data,size);
return IOS_IoctlvFormat(__es_hid, __es_fd, IOCTL_ES_DIGETTMDVIEW, "di:d", s_tmd, (s_tmd == NULL ? 0 : tmd_size), &view_size, view, view_size);
}

s32 ES_DiGetTicketView(const signed_blob *s_tik, tikview *view)
{
if (__es_fd < 0) return ES_ENOTINIT;
if (!view) return ES_EINVAL;
if (!ISALIGNED(s_tik, 4) || !ISALIGNED(view, 4)) return ES_EALIGN;

return IOS_IoctlvFormat(__es_hid, __es_fd, IOCTL_ES_DIGETTICKETVIEW, "d:d", s_tik, (s_tik == NULL ? 0 : STD_SIGNED_TIK_SIZE), view, sizeof(tikview));
}

s32 ES_GetStoredTMDSize(u64 titleID, u32 *size)
Expand Down Expand Up @@ -474,7 +535,7 @@ s32 ES_GetSharedContents(sha1 *contents, u32 cnt)
return IOS_IoctlvFormat(__es_hid,__es_fd,IOCTL_ES_GETSHAREDCONTENTS,"i:d",cnt,contents,sizeof(sha1)*cnt);
}

signed_blob *ES_NextCert(const signed_blob *certs)
const signed_blob *ES_NextCert(const signed_blob *certs)
{
cert_header *cert;
if(!SIGNATURE_SIZE(certs)) return NULL;
Expand Down Expand Up @@ -558,7 +619,7 @@ s32 ES_DiVerifyWithTicketView(const signed_blob *certificates, u32 certificates_
if (!s_tmd || !IS_VALID_SIGNATURE(s_tmd) || tmd_size != SIGNED_TMD_SIZE(s_tmd))
return ES_EINVAL;

if (certificates_size && !__ES_sanity_check_certlist(certificates, certificates_size)) // ES_DiVerifyWithTicketView must fetch the system's certificate store for the ticket. It also does not check the size. It does check the pointer though.
if (!certificates || (certificates_size && !__ES_sanity_check_certlist(certificates, certificates_size)) || !ISALIGNED(certificates_size, 64)) // ES will copy our certificates first then read the system's on top of that. So if the size is somehow not a multiple of 64 bytes then, unless you plan to provide the ticket certificates yourself, the function is going to break
return ES_EINVAL;

// Alignment demands according to the actual IPC handler. ES ultimately allocates it's own 64-byte aligned buffer and copies our data.
Expand Down Expand Up @@ -630,7 +691,7 @@ s32 ES_ExportContentBegin(u64 titleID, u32 contentID) {
s32 ES_ExportContentData(s32 cfd, void *data, u32 size) {
if (__es_fd < 0) return ES_ENOTINIT;
if (!data || !size) return ES_EINVAL;
if (!ISALIGNED(data, 16) /* passed directly to IOSC_Encrypt */ || !ISALIGNED(size, 32) /* !? ES rounds up data_read to 32 bytes */)
if (!ISALIGNED(data, 32) || !ISALIGNED(size, 32))
return ES_EALIGN;

return IOS_IoctlvFormat(__es_hid, __es_fd, IOCTL_ES_EXPORTCONTENTDATA, "i:d", cfd, data, size);
Expand Down Expand Up @@ -690,7 +751,7 @@ s32 ES_AddContentStart(u64 titleID, u32 cid)
return IOS_IoctlvFormat(__es_hid, __es_fd, IOCTL_ES_ADDCONTENTSTART, "qi:", titleID, cid);
}

s32 ES_AddContentData(s32 cfd, u8 *data, u32 data_size)
s32 ES_AddContentData(s32 cfd, const void *data, u32 data_size)
{
if(__es_fd<0) return ES_ENOTINIT;
if(cfd<0) return ES_EINVAL;
Expand Down Expand Up @@ -740,14 +801,14 @@ s32 ES_OpenContent(u16 index)
return IOS_IoctlvFormat(__es_hid, __es_fd, IOCTL_ES_OPENCONTENT, "i:", index);
}

s32 ES_OpenTitleContent(u64 titleID, tikview *views, u16 index)
s32 ES_OpenTitleContent(u64 titleID, const tikview *views, u16 index)
{
if(__es_fd<0) return ES_ENOTINIT;
if(!ISALIGNED(views, 4)) return ES_EALIGN;
return IOS_IoctlvFormat(__es_hid, __es_fd, IOCTL_ES_OPENTITLECONTENT, "qdi:", titleID, views, sizeof(tikview), index);
}

s32 ES_ReadContent(s32 cfd, u8 *data, u32 data_size)
s32 ES_ReadContent(s32 cfd, void *data, u32 data_size)
{
if(__es_fd<0) return ES_ENOTINIT;
if(cfd<0) return ES_EINVAL;
Expand Down Expand Up @@ -782,31 +843,31 @@ s32 ES_DeleteTitleContent(u64 titleID)
return IOS_IoctlvFormat(__es_hid, __es_fd, IOCTL_ES_DELETETITLECONTENT, "q:", titleID);
}

s32 ES_Encrypt(u32 keynum, u32 *iv, void *source, u32 size, void *dest)
s32 ES_Encrypt(u32 keynum, u32 *iv, const void *source, u32 size, void *dest)
{
if (__es_fd < 0)
return ES_ENOTINIT;
if (!iv || !source || !size || !dest)
return ES_EINVAL;
if (!ISALIGNED(iv, 4) || !ISALIGNED(source, 16) || !ISALIGNED(dest, 16) || !ISALIGNED(size, 16))
if (!ISALIGNED(iv, 4) || !ISALIGNED(source, 32) || !ISALIGNED(dest, 32) || !ISALIGNED(size, 16))
return ES_EALIGN;

return IOS_IoctlvFormat(__es_hid, __es_fd, IOCTL_ES_ENCRYPT, "idd:dd", keynum, iv, 0x10, source, size, iv, 0x10, dest, size);
}

s32 ES_Decrypt(u32 keynum, u32 *iv, void *source, u32 size, void *dest)
s32 ES_Decrypt(u32 keynum, u32 *iv, const void *source, u32 size, void *dest)
{
if (__es_fd < 0)
return ES_ENOTINIT;
if (!iv || !source || !size || !dest)
return ES_EINVAL;
if (!ISALIGNED(iv, 4) || !ISALIGNED(source, 16) || !ISALIGNED(dest, 16) || !ISALIGNED(size, 16))
if (!ISALIGNED(iv, 4) || !ISALIGNED(source, 32) || !ISALIGNED(dest, 32) || !ISALIGNED(size, 16))
return ES_EALIGN;

return IOS_IoctlvFormat(__es_hid, __es_fd, IOCTL_ES_DECRYPT, "idd:dd", keynum, iv, 0x10, source, size, iv, 0x10, dest, size);
}

s32 ES_Sign(void *data, u32 size, u8 *ap_signature, signed_blob *ap_certificate)
s32 ES_Sign(const void *data, u32 size, u8 *ap_signature, signed_blob *ap_certificate)
{
if (__es_fd < 0) return ES_ENOTINIT;
if (!data || !size || !ap_signature || !ap_certificate) return ES_EINVAL;
Expand All @@ -817,7 +878,7 @@ s32 ES_Sign(void *data, u32 size, u8 *ap_signature, signed_blob *ap_certificate)
return IOS_IoctlvFormat(__es_hid, __es_fd, IOCTL_ES_SIGN, "d:dd", data, size, ap_signature, 0x3C, ap_certificate, 0x180);
}

s32 ES_VerifySign(void *data, u32 size, u8 *ap_signature, signed_blob *certificates, u32 certificates_size) {
s32 ES_VerifySign(const void *data, u32 size, const u8 *ap_signature, const signed_blob *certificates, u32 certificates_size) {
if (__es_fd < 0) return ES_ENOTINIT;
if (!data || !size || !ap_signature || !certificates || !certificates_size) return ES_EINVAL;
if (!__ES_sanity_check_certlist(certificates, certificates_size)) return ES_EINVAL;
Expand Down Expand Up @@ -863,6 +924,13 @@ s32 ES_GetBoot2Version(u32 *version)
return ret;
}

s32 ES_CheckHasKoreanKey(void)
{
if (__es_fd < 0) return ES_ENOTINIT;

return IOS_IoctlvFormat(__es_hid, __es_fd, IOCTL_ES_CHECKHASKOREANKEY, "");
}

// 64k buffer size for alignment
#define ES_READ_BUF_SIZE 65536

Expand Down