Skip to content

Commit

Permalink
Added more ES functions pt.2 (#193)
Browse files Browse the repository at this point in the history
* add korean common key check

* formal certificates check for DiVerifyWithTicketView
  • Loading branch information
Naim2000 authored Feb 21, 2025
1 parent 841442b commit fbc8f2e
Show file tree
Hide file tree
Showing 2 changed files with 113 additions and 31 deletions.
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

0 comments on commit fbc8f2e

Please sign in to comment.