Add COPYING file
[ps3tools.git] / makeself.c
blob487cd930d7492a26775f53e25b62a1da53f5d193
1 // Copyright 2010 Sven Peter <svenpeter@gmail.com>
2 // Licensed under the terms of the GNU GPL, version 2
3 // http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt
5 #include "tools.h"
6 #include "types.h"
8 #include <stdio.h>
9 #include <string.h>
10 #include <stdlib.h>
11 #include <limits.h>
12 #include <sys/stat.h>
13 #include <zlib.h>
15 #define ALIGNMENT 0x20
16 #define MAX_PHDR 255
18 static u8 *elf = NULL;
19 static u8 *self = NULL;
21 static enum sce_key type;
23 struct elf_hdr ehdr;
24 struct elf_phdr phdr[MAX_PHDR];
25 static int arch64;
27 static u8 sce_header[0x70];
28 static u8 info_header[0x20];
29 static u8 ctrl_header[0x70];
30 static u8 version_header[0x10];
32 static u8 *sec_header;
33 static u32 sec_header_size;
35 static u8 *meta_header;
36 static u32 meta_header_size;
38 static u64 header_size;
39 static u32 meta_offset;
40 static u64 elf_size;
41 static u64 compressed_size;
42 static u64 info_offset;
43 static u64 version_offset;
44 static u64 elf_offset;
45 static u64 phdr_offset;
46 static u64 shdr_offset;
47 static u64 sec_offset;
48 static u64 ctrl_offset;
49 static u64 version;
50 static u64 auth_id;
51 static u64 vendor_id;
52 static u16 sdk_type;
54 struct key ks;
56 static const char *elf_name = NULL;
57 static const char *self_name = NULL;
58 static int compression = 0;
60 static struct {
61 u64 offset;
62 u64 size;
63 u8 *ptr;
64 int compressed;
65 } phdr_map[MAX_PHDR];
67 static void get_type(const char *p)
69 if (strncmp(p, "lv0", 4) == 0)
70 type = KEY_LV0;
71 else if (strncmp(p, "lv1", 4) == 0)
72 type = KEY_LV1;
73 else if (strncmp(p, "lv2", 4) == 0)
74 type = KEY_LV2;
75 else if (strncmp(p, "iso", 4) == 0)
76 type = KEY_ISO;
77 else if (strncmp(p, "app", 4) == 0)
78 type = KEY_APP;
79 else if (strncmp(p, "ldr", 4) == 0)
80 type = KEY_LDR;
81 else
82 fail("invalid type: %s", p);
85 static void get_keys(const char *suffix)
87 if (key_get(type, suffix, &ks) < 0)
88 fail("key_get failed");
90 if (ks.pub_avail < 0)
91 fail("no public key available");
93 if (ks.priv_avail < 0)
94 fail("no private key available");
96 if (ecdsa_set_curve(ks.ctype) < 0)
97 fail("ecdsa_set_curve failed");
99 ecdsa_set_pub(ks.pub);
100 ecdsa_set_priv(ks.priv);
103 static void parse_elf(void)
105 u32 i;
107 arch64 = elf_read_hdr(elf, &ehdr);
109 for (i = 0; i < ehdr.e_phnum; i++)
110 elf_read_phdr(arch64, elf + ehdr.e_phoff + i * ehdr.e_phentsize, &phdr[i]);
113 static void build_sce_hdr(void)
115 memset(sce_header, 0, sizeof sce_header);
117 wbe32(sce_header + 0x00, 0x53434500); // magic
118 wbe32(sce_header + 0x04, 2); // version
119 wbe16(sce_header + 0x08, sdk_type); // dunno, sdk type?
120 wbe16(sce_header + 0x0a, 1); // SCE header type; self
121 wbe32(sce_header + 0x0c, meta_offset);
122 wbe64(sce_header + 0x10, header_size);
123 wbe64(sce_header + 0x18, round_up(elf_size, ALIGNMENT));
124 wbe64(sce_header + 0x20, 3); // dunno, has to be 3
125 wbe64(sce_header + 0x28, info_offset);
126 wbe64(sce_header + 0x30, elf_offset);
127 wbe64(sce_header + 0x38, phdr_offset);
128 wbe64(sce_header + 0x40, shdr_offset);
129 wbe64(sce_header + 0x48, sec_offset);
130 wbe64(sce_header + 0x50, version_offset);
131 wbe64(sce_header + 0x58, ctrl_offset);
132 wbe64(sce_header + 0x60, 0x70); // ctrl size
135 static void build_version_hdr(void)
137 memset(version_header, 0, sizeof version_header);
138 wbe32(version_header, 1);
139 wbe32(version_header + 0x08, 0x10);
142 static void build_info_hdr(void)
144 u32 app_type;
146 memset(info_header, 0, sizeof info_header);
148 switch (type) {
149 case KEY_LV0:
150 app_type = 1;
151 break;
152 case KEY_LV1:
153 app_type = 2;
154 break;
155 case KEY_LV2:
156 app_type = 3;
157 break;
158 case KEY_APP:
159 app_type = 4;
160 break;
161 case KEY_ISO:
162 app_type = 5;
163 break;
164 case KEY_LDR:
165 app_type = 6;
166 break;
167 default:
168 fail("something that should never fail failed.");
171 wbe64(info_header + 0x00, auth_id);
172 wbe32(info_header + 0x08, vendor_id);
173 wbe32(info_header + 0x0c, app_type);
174 wbe64(info_header + 0x10, version); // version 1.0.0
177 static void build_ctrl_hdr(void)
179 memset(ctrl_header, 0, sizeof ctrl_header);
181 wbe32(ctrl_header + 0x00, 1); // type: control flags
182 wbe32(ctrl_header + 0x04, 0x30); // length
183 // flags are all zero here
185 wbe32(ctrl_header + 0x30, 2); // type: digest
186 wbe32(ctrl_header + 0x34, 0x40); // length
189 static void build_sec_hdr(void)
191 u32 i;
192 u8 *ptr;
194 sec_header_size = ehdr.e_phnum * 0x20;
195 sec_header = malloc(sec_header_size);
197 memset(sec_header, 0, sec_header_size);
199 for (i = 0; i < ehdr.e_phnum; i++) {
200 ptr = sec_header + i * 0x20;
202 wbe64(ptr + 0x00, phdr_map[i].offset);
203 wbe64(ptr + 0x08, phdr_map[i].size);
205 if (phdr_map[i].compressed == 1)
206 wbe32(ptr + 0x10, 2);
207 else
208 wbe32(ptr + 0x10, 1);
210 wbe32(ptr + 0x14, 0); // unknown
211 wbe32(ptr + 0x18, 0); // unknown
213 if (phdr[i].p_type == 1)
214 wbe32(ptr + 0x1c, 1); // encrypted LOAD phdr
215 else
216 wbe32(ptr + 0x1c, 0); // no loadable phdr
220 static void meta_add_phdr(u8 *ptr, u32 i)
222 wbe64(ptr + 0x00, phdr_map[i].offset);
223 wbe64(ptr + 0x08, phdr_map[i].size);
225 // unknown
226 wbe32(ptr + 0x10, 2);
227 wbe32(ptr + 0x14, i); // phdr index maybe?
228 wbe32(ptr + 0x18, 2);
230 wbe32(ptr + 0x1c, i*8); // sha index
231 wbe32(ptr + 0x20, 1); // not encpryted
232 wbe32(ptr + 0x24, 0xffffffff); // no key
233 wbe32(ptr + 0x28, 0xffffffff); // no iv
234 wbe32(ptr + 0x2c, 1); // not compressed
237 static void meta_add_load(u8 *ptr, u32 i)
239 wbe64(ptr + 0x00, phdr_map[i].offset);
240 wbe64(ptr + 0x08, phdr_map[i].size);
242 // unknown
243 wbe32(ptr + 0x10, 2);
244 wbe32(ptr + 0x14, i); // phdr index maybe?
245 wbe32(ptr + 0x18, 2);
247 wbe32(ptr + 0x1c, i*8); // sha index
248 wbe32(ptr + 0x20, 3); // phdr is encrypted
249 wbe32(ptr + 0x24, (i*8) + 6); // key index
250 wbe32(ptr + 0x28, (i*8) + 7); // iv index
252 if (phdr_map[i].compressed == 1)
253 wbe32(ptr + 0x2c, 2);
254 else
255 wbe32(ptr + 0x2c, 1);
258 static void build_meta_hdr(void)
260 u32 i;
261 u8 *ptr;
263 meta_header_size = 0x80 + ehdr.e_phnum * (0x30 + 0x20 + 0x60) + 0x30;
264 meta_header = malloc(meta_header_size);
265 memset(meta_header, 0, meta_header_size);
267 ptr = meta_header + 0x20;
269 // aes keys for meta encryption
270 get_rand(ptr, 0x10);
271 get_rand(ptr + 0x20, 0x10);
272 ptr += 0x40;
274 // area covered by the signature
275 wbe64(ptr + 0x00, meta_offset + meta_header_size - 0x30);
277 wbe32(ptr + 0x08, 1);
278 wbe32(ptr + 0x0c, ehdr.e_phnum); // number of encrypted headers
279 wbe32(ptr + 0x10, ehdr.e_phnum * 8); // number of keys/hashes required
280 wbe32(ptr + 0x14, meta_header_size / 0x10);
281 ptr += 0x20;
283 // add encrypted phdr information
284 for (i = 0; i < ehdr.e_phnum; i++) {
285 if (phdr[i].p_type == 1)
286 meta_add_load(ptr, i);
287 else
288 meta_add_phdr(ptr, i);
290 ptr += 0x30;
293 // add keys/ivs and hmac keys
294 get_rand(ptr, ehdr.e_phnum * 8 * 0x10);
297 static void calculate_hashes(void)
299 u32 i;
300 u8 *keys;
302 keys = self + meta_offset + 0x80 + (0x30 * ehdr.e_phnum);
304 for (i = 0; i < ehdr.e_phnum; i++) {
305 memset(keys + (i * 8 * 0x10), 0, 0x20);
306 sha1_hmac(keys + ((i * 8) + 2) * 0x10,
307 self + phdr_map[i].offset,
308 phdr_map[i].size,
309 keys + (i * 8) * 0x10
314 static void build_hdr(void)
316 memcpy(self, sce_header, sizeof sce_header);
317 memcpy(self + info_offset, info_header, sizeof info_header);
318 memcpy(self + version_offset, version_header, sizeof version_header);
319 memcpy(self + ctrl_offset, ctrl_header, sizeof ctrl_header);
320 memcpy(self + sec_offset, sec_header, sec_header_size);
321 memcpy(self + phdr_offset, elf + ehdr.e_phoff, ehdr.e_phnum * ehdr.e_phentsize);
322 // memcpy(self + shdr_offset, elf + ehdr.e_shoff, ehdr.e_shnum * ehdr.e_shentsize);
323 memcpy(self + meta_offset, meta_header, meta_header_size);
324 memcpy(self + elf_offset, elf, ehdr.e_ehsize);
327 static void write_elf(void)
329 u32 i;
331 if (compression) {
332 for (i = 0; i < ehdr.e_phnum; i++) {
333 memcpy(self + phdr_map[i].offset,
334 phdr_map[i].ptr,
335 phdr_map[i].size);
337 memcpy(self + shdr_offset, elf + ehdr.e_shoff, ehdr.e_shnum * ehdr.e_shentsize);
338 } else {
339 memcpy(self + header_size, elf, elf_size);
343 static void compress_elf(void)
345 u32 i;
346 u64 offset;
347 uLongf size_zlib;
348 int res;
349 u64 size_compressed;
351 offset = header_size;
353 for (i = 0; i < ehdr.e_phnum; i++) {
354 phdr_map[i].offset = offset;
356 if (phdr[i].p_type != 1) {
357 phdr_map[i].ptr = elf + phdr[i].p_off;
358 phdr_map[i].size = phdr[i].p_filesz;
359 phdr_map[i].compressed = 0;
360 offset = round_up(offset + phdr[i].p_filesz, 0x20);
361 continue;
364 size_compressed = compressBound(phdr[i].p_filesz);
365 size_zlib = size_compressed;
367 phdr_map[i].ptr = malloc(size_compressed);
368 if (!phdr_map[i].ptr)
369 fail("out of memory");
371 res = compress(phdr_map[i].ptr, &size_zlib,
372 elf + phdr[i].p_off, phdr[i].p_filesz);
374 if (size_zlib >= phdr[i].p_filesz) {
375 free(phdr_map[i].ptr);
376 phdr_map[i].ptr = elf + phdr[i].p_off;
377 phdr_map[i].size = phdr[i].p_filesz;
378 phdr_map[i].compressed = 0;
379 offset = round_up(offset + phdr[i].p_filesz, ALIGNMENT);
380 } else {
381 phdr_map[i].ptr = realloc(phdr_map[i].ptr, size_zlib);
382 if (phdr_map[i].ptr == NULL)
383 fail("out of memory");
385 phdr_map[i].size = size_zlib;
386 phdr_map[i].compressed = 1;
387 offset = round_up(offset + phdr_map[i].size, ALIGNMENT);
391 compressed_size = phdr_map[i - 1].offset + phdr_map[i - 1].size;
392 shdr_offset = compressed_size;
393 compressed_size += ehdr.e_shentsize * ehdr.e_shnum;
396 static void fill_phdr_map(void)
398 u32 i;
400 memset(phdr_map, 0, sizeof phdr_map);
402 for (i = 0; i < ehdr.e_phnum; i++) {
403 phdr_map[i].offset = phdr[i].p_off + header_size;
404 phdr_map[i].size = phdr[i].p_filesz;
405 phdr_map[i].compressed = 0;
406 phdr[i].ptr = NULL;
409 compressed_size = elf_size;
410 shdr_offset = ehdr.e_shoff + header_size;
413 static void sign_hdr(void)
415 u8 *r, *s;
416 u8 hash[20];
417 u64 sig_len;
419 sig_len = be64(self + meta_offset + 0x60);
420 r = self + sig_len;
421 s = r + 21;
423 sha1(self, sig_len, hash);
425 ecdsa_sign(hash, r, s);
428 static u64 get_filesize(const char *path)
430 struct stat st;
432 stat(path, &st);
434 return st.st_size;
437 static void get_version(const char *v)
439 u8 *ptr;
440 u32 i;
441 u32 maj, min, rev;
442 u32 tmp;
444 i = 0;
445 maj = min = rev = tmp = 0;
446 ptr = (u8 *)v;
447 while (*ptr) {
448 if (i > 2) {
449 fprintf(stderr, "WARNING: invalid sdk_version, using 1.0.0\n");
450 version = 1ULL << 48;
451 return;
454 if (*ptr == '.') {
455 if (i == 0)
456 maj = tmp;
457 else if (i == 1)
458 min = tmp;
459 else if (i == 2)
460 rev = tmp;
461 i++;
462 ptr++;
463 tmp = 0;
464 continue;
467 if (*ptr >= '0' && *ptr <= '9') {
468 tmp <<= 4;
469 tmp += *ptr - '0';
470 ptr++;
471 continue;
474 fprintf(stderr, "WARNING: invalid sdk_version, using 1.0.0\n");
475 version = 1ULL << 48;
476 return;
479 if (i == 2)
480 rev = tmp;
482 version = ((u64)maj & 0xffff) << 48;
483 version |= ((u64)min & 0xffff) << 32;
484 version |= rev;
487 static void get_vendor(char *v)
489 vendor_id = strtoull(v, NULL, 16);
492 static void get_auth(char *a)
494 auth_id = strtoull(a, NULL, 16);
497 static void get_sdktype(char * t)
499 sdk_type = strtoul(t, NULL, 10);
502 static void get_args(int argc, char *argv[])
504 u32 i;
506 if (argc != 9 && argc != 10)
507 fail("usage: makeself [-c] [type] [version suffix] [version] [vendor id] [auth id] [sdk type] [elf] [self]");
509 i = 1;
511 if (argc == 10) {
512 if (strcmp(argv[1], "-c") != 0)
513 fail("invalid option: %s", argv[1]);
514 compression = 1;
515 i++;
518 get_type(argv[i++]);
519 get_keys(argv[i++]);
520 get_version(argv[i++]);
521 get_vendor(argv[i++]);
522 get_auth(argv[i++]);
523 get_sdktype(argv[i++]);
525 elf_name = argv[i++];
526 self_name = argv[i++];
528 if (compression) {
529 if (type == KEY_ISO)
530 fail("no compression support for isolated modules");
531 if (type == KEY_LDR)
532 fail("no compression support for secure loaders");
537 int main(int argc, char *argv[])
539 FILE *fp;
540 u8 bfr[ALIGNMENT];
542 get_args(argc, argv);
544 elf_size = get_filesize(elf_name);
545 elf = mmap_file(elf_name);
547 parse_elf();
549 meta_header_size = 0x80 + ehdr.e_phnum * (0x30 + 0x20 + 0x60) + 0x30;
550 info_offset = 0x70;
551 elf_offset = 0x90;
552 phdr_offset = elf_offset + ehdr.e_ehsize;
553 sec_offset = round_up(phdr_offset + ehdr.e_phentsize * ehdr.e_phnum, ALIGNMENT);
554 version_offset = round_up(sec_offset + ehdr.e_phnum * 0x20, ALIGNMENT);
555 ctrl_offset = round_up(version_offset + 0x10, ALIGNMENT);
556 meta_offset = round_up(ctrl_offset + 0x70, ALIGNMENT);
557 header_size = round_up(meta_offset + meta_header_size, 0x80);
559 if (compression)
560 compress_elf();
561 else
562 fill_phdr_map();
564 build_sce_hdr();
565 build_info_hdr();
566 build_ctrl_hdr();
567 build_sec_hdr();
568 build_version_hdr();
569 build_meta_hdr();
571 self = malloc(header_size + elf_size);
572 memset(self, 0, header_size + elf_size);
574 build_hdr();
575 write_elf();
576 calculate_hashes();
577 sign_hdr();
579 sce_encrypt_data(self);
580 sce_encrypt_header(self, &ks);
582 fp = fopen(self_name, "wb");
583 if (fp == NULL)
584 fail("fopen(%s) failed", self_name);
586 if (fwrite(self, header_size + compressed_size, 1, fp) != 1)
587 fail("unable to write self");
589 memset(bfr, 0, sizeof bfr);
590 fwrite(bfr, round_up(compressed_size, ALIGNMENT) - compressed_size, 1, fp);
592 fclose(fp);
594 return 0;