1 /*-------------------------------------------------------------
3 es.c -- ETicket services
6 Michael Wiedenbauer (shagkur)
7 Dave Murphy (WinterMute)
11 This software is provided 'as-is', without any express or implied
12 warranty. In no event will the authors be held liable for any
13 damages arising from the use of this software.
15 Permission is granted to anyone to use this software for any
16 purpose, including commercial applications, and to alter it and
17 redistribute it freely, subject to the following restrictions:
19 1. The origin of this software must not be misrepresented; you
20 must not claim that you wrote the original software. If you use
21 this software in a product, an acknowledgment in the product
22 documentation would be appreciated but is not required.
24 2. Altered source versions must be plainly marked as such, and
25 must not be misrepresented as being the original software.
27 3. This notice may not be removed or altered from any source
30 -------------------------------------------------------------*/
34 #include <sys/iosupport.h>
35 #include <sys/fcntl.h>
40 #include <sys/errno.h>
43 #include "processor.h"
49 #define IOCTL_ES_ADDTICKET 0x01
50 #define IOCTL_ES_ADDTITLESTART 0x02
51 #define IOCTL_ES_ADDCONTENTSTART 0x03
52 #define IOCTL_ES_ADDCONTENTDATA 0x04
53 #define IOCTL_ES_ADDCONTENTFINISH 0x05
54 #define IOCTL_ES_ADDTITLEFINISH 0x06
55 #define IOCTL_ES_GETDEVICEID 0x07
56 #define IOCTL_ES_LAUNCH 0x08
57 #define IOCTL_ES_OPENCONTENT 0x09
58 #define IOCTL_ES_READCONTENT 0x0A
59 #define IOCTL_ES_CLOSECONTENT 0x0B
60 #define IOCTL_ES_GETOWNEDTITLECNT 0x0C
61 #define IOCTL_ES_GETOWNEDTITLES 0x0D
62 #define IOCTL_ES_GETTITLECNT 0x0E
63 #define IOCTL_ES_GETTITLES 0x0F
64 #define IOCTL_ES_GETTITLECONTENTSCNT 0x10
65 #define IOCTL_ES_GETTITLECONTENTS 0x11
66 #define IOCTL_ES_GETVIEWCNT 0x12
67 #define IOCTL_ES_GETVIEWS 0x13
68 #define IOCTL_ES_GETTMDVIEWCNT 0x14
69 #define IOCTL_ES_GETTMDVIEWS 0x15
70 //#define IOCTL_ES_GETCONSUMPTION 0x16
71 #define IOCTL_ES_DELETETITLE 0x17
72 #define IOCTL_ES_DELETETICKET 0x18
73 //#define IOCTL_ES_DIGETTMDVIEWSIZE 0x19
74 //#define IOCTL_ES_DIGETTMDVIEW 0x1A
75 //#define IOCTL_ES_DIGETTICKETVIEW 0x1B
76 #define IOCTL_ES_DIVERIFY 0x1C
77 #define IOCTL_ES_GETTITLEDIR 0x1D
78 #define IOCTL_ES_GETDEVICECERT 0x1E
79 #define IOCTL_ES_IMPORTBOOT 0x1F
80 #define IOCTL_ES_GETTITLEID 0x20
81 #define IOCTL_ES_SETUID 0x21
82 #define IOCTL_ES_DELETETITLECONTENT 0x22
83 #define IOCTL_ES_SEEKCONTENT 0x23
84 #define IOCTL_ES_OPENTITLECONTENT 0x24
85 //#define IOCTL_ES_LAUNCHBC 0x25
86 //#define IOCTL_ES_EXPORTTITLEINIT 0x26
87 //#define IOCTL_ES_EXPORTCONTENTBEGIN 0x27
88 //#define IOCTL_ES_EXPORTCONTENTDATA 0x28
89 //#define IOCTL_ES_EXPORTCONTENTEND 0x29
90 //#define IOCTL_ES_EXPORTTITLEDONE 0x2A
91 #define IOCTL_ES_ADDTMD 0x2B
92 #define IOCTL_ES_ENCRYPT 0x2C
93 #define IOCTL_ES_DECRYPT 0x2D
94 #define IOCTL_ES_GETBOOT2VERSION 0x2E
95 #define IOCTL_ES_ADDTITLECANCEL 0x2F
96 #define IOCTL_ES_SIGN 0x30
97 //#define IOCTL_ES_VERIFYSIGN 0x31
98 #define IOCTL_ES_GETSTOREDCONTENTCNT 0x32
99 #define IOCTL_ES_GETSTOREDCONTENTS 0x33
100 #define IOCTL_ES_GETSTOREDTMDSIZE 0x34
101 #define IOCTL_ES_GETSTOREDTMD 0x35
102 #define IOCTL_ES_GETSHAREDCONTENTCNT 0x36
103 #define IOCTL_ES_GETSHAREDCONTENTS 0x37
106 #define ES_HEAP_SIZE 0x800
108 #define ISALIGNED(x) ((((u32)x)&0x1F)==0)
110 static char __es_fs
[] ATTRIBUTE_ALIGN(32) = "/dev/es";
112 static s32 __es_fd
= -1;
113 static s32 __es_hid
= -1;
115 static void __ES_InitFS(void);
116 static void __ES_DeinitFS(void);
127 __es_hid
= iosCreateHeap(ES_HEAP_SIZE
);
133 ret
= IOS_Open(__es_fs
,0);
140 printf("ES FD %d\n",__es_fd
);
152 if(__es_fd
< 0) return 0;
156 ret
= IOS_Close(__es_fd
);
166 // Used by ios.c after reloading IOS
173 s32
ES_GetTitleID(u64
*titleID
)
178 if(__es_fd
<0) return ES_ENOTINIT
;
179 if(!titleID
) return ES_EINVAL
;
181 ret
= IOS_IoctlvFormat(__es_hid
,__es_fd
,IOCTL_ES_GETTITLEID
,":q",&title
);
182 if(ret
<0) return ret
;
188 s32
ES_SetUID(u64 uid
)
190 if(__es_fd
<0) return ES_ENOTINIT
;
192 return IOS_IoctlvFormat(__es_hid
,__es_fd
,IOCTL_ES_SETUID
,"q:",uid
);
195 s32
ES_GetDataDir(u64 titleID
,char *filepath
)
199 if(__es_fd
<0) return ES_ENOTINIT
;
200 if(!filepath
) return ES_EINVAL
;
201 if(!ISALIGNED(filepath
)) return ES_EALIGN
;
203 ret
= IOS_IoctlvFormat(__es_hid
,__es_fd
,IOCTL_ES_GETTITLEDIR
,"q:d",titleID
,filepath
,30);
208 s32
ES_LaunchTitle(u64 titleID
, const tikview
*view
)
212 STACK_ALIGN(u64
,title
,1,32);
213 STACK_ALIGN(ioctlv
,vectors
,2,32);
215 if(__es_fd
<0) return ES_ENOTINIT
;
216 if(!view
) return ES_EINVAL
;
217 if(!ISALIGNED(view
)) return ES_EALIGN
;
220 printf("ES LaunchTitle %d %016llx 0x%08x 0x%02x\n",__es_fd
,titleID
,(u32
)view
,sizeof(tikview
));
225 vectors
[0].data
= (void*)title
;
226 vectors
[0].len
= sizeof(u64
);
227 vectors
[1].data
= (void*)view
;
228 vectors
[1].len
= sizeof(tikview
);
229 res
= IOS_IoctlvReboot(__es_fd
,IOCTL_ES_LAUNCH
,2,0,vectors
);
232 printf(" =%d\n",res
);
238 s32
ES_LaunchTitleBackground(u64 titleID
, const tikview
*view
)
242 STACK_ALIGN(u64
,title
,1,32);
243 STACK_ALIGN(ioctlv
,vectors
,2,32);
245 if(__es_fd
<0) return ES_ENOTINIT
;
246 if(!view
) return ES_EINVAL
;
247 if(!ISALIGNED(view
)) return ES_EALIGN
;
250 printf("ES LaunchTitleBackground %d %016llx 0x%08x 0x%02x\n",__es_fd
,titleID
,(u32
)view
,sizeof(tikview
));
254 vectors
[0].data
= (void*)title
;
255 vectors
[0].len
= sizeof(u64
);
256 vectors
[1].data
= (void*)view
;
257 vectors
[1].len
= sizeof(tikview
);
258 res
= IOS_IoctlvRebootBackground(__es_fd
,IOCTL_ES_LAUNCH
,2,0,vectors
);
261 printf(" =%d\n",res
);
267 s32
ES_GetNumTicketViews(u64 titleID
, u32
*cnt
)
272 if(__es_fd
<0) return ES_ENOTINIT
;
273 if(!cnt
) return ES_EINVAL
;
275 ret
= IOS_IoctlvFormat(__es_hid
,__es_fd
,IOCTL_ES_GETVIEWCNT
,"q:i",titleID
,&cntviews
);
277 if(ret
<0) return ret
;
282 s32
ES_GetTicketViews(u64 titleID
, tikview
*views
, u32 cnt
)
284 if(__es_fd
<0) return ES_ENOTINIT
;
285 if(cnt
<= 0) return ES_EINVAL
;
286 if(!views
) return ES_EINVAL
;
287 if(!ISALIGNED(views
)) return ES_EALIGN
;
289 return IOS_IoctlvFormat(__es_hid
,__es_fd
,IOCTL_ES_GETVIEWS
,"qi:d",titleID
,cnt
,views
,sizeof(tikview
)*cnt
);
292 s32
ES_GetNumOwnedTitles(u32
*cnt
)
297 if(__es_fd
<0) return ES_ENOTINIT
;
298 if(cnt
== NULL
) return ES_EINVAL
;
300 ret
= IOS_IoctlvFormat(__es_hid
,__es_fd
,IOCTL_ES_GETOWNEDTITLECNT
,":i",&cnttitles
);
302 if(ret
<0) return ret
;
307 s32
ES_GetOwnedTitles(u64
*titles
, u32 cnt
)
309 if(__es_fd
<0) return ES_ENOTINIT
;
310 if(cnt
<= 0) return ES_EINVAL
;
311 if(!titles
) return ES_EINVAL
;
312 if(!ISALIGNED(titles
)) return ES_EALIGN
;
314 return IOS_IoctlvFormat(__es_hid
,__es_fd
,IOCTL_ES_GETOWNEDTITLES
,"i:d",cnt
,titles
,sizeof(u64
)*cnt
);
317 s32
ES_GetNumTitles(u32
*cnt
)
322 if(__es_fd
<0) return ES_ENOTINIT
;
323 if(cnt
== NULL
) return ES_EINVAL
;
325 ret
= IOS_IoctlvFormat(__es_hid
,__es_fd
,IOCTL_ES_GETTITLECNT
,":i",&cnttitles
);
327 if(ret
<0) return ret
;
332 s32
ES_GetTitles(u64
*titles
, u32 cnt
)
334 if(__es_fd
<0) return ES_ENOTINIT
;
335 if(cnt
<= 0) return ES_EINVAL
;
336 if(!titles
) return ES_EINVAL
;
337 if(!ISALIGNED(titles
)) return ES_EALIGN
;
339 return IOS_IoctlvFormat(__es_hid
,__es_fd
,IOCTL_ES_GETTITLES
,"i:d",cnt
,titles
,sizeof(u64
)*cnt
);
342 s32
ES_GetNumStoredTMDContents(const signed_blob
*stmd
, u32 tmd_size
, u32
*cnt
)
347 if(__es_fd
<0) return ES_ENOTINIT
;
348 if(!cnt
) return ES_EINVAL
;
349 if(!stmd
|| !IS_VALID_SIGNATURE(stmd
)) return ES_EINVAL
;
350 if(!ISALIGNED(stmd
)) return ES_EALIGN
;
352 ret
= IOS_IoctlvFormat(__es_hid
,__es_fd
,IOCTL_ES_GETSTOREDCONTENTCNT
,"d:i",stmd
,tmd_size
,&cntct
);
354 if(ret
<0) return ret
;
359 s32
ES_GetStoredTMDContents(const signed_blob
*stmd
, u32 tmd_size
, u32
*contents
, u32 cnt
)
361 if(__es_fd
<0) return ES_ENOTINIT
;
362 if(cnt
<= 0) return ES_EINVAL
;
363 if(!contents
) return ES_EINVAL
;
364 if(!stmd
|| !IS_VALID_SIGNATURE(stmd
)) return ES_EINVAL
;
365 if(!ISALIGNED(stmd
)) return ES_EALIGN
;
366 if(!ISALIGNED(contents
)) return ES_EALIGN
;
367 if(tmd_size
> MAX_SIGNED_TMD_SIZE
) return ES_EINVAL
;
369 return IOS_IoctlvFormat(__es_hid
,__es_fd
,IOCTL_ES_GETSTOREDCONTENTS
,"di:d",stmd
,tmd_size
,cnt
,contents
,sizeof(u32
)*cnt
);
372 s32
ES_GetTitleContentsCount(u64 titleID
, u32
*num
)
377 if(__es_fd
<0) return ES_ENOTINIT
;
378 if(!num
) return ES_EINVAL
;
380 ret
= IOS_IoctlvFormat(__es_hid
,__es_fd
,IOCTL_ES_GETTITLECONTENTSCNT
,"q:i",titleID
,&_num
);
382 if(ret
<0) return ret
;
387 s32
ES_GetTitleContents(u64 titleID
, u8
*data
, u32 size
)
389 if(__es_fd
<0) return ES_ENOTINIT
;
390 if(size
<= 0) return ES_EINVAL
;
391 if(!data
) return ES_EINVAL
;
392 if(!ISALIGNED(data
)) return ES_EALIGN
;
394 return IOS_IoctlvFormat(__es_hid
,__es_fd
,IOCTL_ES_GETSTOREDTMD
,"qi:d",titleID
,size
,data
,size
);
397 s32
ES_GetTMDViewSize(u64 titleID
, u32
*size
)
402 if(__es_fd
<0) return ES_ENOTINIT
;
403 if(!size
) return ES_EINVAL
;
405 ret
= IOS_IoctlvFormat(__es_hid
,__es_fd
,IOCTL_ES_GETTMDVIEWCNT
,"q:i",titleID
,&tmdsize
);
407 if(ret
<0) return ret
;
412 s32
ES_GetTMDView(u64 titleID
, u8
*data
, u32 size
)
414 if(__es_fd
<0) return ES_ENOTINIT
;
415 if(size
<= 0) return ES_EINVAL
;
416 if(!data
) return ES_EINVAL
;
417 if(!ISALIGNED(data
)) return ES_EALIGN
;
419 return IOS_IoctlvFormat(__es_hid
,__es_fd
,IOCTL_ES_GETTMDVIEWS
,"qi:d",titleID
,size
,data
,size
);
422 s32
ES_GetStoredTMDSize(u64 titleID
, u32
*size
)
427 if(__es_fd
<0) return ES_ENOTINIT
;
428 if(!size
) return ES_EINVAL
;
430 ret
= IOS_IoctlvFormat(__es_hid
,__es_fd
,IOCTL_ES_GETSTOREDTMDSIZE
,"q:i",titleID
,&tmdsize
);
432 if(ret
<0) return ret
;
437 s32
ES_GetStoredTMD(u64 titleID
, signed_blob
*stmd
, u32 size
)
439 if(__es_fd
<0) return ES_ENOTINIT
;
440 if(size
<= 0) return ES_EINVAL
;
441 if(!stmd
) return ES_EINVAL
;
442 if(!ISALIGNED(stmd
)) return ES_EALIGN
;
443 if(size
> MAX_SIGNED_TMD_SIZE
) return ES_EINVAL
;
445 return IOS_IoctlvFormat(__es_hid
,__es_fd
,IOCTL_ES_GETSTOREDTMD
,"qi:d",titleID
,size
,stmd
,size
);
448 s32
ES_GetNumSharedContents(u32
*cnt
)
453 if(__es_fd
<0) return ES_ENOTINIT
;
454 if(!cnt
) return ES_EINVAL
;
456 ret
= IOS_IoctlvFormat(__es_hid
,__es_fd
,IOCTL_ES_GETSHAREDCONTENTCNT
,":i",&cntct
);
458 if(ret
<0) return ret
;
463 s32
ES_GetSharedContents(sha1
*contents
, u32 cnt
)
465 if(__es_fd
<0) return ES_ENOTINIT
;
466 if(cnt
<= 0) return ES_EINVAL
;
467 if(!contents
) return ES_EINVAL
;
468 if(!ISALIGNED(contents
)) return ES_EALIGN
;
470 return IOS_IoctlvFormat(__es_hid
,__es_fd
,IOCTL_ES_GETSHAREDCONTENTS
,"i:d",cnt
,contents
,sizeof(sha1
)*cnt
);
473 signed_blob
*ES_NextCert(const signed_blob
*certs
)
476 if(!SIGNATURE_SIZE(certs
)) return NULL
;
477 cert
= SIGNATURE_PAYLOAD(certs
);
478 if(!CERTIFICATE_SIZE(cert
)) return NULL
;
479 return (signed_blob
*)(((u8
*)cert
) + CERTIFICATE_SIZE(cert
));
482 s32
__ES_sanity_check_certlist(const signed_blob
*certs
, u32 certsize
)
487 if(!certs
|| !certsize
) return 0;
489 end
= (signed_blob
*)(((u8
*)certs
) + certsize
);
490 while(certs
!= end
) {
492 printf("Checking certificate at %p\n",certs
);
494 certs
= ES_NextCert(certs
);
499 printf("Num of certificates: %d\n",count
);
504 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
)
512 if(__es_fd
<0) return ES_ENOTINIT
;
514 if(ticket_size
!= STD_SIGNED_TIK_SIZE
) return ES_EINVAL
;
515 if(!stmd
|| !tmd_size
|| !IS_VALID_SIGNATURE(stmd
)) return ES_EINVAL
;
516 if(!sticket
|| !IS_VALID_SIGNATURE(sticket
)) return ES_EINVAL
;
517 if(!__ES_sanity_check_certlist(certificates
, certificates_size
)) return ES_EINVAL
;
518 if(!ISALIGNED(certificates
)) return ES_EALIGN
;
519 if(!ISALIGNED(stmd
)) return ES_EALIGN
;
520 if(!ISALIGNED(sticket
)) return ES_EALIGN
;
521 if(tmd_size
> MAX_SIGNED_TMD_SIZE
) return ES_EINVAL
;
523 p_tmd
= SIGNATURE_PAYLOAD(stmd
);
525 if(!(keyid_buf
= iosAlloc(__es_hid
, 4))) return ES_ENOMEM
;
526 if(!(hashes
= iosAlloc(__es_hid
, p_tmd
->num_contents
*20))) {
527 iosFree(__es_hid
, keyid_buf
);
531 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);
532 if(ret
>= 0 && keyid
) *keyid
= *keyid_buf
;
534 iosFree(__es_hid
, keyid_buf
);
535 iosFree(__es_hid
, hashes
);
545 s32
ES_AddTicket(const signed_blob
*stik
, u32 stik_size
, const signed_blob
*certificates
, u32 certificates_size
, const signed_blob
*crl
, u32 crl_size
)
549 if(__es_fd
<0) return ES_ENOTINIT
;
550 if(stik_size
!= STD_SIGNED_TIK_SIZE
) return ES_EINVAL
;
551 if(!stik
|| !IS_VALID_SIGNATURE(stik
)) return ES_EINVAL
;
552 if(crl_size
&& (!crl
|| !IS_VALID_SIGNATURE(crl
))) return ES_EINVAL
;
553 if(!__ES_sanity_check_certlist(certificates
, certificates_size
)) return ES_EINVAL
;
554 if(!certificates
|| !ISALIGNED(certificates
)) return ES_EALIGN
;
555 if(!ISALIGNED(stik
)) return ES_EALIGN
;
556 if(!ISALIGNED(certificates
)) return ES_EALIGN
;
557 if(!ISALIGNED(crl
)) return ES_EALIGN
;
559 if(!crl_size
) crl
=NULL
;
561 ret
= IOS_IoctlvFormat(__es_hid
, __es_fd
, IOCTL_ES_ADDTICKET
, "ddd:", stik
, stik_size
, certificates
, certificates_size
, crl
, crl_size
);
566 s32
ES_DeleteTicket(const tikview
*view
)
570 if(__es_fd
<0) return ES_ENOTINIT
;
571 if(!view
) return ES_EINVAL
;
572 if(!ISALIGNED(view
)) return ES_EALIGN
;
573 ret
= IOS_IoctlvFormat(__es_hid
, __es_fd
, IOCTL_ES_DELETETICKET
, "d:", view
, sizeof(tikview
));
577 s32
ES_AddTitleTMD(const signed_blob
*stmd
, u32 stmd_size
)
581 if(__es_fd
<0) return ES_ENOTINIT
;
582 if(!stmd
|| !IS_VALID_SIGNATURE(stmd
)) return ES_EINVAL
;
583 if(stmd_size
!= SIGNED_TMD_SIZE(stmd
)) return ES_EINVAL
;
584 if(!ISALIGNED(stmd
)) return ES_EALIGN
;
586 ret
= IOS_IoctlvFormat(__es_hid
, __es_fd
, IOCTL_ES_ADDTMD
, "d:", stmd
, stmd_size
);
591 s32
ES_AddTitleStart(const signed_blob
*stmd
, u32 tmd_size
, const signed_blob
*certificates
, u32 certificates_size
, const signed_blob
*crl
, u32 crl_size
)
595 if(__es_fd
<0) return ES_ENOTINIT
;
596 if(!stmd
|| !IS_VALID_SIGNATURE(stmd
)) return ES_EINVAL
;
597 if(tmd_size
!= SIGNED_TMD_SIZE(stmd
)) return ES_EINVAL
;
598 if(crl_size
&& (!crl
|| !IS_VALID_SIGNATURE(crl
))) return ES_EINVAL
;
599 if(!__ES_sanity_check_certlist(certificates
, certificates_size
)) return ES_EINVAL
;
600 if(!certificates
|| !ISALIGNED(certificates
)) return ES_EALIGN
;
601 if(!ISALIGNED(stmd
)) return ES_EALIGN
;
602 if(!ISALIGNED(certificates
)) return ES_EALIGN
;
603 if(!ISALIGNED(crl
)) return ES_EALIGN
;
605 if(!crl_size
) crl
=NULL
;
607 ret
= IOS_IoctlvFormat(__es_hid
, __es_fd
, IOCTL_ES_ADDTITLESTART
, "dddi:", stmd
, tmd_size
, certificates
, certificates_size
, crl
, crl_size
, 1);
611 s32
ES_AddContentStart(u64 titleID
, u32 cid
)
613 if(__es_fd
<0) return ES_ENOTINIT
;
614 return IOS_IoctlvFormat(__es_hid
, __es_fd
, IOCTL_ES_ADDCONTENTSTART
, "qi:", titleID
, cid
);
617 s32
ES_AddContentData(s32 cfd
, u8
*data
, u32 data_size
)
619 if(__es_fd
<0) return ES_ENOTINIT
;
620 if(cfd
<0) return ES_EINVAL
;
621 if(!data
|| !data_size
) return ES_EINVAL
;
622 if(!ISALIGNED(data
)) return ES_EALIGN
;
623 return IOS_IoctlvFormat(__es_hid
, __es_fd
, IOCTL_ES_ADDCONTENTDATA
, "id:", cfd
, data
, data_size
);
626 s32
ES_AddContentFinish(u32 cid
)
628 if(__es_fd
<0) return ES_ENOTINIT
;
629 return IOS_IoctlvFormat(__es_hid
, __es_fd
, IOCTL_ES_ADDCONTENTFINISH
, "i:", cid
);
632 s32
ES_AddTitleFinish(void)
634 if(__es_fd
<0) return ES_ENOTINIT
;
635 return IOS_IoctlvFormat(__es_hid
, __es_fd
, IOCTL_ES_ADDTITLEFINISH
, "");
638 s32
ES_AddTitleCancel(void)
640 if(__es_fd
<0) return ES_ENOTINIT
;
641 return IOS_IoctlvFormat(__es_hid
, __es_fd
, IOCTL_ES_ADDTITLECANCEL
, "");
644 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
)
646 if(__es_fd
<0) return ES_ENOTINIT
;
647 if(!tik
|| !tik_size
) return ES_EINVAL
;
648 if(!tik_certs
|| !tik_certs_size
) return ES_EINVAL
;
649 if(!tmd
|| !tmd_size
) return ES_EINVAL
;
650 if(!tmd_certs
|| !tmd_certs_size
) return ES_EINVAL
;
651 if(!content
|| !content_size
) return ES_EINVAL
;
652 if(!ISALIGNED(tik
)) return ES_EALIGN
;
653 if(!ISALIGNED(tmd
)) return ES_EALIGN
;
654 if(!ISALIGNED(tik_certs
)) return ES_EALIGN
;
655 if(!ISALIGNED(tmd_certs
)) return ES_EALIGN
;
656 if(!ISALIGNED(content
)) return ES_EALIGN
;
658 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
);
661 s32
ES_OpenContent(u16 index
)
663 if(__es_fd
<0) return ES_ENOTINIT
;
664 return IOS_IoctlvFormat(__es_hid
, __es_fd
, IOCTL_ES_OPENCONTENT
, "i:", index
);
667 s32
ES_OpenTitleContent(u64 titleID
, tikview
*views
, u16 index
)
669 if(__es_fd
<0) return ES_ENOTINIT
;
670 if(!ISALIGNED(views
)) return ES_EALIGN
;
671 return IOS_IoctlvFormat(__es_hid
, __es_fd
, IOCTL_ES_OPENTITLECONTENT
, "qdi:", titleID
, views
, sizeof(tikview
), index
);
674 s32
ES_ReadContent(s32 cfd
, u8
*data
, u32 data_size
)
676 if(__es_fd
<0) return ES_ENOTINIT
;
677 if(cfd
<0) return ES_EINVAL
;
678 if(!data
|| !data_size
) return ES_EINVAL
;
679 if(!ISALIGNED(data
)) return ES_EALIGN
;
680 return IOS_IoctlvFormat(__es_hid
, __es_fd
, IOCTL_ES_READCONTENT
, "i:d", cfd
, data
, data_size
);
683 s32
ES_SeekContent(s32 cfd
, s32 where
, s32 whence
)
685 if(__es_fd
<0) return ES_ENOTINIT
;
686 if(cfd
<0) return ES_EINVAL
;
687 return IOS_IoctlvFormat(__es_hid
, __es_fd
, IOCTL_ES_SEEKCONTENT
, "iii:", cfd
, where
, whence
);
690 s32
ES_CloseContent(s32 cfd
)
692 if(__es_fd
<0) return ES_ENOTINIT
;
693 if(cfd
<0) return ES_EINVAL
;
694 return IOS_IoctlvFormat(__es_hid
, __es_fd
, IOCTL_ES_CLOSECONTENT
, "i:", cfd
);
697 s32
ES_DeleteTitle(u64 titleID
)
699 if(__es_fd
<0) return ES_ENOTINIT
;
700 return IOS_IoctlvFormat(__es_hid
, __es_fd
, IOCTL_ES_DELETETITLE
, "q:", titleID
);
703 s32
ES_DeleteTitleContent(u64 titleID
)
705 if(__es_fd
<0) return ES_ENOTINIT
;
706 return IOS_IoctlvFormat(__es_hid
, __es_fd
, IOCTL_ES_DELETETITLECONTENT
, "q:", titleID
);
709 s32
ES_Encrypt(u32 keynum
, u8
*iv
, u8
*source
, u32 size
, u8
*dest
)
711 if(__es_fd
<0) return ES_ENOTINIT
;
712 if(!iv
|| !source
|| !size
|| !dest
) return ES_EINVAL
;
713 if(!ISALIGNED(source
) || !ISALIGNED(iv
) || !ISALIGNED(dest
)) return ES_EALIGN
;
714 return IOS_IoctlvFormat(__es_hid
, __es_fd
, IOCTL_ES_ENCRYPT
, "idd:dd", keynum
, iv
, 0x10, source
, size
, iv
, 0x10, dest
, size
);
717 s32
ES_Decrypt(u32 keynum
, u8
*iv
, u8
*source
, u32 size
, u8
*dest
)
719 if(__es_fd
<0) return ES_ENOTINIT
;
720 if(!iv
|| !source
|| !size
|| !dest
) return ES_EINVAL
;
721 if(!ISALIGNED(source
) || !ISALIGNED(iv
) || !ISALIGNED(dest
)) return ES_EALIGN
;
722 return IOS_IoctlvFormat(__es_hid
, __es_fd
, IOCTL_ES_DECRYPT
, "idd:dd", keynum
, iv
, 0x10, source
, size
, iv
, 0x10, dest
, size
);
725 s32
ES_Sign(u8
*source
, u32 size
, u8
*sig
, u8
*certs
)
727 if(__es_fd
<0) return ES_ENOTINIT
;
728 if(!source
|| !size
|| !sig
|| !certs
) return ES_EINVAL
;
729 if(!ISALIGNED(source
) || !ISALIGNED(sig
) || !ISALIGNED(certs
)) return ES_EALIGN
;
730 return IOS_IoctlvFormat(__es_hid
, __es_fd
, IOCTL_ES_SIGN
, "d:dd", source
, size
, sig
, 0x3C, certs
, 0x180);
733 s32
ES_GetDeviceCert(u8
*outbuf
)
735 if(__es_fd
<0) return ES_ENOTINIT
;
736 if(!outbuf
) return ES_EINVAL
;
737 if(!ISALIGNED(outbuf
)) return ES_EALIGN
;
738 return IOS_IoctlvFormat(__es_hid
, __es_fd
, IOCTL_ES_GETDEVICECERT
, ":d", outbuf
, 0x180);
741 s32
ES_GetDeviceID(u32
*device_id
)
746 if(__es_fd
<0) return ES_ENOTINIT
;
747 if(!device_id
) return ES_EINVAL
;
749 ret
= IOS_IoctlvFormat(__es_hid
, __es_fd
, IOCTL_ES_GETDEVICEID
, ":i", &_device_id
);
750 if (ret
>=0) *device_id
= _device_id
;
755 s32
ES_GetBoot2Version(u32
*version
)
760 if(__es_fd
<0) return ES_ENOTINIT
;
761 if(!version
) return ES_EINVAL
;
763 ret
= IOS_IoctlvFormat(__es_hid
, __es_fd
, IOCTL_ES_GETBOOT2VERSION
, ":i", &_version
);
764 if (ret
>=0) *version
= _version
;
769 // 64k buffer size for alignment
770 #define ES_READ_BUF_SIZE 65536
780 // valid path formats:
781 // format example description
782 // es:%08x es:00000004 Content index for current title ID
783 // es:ID%08x es:ID00000033 Content ID for current title ID
784 // es:%016llx/%08x es:0000000100000002/00000004 Content index for some title ID (not fully implemented yet)
785 // es:%016llx/ID%08x es:0000000100000002/ID00000033 Content ID for some title ID (not fully implemented yet)
786 // leading zeroes may be omitted, 0x prefix allowed. All numbers in hex.
788 static s32
_ES_decodepath (struct _reent
*r
, const char *path
, u64
*titleID
, tmd_content
*content
)
792 STACK_ALIGN(u8
, _tmdbuf
, MAX_SIGNED_TMD_SIZE
, 32);
795 tmd_content
*_contents
;
796 tmd_content _content
;
804 if(strncmp(path
,"es:",3)) {
811 if(ES_GetTitleID(&mytid
) < 0) {
816 // Read in Title ID, if this is an absolute path
824 _tid
= _strtoull_r(r
, path
, &bad
, 16);
825 if(r
->_errno
) return -1;
826 if((bad
== path
) || (bad
[0] != '/')) {
835 // check if path is a content ID
836 if(!strncmp(path
,"ID",2)) {
843 // read in the argument (content ID or content index)
845 arg
= _strtoul_r(r
, path
, &bad
, 16);
846 if(r
->_errno
) return -1;
847 if((bad
== path
) || (bad
[0] != 0)) {
852 // now get the TMD and find the content entry
853 if(ES_GetStoredTMDSize(_tid
, &tmd_size
) < 0) {
858 _stmd
= (signed_blob
*)_tmdbuf
;
859 if(ES_GetStoredTMD(_tid
, _stmd
, tmd_size
) < 0) {
863 if(!IS_VALID_SIGNATURE(_stmd
)) {
867 _tmd
= SIGNATURE_PAYLOAD(_stmd
);
868 _contents
= TMD_CONTENTS(_tmd
);
870 for(i
=0;i
<_tmd
->num_contents
;i
++) {
872 if(_contents
[i
].cid
== arg
) {
873 _content
= _contents
[i
];
877 if(_contents
[i
].index
== arg
) {
878 _content
= _contents
[i
];
883 if(i
>= _tmd
->num_contents
) {
889 if(_tid
== mytid
) *titleID
= 0;
890 else *titleID
= _tid
;
892 if(content
) *content
= _content
;
896 static int _ES_open_r (struct _reent
*r
, void *fileStruct
, const char *path
, int flags
, int mode
) {
897 es_fd
*file
= (es_fd
*) fileStruct
;
900 if(_ES_decodepath(r
, path
, &file
->titleID
, &file
->content
) < 0) {
904 // writing not supported
905 if ((flags
& 0x03) != O_RDONLY
) {
911 if(file
->titleID
== 0)
912 file
->cfd
= ES_OpenContent(file
->content
.index
);
915 u32 cnt
ATTRIBUTE_ALIGN(32);
916 ES_GetNumTicketViews(file
->titleID
, &cnt
);
917 tikview
*views
= (tikview
*)memalign( 32, sizeof(tikview
)*cnt
);
922 ES_GetTicketViews(file
->titleID
, views
, cnt
);
923 file
->cfd
= ES_OpenTitleContent(file
->titleID
, views
, file
->content
.index
);
934 LWP_MutexInit(&file
->mutex
, false);
939 static int _ES_close_r (struct _reent
*r
, int fd
) {
940 es_fd
*file
= (es_fd
*) fd
;
942 LWP_MutexLock(file
->mutex
);
944 if(ES_CloseContent(file
->cfd
) < 0) {
950 if(file
->iobuf
) _free_r(r
,file
->iobuf
);
952 LWP_MutexUnlock(file
->mutex
);
953 LWP_MutexDestroy(file
->mutex
);
957 static int _ES_read_r (struct _reent
*r
, int fd
, char *ptr
, size_t len
) {
958 es_fd
*file
= (es_fd
*) fd
;
963 LWP_MutexLock(file
->mutex
);
965 LWP_MutexUnlock(file
->mutex
);
970 // if aligned, just pass through the read
973 res
= ES_ReadContent(file
->cfd
, (u8
*)ptr
, len
);
975 LWP_MutexUnlock(file
->mutex
);
976 // we don't really know what the error codes mean...
981 // otherwise read in blocks to an aligned buffer
985 file
->iobuf
= _memalign_r(r
, 32, ES_READ_BUF_SIZE
);
992 if(len
> ES_READ_BUF_SIZE
) chunk
= ES_READ_BUF_SIZE
;
994 res
= ES_ReadContent(file
->cfd
, file
->iobuf
, chunk
);
996 LWP_MutexUnlock(file
->mutex
);
997 // we don't really know what the error codes mean...
1003 memcpy(ptr
, file
->iobuf
, res
);
1005 if(res
< chunk
) break;
1009 LWP_MutexUnlock(file
->mutex
);
1013 static off_t
_ES_seek_r (struct _reent
*r
, int fd
, off_t where
, int whence
) {
1014 es_fd
*file
= (es_fd
*) fd
;
1017 LWP_MutexLock(file
->mutex
);
1019 LWP_MutexUnlock(file
->mutex
);
1024 res
= ES_SeekContent(file
->cfd
, where
, whence
);
1025 LWP_MutexUnlock(file
->mutex
);
1034 static void _ES_fillstat(u64 titleID
, tmd_content
*content
, struct stat
*st
) {
1035 memset(st
, 0, sizeof(*st
));
1036 // the inode is the content ID
1037 // (pretend each Title ID is a different filesystem)
1038 st
->st_ino
= content
->cid
;
1039 // st_dev is only a short, so do the best we can and use the middle two letters
1040 // of the title ID if it's not a system content, otherwise use the low 16 bits
1041 if((titleID
>>32) == 1)
1042 st
->st_dev
= titleID
& 0xFFFF;
1044 st
->st_dev
= (titleID
>>8) & 0xFFFF;
1046 // not necessarily true due to shared contents, but
1047 // we're not going to implement shared content scan here and now
1049 // instead, give the file group read permissions if it's a shared content
1050 st
->st_mode
= S_IFREG
| S_IRUSR
;
1051 if(content
->type
& 0x8000)
1052 st
->st_mode
|= S_IRGRP
;
1054 // use st_dev as a uid too, see above
1055 st
->st_uid
= st
->st_dev
;
1059 st
->st_size
= content
->size
;
1060 st
->st_blocks
= (st
->st_size
+ 511) / 512;
1061 // NAND fs cluster size (not like anyone cares, but...)
1062 st
->st_blksize
= 16384;
1065 static int _ES_fstat_r (struct _reent
*r
, int fd
, struct stat
*st
) {
1066 es_fd
*file
= (es_fd
*) fd
;
1068 LWP_MutexLock(file
->mutex
);
1070 LWP_MutexUnlock(file
->mutex
);
1075 _ES_fillstat(file
->titleID
, &file
->content
, st
);
1076 LWP_MutexUnlock(file
->mutex
);
1081 static int _ES_stat_r (struct _reent
*r
, const char *path
, struct stat
*st
) {
1082 tmd_content content
;
1085 if(_ES_decodepath(r
, path
, &titleID
, &content
) < 0) {
1088 _ES_fillstat(titleID
, &content
, st
);
1092 static const devoptab_t dotab_es
= {
1115 static void __ES_InitFS(void) {
1116 AddDevice(&dotab_es
);
1119 static void __ES_DeinitFS(void) {
1120 RemoveDevice("es:");
1123 #endif /* defined(HW_RVL) */