1 /*-------------------------------------------------------------
3 es.c -- ETicket services
6 Michael Wiedenbauer (shagkur)
7 Dave Murphy (WinterMute)
10 This software is provided 'as-is', without any express or implied
11 warranty. In no event will the authors be held liable for any
12 damages arising from the use of this software.
14 Permission is granted to anyone to use this software for any
15 purpose, including commercial applications, and to alter it and
16 redistribute it freely, subject to the following restrictions:
18 1. The origin of this software must not be misrepresented; you
19 must not claim that you wrote the original software. If you use
20 this software in a product, an acknowledgment in the product
21 documentation would be appreciated but is not required.
23 2. Altered source versions must be plainly marked as such, and
24 must not be misrepresented as being the original software.
26 3. This notice may not be removed or altered from any source
29 -------------------------------------------------------------*/
33 #include <sys/iosupport.h>
34 #include <sys/fcntl.h>
39 #include <sys/errno.h>
42 #include "processor.h"
48 #define IOCTL_ES_ADDTICKET 0x01
49 #define IOCTL_ES_ADDTITLESTART 0x02
50 #define IOCTL_ES_ADDCONTENTSTART 0x03
51 #define IOCTL_ES_ADDCONTENTDATA 0x04
52 #define IOCTL_ES_ADDCONTENTFINISH 0x05
53 #define IOCTL_ES_ADDTITLEFINISH 0x06
54 #define IOCTL_ES_GETDEVICEID 0x07
55 #define IOCTL_ES_LAUNCH 0x08
56 #define IOCTL_ES_OPENCONTENT 0x09
57 #define IOCTL_ES_READCONTENT 0x0A
58 #define IOCTL_ES_CLOSECONTENT 0x0B
59 #define IOCTL_ES_GETOWNEDTITLECNT 0x0C
60 #define IOCTL_ES_GETOWNEDTITLES 0x0D
61 #define IOCTL_ES_GETTITLECNT 0x0E
62 #define IOCTL_ES_GETTITLES 0x0F
63 #define IOCTL_ES_GETTITLECONTENTSCNT 0x10
64 #define IOCTL_ES_GETTITLECONTENTS 0x11
65 #define IOCTL_ES_GETVIEWCNT 0x12
66 #define IOCTL_ES_GETVIEWS 0x13
67 #define IOCTL_ES_GETTMDVIEWCNT 0x14
68 #define IOCTL_ES_GETTMDVIEWS 0x15
69 //#define IOCTL_ES_GETCONSUMPTION 0x16
70 #define IOCTL_ES_DELETETITLE 0x17
71 #define IOCTL_ES_DELETETICKET 0x18
72 //#define IOCTL_ES_DIGETTMDVIEWSIZE 0x19
73 //#define IOCTL_ES_DIGETTMDVIEW 0x1A
74 //#define IOCTL_ES_DIGETTICKETVIEW 0x1B
75 #define IOCTL_ES_DIVERIFY 0x1C
76 #define IOCTL_ES_GETTITLEDIR 0x1D
77 #define IOCTL_ES_GETDEVICECERT 0x1E
78 #define IOCTL_ES_IMPORTBOOT 0x1F
79 #define IOCTL_ES_GETTITLEID 0x20
80 #define IOCTL_ES_SETUID 0x21
81 #define IOCTL_ES_DELETETITLECONTENT 0x22
82 #define IOCTL_ES_SEEKCONTENT 0x23
83 #define IOCTL_ES_OPENTITLECONTENT 0x24
84 //#define IOCTL_ES_LAUNCHBC 0x25
85 //#define IOCTL_ES_EXPORTTITLEINIT 0x26
86 //#define IOCTL_ES_EXPORTCONTENTBEGIN 0x27
87 //#define IOCTL_ES_EXPORTCONTENTDATA 0x28
88 //#define IOCTL_ES_EXPORTCONTENTEND 0x29
89 //#define IOCTL_ES_EXPORTTITLEDONE 0x2A
90 #define IOCTL_ES_ADDTMD 0x2B
91 #define IOCTL_ES_ENCRYPT 0x2C
92 #define IOCTL_ES_DECRYPT 0x2D
93 #define IOCTL_ES_GETBOOT2VERSION 0x2E
94 #define IOCTL_ES_ADDTITLECANCEL 0x2F
95 #define IOCTL_ES_SIGN 0x30
96 //#define IOCTL_ES_VERIFYSIGN 0x31
97 #define IOCTL_ES_GETSTOREDCONTENTCNT 0x32
98 #define IOCTL_ES_GETSTOREDCONTENTS 0x33
99 #define IOCTL_ES_GETSTOREDTMDSIZE 0x34
100 #define IOCTL_ES_GETSTOREDTMD 0x35
101 #define IOCTL_ES_GETSHAREDCONTENTCNT 0x36
102 #define IOCTL_ES_GETSHAREDCONTENTS 0x37
105 #define ES_HEAP_SIZE 0x800
107 #define ISALIGNED(x) ((((u32)x)&0x1F)==0)
109 static char __es_fs
[] ATTRIBUTE_ALIGN(32) = "/dev/es";
111 static s32 __es_fd
= -1;
112 static s32 __es_hid
= -1;
114 static void __ES_InitFS(void);
115 static void __ES_DeinitFS(void);
126 __es_hid
= iosCreateHeap(ES_HEAP_SIZE
);
127 if(__es_hid
< 0) return __es_hid
;
130 ret
= IOS_Open(__es_fs
,0);
131 if(ret
<0) return ret
;
135 printf("ES FD %d\n",__es_fd
);
147 if(__es_fd
< 0) return 0;
151 ret
= IOS_Close(__es_fd
);
153 // If close fails, I'd rather return error but still reset the fd.
154 // Otherwise you're stuck with an uncloseable ES, and you can't open again either
155 //if(ret<0) return ret;
165 // Used by ios.c after reloading IOS
172 s32
ES_GetTitleID(u64
*titleID
)
177 if(__es_fd
<0) return ES_ENOTINIT
;
178 if(!titleID
) return ES_EINVAL
;
180 ret
= IOS_IoctlvFormat(__es_hid
,__es_fd
,IOCTL_ES_GETTITLEID
,":q",&title
);
181 if(ret
<0) return ret
;
187 s32
ES_SetUID(u64 uid
)
189 if(__es_fd
<0) return ES_ENOTINIT
;
191 return IOS_IoctlvFormat(__es_hid
,__es_fd
,IOCTL_ES_SETUID
,"q:",uid
);
194 s32
ES_GetDataDir(u64 titleID
,char *filepath
)
198 if(__es_fd
<0) return ES_ENOTINIT
;
199 if(!filepath
) return ES_EINVAL
;
200 if(!ISALIGNED(filepath
)) return ES_EALIGN
;
202 ret
= IOS_IoctlvFormat(__es_hid
,__es_fd
,IOCTL_ES_GETTITLEDIR
,"q:d",titleID
,filepath
,30);
207 s32
ES_LaunchTitle(u64 titleID
, const tikview
*view
)
211 STACK_ALIGN(u64
,title
,1,32);
212 STACK_ALIGN(ioctlv
,vectors
,2,32);
214 if(__es_fd
<0) return ES_ENOTINIT
;
215 if(!view
) return ES_EINVAL
;
216 if(!ISALIGNED(view
)) return ES_EALIGN
;
219 printf("ES LaunchTitle %d %016llx 0x%08x 0x%02x\n",__es_fd
,titleID
,(u32
)view
,sizeof(tikview
));
224 vectors
[0].data
= (void*)title
;
225 vectors
[0].len
= sizeof(u64
);
226 vectors
[1].data
= (void*)view
;
227 vectors
[1].len
= sizeof(tikview
);
228 res
= IOS_IoctlvReboot(__es_fd
,IOCTL_ES_LAUNCH
,2,0,vectors
);
231 printf(" =%d\n",res
);
237 s32
ES_LaunchTitleBackground(u64 titleID
, const tikview
*view
)
241 STACK_ALIGN(u64
,title
,1,32);
242 STACK_ALIGN(ioctlv
,vectors
,2,32);
244 if(__es_fd
<0) return ES_ENOTINIT
;
245 if(!view
) return ES_EINVAL
;
246 if(!ISALIGNED(view
)) return ES_EALIGN
;
249 printf("ES LaunchTitleBackground %d %016llx 0x%08x 0x%02x\n",__es_fd
,titleID
,(u32
)view
,sizeof(tikview
));
253 vectors
[0].data
= (void*)title
;
254 vectors
[0].len
= sizeof(u64
);
255 vectors
[1].data
= (void*)view
;
256 vectors
[1].len
= sizeof(tikview
);
257 res
= IOS_IoctlvRebootBackground(__es_fd
,IOCTL_ES_LAUNCH
,2,0,vectors
);
260 printf(" =%d\n",res
);
266 s32
ES_GetNumTicketViews(u64 titleID
, u32
*cnt
)
271 if(__es_fd
<0) return ES_ENOTINIT
;
272 if(!cnt
) return ES_EINVAL
;
274 ret
= IOS_IoctlvFormat(__es_hid
,__es_fd
,IOCTL_ES_GETVIEWCNT
,"q:i",titleID
,&cntviews
);
276 if(ret
<0) return ret
;
281 s32
ES_GetTicketViews(u64 titleID
, tikview
*views
, u32 cnt
)
283 if(__es_fd
<0) return ES_ENOTINIT
;
284 if(cnt
<= 0) return ES_EINVAL
;
285 if(!views
) return ES_EINVAL
;
286 if(!ISALIGNED(views
)) return ES_EALIGN
;
288 return IOS_IoctlvFormat(__es_hid
,__es_fd
,IOCTL_ES_GETVIEWS
,"qi:d",titleID
,cnt
,views
,sizeof(tikview
)*cnt
);
291 s32
ES_GetNumOwnedTitles(u32
*cnt
)
296 if(__es_fd
<0) return ES_ENOTINIT
;
297 if(cnt
== NULL
) return ES_EINVAL
;
299 ret
= IOS_IoctlvFormat(__es_hid
,__es_fd
,IOCTL_ES_GETOWNEDTITLECNT
,":i",&cnttitles
);
301 if(ret
<0) return ret
;
306 s32
ES_GetOwnedTitles(u64
*titles
, u32 cnt
)
308 if(__es_fd
<0) return ES_ENOTINIT
;
309 if(cnt
<= 0) return ES_EINVAL
;
310 if(!titles
) return ES_EINVAL
;
311 if(!ISALIGNED(titles
)) return ES_EALIGN
;
313 return IOS_IoctlvFormat(__es_hid
,__es_fd
,IOCTL_ES_GETOWNEDTITLES
,"i:d",cnt
,titles
,sizeof(u64
)*cnt
);
316 s32
ES_GetNumTitles(u32
*cnt
)
321 if(__es_fd
<0) return ES_ENOTINIT
;
322 if(cnt
== NULL
) return ES_EINVAL
;
324 ret
= IOS_IoctlvFormat(__es_hid
,__es_fd
,IOCTL_ES_GETTITLECNT
,":i",&cnttitles
);
326 if(ret
<0) return ret
;
331 s32
ES_GetTitles(u64
*titles
, u32 cnt
)
333 if(__es_fd
<0) return ES_ENOTINIT
;
334 if(cnt
<= 0) return ES_EINVAL
;
335 if(!titles
) return ES_EINVAL
;
336 if(!ISALIGNED(titles
)) return ES_EALIGN
;
338 return IOS_IoctlvFormat(__es_hid
,__es_fd
,IOCTL_ES_GETTITLES
,"i:d",cnt
,titles
,sizeof(u64
)*cnt
);
341 s32
ES_GetNumStoredTMDContents(const signed_blob
*stmd
, u32 tmd_size
, u32
*cnt
)
346 if(__es_fd
<0) return ES_ENOTINIT
;
347 if(!cnt
) return ES_EINVAL
;
348 if(!stmd
|| !IS_VALID_SIGNATURE(stmd
)) return ES_EINVAL
;
349 if(!ISALIGNED(stmd
)) return ES_EALIGN
;
351 ret
= IOS_IoctlvFormat(__es_hid
,__es_fd
,IOCTL_ES_GETSTOREDCONTENTCNT
,"d:i",stmd
,tmd_size
,&cntct
);
353 if(ret
<0) return ret
;
358 s32
ES_GetStoredTMDContents(const signed_blob
*stmd
, u32 tmd_size
, u32
*contents
, u32 cnt
)
360 if(__es_fd
<0) return ES_ENOTINIT
;
361 if(cnt
<= 0) return ES_EINVAL
;
362 if(!contents
) return ES_EINVAL
;
363 if(!stmd
|| !IS_VALID_SIGNATURE(stmd
)) return ES_EINVAL
;
364 if(!ISALIGNED(stmd
)) return ES_EALIGN
;
365 if(!ISALIGNED(contents
)) return ES_EALIGN
;
366 if(tmd_size
> MAX_SIGNED_TMD_SIZE
) return ES_EINVAL
;
368 return IOS_IoctlvFormat(__es_hid
,__es_fd
,IOCTL_ES_GETSTOREDCONTENTS
,"di:d",stmd
,tmd_size
,cnt
,contents
,sizeof(u32
)*cnt
);
371 s32
ES_GetTitleContentsCount(u64 titleID
, u32
*num
)
376 if(__es_fd
<0) return ES_ENOTINIT
;
377 if(!num
) return ES_EINVAL
;
379 ret
= IOS_IoctlvFormat(__es_hid
,__es_fd
,IOCTL_ES_GETTITLECONTENTSCNT
,"q:i",titleID
,&_num
);
381 if(ret
<0) return ret
;
386 s32
ES_GetTitleContents(u64 titleID
, u8
*data
, u32 size
)
388 if(__es_fd
<0) return ES_ENOTINIT
;
389 if(size
<= 0) return ES_EINVAL
;
390 if(!data
) return ES_EINVAL
;
391 if(!ISALIGNED(data
)) return ES_EALIGN
;
393 return IOS_IoctlvFormat(__es_hid
,__es_fd
,IOCTL_ES_GETSTOREDTMD
,"qi:d",titleID
,size
,data
,size
);
396 s32
ES_GetTMDViewSize(u64 titleID
, u32
*size
)
401 if(__es_fd
<0) return ES_ENOTINIT
;
402 if(!size
) return ES_EINVAL
;
404 ret
= IOS_IoctlvFormat(__es_hid
,__es_fd
,IOCTL_ES_GETTMDVIEWCNT
,"q:i",titleID
,&tmdsize
);
406 if(ret
<0) return ret
;
411 s32
ES_GetTMDView(u64 titleID
, u8
*data
, u32 size
)
413 if(__es_fd
<0) return ES_ENOTINIT
;
414 if(size
<= 0) return ES_EINVAL
;
415 if(!data
) return ES_EINVAL
;
416 if(!ISALIGNED(data
)) return ES_EALIGN
;
418 return IOS_IoctlvFormat(__es_hid
,__es_fd
,IOCTL_ES_GETTMDVIEWS
,"qi:d",titleID
,size
,data
,size
);
421 s32
ES_GetStoredTMDSize(u64 titleID
, u32
*size
)
426 if(__es_fd
<0) return ES_ENOTINIT
;
427 if(!size
) return ES_EINVAL
;
429 ret
= IOS_IoctlvFormat(__es_hid
,__es_fd
,IOCTL_ES_GETSTOREDTMDSIZE
,"q:i",titleID
,&tmdsize
);
431 if(ret
<0) return ret
;
436 s32
ES_GetStoredTMD(u64 titleID
, signed_blob
*stmd
, u32 size
)
438 if(__es_fd
<0) return ES_ENOTINIT
;
439 if(size
<= 0) return ES_EINVAL
;
440 if(!stmd
) return ES_EINVAL
;
441 if(!ISALIGNED(stmd
)) return ES_EALIGN
;
442 if(size
> MAX_SIGNED_TMD_SIZE
) return ES_EINVAL
;
444 return IOS_IoctlvFormat(__es_hid
,__es_fd
,IOCTL_ES_GETSTOREDTMD
,"qi:d",titleID
,size
,stmd
,size
);
447 s32
ES_GetNumSharedContents(u32
*cnt
)
452 if(__es_fd
<0) return ES_ENOTINIT
;
453 if(!cnt
) return ES_EINVAL
;
455 ret
= IOS_IoctlvFormat(__es_hid
,__es_fd
,IOCTL_ES_GETSHAREDCONTENTCNT
,":i",&cntct
);
457 if(ret
<0) return ret
;
462 s32
ES_GetSharedContents(sha1
*contents
, u32 cnt
)
464 if(__es_fd
<0) return ES_ENOTINIT
;
465 if(cnt
<= 0) return ES_EINVAL
;
466 if(!contents
) return ES_EINVAL
;
467 if(!ISALIGNED(contents
)) return ES_EALIGN
;
469 return IOS_IoctlvFormat(__es_hid
,__es_fd
,IOCTL_ES_GETSHAREDCONTENTS
,"i:d",cnt
,contents
,sizeof(sha1
)*cnt
);
472 signed_blob
*ES_NextCert(const signed_blob
*certs
)
475 if(!SIGNATURE_SIZE(certs
)) return NULL
;
476 cert
= SIGNATURE_PAYLOAD(certs
);
477 if(!CERTIFICATE_SIZE(cert
)) return NULL
;
478 return (signed_blob
*)(((u8
*)cert
) + CERTIFICATE_SIZE(cert
));
481 s32
__ES_sanity_check_certlist(const signed_blob
*certs
, u32 certsize
)
486 if(!certs
|| !certsize
) return 0;
488 end
= (signed_blob
*)(((u8
*)certs
) + certsize
);
489 while(certs
!= end
) {
491 printf("Checking certificate at %p\n",certs
);
493 certs
= ES_NextCert(certs
);
498 printf("Num of certificates: %d\n",count
);
503 s32
ES_Identify(const signed_blob
*certificates
, u32 certificates_size
, const signed_blob
*stmd
, u32 tmd_size
, const signed_blob
*sticket
, u32 ticket_size
, u32
*keyid
)
511 if(__es_fd
<0) return ES_ENOTINIT
;
513 if(ticket_size
!= STD_SIGNED_TIK_SIZE
) return ES_EINVAL
;
514 if(!stmd
|| !tmd_size
|| !IS_VALID_SIGNATURE(stmd
)) return ES_EINVAL
;
515 if(!sticket
|| !IS_VALID_SIGNATURE(sticket
)) return ES_EINVAL
;
516 if(!__ES_sanity_check_certlist(certificates
, certificates_size
)) return ES_EINVAL
;
517 if(!ISALIGNED(certificates
)) return ES_EALIGN
;
518 if(!ISALIGNED(stmd
)) return ES_EALIGN
;
519 if(!ISALIGNED(sticket
)) return ES_EALIGN
;
520 if(tmd_size
> MAX_SIGNED_TMD_SIZE
) return ES_EINVAL
;
522 p_tmd
= SIGNATURE_PAYLOAD(stmd
);
524 if(!(keyid_buf
= iosAlloc(__es_hid
, 4))) return ES_ENOMEM
;
525 if(!(hashes
= iosAlloc(__es_hid
, p_tmd
->num_contents
*20))) {
526 iosFree(__es_hid
, keyid_buf
);
530 ret
= IOS_IoctlvFormat(__es_hid
, __es_fd
, IOCTL_ES_DIVERIFY
, "dddd:id", certificates
, certificates_size
, 0, 0, sticket
, ticket_size
, stmd
, tmd_size
, keyid_buf
, hashes
, p_tmd
->num_contents
*20);
531 if(ret
>= 0 && keyid
) *keyid
= *keyid_buf
;
533 iosFree(__es_hid
, keyid_buf
);
534 iosFree(__es_hid
, hashes
);
544 s32
ES_AddTicket(const signed_blob
*stik
, u32 stik_size
, const signed_blob
*certificates
, u32 certificates_size
, const signed_blob
*crl
, u32 crl_size
)
548 if(__es_fd
<0) return ES_ENOTINIT
;
549 if(stik_size
!= STD_SIGNED_TIK_SIZE
) return ES_EINVAL
;
550 if(!stik
|| !IS_VALID_SIGNATURE(stik
)) return ES_EINVAL
;
551 if(crl_size
&& (!crl
|| !IS_VALID_SIGNATURE(crl
))) return ES_EINVAL
;
552 if(!__ES_sanity_check_certlist(certificates
, certificates_size
)) return ES_EINVAL
;
553 if(!certificates
|| !ISALIGNED(certificates
)) return ES_EALIGN
;
554 if(!ISALIGNED(stik
)) return ES_EALIGN
;
555 if(!ISALIGNED(certificates
)) return ES_EALIGN
;
556 if(!ISALIGNED(crl
)) return ES_EALIGN
;
558 if(!crl_size
) crl
=NULL
;
560 ret
= IOS_IoctlvFormat(__es_hid
, __es_fd
, IOCTL_ES_ADDTICKET
, "ddd:", stik
, stik_size
, certificates
, certificates_size
, crl
, crl_size
);
565 s32
ES_DeleteTicket(const tikview
*view
)
569 if(__es_fd
<0) return ES_ENOTINIT
;
570 if(!view
) return ES_EINVAL
;
571 if(!ISALIGNED(view
)) return ES_EALIGN
;
572 ret
= IOS_IoctlvFormat(__es_hid
, __es_fd
, IOCTL_ES_DELETETICKET
, "d:", view
, sizeof(tikview
));
576 s32
ES_AddTitleTMD(const signed_blob
*stmd
, u32 stmd_size
)
580 if(__es_fd
<0) return ES_ENOTINIT
;
581 if(!stmd
|| !IS_VALID_SIGNATURE(stmd
)) return ES_EINVAL
;
582 if(stmd_size
!= SIGNED_TMD_SIZE(stmd
)) return ES_EINVAL
;
583 if(!ISALIGNED(stmd
)) return ES_EALIGN
;
585 ret
= IOS_IoctlvFormat(__es_hid
, __es_fd
, IOCTL_ES_ADDTMD
, "d:", stmd
, stmd_size
);
590 s32
ES_AddTitleStart(const signed_blob
*stmd
, u32 tmd_size
, const signed_blob
*certificates
, u32 certificates_size
, const signed_blob
*crl
, u32 crl_size
)
594 if(__es_fd
<0) return ES_ENOTINIT
;
595 if(!stmd
|| !IS_VALID_SIGNATURE(stmd
)) return ES_EINVAL
;
596 if(tmd_size
!= SIGNED_TMD_SIZE(stmd
)) return ES_EINVAL
;
597 if(crl_size
&& (!crl
|| !IS_VALID_SIGNATURE(crl
))) return ES_EINVAL
;
598 if(!__ES_sanity_check_certlist(certificates
, certificates_size
)) return ES_EINVAL
;
599 if(!certificates
|| !ISALIGNED(certificates
)) return ES_EALIGN
;
600 if(!ISALIGNED(stmd
)) return ES_EALIGN
;
601 if(!ISALIGNED(certificates
)) return ES_EALIGN
;
602 if(!ISALIGNED(crl
)) return ES_EALIGN
;
604 if(!crl_size
) crl
=NULL
;
606 ret
= IOS_IoctlvFormat(__es_hid
, __es_fd
, IOCTL_ES_ADDTITLESTART
, "dddi:", stmd
, tmd_size
, certificates
, certificates_size
, crl
, crl_size
, 1);
610 s32
ES_AddContentStart(u64 titleID
, u32 cid
)
612 if(__es_fd
<0) return ES_ENOTINIT
;
613 return IOS_IoctlvFormat(__es_hid
, __es_fd
, IOCTL_ES_ADDCONTENTSTART
, "qi:", titleID
, cid
);
616 s32
ES_AddContentData(s32 cfd
, u8
*data
, u32 data_size
)
618 if(__es_fd
<0) return ES_ENOTINIT
;
619 if(cfd
<0) return ES_EINVAL
;
620 if(!data
|| !data_size
) return ES_EINVAL
;
621 if(!ISALIGNED(data
)) return ES_EALIGN
;
622 return IOS_IoctlvFormat(__es_hid
, __es_fd
, IOCTL_ES_ADDCONTENTDATA
, "id:", cfd
, data
, data_size
);
625 s32
ES_AddContentFinish(u32 cid
)
627 if(__es_fd
<0) return ES_ENOTINIT
;
628 return IOS_IoctlvFormat(__es_hid
, __es_fd
, IOCTL_ES_ADDCONTENTFINISH
, "i:", cid
);
631 s32
ES_AddTitleFinish(void)
633 if(__es_fd
<0) return ES_ENOTINIT
;
634 return IOS_IoctlvFormat(__es_hid
, __es_fd
, IOCTL_ES_ADDTITLEFINISH
, "");
637 s32
ES_AddTitleCancel(void)
639 if(__es_fd
<0) return ES_ENOTINIT
;
640 return IOS_IoctlvFormat(__es_hid
, __es_fd
, IOCTL_ES_ADDTITLECANCEL
, "");
643 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
)
645 if(__es_fd
<0) return ES_ENOTINIT
;
646 if(!tik
|| !tik_size
) return ES_EINVAL
;
647 if(!tik_certs
|| !tik_certs_size
) return ES_EINVAL
;
648 if(!tmd
|| !tmd_size
) return ES_EINVAL
;
649 if(!tmd_certs
|| !tmd_certs_size
) return ES_EINVAL
;
650 if(!content
|| !content_size
) return ES_EINVAL
;
651 if(!ISALIGNED(tik
)) return ES_EALIGN
;
652 if(!ISALIGNED(tmd
)) return ES_EALIGN
;
653 if(!ISALIGNED(tik_certs
)) return ES_EALIGN
;
654 if(!ISALIGNED(tmd_certs
)) return ES_EALIGN
;
655 if(!ISALIGNED(content
)) return ES_EALIGN
;
657 return IOS_IoctlvFormat(__es_hid
, __es_fd
, IOCTL_ES_IMPORTBOOT
, "dddddd:", tik
, tik_size
, tik_certs
, tik_certs_size
, tmd
, tmd_size
, tmd_certs
, tmd_certs_size
, NULL
, 0, content
, content_size
);
660 s32
ES_OpenContent(u16 index
)
662 if(__es_fd
<0) return ES_ENOTINIT
;
663 return IOS_IoctlvFormat(__es_hid
, __es_fd
, IOCTL_ES_OPENCONTENT
, "i:", index
);
666 s32
ES_OpenTitleContent(u64 titleID
, u16 index
)
668 if(__es_fd
<0) return ES_ENOTINIT
;
669 return IOS_IoctlvFormat(__es_hid
, __es_fd
, IOCTL_ES_OPENTITLECONTENT
, "qi:", titleID
, index
);
672 s32
ES_ReadContent(s32 cfd
, u8
*data
, u32 data_size
)
674 if(__es_fd
<0) return ES_ENOTINIT
;
675 if(cfd
<0) return ES_EINVAL
;
676 if(!data
|| !data_size
) return ES_EINVAL
;
677 if(!ISALIGNED(data
)) return ES_EALIGN
;
678 return IOS_IoctlvFormat(__es_hid
, __es_fd
, IOCTL_ES_READCONTENT
, "i:d", cfd
, data
, data_size
);
681 s32
ES_SeekContent(s32 cfd
, s32 where
, s32 whence
)
683 if(__es_fd
<0) return ES_ENOTINIT
;
684 if(cfd
<0) return ES_EINVAL
;
685 return IOS_IoctlvFormat(__es_hid
, __es_fd
, IOCTL_ES_SEEKCONTENT
, "iii:", cfd
, where
, whence
);
688 s32
ES_CloseContent(s32 cfd
)
690 if(__es_fd
<0) return ES_ENOTINIT
;
691 if(cfd
<0) return ES_EINVAL
;
692 return IOS_IoctlvFormat(__es_hid
, __es_fd
, IOCTL_ES_CLOSECONTENT
, "i:", cfd
);
695 s32
ES_DeleteTitle(u64 titleID
)
697 if(__es_fd
<0) return ES_ENOTINIT
;
698 return IOS_IoctlvFormat(__es_hid
, __es_fd
, IOCTL_ES_DELETETITLE
, "q:", titleID
);
701 s32
ES_DeleteTitleContent(u64 titleID
)
703 if(__es_fd
<0) return ES_ENOTINIT
;
704 return IOS_IoctlvFormat(__es_hid
, __es_fd
, IOCTL_ES_DELETETITLECONTENT
, "q:", titleID
);
707 s32
ES_Encrypt(u32 keynum
, u8
*iv
, u8
*source
, u32 size
, u8
*dest
)
709 if(__es_fd
<0) return ES_ENOTINIT
;
710 if(!iv
|| !source
|| !size
|| !dest
) return ES_EINVAL
;
711 if(!ISALIGNED(source
) || !ISALIGNED(iv
) || !ISALIGNED(dest
)) return ES_EALIGN
;
712 return IOS_IoctlvFormat(__es_hid
, __es_fd
, IOCTL_ES_ENCRYPT
, "idd:dd", keynum
, iv
, 0x10, source
, size
, iv
, 0x10, dest
, size
);
715 s32
ES_Decrypt(u32 keynum
, u8
*iv
, u8
*source
, u32 size
, u8
*dest
)
717 if(__es_fd
<0) return ES_ENOTINIT
;
718 if(!iv
|| !source
|| !size
|| !dest
) return ES_EINVAL
;
719 if(!ISALIGNED(source
) || !ISALIGNED(iv
) || !ISALIGNED(dest
)) return ES_EALIGN
;
720 return IOS_IoctlvFormat(__es_hid
, __es_fd
, IOCTL_ES_DECRYPT
, "idd:dd", keynum
, iv
, 0x10, source
, size
, iv
, 0x10, dest
, size
);
723 s32
ES_Sign(u8
*source
, u32 size
, u8
*sig
, u8
*certs
)
725 if(__es_fd
<0) return ES_ENOTINIT
;
726 if(!source
|| !size
|| !sig
|| !certs
) return ES_EINVAL
;
727 if(!ISALIGNED(source
) || !ISALIGNED(sig
) || !ISALIGNED(certs
)) return ES_EALIGN
;
728 return IOS_IoctlvFormat(__es_hid
, __es_fd
, IOCTL_ES_SIGN
, "d:dd", source
, size
, sig
, 0x3C, certs
, 0x180);
731 s32
ES_GetDeviceCert(u8
*outbuf
)
733 if(__es_fd
<0) return ES_ENOTINIT
;
734 if(!outbuf
) return ES_EINVAL
;
735 if(!ISALIGNED(outbuf
)) return ES_EALIGN
;
736 return IOS_IoctlvFormat(__es_hid
, __es_fd
, IOCTL_ES_GETDEVICECERT
, ":d", outbuf
, 0x180);
739 s32
ES_GetDeviceID(u32
*device_id
)
744 if(__es_fd
<0) return ES_ENOTINIT
;
745 if(!device_id
) return ES_EINVAL
;
747 ret
= IOS_IoctlvFormat(__es_hid
, __es_fd
, IOCTL_ES_GETDEVICEID
, ":i", &_device_id
);
748 if (ret
>=0) *device_id
= _device_id
;
753 s32
ES_GetBoot2Version(u32
*version
)
758 if(__es_fd
<0) return ES_ENOTINIT
;
759 if(!version
) return ES_EINVAL
;
761 ret
= IOS_IoctlvFormat(__es_hid
, __es_fd
, IOCTL_ES_GETBOOT2VERSION
, ":i", &_version
);
762 if (ret
>=0) *version
= _version
;
767 // 64k buffer size for alignment
768 #define ES_READ_BUF_SIZE 65536
778 // valid path formats:
779 // format example description
780 // es:%08x es:00000004 Content index for current title ID
781 // es:ID%08x es:ID00000033 Content ID for current title ID
782 // es:%016llx/%08x es:0000000100000002/00000004 Content index for some title ID (not fully implemented yet)
783 // es:%016llx/ID%08x es:0000000100000002/ID00000033 Content ID for some title ID (not fully implemented yet)
784 // leading zeroes may be omitted, 0x prefix allowed. All numbers in hex.
786 static s32
_ES_decodepath (struct _reent
*r
, const char *path
, u64
*titleID
, tmd_content
*content
)
790 STACK_ALIGN(u8
, _tmdbuf
, MAX_SIGNED_TMD_SIZE
, 32);
793 tmd_content
*_contents
;
794 tmd_content _content
;
802 if(strncmp(path
,"es:",3)) {
809 if(ES_GetTitleID(&mytid
) < 0) {
814 // Read in Title ID, if this is an absolute path
822 _tid
= _strtoull_r(r
, path
, &bad
, 16);
823 if(r
->_errno
) return -1;
824 if((bad
== path
) || (bad
[0] != '/')) {
833 // check if path is a content ID
834 if(!strncmp(path
,"ID",2)) {
841 // read in the argument (content ID or content index)
843 arg
= _strtoul_r(r
, path
, &bad
, 16);
844 if(r
->_errno
) return -1;
845 if((bad
== path
) || (bad
[0] != 0)) {
850 // now get the TMD and find the content entry
851 if(ES_GetStoredTMDSize(_tid
, &tmd_size
) < 0) {
856 _stmd
= (signed_blob
*)_tmdbuf
;
857 if(ES_GetStoredTMD(_tid
, _stmd
, tmd_size
) < 0) {
861 if(!IS_VALID_SIGNATURE(_stmd
)) {
865 _tmd
= SIGNATURE_PAYLOAD(_stmd
);
866 _contents
= TMD_CONTENTS(_tmd
);
868 for(i
=0;i
<_tmd
->num_contents
;i
++) {
870 if(_contents
[i
].cid
== arg
) {
871 _content
= _contents
[i
];
875 if(_contents
[i
].index
== arg
) {
876 _content
= _contents
[i
];
881 if(i
>= _tmd
->num_contents
) {
887 if(_tid
== mytid
) *titleID
= 0;
888 else *titleID
= _tid
;
890 if(content
) *content
= _content
;
894 static int _ES_open_r (struct _reent
*r
, void *fileStruct
, const char *path
, int flags
, int mode
) {
895 es_fd
*file
= (es_fd
*) fileStruct
;
898 if(_ES_decodepath(r
, path
, &file
->titleID
, &file
->content
) < 0) {
902 // writing not supported
903 if ((flags
& 0x03) != O_RDONLY
) {
909 if(file
->titleID
== 0)
910 file
->cfd
= ES_OpenContent(file
->content
.index
);
912 file
->cfd
= ES_OpenTitleContent(file
->titleID
, file
->content
.index
);
921 LWP_MutexInit(&file
->mutex
, false);
926 static int _ES_close_r (struct _reent
*r
, int fd
) {
927 es_fd
*file
= (es_fd
*) fd
;
929 LWP_MutexLock(file
->mutex
);
931 if(ES_CloseContent(file
->cfd
) < 0) {
937 if(file
->iobuf
) _free_r(r
,file
->iobuf
);
939 LWP_MutexUnlock(file
->mutex
);
940 LWP_MutexDestroy(file
->mutex
);
944 static int _ES_read_r (struct _reent
*r
, int fd
, char *ptr
, size_t len
) {
945 es_fd
*file
= (es_fd
*) fd
;
950 LWP_MutexLock(file
->mutex
);
952 LWP_MutexUnlock(file
->mutex
);
957 // if aligned, just pass through the read
960 res
= ES_ReadContent(file
->cfd
, (u8
*)ptr
, len
);
962 LWP_MutexUnlock(file
->mutex
);
963 // we don't really know what the error codes mean...
968 // otherwise read in blocks to an aligned buffer
972 file
->iobuf
= _memalign_r(r
, 32, ES_READ_BUF_SIZE
);
979 if(len
> ES_READ_BUF_SIZE
) chunk
= ES_READ_BUF_SIZE
;
981 res
= ES_ReadContent(file
->cfd
, file
->iobuf
, chunk
);
983 LWP_MutexUnlock(file
->mutex
);
984 // we don't really know what the error codes mean...
990 memcpy(ptr
, file
->iobuf
, res
);
992 if(res
< chunk
) break;
996 LWP_MutexUnlock(file
->mutex
);
1000 static off_t
_ES_seek_r (struct _reent
*r
, int fd
, off_t where
, int whence
) {
1001 es_fd
*file
= (es_fd
*) fd
;
1004 LWP_MutexLock(file
->mutex
);
1006 LWP_MutexUnlock(file
->mutex
);
1011 res
= ES_SeekContent(file
->cfd
, where
, whence
);
1012 LWP_MutexUnlock(file
->mutex
);
1021 static void _ES_fillstat(u64 titleID
, tmd_content
*content
, struct stat
*st
) {
1022 memset(st
, 0, sizeof(*st
));
1023 // the inode is the content ID
1024 // (pretend each Title ID is a different filesystem)
1025 st
->st_ino
= content
->cid
;
1026 // st_dev is only a short, so do the best we can and use the middle two letters
1027 // of the title ID if it's not a system content, otherwise use the low 16 bits
1028 if((titleID
>>32) == 1)
1029 st
->st_dev
= titleID
& 0xFFFF;
1031 st
->st_dev
= (titleID
>>8) & 0xFFFF;
1033 // not necessarily true due to shared contents, but
1034 // we're not going to implement shared content scan here and now
1036 // instead, give the file group read permissions if it's a shared content
1037 st
->st_mode
= S_IFREG
| S_IRUSR
;
1038 if(content
->type
& 0x8000)
1039 st
->st_mode
|= S_IRGRP
;
1041 // use st_dev as a uid too, see above
1042 st
->st_uid
= st
->st_dev
;
1046 st
->st_size
= content
->size
;
1047 st
->st_blocks
= (st
->st_size
+ 511) / 512;
1048 // NAND fs cluster size (not like anyone cares, but...)
1049 st
->st_blksize
= 16384;
1052 static int _ES_fstat_r (struct _reent
*r
, int fd
, struct stat
*st
) {
1053 es_fd
*file
= (es_fd
*) fd
;
1055 LWP_MutexLock(file
->mutex
);
1057 LWP_MutexUnlock(file
->mutex
);
1062 _ES_fillstat(file
->titleID
, &file
->content
, st
);
1063 LWP_MutexUnlock(file
->mutex
);
1068 static int _ES_stat_r (struct _reent
*r
, const char *path
, struct stat
*st
) {
1069 tmd_content content
;
1072 if(_ES_decodepath(r
, path
, &titleID
, &content
) < 0) {
1075 _ES_fillstat(titleID
, &content
, st
);
1079 static const devoptab_t dotab_es
= {
1102 static void __ES_InitFS(void) {
1103 AddDevice(&dotab_es
);
1106 static void __ES_DeinitFS(void) {
1110 #endif /* defined(HW_RVL) */