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
, tikview
*views
, u16 index
)
668 if(__es_fd
<0) return ES_ENOTINIT
;
669 if(!ISALIGNED(views
)) return ES_EALIGN
;
670 return IOS_IoctlvFormat(__es_hid
, __es_fd
, IOCTL_ES_OPENTITLECONTENT
, "qdi:", titleID
, views
, sizeof(tikview
), index
);
673 s32
ES_ReadContent(s32 cfd
, u8
*data
, u32 data_size
)
675 if(__es_fd
<0) return ES_ENOTINIT
;
676 if(cfd
<0) return ES_EINVAL
;
677 if(!data
|| !data_size
) return ES_EINVAL
;
678 if(!ISALIGNED(data
)) return ES_EALIGN
;
679 return IOS_IoctlvFormat(__es_hid
, __es_fd
, IOCTL_ES_READCONTENT
, "i:d", cfd
, data
, data_size
);
682 s32
ES_SeekContent(s32 cfd
, s32 where
, s32 whence
)
684 if(__es_fd
<0) return ES_ENOTINIT
;
685 if(cfd
<0) return ES_EINVAL
;
686 return IOS_IoctlvFormat(__es_hid
, __es_fd
, IOCTL_ES_SEEKCONTENT
, "iii:", cfd
, where
, whence
);
689 s32
ES_CloseContent(s32 cfd
)
691 if(__es_fd
<0) return ES_ENOTINIT
;
692 if(cfd
<0) return ES_EINVAL
;
693 return IOS_IoctlvFormat(__es_hid
, __es_fd
, IOCTL_ES_CLOSECONTENT
, "i:", cfd
);
696 s32
ES_DeleteTitle(u64 titleID
)
698 if(__es_fd
<0) return ES_ENOTINIT
;
699 return IOS_IoctlvFormat(__es_hid
, __es_fd
, IOCTL_ES_DELETETITLE
, "q:", titleID
);
702 s32
ES_DeleteTitleContent(u64 titleID
)
704 if(__es_fd
<0) return ES_ENOTINIT
;
705 return IOS_IoctlvFormat(__es_hid
, __es_fd
, IOCTL_ES_DELETETITLECONTENT
, "q:", titleID
);
708 s32
ES_Encrypt(u32 keynum
, u8
*iv
, u8
*source
, u32 size
, u8
*dest
)
710 if(__es_fd
<0) return ES_ENOTINIT
;
711 if(!iv
|| !source
|| !size
|| !dest
) return ES_EINVAL
;
712 if(!ISALIGNED(source
) || !ISALIGNED(iv
) || !ISALIGNED(dest
)) return ES_EALIGN
;
713 return IOS_IoctlvFormat(__es_hid
, __es_fd
, IOCTL_ES_ENCRYPT
, "idd:dd", keynum
, iv
, 0x10, source
, size
, iv
, 0x10, dest
, size
);
716 s32
ES_Decrypt(u32 keynum
, u8
*iv
, u8
*source
, u32 size
, u8
*dest
)
718 if(__es_fd
<0) return ES_ENOTINIT
;
719 if(!iv
|| !source
|| !size
|| !dest
) return ES_EINVAL
;
720 if(!ISALIGNED(source
) || !ISALIGNED(iv
) || !ISALIGNED(dest
)) return ES_EALIGN
;
721 return IOS_IoctlvFormat(__es_hid
, __es_fd
, IOCTL_ES_DECRYPT
, "idd:dd", keynum
, iv
, 0x10, source
, size
, iv
, 0x10, dest
, size
);
724 s32
ES_Sign(u8
*source
, u32 size
, u8
*sig
, u8
*certs
)
726 if(__es_fd
<0) return ES_ENOTINIT
;
727 if(!source
|| !size
|| !sig
|| !certs
) return ES_EINVAL
;
728 if(!ISALIGNED(source
) || !ISALIGNED(sig
) || !ISALIGNED(certs
)) return ES_EALIGN
;
729 return IOS_IoctlvFormat(__es_hid
, __es_fd
, IOCTL_ES_SIGN
, "d:dd", source
, size
, sig
, 0x3C, certs
, 0x180);
732 s32
ES_GetDeviceCert(u8
*outbuf
)
734 if(__es_fd
<0) return ES_ENOTINIT
;
735 if(!outbuf
) return ES_EINVAL
;
736 if(!ISALIGNED(outbuf
)) return ES_EALIGN
;
737 return IOS_IoctlvFormat(__es_hid
, __es_fd
, IOCTL_ES_GETDEVICECERT
, ":d", outbuf
, 0x180);
740 s32
ES_GetDeviceID(u32
*device_id
)
745 if(__es_fd
<0) return ES_ENOTINIT
;
746 if(!device_id
) return ES_EINVAL
;
748 ret
= IOS_IoctlvFormat(__es_hid
, __es_fd
, IOCTL_ES_GETDEVICEID
, ":i", &_device_id
);
749 if (ret
>=0) *device_id
= _device_id
;
754 s32
ES_GetBoot2Version(u32
*version
)
759 if(__es_fd
<0) return ES_ENOTINIT
;
760 if(!version
) return ES_EINVAL
;
762 ret
= IOS_IoctlvFormat(__es_hid
, __es_fd
, IOCTL_ES_GETBOOT2VERSION
, ":i", &_version
);
763 if (ret
>=0) *version
= _version
;
768 // 64k buffer size for alignment
769 #define ES_READ_BUF_SIZE 65536
779 // valid path formats:
780 // format example description
781 // es:%08x es:00000004 Content index for current title ID
782 // es:ID%08x es:ID00000033 Content ID for current title ID
783 // es:%016llx/%08x es:0000000100000002/00000004 Content index for some title ID (not fully implemented yet)
784 // es:%016llx/ID%08x es:0000000100000002/ID00000033 Content ID for some title ID (not fully implemented yet)
785 // leading zeroes may be omitted, 0x prefix allowed. All numbers in hex.
787 static s32
_ES_decodepath (struct _reent
*r
, const char *path
, u64
*titleID
, tmd_content
*content
)
791 STACK_ALIGN(u8
, _tmdbuf
, MAX_SIGNED_TMD_SIZE
, 32);
794 tmd_content
*_contents
;
795 tmd_content _content
;
803 if(strncmp(path
,"es:",3)) {
810 if(ES_GetTitleID(&mytid
) < 0) {
815 // Read in Title ID, if this is an absolute path
823 _tid
= _strtoull_r(r
, path
, &bad
, 16);
824 if(r
->_errno
) return -1;
825 if((bad
== path
) || (bad
[0] != '/')) {
834 // check if path is a content ID
835 if(!strncmp(path
,"ID",2)) {
842 // read in the argument (content ID or content index)
844 arg
= _strtoul_r(r
, path
, &bad
, 16);
845 if(r
->_errno
) return -1;
846 if((bad
== path
) || (bad
[0] != 0)) {
851 // now get the TMD and find the content entry
852 if(ES_GetStoredTMDSize(_tid
, &tmd_size
) < 0) {
857 _stmd
= (signed_blob
*)_tmdbuf
;
858 if(ES_GetStoredTMD(_tid
, _stmd
, tmd_size
) < 0) {
862 if(!IS_VALID_SIGNATURE(_stmd
)) {
866 _tmd
= SIGNATURE_PAYLOAD(_stmd
);
867 _contents
= TMD_CONTENTS(_tmd
);
869 for(i
=0;i
<_tmd
->num_contents
;i
++) {
871 if(_contents
[i
].cid
== arg
) {
872 _content
= _contents
[i
];
876 if(_contents
[i
].index
== arg
) {
877 _content
= _contents
[i
];
882 if(i
>= _tmd
->num_contents
) {
888 if(_tid
== mytid
) *titleID
= 0;
889 else *titleID
= _tid
;
891 if(content
) *content
= _content
;
895 static int _ES_open_r (struct _reent
*r
, void *fileStruct
, const char *path
, int flags
, int mode
) {
896 es_fd
*file
= (es_fd
*) fileStruct
;
899 if(_ES_decodepath(r
, path
, &file
->titleID
, &file
->content
) < 0) {
903 // writing not supported
904 if ((flags
& 0x03) != O_RDONLY
) {
910 if(file
->titleID
== 0)
911 file
->cfd
= ES_OpenContent(file
->content
.index
);
914 u32 cnt
ATTRIBUTE_ALIGN(32);
915 ES_GetNumTicketViews(file
->titleID
, &cnt
);
916 tikview
*views
= (tikview
*)memalign( 32, sizeof(tikview
)*cnt
);
921 ES_GetTicketViews(file
->titleID
, views
, cnt
);
922 file
->cfd
= ES_OpenTitleContent(file
->titleID
, views
, file
->content
.index
);
933 LWP_MutexInit(&file
->mutex
, false);
938 static int _ES_close_r (struct _reent
*r
, int fd
) {
939 es_fd
*file
= (es_fd
*) fd
;
941 LWP_MutexLock(file
->mutex
);
943 if(ES_CloseContent(file
->cfd
) < 0) {
949 if(file
->iobuf
) _free_r(r
,file
->iobuf
);
951 LWP_MutexUnlock(file
->mutex
);
952 LWP_MutexDestroy(file
->mutex
);
956 static int _ES_read_r (struct _reent
*r
, int fd
, char *ptr
, size_t len
) {
957 es_fd
*file
= (es_fd
*) fd
;
962 LWP_MutexLock(file
->mutex
);
964 LWP_MutexUnlock(file
->mutex
);
969 // if aligned, just pass through the read
972 res
= ES_ReadContent(file
->cfd
, (u8
*)ptr
, len
);
974 LWP_MutexUnlock(file
->mutex
);
975 // we don't really know what the error codes mean...
980 // otherwise read in blocks to an aligned buffer
984 file
->iobuf
= _memalign_r(r
, 32, ES_READ_BUF_SIZE
);
991 if(len
> ES_READ_BUF_SIZE
) chunk
= ES_READ_BUF_SIZE
;
993 res
= ES_ReadContent(file
->cfd
, file
->iobuf
, chunk
);
995 LWP_MutexUnlock(file
->mutex
);
996 // we don't really know what the error codes mean...
1002 memcpy(ptr
, file
->iobuf
, res
);
1004 if(res
< chunk
) break;
1008 LWP_MutexUnlock(file
->mutex
);
1012 static off_t
_ES_seek_r (struct _reent
*r
, int fd
, off_t where
, int whence
) {
1013 es_fd
*file
= (es_fd
*) fd
;
1016 LWP_MutexLock(file
->mutex
);
1018 LWP_MutexUnlock(file
->mutex
);
1023 res
= ES_SeekContent(file
->cfd
, where
, whence
);
1024 LWP_MutexUnlock(file
->mutex
);
1033 static void _ES_fillstat(u64 titleID
, tmd_content
*content
, struct stat
*st
) {
1034 memset(st
, 0, sizeof(*st
));
1035 // the inode is the content ID
1036 // (pretend each Title ID is a different filesystem)
1037 st
->st_ino
= content
->cid
;
1038 // st_dev is only a short, so do the best we can and use the middle two letters
1039 // of the title ID if it's not a system content, otherwise use the low 16 bits
1040 if((titleID
>>32) == 1)
1041 st
->st_dev
= titleID
& 0xFFFF;
1043 st
->st_dev
= (titleID
>>8) & 0xFFFF;
1045 // not necessarily true due to shared contents, but
1046 // we're not going to implement shared content scan here and now
1048 // instead, give the file group read permissions if it's a shared content
1049 st
->st_mode
= S_IFREG
| S_IRUSR
;
1050 if(content
->type
& 0x8000)
1051 st
->st_mode
|= S_IRGRP
;
1053 // use st_dev as a uid too, see above
1054 st
->st_uid
= st
->st_dev
;
1058 st
->st_size
= content
->size
;
1059 st
->st_blocks
= (st
->st_size
+ 511) / 512;
1060 // NAND fs cluster size (not like anyone cares, but...)
1061 st
->st_blksize
= 16384;
1064 static int _ES_fstat_r (struct _reent
*r
, int fd
, struct stat
*st
) {
1065 es_fd
*file
= (es_fd
*) fd
;
1067 LWP_MutexLock(file
->mutex
);
1069 LWP_MutexUnlock(file
->mutex
);
1074 _ES_fillstat(file
->titleID
, &file
->content
, st
);
1075 LWP_MutexUnlock(file
->mutex
);
1080 static int _ES_stat_r (struct _reent
*r
, const char *path
, struct stat
*st
) {
1081 tmd_content content
;
1084 if(_ES_decodepath(r
, path
, &titleID
, &content
) < 0) {
1087 _ES_fillstat(titleID
, &content
, st
);
1091 static const devoptab_t dotab_es
= {
1114 static void __ES_InitFS(void) {
1115 AddDevice(&dotab_es
);
1118 static void __ES_DeinitFS(void) {
1119 RemoveDevice("es:");
1122 #endif /* defined(HW_RVL) */