]> git.saurik.com Git - ldid.git/blob - ldid.cpp
Add a flag for checkra1n that does codesign -dvvv.
[ldid.git] / ldid.cpp
1 /* ldid - (Mach-O) Link-Loader Identity Editor
2 * Copyright (C) 2007-2015 Jay Freeman (saurik)
3 */
4
5 /* GNU Affero General Public License, Version 3 {{{ */
6 /*
7 * This program is free software: you can redistribute it and/or modify
8 * it under the terms of the GNU Affero General Public License as published by
9 * the Free Software Foundation, either version 3 of the License, or
10 * (at your option) any later version.
11
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU Affero General Public License for more details.
16
17 * You should have received a copy of the GNU Affero General Public License
18 * along with this program. If not, see <http://www.gnu.org/licenses/>.
19 **/
20 /* }}} */
21
22 #include <cstdio>
23 #include <cstdlib>
24 #include <cstring>
25 #include <fstream>
26 #include <iostream>
27 #include <memory>
28 #include <set>
29 #include <sstream>
30 #include <string>
31 #include <vector>
32
33 #include <dirent.h>
34 #include <errno.h>
35 #include <fcntl.h>
36 #include <regex.h>
37 #include <stdbool.h>
38 #include <stdint.h>
39 #include <unistd.h>
40
41 #include <sys/mman.h>
42 #include <sys/stat.h>
43 #include <sys/types.h>
44
45 #ifndef LDID_NOSMIME
46 #include <openssl/err.h>
47 #include <openssl/pem.h>
48 #include <openssl/pkcs7.h>
49 #include <openssl/pkcs12.h>
50 #endif
51
52 #ifdef __APPLE__
53 #include <CommonCrypto/CommonDigest.h>
54
55 #define LDID_SHA1_DIGEST_LENGTH CC_SHA1_DIGEST_LENGTH
56 #define LDID_SHA1 CC_SHA1
57 #define LDID_SHA1_CTX CC_SHA1_CTX
58 #define LDID_SHA1_Init CC_SHA1_Init
59 #define LDID_SHA1_Update CC_SHA1_Update
60 #define LDID_SHA1_Final CC_SHA1_Final
61
62 #define LDID_SHA256_DIGEST_LENGTH CC_SHA256_DIGEST_LENGTH
63 #define LDID_SHA256 CC_SHA256
64 #define LDID_SHA256_CTX CC_SHA256_CTX
65 #define LDID_SHA256_Init CC_SHA256_Init
66 #define LDID_SHA256_Update CC_SHA256_Update
67 #define LDID_SHA256_Final CC_SHA256_Final
68 #else
69 #include <openssl/sha.h>
70
71 #define LDID_SHA1_DIGEST_LENGTH SHA_DIGEST_LENGTH
72 #define LDID_SHA1 SHA1
73 #define LDID_SHA1_CTX SHA_CTX
74 #define LDID_SHA1_Init SHA1_Init
75 #define LDID_SHA1_Update SHA1_Update
76 #define LDID_SHA1_Final SHA1_Final
77
78 #define LDID_SHA256_DIGEST_LENGTH SHA256_DIGEST_LENGTH
79 #define LDID_SHA256 SHA256
80 #define LDID_SHA256_CTX SHA256_CTX
81 #define LDID_SHA256_Init SHA256_Init
82 #define LDID_SHA256_Update SHA256_Update
83 #define LDID_SHA256_Final SHA256_Final
84 #endif
85
86 #ifndef LDID_NOPLIST
87 #include <plist/plist.h>
88 #elif __APPLE__
89 #include <CoreFoundation/CoreFoundation.h>
90 #endif
91
92 #include "ldid.hpp"
93
94 #define _assert___(line) \
95 #line
96 #define _assert__(line) \
97 _assert___(line)
98
99 #ifndef $
100 #define $(value) value
101 #endif
102
103 #ifdef __EXCEPTIONS
104 #define _assert_(expr, format, ...) \
105 do if (!(expr)) { \
106 fprintf(stderr, $("%s(%u): _assert(): " format "\n"), __FILE__, __LINE__, ## __VA_ARGS__); \
107 throw $(__FILE__ "(" _assert__(__LINE__) "): _assert(" #expr ")"); \
108 } while (false)
109 #else
110 // XXX: this is not acceptable
111 #define _assert_(expr, format, ...) \
112 do if (!(expr)) { \
113 fprintf(stderr, $("%s(%u): _assert(): " format "\n"), __FILE__, __LINE__, ## __VA_ARGS__); \
114 exit(-1); \
115 } while (false)
116 #endif
117
118 #define _assert(expr) \
119 _assert_(expr, "%s", $(#expr))
120
121 #define _syscall(expr, ...) [&] { for (;;) { \
122 auto _value(expr); \
123 if ((long) _value != -1) \
124 return _value; \
125 int error(errno); \
126 if (error == EINTR) \
127 continue; \
128 /* XXX: EINTR is included in this list to fix g++ */ \
129 for (auto success : (long[]) {EINTR, __VA_ARGS__}) \
130 if (error == success) \
131 return (decltype(expr)) -success; \
132 _assert_(false, "errno=%u", error); \
133 } }()
134
135 #define _trace() \
136 fprintf(stderr, $("_trace(%s:%u): %s\n"), __FILE__, __LINE__, $(__FUNCTION__))
137
138 #define _not(type) \
139 ((type) ~ (type) 0)
140
141 #define _packed \
142 __attribute__((packed))
143
144 template <typename Type_>
145 struct Iterator_ {
146 typedef typename Type_::const_iterator Result;
147 };
148
149 #define _foreach(item, list) \
150 for (bool _stop(true); _stop; ) \
151 for (const __typeof__(list) &_list = (list); _stop; _stop = false) \
152 for (Iterator_<__typeof__(list)>::Result _item = _list.begin(); _item != _list.end(); ++_item) \
153 for (bool _suck(true); _suck; _suck = false) \
154 for (const __typeof__(*_item) &item = *_item; _suck; _suck = false)
155
156 class _Scope {
157 };
158
159 template <typename Function_>
160 class Scope :
161 public _Scope
162 {
163 private:
164 Function_ function_;
165
166 public:
167 Scope(const Function_ &function) :
168 function_(function)
169 {
170 }
171
172 ~Scope() {
173 function_();
174 }
175 };
176
177 template <typename Function_>
178 Scope<Function_> _scope(const Function_ &function) {
179 return Scope<Function_>(function);
180 }
181
182 #define _scope__(counter, function) \
183 __attribute__((__unused__)) \
184 const _Scope &_scope ## counter(_scope([&]function))
185 #define _scope_(counter, function) \
186 _scope__(counter, function)
187 #define _scope(function) \
188 _scope_(__COUNTER__, function)
189
190 #define CPU_ARCH_MASK uint32_t(0xff000000)
191 #define CPU_ARCH_ABI64 uint32_t(0x01000000)
192
193 #define CPU_TYPE_ANY uint32_t(-1)
194 #define CPU_TYPE_VAX uint32_t( 1)
195 #define CPU_TYPE_MC680x0 uint32_t( 6)
196 #define CPU_TYPE_X86 uint32_t( 7)
197 #define CPU_TYPE_MC98000 uint32_t(10)
198 #define CPU_TYPE_HPPA uint32_t(11)
199 #define CPU_TYPE_ARM uint32_t(12)
200 #define CPU_TYPE_MC88000 uint32_t(13)
201 #define CPU_TYPE_SPARC uint32_t(14)
202 #define CPU_TYPE_I860 uint32_t(15)
203 #define CPU_TYPE_POWERPC uint32_t(18)
204
205 #define CPU_TYPE_I386 CPU_TYPE_X86
206
207 #define CPU_TYPE_ARM64 (CPU_ARCH_ABI64 | CPU_TYPE_ARM)
208 #define CPU_TYPE_POWERPC64 (CPU_ARCH_ABI64 | CPU_TYPE_POWERPC)
209 #define CPU_TYPE_X86_64 (CPU_ARCH_ABI64 | CPU_TYPE_X86)
210
211 struct fat_header {
212 uint32_t magic;
213 uint32_t nfat_arch;
214 } _packed;
215
216 #define FAT_MAGIC 0xcafebabe
217 #define FAT_CIGAM 0xbebafeca
218
219 struct fat_arch {
220 uint32_t cputype;
221 uint32_t cpusubtype;
222 uint32_t offset;
223 uint32_t size;
224 uint32_t align;
225 } _packed;
226
227 struct mach_header {
228 uint32_t magic;
229 uint32_t cputype;
230 uint32_t cpusubtype;
231 uint32_t filetype;
232 uint32_t ncmds;
233 uint32_t sizeofcmds;
234 uint32_t flags;
235 } _packed;
236
237 #define MH_MAGIC 0xfeedface
238 #define MH_CIGAM 0xcefaedfe
239
240 #define MH_MAGIC_64 0xfeedfacf
241 #define MH_CIGAM_64 0xcffaedfe
242
243 #define MH_DYLDLINK 0x4
244
245 #define MH_OBJECT 0x1
246 #define MH_EXECUTE 0x2
247 #define MH_DYLIB 0x6
248 #define MH_DYLINKER 0x7
249 #define MH_BUNDLE 0x8
250 #define MH_DYLIB_STUB 0x9
251
252 struct load_command {
253 uint32_t cmd;
254 uint32_t cmdsize;
255 } _packed;
256
257 #define LC_REQ_DYLD uint32_t(0x80000000)
258
259 #define LC_SEGMENT uint32_t(0x01)
260 #define LC_SYMTAB uint32_t(0x02)
261 #define LC_DYSYMTAB uint32_t(0x0b)
262 #define LC_LOAD_DYLIB uint32_t(0x0c)
263 #define LC_ID_DYLIB uint32_t(0x0d)
264 #define LC_SEGMENT_64 uint32_t(0x19)
265 #define LC_UUID uint32_t(0x1b)
266 #define LC_CODE_SIGNATURE uint32_t(0x1d)
267 #define LC_SEGMENT_SPLIT_INFO uint32_t(0x1e)
268 #define LC_REEXPORT_DYLIB uint32_t(0x1f | LC_REQ_DYLD)
269 #define LC_ENCRYPTION_INFO uint32_t(0x21)
270 #define LC_DYLD_INFO uint32_t(0x22)
271 #define LC_DYLD_INFO_ONLY uint32_t(0x22 | LC_REQ_DYLD)
272 #define LC_ENCRYPTION_INFO_64 uint32_t(0x2c)
273
274 union Version {
275 struct {
276 uint8_t patch;
277 uint8_t minor;
278 uint16_t major;
279 } _packed;
280
281 uint32_t value;
282 };
283
284 struct dylib {
285 uint32_t name;
286 uint32_t timestamp;
287 uint32_t current_version;
288 uint32_t compatibility_version;
289 } _packed;
290
291 struct dylib_command {
292 uint32_t cmd;
293 uint32_t cmdsize;
294 struct dylib dylib;
295 } _packed;
296
297 struct uuid_command {
298 uint32_t cmd;
299 uint32_t cmdsize;
300 uint8_t uuid[16];
301 } _packed;
302
303 struct symtab_command {
304 uint32_t cmd;
305 uint32_t cmdsize;
306 uint32_t symoff;
307 uint32_t nsyms;
308 uint32_t stroff;
309 uint32_t strsize;
310 } _packed;
311
312 struct dyld_info_command {
313 uint32_t cmd;
314 uint32_t cmdsize;
315 uint32_t rebase_off;
316 uint32_t rebase_size;
317 uint32_t bind_off;
318 uint32_t bind_size;
319 uint32_t weak_bind_off;
320 uint32_t weak_bind_size;
321 uint32_t lazy_bind_off;
322 uint32_t lazy_bind_size;
323 uint32_t export_off;
324 uint32_t export_size;
325 } _packed;
326
327 struct dysymtab_command {
328 uint32_t cmd;
329 uint32_t cmdsize;
330 uint32_t ilocalsym;
331 uint32_t nlocalsym;
332 uint32_t iextdefsym;
333 uint32_t nextdefsym;
334 uint32_t iundefsym;
335 uint32_t nundefsym;
336 uint32_t tocoff;
337 uint32_t ntoc;
338 uint32_t modtaboff;
339 uint32_t nmodtab;
340 uint32_t extrefsymoff;
341 uint32_t nextrefsyms;
342 uint32_t indirectsymoff;
343 uint32_t nindirectsyms;
344 uint32_t extreloff;
345 uint32_t nextrel;
346 uint32_t locreloff;
347 uint32_t nlocrel;
348 } _packed;
349
350 struct dylib_table_of_contents {
351 uint32_t symbol_index;
352 uint32_t module_index;
353 } _packed;
354
355 struct dylib_module {
356 uint32_t module_name;
357 uint32_t iextdefsym;
358 uint32_t nextdefsym;
359 uint32_t irefsym;
360 uint32_t nrefsym;
361 uint32_t ilocalsym;
362 uint32_t nlocalsym;
363 uint32_t iextrel;
364 uint32_t nextrel;
365 uint32_t iinit_iterm;
366 uint32_t ninit_nterm;
367 uint32_t objc_module_info_addr;
368 uint32_t objc_module_info_size;
369 } _packed;
370
371 struct dylib_reference {
372 uint32_t isym:24;
373 uint32_t flags:8;
374 } _packed;
375
376 struct relocation_info {
377 int32_t r_address;
378 uint32_t r_symbolnum:24;
379 uint32_t r_pcrel:1;
380 uint32_t r_length:2;
381 uint32_t r_extern:1;
382 uint32_t r_type:4;
383 } _packed;
384
385 struct nlist {
386 union {
387 char *n_name;
388 int32_t n_strx;
389 } n_un;
390
391 uint8_t n_type;
392 uint8_t n_sect;
393 uint8_t n_desc;
394 uint32_t n_value;
395 } _packed;
396
397 struct segment_command {
398 uint32_t cmd;
399 uint32_t cmdsize;
400 char segname[16];
401 uint32_t vmaddr;
402 uint32_t vmsize;
403 uint32_t fileoff;
404 uint32_t filesize;
405 uint32_t maxprot;
406 uint32_t initprot;
407 uint32_t nsects;
408 uint32_t flags;
409 } _packed;
410
411 struct segment_command_64 {
412 uint32_t cmd;
413 uint32_t cmdsize;
414 char segname[16];
415 uint64_t vmaddr;
416 uint64_t vmsize;
417 uint64_t fileoff;
418 uint64_t filesize;
419 uint32_t maxprot;
420 uint32_t initprot;
421 uint32_t nsects;
422 uint32_t flags;
423 } _packed;
424
425 struct section {
426 char sectname[16];
427 char segname[16];
428 uint32_t addr;
429 uint32_t size;
430 uint32_t offset;
431 uint32_t align;
432 uint32_t reloff;
433 uint32_t nreloc;
434 uint32_t flags;
435 uint32_t reserved1;
436 uint32_t reserved2;
437 } _packed;
438
439 struct section_64 {
440 char sectname[16];
441 char segname[16];
442 uint64_t addr;
443 uint64_t size;
444 uint32_t offset;
445 uint32_t align;
446 uint32_t reloff;
447 uint32_t nreloc;
448 uint32_t flags;
449 uint32_t reserved1;
450 uint32_t reserved2;
451 uint32_t reserved3;
452 } _packed;
453
454 struct linkedit_data_command {
455 uint32_t cmd;
456 uint32_t cmdsize;
457 uint32_t dataoff;
458 uint32_t datasize;
459 } _packed;
460
461 struct encryption_info_command {
462 uint32_t cmd;
463 uint32_t cmdsize;
464 uint32_t cryptoff;
465 uint32_t cryptsize;
466 uint32_t cryptid;
467 } _packed;
468
469 #define BIND_OPCODE_MASK 0xf0
470 #define BIND_IMMEDIATE_MASK 0x0f
471 #define BIND_OPCODE_DONE 0x00
472 #define BIND_OPCODE_SET_DYLIB_ORDINAL_IMM 0x10
473 #define BIND_OPCODE_SET_DYLIB_ORDINAL_ULEB 0x20
474 #define BIND_OPCODE_SET_DYLIB_SPECIAL_IMM 0x30
475 #define BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM 0x40
476 #define BIND_OPCODE_SET_TYPE_IMM 0x50
477 #define BIND_OPCODE_SET_ADDEND_SLEB 0x60
478 #define BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB 0x70
479 #define BIND_OPCODE_ADD_ADDR_ULEB 0x80
480 #define BIND_OPCODE_DO_BIND 0x90
481 #define BIND_OPCODE_DO_BIND_ADD_ADDR_ULEB 0xa0
482 #define BIND_OPCODE_DO_BIND_ADD_ADDR_IMM_SCALED 0xb0
483 #define BIND_OPCODE_DO_BIND_ULEB_TIMES_SKIPPING_ULEB 0xc0
484
485 struct : ldid::Progress {
486 virtual void operator()(const std::string &value) const {
487 }
488
489 virtual void operator()(double value) const {
490 }
491 } dummy_;
492
493 struct Progression : ldid::Progress {
494 const ldid::Progress &progress_;
495 std::string name_;
496
497 Progression(const ldid::Progress &progress, const std::string &name) :
498 progress_(progress),
499 name_(name)
500 {
501 }
502
503 virtual void operator()(const std::string &value) const {
504 return progress_(name_ + " (" + value + ")");
505 }
506
507 virtual void operator()(double value) const {
508 return progress_(value);
509 }
510 };
511
512 static std::streamsize read(std::streambuf &stream, void *data, size_t size) {
513 auto writ(stream.sgetn(static_cast<char *>(data), size));
514 _assert(writ >= 0);
515 return writ;
516 }
517
518 static inline void get(std::streambuf &stream, void *data, size_t size) {
519 _assert(read(stream, data, size) == size);
520 }
521
522 static inline void put(std::streambuf &stream, const void *data, size_t size) {
523 _assert(stream.sputn(static_cast<const char *>(data), size) == size);
524 }
525
526 static inline void put(std::streambuf &stream, const void *data, size_t size, const ldid::Progress &progress) {
527 progress(0);
528 for (size_t total(0); total != size;) {
529 auto writ(std::min(size - total, size_t(4096 * 4)));
530 _assert(stream.sputn(static_cast<const char *>(data) + total, writ) == writ);
531 total += writ;
532 progress(double(total) / size);
533 }
534 }
535
536 static size_t most(std::streambuf &stream, void *data, size_t size) {
537 size_t total(size);
538 while (size > 0)
539 if (auto writ = read(stream, data, size))
540 size -= writ;
541 else break;
542 return total - size;
543 }
544
545 static inline void pad(std::streambuf &stream, size_t size) {
546 char padding[size];
547 memset(padding, 0, size);
548 put(stream, padding, size);
549 }
550
551 template <typename Type_>
552 Type_ Align(Type_ value, size_t align) {
553 value += align - 1;
554 value /= align;
555 value *= align;
556 return value;
557 }
558
559 static const uint8_t PageShift_(0x0c);
560 static const uint32_t PageSize_(1 << PageShift_);
561
562 static inline uint16_t Swap_(uint16_t value) {
563 return
564 ((value >> 8) & 0x00ff) |
565 ((value << 8) & 0xff00);
566 }
567
568 static inline uint32_t Swap_(uint32_t value) {
569 value = ((value >> 8) & 0x00ff00ff) |
570 ((value << 8) & 0xff00ff00);
571 value = ((value >> 16) & 0x0000ffff) |
572 ((value << 16) & 0xffff0000);
573 return value;
574 }
575
576 static inline uint64_t Swap_(uint64_t value) {
577 value = (value & 0x00000000ffffffff) << 32 | (value & 0xffffffff00000000) >> 32;
578 value = (value & 0x0000ffff0000ffff) << 16 | (value & 0xffff0000ffff0000) >> 16;
579 value = (value & 0x00ff00ff00ff00ff) << 8 | (value & 0xff00ff00ff00ff00) >> 8;
580 return value;
581 }
582
583 static inline int16_t Swap_(int16_t value) {
584 return Swap_(static_cast<uint16_t>(value));
585 }
586
587 static inline int32_t Swap_(int32_t value) {
588 return Swap_(static_cast<uint32_t>(value));
589 }
590
591 static inline int64_t Swap_(int64_t value) {
592 return Swap_(static_cast<uint64_t>(value));
593 }
594
595 static bool little_(true);
596
597 static inline uint16_t Swap(uint16_t value) {
598 return little_ ? Swap_(value) : value;
599 }
600
601 static inline uint32_t Swap(uint32_t value) {
602 return little_ ? Swap_(value) : value;
603 }
604
605 static inline uint64_t Swap(uint64_t value) {
606 return little_ ? Swap_(value) : value;
607 }
608
609 static inline int16_t Swap(int16_t value) {
610 return Swap(static_cast<uint16_t>(value));
611 }
612
613 static inline int32_t Swap(int32_t value) {
614 return Swap(static_cast<uint32_t>(value));
615 }
616
617 static inline int64_t Swap(int64_t value) {
618 return Swap(static_cast<uint64_t>(value));
619 }
620
621 class Swapped {
622 protected:
623 bool swapped_;
624
625 Swapped() :
626 swapped_(false)
627 {
628 }
629
630 public:
631 Swapped(bool swapped) :
632 swapped_(swapped)
633 {
634 }
635
636 template <typename Type_>
637 Type_ Swap(Type_ value) const {
638 return swapped_ ? Swap_(value) : value;
639 }
640 };
641
642 class Data :
643 public Swapped
644 {
645 private:
646 void *base_;
647 size_t size_;
648
649 public:
650 Data(void *base, size_t size) :
651 base_(base),
652 size_(size)
653 {
654 }
655
656 void *GetBase() const {
657 return base_;
658 }
659
660 size_t GetSize() const {
661 return size_;
662 }
663 };
664
665 class MachHeader :
666 public Data
667 {
668 private:
669 bool bits64_;
670
671 struct mach_header *mach_header_;
672 struct load_command *load_command_;
673
674 public:
675 MachHeader(void *base, size_t size) :
676 Data(base, size)
677 {
678 mach_header_ = (mach_header *) base;
679
680 switch (Swap(mach_header_->magic)) {
681 case MH_CIGAM:
682 swapped_ = !swapped_;
683 case MH_MAGIC:
684 bits64_ = false;
685 break;
686
687 case MH_CIGAM_64:
688 swapped_ = !swapped_;
689 case MH_MAGIC_64:
690 bits64_ = true;
691 break;
692
693 default:
694 _assert(false);
695 }
696
697 void *post = mach_header_ + 1;
698 if (bits64_)
699 post = (uint32_t *) post + 1;
700 load_command_ = (struct load_command *) post;
701
702 _assert(
703 Swap(mach_header_->filetype) == MH_EXECUTE ||
704 Swap(mach_header_->filetype) == MH_DYLIB ||
705 Swap(mach_header_->filetype) == MH_DYLINKER ||
706 Swap(mach_header_->filetype) == MH_BUNDLE
707 );
708 }
709
710 bool Bits64() const {
711 return bits64_;
712 }
713
714 struct mach_header *operator ->() const {
715 return mach_header_;
716 }
717
718 operator struct mach_header *() const {
719 return mach_header_;
720 }
721
722 uint32_t GetCPUType() const {
723 return Swap(mach_header_->cputype);
724 }
725
726 uint32_t GetCPUSubtype() const {
727 return Swap(mach_header_->cpusubtype) & 0xff;
728 }
729
730 struct load_command *GetLoadCommand() const {
731 return load_command_;
732 }
733
734 std::vector<struct load_command *> GetLoadCommands() const {
735 std::vector<struct load_command *> load_commands;
736
737 struct load_command *load_command = load_command_;
738 for (uint32_t cmd = 0; cmd != Swap(mach_header_->ncmds); ++cmd) {
739 load_commands.push_back(load_command);
740 load_command = (struct load_command *) ((uint8_t *) load_command + Swap(load_command->cmdsize));
741 }
742
743 return load_commands;
744 }
745
746 void ForSection(const ldid::Functor<void (const char *, const char *, void *, size_t)> &code) const {
747 _foreach (load_command, GetLoadCommands())
748 switch (Swap(load_command->cmd)) {
749 case LC_SEGMENT: {
750 auto segment(reinterpret_cast<struct segment_command *>(load_command));
751 code(segment->segname, NULL, GetOffset<void>(segment->fileoff), segment->filesize);
752 auto section(reinterpret_cast<struct section *>(segment + 1));
753 for (uint32_t i(0), e(Swap(segment->nsects)); i != e; ++i, ++section)
754 code(segment->segname, section->sectname, GetOffset<void>(segment->fileoff + section->offset), section->size);
755 } break;
756
757 case LC_SEGMENT_64: {
758 auto segment(reinterpret_cast<struct segment_command_64 *>(load_command));
759 code(segment->segname, NULL, GetOffset<void>(segment->fileoff), segment->filesize);
760 auto section(reinterpret_cast<struct section_64 *>(segment + 1));
761 for (uint32_t i(0), e(Swap(segment->nsects)); i != e; ++i, ++section)
762 code(segment->segname, section->sectname, GetOffset<void>(segment->fileoff + section->offset), section->size);
763 } break;
764 }
765 }
766
767 template <typename Target_>
768 Target_ *GetOffset(uint32_t offset) const {
769 return reinterpret_cast<Target_ *>(offset + (uint8_t *) mach_header_);
770 }
771 };
772
773 class FatMachHeader :
774 public MachHeader
775 {
776 private:
777 fat_arch *fat_arch_;
778
779 public:
780 FatMachHeader(void *base, size_t size, fat_arch *fat_arch) :
781 MachHeader(base, size),
782 fat_arch_(fat_arch)
783 {
784 }
785
786 fat_arch *GetFatArch() const {
787 return fat_arch_;
788 }
789 };
790
791 class FatHeader :
792 public Data
793 {
794 private:
795 fat_header *fat_header_;
796 std::vector<FatMachHeader> mach_headers_;
797
798 public:
799 FatHeader(void *base, size_t size) :
800 Data(base, size)
801 {
802 fat_header_ = reinterpret_cast<struct fat_header *>(base);
803
804 if (Swap(fat_header_->magic) == FAT_CIGAM) {
805 swapped_ = !swapped_;
806 goto fat;
807 } else if (Swap(fat_header_->magic) != FAT_MAGIC) {
808 fat_header_ = NULL;
809 mach_headers_.push_back(FatMachHeader(base, size, NULL));
810 } else fat: {
811 size_t fat_narch = Swap(fat_header_->nfat_arch);
812 fat_arch *fat_arch = reinterpret_cast<struct fat_arch *>(fat_header_ + 1);
813 size_t arch;
814 for (arch = 0; arch != fat_narch; ++arch) {
815 uint32_t arch_offset = Swap(fat_arch->offset);
816 uint32_t arch_size = Swap(fat_arch->size);
817 mach_headers_.push_back(FatMachHeader((uint8_t *) base + arch_offset, arch_size, fat_arch));
818 ++fat_arch;
819 }
820 }
821 }
822
823 std::vector<FatMachHeader> &GetMachHeaders() {
824 return mach_headers_;
825 }
826
827 bool IsFat() const {
828 return fat_header_ != NULL;
829 }
830
831 struct fat_header *operator ->() const {
832 return fat_header_;
833 }
834
835 operator struct fat_header *() const {
836 return fat_header_;
837 }
838 };
839
840 #define CSMAGIC_REQUIREMENT uint32_t(0xfade0c00)
841 #define CSMAGIC_REQUIREMENTS uint32_t(0xfade0c01)
842 #define CSMAGIC_CODEDIRECTORY uint32_t(0xfade0c02)
843 #define CSMAGIC_EMBEDDED_SIGNATURE uint32_t(0xfade0cc0)
844 #define CSMAGIC_EMBEDDED_SIGNATURE_OLD uint32_t(0xfade0b02)
845 #define CSMAGIC_EMBEDDED_ENTITLEMENTS uint32_t(0xfade7171)
846 #define CSMAGIC_DETACHED_SIGNATURE uint32_t(0xfade0cc1)
847 #define CSMAGIC_BLOBWRAPPER uint32_t(0xfade0b01)
848
849 #define CSSLOT_CODEDIRECTORY uint32_t(0x00000)
850 #define CSSLOT_INFOSLOT uint32_t(0x00001)
851 #define CSSLOT_REQUIREMENTS uint32_t(0x00002)
852 #define CSSLOT_RESOURCEDIR uint32_t(0x00003)
853 #define CSSLOT_APPLICATION uint32_t(0x00004)
854 #define CSSLOT_ENTITLEMENTS uint32_t(0x00005)
855 #define CSSLOT_ALTERNATE uint32_t(0x01000)
856
857 #define CSSLOT_SIGNATURESLOT uint32_t(0x10000)
858
859 #define CS_HASHTYPE_SHA160_160 1
860 #define CS_HASHTYPE_SHA256_256 2
861 #define CS_HASHTYPE_SHA256_160 3
862 #define CS_HASHTYPE_SHA386_386 4
863
864 struct BlobIndex {
865 uint32_t type;
866 uint32_t offset;
867 } _packed;
868
869 struct Blob {
870 uint32_t magic;
871 uint32_t length;
872 } _packed;
873
874 struct SuperBlob {
875 struct Blob blob;
876 uint32_t count;
877 struct BlobIndex index[];
878 } _packed;
879
880 struct CodeDirectory {
881 uint32_t version;
882 uint32_t flags;
883 uint32_t hashOffset;
884 uint32_t identOffset;
885 uint32_t nSpecialSlots;
886 uint32_t nCodeSlots;
887 uint32_t codeLimit;
888 uint8_t hashSize;
889 uint8_t hashType;
890 uint8_t platform;
891 uint8_t pageSize;
892 uint32_t spare2;
893 uint32_t scatterOffset;
894 uint32_t teamIDOffset;
895 //uint32_t spare3;
896 //uint64_t codeLimit64;
897 } _packed;
898
899 enum CodeSignatureFlags {
900 kSecCodeSignatureHost = 0x0001,
901 kSecCodeSignatureAdhoc = 0x0002,
902 kSecCodeSignatureForceHard = 0x0100,
903 kSecCodeSignatureForceKill = 0x0200,
904 kSecCodeSignatureForceExpiration = 0x0400,
905 kSecCodeSignatureRestrict = 0x0800,
906 kSecCodeSignatureEnforcement = 0x1000,
907 kSecCodeSignatureLibraryValidation = 0x2000,
908 kSecCodeSignatureRuntime = 0x10000,
909 };
910
911 enum Kind : uint32_t {
912 exprForm = 1, // prefix expr form
913 };
914
915 enum ExprOp : uint32_t {
916 opFalse, // unconditionally false
917 opTrue, // unconditionally true
918 opIdent, // match canonical code [string]
919 opAppleAnchor, // signed by Apple as Apple's product
920 opAnchorHash, // match anchor [cert hash]
921 opInfoKeyValue, // *legacy* - use opInfoKeyField [key; value]
922 opAnd, // binary prefix expr AND expr [expr; expr]
923 opOr, // binary prefix expr OR expr [expr; expr]
924 opCDHash, // match hash of CodeDirectory directly [cd hash]
925 opNot, // logical inverse [expr]
926 opInfoKeyField, // Info.plist key field [string; match suffix]
927 opCertField, // Certificate field [cert index; field name; match suffix]
928 opTrustedCert, // require trust settings to approve one particular cert [cert index]
929 opTrustedCerts, // require trust settings to approve the cert chain
930 opCertGeneric, // Certificate component by OID [cert index; oid; match suffix]
931 opAppleGenericAnchor, // signed by Apple in any capacity
932 opEntitlementField, // entitlement dictionary field [string; match suffix]
933 opCertPolicy, // Certificate policy by OID [cert index; oid; match suffix]
934 opNamedAnchor, // named anchor type
935 opNamedCode, // named subroutine
936 opPlatform, // platform constraint [integer]
937 exprOpCount // (total opcode count in use)
938 };
939
940 enum MatchOperation {
941 matchExists, // anything but explicit "false" - no value stored
942 matchEqual, // equal (CFEqual)
943 matchContains, // partial match (substring)
944 matchBeginsWith, // partial match (initial substring)
945 matchEndsWith, // partial match (terminal substring)
946 matchLessThan, // less than (string with numeric comparison)
947 matchGreaterThan, // greater than (string with numeric comparison)
948 matchLessEqual, // less or equal (string with numeric comparison)
949 matchGreaterEqual, // greater or equal (string with numeric comparison)
950 };
951
952 #define OID_ISO_MEMBER 42
953 #define OID_US OID_ISO_MEMBER, 134, 72
954 #define APPLE_OID OID_US, 0x86, 0xf7, 0x63
955 #define APPLE_ADS_OID APPLE_OID, 0x64
956 #define APPLE_EXTENSION_OID APPLE_ADS_OID, 6
957
958 #ifndef LDID_NOFLAGT
959 extern "C" uint32_t hash(uint8_t *k, uint32_t length, uint32_t initval);
960 #endif
961
962 struct Algorithm {
963 size_t size_;
964 uint8_t type_;
965
966 Algorithm(size_t size, uint8_t type) :
967 size_(size),
968 type_(type)
969 {
970 }
971
972 virtual const uint8_t *operator [](const ldid::Hash &hash) const = 0;
973
974 virtual void operator ()(uint8_t *hash, const void *data, size_t size) const = 0;
975 virtual void operator ()(ldid::Hash &hash, const void *data, size_t size) const = 0;
976 virtual void operator ()(std::vector<char> &hash, const void *data, size_t size) const = 0;
977
978 virtual const char *name() = 0;
979 };
980
981 struct AlgorithmSHA1 :
982 Algorithm
983 {
984 AlgorithmSHA1() :
985 Algorithm(LDID_SHA1_DIGEST_LENGTH, CS_HASHTYPE_SHA160_160)
986 {
987 }
988
989 virtual const uint8_t *operator [](const ldid::Hash &hash) const {
990 return hash.sha1_;
991 }
992
993 void operator ()(uint8_t *hash, const void *data, size_t size) const {
994 LDID_SHA1(static_cast<const uint8_t *>(data), size, hash);
995 }
996
997 void operator ()(ldid::Hash &hash, const void *data, size_t size) const {
998 return operator()(hash.sha1_, data, size);
999 }
1000
1001 void operator ()(std::vector<char> &hash, const void *data, size_t size) const {
1002 hash.resize(LDID_SHA1_DIGEST_LENGTH);
1003 return operator ()(reinterpret_cast<uint8_t *>(hash.data()), data, size);
1004 }
1005
1006 virtual const char *name() {
1007 return "sha1";
1008 }
1009 };
1010
1011 struct AlgorithmSHA256 :
1012 Algorithm
1013 {
1014 AlgorithmSHA256() :
1015 Algorithm(LDID_SHA256_DIGEST_LENGTH, CS_HASHTYPE_SHA256_256)
1016 {
1017 }
1018
1019 virtual const uint8_t *operator [](const ldid::Hash &hash) const {
1020 return hash.sha256_;
1021 }
1022
1023 void operator ()(uint8_t *hash, const void *data, size_t size) const {
1024 LDID_SHA256(static_cast<const uint8_t *>(data), size, hash);
1025 }
1026
1027 void operator ()(ldid::Hash &hash, const void *data, size_t size) const {
1028 return operator()(hash.sha256_, data, size);
1029 }
1030
1031 void operator ()(std::vector<char> &hash, const void *data, size_t size) const {
1032 hash.resize(LDID_SHA256_DIGEST_LENGTH);
1033 return operator ()(reinterpret_cast<uint8_t *>(hash.data()), data, size);
1034 }
1035
1036 virtual const char *name() {
1037 return "sha256";
1038 }
1039 };
1040
1041 static bool do_sha1(true);
1042 static bool do_sha256(true);
1043
1044 static const std::vector<Algorithm *> &GetAlgorithms() {
1045 static AlgorithmSHA1 sha1;
1046 static AlgorithmSHA256 sha256;
1047
1048 static std::vector<Algorithm *> algorithms;
1049 if (algorithms.empty()) {
1050 if (do_sha1)
1051 algorithms.push_back(&sha1);
1052 if (do_sha256)
1053 algorithms.push_back(&sha256);
1054 }
1055
1056 return algorithms;
1057 }
1058
1059 struct Baton {
1060 std::string entitlements_;
1061 };
1062
1063 struct CodesignAllocation {
1064 FatMachHeader mach_header_;
1065 uint32_t offset_;
1066 uint32_t size_;
1067 uint32_t limit_;
1068 uint32_t alloc_;
1069 uint32_t align_;
1070 const char *arch_;
1071 Baton baton_;
1072
1073 CodesignAllocation(FatMachHeader mach_header, size_t offset, size_t size, size_t limit, size_t alloc, size_t align, const char *arch, const Baton &baton) :
1074 mach_header_(mach_header),
1075 offset_(offset),
1076 size_(size),
1077 limit_(limit),
1078 alloc_(alloc),
1079 align_(align),
1080 arch_(arch),
1081 baton_(baton)
1082 {
1083 }
1084 };
1085
1086 #ifndef LDID_NOTOOLS
1087 class File {
1088 private:
1089 int file_;
1090
1091 public:
1092 File() :
1093 file_(-1)
1094 {
1095 }
1096
1097 ~File() {
1098 if (file_ != -1)
1099 _syscall(close(file_));
1100 }
1101
1102 void open(const char *path, int flags) {
1103 _assert(file_ == -1);
1104 file_ = _syscall(::open(path, flags));
1105 }
1106
1107 int file() const {
1108 return file_;
1109 }
1110 };
1111
1112 class Map {
1113 private:
1114 File file_;
1115 void *data_;
1116 size_t size_;
1117
1118 void clear() {
1119 if (data_ == NULL)
1120 return;
1121 _syscall(munmap(data_, size_));
1122 data_ = NULL;
1123 size_ = 0;
1124 }
1125
1126 public:
1127 Map() :
1128 data_(NULL),
1129 size_(0)
1130 {
1131 }
1132
1133 Map(const std::string &path, int oflag, int pflag, int mflag) :
1134 Map()
1135 {
1136 open(path, oflag, pflag, mflag);
1137 }
1138
1139 Map(const std::string &path, bool edit) :
1140 Map()
1141 {
1142 open(path, edit);
1143 }
1144
1145 ~Map() {
1146 clear();
1147 }
1148
1149 bool empty() const {
1150 return data_ == NULL;
1151 }
1152
1153 void open(const std::string &path, int oflag, int pflag, int mflag) {
1154 clear();
1155
1156 file_.open(path.c_str(), oflag);
1157 int file(file_.file());
1158
1159 struct stat stat;
1160 _syscall(fstat(file, &stat));
1161 size_ = stat.st_size;
1162
1163 data_ = _syscall(mmap(NULL, size_, pflag, mflag, file, 0));
1164 }
1165
1166 void open(const std::string &path, bool edit) {
1167 if (edit)
1168 open(path, O_RDWR, PROT_READ | PROT_WRITE, MAP_SHARED);
1169 else
1170 open(path, O_RDONLY, PROT_READ, MAP_PRIVATE);
1171 }
1172
1173 void *data() const {
1174 return data_;
1175 }
1176
1177 size_t size() const {
1178 return size_;
1179 }
1180
1181 operator std::string() const {
1182 return std::string(static_cast<char *>(data_), size_);
1183 }
1184 };
1185 #endif
1186
1187 namespace ldid {
1188
1189 #ifndef LDID_NOPLIST
1190 static plist_t plist(const std::string &data);
1191 #endif
1192
1193 void Analyze(const MachHeader &mach_header, const Functor<void (const char *data, size_t size)> &entitle) {
1194 _foreach (load_command, mach_header.GetLoadCommands())
1195 if (mach_header.Swap(load_command->cmd) == LC_CODE_SIGNATURE) {
1196 auto signature(reinterpret_cast<struct linkedit_data_command *>(load_command));
1197 auto offset(mach_header.Swap(signature->dataoff));
1198 auto pointer(reinterpret_cast<uint8_t *>(mach_header.GetBase()) + offset);
1199 auto super(reinterpret_cast<struct SuperBlob *>(pointer));
1200
1201 for (size_t index(0); index != Swap(super->count); ++index)
1202 if (Swap(super->index[index].type) == CSSLOT_ENTITLEMENTS) {
1203 auto begin(Swap(super->index[index].offset));
1204 auto blob(reinterpret_cast<struct Blob *>(pointer + begin));
1205 auto writ(Swap(blob->length) - sizeof(*blob));
1206 entitle(reinterpret_cast<char *>(blob + 1), writ);
1207 }
1208 }
1209 }
1210
1211 std::string Analyze(const void *data, size_t size) {
1212 std::string entitlements;
1213
1214 FatHeader fat_header(const_cast<void *>(data), size);
1215 _foreach (mach_header, fat_header.GetMachHeaders())
1216 Analyze(mach_header, fun([&](const char *data, size_t size) {
1217 if (entitlements.empty())
1218 entitlements.assign(data, size);
1219 else
1220 _assert(entitlements.compare(0, entitlements.size(), data, size) == 0);
1221 }));
1222
1223 return entitlements;
1224 }
1225
1226 static void Allocate(const void *idata, size_t isize, std::streambuf &output, const Functor<size_t (const MachHeader &, Baton &, size_t)> &allocate, const Functor<size_t (const MachHeader &, const Baton &, std::streambuf &output, size_t, const std::string &, const char *, const Progress &)> &save, const Progress &progress) {
1227 FatHeader source(const_cast<void *>(idata), isize);
1228
1229 size_t offset(0);
1230 if (source.IsFat())
1231 offset += sizeof(fat_header) + sizeof(fat_arch) * source.Swap(source->nfat_arch);
1232
1233 std::vector<CodesignAllocation> allocations;
1234 _foreach (mach_header, source.GetMachHeaders()) {
1235 struct linkedit_data_command *signature(NULL);
1236 struct symtab_command *symtab(NULL);
1237
1238 _foreach (load_command, mach_header.GetLoadCommands()) {
1239 uint32_t cmd(mach_header.Swap(load_command->cmd));
1240 if (false);
1241 else if (cmd == LC_CODE_SIGNATURE)
1242 signature = reinterpret_cast<struct linkedit_data_command *>(load_command);
1243 else if (cmd == LC_SYMTAB)
1244 symtab = reinterpret_cast<struct symtab_command *>(load_command);
1245 }
1246
1247 size_t size;
1248 if (signature == NULL)
1249 size = mach_header.GetSize();
1250 else {
1251 size = mach_header.Swap(signature->dataoff);
1252 _assert(size <= mach_header.GetSize());
1253 }
1254
1255 if (symtab != NULL) {
1256 auto end(mach_header.Swap(symtab->stroff) + mach_header.Swap(symtab->strsize));
1257 if (symtab->stroff != 0 || symtab->strsize != 0) {
1258 _assert(end <= size);
1259 _assert(end >= size - 0x10);
1260 size = end;
1261 }
1262 }
1263
1264 Baton baton;
1265 size_t alloc(allocate(mach_header, baton, size));
1266
1267 auto *fat_arch(mach_header.GetFatArch());
1268 uint32_t align;
1269
1270 if (fat_arch != NULL)
1271 align = source.Swap(fat_arch->align);
1272 else switch (mach_header.GetCPUType()) {
1273 case CPU_TYPE_POWERPC:
1274 case CPU_TYPE_POWERPC64:
1275 case CPU_TYPE_X86:
1276 case CPU_TYPE_X86_64:
1277 align = 0xc;
1278 break;
1279 case CPU_TYPE_ARM:
1280 case CPU_TYPE_ARM64:
1281 align = 0xe;
1282 break;
1283 default:
1284 align = 0x0;
1285 break;
1286 }
1287
1288 const char *arch(NULL);
1289 switch (mach_header.GetCPUType()) {
1290 case CPU_TYPE_POWERPC:
1291 arch = "ppc";
1292 break;
1293 case CPU_TYPE_POWERPC64:
1294 arch = "ppc64";
1295 break;
1296 case CPU_TYPE_X86:
1297 arch = "i386";
1298 break;
1299 case CPU_TYPE_X86_64:
1300 arch = "x86_64";
1301 break;
1302 case CPU_TYPE_ARM:
1303 arch = "arm";
1304 break;
1305 case CPU_TYPE_ARM64:
1306 arch = "arm64";
1307 break;
1308 }
1309
1310 offset = Align(offset, 1 << align);
1311
1312 uint32_t limit(size);
1313 if (alloc != 0)
1314 limit = Align(limit, 0x10);
1315
1316 allocations.push_back(CodesignAllocation(mach_header, offset, size, limit, alloc, align, arch, baton));
1317 offset += size + alloc;
1318 offset = Align(offset, 0x10);
1319 }
1320
1321 size_t position(0);
1322
1323 if (source.IsFat()) {
1324 fat_header fat_header;
1325 fat_header.magic = Swap(FAT_MAGIC);
1326 fat_header.nfat_arch = Swap(uint32_t(allocations.size()));
1327 put(output, &fat_header, sizeof(fat_header));
1328 position += sizeof(fat_header);
1329
1330 _foreach (allocation, allocations) {
1331 auto &mach_header(allocation.mach_header_);
1332
1333 fat_arch fat_arch;
1334 fat_arch.cputype = Swap(mach_header->cputype);
1335 fat_arch.cpusubtype = Swap(mach_header->cpusubtype);
1336 fat_arch.offset = Swap(allocation.offset_);
1337 fat_arch.size = Swap(allocation.limit_ + allocation.alloc_);
1338 fat_arch.align = Swap(allocation.align_);
1339 put(output, &fat_arch, sizeof(fat_arch));
1340 position += sizeof(fat_arch);
1341 }
1342 }
1343
1344 _foreach (allocation, allocations) {
1345 progress(allocation.arch_);
1346 auto &mach_header(allocation.mach_header_);
1347
1348 pad(output, allocation.offset_ - position);
1349 position = allocation.offset_;
1350
1351 std::vector<std::string> commands;
1352
1353 _foreach (load_command, mach_header.GetLoadCommands()) {
1354 std::string copy(reinterpret_cast<const char *>(load_command), load_command->cmdsize);
1355
1356 switch (mach_header.Swap(load_command->cmd)) {
1357 case LC_CODE_SIGNATURE:
1358 continue;
1359 break;
1360
1361 case LC_SEGMENT: {
1362 auto segment_command(reinterpret_cast<struct segment_command *>(&copy[0]));
1363 if (strncmp(segment_command->segname, "__LINKEDIT", 16) != 0)
1364 break;
1365 size_t size(mach_header.Swap(allocation.limit_ + allocation.alloc_ - mach_header.Swap(segment_command->fileoff)));
1366 segment_command->filesize = size;
1367 segment_command->vmsize = Align(size, 1 << allocation.align_);
1368 } break;
1369
1370 case LC_SEGMENT_64: {
1371 auto segment_command(reinterpret_cast<struct segment_command_64 *>(&copy[0]));
1372 if (strncmp(segment_command->segname, "__LINKEDIT", 16) != 0)
1373 break;
1374 size_t size(mach_header.Swap(allocation.limit_ + allocation.alloc_ - mach_header.Swap(segment_command->fileoff)));
1375 segment_command->filesize = size;
1376 segment_command->vmsize = Align(size, 1 << allocation.align_);
1377 } break;
1378 }
1379
1380 commands.push_back(copy);
1381 }
1382
1383 if (allocation.alloc_ != 0) {
1384 linkedit_data_command signature;
1385 signature.cmd = mach_header.Swap(LC_CODE_SIGNATURE);
1386 signature.cmdsize = mach_header.Swap(uint32_t(sizeof(signature)));
1387 signature.dataoff = mach_header.Swap(allocation.limit_);
1388 signature.datasize = mach_header.Swap(allocation.alloc_);
1389 commands.push_back(std::string(reinterpret_cast<const char *>(&signature), sizeof(signature)));
1390 }
1391
1392 size_t begin(position);
1393
1394 uint32_t after(0);
1395 _foreach(command, commands)
1396 after += command.size();
1397
1398 std::stringbuf altern;
1399
1400 struct mach_header header(*mach_header);
1401 header.ncmds = mach_header.Swap(uint32_t(commands.size()));
1402 header.sizeofcmds = mach_header.Swap(after);
1403 put(output, &header, sizeof(header));
1404 put(altern, &header, sizeof(header));
1405 position += sizeof(header);
1406
1407 if (mach_header.Bits64()) {
1408 auto pad(mach_header.Swap(uint32_t(0)));
1409 put(output, &pad, sizeof(pad));
1410 put(altern, &pad, sizeof(pad));
1411 position += sizeof(pad);
1412 }
1413
1414 _foreach(command, commands) {
1415 put(output, command.data(), command.size());
1416 put(altern, command.data(), command.size());
1417 position += command.size();
1418 }
1419
1420 uint32_t before(mach_header.Swap(mach_header->sizeofcmds));
1421 if (before > after) {
1422 pad(output, before - after);
1423 pad(altern, before - after);
1424 position += before - after;
1425 }
1426
1427 auto top(reinterpret_cast<char *>(mach_header.GetBase()));
1428
1429 std::string overlap(altern.str());
1430 overlap.append(top + overlap.size(), Align(overlap.size(), 0x1000) - overlap.size());
1431
1432 put(output, top + (position - begin), allocation.size_ - (position - begin), progress);
1433 position = begin + allocation.size_;
1434
1435 pad(output, allocation.limit_ - allocation.size_);
1436 position += allocation.limit_ - allocation.size_;
1437
1438 size_t saved(save(mach_header, allocation.baton_, output, allocation.limit_, overlap, top, progress));
1439 if (allocation.alloc_ > saved)
1440 pad(output, allocation.alloc_ - saved);
1441 else
1442 _assert(allocation.alloc_ == saved);
1443 position += allocation.alloc_;
1444 }
1445 }
1446
1447 }
1448
1449 typedef std::map<uint32_t, std::string> Blobs;
1450
1451 static void insert(Blobs &blobs, uint32_t slot, const std::stringbuf &buffer) {
1452 auto value(buffer.str());
1453 std::swap(blobs[slot], value);
1454 }
1455
1456 static const std::string &insert(Blobs &blobs, uint32_t slot, uint32_t magic, const std::stringbuf &buffer) {
1457 auto value(buffer.str());
1458 Blob blob;
1459 blob.magic = Swap(magic);
1460 blob.length = Swap(uint32_t(sizeof(blob) + value.size()));
1461 value.insert(0, reinterpret_cast<char *>(&blob), sizeof(blob));
1462 auto &save(blobs[slot]);
1463 std::swap(save, value);
1464 return save;
1465 }
1466
1467 static size_t put(std::streambuf &output, uint32_t magic, const Blobs &blobs) {
1468 size_t total(0);
1469 _foreach (blob, blobs)
1470 total += blob.second.size();
1471
1472 struct SuperBlob super;
1473 super.blob.magic = Swap(magic);
1474 super.blob.length = Swap(uint32_t(sizeof(SuperBlob) + blobs.size() * sizeof(BlobIndex) + total));
1475 super.count = Swap(uint32_t(blobs.size()));
1476 put(output, &super, sizeof(super));
1477
1478 size_t offset(sizeof(SuperBlob) + sizeof(BlobIndex) * blobs.size());
1479
1480 _foreach (blob, blobs) {
1481 BlobIndex index;
1482 index.type = Swap(blob.first);
1483 index.offset = Swap(uint32_t(offset));
1484 put(output, &index, sizeof(index));
1485 offset += blob.second.size();
1486 }
1487
1488 _foreach (blob, blobs)
1489 put(output, blob.second.data(), blob.second.size());
1490
1491 return offset;
1492 }
1493
1494 #ifndef LDID_NOSMIME
1495 class Buffer {
1496 private:
1497 BIO *bio_;
1498
1499 public:
1500 Buffer(BIO *bio) :
1501 bio_(bio)
1502 {
1503 _assert(bio_ != NULL);
1504 }
1505
1506 Buffer() :
1507 bio_(BIO_new(BIO_s_mem()))
1508 {
1509 }
1510
1511 Buffer(const char *data, size_t size) :
1512 Buffer(BIO_new_mem_buf(const_cast<char *>(data), size))
1513 {
1514 }
1515
1516 Buffer(const std::string &data) :
1517 Buffer(data.data(), data.size())
1518 {
1519 }
1520
1521 Buffer(PKCS7 *pkcs) :
1522 Buffer()
1523 {
1524 _assert(i2d_PKCS7_bio(bio_, pkcs) != 0);
1525 }
1526
1527 ~Buffer() {
1528 BIO_free_all(bio_);
1529 }
1530
1531 operator BIO *() const {
1532 return bio_;
1533 }
1534
1535 explicit operator std::string() const {
1536 char *data;
1537 auto size(BIO_get_mem_data(bio_, &data));
1538 return std::string(data, size);
1539 }
1540 };
1541
1542 class Stuff {
1543 private:
1544 PKCS12 *value_;
1545 EVP_PKEY *key_;
1546 X509 *cert_;
1547 STACK_OF(X509) *ca_;
1548
1549 public:
1550 Stuff(BIO *bio) :
1551 value_(d2i_PKCS12_bio(bio, NULL)),
1552 ca_(NULL)
1553 {
1554 _assert(value_ != NULL);
1555 _assert(PKCS12_parse(value_, "", &key_, &cert_, &ca_) != 0);
1556
1557 _assert(key_ != NULL);
1558 _assert(cert_ != NULL);
1559
1560 if (ca_ == NULL)
1561 ca_ = sk_X509_new_null();
1562 _assert(ca_ != NULL);
1563 }
1564
1565 Stuff(const std::string &data) :
1566 Stuff(Buffer(data))
1567 {
1568 }
1569
1570 ~Stuff() {
1571 sk_X509_pop_free(ca_, X509_free);
1572 X509_free(cert_);
1573 EVP_PKEY_free(key_);
1574 PKCS12_free(value_);
1575 }
1576
1577 operator PKCS12 *() const {
1578 return value_;
1579 }
1580
1581 operator EVP_PKEY *() const {
1582 return key_;
1583 }
1584
1585 operator X509 *() const {
1586 return cert_;
1587 }
1588
1589 operator STACK_OF(X509) *() const {
1590 return ca_;
1591 }
1592 };
1593
1594 class Signature {
1595 private:
1596 PKCS7 *value_;
1597
1598 public:
1599 Signature(const Stuff &stuff, const Buffer &data, const std::string &xml) {
1600 value_ = PKCS7_new();
1601 _assert(value_ != NULL);
1602
1603 _assert(PKCS7_set_type(value_, NID_pkcs7_signed));
1604 _assert(PKCS7_content_new(value_, NID_pkcs7_data));
1605
1606 STACK_OF(X509) *certs(stuff);
1607 for (unsigned i(0), e(sk_X509_num(certs)); i != e; i++)
1608 _assert(PKCS7_add_certificate(value_, sk_X509_value(certs, e - i - 1)));
1609
1610 // XXX: this is the same as PKCS7_sign_add_signer(value_, stuff, stuff, NULL, PKCS7_NOSMIMECAP)
1611 _assert(X509_check_private_key(stuff, stuff));
1612 auto info(PKCS7_add_signature(value_, stuff, stuff, EVP_sha1()));
1613 _assert(info != NULL);
1614 _assert(PKCS7_add_certificate(value_, stuff));
1615 _assert(PKCS7_add_signed_attribute(info, NID_pkcs9_contentType, V_ASN1_OBJECT, OBJ_nid2obj(NID_pkcs7_data)));
1616
1617 PKCS7_set_detached(value_, 1);
1618
1619 ASN1_OCTET_STRING *string(ASN1_OCTET_STRING_new());
1620 _assert(string != NULL);
1621 try {
1622 _assert(ASN1_STRING_set(string, xml.data(), xml.size()));
1623
1624 static auto nid(OBJ_create("1.2.840.113635.100.9.1", "", ""));
1625 _assert(PKCS7_add_signed_attribute(info, nid, V_ASN1_OCTET_STRING, string));
1626 } catch (...) {
1627 ASN1_OCTET_STRING_free(string);
1628 throw;
1629 }
1630
1631 // XXX: this is the same as PKCS7_final(value_, data, PKCS7_BINARY)
1632 BIO *bio(PKCS7_dataInit(value_, NULL));
1633 _assert(bio != NULL);
1634 _scope({ BIO_free_all(bio); });
1635 SMIME_crlf_copy(data, bio, PKCS7_BINARY);
1636 BIO_flush(bio);
1637 _assert(PKCS7_dataFinal(value_, bio));
1638 }
1639
1640 ~Signature() {
1641 PKCS7_free(value_);
1642 }
1643
1644 operator PKCS7 *() const {
1645 return value_;
1646 }
1647 };
1648 #endif
1649
1650 class NullBuffer :
1651 public std::streambuf
1652 {
1653 public:
1654 virtual std::streamsize xsputn(const char_type *data, std::streamsize size) {
1655 return size;
1656 }
1657
1658 virtual int_type overflow(int_type next) {
1659 return next;
1660 }
1661 };
1662
1663 class HashBuffer :
1664 public std::streambuf
1665 {
1666 private:
1667 ldid::Hash &hash_;
1668
1669 LDID_SHA1_CTX sha1_;
1670 LDID_SHA256_CTX sha256_;
1671
1672 public:
1673 HashBuffer(ldid::Hash &hash) :
1674 hash_(hash)
1675 {
1676 LDID_SHA1_Init(&sha1_);
1677 LDID_SHA256_Init(&sha256_);
1678 }
1679
1680 ~HashBuffer() {
1681 LDID_SHA1_Final(reinterpret_cast<uint8_t *>(hash_.sha1_), &sha1_);
1682 LDID_SHA256_Final(reinterpret_cast<uint8_t *>(hash_.sha256_), &sha256_);
1683 }
1684
1685 virtual std::streamsize xsputn(const char_type *data, std::streamsize size) {
1686 LDID_SHA1_Update(&sha1_, data, size);
1687 LDID_SHA256_Update(&sha256_, data, size);
1688 return size;
1689 }
1690
1691 virtual int_type overflow(int_type next) {
1692 if (next == traits_type::eof())
1693 return sync();
1694 char value(next);
1695 xsputn(&value, 1);
1696 return next;
1697 }
1698 };
1699
1700 class HashProxy :
1701 public HashBuffer
1702 {
1703 private:
1704 std::streambuf &buffer_;
1705
1706 public:
1707 HashProxy(ldid::Hash &hash, std::streambuf &buffer) :
1708 HashBuffer(hash),
1709 buffer_(buffer)
1710 {
1711 }
1712
1713 virtual std::streamsize xsputn(const char_type *data, std::streamsize size) {
1714 _assert(HashBuffer::xsputn(data, size) == size);
1715 return buffer_.sputn(data, size);
1716 }
1717 };
1718
1719 #ifndef LDID_NOTOOLS
1720 static bool Starts(const std::string &lhs, const std::string &rhs) {
1721 return lhs.size() >= rhs.size() && lhs.compare(0, rhs.size(), rhs) == 0;
1722 }
1723
1724 class Split {
1725 public:
1726 std::string dir;
1727 std::string base;
1728
1729 Split(const std::string &path) {
1730 size_t slash(path.rfind('/'));
1731 if (slash == std::string::npos)
1732 base = path;
1733 else {
1734 dir = path.substr(0, slash + 1);
1735 base = path.substr(slash + 1);
1736 }
1737 }
1738 };
1739
1740 static void mkdir_p(const std::string &path) {
1741 if (path.empty())
1742 return;
1743 #ifdef __WIN32__
1744 if (_syscall(mkdir(path.c_str()), EEXIST) == -EEXIST)
1745 return;
1746 #else
1747 if (_syscall(mkdir(path.c_str(), 0755), EEXIST) == -EEXIST)
1748 return;
1749 #endif
1750 auto slash(path.rfind('/', path.size() - 1));
1751 if (slash == std::string::npos)
1752 return;
1753 mkdir_p(path.substr(0, slash));
1754 }
1755
1756 static std::string Temporary(std::filebuf &file, const Split &split) {
1757 std::string temp(split.dir + ".ldid." + split.base);
1758 mkdir_p(split.dir);
1759 _assert_(file.open(temp.c_str(), std::ios::out | std::ios::trunc | std::ios::binary) == &file, "open(): %s", temp.c_str());
1760 return temp;
1761 }
1762
1763 static void Commit(const std::string &path, const std::string &temp) {
1764 struct stat info;
1765 if (_syscall(stat(path.c_str(), &info), ENOENT) == 0) {
1766 #ifndef __WIN32__
1767 _syscall(chown(temp.c_str(), info.st_uid, info.st_gid));
1768 #endif
1769 _syscall(chmod(temp.c_str(), info.st_mode));
1770 }
1771
1772 _syscall(rename(temp.c_str(), path.c_str()));
1773 }
1774 #endif
1775
1776 namespace ldid {
1777
1778 #ifndef LDID_NOSMIME
1779 static void get(std::string &value, X509_NAME *name, int nid) {
1780 auto index(X509_NAME_get_index_by_NID(name, nid, -1));
1781 _assert(index >= 0);
1782 auto next(X509_NAME_get_index_by_NID(name, nid, index));
1783 _assert(next == -1);
1784 auto entry(X509_NAME_get_entry(name, index));
1785 _assert(entry != NULL);
1786 auto asn(X509_NAME_ENTRY_get_data(entry));
1787 _assert(asn != NULL);
1788 value.assign(reinterpret_cast<char *>(ASN1_STRING_data(asn)), ASN1_STRING_length(asn));
1789 }
1790 #endif
1791
1792 static void req(std::streambuf &buffer, uint32_t value) {
1793 value = Swap(value);
1794 put(buffer, &value, sizeof(value));
1795 }
1796
1797 static void req(std::streambuf &buffer, const std::string &value) {
1798 req(buffer, value.size());
1799 put(buffer, value.data(), value.size());
1800 static uint8_t zeros[] = {0,0,0,0};
1801 put(buffer, zeros, 3 - (value.size() + 3) % 4);
1802 }
1803
1804 template <size_t Size_>
1805 static void req(std::streambuf &buffer, uint8_t (&&data)[Size_]) {
1806 req(buffer, Size_);
1807 put(buffer, data, Size_);
1808 static uint8_t zeros[] = {0,0,0,0};
1809 put(buffer, zeros, 3 - (Size_ + 3) % 4);
1810 }
1811
1812 Hash Sign(const void *idata, size_t isize, std::streambuf &output, const std::string &identifier, const std::string &entitlements, bool merge, const std::string &requirements, const std::string &key, const Slots &slots, uint32_t flags, bool platform, const Progress &progress) {
1813 Hash hash;
1814
1815
1816 std::string team;
1817 std::string common;
1818
1819 #ifndef LDID_NOSMIME
1820 if (!key.empty()) {
1821 Stuff stuff(key);
1822 auto name(X509_get_subject_name(stuff));
1823 _assert(name != NULL);
1824 get(team, name, NID_organizationalUnitName);
1825 get(common, name, NID_commonName);
1826 }
1827 #endif
1828
1829
1830 std::stringbuf backing;
1831
1832 if (!requirements.empty()) {
1833 put(backing, requirements.data(), requirements.size());
1834 } else {
1835 Blobs blobs;
1836
1837 std::stringbuf requirement;
1838 req(requirement, exprForm);
1839 req(requirement, opAnd);
1840 req(requirement, opIdent);
1841 req(requirement, identifier);
1842 req(requirement, opAnd);
1843 req(requirement, opAppleGenericAnchor);
1844 req(requirement, opAnd);
1845 req(requirement, opCertField);
1846 req(requirement, 0);
1847 req(requirement, "subject.CN");
1848 req(requirement, matchEqual);
1849 req(requirement, common);
1850 req(requirement, opCertGeneric);
1851 req(requirement, 1);
1852 req(requirement, (uint8_t []) {APPLE_EXTENSION_OID, 2, 1});
1853 req(requirement, matchExists);
1854 insert(blobs, 3, CSMAGIC_REQUIREMENT, requirement);
1855
1856 put(backing, CSMAGIC_REQUIREMENTS, blobs);
1857 }
1858
1859
1860 // XXX: this is just a "sufficiently large number"
1861 size_t certificate(0x3000);
1862
1863 Allocate(idata, isize, output, fun([&](const MachHeader &mach_header, Baton &baton, size_t size) -> size_t {
1864 size_t alloc(sizeof(struct SuperBlob));
1865
1866 uint32_t normal((size + PageSize_ - 1) / PageSize_);
1867
1868 uint32_t special(0);
1869
1870 _foreach (slot, slots)
1871 special = std::max(special, slot.first);
1872
1873 mach_header.ForSection(fun([&](const char *segment, const char *section, void *data, size_t size) {
1874 if (strcmp(segment, "__TEXT") == 0 && section != NULL && strcmp(section, "__info_plist") == 0)
1875 special = std::max(special, CSSLOT_INFOSLOT);
1876 }));
1877
1878 special = std::max(special, CSSLOT_REQUIREMENTS);
1879 alloc += sizeof(struct BlobIndex);
1880 alloc += backing.str().size();
1881
1882 if (!merge)
1883 baton.entitlements_ = entitlements;
1884 else {
1885 #ifndef LDID_NOPLIST
1886 Analyze(mach_header, fun([&](const char *data, size_t size) {
1887 baton.entitlements_.assign(data, size);
1888 }));
1889
1890 if (baton.entitlements_.empty())
1891 baton.entitlements_ = entitlements;
1892 else if (!entitlements.empty()) {
1893 auto combined(plist(baton.entitlements_));
1894 _scope({ plist_free(combined); });
1895 _assert(plist_get_node_type(combined) == PLIST_DICT);
1896
1897 auto merging(plist(entitlements));
1898 _scope({ plist_free(merging); });
1899 _assert(plist_get_node_type(merging) == PLIST_DICT);
1900
1901 plist_dict_iter iterator(NULL);
1902 plist_dict_new_iter(merging, &iterator);
1903 _scope({ free(iterator); });
1904
1905 for (;;) {
1906 char *key(NULL);
1907 plist_t value(NULL);
1908 plist_dict_next_item(merging, iterator, &key, &value);
1909 if (key == NULL)
1910 break;
1911 _scope({ free(key); });
1912 plist_dict_set_item(combined, key, plist_copy(value));
1913 }
1914
1915 char *xml(NULL);
1916 uint32_t size;
1917 plist_to_xml(combined, &xml, &size);
1918 _scope({ free(xml); });
1919
1920 baton.entitlements_.assign(xml, size);
1921 }
1922 #else
1923 _assert(false);
1924 #endif
1925 }
1926
1927 if (!baton.entitlements_.empty()) {
1928 special = std::max(special, CSSLOT_ENTITLEMENTS);
1929 alloc += sizeof(struct BlobIndex);
1930 alloc += sizeof(struct Blob);
1931 alloc += baton.entitlements_.size();
1932 }
1933
1934 size_t directory(0);
1935
1936 directory += sizeof(struct BlobIndex);
1937 directory += sizeof(struct Blob);
1938 directory += sizeof(struct CodeDirectory);
1939 directory += identifier.size() + 1;
1940
1941 if (!team.empty())
1942 directory += team.size() + 1;
1943
1944 for (Algorithm *algorithm : GetAlgorithms())
1945 alloc = Align(alloc + directory + (special + normal) * algorithm->size_, 16);
1946
1947 #ifndef LDID_NOSMIME
1948 if (!key.empty()) {
1949 alloc += sizeof(struct BlobIndex);
1950 alloc += sizeof(struct Blob);
1951 alloc += certificate;
1952 }
1953 #endif
1954
1955 return alloc;
1956 }), fun([&](const MachHeader &mach_header, const Baton &baton, std::streambuf &output, size_t limit, const std::string &overlap, const char *top, const Progress &progress) -> size_t {
1957 Blobs blobs;
1958
1959 if (true) {
1960 insert(blobs, CSSLOT_REQUIREMENTS, backing);
1961 }
1962
1963 if (!baton.entitlements_.empty()) {
1964 std::stringbuf data;
1965 put(data, baton.entitlements_.data(), baton.entitlements_.size());
1966 insert(blobs, CSSLOT_ENTITLEMENTS, CSMAGIC_EMBEDDED_ENTITLEMENTS, data);
1967 }
1968
1969 Slots posts(slots);
1970
1971 mach_header.ForSection(fun([&](const char *segment, const char *section, void *data, size_t size) {
1972 if (strcmp(segment, "__TEXT") == 0 && section != NULL && strcmp(section, "__info_plist") == 0) {
1973 auto &slot(posts[CSSLOT_INFOSLOT]);
1974 for (Algorithm *algorithm : GetAlgorithms())
1975 (*algorithm)(slot, data, size);
1976 }
1977 }));
1978
1979 unsigned total(0);
1980 for (Algorithm *pointer : GetAlgorithms()) {
1981 Algorithm &algorithm(*pointer);
1982
1983 std::stringbuf data;
1984
1985 uint32_t special(0);
1986 _foreach (blob, blobs)
1987 special = std::max(special, blob.first);
1988 _foreach (slot, posts)
1989 special = std::max(special, slot.first);
1990 uint32_t normal((limit + PageSize_ - 1) / PageSize_);
1991
1992 CodeDirectory directory;
1993 directory.version = Swap(uint32_t(0x00020200));
1994 directory.flags = Swap(uint32_t(flags));
1995 directory.nSpecialSlots = Swap(special);
1996 directory.codeLimit = Swap(uint32_t(limit));
1997 directory.nCodeSlots = Swap(normal);
1998 directory.hashSize = algorithm.size_;
1999 directory.hashType = algorithm.type_;
2000 directory.platform = platform ? 0x01 : 0x00;
2001 directory.pageSize = PageShift_;
2002 directory.spare2 = Swap(uint32_t(0));
2003 directory.scatterOffset = Swap(uint32_t(0));
2004 //directory.spare3 = Swap(uint32_t(0));
2005 //directory.codeLimit64 = Swap(uint64_t(0));
2006
2007 uint32_t offset(sizeof(Blob) + sizeof(CodeDirectory));
2008
2009 directory.identOffset = Swap(uint32_t(offset));
2010 offset += identifier.size() + 1;
2011
2012 if (team.empty())
2013 directory.teamIDOffset = Swap(uint32_t(0));
2014 else {
2015 directory.teamIDOffset = Swap(uint32_t(offset));
2016 offset += team.size() + 1;
2017 }
2018
2019 offset += special * algorithm.size_;
2020 directory.hashOffset = Swap(uint32_t(offset));
2021 offset += normal * algorithm.size_;
2022
2023 put(data, &directory, sizeof(directory));
2024
2025 put(data, identifier.c_str(), identifier.size() + 1);
2026 if (!team.empty())
2027 put(data, team.c_str(), team.size() + 1);
2028
2029 std::vector<uint8_t> storage((special + normal) * algorithm.size_);
2030 auto *hashes(&storage[special * algorithm.size_]);
2031
2032 memset(storage.data(), 0, special * algorithm.size_);
2033
2034 _foreach (blob, blobs) {
2035 auto local(reinterpret_cast<const Blob *>(&blob.second[0]));
2036 algorithm(hashes - blob.first * algorithm.size_, local, Swap(local->length));
2037 }
2038
2039 _foreach (slot, posts)
2040 memcpy(hashes - slot.first * algorithm.size_, algorithm[slot.second], algorithm.size_);
2041
2042 progress(0);
2043 if (normal != 1)
2044 for (size_t i = 0; i != normal - 1; ++i) {
2045 algorithm(hashes + i * algorithm.size_, (PageSize_ * i < overlap.size() ? overlap.data() : top) + PageSize_ * i, PageSize_);
2046 progress(double(i) / normal);
2047 }
2048 if (normal != 0)
2049 algorithm(hashes + (normal - 1) * algorithm.size_, top + PageSize_ * (normal - 1), ((limit - 1) % PageSize_) + 1);
2050 progress(1);
2051
2052 put(data, storage.data(), storage.size());
2053
2054 const auto &save(insert(blobs, total == 0 ? CSSLOT_CODEDIRECTORY : CSSLOT_ALTERNATE + total - 1, CSMAGIC_CODEDIRECTORY, data));
2055 algorithm(hash, save.data(), save.size());
2056
2057 ++total;
2058 }
2059
2060 #ifndef LDID_NOSMIME
2061 if (!key.empty()) {
2062 #ifdef LDID_NOPLIST
2063 auto plist(CFDictionaryCreateMutable(kCFAllocatorDefault, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks));
2064 _scope({ CFRelease(plist); });
2065
2066 auto cdhashes(CFArrayCreateMutable(kCFAllocatorDefault, 0, &kCFTypeArrayCallBacks));
2067 _scope({ CFRelease(cdhashes); });
2068
2069 CFDictionarySetValue(plist, CFSTR("cdhashes"), cdhashes);
2070 #else
2071 auto plist(plist_new_dict());
2072 _scope({ plist_free(plist); });
2073
2074 auto cdhashes(plist_new_array());
2075 plist_dict_set_item(plist, "cdhashes", cdhashes);
2076 #endif
2077
2078 unsigned total(0);
2079 for (Algorithm *pointer : GetAlgorithms()) {
2080 Algorithm &algorithm(*pointer);
2081 (void) algorithm;
2082
2083 const auto &blob(blobs[total == 0 ? CSSLOT_CODEDIRECTORY : CSSLOT_ALTERNATE + total - 1]);
2084 ++total;
2085
2086 std::vector<char> hash;
2087 algorithm(hash, blob.data(), blob.size());
2088 hash.resize(20);
2089
2090 #ifdef LDID_NOPLIST
2091 auto value(CFDataCreate(kCFAllocatorDefault, reinterpret_cast<const UInt8 *>(hash.data()), hash.size()));
2092 _scope({ CFRelease(value); });
2093 CFArrayAppendValue(cdhashes, value);
2094 #else
2095 plist_array_append_item(cdhashes, plist_new_data(hash.data(), hash.size()));
2096 #endif
2097 }
2098
2099 #ifdef LDID_NOPLIST
2100 auto created(CFPropertyListCreateXMLData(kCFAllocatorDefault, plist));
2101 _scope({ CFRelease(created); });
2102 auto xml(reinterpret_cast<const char *>(CFDataGetBytePtr(created)));
2103 auto size(CFDataGetLength(created));
2104 #else
2105 char *xml(NULL);
2106 uint32_t size;
2107 plist_to_xml(plist, &xml, &size);
2108 _scope({ free(xml); });
2109 #endif
2110
2111 std::stringbuf data;
2112 const std::string &sign(blobs[CSSLOT_CODEDIRECTORY]);
2113
2114 Stuff stuff(key);
2115 Buffer bio(sign);
2116
2117 Signature signature(stuff, sign, std::string(xml, size));
2118 Buffer result(signature);
2119 std::string value(result);
2120 put(data, value.data(), value.size());
2121
2122 const auto &save(insert(blobs, CSSLOT_SIGNATURESLOT, CSMAGIC_BLOBWRAPPER, data));
2123 _assert(save.size() <= certificate);
2124 }
2125 #endif
2126
2127 return put(output, CSMAGIC_EMBEDDED_SIGNATURE, blobs);
2128 }), progress);
2129
2130 return hash;
2131 }
2132
2133 #ifndef LDID_NOTOOLS
2134 static void Unsign(void *idata, size_t isize, std::streambuf &output, const Progress &progress) {
2135 Allocate(idata, isize, output, fun([](const MachHeader &mach_header, Baton &baton, size_t size) -> size_t {
2136 return 0;
2137 }), fun([](const MachHeader &mach_header, const Baton &baton, std::streambuf &output, size_t limit, const std::string &overlap, const char *top, const Progress &progress) -> size_t {
2138 return 0;
2139 }), progress);
2140 }
2141
2142 std::string DiskFolder::Path(const std::string &path) const {
2143 return path_ + path;
2144 }
2145
2146 DiskFolder::DiskFolder(const std::string &path) :
2147 path_(path)
2148 {
2149 _assert_(path_.size() != 0 && path_[path_.size() - 1] == '/', "missing / on %s", path_.c_str());
2150 }
2151
2152 DiskFolder::~DiskFolder() {
2153 if (!std::uncaught_exception())
2154 for (const auto &commit : commit_)
2155 Commit(commit.first, commit.second);
2156 }
2157
2158 #ifndef __WIN32__
2159 std::string readlink(const std::string &path) {
2160 for (size_t size(1024); ; size *= 2) {
2161 std::string data;
2162 data.resize(size);
2163
2164 int writ(_syscall(::readlink(path.c_str(), &data[0], data.size())));
2165 if (size_t(writ) >= size)
2166 continue;
2167
2168 data.resize(writ);
2169 return data;
2170 }
2171 }
2172 #endif
2173
2174 void DiskFolder::Find(const std::string &root, const std::string &base, const Functor<void (const std::string &)> &code, const Functor<void (const std::string &, const Functor<std::string ()> &)> &link) const {
2175 std::string path(Path(root) + base);
2176
2177 DIR *dir(opendir(path.c_str()));
2178 _assert(dir != NULL);
2179 _scope({ _syscall(closedir(dir)); });
2180
2181 while (auto child = readdir(dir)) {
2182 std::string name(child->d_name);
2183 if (name == "." || name == "..")
2184 continue;
2185 if (Starts(name, ".ldid."))
2186 continue;
2187
2188 bool directory;
2189
2190 #ifdef __WIN32__
2191 struct stat info;
2192 _syscall(stat((path + name).c_str(), &info));
2193 if (false);
2194 else if (S_ISDIR(info.st_mode))
2195 directory = true;
2196 else if (S_ISREG(info.st_mode))
2197 directory = false;
2198 else
2199 _assert_(false, "st_mode=%x", info.st_mode);
2200 #else
2201 switch (child->d_type) {
2202 case DT_DIR:
2203 directory = true;
2204 break;
2205 case DT_REG:
2206 directory = false;
2207 break;
2208 case DT_LNK:
2209 link(base + name, fun([&]() { return readlink(path + name); }));
2210 continue;
2211 default:
2212 _assert_(false, "d_type=%u", child->d_type);
2213 }
2214 #endif
2215
2216 if (directory)
2217 Find(root, base + name + "/", code, link);
2218 else
2219 code(base + name);
2220 }
2221 }
2222
2223 void DiskFolder::Save(const std::string &path, bool edit, const void *flag, const Functor<void (std::streambuf &)> &code) {
2224 if (!edit) {
2225 // XXX: use nullbuf
2226 std::stringbuf save;
2227 code(save);
2228 } else {
2229 std::filebuf save;
2230 auto from(Path(path));
2231 commit_[from] = Temporary(save, from);
2232 code(save);
2233 }
2234 }
2235
2236 bool DiskFolder::Look(const std::string &path) const {
2237 return _syscall(access(Path(path).c_str(), R_OK), ENOENT) == 0;
2238 }
2239
2240 void DiskFolder::Open(const std::string &path, const Functor<void (std::streambuf &, size_t, const void *)> &code) const {
2241 std::filebuf data;
2242 auto result(data.open(Path(path).c_str(), std::ios::binary | std::ios::in));
2243 _assert_(result == &data, "DiskFolder::Open(%s)", Path(path).c_str());
2244
2245 auto length(data.pubseekoff(0, std::ios::end, std::ios::in));
2246 data.pubseekpos(0, std::ios::in);
2247 code(data, length, NULL);
2248 }
2249
2250 void DiskFolder::Find(const std::string &path, const Functor<void (const std::string &)> &code, const Functor<void (const std::string &, const Functor<std::string ()> &)> &link) const {
2251 Find(path, "", code, link);
2252 }
2253 #endif
2254
2255 SubFolder::SubFolder(Folder &parent, const std::string &path) :
2256 parent_(parent),
2257 path_(path)
2258 {
2259 _assert_(path_.size() == 0 || path_[path_.size() - 1] == '/', "missing / on %s", path_.c_str());
2260 }
2261
2262 std::string SubFolder::Path(const std::string &path) const {
2263 return path_ + path;
2264 }
2265
2266 void SubFolder::Save(const std::string &path, bool edit, const void *flag, const Functor<void (std::streambuf &)> &code) {
2267 return parent_.Save(Path(path), edit, flag, code);
2268 }
2269
2270 bool SubFolder::Look(const std::string &path) const {
2271 return parent_.Look(Path(path));
2272 }
2273
2274 void SubFolder::Open(const std::string &path, const Functor<void (std::streambuf &, size_t, const void *)> &code) const {
2275 return parent_.Open(Path(path), code);
2276 }
2277
2278 void SubFolder::Find(const std::string &path, const Functor<void (const std::string &)> &code, const Functor<void (const std::string &, const Functor<std::string ()> &)> &link) const {
2279 return parent_.Find(Path(path), code, link);
2280 }
2281
2282 std::string UnionFolder::Map(const std::string &path) const {
2283 auto remap(remaps_.find(path));
2284 if (remap == remaps_.end())
2285 return path;
2286 return remap->second;
2287 }
2288
2289 void UnionFolder::Map(const std::string &path, const Functor<void (const std::string &)> &code, const std::string &file, const Functor<void (const Functor<void (std::streambuf &, size_t, const void *)> &)> &save) const {
2290 if (file.size() >= path.size() && file.substr(0, path.size()) == path)
2291 code(file.substr(path.size()));
2292 }
2293
2294 UnionFolder::UnionFolder(Folder &parent) :
2295 parent_(parent)
2296 {
2297 }
2298
2299 void UnionFolder::Save(const std::string &path, bool edit, const void *flag, const Functor<void (std::streambuf &)> &code) {
2300 return parent_.Save(Map(path), edit, flag, code);
2301 }
2302
2303 bool UnionFolder::Look(const std::string &path) const {
2304 auto file(resets_.find(path));
2305 if (file != resets_.end())
2306 return true;
2307 return parent_.Look(Map(path));
2308 }
2309
2310 void UnionFolder::Open(const std::string &path, const Functor<void (std::streambuf &, size_t, const void *)> &code) const {
2311 auto file(resets_.find(path));
2312 if (file == resets_.end())
2313 return parent_.Open(Map(path), code);
2314 auto &entry(file->second);
2315
2316 auto &data(*entry.data_);
2317 auto length(data.pubseekoff(0, std::ios::end, std::ios::in));
2318 data.pubseekpos(0, std::ios::in);
2319 code(data, length, entry.flag_);
2320 }
2321
2322 void UnionFolder::Find(const std::string &path, const Functor<void (const std::string &)> &code, const Functor<void (const std::string &, const Functor<std::string ()> &)> &link) const {
2323 for (auto &reset : resets_)
2324 Map(path, code, reset.first, fun([&](const Functor<void (std::streambuf &, size_t, const void *)> &code) {
2325 auto &entry(reset.second);
2326 auto &data(*entry.data_);
2327 auto length(data.pubseekoff(0, std::ios::end, std::ios::in));
2328 data.pubseekpos(0, std::ios::in);
2329 code(data, length, entry.flag_);
2330 }));
2331
2332 for (auto &remap : remaps_)
2333 Map(path, code, remap.first, fun([&](const Functor<void (std::streambuf &, size_t, const void *)> &code) {
2334 parent_.Open(remap.second, fun([&](std::streambuf &data, size_t length, const void *flag) {
2335 code(data, length, flag);
2336 }));
2337 }));
2338
2339 parent_.Find(path, fun([&](const std::string &name) {
2340 if (deletes_.find(path + name) == deletes_.end())
2341 code(name);
2342 }), fun([&](const std::string &name, const Functor<std::string ()> &read) {
2343 if (deletes_.find(path + name) == deletes_.end())
2344 link(name, read);
2345 }));
2346 }
2347
2348 #ifndef LDID_NOTOOLS
2349 static void copy(std::streambuf &source, std::streambuf &target, size_t length, const Progress &progress) {
2350 progress(0);
2351 size_t total(0);
2352 for (;;) {
2353 char data[4096 * 4];
2354 size_t writ(source.sgetn(data, sizeof(data)));
2355 if (writ == 0)
2356 break;
2357 _assert(target.sputn(data, writ) == writ);
2358 total += writ;
2359 progress(double(total) / length);
2360 }
2361 }
2362
2363 #ifndef LDID_NOPLIST
2364 static plist_t plist(const std::string &data) {
2365 plist_t plist(NULL);
2366 if (Starts(data, "bplist00"))
2367 plist_from_bin(data.data(), data.size(), &plist);
2368 else
2369 plist_from_xml(data.data(), data.size(), &plist);
2370 _assert(plist != NULL);
2371 return plist;
2372 }
2373
2374 static void plist_d(std::streambuf &buffer, size_t length, const Functor<void (plist_t)> &code) {
2375 std::stringbuf data;
2376 copy(buffer, data, length, dummy_);
2377 auto node(plist(data.str()));
2378 _scope({ plist_free(node); });
2379 _assert(plist_get_node_type(node) == PLIST_DICT);
2380 code(node);
2381 }
2382
2383 static std::string plist_s(plist_t node) {
2384 _assert(node != NULL);
2385 _assert(plist_get_node_type(node) == PLIST_STRING);
2386 char *data;
2387 plist_get_string_val(node, &data);
2388 _scope({ free(data); });
2389 return data;
2390 }
2391 #endif
2392
2393 enum Mode {
2394 NoMode,
2395 OptionalMode,
2396 OmitMode,
2397 NestedMode,
2398 TopMode,
2399 };
2400
2401 class Expression {
2402 private:
2403 regex_t regex_;
2404 std::vector<std::string> matches_;
2405
2406 public:
2407 Expression(const std::string &code) {
2408 _assert_(regcomp(&regex_, code.c_str(), REG_EXTENDED) == 0, "regcomp()");
2409 matches_.resize(regex_.re_nsub + 1);
2410 }
2411
2412 ~Expression() {
2413 regfree(&regex_);
2414 }
2415
2416 bool operator ()(const std::string &data) {
2417 regmatch_t matches[matches_.size()];
2418 auto value(regexec(&regex_, data.c_str(), matches_.size(), matches, 0));
2419 if (value == REG_NOMATCH)
2420 return false;
2421 _assert_(value == 0, "regexec()");
2422 for (size_t i(0); i != matches_.size(); ++i)
2423 matches_[i].assign(data.data() + matches[i].rm_so, matches[i].rm_eo - matches[i].rm_so);
2424 return true;
2425 }
2426
2427 const std::string &operator [](size_t index) const {
2428 return matches_[index];
2429 }
2430 };
2431
2432 struct Rule {
2433 unsigned weight_;
2434 Mode mode_;
2435 std::string code_;
2436
2437 mutable std::auto_ptr<Expression> regex_;
2438
2439 Rule(unsigned weight, Mode mode, const std::string &code) :
2440 weight_(weight),
2441 mode_(mode),
2442 code_(code)
2443 {
2444 }
2445
2446 Rule(const Rule &rhs) :
2447 weight_(rhs.weight_),
2448 mode_(rhs.mode_),
2449 code_(rhs.code_)
2450 {
2451 }
2452
2453 void Compile() const {
2454 regex_.reset(new Expression(code_));
2455 }
2456
2457 bool operator ()(const std::string &data) const {
2458 _assert(regex_.get() != NULL);
2459 return (*regex_)(data);
2460 }
2461
2462 bool operator <(const Rule &rhs) const {
2463 if (weight_ > rhs.weight_)
2464 return true;
2465 if (weight_ < rhs.weight_)
2466 return false;
2467 return mode_ > rhs.mode_;
2468 }
2469 };
2470
2471 struct RuleCode {
2472 bool operator ()(const Rule *lhs, const Rule *rhs) const {
2473 return lhs->code_ < rhs->code_;
2474 }
2475 };
2476
2477 #ifndef LDID_NOPLIST
2478 static Hash Sign(const uint8_t *prefix, size_t size, std::streambuf &buffer, Hash &hash, std::streambuf &save, const std::string &identifier, const std::string &entitlements, bool merge, const std::string &requirements, const std::string &key, const Slots &slots, size_t length, uint32_t flags, bool platform, const Progress &progress) {
2479 // XXX: this is a miserable fail
2480 std::stringbuf temp;
2481 put(temp, prefix, size);
2482 copy(buffer, temp, length - size, progress);
2483 // XXX: this is a stupid hack
2484 pad(temp, 0x10 - (length & 0xf));
2485 auto data(temp.str());
2486
2487 HashProxy proxy(hash, save);
2488 return Sign(data.data(), data.size(), proxy, identifier, entitlements, merge, requirements, key, slots, flags, platform, progress);
2489 }
2490
2491 struct State {
2492 std::map<std::string, Hash> files;
2493 std::map<std::string, std::string> links;
2494
2495 void Merge(const std::string &root, const State &state) {
2496 for (const auto &entry : state.files)
2497 files[root + entry.first] = entry.second;
2498 for (const auto &entry : state.links)
2499 links[root + entry.first] = entry.second;
2500 }
2501 };
2502
2503 Bundle Sign(const std::string &root, Folder &parent, const std::string &key, State &remote, const std::string &requirements, const Functor<std::string (const std::string &, const std::string &)> &alter, const Progress &progress) {
2504 std::string executable;
2505 std::string identifier;
2506
2507 bool mac(false);
2508
2509 std::string info("Info.plist");
2510
2511 SubFolder folder(parent, [&]() {
2512 if (parent.Look(info))
2513 return "";
2514 mac = true;
2515 if (false);
2516 else if (parent.Look("Contents/" + info))
2517 return "Contents/";
2518 else if (parent.Look("Resources/" + info)) {
2519 info = "Resources/" + info;
2520 return "";
2521 } else _assert_(false, "cannot find Info.plist");
2522 }());
2523
2524 folder.Open(info, fun([&](std::streambuf &buffer, size_t length, const void *flag) {
2525 plist_d(buffer, length, fun([&](plist_t node) {
2526 executable = plist_s(plist_dict_get_item(node, "CFBundleExecutable"));
2527 identifier = plist_s(plist_dict_get_item(node, "CFBundleIdentifier"));
2528 }));
2529 }));
2530
2531 if (mac && info == "Info.plist")
2532 executable = "MacOS/" + executable;
2533
2534 progress(root + "*");
2535
2536 std::string entitlements;
2537 folder.Open(executable, fun([&](std::streambuf &buffer, size_t length, const void *flag) {
2538 // XXX: this is a miserable fail
2539 std::stringbuf temp;
2540 copy(buffer, temp, length, progress);
2541 // XXX: this is a stupid hack
2542 pad(temp, 0x10 - (length & 0xf));
2543 auto data(temp.str());
2544 entitlements = alter(root, Analyze(data.data(), data.size()));
2545 }));
2546
2547 static const std::string directory("_CodeSignature/");
2548 static const std::string signature(directory + "CodeResources");
2549
2550 std::map<std::string, std::multiset<Rule>> versions;
2551
2552 auto &rules1(versions[""]);
2553 auto &rules2(versions["2"]);
2554
2555 const std::string resources(mac ? "Resources/" : "");
2556
2557 if (true) {
2558 rules1.insert(Rule{1, NoMode, "^" + (resources == "" ? ".*" : resources)});
2559 rules1.insert(Rule{1000, OptionalMode, "^" + resources + ".*\\.lproj/"});
2560 rules1.insert(Rule{1100, OmitMode, "^" + resources + ".*\\.lproj/locversion.plist$"});
2561 rules1.insert(Rule{1010, NoMode, "^" + resources + "Base\\.lproj/"});
2562 rules1.insert(Rule{1, NoMode, "^version.plist$"});
2563 }
2564
2565 if (true) {
2566 rules2.insert(Rule{11, NoMode, ".*\\.dSYM($|/)"});
2567 if (mac) rules2.insert(Rule{20, NoMode, "^" + resources});
2568 rules2.insert(Rule{2000, OmitMode, "^(.*/)?\\.DS_Store$"});
2569 if (mac) rules2.insert(Rule{10, NestedMode, "^(Frameworks|SharedFrameworks|PlugIns|Plug-ins|XPCServices|Helpers|MacOS|Library/(Automator|Spotlight|LoginItems))/"});
2570 rules2.insert(Rule{1, NoMode, "^.*"});
2571 rules2.insert(Rule{1000, OptionalMode, "^" + resources + ".*\\.lproj/"});
2572 rules2.insert(Rule{1100, OmitMode, "^" + resources + ".*\\.lproj/locversion.plist$"});
2573 if (!mac) rules2.insert(Rule{1010, NoMode, "^Base\\.lproj/"});
2574 rules2.insert(Rule{20, OmitMode, "^Info\\.plist$"});
2575 rules2.insert(Rule{20, OmitMode, "^PkgInfo$"});
2576 if (mac) rules2.insert(Rule{10, NestedMode, "^[^/]+$"});
2577 rules2.insert(Rule{20, NoMode, "^embedded\\.provisionprofile$"});
2578 if (mac) rules2.insert(Rule{1010, NoMode, "^" + resources + "Base\\.lproj/"});
2579 rules2.insert(Rule{20, NoMode, "^version\\.plist$"});
2580 }
2581
2582 State local;
2583
2584 std::string failure(mac ? "Contents/|Versions/[^/]*/Resources/" : "");
2585 Expression nested("^(Frameworks/[^/]*\\.framework|PlugIns/[^/]*\\.appex(()|/[^/]*.app))/(" + failure + ")Info\\.plist$");
2586 std::map<std::string, Bundle> bundles;
2587
2588 folder.Find("", fun([&](const std::string &name) {
2589 if (!nested(name))
2590 return;
2591 auto bundle(root + Split(name).dir);
2592 if (mac) {
2593 _assert(!bundle.empty());
2594 bundle = Split(bundle.substr(0, bundle.size() - 1)).dir;
2595 }
2596 SubFolder subfolder(folder, bundle);
2597
2598 bundles[nested[1]] = Sign(bundle, subfolder, key, local, "", Starts(name, "PlugIns/") ? alter :
2599 static_cast<const Functor<std::string (const std::string &, const std::string &)> &>(fun([&](const std::string &, const std::string &) -> std::string { return entitlements; }))
2600 , progress);
2601 }), fun([&](const std::string &name, const Functor<std::string ()> &read) {
2602 }));
2603
2604 std::set<std::string> excludes;
2605
2606 auto exclude([&](const std::string &name) {
2607 // BundleDiskRep::adjustResources -> builder.addExclusion
2608 if (name == executable || Starts(name, directory) || Starts(name, "_MASReceipt/") || name == "CodeResources")
2609 return true;
2610
2611 for (const auto &bundle : bundles)
2612 if (Starts(name, bundle.first + "/")) {
2613 excludes.insert(name);
2614 return true;
2615 }
2616
2617 return false;
2618 });
2619
2620 folder.Find("", fun([&](const std::string &name) {
2621 if (exclude(name))
2622 return;
2623
2624 if (local.files.find(name) != local.files.end())
2625 return;
2626 auto &hash(local.files[name]);
2627
2628 folder.Open(name, fun([&](std::streambuf &data, size_t length, const void *flag) {
2629 progress(root + name);
2630
2631 union {
2632 struct {
2633 uint32_t magic;
2634 uint32_t count;
2635 };
2636
2637 uint8_t bytes[8];
2638 } header;
2639
2640 auto size(most(data, &header.bytes, sizeof(header.bytes)));
2641
2642 if (name != "_WatchKitStub/WK" && size == sizeof(header.bytes))
2643 switch (Swap(header.magic)) {
2644 case FAT_MAGIC:
2645 // Java class file format
2646 if (Swap(header.count) >= 40)
2647 break;
2648 case FAT_CIGAM:
2649 case MH_MAGIC: case MH_MAGIC_64:
2650 case MH_CIGAM: case MH_CIGAM_64:
2651 folder.Save(name, true, flag, fun([&](std::streambuf &save) {
2652 Slots slots;
2653 Sign(header.bytes, size, data, hash, save, identifier, "", false, "", key, slots, length, 0, false, Progression(progress, root + name));
2654 }));
2655 return;
2656 }
2657
2658 folder.Save(name, false, flag, fun([&](std::streambuf &save) {
2659 HashProxy proxy(hash, save);
2660 put(proxy, header.bytes, size);
2661 copy(data, proxy, length - size, progress);
2662 }));
2663 }));
2664 }), fun([&](const std::string &name, const Functor<std::string ()> &read) {
2665 if (exclude(name))
2666 return;
2667
2668 local.links[name] = read();
2669 }));
2670
2671 auto plist(plist_new_dict());
2672 _scope({ plist_free(plist); });
2673
2674 for (const auto &version : versions) {
2675 auto files(plist_new_dict());
2676 plist_dict_set_item(plist, ("files" + version.first).c_str(), files);
2677
2678 for (const auto &rule : version.second)
2679 rule.Compile();
2680
2681 bool old(&version.second == &rules1);
2682
2683 for (const auto &hash : local.files)
2684 for (const auto &rule : version.second)
2685 if (rule(hash.first)) {
2686 if (!old && mac && excludes.find(hash.first) != excludes.end());
2687 else if (old && rule.mode_ == NoMode)
2688 plist_dict_set_item(files, hash.first.c_str(), plist_new_data(reinterpret_cast<const char *>(hash.second.sha1_), sizeof(hash.second.sha1_)));
2689 else if (rule.mode_ != OmitMode) {
2690 auto entry(plist_new_dict());
2691 plist_dict_set_item(entry, "hash", plist_new_data(reinterpret_cast<const char *>(hash.second.sha1_), sizeof(hash.second.sha1_)));
2692 if (!old)
2693 plist_dict_set_item(entry, "hash2", plist_new_data(reinterpret_cast<const char *>(hash.second.sha256_), sizeof(hash.second.sha256_)));
2694 if (rule.mode_ == OptionalMode)
2695 plist_dict_set_item(entry, "optional", plist_new_bool(true));
2696 plist_dict_set_item(files, hash.first.c_str(), entry);
2697 }
2698
2699 break;
2700 }
2701
2702 if (!old)
2703 for (const auto &link : local.links)
2704 for (const auto &rule : version.second)
2705 if (rule(link.first)) {
2706 if (rule.mode_ != OmitMode) {
2707 auto entry(plist_new_dict());
2708 plist_dict_set_item(entry, "symlink", plist_new_string(link.second.c_str()));
2709 if (rule.mode_ == OptionalMode)
2710 plist_dict_set_item(entry, "optional", plist_new_bool(true));
2711 plist_dict_set_item(files, link.first.c_str(), entry);
2712 }
2713
2714 break;
2715 }
2716
2717 if (!old && mac)
2718 for (const auto &bundle : bundles) {
2719 auto entry(plist_new_dict());
2720 plist_dict_set_item(entry, "cdhash", plist_new_data(reinterpret_cast<const char *>(bundle.second.hash.sha256_), sizeof(bundle.second.hash.sha256_)));
2721 plist_dict_set_item(entry, "requirement", plist_new_string("anchor apple generic"));
2722 plist_dict_set_item(files, bundle.first.c_str(), entry);
2723 }
2724 }
2725
2726 for (const auto &version : versions) {
2727 auto rules(plist_new_dict());
2728 plist_dict_set_item(plist, ("rules" + version.first).c_str(), rules);
2729
2730 std::multiset<const Rule *, RuleCode> ordered;
2731 for (const auto &rule : version.second)
2732 ordered.insert(&rule);
2733
2734 for (const auto &rule : ordered)
2735 if (rule->weight_ == 1 && rule->mode_ == NoMode)
2736 plist_dict_set_item(rules, rule->code_.c_str(), plist_new_bool(true));
2737 else {
2738 auto entry(plist_new_dict());
2739 plist_dict_set_item(rules, rule->code_.c_str(), entry);
2740
2741 switch (rule->mode_) {
2742 case NoMode:
2743 break;
2744 case OmitMode:
2745 plist_dict_set_item(entry, "omit", plist_new_bool(true));
2746 break;
2747 case OptionalMode:
2748 plist_dict_set_item(entry, "optional", plist_new_bool(true));
2749 break;
2750 case NestedMode:
2751 plist_dict_set_item(entry, "nested", plist_new_bool(true));
2752 break;
2753 case TopMode:
2754 plist_dict_set_item(entry, "top", plist_new_bool(true));
2755 break;
2756 }
2757
2758 if (rule->weight_ >= 10000)
2759 plist_dict_set_item(entry, "weight", plist_new_uint(rule->weight_));
2760 else if (rule->weight_ != 1)
2761 plist_dict_set_item(entry, "weight", plist_new_real(rule->weight_));
2762 }
2763 }
2764
2765 folder.Save(signature, true, NULL, fun([&](std::streambuf &save) {
2766 HashProxy proxy(local.files[signature], save);
2767 char *xml(NULL);
2768 uint32_t size;
2769 plist_to_xml(plist, &xml, &size);
2770 _scope({ free(xml); });
2771 put(proxy, xml, size);
2772 }));
2773
2774 Bundle bundle;
2775 bundle.path = folder.Path(executable);
2776
2777 folder.Open(executable, fun([&](std::streambuf &buffer, size_t length, const void *flag) {
2778 progress(root + executable);
2779 folder.Save(executable, true, flag, fun([&](std::streambuf &save) {
2780 Slots slots;
2781 slots[1] = local.files.at(info);
2782 slots[3] = local.files.at(signature);
2783 bundle.hash = Sign(NULL, 0, buffer, local.files[executable], save, identifier, entitlements, false, requirements, key, slots, length, 0, false, Progression(progress, root + executable));
2784 }));
2785 }));
2786
2787 remote.Merge(root, local);
2788 return bundle;
2789 }
2790
2791 Bundle Sign(const std::string &root, Folder &folder, const std::string &key, const std::string &requirements, const Functor<std::string (const std::string &, const std::string &)> &alter, const Progress &progress) {
2792 State local;
2793 return Sign(root, folder, key, local, requirements, alter, progress);
2794 }
2795 #endif
2796
2797 #endif
2798 }
2799
2800 std::string Hex(const uint8_t *data, size_t size) {
2801 std::string hex;
2802 hex.reserve(size * 2);
2803 for (size_t i(0); i != size; ++i) {
2804 hex += "0123456789abcdef"[data[i] >> 4];
2805 hex += "0123456789abcdef"[data[i] & 0xf];
2806 }
2807 return hex;
2808 }
2809
2810 static void usage(const char *argv0) {
2811 fprintf(stderr, "usage: %s -S[entitlements.xml] <binary>\n", argv0);
2812 fprintf(stderr, " %s -e MobileSafari\n", argv0);
2813 fprintf(stderr, " %s -S cat\n", argv0);
2814 fprintf(stderr, " %s -Stfp.xml gdb\n", argv0);
2815 }
2816
2817 #ifndef LDID_NOTOOLS
2818 int main(int argc, char *argv[]) {
2819 #ifndef LDID_NOSMIME
2820 OpenSSL_add_all_algorithms();
2821 #endif
2822
2823 union {
2824 uint16_t word;
2825 uint8_t byte[2];
2826 } endian = {1};
2827
2828 little_ = endian.byte[0];
2829
2830 bool flag_r(false);
2831 bool flag_e(false);
2832 bool flag_q(false);
2833
2834 bool flag_H(false);
2835 bool flag_h(false);
2836
2837 #ifndef LDID_NOFLAGT
2838 bool flag_T(false);
2839 #endif
2840
2841 bool flag_S(false);
2842 bool flag_s(false);
2843
2844 bool flag_D(false);
2845
2846 bool flag_A(false);
2847 bool flag_a(false);
2848
2849 bool flag_u(false);
2850
2851 bool flag_M(false);
2852
2853 uint32_t flags(0);
2854 bool platform(false);
2855
2856 uint32_t flag_CPUType(_not(uint32_t));
2857 uint32_t flag_CPUSubtype(_not(uint32_t));
2858
2859 const char *flag_I(NULL);
2860
2861 #ifndef LDID_NOFLAGT
2862 bool timeh(false);
2863 uint32_t timev(0);
2864 #endif
2865
2866 Map entitlements;
2867 Map requirements;
2868 Map key;
2869 ldid::Slots slots;
2870
2871 std::vector<std::string> files;
2872
2873 if (argc == 1) {
2874 usage(argv[0]);
2875 return 0;
2876 }
2877
2878 for (int argi(1); argi != argc; ++argi)
2879 if (argv[argi][0] != '-')
2880 files.push_back(argv[argi]);
2881 else switch (argv[argi][1]) {
2882 case 'r':
2883 _assert(!flag_s);
2884 _assert(!flag_S);
2885 flag_r = true;
2886 break;
2887
2888 case 'e': flag_e = true; break;
2889
2890 case 'E': {
2891 const char *string = argv[argi] + 2;
2892 const char *colon = strchr(string, ':');
2893 _assert(colon != NULL);
2894 Map file(colon + 1, O_RDONLY, PROT_READ, MAP_PRIVATE);
2895 char *arge;
2896 unsigned number(strtoul(string, &arge, 0));
2897 _assert(arge == colon);
2898 auto &slot(slots[number]);
2899 for (Algorithm *algorithm : GetAlgorithms())
2900 (*algorithm)(slot, file.data(), file.size());
2901 } break;
2902
2903 case 'q': flag_q = true; break;
2904
2905 case 'H': {
2906 const char *hash = argv[argi] + 2;
2907
2908 if (!flag_H) {
2909 flag_H = true;
2910
2911 do_sha1 = false;
2912 do_sha256 = false;
2913
2914 fprintf(stderr, "WARNING: -H is only present for compatibility with a fork of ldid\n");
2915 fprintf(stderr, " you should NOT be manually specifying the hash algorithm\n");
2916 }
2917
2918 if (false);
2919 else if (strcmp(hash, "sha1") == 0)
2920 do_sha1 = true;
2921 else if (strcmp(hash, "sha256") == 0)
2922 do_sha256 = true;
2923 else _assert(false);
2924 } break;
2925
2926 case 'h': flag_h = true; break;
2927
2928 case 'Q': {
2929 const char *xml = argv[argi] + 2;
2930 requirements.open(xml, O_RDONLY, PROT_READ, MAP_PRIVATE);
2931 } break;
2932
2933 case 'D': flag_D = true; break;
2934
2935 case 'a': flag_a = true; break;
2936
2937 case 'A':
2938 _assert(!flag_A);
2939 flag_A = true;
2940 if (argv[argi][2] != '\0') {
2941 const char *cpu = argv[argi] + 2;
2942 const char *colon = strchr(cpu, ':');
2943 _assert(colon != NULL);
2944 char *arge;
2945 flag_CPUType = strtoul(cpu, &arge, 0);
2946 _assert(arge == colon);
2947 flag_CPUSubtype = strtoul(colon + 1, &arge, 0);
2948 _assert(arge == argv[argi] + strlen(argv[argi]));
2949 }
2950 break;
2951
2952 case 'C': {
2953 const char *name = argv[argi] + 2;
2954 if (false);
2955 else if (strcmp(name, "host") == 0)
2956 flags |= kSecCodeSignatureHost;
2957 else if (strcmp(name, "adhoc") == 0)
2958 flags |= kSecCodeSignatureAdhoc;
2959 else if (strcmp(name, "hard") == 0)
2960 flags |= kSecCodeSignatureForceHard;
2961 else if (strcmp(name, "kill") == 0)
2962 flags |= kSecCodeSignatureForceKill;
2963 else if (strcmp(name, "expires") == 0)
2964 flags |= kSecCodeSignatureForceExpiration;
2965 else if (strcmp(name, "restrict") == 0)
2966 flags |= kSecCodeSignatureRestrict;
2967 else if (strcmp(name, "enforcement") == 0)
2968 flags |= kSecCodeSignatureEnforcement;
2969 else if (strcmp(name, "library-validation") == 0)
2970 flags |= kSecCodeSignatureLibraryValidation;
2971 else if (strcmp(name, "runtime") == 0)
2972 flags |= kSecCodeSignatureRuntime;
2973 else _assert(false);
2974 } break;
2975
2976 case 'P':
2977 platform = true;
2978 break;
2979
2980 case 's':
2981 _assert(!flag_r);
2982 _assert(!flag_S);
2983 flag_s = true;
2984 break;
2985
2986 case 'S':
2987 _assert(!flag_r);
2988 _assert(!flag_s);
2989 flag_S = true;
2990 if (argv[argi][2] != '\0') {
2991 const char *xml = argv[argi] + 2;
2992 entitlements.open(xml, O_RDONLY, PROT_READ, MAP_PRIVATE);
2993 }
2994 break;
2995
2996 case 'M':
2997 flag_M = true;
2998 break;
2999
3000 case 'K':
3001 if (argv[argi][2] != '\0')
3002 key.open(argv[argi] + 2, O_RDONLY, PROT_READ, MAP_PRIVATE);
3003 break;
3004
3005 #ifndef LDID_NOFLAGT
3006 case 'T': {
3007 flag_T = true;
3008 if (argv[argi][2] == '-')
3009 timeh = true;
3010 else {
3011 char *arge;
3012 timev = strtoul(argv[argi] + 2, &arge, 0);
3013 _assert(arge == argv[argi] + strlen(argv[argi]));
3014 }
3015 } break;
3016 #endif
3017
3018 case 'u': {
3019 flag_u = true;
3020 } break;
3021
3022 case 'I': {
3023 flag_I = argv[argi] + 2;
3024 } break;
3025
3026 default:
3027 usage(argv[0]);
3028 return 1;
3029 break;
3030 }
3031
3032 _assert(flag_S || key.empty());
3033 _assert(flag_S || flag_I == NULL);
3034
3035 if (files.empty())
3036 return 0;
3037
3038 size_t filei(0), filee(0);
3039 _foreach (file, files) try {
3040 std::string path(file);
3041
3042 struct stat info;
3043 _syscall(stat(path.c_str(), &info));
3044
3045 if (flag_S && S_ISDIR(info.st_mode)) {
3046 #ifndef LDID_NOPLIST
3047 _assert(!flag_r);
3048 ldid::DiskFolder folder(path + "/");
3049 path += "/" + Sign("", folder, key, requirements, ldid::fun([&](const std::string &, const std::string &) -> std::string { return entitlements; }), dummy_).path;
3050 #else
3051 _assert(false);
3052 #endif
3053 } else if (flag_S || flag_r) {
3054 Map input(path, O_RDONLY, PROT_READ, MAP_PRIVATE);
3055
3056 std::filebuf output;
3057 Split split(path);
3058 auto temp(Temporary(output, split));
3059
3060 if (flag_r)
3061 ldid::Unsign(input.data(), input.size(), output, dummy_);
3062 else {
3063 std::string identifier(flag_I ?: split.base.c_str());
3064 ldid::Sign(input.data(), input.size(), output, identifier, entitlements, flag_M, requirements, key, slots, flags, platform, dummy_);
3065 }
3066
3067 Commit(path, temp);
3068 }
3069
3070 bool modify(false);
3071 #ifndef LDID_NOFLAGT
3072 if (flag_T)
3073 modify = true;
3074 #endif
3075 if (flag_s)
3076 modify = true;
3077
3078 Map mapping(path, modify);
3079 FatHeader fat_header(mapping.data(), mapping.size());
3080
3081 _foreach (mach_header, fat_header.GetMachHeaders()) {
3082 struct linkedit_data_command *signature(NULL);
3083 struct encryption_info_command *encryption(NULL);
3084
3085 if (flag_A) {
3086 if (mach_header.GetCPUType() != flag_CPUType)
3087 continue;
3088 if (mach_header.GetCPUSubtype() != flag_CPUSubtype)
3089 continue;
3090 }
3091
3092 if (flag_a)
3093 printf("cpu=0x%x:0x%x\n", mach_header.GetCPUType(), mach_header.GetCPUSubtype());
3094
3095 _foreach (load_command, mach_header.GetLoadCommands()) {
3096 uint32_t cmd(mach_header.Swap(load_command->cmd));
3097
3098 if (false);
3099 else if (cmd == LC_CODE_SIGNATURE)
3100 signature = reinterpret_cast<struct linkedit_data_command *>(load_command);
3101 else if (cmd == LC_ENCRYPTION_INFO || cmd == LC_ENCRYPTION_INFO_64)
3102 encryption = reinterpret_cast<struct encryption_info_command *>(load_command);
3103 else if (cmd == LC_LOAD_DYLIB) {
3104 volatile struct dylib_command *dylib_command(reinterpret_cast<struct dylib_command *>(load_command));
3105 const char *name(reinterpret_cast<const char *>(load_command) + mach_header.Swap(dylib_command->dylib.name));
3106
3107 if (strcmp(name, "/System/Library/Frameworks/UIKit.framework/UIKit") == 0) {
3108 if (flag_u) {
3109 Version version;
3110 version.value = mach_header.Swap(dylib_command->dylib.current_version);
3111 printf("uikit=%u.%u.%u\n", version.major, version.minor, version.patch);
3112 }
3113 }
3114 }
3115 #ifndef LDID_NOFLAGT
3116 else if (cmd == LC_ID_DYLIB) {
3117 volatile struct dylib_command *dylib_command(reinterpret_cast<struct dylib_command *>(load_command));
3118
3119 if (flag_T) {
3120 uint32_t timed;
3121
3122 if (!timeh)
3123 timed = timev;
3124 else {
3125 dylib_command->dylib.timestamp = 0;
3126 timed = hash(reinterpret_cast<uint8_t *>(mach_header.GetBase()), mach_header.GetSize(), timev);
3127 }
3128
3129 dylib_command->dylib.timestamp = mach_header.Swap(timed);
3130 }
3131 }
3132 #endif
3133 }
3134
3135 if (flag_D) {
3136 _assert(encryption != NULL);
3137 encryption->cryptid = mach_header.Swap(0);
3138 }
3139
3140 if (flag_e) {
3141 _assert(signature != NULL);
3142
3143 uint32_t data = mach_header.Swap(signature->dataoff);
3144
3145 uint8_t *top = reinterpret_cast<uint8_t *>(mach_header.GetBase());
3146 uint8_t *blob = top + data;
3147 struct SuperBlob *super = reinterpret_cast<struct SuperBlob *>(blob);
3148
3149 for (size_t index(0); index != Swap(super->count); ++index)
3150 if (Swap(super->index[index].type) == CSSLOT_ENTITLEMENTS) {
3151 uint32_t begin = Swap(super->index[index].offset);
3152 struct Blob *entitlements = reinterpret_cast<struct Blob *>(blob + begin);
3153 fwrite(entitlements + 1, 1, Swap(entitlements->length) - sizeof(*entitlements), stdout);
3154 }
3155 }
3156
3157 if (flag_q) {
3158 _assert(signature != NULL);
3159
3160 uint32_t data = mach_header.Swap(signature->dataoff);
3161
3162 uint8_t *top = reinterpret_cast<uint8_t *>(mach_header.GetBase());
3163 uint8_t *blob = top + data;
3164 struct SuperBlob *super = reinterpret_cast<struct SuperBlob *>(blob);
3165
3166 for (size_t index(0); index != Swap(super->count); ++index)
3167 if (Swap(super->index[index].type) == CSSLOT_REQUIREMENTS) {
3168 uint32_t begin = Swap(super->index[index].offset);
3169 struct Blob *requirement = reinterpret_cast<struct Blob *>(blob + begin);
3170 fwrite(requirement, 1, Swap(requirement->length), stdout);
3171 }
3172 }
3173
3174 if (flag_s) {
3175 _assert(signature != NULL);
3176
3177 uint32_t data = mach_header.Swap(signature->dataoff);
3178
3179 uint8_t *top = reinterpret_cast<uint8_t *>(mach_header.GetBase());
3180 uint8_t *blob = top + data;
3181 struct SuperBlob *super = reinterpret_cast<struct SuperBlob *>(blob);
3182
3183 for (size_t index(0); index != Swap(super->count); ++index)
3184 if (Swap(super->index[index].type) == CSSLOT_CODEDIRECTORY) {
3185 uint32_t begin = Swap(super->index[index].offset);
3186 struct CodeDirectory *directory = reinterpret_cast<struct CodeDirectory *>(blob + begin + sizeof(Blob));
3187
3188 uint8_t (*hashes)[LDID_SHA1_DIGEST_LENGTH] = reinterpret_cast<uint8_t (*)[LDID_SHA1_DIGEST_LENGTH]>(blob + begin + Swap(directory->hashOffset));
3189 uint32_t pages = Swap(directory->nCodeSlots);
3190
3191 if (pages != 1)
3192 for (size_t i = 0; i != pages - 1; ++i)
3193 LDID_SHA1(top + PageSize_ * i, PageSize_, hashes[i]);
3194 if (pages != 0)
3195 LDID_SHA1(top + PageSize_ * (pages - 1), ((data - 1) % PageSize_) + 1, hashes[pages - 1]);
3196 }
3197 }
3198
3199 if (flag_h) {
3200 _assert(signature != NULL);
3201
3202 auto algorithms(GetAlgorithms());
3203
3204 uint32_t data = mach_header.Swap(signature->dataoff);
3205
3206 uint8_t *top = reinterpret_cast<uint8_t *>(mach_header.GetBase());
3207 uint8_t *blob = top + data;
3208 struct SuperBlob *super = reinterpret_cast<struct SuperBlob *>(blob);
3209
3210 struct Candidate {
3211 CodeDirectory *directory_;
3212 size_t size_;
3213 Algorithm &algorithm_;
3214 std::string hash_;
3215 };
3216
3217 std::map<uint8_t, Candidate> candidates;
3218
3219 for (size_t index(0); index != Swap(super->count); ++index) {
3220 auto type(Swap(super->index[index].type));
3221 if ((type == CSSLOT_CODEDIRECTORY || type >= CSSLOT_ALTERNATE) && type != CSSLOT_SIGNATURESLOT) {
3222 uint32_t begin = Swap(super->index[index].offset);
3223 uint32_t end = index + 1 == Swap(super->count) ? Swap(super->blob.length) : Swap(super->index[index + 1].offset);
3224 struct CodeDirectory *directory = reinterpret_cast<struct CodeDirectory *>(blob + begin + sizeof(Blob));
3225 auto type(directory->hashType);
3226 _assert(type > 0 && type <= algorithms.size());
3227 auto &algorithm(*algorithms[type - 1]);
3228 uint8_t hash[algorithm.size_];
3229 algorithm(hash, blob + begin, end - begin);
3230 candidates.insert({type, {directory, end - begin, algorithm, Hex(hash, 20)}});
3231 }
3232 }
3233
3234 _assert(!candidates.empty());
3235 auto best(candidates.end());
3236 --best;
3237
3238 const auto directory(best->second.directory_);
3239 const auto flags(Swap(directory->flags));
3240
3241 std::string names;
3242 if (flags & kSecCodeSignatureHost)
3243 names += ",host";
3244 if (flags & kSecCodeSignatureAdhoc)
3245 names += ",adhoc";
3246 if (flags & kSecCodeSignatureForceHard)
3247 names += ",hard";
3248 if (flags & kSecCodeSignatureForceKill)
3249 names += ",kill";
3250 if (flags & kSecCodeSignatureForceExpiration)
3251 names += ",expires";
3252 if (flags & kSecCodeSignatureRestrict)
3253 names += ",restrict";
3254 if (flags & kSecCodeSignatureEnforcement)
3255 names += ",enforcement";
3256 if (flags & kSecCodeSignatureLibraryValidation)
3257 names += ",library-validation";
3258 if (flags & kSecCodeSignatureRuntime)
3259 names += ",runtime";
3260
3261 printf("CodeDirectory v=%x size=%zd flags=0x%x(%s) hashes=%d+%d location=embedded\n",
3262 Swap(directory->version), best->second.size_, flags, names.empty() ? "none" : names.c_str() + 1, Swap(directory->nCodeSlots), Swap(directory->nSpecialSlots));
3263 printf("Hash type=%s size=%d\n", best->second.algorithm_.name(), directory->hashSize);
3264
3265 std::string choices;
3266 for (const auto &candidate : candidates) {
3267 auto choice(candidate.second.algorithm_.name());
3268 choices += ',';
3269 choices += choice;
3270 printf("CandidateCDHash %s=%s\n", choice, candidate.second.hash_.c_str());
3271 }
3272 printf("Hash choices=%s\n", choices.c_str() + 1);
3273
3274 printf("CDHash=%s\n", best->second.hash_.c_str());
3275 }
3276 }
3277
3278 ++filei;
3279 } catch (const char *) {
3280 ++filee;
3281 ++filei;
3282 }
3283
3284 return filee;
3285 }
3286 #endif