├── ios.sh ├── .gitignore ├── .gitmodules ├── version.sh ├── control.sh ├── deb.sh ├── plist.sh ├── control ├── sysroot.sh ├── make.sh ├── sha1.h ├── ldid.hpp ├── lookup2.c ├── COPYING └── ldid.cpp /ios.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | ./make.sh true 3 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | ios 2 | out 3 | ldid 4 | ldid.deb 5 | debs 6 | *.o 7 | _ 8 | sysroot32 9 | sysroot64 10 | -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "libplist"] 2 | path = libplist 3 | url = https://github.com/libimobiledevice/libplist.git 4 | -------------------------------------------------------------------------------- /version.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | echo "$(git describe --tags --dirty="+" --match="v*" | sed -e 's@-\([^-]*\)-\([^-]*\)$@+\1.\2@;s@^v@2:@')" 3 | -------------------------------------------------------------------------------- /control.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | dir=$1 3 | dir=${dir:=_} 4 | sed -e "s@^\(Version:.*\)@\1$(./version.sh)@" control 5 | echo "Installed-Size: $(du -s "${dir}" | cut -f 1)" 6 | -------------------------------------------------------------------------------- /deb.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | rm -rf _ 3 | mkdir -p _/usr/bin 4 | cp -a ios/ldid _/usr/bin/ldid 5 | mkdir -p _/DEBIAN 6 | ./control.sh _ >_/DEBIAN/control 7 | mkdir -p debs 8 | ln -sf debs/ldid_$(./version.sh)_iphoneos-arm.deb ldid.deb 9 | dpkg-deb -b _ ldid.deb 10 | readlink ldid.deb 11 | -------------------------------------------------------------------------------- /plist.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | ./configure CC='clang -mmacosx-version-min=10.4 -arch i386 -arch x86_64' CXX='clang++ -mmacosx-version-min=10.4 -arch i386 -arch x86_64' CPP='clang -E' CXXCPP='clang++ -E' libxml2_LIBS=-lxml2 libxml2_CFLAGS=-I/usr/include/libxml2 --enable-static --disable-shared 3 | -------------------------------------------------------------------------------- /control: -------------------------------------------------------------------------------- 1 | Package: ldid 2 | Priority: optional 3 | Section: Development 4 | Maintainer: Jay Freeman (saurik) 5 | Architecture: iphoneos-arm 6 | Version: 7 | Description: pseudo-codesign Mach-O files 8 | Name: Link Identity Editor 9 | Author: Jay Freeman (saurik) 10 | Depiction: http://cydia.saurik.com/info/ldid/ 11 | Depends: libplist (>= 2.0.0), openssl 12 | Tag: purpose::console, role::developer 13 | -------------------------------------------------------------------------------- /sysroot.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | set -e 3 | 4 | rm -rf sysroot32 sysroot64 5 | mkdir -p sysroot32 sysroot64 6 | 7 | function merge() { 8 | wget --no-check-certificate "${apt}/$1" 9 | dpkg-deb -x "$1" . 10 | } 11 | 12 | pushd sysroot32 13 | apt=http://apt.saurik.com/debs 14 | merge openssl_0.9.8zg-13_iphoneos-arm.deb 15 | merge libplist_2.0.0-1_iphoneos-arm.deb 16 | popd 17 | 18 | pushd sysroot64 19 | apt=https://apt.bingner.com/debs/1443.00 20 | merge libssl1.0_1.0.2q-1_iphoneos-arm.deb 21 | merge libssl-dev_1.0.2q-1_iphoneos-arm.deb 22 | merge libplist_2.0.0-1_iphoneos-arm.deb 23 | popd 24 | 25 | for lib in libplist libcrypto; do 26 | for dylib in sysroot*/usr/lib/"${lib}".*.dylib; do 27 | echo install_name_tool -id /usr/lib/"${lib}".dylib "${dylib}" 28 | chmod 755 "${dylib}" 29 | install_name_tool -id /usr/lib/"${lib}".dylib "${dylib}" 30 | done 31 | done 32 | -------------------------------------------------------------------------------- /make.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | set -e 4 | shopt -s extglob 5 | 6 | if [[ $# == 0 ]]; then 7 | ios=false 8 | else 9 | ios=$1 10 | shift 11 | fi 12 | 13 | export DEVELOPER_DIR=/Applications/Xcode-5.1.1.app 14 | 15 | os=() 16 | 17 | if "${ios}"; then 18 | 19 | out=ios 20 | flags=(cycc -- -miphoneos-version-min=2.0 -arch armv6 -arch arm64) 21 | 22 | flags+=(-Xarch_armv6 -Isysroot32/usr/include) 23 | flags+=(-Xarch_arm64 -Isysroot64/usr/include) 24 | 25 | flags+=(-Xarch_armv6 -Lsysroot32/usr/lib) 26 | flags+=(-Xarch_arm64 -Lsysroot64/usr/lib) 27 | 28 | static=false 29 | flags+=(-framework CoreFoundation) 30 | 31 | flags+=(-lplist) 32 | flags+=(-lcrypto) 33 | 34 | else 35 | 36 | out=out 37 | 38 | if which xcrun &>/dev/null; then 39 | flags=(xcrun -sdk macosx g++) 40 | flags+=(-mmacosx-version-min=10.4) 41 | 42 | for arch in i386 x86_64; do 43 | flags+=(-arch "${arch}") 44 | done 45 | else 46 | flags=(g++) 47 | fi 48 | 49 | #flags+=(-L../../lib-osx/openssl) 50 | 51 | # XXX: cannot redistribute 52 | static=true 53 | flags+=(-Isysroot64/usr/include) 54 | flags+=(-lcrypto) 55 | #flags+=(-Wl,/usr/lib/libcrypto.42.dylib) 56 | 57 | fi 58 | 59 | sdk=$(xcodebuild -sdk iphoneos -version Path) 60 | 61 | flags+=(-I.) 62 | 63 | if ${static}; then 64 | 65 | flags+=(-I"${sdk}"/usr/include/libxml2) 66 | flags+=(-Ilibplist/include) 67 | flags+=(-Ilibplist/libcnary/include) 68 | 69 | for c in libplist/libcnary/!(cnary).c libplist/src/*.c; do 70 | o=${c%.c}.o 71 | o="${out}"/${o##*/} 72 | os+=("${o}") 73 | if [[ "${c}" -nt "${o}" ]]; then 74 | "${flags[@]}" -c -o "${o}" -x c "${c}" 75 | fi 76 | done 77 | 78 | fi 79 | 80 | flags+=("$@") 81 | 82 | mkdir -p "${out}" 83 | set -x 84 | 85 | "${flags[@]}" -O3 -g0 -c -std=c++11 -o "${out}"/ldid.o ldid.cpp 86 | "${flags[@]}" -O3 -g0 -o "${out}"/ldid "${out}"/ldid.o "${os[@]}" -x c lookup2.c -lxml2 -framework Security 87 | 88 | if ! "${ios}"; then 89 | ln -sf out/ldid . 90 | fi 91 | -------------------------------------------------------------------------------- /sha1.h: -------------------------------------------------------------------------------- 1 | /* 2 | * sha1.h 3 | * 4 | * Description: 5 | * This is the header file for code which implements the Secure 6 | * Hashing Algorithm 1 as defined in FIPS PUB 180-1 published 7 | * April 17, 1995. 8 | * 9 | * Many of the variable names in this code, especially the 10 | * single character names, were used because those were the names 11 | * used in the publication. 12 | * 13 | * Please read the file sha1.c for more information. 14 | * 15 | */ 16 | 17 | #ifndef _SHA1_H_ 18 | #define _SHA1_H_ 19 | 20 | #include 21 | 22 | #ifndef _SHA_enum_ 23 | #define _SHA_enum_ 24 | enum 25 | { 26 | shaSuccess = 0, 27 | shaNull, /* Null pointer parameter */ 28 | shaInputTooLong, /* input data too long */ 29 | shaStateError /* called Input after Result */ 30 | }; 31 | #endif 32 | #define SHA1HashSize 20 33 | 34 | /* 35 | * This structure will hold context information for the SHA-1 36 | * hashing operation 37 | */ 38 | typedef struct SHA1Context 39 | { 40 | uint32_t Intermediate_Hash[SHA1HashSize/4]; /* Message Digest */ 41 | 42 | uint32_t Length_Low; /* Message length in bits */ 43 | uint32_t Length_High; /* Message length in bits */ 44 | 45 | /* Index into message block array */ 46 | int_least16_t Message_Block_Index; 47 | uint8_t Message_Block[64]; /* 512-bit message blocks */ 48 | 49 | int Computed; /* Is the digest computed? */ 50 | int Corrupted; /* Is the message digest corrupted? */ 51 | } SHA1Context; 52 | 53 | /* 54 | * Function Prototypes 55 | */ 56 | 57 | int SHA1Reset( SHA1Context *); 58 | int SHA1Input( SHA1Context *, 59 | const uint8_t *, 60 | unsigned int); 61 | int SHA1Result( SHA1Context *, 62 | uint8_t Message_Digest[SHA1HashSize]); 63 | 64 | #endif 65 | -------------------------------------------------------------------------------- /ldid.hpp: -------------------------------------------------------------------------------- 1 | #ifndef LDID_HPP 2 | #define LDID_HPP 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | namespace ldid { 13 | 14 | // I wish Apple cared about providing quality toolchains :/ 15 | 16 | template 17 | class Functor; 18 | 19 | template 20 | class Functor { 21 | public: 22 | virtual Type_ operator ()(Args_... args) const = 0; 23 | }; 24 | 25 | template 26 | class FunctorImpl; 27 | 28 | template 29 | class FunctorImpl : 30 | public Functor 31 | { 32 | private: 33 | const Value_ *value_; 34 | 35 | public: 36 | FunctorImpl(const Value_ &value) : 37 | value_(&value) 38 | { 39 | } 40 | 41 | virtual Type_ operator ()(Args_... args) const { 42 | return (*value_)(args...); 43 | } 44 | }; 45 | 46 | template 47 | FunctorImpl fun(const Function_ &value) { 48 | return value; 49 | } 50 | 51 | struct Progress { 52 | virtual void operator()(const std::string &value) const = 0; 53 | virtual void operator()(double value) const = 0; 54 | }; 55 | 56 | class Folder { 57 | public: 58 | virtual void Save(const std::string &path, bool edit, const void *flag, const Functor &code) = 0; 59 | virtual bool Look(const std::string &path) const = 0; 60 | virtual void Open(const std::string &path, const Functor &code) const = 0; 61 | virtual void Find(const std::string &path, const Functor &code, const Functor &)> &link) const = 0; 62 | }; 63 | 64 | class DiskFolder : 65 | public Folder 66 | { 67 | private: 68 | const std::string path_; 69 | std::map commit_; 70 | 71 | protected: 72 | std::string Path(const std::string &path) const; 73 | 74 | private: 75 | void Find(const std::string &root, const std::string &base, const Functor &code, const Functor &)> &link) const; 76 | 77 | public: 78 | DiskFolder(const std::string &path); 79 | ~DiskFolder(); 80 | 81 | virtual void Save(const std::string &path, bool edit, const void *flag, const Functor &code); 82 | virtual bool Look(const std::string &path) const; 83 | virtual void Open(const std::string &path, const Functor &code) const; 84 | virtual void Find(const std::string &path, const Functor &code, const Functor &)> &link) const; 85 | }; 86 | 87 | class SubFolder : 88 | public Folder 89 | { 90 | private: 91 | Folder &parent_; 92 | std::string path_; 93 | 94 | public: 95 | SubFolder(Folder &parent, const std::string &path); 96 | 97 | std::string Path(const std::string &path) const; 98 | 99 | virtual void Save(const std::string &path, bool edit, const void *flag, const Functor &code); 100 | virtual bool Look(const std::string &path) const; 101 | virtual void Open(const std::string &path, const Functor &code) const; 102 | virtual void Find(const std::string &path, const Functor &code, const Functor &)> &link) const; 103 | }; 104 | 105 | class UnionFolder : 106 | public Folder 107 | { 108 | private: 109 | struct Reset { 110 | const void *flag_; 111 | std::streambuf *data_; 112 | }; 113 | 114 | Folder &parent_; 115 | std::set deletes_; 116 | 117 | std::map remaps_; 118 | mutable std::map resets_; 119 | 120 | std::string Map(const std::string &path) const; 121 | void Map(const std::string &path, const Functor &code, const std::string &file, const Functor &)> &save) const; 122 | 123 | public: 124 | UnionFolder(Folder &parent); 125 | 126 | virtual void Save(const std::string &path, bool edit, const void *flag, const Functor &code); 127 | virtual bool Look(const std::string &path) const; 128 | virtual void Open(const std::string &path, const Functor &code) const; 129 | virtual void Find(const std::string &path, const Functor &code, const Functor &)> &link) const; 130 | 131 | void operator ()(const std::string &from) { 132 | deletes_.insert(from); 133 | } 134 | 135 | void operator ()(const std::string &from, const std::string &to) { 136 | operator ()(from); 137 | remaps_[to] = from; 138 | } 139 | 140 | void operator ()(const std::string &from, const void *flag, std::streambuf &data) { 141 | operator ()(from); 142 | auto &reset(resets_[from]); 143 | reset.flag_ = flag; 144 | reset.data_ = &data; 145 | } 146 | }; 147 | 148 | struct Hash { 149 | uint8_t sha1_[0x14]; 150 | uint8_t sha256_[0x20]; 151 | }; 152 | 153 | struct Bundle { 154 | std::string path; 155 | Hash hash; 156 | }; 157 | 158 | Bundle Sign(const std::string &root, Folder &folder, const std::string &key, const std::string &requirements, const Functor &alter, const Progress &progress); 159 | 160 | typedef std::map Slots; 161 | 162 | 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); 163 | 164 | } 165 | 166 | #endif//LDID_HPP 167 | -------------------------------------------------------------------------------- /lookup2.c: -------------------------------------------------------------------------------- 1 | /* 2 | -------------------------------------------------------------------- 3 | lookup2.c, by Bob Jenkins, December 1996, Public Domain. 4 | hash(), hash2(), hash3, and mix() are externally useful functions. 5 | Routines to test the hash are included if SELF_TEST is defined. 6 | You can use this free for any purpose. It has no warranty. 7 | -------------------------------------------------------------------- 8 | */ 9 | #include 10 | #include 11 | #include 12 | typedef unsigned long int ub4; /* unsigned 4-byte quantities */ 13 | typedef unsigned char ub1; 14 | 15 | #define hashsize(n) ((ub4)1<<(n)) 16 | #define hashmask(n) (hashsize(n)-1) 17 | 18 | /* 19 | -------------------------------------------------------------------- 20 | mix -- mix 3 32-bit values reversibly. 21 | For every delta with one or two bit set, and the deltas of all three 22 | high bits or all three low bits, whether the original value of a,b,c 23 | is almost all zero or is uniformly distributed, 24 | * If mix() is run forward or backward, at least 32 bits in a,b,c 25 | have at least 1/4 probability of changing. 26 | * If mix() is run forward, every bit of c will change between 1/3 and 27 | 2/3 of the time. (Well, 22/100 and 78/100 for some 2-bit deltas.) 28 | mix() was built out of 36 single-cycle latency instructions in a 29 | structure that could supported 2x parallelism, like so: 30 | a -= b; 31 | a -= c; x = (c>>13); 32 | b -= c; a ^= x; 33 | b -= a; x = (a<<8); 34 | c -= a; b ^= x; 35 | c -= b; x = (b>>13); 36 | ... 37 | Unfortunately, superscalar Pentiums and Sparcs can't take advantage 38 | of that parallelism. They've also turned some of those single-cycle 39 | latency instructions into multi-cycle latency instructions. Still, 40 | this is the fastest good hash I could find. There were about 2^^68 41 | to choose from. I only looked at a billion or so. 42 | -------------------------------------------------------------------- 43 | */ 44 | #define mix(a,b,c) \ 45 | { \ 46 | a -= b; a -= c; a ^= (c>>13); \ 47 | b -= c; b -= a; b ^= (a<<8); \ 48 | c -= a; c -= b; c ^= (b>>13); \ 49 | a -= b; a -= c; a ^= (c>>12); \ 50 | b -= c; b -= a; b ^= (a<<16); \ 51 | c -= a; c -= b; c ^= (b>>5); \ 52 | a -= b; a -= c; a ^= (c>>3); \ 53 | b -= c; b -= a; b ^= (a<<10); \ 54 | c -= a; c -= b; c ^= (b>>15); \ 55 | } 56 | 57 | /* same, but slower, works on systems that might have 8 byte ub4's */ 58 | #define mix2(a,b,c) \ 59 | { \ 60 | a -= b; a -= c; a ^= (c>>13); \ 61 | b -= c; b -= a; b ^= (a<< 8); \ 62 | c -= a; c -= b; c ^= ((b&0xffffffff)>>13); \ 63 | a -= b; a -= c; a ^= ((c&0xffffffff)>>12); \ 64 | b -= c; b -= a; b = (b ^ (a<<16)) & 0xffffffff; \ 65 | c -= a; c -= b; c = (c ^ (b>> 5)) & 0xffffffff; \ 66 | a -= b; a -= c; a = (a ^ (c>> 3)) & 0xffffffff; \ 67 | b -= c; b -= a; b = (b ^ (a<<10)) & 0xffffffff; \ 68 | c -= a; c -= b; c = (c ^ (b>>15)) & 0xffffffff; \ 69 | } 70 | 71 | /* 72 | -------------------------------------------------------------------- 73 | hash() -- hash a variable-length key into a 32-bit value 74 | k : the key (the unaligned variable-length array of bytes) 75 | len : the length of the key, counting by bytes 76 | level : can be any 4-byte value 77 | Returns a 32-bit value. Every bit of the key affects every bit of 78 | the return value. Every 1-bit and 2-bit delta achieves avalanche. 79 | About 36+6len instructions. 80 | 81 | The best hash table sizes are powers of 2. There is no need to do 82 | mod a prime (mod is sooo slow!). If you need less than 32 bits, 83 | use a bitmask. For example, if you need only 10 bits, do 84 | h = (h & hashmask(10)); 85 | In which case, the hash table should have hashsize(10) elements. 86 | 87 | If you are hashing n strings (ub1 **)k, do it like this: 88 | for (i=0, h=0; i= 12) 113 | { 114 | a += (k[0] +((ub4)k[1]<<8) +((ub4)k[2]<<16) +((ub4)k[3]<<24)); 115 | b += (k[4] +((ub4)k[5]<<8) +((ub4)k[6]<<16) +((ub4)k[7]<<24)); 116 | c += (k[8] +((ub4)k[9]<<8) +((ub4)k[10]<<16)+((ub4)k[11]<<24)); 117 | mix(a,b,c); 118 | k += 12; len -= 12; 119 | } 120 | 121 | /*------------------------------------- handle the last 11 bytes */ 122 | c += length; 123 | switch(len) /* all the case statements fall through */ 124 | { 125 | case 11: c+=((ub4)k[10]<<24); 126 | case 10: c+=((ub4)k[9]<<16); 127 | case 9 : c+=((ub4)k[8]<<8); 128 | /* the first byte of c is reserved for the length */ 129 | case 8 : b+=((ub4)k[7]<<24); 130 | case 7 : b+=((ub4)k[6]<<16); 131 | case 6 : b+=((ub4)k[5]<<8); 132 | case 5 : b+=k[4]; 133 | case 4 : a+=((ub4)k[3]<<24); 134 | case 3 : a+=((ub4)k[2]<<16); 135 | case 2 : a+=((ub4)k[1]<<8); 136 | case 1 : a+=k[0]; 137 | /* case 0: nothing left to add */ 138 | } 139 | mix(a,b,c); 140 | /*-------------------------------------------- report the result */ 141 | return c; 142 | } 143 | 144 | 145 | /* 146 | -------------------------------------------------------------------- 147 | This works on all machines. hash2() is identical to hash() on 148 | little-endian machines, except that the length has to be measured 149 | in ub4s instead of bytes. It is much faster than hash(). It 150 | requires 151 | -- that the key be an array of ub4's, and 152 | -- that all your machines have the same endianness, and 153 | -- that the length be the number of ub4's in the key 154 | -------------------------------------------------------------------- 155 | */ 156 | ub4 hash2( k, length, initval) 157 | register ub4 *k; /* the key */ 158 | register ub4 length; /* the length of the key, in ub4s */ 159 | register ub4 initval; /* the previous hash, or an arbitrary value */ 160 | { 161 | register ub4 a,b,c,len; 162 | 163 | /* Set up the internal state */ 164 | len = length; 165 | a = b = 0x9e3779b9; /* the golden ratio; an arbitrary value */ 166 | c = initval; /* the previous hash value */ 167 | 168 | /*---------------------------------------- handle most of the key */ 169 | while (len >= 3) 170 | { 171 | a += k[0]; 172 | b += k[1]; 173 | c += k[2]; 174 | mix(a,b,c); 175 | k += 3; len -= 3; 176 | } 177 | 178 | /*-------------------------------------- handle the last 2 ub4's */ 179 | c += length; 180 | switch(len) /* all the case statements fall through */ 181 | { 182 | /* c is reserved for the length */ 183 | case 2 : b+=k[1]; 184 | case 1 : a+=k[0]; 185 | /* case 0: nothing left to add */ 186 | } 187 | mix(a,b,c); 188 | /*-------------------------------------------- report the result */ 189 | return c; 190 | } 191 | 192 | /* 193 | -------------------------------------------------------------------- 194 | This is identical to hash() on little-endian machines (like Intel 195 | x86s or VAXen). It gives nondeterministic results on big-endian 196 | machines. It is faster than hash(), but a little slower than 197 | hash2(), and it requires 198 | -- that all your machines be little-endian 199 | -------------------------------------------------------------------- 200 | */ 201 | 202 | ub4 hash3( k, length, initval) 203 | register ub1 *k; /* the key */ 204 | register ub4 length; /* the length of the key */ 205 | register ub4 initval; /* the previous hash, or an arbitrary value */ 206 | { 207 | register ub4 a,b,c,len; 208 | 209 | /* Set up the internal state */ 210 | len = length; 211 | a = b = 0x9e3779b9; /* the golden ratio; an arbitrary value */ 212 | c = initval; /* the previous hash value */ 213 | 214 | /*---------------------------------------- handle most of the key */ 215 | if (((ub4)k)&3) 216 | { 217 | while (len >= 12) /* unaligned */ 218 | { 219 | a += (k[0] +((ub4)k[1]<<8) +((ub4)k[2]<<16) +((ub4)k[3]<<24)); 220 | b += (k[4] +((ub4)k[5]<<8) +((ub4)k[6]<<16) +((ub4)k[7]<<24)); 221 | c += (k[8] +((ub4)k[9]<<8) +((ub4)k[10]<<16)+((ub4)k[11]<<24)); 222 | mix(a,b,c); 223 | k += 12; len -= 12; 224 | } 225 | } 226 | else 227 | { 228 | while (len >= 12) /* aligned */ 229 | { 230 | a += *(ub4 *)(k+0); 231 | b += *(ub4 *)(k+4); 232 | c += *(ub4 *)(k+8); 233 | mix(a,b,c); 234 | k += 12; len -= 12; 235 | } 236 | } 237 | 238 | /*------------------------------------- handle the last 11 bytes */ 239 | c += length; 240 | switch(len) /* all the case statements fall through */ 241 | { 242 | case 11: c+=((ub4)k[10]<<24); 243 | case 10: c+=((ub4)k[9]<<16); 244 | case 9 : c+=((ub4)k[8]<<8); 245 | /* the first byte of c is reserved for the length */ 246 | case 8 : b+=((ub4)k[7]<<24); 247 | case 7 : b+=((ub4)k[6]<<16); 248 | case 6 : b+=((ub4)k[5]<<8); 249 | case 5 : b+=k[4]; 250 | case 4 : a+=((ub4)k[3]<<24); 251 | case 3 : a+=((ub4)k[2]<<16); 252 | case 2 : a+=((ub4)k[1]<<8); 253 | case 1 : a+=k[0]; 254 | /* case 0: nothing left to add */ 255 | } 256 | mix(a,b,c); 257 | /*-------------------------------------------- report the result */ 258 | return c; 259 | } 260 | 261 | 262 | 263 | #ifdef SELF_TEST 264 | 265 | /* used for timings */ 266 | void driver1() 267 | { 268 | ub4 buf[256]; 269 | ub4 i; 270 | ub4 h=0; 271 | 272 | for (i=0; i<256; ++i) 273 | { 274 | h = hash(buf,i,h); 275 | } 276 | } 277 | 278 | /* check that every input bit changes every output bit half the time */ 279 | #define HASHSTATE 1 280 | #define HASHLEN 1 281 | #define MAXPAIR 80 282 | #define MAXLEN 70 283 | void driver2() 284 | { 285 | ub1 qa[MAXLEN+1], qb[MAXLEN+2], *a = &qa[0], *b = &qb[1]; 286 | ub4 c[HASHSTATE], d[HASHSTATE], i, j=0, k, l, m, z; 287 | ub4 e[HASHSTATE],f[HASHSTATE],g[HASHSTATE],h[HASHSTATE]; 288 | ub4 x[HASHSTATE],y[HASHSTATE]; 289 | ub4 hlen; 290 | 291 | printf("No more than %d trials should ever be needed \n",MAXPAIR/2); 292 | for (hlen=0; hlen < MAXLEN; ++hlen) 293 | { 294 | z=0; 295 | for (i=0; i>(8-j)); 312 | c[0] = hash(a, hlen, m); 313 | b[i] ^= ((k+1)<>(8-j)); 315 | d[0] = hash(b, hlen, m); 316 | /* check every bit is 1, 0, set, and not set at least once */ 317 | for (l=0; lz) z=k; 330 | if (k==MAXPAIR) 331 | { 332 | printf("Some bit didn't change: "); 333 | printf("%.8lx %.8lx %.8lx %.8lx %.8lx %.8lx ", 334 | e[0],f[0],g[0],h[0],x[0],y[0]); 335 | printf("i %ld j %ld m %ld len %ld\n",i,j,m,hlen); 336 | } 337 | if (z==MAXPAIR) goto done; 338 | } 339 | } 340 | } 341 | done: 342 | if (z < MAXPAIR) 343 | { 344 | printf("Mix success %2ld bytes %2ld initvals ",i,m); 345 | printf("required %ld trials\n",z/2); 346 | } 347 | } 348 | printf("\n"); 349 | } 350 | 351 | /* Check for reading beyond the end of the buffer and alignment problems */ 352 | void driver3() 353 | { 354 | ub1 buf[MAXLEN+20], *b; 355 | ub4 len; 356 | ub1 q[] = "This is the time for all good men to come to the aid of their country"; 357 | ub1 qq[] = "xThis is the time for all good men to come to the aid of their country"; 358 | ub1 qqq[] = "xxThis is the time for all good men to come to the aid of their country"; 359 | ub1 qqqq[] = "xxxThis is the time for all good men to come to the aid of their country"; 360 | ub4 h,i,j,ref,x,y; 361 | 362 | printf("Endianness. These should all be the same:\n"); 363 | printf("%.8lx\n", hash(q, sizeof(q)-1, (ub4)0)); 364 | printf("%.8lx\n", hash(qq+1, sizeof(q)-1, (ub4)0)); 365 | printf("%.8lx\n", hash(qqq+2, sizeof(q)-1, (ub4)0)); 366 | printf("%.8lx\n", hash(qqqq+3, sizeof(q)-1, (ub4)0)); 367 | printf("\n"); 368 | for (h=0, b=buf+1; h<8; ++h, ++b) 369 | { 370 | for (i=0; i 5 | Everyone is permitted to copy and distribute verbatim copies 6 | of this license document, but changing it is not allowed. 7 | 8 | Preamble 9 | 10 | The GNU Affero General Public License is a free, copyleft license for 11 | software and other kinds of works, specifically designed to ensure 12 | cooperation with the community in the case of network server software. 13 | 14 | The licenses for most software and other practical works are designed 15 | to take away your freedom to share and change the works. By contrast, 16 | our General Public Licenses are intended to guarantee your freedom to 17 | share and change all versions of a program--to make sure it remains free 18 | software for all its users. 19 | 20 | When we speak of free software, we are referring to freedom, not 21 | price. Our General Public Licenses are designed to make sure that you 22 | have the freedom to distribute copies of free software (and charge for 23 | them if you wish), that you receive source code or can get it if you 24 | want it, that you can change the software or use pieces of it in new 25 | free programs, and that you know you can do these things. 26 | 27 | Developers that use our General Public Licenses protect your rights 28 | with two steps: (1) assert copyright on the software, and (2) offer 29 | you this License which gives you legal permission to copy, distribute 30 | and/or modify the software. 31 | 32 | A secondary benefit of defending all users' freedom is that 33 | improvements made in alternate versions of the program, if they 34 | receive widespread use, become available for other developers to 35 | incorporate. Many developers of free software are heartened and 36 | encouraged by the resulting cooperation. However, in the case of 37 | software used on network servers, this result may fail to come about. 38 | The GNU General Public License permits making a modified version and 39 | letting the public access it on a server without ever releasing its 40 | source code to the public. 41 | 42 | The GNU Affero General Public License is designed specifically to 43 | ensure that, in such cases, the modified source code becomes available 44 | to the community. It requires the operator of a network server to 45 | provide the source code of the modified version running there to the 46 | users of that server. Therefore, public use of a modified version, on 47 | a publicly accessible server, gives the public access to the source 48 | code of the modified version. 49 | 50 | An older license, called the Affero General Public License and 51 | published by Affero, was designed to accomplish similar goals. This is 52 | a different license, not a version of the Affero GPL, but Affero has 53 | released a new version of the Affero GPL which permits relicensing under 54 | this license. 55 | 56 | The precise terms and conditions for copying, distribution and 57 | modification follow. 58 | 59 | TERMS AND CONDITIONS 60 | 61 | 0. Definitions. 62 | 63 | "This License" refers to version 3 of the GNU Affero General Public License. 64 | 65 | "Copyright" also means copyright-like laws that apply to other kinds of 66 | works, such as semiconductor masks. 67 | 68 | "The Program" refers to any copyrightable work licensed under this 69 | License. Each licensee is addressed as "you". "Licensees" and 70 | "recipients" may be individuals or organizations. 71 | 72 | To "modify" a work means to copy from or adapt all or part of the work 73 | in a fashion requiring copyright permission, other than the making of an 74 | exact copy. The resulting work is called a "modified version" of the 75 | earlier work or a work "based on" the earlier work. 76 | 77 | A "covered work" means either the unmodified Program or a work based 78 | on the Program. 79 | 80 | To "propagate" a work means to do anything with it that, without 81 | permission, would make you directly or secondarily liable for 82 | infringement under applicable copyright law, except executing it on a 83 | computer or modifying a private copy. Propagation includes copying, 84 | distribution (with or without modification), making available to the 85 | public, and in some countries other activities as well. 86 | 87 | To "convey" a work means any kind of propagation that enables other 88 | parties to make or receive copies. Mere interaction with a user through 89 | a computer network, with no transfer of a copy, is not conveying. 90 | 91 | An interactive user interface displays "Appropriate Legal Notices" 92 | to the extent that it includes a convenient and prominently visible 93 | feature that (1) displays an appropriate copyright notice, and (2) 94 | tells the user that there is no warranty for the work (except to the 95 | extent that warranties are provided), that licensees may convey the 96 | work under this License, and how to view a copy of this License. If 97 | the interface presents a list of user commands or options, such as a 98 | menu, a prominent item in the list meets this criterion. 99 | 100 | 1. Source Code. 101 | 102 | The "source code" for a work means the preferred form of the work 103 | for making modifications to it. "Object code" means any non-source 104 | form of a work. 105 | 106 | A "Standard Interface" means an interface that either is an official 107 | standard defined by a recognized standards body, or, in the case of 108 | interfaces specified for a particular programming language, one that 109 | is widely used among developers working in that language. 110 | 111 | The "System Libraries" of an executable work include anything, other 112 | than the work as a whole, that (a) is included in the normal form of 113 | packaging a Major Component, but which is not part of that Major 114 | Component, and (b) serves only to enable use of the work with that 115 | Major Component, or to implement a Standard Interface for which an 116 | implementation is available to the public in source code form. A 117 | "Major Component", in this context, means a major essential component 118 | (kernel, window system, and so on) of the specific operating system 119 | (if any) on which the executable work runs, or a compiler used to 120 | produce the work, or an object code interpreter used to run it. 121 | 122 | The "Corresponding Source" for a work in object code form means all 123 | the source code needed to generate, install, and (for an executable 124 | work) run the object code and to modify the work, including scripts to 125 | control those activities. However, it does not include the work's 126 | System Libraries, or general-purpose tools or generally available free 127 | programs which are used unmodified in performing those activities but 128 | which are not part of the work. For example, Corresponding Source 129 | includes interface definition files associated with source files for 130 | the work, and the source code for shared libraries and dynamically 131 | linked subprograms that the work is specifically designed to require, 132 | such as by intimate data communication or control flow between those 133 | subprograms and other parts of the work. 134 | 135 | The Corresponding Source need not include anything that users 136 | can regenerate automatically from other parts of the Corresponding 137 | Source. 138 | 139 | The Corresponding Source for a work in source code form is that 140 | same work. 141 | 142 | 2. Basic Permissions. 143 | 144 | All rights granted under this License are granted for the term of 145 | copyright on the Program, and are irrevocable provided the stated 146 | conditions are met. This License explicitly affirms your unlimited 147 | permission to run the unmodified Program. The output from running a 148 | covered work is covered by this License only if the output, given its 149 | content, constitutes a covered work. This License acknowledges your 150 | rights of fair use or other equivalent, as provided by copyright law. 151 | 152 | You may make, run and propagate covered works that you do not 153 | convey, without conditions so long as your license otherwise remains 154 | in force. You may convey covered works to others for the sole purpose 155 | of having them make modifications exclusively for you, or provide you 156 | with facilities for running those works, provided that you comply with 157 | the terms of this License in conveying all material for which you do 158 | not control copyright. Those thus making or running the covered works 159 | for you must do so exclusively on your behalf, under your direction 160 | and control, on terms that prohibit them from making any copies of 161 | your copyrighted material outside their relationship with you. 162 | 163 | Conveying under any other circumstances is permitted solely under 164 | the conditions stated below. Sublicensing is not allowed; section 10 165 | makes it unnecessary. 166 | 167 | 3. Protecting Users' Legal Rights From Anti-Circumvention Law. 168 | 169 | No covered work shall be deemed part of an effective technological 170 | measure under any applicable law fulfilling obligations under article 171 | 11 of the WIPO copyright treaty adopted on 20 December 1996, or 172 | similar laws prohibiting or restricting circumvention of such 173 | measures. 174 | 175 | When you convey a covered work, you waive any legal power to forbid 176 | circumvention of technological measures to the extent such circumvention 177 | is effected by exercising rights under this License with respect to 178 | the covered work, and you disclaim any intention to limit operation or 179 | modification of the work as a means of enforcing, against the work's 180 | users, your or third parties' legal rights to forbid circumvention of 181 | technological measures. 182 | 183 | 4. Conveying Verbatim Copies. 184 | 185 | You may convey verbatim copies of the Program's source code as you 186 | receive it, in any medium, provided that you conspicuously and 187 | appropriately publish on each copy an appropriate copyright notice; 188 | keep intact all notices stating that this License and any 189 | non-permissive terms added in accord with section 7 apply to the code; 190 | keep intact all notices of the absence of any warranty; and give all 191 | recipients a copy of this License along with the Program. 192 | 193 | You may charge any price or no price for each copy that you convey, 194 | and you may offer support or warranty protection for a fee. 195 | 196 | 5. Conveying Modified Source Versions. 197 | 198 | You may convey a work based on the Program, or the modifications to 199 | produce it from the Program, in the form of source code under the 200 | terms of section 4, provided that you also meet all of these conditions: 201 | 202 | a) The work must carry prominent notices stating that you modified 203 | it, and giving a relevant date. 204 | 205 | b) The work must carry prominent notices stating that it is 206 | released under this License and any conditions added under section 207 | 7. This requirement modifies the requirement in section 4 to 208 | "keep intact all notices". 209 | 210 | c) You must license the entire work, as a whole, under this 211 | License to anyone who comes into possession of a copy. This 212 | License will therefore apply, along with any applicable section 7 213 | additional terms, to the whole of the work, and all its parts, 214 | regardless of how they are packaged. This License gives no 215 | permission to license the work in any other way, but it does not 216 | invalidate such permission if you have separately received it. 217 | 218 | d) If the work has interactive user interfaces, each must display 219 | Appropriate Legal Notices; however, if the Program has interactive 220 | interfaces that do not display Appropriate Legal Notices, your 221 | work need not make them do so. 222 | 223 | A compilation of a covered work with other separate and independent 224 | works, which are not by their nature extensions of the covered work, 225 | and which are not combined with it such as to form a larger program, 226 | in or on a volume of a storage or distribution medium, is called an 227 | "aggregate" if the compilation and its resulting copyright are not 228 | used to limit the access or legal rights of the compilation's users 229 | beyond what the individual works permit. Inclusion of a covered work 230 | in an aggregate does not cause this License to apply to the other 231 | parts of the aggregate. 232 | 233 | 6. Conveying Non-Source Forms. 234 | 235 | You may convey a covered work in object code form under the terms 236 | of sections 4 and 5, provided that you also convey the 237 | machine-readable Corresponding Source under the terms of this License, 238 | in one of these ways: 239 | 240 | a) Convey the object code in, or embodied in, a physical product 241 | (including a physical distribution medium), accompanied by the 242 | Corresponding Source fixed on a durable physical medium 243 | customarily used for software interchange. 244 | 245 | b) Convey the object code in, or embodied in, a physical product 246 | (including a physical distribution medium), accompanied by a 247 | written offer, valid for at least three years and valid for as 248 | long as you offer spare parts or customer support for that product 249 | model, to give anyone who possesses the object code either (1) a 250 | copy of the Corresponding Source for all the software in the 251 | product that is covered by this License, on a durable physical 252 | medium customarily used for software interchange, for a price no 253 | more than your reasonable cost of physically performing this 254 | conveying of source, or (2) access to copy the 255 | Corresponding Source from a network server at no charge. 256 | 257 | c) Convey individual copies of the object code with a copy of the 258 | written offer to provide the Corresponding Source. This 259 | alternative is allowed only occasionally and noncommercially, and 260 | only if you received the object code with such an offer, in accord 261 | with subsection 6b. 262 | 263 | d) Convey the object code by offering access from a designated 264 | place (gratis or for a charge), and offer equivalent access to the 265 | Corresponding Source in the same way through the same place at no 266 | further charge. You need not require recipients to copy the 267 | Corresponding Source along with the object code. If the place to 268 | copy the object code is a network server, the Corresponding Source 269 | may be on a different server (operated by you or a third party) 270 | that supports equivalent copying facilities, provided you maintain 271 | clear directions next to the object code saying where to find the 272 | Corresponding Source. Regardless of what server hosts the 273 | Corresponding Source, you remain obligated to ensure that it is 274 | available for as long as needed to satisfy these requirements. 275 | 276 | e) Convey the object code using peer-to-peer transmission, provided 277 | you inform other peers where the object code and Corresponding 278 | Source of the work are being offered to the general public at no 279 | charge under subsection 6d. 280 | 281 | A separable portion of the object code, whose source code is excluded 282 | from the Corresponding Source as a System Library, need not be 283 | included in conveying the object code work. 284 | 285 | A "User Product" is either (1) a "consumer product", which means any 286 | tangible personal property which is normally used for personal, family, 287 | or household purposes, or (2) anything designed or sold for incorporation 288 | into a dwelling. In determining whether a product is a consumer product, 289 | doubtful cases shall be resolved in favor of coverage. For a particular 290 | product received by a particular user, "normally used" refers to a 291 | typical or common use of that class of product, regardless of the status 292 | of the particular user or of the way in which the particular user 293 | actually uses, or expects or is expected to use, the product. A product 294 | is a consumer product regardless of whether the product has substantial 295 | commercial, industrial or non-consumer uses, unless such uses represent 296 | the only significant mode of use of the product. 297 | 298 | "Installation Information" for a User Product means any methods, 299 | procedures, authorization keys, or other information required to install 300 | and execute modified versions of a covered work in that User Product from 301 | a modified version of its Corresponding Source. The information must 302 | suffice to ensure that the continued functioning of the modified object 303 | code is in no case prevented or interfered with solely because 304 | modification has been made. 305 | 306 | If you convey an object code work under this section in, or with, or 307 | specifically for use in, a User Product, and the conveying occurs as 308 | part of a transaction in which the right of possession and use of the 309 | User Product is transferred to the recipient in perpetuity or for a 310 | fixed term (regardless of how the transaction is characterized), the 311 | Corresponding Source conveyed under this section must be accompanied 312 | by the Installation Information. But this requirement does not apply 313 | if neither you nor any third party retains the ability to install 314 | modified object code on the User Product (for example, the work has 315 | been installed in ROM). 316 | 317 | The requirement to provide Installation Information does not include a 318 | requirement to continue to provide support service, warranty, or updates 319 | for a work that has been modified or installed by the recipient, or for 320 | the User Product in which it has been modified or installed. Access to a 321 | network may be denied when the modification itself materially and 322 | adversely affects the operation of the network or violates the rules and 323 | protocols for communication across the network. 324 | 325 | Corresponding Source conveyed, and Installation Information provided, 326 | in accord with this section must be in a format that is publicly 327 | documented (and with an implementation available to the public in 328 | source code form), and must require no special password or key for 329 | unpacking, reading or copying. 330 | 331 | 7. Additional Terms. 332 | 333 | "Additional permissions" are terms that supplement the terms of this 334 | License by making exceptions from one or more of its conditions. 335 | Additional permissions that are applicable to the entire Program shall 336 | be treated as though they were included in this License, to the extent 337 | that they are valid under applicable law. If additional permissions 338 | apply only to part of the Program, that part may be used separately 339 | under those permissions, but the entire Program remains governed by 340 | this License without regard to the additional permissions. 341 | 342 | When you convey a copy of a covered work, you may at your option 343 | remove any additional permissions from that copy, or from any part of 344 | it. (Additional permissions may be written to require their own 345 | removal in certain cases when you modify the work.) You may place 346 | additional permissions on material, added by you to a covered work, 347 | for which you have or can give appropriate copyright permission. 348 | 349 | Notwithstanding any other provision of this License, for material you 350 | add to a covered work, you may (if authorized by the copyright holders of 351 | that material) supplement the terms of this License with terms: 352 | 353 | a) Disclaiming warranty or limiting liability differently from the 354 | terms of sections 15 and 16 of this License; or 355 | 356 | b) Requiring preservation of specified reasonable legal notices or 357 | author attributions in that material or in the Appropriate Legal 358 | Notices displayed by works containing it; or 359 | 360 | c) Prohibiting misrepresentation of the origin of that material, or 361 | requiring that modified versions of such material be marked in 362 | reasonable ways as different from the original version; or 363 | 364 | d) Limiting the use for publicity purposes of names of licensors or 365 | authors of the material; or 366 | 367 | e) Declining to grant rights under trademark law for use of some 368 | trade names, trademarks, or service marks; or 369 | 370 | f) Requiring indemnification of licensors and authors of that 371 | material by anyone who conveys the material (or modified versions of 372 | it) with contractual assumptions of liability to the recipient, for 373 | any liability that these contractual assumptions directly impose on 374 | those licensors and authors. 375 | 376 | All other non-permissive additional terms are considered "further 377 | restrictions" within the meaning of section 10. If the Program as you 378 | received it, or any part of it, contains a notice stating that it is 379 | governed by this License along with a term that is a further 380 | restriction, you may remove that term. If a license document contains 381 | a further restriction but permits relicensing or conveying under this 382 | License, you may add to a covered work material governed by the terms 383 | of that license document, provided that the further restriction does 384 | not survive such relicensing or conveying. 385 | 386 | If you add terms to a covered work in accord with this section, you 387 | must place, in the relevant source files, a statement of the 388 | additional terms that apply to those files, or a notice indicating 389 | where to find the applicable terms. 390 | 391 | Additional terms, permissive or non-permissive, may be stated in the 392 | form of a separately written license, or stated as exceptions; 393 | the above requirements apply either way. 394 | 395 | 8. Termination. 396 | 397 | You may not propagate or modify a covered work except as expressly 398 | provided under this License. Any attempt otherwise to propagate or 399 | modify it is void, and will automatically terminate your rights under 400 | this License (including any patent licenses granted under the third 401 | paragraph of section 11). 402 | 403 | However, if you cease all violation of this License, then your 404 | license from a particular copyright holder is reinstated (a) 405 | provisionally, unless and until the copyright holder explicitly and 406 | finally terminates your license, and (b) permanently, if the copyright 407 | holder fails to notify you of the violation by some reasonable means 408 | prior to 60 days after the cessation. 409 | 410 | Moreover, your license from a particular copyright holder is 411 | reinstated permanently if the copyright holder notifies you of the 412 | violation by some reasonable means, this is the first time you have 413 | received notice of violation of this License (for any work) from that 414 | copyright holder, and you cure the violation prior to 30 days after 415 | your receipt of the notice. 416 | 417 | Termination of your rights under this section does not terminate the 418 | licenses of parties who have received copies or rights from you under 419 | this License. If your rights have been terminated and not permanently 420 | reinstated, you do not qualify to receive new licenses for the same 421 | material under section 10. 422 | 423 | 9. Acceptance Not Required for Having Copies. 424 | 425 | You are not required to accept this License in order to receive or 426 | run a copy of the Program. Ancillary propagation of a covered work 427 | occurring solely as a consequence of using peer-to-peer transmission 428 | to receive a copy likewise does not require acceptance. However, 429 | nothing other than this License grants you permission to propagate or 430 | modify any covered work. These actions infringe copyright if you do 431 | not accept this License. Therefore, by modifying or propagating a 432 | covered work, you indicate your acceptance of this License to do so. 433 | 434 | 10. Automatic Licensing of Downstream Recipients. 435 | 436 | Each time you convey a covered work, the recipient automatically 437 | receives a license from the original licensors, to run, modify and 438 | propagate that work, subject to this License. You are not responsible 439 | for enforcing compliance by third parties with this License. 440 | 441 | An "entity transaction" is a transaction transferring control of an 442 | organization, or substantially all assets of one, or subdividing an 443 | organization, or merging organizations. If propagation of a covered 444 | work results from an entity transaction, each party to that 445 | transaction who receives a copy of the work also receives whatever 446 | licenses to the work the party's predecessor in interest had or could 447 | give under the previous paragraph, plus a right to possession of the 448 | Corresponding Source of the work from the predecessor in interest, if 449 | the predecessor has it or can get it with reasonable efforts. 450 | 451 | You may not impose any further restrictions on the exercise of the 452 | rights granted or affirmed under this License. For example, you may 453 | not impose a license fee, royalty, or other charge for exercise of 454 | rights granted under this License, and you may not initiate litigation 455 | (including a cross-claim or counterclaim in a lawsuit) alleging that 456 | any patent claim is infringed by making, using, selling, offering for 457 | sale, or importing the Program or any portion of it. 458 | 459 | 11. Patents. 460 | 461 | A "contributor" is a copyright holder who authorizes use under this 462 | License of the Program or a work on which the Program is based. The 463 | work thus licensed is called the contributor's "contributor version". 464 | 465 | A contributor's "essential patent claims" are all patent claims 466 | owned or controlled by the contributor, whether already acquired or 467 | hereafter acquired, that would be infringed by some manner, permitted 468 | by this License, of making, using, or selling its contributor version, 469 | but do not include claims that would be infringed only as a 470 | consequence of further modification of the contributor version. For 471 | purposes of this definition, "control" includes the right to grant 472 | patent sublicenses in a manner consistent with the requirements of 473 | this License. 474 | 475 | Each contributor grants you a non-exclusive, worldwide, royalty-free 476 | patent license under the contributor's essential patent claims, to 477 | make, use, sell, offer for sale, import and otherwise run, modify and 478 | propagate the contents of its contributor version. 479 | 480 | In the following three paragraphs, a "patent license" is any express 481 | agreement or commitment, however denominated, not to enforce a patent 482 | (such as an express permission to practice a patent or covenant not to 483 | sue for patent infringement). To "grant" such a patent license to a 484 | party means to make such an agreement or commitment not to enforce a 485 | patent against the party. 486 | 487 | If you convey a covered work, knowingly relying on a patent license, 488 | and the Corresponding Source of the work is not available for anyone 489 | to copy, free of charge and under the terms of this License, through a 490 | publicly available network server or other readily accessible means, 491 | then you must either (1) cause the Corresponding Source to be so 492 | available, or (2) arrange to deprive yourself of the benefit of the 493 | patent license for this particular work, or (3) arrange, in a manner 494 | consistent with the requirements of this License, to extend the patent 495 | license to downstream recipients. "Knowingly relying" means you have 496 | actual knowledge that, but for the patent license, your conveying the 497 | covered work in a country, or your recipient's use of the covered work 498 | in a country, would infringe one or more identifiable patents in that 499 | country that you have reason to believe are valid. 500 | 501 | If, pursuant to or in connection with a single transaction or 502 | arrangement, you convey, or propagate by procuring conveyance of, a 503 | covered work, and grant a patent license to some of the parties 504 | receiving the covered work authorizing them to use, propagate, modify 505 | or convey a specific copy of the covered work, then the patent license 506 | you grant is automatically extended to all recipients of the covered 507 | work and works based on it. 508 | 509 | A patent license is "discriminatory" if it does not include within 510 | the scope of its coverage, prohibits the exercise of, or is 511 | conditioned on the non-exercise of one or more of the rights that are 512 | specifically granted under this License. You may not convey a covered 513 | work if you are a party to an arrangement with a third party that is 514 | in the business of distributing software, under which you make payment 515 | to the third party based on the extent of your activity of conveying 516 | the work, and under which the third party grants, to any of the 517 | parties who would receive the covered work from you, a discriminatory 518 | patent license (a) in connection with copies of the covered work 519 | conveyed by you (or copies made from those copies), or (b) primarily 520 | for and in connection with specific products or compilations that 521 | contain the covered work, unless you entered into that arrangement, 522 | or that patent license was granted, prior to 28 March 2007. 523 | 524 | Nothing in this License shall be construed as excluding or limiting 525 | any implied license or other defenses to infringement that may 526 | otherwise be available to you under applicable patent law. 527 | 528 | 12. No Surrender of Others' Freedom. 529 | 530 | If conditions are imposed on you (whether by court order, agreement or 531 | otherwise) that contradict the conditions of this License, they do not 532 | excuse you from the conditions of this License. If you cannot convey a 533 | covered work so as to satisfy simultaneously your obligations under this 534 | License and any other pertinent obligations, then as a consequence you may 535 | not convey it at all. For example, if you agree to terms that obligate you 536 | to collect a royalty for further conveying from those to whom you convey 537 | the Program, the only way you could satisfy both those terms and this 538 | License would be to refrain entirely from conveying the Program. 539 | 540 | 13. Remote Network Interaction; Use with the GNU General Public License. 541 | 542 | Notwithstanding any other provision of this License, if you modify the 543 | Program, your modified version must prominently offer all users 544 | interacting with it remotely through a computer network (if your version 545 | supports such interaction) an opportunity to receive the Corresponding 546 | Source of your version by providing access to the Corresponding Source 547 | from a network server at no charge, through some standard or customary 548 | means of facilitating copying of software. This Corresponding Source 549 | shall include the Corresponding Source for any work covered by version 3 550 | of the GNU General Public License that is incorporated pursuant to the 551 | following paragraph. 552 | 553 | Notwithstanding any other provision of this License, you have 554 | permission to link or combine any covered work with a work licensed 555 | under version 3 of the GNU General Public License into a single 556 | combined work, and to convey the resulting work. The terms of this 557 | License will continue to apply to the part which is the covered work, 558 | but the work with which it is combined will remain governed by version 559 | 3 of the GNU General Public License. 560 | 561 | 14. Revised Versions of this License. 562 | 563 | The Free Software Foundation may publish revised and/or new versions of 564 | the GNU Affero General Public License from time to time. Such new versions 565 | will be similar in spirit to the present version, but may differ in detail to 566 | address new problems or concerns. 567 | 568 | Each version is given a distinguishing version number. If the 569 | Program specifies that a certain numbered version of the GNU Affero General 570 | Public License "or any later version" applies to it, you have the 571 | option of following the terms and conditions either of that numbered 572 | version or of any later version published by the Free Software 573 | Foundation. If the Program does not specify a version number of the 574 | GNU Affero General Public License, you may choose any version ever published 575 | by the Free Software Foundation. 576 | 577 | If the Program specifies that a proxy can decide which future 578 | versions of the GNU Affero General Public License can be used, that proxy's 579 | public statement of acceptance of a version permanently authorizes you 580 | to choose that version for the Program. 581 | 582 | Later license versions may give you additional or different 583 | permissions. However, no additional obligations are imposed on any 584 | author or copyright holder as a result of your choosing to follow a 585 | later version. 586 | 587 | 15. Disclaimer of Warranty. 588 | 589 | THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY 590 | APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT 591 | HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY 592 | OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, 593 | THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 594 | PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM 595 | IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF 596 | ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 597 | 598 | 16. Limitation of Liability. 599 | 600 | IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING 601 | WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS 602 | THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY 603 | GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE 604 | USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF 605 | DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD 606 | PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), 607 | EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF 608 | SUCH DAMAGES. 609 | 610 | 17. Interpretation of Sections 15 and 16. 611 | 612 | If the disclaimer of warranty and limitation of liability provided 613 | above cannot be given local legal effect according to their terms, 614 | reviewing courts shall apply local law that most closely approximates 615 | an absolute waiver of all civil liability in connection with the 616 | Program, unless a warranty or assumption of liability accompanies a 617 | copy of the Program in return for a fee. 618 | 619 | END OF TERMS AND CONDITIONS 620 | 621 | How to Apply These Terms to Your New Programs 622 | 623 | If you develop a new program, and you want it to be of the greatest 624 | possible use to the public, the best way to achieve this is to make it 625 | free software which everyone can redistribute and change under these terms. 626 | 627 | To do so, attach the following notices to the program. It is safest 628 | to attach them to the start of each source file to most effectively 629 | state the exclusion of warranty; and each file should have at least 630 | the "copyright" line and a pointer to where the full notice is found. 631 | 632 | 633 | Copyright (C) 634 | 635 | This program is free software: you can redistribute it and/or modify 636 | it under the terms of the GNU Affero General Public License as published by 637 | the Free Software Foundation, either version 3 of the License, or 638 | (at your option) any later version. 639 | 640 | This program is distributed in the hope that it will be useful, 641 | but WITHOUT ANY WARRANTY; without even the implied warranty of 642 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 643 | GNU Affero General Public License for more details. 644 | 645 | You should have received a copy of the GNU Affero General Public License 646 | along with this program. If not, see . 647 | 648 | Also add information on how to contact you by electronic and paper mail. 649 | 650 | If your software can interact with users remotely through a computer 651 | network, you should also make sure that it provides a way for users to 652 | get its source. For example, if your program is a web application, its 653 | interface could display a "Source" link that leads users to an archive 654 | of the code. There are many ways you could offer source, and different 655 | solutions will be better for different programs; see section 13 for the 656 | specific requirements. 657 | 658 | You should also get your employer (if you work as a programmer) or school, 659 | if any, to sign a "copyright disclaimer" for the program, if necessary. 660 | For more information on this, and how to apply and follow the GNU AGPL, see 661 | . 662 | -------------------------------------------------------------------------------- /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 . 19 | **/ 20 | /* }}} */ 21 | 22 | #include 23 | #include 24 | #include 25 | #include 26 | #include 27 | #include 28 | #include 29 | #include 30 | #include 31 | #include 32 | 33 | #include 34 | #include 35 | #include 36 | #include 37 | #include 38 | #include 39 | #include 40 | 41 | #include 42 | #include 43 | #include 44 | 45 | #ifndef LDID_NOSMIME 46 | #include 47 | #include 48 | #include 49 | #include 50 | #include 51 | #endif 52 | 53 | #ifdef __APPLE__ 54 | #include 55 | 56 | #define LDID_SHA1_DIGEST_LENGTH CC_SHA1_DIGEST_LENGTH 57 | #define LDID_SHA1 CC_SHA1 58 | #define LDID_SHA1_CTX CC_SHA1_CTX 59 | #define LDID_SHA1_Init CC_SHA1_Init 60 | #define LDID_SHA1_Update CC_SHA1_Update 61 | #define LDID_SHA1_Final CC_SHA1_Final 62 | 63 | #define LDID_SHA256_DIGEST_LENGTH CC_SHA256_DIGEST_LENGTH 64 | #define LDID_SHA256 CC_SHA256 65 | #define LDID_SHA256_CTX CC_SHA256_CTX 66 | #define LDID_SHA256_Init CC_SHA256_Init 67 | #define LDID_SHA256_Update CC_SHA256_Update 68 | #define LDID_SHA256_Final CC_SHA256_Final 69 | #else 70 | #include 71 | 72 | #define LDID_SHA1_DIGEST_LENGTH SHA_DIGEST_LENGTH 73 | #define LDID_SHA1 SHA1 74 | #define LDID_SHA1_CTX SHA_CTX 75 | #define LDID_SHA1_Init SHA1_Init 76 | #define LDID_SHA1_Update SHA1_Update 77 | #define LDID_SHA1_Final SHA1_Final 78 | 79 | #define LDID_SHA256_DIGEST_LENGTH SHA256_DIGEST_LENGTH 80 | #define LDID_SHA256 SHA256 81 | #define LDID_SHA256_CTX SHA256_CTX 82 | #define LDID_SHA256_Init SHA256_Init 83 | #define LDID_SHA256_Update SHA256_Update 84 | #define LDID_SHA256_Final SHA256_Final 85 | #endif 86 | 87 | #ifndef LDID_NOPLIST 88 | #include 89 | #elif __APPLE__ 90 | #include 91 | #endif 92 | 93 | #include "ldid.hpp" 94 | 95 | #define _assert___(line) \ 96 | #line 97 | #define _assert__(line) \ 98 | _assert___(line) 99 | 100 | #ifndef $ 101 | #define $(value) value 102 | #endif 103 | 104 | #ifdef __EXCEPTIONS 105 | #define _assert_(expr, format, ...) \ 106 | do if (!(expr)) { \ 107 | fprintf(stderr, $("%s(%u): _assert(): " format "\n"), __FILE__, __LINE__, ## __VA_ARGS__); \ 108 | throw $(__FILE__ "(" _assert__(__LINE__) "): _assert(" #expr ")"); \ 109 | } while (false) 110 | #else 111 | // XXX: this is not acceptable 112 | #define _assert_(expr, format, ...) \ 113 | do if (!(expr)) { \ 114 | fprintf(stderr, $("%s(%u): _assert(): " format "\n"), __FILE__, __LINE__, ## __VA_ARGS__); \ 115 | exit(-1); \ 116 | } while (false) 117 | #endif 118 | 119 | #define _assert(expr) \ 120 | _assert_(expr, "%s", $(#expr)) 121 | 122 | #define _syscall(expr, ...) [&] { for (;;) { \ 123 | auto _value(expr); \ 124 | if ((long) _value != -1) \ 125 | return _value; \ 126 | int error(errno); \ 127 | if (error == EINTR) \ 128 | continue; \ 129 | /* XXX: EINTR is included in this list to fix g++ */ \ 130 | for (auto success : (long[]) {EINTR, __VA_ARGS__}) \ 131 | if (error == success) \ 132 | return (decltype(expr)) -success; \ 133 | _assert_(false, "errno=%u", error); \ 134 | } }() 135 | 136 | #define _trace() \ 137 | fprintf(stderr, $("_trace(%s:%u): %s\n"), __FILE__, __LINE__, $(__FUNCTION__)) 138 | 139 | #define _not(type) \ 140 | ((type) ~ (type) 0) 141 | 142 | #define _packed \ 143 | __attribute__((packed)) 144 | 145 | template 146 | struct Iterator_ { 147 | typedef typename Type_::const_iterator Result; 148 | }; 149 | 150 | #define _foreach(item, list) \ 151 | for (bool _stop(true); _stop; ) \ 152 | for (const __typeof__(list) &_list = (list); _stop; _stop = false) \ 153 | for (Iterator_<__typeof__(list)>::Result _item = _list.begin(); _item != _list.end(); ++_item) \ 154 | for (bool _suck(true); _suck; _suck = false) \ 155 | for (const __typeof__(*_item) &item = *_item; _suck; _suck = false) 156 | 157 | class _Scope { 158 | }; 159 | 160 | template 161 | class Scope : 162 | public _Scope 163 | { 164 | private: 165 | Function_ function_; 166 | 167 | public: 168 | Scope(const Function_ &function) : 169 | function_(function) 170 | { 171 | } 172 | 173 | ~Scope() { 174 | function_(); 175 | } 176 | }; 177 | 178 | template 179 | Scope _scope(const Function_ &function) { 180 | return Scope(function); 181 | } 182 | 183 | #define _scope__(counter, function) \ 184 | __attribute__((__unused__)) \ 185 | const _Scope &_scope ## counter(_scope([&]function)) 186 | #define _scope_(counter, function) \ 187 | _scope__(counter, function) 188 | #define _scope(function) \ 189 | _scope_(__COUNTER__, function) 190 | 191 | #define CPU_ARCH_MASK uint32_t(0xff000000) 192 | #define CPU_ARCH_ABI64 uint32_t(0x01000000) 193 | 194 | #define CPU_TYPE_ANY uint32_t(-1) 195 | #define CPU_TYPE_VAX uint32_t( 1) 196 | #define CPU_TYPE_MC680x0 uint32_t( 6) 197 | #define CPU_TYPE_X86 uint32_t( 7) 198 | #define CPU_TYPE_MC98000 uint32_t(10) 199 | #define CPU_TYPE_HPPA uint32_t(11) 200 | #define CPU_TYPE_ARM uint32_t(12) 201 | #define CPU_TYPE_MC88000 uint32_t(13) 202 | #define CPU_TYPE_SPARC uint32_t(14) 203 | #define CPU_TYPE_I860 uint32_t(15) 204 | #define CPU_TYPE_POWERPC uint32_t(18) 205 | 206 | #define CPU_TYPE_I386 CPU_TYPE_X86 207 | 208 | #define CPU_TYPE_ARM64 (CPU_ARCH_ABI64 | CPU_TYPE_ARM) 209 | #define CPU_TYPE_POWERPC64 (CPU_ARCH_ABI64 | CPU_TYPE_POWERPC) 210 | #define CPU_TYPE_X86_64 (CPU_ARCH_ABI64 | CPU_TYPE_X86) 211 | 212 | struct fat_header { 213 | uint32_t magic; 214 | uint32_t nfat_arch; 215 | } _packed; 216 | 217 | #define FAT_MAGIC 0xcafebabe 218 | #define FAT_CIGAM 0xbebafeca 219 | 220 | struct fat_arch { 221 | uint32_t cputype; 222 | uint32_t cpusubtype; 223 | uint32_t offset; 224 | uint32_t size; 225 | uint32_t align; 226 | } _packed; 227 | 228 | struct mach_header { 229 | uint32_t magic; 230 | uint32_t cputype; 231 | uint32_t cpusubtype; 232 | uint32_t filetype; 233 | uint32_t ncmds; 234 | uint32_t sizeofcmds; 235 | uint32_t flags; 236 | } _packed; 237 | 238 | #define MH_MAGIC 0xfeedface 239 | #define MH_CIGAM 0xcefaedfe 240 | 241 | #define MH_MAGIC_64 0xfeedfacf 242 | #define MH_CIGAM_64 0xcffaedfe 243 | 244 | #define MH_DYLDLINK 0x4 245 | 246 | #define MH_OBJECT 0x1 247 | #define MH_EXECUTE 0x2 248 | #define MH_DYLIB 0x6 249 | #define MH_DYLINKER 0x7 250 | #define MH_BUNDLE 0x8 251 | #define MH_DYLIB_STUB 0x9 252 | 253 | struct load_command { 254 | uint32_t cmd; 255 | uint32_t cmdsize; 256 | } _packed; 257 | 258 | #define LC_REQ_DYLD uint32_t(0x80000000) 259 | 260 | #define LC_SEGMENT uint32_t(0x01) 261 | #define LC_SYMTAB uint32_t(0x02) 262 | #define LC_DYSYMTAB uint32_t(0x0b) 263 | #define LC_LOAD_DYLIB uint32_t(0x0c) 264 | #define LC_ID_DYLIB uint32_t(0x0d) 265 | #define LC_SEGMENT_64 uint32_t(0x19) 266 | #define LC_UUID uint32_t(0x1b) 267 | #define LC_CODE_SIGNATURE uint32_t(0x1d) 268 | #define LC_SEGMENT_SPLIT_INFO uint32_t(0x1e) 269 | #define LC_REEXPORT_DYLIB uint32_t(0x1f | LC_REQ_DYLD) 270 | #define LC_ENCRYPTION_INFO uint32_t(0x21) 271 | #define LC_DYLD_INFO uint32_t(0x22) 272 | #define LC_DYLD_INFO_ONLY uint32_t(0x22 | LC_REQ_DYLD) 273 | #define LC_ENCRYPTION_INFO_64 uint32_t(0x2c) 274 | 275 | union Version { 276 | struct { 277 | uint8_t patch; 278 | uint8_t minor; 279 | uint16_t major; 280 | } _packed; 281 | 282 | uint32_t value; 283 | }; 284 | 285 | struct dylib { 286 | uint32_t name; 287 | uint32_t timestamp; 288 | uint32_t current_version; 289 | uint32_t compatibility_version; 290 | } _packed; 291 | 292 | struct dylib_command { 293 | uint32_t cmd; 294 | uint32_t cmdsize; 295 | struct dylib dylib; 296 | } _packed; 297 | 298 | struct uuid_command { 299 | uint32_t cmd; 300 | uint32_t cmdsize; 301 | uint8_t uuid[16]; 302 | } _packed; 303 | 304 | struct symtab_command { 305 | uint32_t cmd; 306 | uint32_t cmdsize; 307 | uint32_t symoff; 308 | uint32_t nsyms; 309 | uint32_t stroff; 310 | uint32_t strsize; 311 | } _packed; 312 | 313 | struct dyld_info_command { 314 | uint32_t cmd; 315 | uint32_t cmdsize; 316 | uint32_t rebase_off; 317 | uint32_t rebase_size; 318 | uint32_t bind_off; 319 | uint32_t bind_size; 320 | uint32_t weak_bind_off; 321 | uint32_t weak_bind_size; 322 | uint32_t lazy_bind_off; 323 | uint32_t lazy_bind_size; 324 | uint32_t export_off; 325 | uint32_t export_size; 326 | } _packed; 327 | 328 | struct dysymtab_command { 329 | uint32_t cmd; 330 | uint32_t cmdsize; 331 | uint32_t ilocalsym; 332 | uint32_t nlocalsym; 333 | uint32_t iextdefsym; 334 | uint32_t nextdefsym; 335 | uint32_t iundefsym; 336 | uint32_t nundefsym; 337 | uint32_t tocoff; 338 | uint32_t ntoc; 339 | uint32_t modtaboff; 340 | uint32_t nmodtab; 341 | uint32_t extrefsymoff; 342 | uint32_t nextrefsyms; 343 | uint32_t indirectsymoff; 344 | uint32_t nindirectsyms; 345 | uint32_t extreloff; 346 | uint32_t nextrel; 347 | uint32_t locreloff; 348 | uint32_t nlocrel; 349 | } _packed; 350 | 351 | struct dylib_table_of_contents { 352 | uint32_t symbol_index; 353 | uint32_t module_index; 354 | } _packed; 355 | 356 | struct dylib_module { 357 | uint32_t module_name; 358 | uint32_t iextdefsym; 359 | uint32_t nextdefsym; 360 | uint32_t irefsym; 361 | uint32_t nrefsym; 362 | uint32_t ilocalsym; 363 | uint32_t nlocalsym; 364 | uint32_t iextrel; 365 | uint32_t nextrel; 366 | uint32_t iinit_iterm; 367 | uint32_t ninit_nterm; 368 | uint32_t objc_module_info_addr; 369 | uint32_t objc_module_info_size; 370 | } _packed; 371 | 372 | struct dylib_reference { 373 | uint32_t isym:24; 374 | uint32_t flags:8; 375 | } _packed; 376 | 377 | struct relocation_info { 378 | int32_t r_address; 379 | uint32_t r_symbolnum:24; 380 | uint32_t r_pcrel:1; 381 | uint32_t r_length:2; 382 | uint32_t r_extern:1; 383 | uint32_t r_type:4; 384 | } _packed; 385 | 386 | struct nlist { 387 | union { 388 | char *n_name; 389 | int32_t n_strx; 390 | } n_un; 391 | 392 | uint8_t n_type; 393 | uint8_t n_sect; 394 | uint8_t n_desc; 395 | uint32_t n_value; 396 | } _packed; 397 | 398 | struct segment_command { 399 | uint32_t cmd; 400 | uint32_t cmdsize; 401 | char segname[16]; 402 | uint32_t vmaddr; 403 | uint32_t vmsize; 404 | uint32_t fileoff; 405 | uint32_t filesize; 406 | uint32_t maxprot; 407 | uint32_t initprot; 408 | uint32_t nsects; 409 | uint32_t flags; 410 | } _packed; 411 | 412 | struct segment_command_64 { 413 | uint32_t cmd; 414 | uint32_t cmdsize; 415 | char segname[16]; 416 | uint64_t vmaddr; 417 | uint64_t vmsize; 418 | uint64_t fileoff; 419 | uint64_t filesize; 420 | uint32_t maxprot; 421 | uint32_t initprot; 422 | uint32_t nsects; 423 | uint32_t flags; 424 | } _packed; 425 | 426 | struct section { 427 | char sectname[16]; 428 | char segname[16]; 429 | uint32_t addr; 430 | uint32_t size; 431 | uint32_t offset; 432 | uint32_t align; 433 | uint32_t reloff; 434 | uint32_t nreloc; 435 | uint32_t flags; 436 | uint32_t reserved1; 437 | uint32_t reserved2; 438 | } _packed; 439 | 440 | struct section_64 { 441 | char sectname[16]; 442 | char segname[16]; 443 | uint64_t addr; 444 | uint64_t size; 445 | uint32_t offset; 446 | uint32_t align; 447 | uint32_t reloff; 448 | uint32_t nreloc; 449 | uint32_t flags; 450 | uint32_t reserved1; 451 | uint32_t reserved2; 452 | uint32_t reserved3; 453 | } _packed; 454 | 455 | struct linkedit_data_command { 456 | uint32_t cmd; 457 | uint32_t cmdsize; 458 | uint32_t dataoff; 459 | uint32_t datasize; 460 | } _packed; 461 | 462 | struct encryption_info_command { 463 | uint32_t cmd; 464 | uint32_t cmdsize; 465 | uint32_t cryptoff; 466 | uint32_t cryptsize; 467 | uint32_t cryptid; 468 | } _packed; 469 | 470 | #define BIND_OPCODE_MASK 0xf0 471 | #define BIND_IMMEDIATE_MASK 0x0f 472 | #define BIND_OPCODE_DONE 0x00 473 | #define BIND_OPCODE_SET_DYLIB_ORDINAL_IMM 0x10 474 | #define BIND_OPCODE_SET_DYLIB_ORDINAL_ULEB 0x20 475 | #define BIND_OPCODE_SET_DYLIB_SPECIAL_IMM 0x30 476 | #define BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM 0x40 477 | #define BIND_OPCODE_SET_TYPE_IMM 0x50 478 | #define BIND_OPCODE_SET_ADDEND_SLEB 0x60 479 | #define BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB 0x70 480 | #define BIND_OPCODE_ADD_ADDR_ULEB 0x80 481 | #define BIND_OPCODE_DO_BIND 0x90 482 | #define BIND_OPCODE_DO_BIND_ADD_ADDR_ULEB 0xa0 483 | #define BIND_OPCODE_DO_BIND_ADD_ADDR_IMM_SCALED 0xb0 484 | #define BIND_OPCODE_DO_BIND_ULEB_TIMES_SKIPPING_ULEB 0xc0 485 | 486 | struct : ldid::Progress { 487 | virtual void operator()(const std::string &value) const { 488 | } 489 | 490 | virtual void operator()(double value) const { 491 | } 492 | } dummy_; 493 | 494 | struct Progression : ldid::Progress { 495 | const ldid::Progress &progress_; 496 | std::string name_; 497 | 498 | Progression(const ldid::Progress &progress, const std::string &name) : 499 | progress_(progress), 500 | name_(name) 501 | { 502 | } 503 | 504 | virtual void operator()(const std::string &value) const { 505 | return progress_(name_ + " (" + value + ")"); 506 | } 507 | 508 | virtual void operator()(double value) const { 509 | return progress_(value); 510 | } 511 | }; 512 | 513 | static std::streamsize read(std::streambuf &stream, void *data, size_t size) { 514 | auto writ(stream.sgetn(static_cast(data), size)); 515 | _assert(writ >= 0); 516 | return writ; 517 | } 518 | 519 | static inline void put(std::streambuf &stream, uint8_t value) { 520 | _assert(stream.sputc(value) != EOF); 521 | } 522 | 523 | static inline void get(std::streambuf &stream, void *data, size_t size) { 524 | _assert(read(stream, data, size) == size); 525 | } 526 | 527 | static inline void put(std::streambuf &stream, const void *data, size_t size) { 528 | _assert(stream.sputn(static_cast(data), size) == size); 529 | } 530 | 531 | static inline void put(std::streambuf &stream, const void *data, size_t size, const ldid::Progress &progress) { 532 | progress(0); 533 | for (size_t total(0); total != size;) { 534 | auto writ(std::min(size - total, size_t(4096 * 4))); 535 | _assert(stream.sputn(static_cast(data) + total, writ) == writ); 536 | total += writ; 537 | progress(double(total) / size); 538 | } 539 | } 540 | 541 | static inline void put(std::streambuf &stream, const std::string &data) { 542 | return put(stream, data.data(), data.size()); 543 | } 544 | 545 | static size_t most(std::streambuf &stream, void *data, size_t size) { 546 | size_t total(size); 547 | while (size > 0) 548 | if (auto writ = read(stream, data, size)) 549 | size -= writ; 550 | else break; 551 | return total - size; 552 | } 553 | 554 | static inline void pad(std::streambuf &stream, size_t size) { 555 | char padding[size]; 556 | memset(padding, 0, size); 557 | put(stream, padding, size); 558 | } 559 | 560 | template 561 | Type_ Align(Type_ value, size_t align) { 562 | value += align - 1; 563 | value /= align; 564 | value *= align; 565 | return value; 566 | } 567 | 568 | static const uint8_t PageShift_(0x0c); 569 | static const uint32_t PageSize_(1 << PageShift_); 570 | 571 | static inline unsigned bytes(uint64_t value) { 572 | return (64 - __builtin_clzll(value) + 7) / 8; 573 | } 574 | 575 | static void put(std::streambuf &stream, uint64_t value, size_t length) { 576 | length *= 8; 577 | do put(stream, uint8_t(value >> (length -= 8))); 578 | while (length != 0); 579 | } 580 | 581 | static void der(std::streambuf &stream, uint64_t value) { 582 | if (value < 128) 583 | put(stream, value); 584 | else { 585 | unsigned length(bytes(value)); 586 | put(stream, 0x80 | length); 587 | put(stream, value, length); 588 | } 589 | } 590 | 591 | static std::string der(uint8_t tag, const char *value, size_t length) { 592 | std::stringbuf data; 593 | put(data, tag); 594 | der(data, length); 595 | put(data, value, length); 596 | return data.str(); 597 | } 598 | 599 | static std::string der(uint8_t tag, const char *value) { 600 | return der(tag, value, strlen(value)); } 601 | static std::string der(uint8_t tag, const std::string &value) { 602 | return der(tag, value.data(), value.size()); } 603 | 604 | template 605 | static void der_(std::stringbuf &data, const Type_ &values) { 606 | size_t size(0); 607 | for (const auto &value : values) 608 | size += value.size(); 609 | der(data, size); 610 | for (const auto &value : values) 611 | put(data, value); 612 | } 613 | 614 | static std::string der(const std::vector &values) { 615 | std::stringbuf data; 616 | put(data, 0x30); 617 | der_(data, values); 618 | return data.str(); 619 | } 620 | 621 | static std::string der(const std::multiset &values) { 622 | std::stringbuf data; 623 | put(data, 0x31); 624 | der_(data, values); 625 | return data.str(); 626 | } 627 | 628 | static std::string der(const std::pair &value) { 629 | const auto key(der(0x0c, value.first)); 630 | std::stringbuf data; 631 | put(data, 0x30); 632 | der(data, key.size() + value.second.size()); 633 | put(data, key); 634 | put(data, value.second); 635 | return data.str(); 636 | } 637 | 638 | #ifndef LDID_NOPLIST 639 | static std::string der(plist_t data) { 640 | switch (const auto type = plist_get_node_type(data)) { 641 | case PLIST_BOOLEAN: { 642 | uint8_t value(0); 643 | plist_get_bool_val(data, &value); 644 | 645 | std::stringbuf data; 646 | put(data, 0x01); 647 | der(data, 1); 648 | put(data, value != 0 ? 1 : 0); 649 | return data.str(); 650 | } break; 651 | 652 | case PLIST_UINT: { 653 | uint64_t value; 654 | plist_get_uint_val(data, &value); 655 | const auto length(bytes(value)); 656 | 657 | std::stringbuf data; 658 | put(data, 0x02); 659 | der(data, length); 660 | put(data, value, length); 661 | return data.str(); 662 | } break; 663 | 664 | case PLIST_REAL: { 665 | _assert(false); 666 | } break; 667 | 668 | case PLIST_DATE: { 669 | _assert(false); 670 | } break; 671 | 672 | case PLIST_DATA: { 673 | char *value; 674 | uint64_t length; 675 | plist_get_data_val(data, &value, &length); 676 | _scope({ free(value); }); 677 | return der(0x04, value, length); 678 | } break; 679 | 680 | case PLIST_STRING: { 681 | char *value; 682 | plist_get_string_val(data, &value); 683 | _scope({ free(value); }); 684 | return der(0x0c, value); 685 | } break; 686 | 687 | case PLIST_ARRAY: { 688 | std::vector values; 689 | for (auto e(plist_array_get_size(data)), i(decltype(e)(0)); i != e; ++i) 690 | values.push_back(der(plist_array_get_item(data, i))); 691 | return der(values); 692 | } break; 693 | 694 | case PLIST_DICT: { 695 | std::multiset values; 696 | 697 | plist_dict_iter iterator(NULL); 698 | plist_dict_new_iter(data, &iterator); 699 | _scope({ free(iterator); }); 700 | 701 | for (;;) { 702 | char *key(NULL); 703 | plist_t value(NULL); 704 | plist_dict_next_item(data, iterator, &key, &value); 705 | if (key == NULL) 706 | break; 707 | _scope({ free(key); }); 708 | values.insert(der(std::make_pair(key, der(value)))); 709 | } 710 | 711 | return der(values); 712 | } break; 713 | 714 | default: { 715 | _assert_(false, "unsupported plist type %d", type); 716 | } break; 717 | } 718 | } 719 | #endif 720 | 721 | static inline uint16_t Swap_(uint16_t value) { 722 | return 723 | ((value >> 8) & 0x00ff) | 724 | ((value << 8) & 0xff00); 725 | } 726 | 727 | static inline uint32_t Swap_(uint32_t value) { 728 | value = ((value >> 8) & 0x00ff00ff) | 729 | ((value << 8) & 0xff00ff00); 730 | value = ((value >> 16) & 0x0000ffff) | 731 | ((value << 16) & 0xffff0000); 732 | return value; 733 | } 734 | 735 | static inline uint64_t Swap_(uint64_t value) { 736 | value = (value & 0x00000000ffffffff) << 32 | (value & 0xffffffff00000000) >> 32; 737 | value = (value & 0x0000ffff0000ffff) << 16 | (value & 0xffff0000ffff0000) >> 16; 738 | value = (value & 0x00ff00ff00ff00ff) << 8 | (value & 0xff00ff00ff00ff00) >> 8; 739 | return value; 740 | } 741 | 742 | static inline int16_t Swap_(int16_t value) { 743 | return Swap_(static_cast(value)); 744 | } 745 | 746 | static inline int32_t Swap_(int32_t value) { 747 | return Swap_(static_cast(value)); 748 | } 749 | 750 | static inline int64_t Swap_(int64_t value) { 751 | return Swap_(static_cast(value)); 752 | } 753 | 754 | static bool little_(true); 755 | 756 | static inline uint16_t Swap(uint16_t value) { 757 | return little_ ? Swap_(value) : value; 758 | } 759 | 760 | static inline uint32_t Swap(uint32_t value) { 761 | return little_ ? Swap_(value) : value; 762 | } 763 | 764 | static inline uint64_t Swap(uint64_t value) { 765 | return little_ ? Swap_(value) : value; 766 | } 767 | 768 | static inline int16_t Swap(int16_t value) { 769 | return Swap(static_cast(value)); 770 | } 771 | 772 | static inline int32_t Swap(int32_t value) { 773 | return Swap(static_cast(value)); 774 | } 775 | 776 | static inline int64_t Swap(int64_t value) { 777 | return Swap(static_cast(value)); 778 | } 779 | 780 | class Swapped { 781 | protected: 782 | bool swapped_; 783 | 784 | Swapped() : 785 | swapped_(false) 786 | { 787 | } 788 | 789 | public: 790 | Swapped(bool swapped) : 791 | swapped_(swapped) 792 | { 793 | } 794 | 795 | template 796 | Type_ Swap(Type_ value) const { 797 | return swapped_ ? Swap_(value) : value; 798 | } 799 | }; 800 | 801 | class Data : 802 | public Swapped 803 | { 804 | private: 805 | void *base_; 806 | size_t size_; 807 | 808 | public: 809 | Data(void *base, size_t size) : 810 | base_(base), 811 | size_(size) 812 | { 813 | } 814 | 815 | void *GetBase() const { 816 | return base_; 817 | } 818 | 819 | size_t GetSize() const { 820 | return size_; 821 | } 822 | }; 823 | 824 | class MachHeader : 825 | public Data 826 | { 827 | private: 828 | bool bits64_; 829 | 830 | struct mach_header *mach_header_; 831 | struct load_command *load_command_; 832 | 833 | public: 834 | MachHeader(void *base, size_t size) : 835 | Data(base, size) 836 | { 837 | mach_header_ = (mach_header *) base; 838 | 839 | switch (Swap(mach_header_->magic)) { 840 | case MH_CIGAM: 841 | swapped_ = !swapped_; 842 | case MH_MAGIC: 843 | bits64_ = false; 844 | break; 845 | 846 | case MH_CIGAM_64: 847 | swapped_ = !swapped_; 848 | case MH_MAGIC_64: 849 | bits64_ = true; 850 | break; 851 | 852 | default: 853 | _assert(false); 854 | } 855 | 856 | void *post = mach_header_ + 1; 857 | if (bits64_) 858 | post = (uint32_t *) post + 1; 859 | load_command_ = (struct load_command *) post; 860 | 861 | _assert( 862 | Swap(mach_header_->filetype) == MH_EXECUTE || 863 | Swap(mach_header_->filetype) == MH_DYLIB || 864 | Swap(mach_header_->filetype) == MH_DYLINKER || 865 | Swap(mach_header_->filetype) == MH_BUNDLE 866 | ); 867 | } 868 | 869 | bool Bits64() const { 870 | return bits64_; 871 | } 872 | 873 | struct mach_header *operator ->() const { 874 | return mach_header_; 875 | } 876 | 877 | operator struct mach_header *() const { 878 | return mach_header_; 879 | } 880 | 881 | uint32_t GetCPUType() const { 882 | return Swap(mach_header_->cputype); 883 | } 884 | 885 | uint32_t GetCPUSubtype() const { 886 | return Swap(mach_header_->cpusubtype) & 0xff; 887 | } 888 | 889 | struct load_command *GetLoadCommand() const { 890 | return load_command_; 891 | } 892 | 893 | std::vector GetLoadCommands() const { 894 | std::vector load_commands; 895 | 896 | struct load_command *load_command = load_command_; 897 | for (uint32_t cmd = 0; cmd != Swap(mach_header_->ncmds); ++cmd) { 898 | load_commands.push_back(load_command); 899 | load_command = (struct load_command *) ((uint8_t *) load_command + Swap(load_command->cmdsize)); 900 | } 901 | 902 | return load_commands; 903 | } 904 | 905 | void ForSection(const ldid::Functor &code) const { 906 | _foreach (load_command, GetLoadCommands()) 907 | switch (Swap(load_command->cmd)) { 908 | case LC_SEGMENT: { 909 | auto segment(reinterpret_cast(load_command)); 910 | code(segment->segname, NULL, GetOffset(segment->fileoff), segment->filesize); 911 | auto section(reinterpret_cast(segment + 1)); 912 | for (uint32_t i(0), e(Swap(segment->nsects)); i != e; ++i, ++section) 913 | code(segment->segname, section->sectname, GetOffset(segment->fileoff + section->offset), section->size); 914 | } break; 915 | 916 | case LC_SEGMENT_64: { 917 | auto segment(reinterpret_cast(load_command)); 918 | code(segment->segname, NULL, GetOffset(segment->fileoff), segment->filesize); 919 | auto section(reinterpret_cast(segment + 1)); 920 | for (uint32_t i(0), e(Swap(segment->nsects)); i != e; ++i, ++section) 921 | code(segment->segname, section->sectname, GetOffset(segment->fileoff + section->offset), section->size); 922 | } break; 923 | } 924 | } 925 | 926 | template 927 | Target_ *GetOffset(uint32_t offset) const { 928 | return reinterpret_cast(offset + (uint8_t *) mach_header_); 929 | } 930 | }; 931 | 932 | class FatMachHeader : 933 | public MachHeader 934 | { 935 | private: 936 | fat_arch *fat_arch_; 937 | 938 | public: 939 | FatMachHeader(void *base, size_t size, fat_arch *fat_arch) : 940 | MachHeader(base, size), 941 | fat_arch_(fat_arch) 942 | { 943 | } 944 | 945 | fat_arch *GetFatArch() const { 946 | return fat_arch_; 947 | } 948 | }; 949 | 950 | class FatHeader : 951 | public Data 952 | { 953 | private: 954 | fat_header *fat_header_; 955 | std::vector mach_headers_; 956 | 957 | public: 958 | FatHeader(void *base, size_t size) : 959 | Data(base, size) 960 | { 961 | fat_header_ = reinterpret_cast(base); 962 | 963 | if (Swap(fat_header_->magic) == FAT_CIGAM) { 964 | swapped_ = !swapped_; 965 | goto fat; 966 | } else if (Swap(fat_header_->magic) != FAT_MAGIC) { 967 | fat_header_ = NULL; 968 | mach_headers_.push_back(FatMachHeader(base, size, NULL)); 969 | } else fat: { 970 | size_t fat_narch = Swap(fat_header_->nfat_arch); 971 | fat_arch *fat_arch = reinterpret_cast(fat_header_ + 1); 972 | size_t arch; 973 | for (arch = 0; arch != fat_narch; ++arch) { 974 | uint32_t arch_offset = Swap(fat_arch->offset); 975 | uint32_t arch_size = Swap(fat_arch->size); 976 | mach_headers_.push_back(FatMachHeader((uint8_t *) base + arch_offset, arch_size, fat_arch)); 977 | ++fat_arch; 978 | } 979 | } 980 | } 981 | 982 | std::vector &GetMachHeaders() { 983 | return mach_headers_; 984 | } 985 | 986 | bool IsFat() const { 987 | return fat_header_ != NULL; 988 | } 989 | 990 | struct fat_header *operator ->() const { 991 | return fat_header_; 992 | } 993 | 994 | operator struct fat_header *() const { 995 | return fat_header_; 996 | } 997 | }; 998 | 999 | #define CSMAGIC_REQUIREMENT uint32_t(0xfade0c00) 1000 | #define CSMAGIC_REQUIREMENTS uint32_t(0xfade0c01) 1001 | #define CSMAGIC_CODEDIRECTORY uint32_t(0xfade0c02) 1002 | #define CSMAGIC_EMBEDDED_SIGNATURE uint32_t(0xfade0cc0) 1003 | #define CSMAGIC_EMBEDDED_SIGNATURE_OLD uint32_t(0xfade0b02) 1004 | #define CSMAGIC_EMBEDDED_ENTITLEMENTS uint32_t(0xfade7171) 1005 | #define CSMAGIC_EMBEDDED_DERFORMAT uint32_t(0xfade7172) // name? 1006 | #define CSMAGIC_DETACHED_SIGNATURE uint32_t(0xfade0cc1) 1007 | #define CSMAGIC_BLOBWRAPPER uint32_t(0xfade0b01) 1008 | 1009 | #define CSSLOT_CODEDIRECTORY uint32_t(0x00000) 1010 | #define CSSLOT_INFOSLOT uint32_t(0x00001) 1011 | #define CSSLOT_REQUIREMENTS uint32_t(0x00002) 1012 | #define CSSLOT_RESOURCEDIR uint32_t(0x00003) 1013 | #define CSSLOT_APPLICATION uint32_t(0x00004) 1014 | #define CSSLOT_ENTITLEMENTS uint32_t(0x00005) 1015 | #define CSSLOT_REPSPECIFIC uint32_t(0x00006) // name? 1016 | #define CSSLOT_DERFORMAT uint32_t(0x00007) // name? 1017 | #define CSSLOT_ALTERNATE uint32_t(0x01000) 1018 | 1019 | #define CSSLOT_SIGNATURESLOT uint32_t(0x10000) 1020 | 1021 | #define CS_HASHTYPE_SHA160_160 1 1022 | #define CS_HASHTYPE_SHA256_256 2 1023 | #define CS_HASHTYPE_SHA256_160 3 1024 | #define CS_HASHTYPE_SHA386_386 4 1025 | 1026 | #if 0 1027 | #define CS_EXECSEG_MAIN_BINARY 0x001 /* executable segment denotes main binary */ 1028 | #define CS_EXECSEG_ALLOW_UNSIGNED 0x010 /* allow unsigned pages (for debugging) */ 1029 | #define CS_EXECSEG_DEBUGGER 0x020 /* main binary is debugger */ 1030 | #define CS_EXECSEG_JIT 0x040 /* JIT enabled */ 1031 | #define CS_EXECSEG_SKIP_LV 0x080 /* skip library validation */ 1032 | #define CS_EXECSEG_CAN_LOAD_CDHASH 0x100 /* can bless cdhash for execution */ 1033 | #define CS_EXECSEG_CAN_EXEC_CDHASH 0x200 /* can execute blessed cdhash */ 1034 | #else 1035 | enum SecCodeExecSegFlags { 1036 | kSecCodeExecSegMainBinary = 0x001, 1037 | kSecCodeExecSegAllowUnsigned = 0x010, 1038 | kSecCodeExecSegDebugger = 0x020, 1039 | kSecCodeExecSegJit = 0x040, 1040 | kSecCodeExecSegSkipLibraryVal = 0x080, 1041 | kSecCodeExecSegCanLoadCdHash = 0x100, 1042 | kSecCodeExecSegCanExecCdHash = 0x100, 1043 | }; 1044 | #endif 1045 | 1046 | struct BlobIndex { 1047 | uint32_t type; 1048 | uint32_t offset; 1049 | } _packed; 1050 | 1051 | struct Blob { 1052 | uint32_t magic; 1053 | uint32_t length; 1054 | } _packed; 1055 | 1056 | struct SuperBlob { 1057 | struct Blob blob; 1058 | uint32_t count; 1059 | struct BlobIndex index[]; 1060 | } _packed; 1061 | 1062 | struct CodeDirectory { 1063 | uint32_t version; 1064 | uint32_t flags; 1065 | uint32_t hashOffset; 1066 | uint32_t identOffset; 1067 | uint32_t nSpecialSlots; 1068 | uint32_t nCodeSlots; 1069 | uint32_t codeLimit; 1070 | uint8_t hashSize; 1071 | uint8_t hashType; 1072 | uint8_t platform; 1073 | uint8_t pageSize; 1074 | uint32_t spare2; 1075 | uint32_t scatterOffset; 1076 | uint32_t teamIDOffset; 1077 | uint32_t spare3; 1078 | uint64_t codeLimit64; 1079 | uint64_t execSegBase; 1080 | uint64_t execSegLimit; 1081 | uint64_t execSegFlags; 1082 | #if 0 // version = 0x20500 1083 | uint32_t runtime; 1084 | uint32_t preEncryptOffset; 1085 | #endif 1086 | #if 0 // version = 0x20600 1087 | uint8_t linkageHashType; 1088 | uint8_t linkageTruncated; 1089 | uint16_t spare4; 1090 | uint32_t linkageOffset; 1091 | uint32_t linkageSize; 1092 | #endif 1093 | } _packed; 1094 | 1095 | enum CodeSignatureFlags { 1096 | kSecCodeSignatureHost = 0x0001, 1097 | kSecCodeSignatureAdhoc = 0x0002, 1098 | kSecCodeSignatureForceHard = 0x0100, 1099 | kSecCodeSignatureForceKill = 0x0200, 1100 | kSecCodeSignatureForceExpiration = 0x0400, 1101 | kSecCodeSignatureRestrict = 0x0800, 1102 | kSecCodeSignatureEnforcement = 0x1000, 1103 | kSecCodeSignatureLibraryValidation = 0x2000, 1104 | kSecCodeSignatureRuntime = 0x10000, 1105 | }; 1106 | 1107 | enum Kind : uint32_t { 1108 | exprForm = 1, // prefix expr form 1109 | }; 1110 | 1111 | enum ExprOp : uint32_t { 1112 | opFalse, // unconditionally false 1113 | opTrue, // unconditionally true 1114 | opIdent, // match canonical code [string] 1115 | opAppleAnchor, // signed by Apple as Apple's product 1116 | opAnchorHash, // match anchor [cert hash] 1117 | opInfoKeyValue, // *legacy* - use opInfoKeyField [key; value] 1118 | opAnd, // binary prefix expr AND expr [expr; expr] 1119 | opOr, // binary prefix expr OR expr [expr; expr] 1120 | opCDHash, // match hash of CodeDirectory directly [cd hash] 1121 | opNot, // logical inverse [expr] 1122 | opInfoKeyField, // Info.plist key field [string; match suffix] 1123 | opCertField, // Certificate field [cert index; field name; match suffix] 1124 | opTrustedCert, // require trust settings to approve one particular cert [cert index] 1125 | opTrustedCerts, // require trust settings to approve the cert chain 1126 | opCertGeneric, // Certificate component by OID [cert index; oid; match suffix] 1127 | opAppleGenericAnchor, // signed by Apple in any capacity 1128 | opEntitlementField, // entitlement dictionary field [string; match suffix] 1129 | opCertPolicy, // Certificate policy by OID [cert index; oid; match suffix] 1130 | opNamedAnchor, // named anchor type 1131 | opNamedCode, // named subroutine 1132 | opPlatform, // platform constraint [integer] 1133 | exprOpCount // (total opcode count in use) 1134 | }; 1135 | 1136 | enum MatchOperation { 1137 | matchExists, // anything but explicit "false" - no value stored 1138 | matchEqual, // equal (CFEqual) 1139 | matchContains, // partial match (substring) 1140 | matchBeginsWith, // partial match (initial substring) 1141 | matchEndsWith, // partial match (terminal substring) 1142 | matchLessThan, // less than (string with numeric comparison) 1143 | matchGreaterThan, // greater than (string with numeric comparison) 1144 | matchLessEqual, // less or equal (string with numeric comparison) 1145 | matchGreaterEqual, // greater or equal (string with numeric comparison) 1146 | }; 1147 | 1148 | #define OID_ISO_MEMBER 42 1149 | #define OID_US OID_ISO_MEMBER, 134, 72 1150 | #define APPLE_OID OID_US, 0x86, 0xf7, 0x63 1151 | #define APPLE_ADS_OID APPLE_OID, 0x64 1152 | #define APPLE_EXTENSION_OID APPLE_ADS_OID, 6 1153 | 1154 | #ifndef LDID_NOFLAGT 1155 | extern "C" uint32_t hash(uint8_t *k, uint32_t length, uint32_t initval); 1156 | #endif 1157 | 1158 | struct Algorithm { 1159 | size_t size_; 1160 | uint8_t type_; 1161 | int nid_; 1162 | 1163 | Algorithm(size_t size, uint8_t type, int nid) : 1164 | size_(size), 1165 | type_(type), 1166 | nid_(nid) 1167 | { 1168 | } 1169 | 1170 | virtual const uint8_t *operator [](const ldid::Hash &hash) const = 0; 1171 | 1172 | virtual void operator ()(uint8_t *hash, const void *data, size_t size) const = 0; 1173 | virtual void operator ()(ldid::Hash &hash, const void *data, size_t size) const = 0; 1174 | virtual void operator ()(std::vector &hash, const void *data, size_t size) const = 0; 1175 | 1176 | virtual const char *name() = 0; 1177 | }; 1178 | 1179 | struct AlgorithmSHA1 : 1180 | Algorithm 1181 | { 1182 | AlgorithmSHA1() : 1183 | Algorithm(LDID_SHA1_DIGEST_LENGTH, CS_HASHTYPE_SHA160_160, NID_sha1) 1184 | { 1185 | } 1186 | 1187 | virtual const uint8_t *operator [](const ldid::Hash &hash) const { 1188 | return hash.sha1_; 1189 | } 1190 | 1191 | void operator ()(uint8_t *hash, const void *data, size_t size) const { 1192 | LDID_SHA1(static_cast(data), size, hash); 1193 | } 1194 | 1195 | void operator ()(ldid::Hash &hash, const void *data, size_t size) const { 1196 | return operator()(hash.sha1_, data, size); 1197 | } 1198 | 1199 | void operator ()(std::vector &hash, const void *data, size_t size) const { 1200 | hash.resize(LDID_SHA1_DIGEST_LENGTH); 1201 | return operator ()(reinterpret_cast(hash.data()), data, size); 1202 | } 1203 | 1204 | virtual const char *name() { 1205 | return "sha1"; 1206 | } 1207 | }; 1208 | 1209 | struct AlgorithmSHA256 : 1210 | Algorithm 1211 | { 1212 | AlgorithmSHA256() : 1213 | Algorithm(LDID_SHA256_DIGEST_LENGTH, CS_HASHTYPE_SHA256_256, NID_sha256) 1214 | { 1215 | } 1216 | 1217 | virtual const uint8_t *operator [](const ldid::Hash &hash) const { 1218 | return hash.sha256_; 1219 | } 1220 | 1221 | void operator ()(uint8_t *hash, const void *data, size_t size) const { 1222 | LDID_SHA256(static_cast(data), size, hash); 1223 | } 1224 | 1225 | void operator ()(ldid::Hash &hash, const void *data, size_t size) const { 1226 | return operator()(hash.sha256_, data, size); 1227 | } 1228 | 1229 | void operator ()(std::vector &hash, const void *data, size_t size) const { 1230 | hash.resize(LDID_SHA256_DIGEST_LENGTH); 1231 | return operator ()(reinterpret_cast(hash.data()), data, size); 1232 | } 1233 | 1234 | virtual const char *name() { 1235 | return "sha256"; 1236 | } 1237 | }; 1238 | 1239 | static bool do_sha1(true); 1240 | static bool do_sha256(true); 1241 | 1242 | static const std::vector &GetAlgorithms() { 1243 | static AlgorithmSHA1 sha1; 1244 | static AlgorithmSHA256 sha256; 1245 | 1246 | static std::vector algorithms; 1247 | if (algorithms.empty()) { 1248 | if (do_sha1) 1249 | algorithms.push_back(&sha1); 1250 | if (do_sha256) 1251 | algorithms.push_back(&sha256); 1252 | } 1253 | 1254 | return algorithms; 1255 | } 1256 | 1257 | struct Baton { 1258 | std::string entitlements_; 1259 | std::string derformat_; 1260 | }; 1261 | 1262 | struct CodesignAllocation { 1263 | FatMachHeader mach_header_; 1264 | uint64_t offset_; 1265 | uint32_t size_; 1266 | uint64_t limit_; 1267 | uint32_t alloc_; 1268 | uint32_t align_; 1269 | const char *arch_; 1270 | Baton baton_; 1271 | 1272 | 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) : 1273 | mach_header_(mach_header), 1274 | offset_(offset), 1275 | size_(size), 1276 | limit_(limit), 1277 | alloc_(alloc), 1278 | align_(align), 1279 | arch_(arch), 1280 | baton_(baton) 1281 | { 1282 | } 1283 | }; 1284 | 1285 | #ifndef LDID_NOTOOLS 1286 | class File { 1287 | private: 1288 | int file_; 1289 | 1290 | public: 1291 | File() : 1292 | file_(-1) 1293 | { 1294 | } 1295 | 1296 | ~File() { 1297 | if (file_ != -1) 1298 | _syscall(close(file_)); 1299 | } 1300 | 1301 | void open(const char *path, int flags) { 1302 | _assert(file_ == -1); 1303 | file_ = _syscall(::open(path, flags)); 1304 | } 1305 | 1306 | int file() const { 1307 | return file_; 1308 | } 1309 | }; 1310 | 1311 | class Map { 1312 | private: 1313 | File file_; 1314 | void *data_; 1315 | size_t size_; 1316 | 1317 | void clear() { 1318 | if (data_ == NULL) 1319 | return; 1320 | _syscall(munmap(data_, size_)); 1321 | data_ = NULL; 1322 | size_ = 0; 1323 | } 1324 | 1325 | public: 1326 | Map() : 1327 | data_(NULL), 1328 | size_(0) 1329 | { 1330 | } 1331 | 1332 | Map(const std::string &path, int oflag, int pflag, int mflag) : 1333 | Map() 1334 | { 1335 | open(path, oflag, pflag, mflag); 1336 | } 1337 | 1338 | Map(const std::string &path, bool edit) : 1339 | Map() 1340 | { 1341 | open(path, edit); 1342 | } 1343 | 1344 | ~Map() { 1345 | clear(); 1346 | } 1347 | 1348 | bool empty() const { 1349 | return data_ == NULL; 1350 | } 1351 | 1352 | void open(const std::string &path, int oflag, int pflag, int mflag) { 1353 | clear(); 1354 | 1355 | file_.open(path.c_str(), oflag); 1356 | int file(file_.file()); 1357 | 1358 | struct stat stat; 1359 | _syscall(fstat(file, &stat)); 1360 | size_ = stat.st_size; 1361 | 1362 | data_ = _syscall(mmap(NULL, size_, pflag, mflag, file, 0)); 1363 | } 1364 | 1365 | void open(const std::string &path, bool edit) { 1366 | if (edit) 1367 | open(path, O_RDWR, PROT_READ | PROT_WRITE, MAP_SHARED); 1368 | else 1369 | open(path, O_RDONLY, PROT_READ, MAP_PRIVATE); 1370 | } 1371 | 1372 | void *data() const { 1373 | return data_; 1374 | } 1375 | 1376 | size_t size() const { 1377 | return size_; 1378 | } 1379 | 1380 | operator std::string() const { 1381 | return std::string(static_cast(data_), size_); 1382 | } 1383 | }; 1384 | #endif 1385 | 1386 | namespace ldid { 1387 | 1388 | #ifndef LDID_NOPLIST 1389 | static plist_t plist(const std::string &data); 1390 | #endif 1391 | 1392 | void Analyze(const MachHeader &mach_header, const Functor &entitle) { 1393 | _foreach (load_command, mach_header.GetLoadCommands()) 1394 | if (mach_header.Swap(load_command->cmd) == LC_CODE_SIGNATURE) { 1395 | auto signature(reinterpret_cast(load_command)); 1396 | auto offset(mach_header.Swap(signature->dataoff)); 1397 | auto pointer(reinterpret_cast(mach_header.GetBase()) + offset); 1398 | auto super(reinterpret_cast(pointer)); 1399 | 1400 | for (size_t index(0); index != Swap(super->count); ++index) 1401 | if (Swap(super->index[index].type) == CSSLOT_ENTITLEMENTS) { 1402 | auto begin(Swap(super->index[index].offset)); 1403 | auto blob(reinterpret_cast(pointer + begin)); 1404 | auto writ(Swap(blob->length) - sizeof(*blob)); 1405 | entitle(reinterpret_cast(blob + 1), writ); 1406 | } 1407 | } 1408 | } 1409 | 1410 | std::string Analyze(const void *data, size_t size) { 1411 | std::string entitlements; 1412 | 1413 | FatHeader fat_header(const_cast(data), size); 1414 | _foreach (mach_header, fat_header.GetMachHeaders()) 1415 | Analyze(mach_header, fun([&](const char *data, size_t size) { 1416 | if (entitlements.empty()) 1417 | entitlements.assign(data, size); 1418 | else 1419 | _assert(entitlements.compare(0, entitlements.size(), data, size) == 0); 1420 | })); 1421 | 1422 | return entitlements; 1423 | } 1424 | 1425 | static void Allocate(const void *idata, size_t isize, std::streambuf &output, const Functor &allocate, const Functor &save, const Progress &progress) { 1426 | FatHeader source(const_cast(idata), isize); 1427 | 1428 | size_t offset(0); 1429 | if (source.IsFat()) 1430 | offset += sizeof(fat_header) + sizeof(fat_arch) * source.Swap(source->nfat_arch); 1431 | 1432 | std::vector allocations; 1433 | _foreach (mach_header, source.GetMachHeaders()) { 1434 | struct linkedit_data_command *signature(NULL); 1435 | struct symtab_command *symtab(NULL); 1436 | 1437 | _foreach (load_command, mach_header.GetLoadCommands()) { 1438 | uint32_t cmd(mach_header.Swap(load_command->cmd)); 1439 | if (false); 1440 | else if (cmd == LC_CODE_SIGNATURE) 1441 | signature = reinterpret_cast(load_command); 1442 | else if (cmd == LC_SYMTAB) 1443 | symtab = reinterpret_cast(load_command); 1444 | } 1445 | 1446 | size_t size; 1447 | if (signature == NULL) 1448 | size = mach_header.GetSize(); 1449 | else { 1450 | size = mach_header.Swap(signature->dataoff); 1451 | _assert(size <= mach_header.GetSize()); 1452 | } 1453 | 1454 | if (symtab != NULL) { 1455 | auto end(mach_header.Swap(symtab->stroff) + mach_header.Swap(symtab->strsize)); 1456 | if (symtab->stroff != 0 || symtab->strsize != 0) { 1457 | _assert(end <= size); 1458 | _assert(end >= size - 0x10); 1459 | size = end; 1460 | } 1461 | } 1462 | 1463 | Baton baton; 1464 | size_t alloc(allocate(mach_header, baton, size)); 1465 | 1466 | auto *fat_arch(mach_header.GetFatArch()); 1467 | uint32_t align; 1468 | 1469 | if (fat_arch != NULL) 1470 | align = source.Swap(fat_arch->align); 1471 | else switch (mach_header.GetCPUType()) { 1472 | case CPU_TYPE_POWERPC: 1473 | case CPU_TYPE_POWERPC64: 1474 | case CPU_TYPE_X86: 1475 | case CPU_TYPE_X86_64: 1476 | align = 0xc; 1477 | break; 1478 | case CPU_TYPE_ARM: 1479 | case CPU_TYPE_ARM64: 1480 | align = 0xe; 1481 | break; 1482 | default: 1483 | align = 0x0; 1484 | break; 1485 | } 1486 | 1487 | const char *arch(NULL); 1488 | switch (mach_header.GetCPUType()) { 1489 | case CPU_TYPE_POWERPC: 1490 | arch = "ppc"; 1491 | break; 1492 | case CPU_TYPE_POWERPC64: 1493 | arch = "ppc64"; 1494 | break; 1495 | case CPU_TYPE_X86: 1496 | arch = "i386"; 1497 | break; 1498 | case CPU_TYPE_X86_64: 1499 | arch = "x86_64"; 1500 | break; 1501 | case CPU_TYPE_ARM: 1502 | arch = "arm"; 1503 | break; 1504 | case CPU_TYPE_ARM64: 1505 | arch = "arm64"; 1506 | break; 1507 | } 1508 | 1509 | offset = Align(offset, 1 << align); 1510 | 1511 | uint32_t limit(size); 1512 | if (alloc != 0) 1513 | limit = Align(limit, 0x10); 1514 | 1515 | allocations.push_back(CodesignAllocation(mach_header, offset, size, limit, alloc, align, arch, baton)); 1516 | offset += size + alloc; 1517 | offset = Align(offset, 0x10); 1518 | } 1519 | 1520 | size_t position(0); 1521 | 1522 | if (source.IsFat()) { 1523 | fat_header fat_header; 1524 | fat_header.magic = Swap(FAT_MAGIC); 1525 | fat_header.nfat_arch = Swap(uint32_t(allocations.size())); 1526 | put(output, &fat_header, sizeof(fat_header)); 1527 | position += sizeof(fat_header); 1528 | 1529 | // XXX: support fat_arch_64 (not in my toolchain) 1530 | // probably use C++14 generic lambda (not in my toolchain) 1531 | 1532 | _assert_(![&]() { 1533 | _foreach (allocation, allocations) { 1534 | const auto offset(allocation.offset_); 1535 | const auto size(allocation.limit_ + allocation.alloc_); 1536 | if (uint32_t(offset) != offset || uint32_t(size) != size) 1537 | return true; 1538 | } 1539 | return false; 1540 | }(), "FAT slice >=4GiB not currently supported"); 1541 | 1542 | _foreach (allocation, allocations) { 1543 | auto &mach_header(allocation.mach_header_); 1544 | 1545 | fat_arch fat_arch; 1546 | fat_arch.cputype = Swap(mach_header->cputype); 1547 | fat_arch.cpusubtype = Swap(mach_header->cpusubtype); 1548 | fat_arch.offset = Swap(uint32_t(allocation.offset_)); 1549 | fat_arch.size = Swap(uint32_t(allocation.limit_ + allocation.alloc_)); 1550 | fat_arch.align = Swap(allocation.align_); 1551 | put(output, &fat_arch, sizeof(fat_arch)); 1552 | position += sizeof(fat_arch); 1553 | } 1554 | } 1555 | 1556 | _foreach (allocation, allocations) { 1557 | progress(allocation.arch_); 1558 | auto &mach_header(allocation.mach_header_); 1559 | 1560 | pad(output, allocation.offset_ - position); 1561 | position = allocation.offset_; 1562 | 1563 | size_t left(-1); 1564 | size_t right(0); 1565 | 1566 | std::vector commands; 1567 | 1568 | _foreach (load_command, mach_header.GetLoadCommands()) { 1569 | std::string copy(reinterpret_cast(load_command), load_command->cmdsize); 1570 | 1571 | switch (mach_header.Swap(load_command->cmd)) { 1572 | case LC_CODE_SIGNATURE: 1573 | continue; 1574 | break; 1575 | 1576 | // XXX: this is getting ridiculous: provide a better abstraction 1577 | 1578 | case LC_SEGMENT: { 1579 | auto segment_command(reinterpret_cast(©[0])); 1580 | 1581 | if ((segment_command->initprot & 04) != 0) { 1582 | auto begin(mach_header.Swap(segment_command->fileoff)); 1583 | auto end(begin + mach_header.Swap(segment_command->filesize)); 1584 | if (left > begin) 1585 | left = begin; 1586 | if (right < end) 1587 | right = end; 1588 | } 1589 | 1590 | if (strncmp(segment_command->segname, "__LINKEDIT", 16) == 0) { 1591 | size_t size(mach_header.Swap(allocation.limit_ + allocation.alloc_ - mach_header.Swap(segment_command->fileoff))); 1592 | segment_command->filesize = size; 1593 | segment_command->vmsize = Align(size, 1 << allocation.align_); 1594 | } 1595 | } break; 1596 | 1597 | case LC_SEGMENT_64: { 1598 | auto segment_command(reinterpret_cast(©[0])); 1599 | 1600 | if ((segment_command->initprot & 04) != 0) { 1601 | auto begin(mach_header.Swap(segment_command->fileoff)); 1602 | auto end(begin + mach_header.Swap(segment_command->filesize)); 1603 | if (left > begin) 1604 | left = begin; 1605 | if (right < end) 1606 | right = end; 1607 | } 1608 | 1609 | if (strncmp(segment_command->segname, "__LINKEDIT", 16) == 0) { 1610 | size_t size(mach_header.Swap(allocation.limit_ + allocation.alloc_ - mach_header.Swap(segment_command->fileoff))); 1611 | segment_command->filesize = size; 1612 | segment_command->vmsize = Align(size, 1 << allocation.align_); 1613 | } 1614 | } break; 1615 | } 1616 | 1617 | commands.push_back(copy); 1618 | } 1619 | 1620 | if (allocation.alloc_ != 0) { 1621 | linkedit_data_command signature; 1622 | signature.cmd = mach_header.Swap(LC_CODE_SIGNATURE); 1623 | signature.cmdsize = mach_header.Swap(uint32_t(sizeof(signature))); 1624 | signature.dataoff = mach_header.Swap(allocation.limit_); 1625 | signature.datasize = mach_header.Swap(allocation.alloc_); 1626 | commands.push_back(std::string(reinterpret_cast(&signature), sizeof(signature))); 1627 | } 1628 | 1629 | size_t begin(position); 1630 | 1631 | uint32_t after(0); 1632 | _foreach(command, commands) 1633 | after += command.size(); 1634 | 1635 | std::stringbuf altern; 1636 | 1637 | struct mach_header header(*mach_header); 1638 | header.ncmds = mach_header.Swap(uint32_t(commands.size())); 1639 | header.sizeofcmds = mach_header.Swap(after); 1640 | put(output, &header, sizeof(header)); 1641 | put(altern, &header, sizeof(header)); 1642 | position += sizeof(header); 1643 | 1644 | if (mach_header.Bits64()) { 1645 | auto pad(mach_header.Swap(uint32_t(0))); 1646 | put(output, &pad, sizeof(pad)); 1647 | put(altern, &pad, sizeof(pad)); 1648 | position += sizeof(pad); 1649 | } 1650 | 1651 | _foreach(command, commands) { 1652 | put(output, command.data(), command.size()); 1653 | put(altern, command.data(), command.size()); 1654 | position += command.size(); 1655 | } 1656 | 1657 | uint32_t before(mach_header.Swap(mach_header->sizeofcmds)); 1658 | if (before > after) { 1659 | pad(output, before - after); 1660 | pad(altern, before - after); 1661 | position += before - after; 1662 | } 1663 | 1664 | auto top(reinterpret_cast(mach_header.GetBase())); 1665 | 1666 | std::string overlap(altern.str()); 1667 | overlap.append(top + overlap.size(), Align(overlap.size(), 0x1000) - overlap.size()); 1668 | 1669 | put(output, top + (position - begin), allocation.size_ - (position - begin), progress); 1670 | position = begin + allocation.size_; 1671 | 1672 | pad(output, allocation.limit_ - allocation.size_); 1673 | position += allocation.limit_ - allocation.size_; 1674 | 1675 | size_t saved(save(mach_header, allocation.baton_, output, allocation.limit_, left, right, overlap, top, progress)); 1676 | if (allocation.alloc_ > saved) 1677 | pad(output, allocation.alloc_ - saved); 1678 | else 1679 | _assert(allocation.alloc_ == saved); 1680 | position += allocation.alloc_; 1681 | } 1682 | } 1683 | 1684 | } 1685 | 1686 | typedef std::map Blobs; 1687 | 1688 | static void insert(Blobs &blobs, uint32_t slot, const std::stringbuf &buffer) { 1689 | auto value(buffer.str()); 1690 | std::swap(blobs[slot], value); 1691 | } 1692 | 1693 | static const std::string &insert(Blobs &blobs, uint32_t slot, uint32_t magic, const std::stringbuf &buffer) { 1694 | auto value(buffer.str()); 1695 | Blob blob; 1696 | blob.magic = Swap(magic); 1697 | blob.length = Swap(uint32_t(sizeof(blob) + value.size())); 1698 | value.insert(0, reinterpret_cast(&blob), sizeof(blob)); 1699 | auto &save(blobs[slot]); 1700 | std::swap(save, value); 1701 | return save; 1702 | } 1703 | 1704 | static size_t put(std::streambuf &output, uint32_t magic, const Blobs &blobs) { 1705 | size_t total(0); 1706 | _foreach (blob, blobs) 1707 | total += blob.second.size(); 1708 | 1709 | struct SuperBlob super; 1710 | super.blob.magic = Swap(magic); 1711 | super.blob.length = Swap(uint32_t(sizeof(SuperBlob) + blobs.size() * sizeof(BlobIndex) + total)); 1712 | super.count = Swap(uint32_t(blobs.size())); 1713 | put(output, &super, sizeof(super)); 1714 | 1715 | size_t offset(sizeof(SuperBlob) + sizeof(BlobIndex) * blobs.size()); 1716 | 1717 | _foreach (blob, blobs) { 1718 | BlobIndex index; 1719 | index.type = Swap(blob.first); 1720 | index.offset = Swap(uint32_t(offset)); 1721 | put(output, &index, sizeof(index)); 1722 | offset += blob.second.size(); 1723 | } 1724 | 1725 | _foreach (blob, blobs) 1726 | put(output, blob.second.data(), blob.second.size()); 1727 | 1728 | return offset; 1729 | } 1730 | 1731 | #ifndef LDID_NOSMIME 1732 | class Buffer { 1733 | private: 1734 | BIO *bio_; 1735 | 1736 | public: 1737 | Buffer(BIO *bio) : 1738 | bio_(bio) 1739 | { 1740 | _assert(bio_ != NULL); 1741 | } 1742 | 1743 | Buffer() : 1744 | bio_(BIO_new(BIO_s_mem())) 1745 | { 1746 | } 1747 | 1748 | Buffer(const char *data, size_t size) : 1749 | Buffer(BIO_new_mem_buf(const_cast(data), size)) 1750 | { 1751 | } 1752 | 1753 | Buffer(const std::string &data) : 1754 | Buffer(data.data(), data.size()) 1755 | { 1756 | } 1757 | 1758 | Buffer(PKCS7 *pkcs) : 1759 | Buffer() 1760 | { 1761 | _assert(i2d_PKCS7_bio(bio_, pkcs) != 0); 1762 | } 1763 | 1764 | ~Buffer() { 1765 | BIO_free_all(bio_); 1766 | } 1767 | 1768 | operator BIO *() const { 1769 | return bio_; 1770 | } 1771 | 1772 | explicit operator std::string() const { 1773 | char *data; 1774 | auto size(BIO_get_mem_data(bio_, &data)); 1775 | return std::string(data, size); 1776 | } 1777 | }; 1778 | 1779 | class Stuff { 1780 | private: 1781 | PKCS12 *value_; 1782 | EVP_PKEY *key_; 1783 | X509 *cert_; 1784 | STACK_OF(X509) *ca_; 1785 | 1786 | public: 1787 | Stuff(BIO *bio) : 1788 | value_(d2i_PKCS12_bio(bio, NULL)), 1789 | ca_(NULL) 1790 | { 1791 | _assert(value_ != NULL); 1792 | _assert(PKCS12_parse(value_, "", &key_, &cert_, &ca_) != 0); 1793 | 1794 | _assert(key_ != NULL); 1795 | _assert(cert_ != NULL); 1796 | 1797 | if (ca_ == NULL) 1798 | ca_ = sk_X509_new_null(); 1799 | _assert(ca_ != NULL); 1800 | } 1801 | 1802 | Stuff(const std::string &data) : 1803 | Stuff(Buffer(data)) 1804 | { 1805 | } 1806 | 1807 | ~Stuff() { 1808 | sk_X509_pop_free(ca_, X509_free); 1809 | X509_free(cert_); 1810 | EVP_PKEY_free(key_); 1811 | PKCS12_free(value_); 1812 | } 1813 | 1814 | operator PKCS12 *() const { 1815 | return value_; 1816 | } 1817 | 1818 | operator EVP_PKEY *() const { 1819 | return key_; 1820 | } 1821 | 1822 | operator X509 *() const { 1823 | return cert_; 1824 | } 1825 | 1826 | operator STACK_OF(X509) *() const { 1827 | return ca_; 1828 | } 1829 | }; 1830 | 1831 | class Octet { 1832 | private: 1833 | ASN1_OCTET_STRING *value_; 1834 | 1835 | public: 1836 | Octet() : 1837 | value_(ASN1_OCTET_STRING_new()) 1838 | { 1839 | _assert(value_ != NULL); 1840 | } 1841 | 1842 | Octet(const std::string &value) : 1843 | Octet() 1844 | { 1845 | _assert(ASN1_STRING_set(value_, value.data(), value.size())); 1846 | } 1847 | 1848 | Octet(const uint8_t *data, size_t size) : 1849 | Octet() 1850 | { 1851 | _assert(ASN1_STRING_set(value_, data, size)); 1852 | } 1853 | 1854 | Octet(const Octet &value) = delete; 1855 | 1856 | ~Octet() { 1857 | if (value_ != NULL) 1858 | ASN1_OCTET_STRING_free(value_); 1859 | } 1860 | 1861 | void release() { 1862 | value_ = NULL; 1863 | } 1864 | 1865 | operator ASN1_OCTET_STRING *() const { 1866 | return value_; 1867 | } 1868 | }; 1869 | 1870 | typedef struct { 1871 | ASN1_OBJECT *algorithm; 1872 | ASN1_OCTET_STRING *value; 1873 | } APPLE_CDHASH; 1874 | 1875 | DECLARE_ASN1_FUNCTIONS(APPLE_CDHASH) 1876 | 1877 | ASN1_NDEF_SEQUENCE(APPLE_CDHASH) = { 1878 | ASN1_SIMPLE(APPLE_CDHASH, algorithm, ASN1_OBJECT), 1879 | ASN1_SIMPLE(APPLE_CDHASH, value, ASN1_OCTET_STRING), 1880 | } ASN1_NDEF_SEQUENCE_END(APPLE_CDHASH) 1881 | 1882 | IMPLEMENT_ASN1_FUNCTIONS(APPLE_CDHASH) 1883 | 1884 | typedef struct { 1885 | ASN1_OBJECT *object; 1886 | STACK_OF(APPLE_CDHASH) *cdhashes; 1887 | } APPLE_CDATTR; 1888 | 1889 | DECLARE_ASN1_FUNCTIONS(APPLE_CDATTR) 1890 | 1891 | ASN1_NDEF_SEQUENCE(APPLE_CDATTR) = { 1892 | ASN1_SIMPLE(APPLE_CDATTR, object, ASN1_OBJECT), 1893 | ASN1_SET_OF(APPLE_CDATTR, cdhashes, APPLE_CDHASH), 1894 | } ASN1_NDEF_SEQUENCE_END(APPLE_CDATTR) 1895 | 1896 | IMPLEMENT_ASN1_FUNCTIONS(APPLE_CDATTR) 1897 | 1898 | class Signature { 1899 | private: 1900 | PKCS7 *value_; 1901 | 1902 | public: 1903 | Signature(const Stuff &stuff, const Buffer &data, const std::string &xml, const ldid::Hash &hash) { 1904 | value_ = PKCS7_new(); 1905 | _assert(value_ != NULL); 1906 | 1907 | _assert(PKCS7_set_type(value_, NID_pkcs7_signed)); 1908 | _assert(PKCS7_content_new(value_, NID_pkcs7_data)); 1909 | 1910 | STACK_OF(X509) *certs(stuff); 1911 | for (unsigned i(0), e(sk_X509_num(certs)); i != e; i++) 1912 | _assert(PKCS7_add_certificate(value_, sk_X509_value(certs, e - i - 1))); 1913 | 1914 | STACK_OF(X509_ATTRIBUTE) *attributes(sk_X509_ATTRIBUTE_new_null()); 1915 | _assert(attributes != NULL); 1916 | _scope({ sk_X509_ATTRIBUTE_pop_free(attributes, X509_ATTRIBUTE_free); }); 1917 | 1918 | 1919 | // XXX: this is the same as PKCS7_sign_add_signer(value_, stuff, stuff, NULL, PKCS7_NOSMIMECAP) 1920 | _assert(X509_check_private_key(stuff, stuff)); 1921 | auto info(PKCS7_add_signature(value_, stuff, stuff, EVP_sha1())); 1922 | _assert(info != NULL); 1923 | _assert(PKCS7_add_certificate(value_, stuff)); 1924 | 1925 | { 1926 | auto attribute(X509_ATTRIBUTE_create(NID_pkcs9_contentType, V_ASN1_OBJECT, OBJ_nid2obj(NID_pkcs7_data))); 1927 | _assert(attribute != NULL); 1928 | _assert(sk_X509_ATTRIBUTE_push(attributes, attribute) != 0); 1929 | } 1930 | 1931 | { 1932 | auto cdattr(APPLE_CDATTR_new()); 1933 | _assert(cdattr != NULL); 1934 | _scope({ APPLE_CDATTR_free(cdattr); }); 1935 | 1936 | static auto nid(OBJ_create("1.2.840.113635.100.9.2", "apple-2", "Apple 2")); 1937 | cdattr->object = OBJ_nid2obj(nid); 1938 | 1939 | for (Algorithm *pointer : GetAlgorithms()) { 1940 | Algorithm &algorithm(*pointer); 1941 | APPLE_CDHASH *cdhash(APPLE_CDHASH_new()); 1942 | _assert(cdhash != NULL); 1943 | _assert(sk_push((_STACK *) cdattr->cdhashes, cdhash) != 0); 1944 | cdhash->algorithm = OBJ_nid2obj(algorithm.nid_); 1945 | Octet string(algorithm[hash], algorithm.size_); 1946 | cdhash->value = string; 1947 | string.release(); 1948 | } 1949 | 1950 | // in e20b57270dece66ce2c68aeb5d14dd6d9f3c5d68 OpenSSL removed a "hack" 1951 | // in the process, they introduced a useful bug in X509_ATTRIBUTE_set1_data 1952 | // however, I don't want to rely on that or detect the bypass before it 1953 | // so, instead, I create my own compatible attribute and re-serialize it :/ 1954 | 1955 | ASN1_STRING *seq(ASN1_STRING_new()); 1956 | _assert(seq != NULL); 1957 | _scope({ ASN1_STRING_free(seq); }); 1958 | seq->length = ASN1_item_i2d((ASN1_VALUE *) cdattr, &seq->data, ASN1_ITEM_rptr(APPLE_CDATTR)); 1959 | 1960 | X509_ATTRIBUTE *attribute(NULL); 1961 | const unsigned char *data(seq->data); 1962 | _assert(d2i_X509_ATTRIBUTE(&attribute, &data, seq->length) != 0); 1963 | _assert(attribute != NULL); 1964 | _assert(sk_X509_ATTRIBUTE_push(attributes, attribute) != 0); 1965 | } 1966 | 1967 | { 1968 | // XXX: move the "cdhashes" plist code to here and remove xml argument 1969 | 1970 | Octet string(xml); 1971 | static auto nid(OBJ_create("1.2.840.113635.100.9.1", "apple-1", "Apple 1")); 1972 | auto attribute(X509_ATTRIBUTE_create(nid, V_ASN1_OCTET_STRING, string)); 1973 | _assert(attribute != NULL); 1974 | string.release(); 1975 | _assert(sk_X509_ATTRIBUTE_push(attributes, attribute) != 0); 1976 | } 1977 | 1978 | _assert(PKCS7_set_signed_attributes(info, attributes) != 0); 1979 | PKCS7_set_detached(value_, 1); 1980 | 1981 | // XXX: this is the same as PKCS7_final(value_, data, PKCS7_BINARY) 1982 | BIO *bio(PKCS7_dataInit(value_, NULL)); 1983 | _assert(bio != NULL); 1984 | _scope({ BIO_free_all(bio); }); 1985 | SMIME_crlf_copy(data, bio, PKCS7_BINARY); 1986 | BIO_flush(bio); 1987 | _assert(PKCS7_dataFinal(value_, bio)); 1988 | } 1989 | 1990 | ~Signature() { 1991 | PKCS7_free(value_); 1992 | } 1993 | 1994 | operator PKCS7 *() const { 1995 | return value_; 1996 | } 1997 | }; 1998 | #endif 1999 | 2000 | class NullBuffer : 2001 | public std::streambuf 2002 | { 2003 | public: 2004 | virtual std::streamsize xsputn(const char_type *data, std::streamsize size) { 2005 | return size; 2006 | } 2007 | 2008 | virtual int_type overflow(int_type next) { 2009 | return next; 2010 | } 2011 | }; 2012 | 2013 | class HashBuffer : 2014 | public std::streambuf 2015 | { 2016 | private: 2017 | ldid::Hash &hash_; 2018 | 2019 | LDID_SHA1_CTX sha1_; 2020 | LDID_SHA256_CTX sha256_; 2021 | 2022 | public: 2023 | HashBuffer(ldid::Hash &hash) : 2024 | hash_(hash) 2025 | { 2026 | LDID_SHA1_Init(&sha1_); 2027 | LDID_SHA256_Init(&sha256_); 2028 | } 2029 | 2030 | ~HashBuffer() { 2031 | LDID_SHA1_Final(reinterpret_cast(hash_.sha1_), &sha1_); 2032 | LDID_SHA256_Final(reinterpret_cast(hash_.sha256_), &sha256_); 2033 | } 2034 | 2035 | virtual std::streamsize xsputn(const char_type *data, std::streamsize size) { 2036 | LDID_SHA1_Update(&sha1_, data, size); 2037 | LDID_SHA256_Update(&sha256_, data, size); 2038 | return size; 2039 | } 2040 | 2041 | virtual int_type overflow(int_type next) { 2042 | if (next == traits_type::eof()) 2043 | return sync(); 2044 | char value(next); 2045 | xsputn(&value, 1); 2046 | return next; 2047 | } 2048 | }; 2049 | 2050 | class HashProxy : 2051 | public HashBuffer 2052 | { 2053 | private: 2054 | std::streambuf &buffer_; 2055 | 2056 | public: 2057 | HashProxy(ldid::Hash &hash, std::streambuf &buffer) : 2058 | HashBuffer(hash), 2059 | buffer_(buffer) 2060 | { 2061 | } 2062 | 2063 | virtual std::streamsize xsputn(const char_type *data, std::streamsize size) { 2064 | _assert(HashBuffer::xsputn(data, size) == size); 2065 | return buffer_.sputn(data, size); 2066 | } 2067 | }; 2068 | 2069 | #ifndef LDID_NOTOOLS 2070 | static bool Starts(const std::string &lhs, const std::string &rhs) { 2071 | return lhs.size() >= rhs.size() && lhs.compare(0, rhs.size(), rhs) == 0; 2072 | } 2073 | 2074 | class Split { 2075 | public: 2076 | std::string dir; 2077 | std::string base; 2078 | 2079 | Split(const std::string &path) { 2080 | size_t slash(path.rfind('/')); 2081 | if (slash == std::string::npos) 2082 | base = path; 2083 | else { 2084 | dir = path.substr(0, slash + 1); 2085 | base = path.substr(slash + 1); 2086 | } 2087 | } 2088 | }; 2089 | 2090 | static void mkdir_p(const std::string &path) { 2091 | if (path.empty()) 2092 | return; 2093 | #ifdef __WIN32__ 2094 | if (_syscall(mkdir(path.c_str()), EEXIST) == -EEXIST) 2095 | return; 2096 | #else 2097 | if (_syscall(mkdir(path.c_str(), 0755), EEXIST) == -EEXIST) 2098 | return; 2099 | #endif 2100 | auto slash(path.rfind('/', path.size() - 1)); 2101 | if (slash == std::string::npos) 2102 | return; 2103 | mkdir_p(path.substr(0, slash)); 2104 | } 2105 | 2106 | static std::string Temporary(std::filebuf &file, const Split &split) { 2107 | std::string temp(split.dir + ".ldid." + split.base); 2108 | mkdir_p(split.dir); 2109 | _assert_(file.open(temp.c_str(), std::ios::out | std::ios::trunc | std::ios::binary) == &file, "open(): %s", temp.c_str()); 2110 | return temp; 2111 | } 2112 | 2113 | static void Commit(const std::string &path, const std::string &temp) { 2114 | struct stat info; 2115 | if (_syscall(stat(path.c_str(), &info), ENOENT) == 0) { 2116 | #ifndef __WIN32__ 2117 | _syscall(chown(temp.c_str(), info.st_uid, info.st_gid)); 2118 | #endif 2119 | _syscall(chmod(temp.c_str(), info.st_mode)); 2120 | } 2121 | 2122 | _syscall(rename(temp.c_str(), path.c_str())); 2123 | } 2124 | #endif 2125 | 2126 | namespace ldid { 2127 | 2128 | #ifndef LDID_NOSMIME 2129 | static void get(std::string &value, X509_NAME *name, int nid) { 2130 | auto index(X509_NAME_get_index_by_NID(name, nid, -1)); 2131 | _assert(index >= 0); 2132 | auto next(X509_NAME_get_index_by_NID(name, nid, index)); 2133 | _assert(next == -1); 2134 | auto entry(X509_NAME_get_entry(name, index)); 2135 | _assert(entry != NULL); 2136 | auto asn(X509_NAME_ENTRY_get_data(entry)); 2137 | _assert(asn != NULL); 2138 | value.assign(reinterpret_cast(ASN1_STRING_data(asn)), ASN1_STRING_length(asn)); 2139 | } 2140 | #endif 2141 | 2142 | static void req(std::streambuf &buffer, uint32_t value) { 2143 | value = Swap(value); 2144 | put(buffer, &value, sizeof(value)); 2145 | } 2146 | 2147 | static void req(std::streambuf &buffer, const std::string &value) { 2148 | req(buffer, value.size()); 2149 | put(buffer, value.data(), value.size()); 2150 | static uint8_t zeros[] = {0,0,0,0}; 2151 | put(buffer, zeros, 3 - (value.size() + 3) % 4); 2152 | } 2153 | 2154 | template 2155 | static void req(std::streambuf &buffer, uint8_t (&&data)[Size_]) { 2156 | req(buffer, Size_); 2157 | put(buffer, data, Size_); 2158 | static uint8_t zeros[] = {0,0,0,0}; 2159 | put(buffer, zeros, 3 - (Size_ + 3) % 4); 2160 | } 2161 | 2162 | 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) { 2163 | Hash hash; 2164 | 2165 | 2166 | std::string team; 2167 | std::string common; 2168 | 2169 | #ifndef LDID_NOSMIME 2170 | if (!key.empty()) { 2171 | Stuff stuff(key); 2172 | auto name(X509_get_subject_name(stuff)); 2173 | _assert(name != NULL); 2174 | get(team, name, NID_organizationalUnitName); 2175 | get(common, name, NID_commonName); 2176 | } 2177 | #endif 2178 | 2179 | 2180 | std::stringbuf backing; 2181 | 2182 | if (!requirements.empty()) { 2183 | put(backing, requirements.data(), requirements.size()); 2184 | } else { 2185 | Blobs blobs; 2186 | 2187 | std::stringbuf requirement; 2188 | req(requirement, exprForm); 2189 | req(requirement, opAnd); 2190 | req(requirement, opIdent); 2191 | req(requirement, identifier); 2192 | req(requirement, opAnd); 2193 | req(requirement, opAppleGenericAnchor); 2194 | req(requirement, opAnd); 2195 | req(requirement, opCertField); 2196 | req(requirement, 0); 2197 | req(requirement, "subject.CN"); 2198 | req(requirement, matchEqual); 2199 | req(requirement, common); 2200 | req(requirement, opCertGeneric); 2201 | req(requirement, 1); 2202 | req(requirement, (uint8_t []) {APPLE_EXTENSION_OID, 2, 1}); 2203 | req(requirement, matchExists); 2204 | insert(blobs, 3, CSMAGIC_REQUIREMENT, requirement); 2205 | 2206 | put(backing, CSMAGIC_REQUIREMENTS, blobs); 2207 | } 2208 | 2209 | 2210 | // XXX: this is just a "sufficiently large number" 2211 | size_t certificate(0x3000); 2212 | 2213 | Allocate(idata, isize, output, fun([&](const MachHeader &mach_header, Baton &baton, size_t size) -> size_t { 2214 | size_t alloc(sizeof(struct SuperBlob)); 2215 | 2216 | uint32_t normal((size + PageSize_ - 1) / PageSize_); 2217 | 2218 | uint32_t special(0); 2219 | 2220 | _foreach (slot, slots) 2221 | special = std::max(special, slot.first); 2222 | 2223 | mach_header.ForSection(fun([&](const char *segment, const char *section, void *data, size_t size) { 2224 | if (strcmp(segment, "__TEXT") == 0 && section != NULL && strcmp(section, "__info_plist") == 0) 2225 | special = std::max(special, CSSLOT_INFOSLOT); 2226 | })); 2227 | 2228 | special = std::max(special, CSSLOT_REQUIREMENTS); 2229 | alloc += sizeof(struct BlobIndex); 2230 | alloc += backing.str().size(); 2231 | 2232 | #ifdef LDID_NOPLIST 2233 | baton.entitlements_ = entitlements; 2234 | #else 2235 | if (merge) 2236 | Analyze(mach_header, fun([&](const char *data, size_t size) { 2237 | baton.entitlements_.assign(data, size); 2238 | })); 2239 | 2240 | if (!baton.entitlements_.empty() || !entitlements.empty()) { 2241 | auto combined(plist(baton.entitlements_)); 2242 | _scope({ plist_free(combined); }); 2243 | _assert(plist_get_node_type(combined) == PLIST_DICT); 2244 | 2245 | auto merging(plist(entitlements)); 2246 | _scope({ plist_free(merging); }); 2247 | _assert(plist_get_node_type(merging) == PLIST_DICT); 2248 | 2249 | plist_dict_iter iterator(NULL); 2250 | plist_dict_new_iter(merging, &iterator); 2251 | _scope({ free(iterator); }); 2252 | 2253 | for (;;) { 2254 | char *key(NULL); 2255 | plist_t value(NULL); 2256 | plist_dict_next_item(merging, iterator, &key, &value); 2257 | if (key == NULL) 2258 | break; 2259 | _scope({ free(key); }); 2260 | plist_dict_set_item(combined, key, plist_copy(value)); 2261 | } 2262 | 2263 | baton.derformat_ = der(combined); 2264 | 2265 | char *xml(NULL); 2266 | uint32_t size; 2267 | plist_to_xml(combined, &xml, &size); 2268 | _scope({ free(xml); }); 2269 | 2270 | baton.entitlements_.assign(xml, size); 2271 | } 2272 | #endif 2273 | 2274 | if (!baton.entitlements_.empty()) { 2275 | special = std::max(special, CSSLOT_ENTITLEMENTS); 2276 | alloc += sizeof(struct BlobIndex); 2277 | alloc += sizeof(struct Blob); 2278 | alloc += baton.entitlements_.size(); 2279 | } 2280 | 2281 | if (!baton.derformat_.empty()) { 2282 | special = std::max(special, CSSLOT_DERFORMAT); 2283 | alloc += sizeof(struct BlobIndex); 2284 | alloc += sizeof(struct Blob); 2285 | alloc += baton.derformat_.size(); 2286 | } 2287 | 2288 | size_t directory(0); 2289 | 2290 | directory += sizeof(struct BlobIndex); 2291 | directory += sizeof(struct Blob); 2292 | directory += sizeof(struct CodeDirectory); 2293 | directory += identifier.size() + 1; 2294 | 2295 | if (!team.empty()) 2296 | directory += team.size() + 1; 2297 | 2298 | for (Algorithm *algorithm : GetAlgorithms()) 2299 | alloc = Align(alloc + directory + (special + normal) * algorithm->size_, 16); 2300 | 2301 | #ifndef LDID_NOSMIME 2302 | if (!key.empty()) { 2303 | alloc += sizeof(struct BlobIndex); 2304 | alloc += sizeof(struct Blob); 2305 | alloc += certificate; 2306 | } 2307 | #endif 2308 | 2309 | return alloc; 2310 | }), fun([&](const MachHeader &mach_header, const Baton &baton, std::streambuf &output, size_t limit, size_t left, size_t right, const std::string &overlap, const char *top, const Progress &progress) -> size_t { 2311 | Blobs blobs; 2312 | 2313 | if (true) { 2314 | insert(blobs, CSSLOT_REQUIREMENTS, backing); 2315 | } 2316 | 2317 | uint64_t execs(0); 2318 | if (mach_header.Swap(mach_header->filetype) == MH_EXECUTE) 2319 | execs |= kSecCodeExecSegMainBinary; 2320 | 2321 | if (!baton.entitlements_.empty()) { 2322 | std::stringbuf data; 2323 | put(data, baton.entitlements_.data(), baton.entitlements_.size()); 2324 | insert(blobs, CSSLOT_ENTITLEMENTS, CSMAGIC_EMBEDDED_ENTITLEMENTS, data); 2325 | 2326 | #ifndef LDID_NOPLIST 2327 | auto entitlements(plist(baton.entitlements_)); 2328 | _scope({ plist_free(entitlements); }); 2329 | _assert(plist_get_node_type(entitlements) == PLIST_DICT); 2330 | 2331 | const auto entitled([&](const char *key) { 2332 | auto item(plist_dict_get_item(entitlements, key)); 2333 | if (plist_get_node_type(item) != PLIST_BOOLEAN) 2334 | return false; 2335 | uint8_t value(0); 2336 | plist_get_bool_val(item, &value); 2337 | return value != 0; 2338 | }); 2339 | 2340 | if (entitled("get-task-allow")) 2341 | execs |= kSecCodeExecSegAllowUnsigned; 2342 | if (entitled("run-unsigned-code")) 2343 | execs |= kSecCodeExecSegAllowUnsigned; 2344 | if (entitled("com.apple.private.cs.debugger")) 2345 | execs |= kSecCodeExecSegDebugger; 2346 | if (entitled("dynamic-codesigning")) 2347 | execs |= kSecCodeExecSegJit; 2348 | if (entitled("com.apple.private.skip-library-validation")) 2349 | execs |= kSecCodeExecSegSkipLibraryVal; 2350 | if (entitled("com.apple.private.amfi.can-load-cdhash")) 2351 | execs |= kSecCodeExecSegCanLoadCdHash; 2352 | if (entitled("com.apple.private.amfi.can-execute-cdhash")) 2353 | execs |= kSecCodeExecSegCanExecCdHash; 2354 | #endif 2355 | } 2356 | 2357 | if (!baton.derformat_.empty()) { 2358 | std::stringbuf data; 2359 | put(data, baton.derformat_.data(), baton.derformat_.size()); 2360 | insert(blobs, CSSLOT_DERFORMAT, CSMAGIC_EMBEDDED_DERFORMAT, data); 2361 | } 2362 | 2363 | Slots posts(slots); 2364 | 2365 | mach_header.ForSection(fun([&](const char *segment, const char *section, void *data, size_t size) { 2366 | if (strcmp(segment, "__TEXT") == 0 && section != NULL && strcmp(section, "__info_plist") == 0) { 2367 | auto &slot(posts[CSSLOT_INFOSLOT]); 2368 | for (Algorithm *algorithm : GetAlgorithms()) 2369 | (*algorithm)(slot, data, size); 2370 | } 2371 | })); 2372 | 2373 | unsigned total(0); 2374 | for (Algorithm *pointer : GetAlgorithms()) { 2375 | Algorithm &algorithm(*pointer); 2376 | 2377 | std::stringbuf data; 2378 | 2379 | uint32_t special(0); 2380 | _foreach (blob, blobs) 2381 | special = std::max(special, blob.first); 2382 | _foreach (slot, posts) 2383 | special = std::max(special, slot.first); 2384 | uint32_t normal((limit + PageSize_ - 1) / PageSize_); 2385 | 2386 | CodeDirectory directory; 2387 | directory.version = Swap(uint32_t(0x00020400)); 2388 | directory.flags = Swap(uint32_t(flags)); 2389 | directory.nSpecialSlots = Swap(special); 2390 | directory.codeLimit = Swap(uint32_t(limit > UINT32_MAX ? UINT32_MAX : limit)); 2391 | directory.nCodeSlots = Swap(normal); 2392 | directory.hashSize = algorithm.size_; 2393 | directory.hashType = algorithm.type_; 2394 | directory.platform = platform ? 0x01 : 0x00; 2395 | directory.pageSize = PageShift_; 2396 | directory.spare2 = Swap(uint32_t(0)); 2397 | directory.scatterOffset = Swap(uint32_t(0)); 2398 | directory.spare3 = Swap(uint32_t(0)); 2399 | directory.codeLimit64 = Swap(uint64_t(limit > UINT32_MAX ? limit : 0)); 2400 | directory.execSegBase = Swap(uint64_t(left)); 2401 | directory.execSegLimit = Swap(uint64_t(right - left)); 2402 | directory.execSegFlags = Swap(execs); 2403 | 2404 | uint32_t offset(sizeof(Blob) + sizeof(CodeDirectory)); 2405 | 2406 | directory.identOffset = Swap(uint32_t(offset)); 2407 | offset += identifier.size() + 1; 2408 | 2409 | if (team.empty()) 2410 | directory.teamIDOffset = Swap(uint32_t(0)); 2411 | else { 2412 | directory.teamIDOffset = Swap(uint32_t(offset)); 2413 | offset += team.size() + 1; 2414 | } 2415 | 2416 | offset += special * algorithm.size_; 2417 | directory.hashOffset = Swap(uint32_t(offset)); 2418 | offset += normal * algorithm.size_; 2419 | 2420 | put(data, &directory, sizeof(directory)); 2421 | 2422 | put(data, identifier.c_str(), identifier.size() + 1); 2423 | if (!team.empty()) 2424 | put(data, team.c_str(), team.size() + 1); 2425 | 2426 | std::vector storage((special + normal) * algorithm.size_); 2427 | auto *hashes(&storage[special * algorithm.size_]); 2428 | 2429 | memset(storage.data(), 0, special * algorithm.size_); 2430 | 2431 | _foreach (blob, blobs) { 2432 | auto local(reinterpret_cast(&blob.second[0])); 2433 | algorithm(hashes - blob.first * algorithm.size_, local, Swap(local->length)); 2434 | } 2435 | 2436 | _foreach (slot, posts) 2437 | memcpy(hashes - slot.first * algorithm.size_, algorithm[slot.second], algorithm.size_); 2438 | 2439 | progress(0); 2440 | if (normal != 1) 2441 | for (size_t i = 0; i != normal - 1; ++i) { 2442 | algorithm(hashes + i * algorithm.size_, (PageSize_ * i < overlap.size() ? overlap.data() : top) + PageSize_ * i, PageSize_); 2443 | progress(double(i) / normal); 2444 | } 2445 | if (normal != 0) 2446 | algorithm(hashes + (normal - 1) * algorithm.size_, top + PageSize_ * (normal - 1), ((limit - 1) % PageSize_) + 1); 2447 | progress(1); 2448 | 2449 | put(data, storage.data(), storage.size()); 2450 | 2451 | const auto &save(insert(blobs, total == 0 ? CSSLOT_CODEDIRECTORY : CSSLOT_ALTERNATE + total - 1, CSMAGIC_CODEDIRECTORY, data)); 2452 | algorithm(hash, save.data(), save.size()); 2453 | 2454 | ++total; 2455 | } 2456 | 2457 | #ifndef LDID_NOSMIME 2458 | if (!key.empty()) { 2459 | #ifdef LDID_NOPLIST 2460 | auto plist(CFDictionaryCreateMutable(kCFAllocatorDefault, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks)); 2461 | _scope({ CFRelease(plist); }); 2462 | 2463 | auto cdhashes(CFArrayCreateMutable(kCFAllocatorDefault, 0, &kCFTypeArrayCallBacks)); 2464 | _scope({ CFRelease(cdhashes); }); 2465 | 2466 | CFDictionarySetValue(plist, CFSTR("cdhashes"), cdhashes); 2467 | #else 2468 | auto plist(plist_new_dict()); 2469 | _scope({ plist_free(plist); }); 2470 | 2471 | auto cdhashes(plist_new_array()); 2472 | plist_dict_set_item(plist, "cdhashes", cdhashes); 2473 | #endif 2474 | 2475 | ldid::Hash hash; 2476 | 2477 | unsigned total(0); 2478 | for (Algorithm *pointer : GetAlgorithms()) { 2479 | Algorithm &algorithm(*pointer); 2480 | (void) algorithm; 2481 | 2482 | const auto &blob(blobs[total == 0 ? CSSLOT_CODEDIRECTORY : CSSLOT_ALTERNATE + total - 1]); 2483 | ++total; 2484 | 2485 | algorithm(hash, blob.data(), blob.size()); 2486 | 2487 | std::vector cdhash(algorithm[hash], algorithm[hash] + algorithm.size_); 2488 | cdhash.resize(20); 2489 | 2490 | #ifdef LDID_NOPLIST 2491 | auto value(CFDataCreate(kCFAllocatorDefault, reinterpret_cast(cdhash.data()), cdhash.size())); 2492 | _scope({ CFRelease(value); }); 2493 | CFArrayAppendValue(cdhashes, value); 2494 | #else 2495 | plist_array_append_item(cdhashes, plist_new_data(cdhash.data(), cdhash.size())); 2496 | #endif 2497 | } 2498 | 2499 | #ifdef LDID_NOPLIST 2500 | auto created(CFPropertyListCreateXMLData(kCFAllocatorDefault, plist)); 2501 | _scope({ CFRelease(created); }); 2502 | auto xml(reinterpret_cast(CFDataGetBytePtr(created))); 2503 | auto size(CFDataGetLength(created)); 2504 | #else 2505 | char *xml(NULL); 2506 | uint32_t size; 2507 | plist_to_xml(plist, &xml, &size); 2508 | _scope({ free(xml); }); 2509 | #endif 2510 | 2511 | std::stringbuf data; 2512 | const std::string &sign(blobs[CSSLOT_CODEDIRECTORY]); 2513 | 2514 | Stuff stuff(key); 2515 | Buffer bio(sign); 2516 | 2517 | Signature signature(stuff, sign, std::string(xml, size), hash); 2518 | Buffer result(signature); 2519 | std::string value(result); 2520 | put(data, value.data(), value.size()); 2521 | 2522 | const auto &save(insert(blobs, CSSLOT_SIGNATURESLOT, CSMAGIC_BLOBWRAPPER, data)); 2523 | _assert(save.size() <= certificate); 2524 | } 2525 | #endif 2526 | 2527 | return put(output, CSMAGIC_EMBEDDED_SIGNATURE, blobs); 2528 | }), progress); 2529 | 2530 | return hash; 2531 | } 2532 | 2533 | #ifndef LDID_NOTOOLS 2534 | static void Unsign(void *idata, size_t isize, std::streambuf &output, const Progress &progress) { 2535 | Allocate(idata, isize, output, fun([](const MachHeader &mach_header, Baton &baton, size_t size) -> size_t { 2536 | return 0; 2537 | }), fun([](const MachHeader &mach_header, const Baton &baton, std::streambuf &output, size_t limit, size_t left, size_t right, const std::string &overlap, const char *top, const Progress &progress) -> size_t { 2538 | return 0; 2539 | }), progress); 2540 | } 2541 | 2542 | std::string DiskFolder::Path(const std::string &path) const { 2543 | return path_ + path; 2544 | } 2545 | 2546 | DiskFolder::DiskFolder(const std::string &path) : 2547 | path_(path) 2548 | { 2549 | _assert_(path_.size() != 0 && path_[path_.size() - 1] == '/', "missing / on %s", path_.c_str()); 2550 | } 2551 | 2552 | DiskFolder::~DiskFolder() { 2553 | if (!std::uncaught_exception()) 2554 | for (const auto &commit : commit_) 2555 | Commit(commit.first, commit.second); 2556 | } 2557 | 2558 | #ifndef __WIN32__ 2559 | std::string readlink(const std::string &path) { 2560 | for (size_t size(1024); ; size *= 2) { 2561 | std::string data; 2562 | data.resize(size); 2563 | 2564 | int writ(_syscall(::readlink(path.c_str(), &data[0], data.size()))); 2565 | if (size_t(writ) >= size) 2566 | continue; 2567 | 2568 | data.resize(writ); 2569 | return data; 2570 | } 2571 | } 2572 | #endif 2573 | 2574 | void DiskFolder::Find(const std::string &root, const std::string &base, const Functor &code, const Functor &)> &link) const { 2575 | std::string path(Path(root) + base); 2576 | 2577 | DIR *dir(opendir(path.c_str())); 2578 | _assert(dir != NULL); 2579 | _scope({ _syscall(closedir(dir)); }); 2580 | 2581 | while (auto child = readdir(dir)) { 2582 | std::string name(child->d_name); 2583 | if (name == "." || name == "..") 2584 | continue; 2585 | if (Starts(name, ".ldid.")) 2586 | continue; 2587 | 2588 | bool directory; 2589 | 2590 | #ifdef __WIN32__ 2591 | struct stat info; 2592 | _syscall(stat((path + name).c_str(), &info)); 2593 | if (false); 2594 | else if (S_ISDIR(info.st_mode)) 2595 | directory = true; 2596 | else if (S_ISREG(info.st_mode)) 2597 | directory = false; 2598 | else 2599 | _assert_(false, "st_mode=%x", info.st_mode); 2600 | #else 2601 | switch (child->d_type) { 2602 | case DT_DIR: 2603 | directory = true; 2604 | break; 2605 | case DT_REG: 2606 | directory = false; 2607 | break; 2608 | case DT_LNK: 2609 | link(base + name, fun([&]() { return readlink(path + name); })); 2610 | continue; 2611 | default: 2612 | _assert_(false, "d_type=%u", child->d_type); 2613 | } 2614 | #endif 2615 | 2616 | if (directory) 2617 | Find(root, base + name + "/", code, link); 2618 | else 2619 | code(base + name); 2620 | } 2621 | } 2622 | 2623 | void DiskFolder::Save(const std::string &path, bool edit, const void *flag, const Functor &code) { 2624 | if (!edit) { 2625 | NullBuffer save; 2626 | code(save); 2627 | } else { 2628 | std::filebuf save; 2629 | auto from(Path(path)); 2630 | commit_[from] = Temporary(save, from); 2631 | code(save); 2632 | } 2633 | } 2634 | 2635 | bool DiskFolder::Look(const std::string &path) const { 2636 | return _syscall(access(Path(path).c_str(), R_OK), ENOENT) == 0; 2637 | } 2638 | 2639 | void DiskFolder::Open(const std::string &path, const Functor &code) const { 2640 | std::filebuf data; 2641 | auto result(data.open(Path(path).c_str(), std::ios::binary | std::ios::in)); 2642 | _assert_(result == &data, "DiskFolder::Open(%s)", Path(path).c_str()); 2643 | 2644 | auto length(data.pubseekoff(0, std::ios::end, std::ios::in)); 2645 | data.pubseekpos(0, std::ios::in); 2646 | code(data, length, NULL); 2647 | } 2648 | 2649 | void DiskFolder::Find(const std::string &path, const Functor &code, const Functor &)> &link) const { 2650 | Find(path, "", code, link); 2651 | } 2652 | #endif 2653 | 2654 | SubFolder::SubFolder(Folder &parent, const std::string &path) : 2655 | parent_(parent), 2656 | path_(path) 2657 | { 2658 | _assert_(path_.size() == 0 || path_[path_.size() - 1] == '/', "missing / on %s", path_.c_str()); 2659 | } 2660 | 2661 | std::string SubFolder::Path(const std::string &path) const { 2662 | return path_ + path; 2663 | } 2664 | 2665 | void SubFolder::Save(const std::string &path, bool edit, const void *flag, const Functor &code) { 2666 | return parent_.Save(Path(path), edit, flag, code); 2667 | } 2668 | 2669 | bool SubFolder::Look(const std::string &path) const { 2670 | return parent_.Look(Path(path)); 2671 | } 2672 | 2673 | void SubFolder::Open(const std::string &path, const Functor &code) const { 2674 | return parent_.Open(Path(path), code); 2675 | } 2676 | 2677 | void SubFolder::Find(const std::string &path, const Functor &code, const Functor &)> &link) const { 2678 | return parent_.Find(Path(path), code, link); 2679 | } 2680 | 2681 | std::string UnionFolder::Map(const std::string &path) const { 2682 | auto remap(remaps_.find(path)); 2683 | if (remap == remaps_.end()) 2684 | return path; 2685 | return remap->second; 2686 | } 2687 | 2688 | void UnionFolder::Map(const std::string &path, const Functor &code, const std::string &file, const Functor &)> &save) const { 2689 | if (file.size() >= path.size() && file.substr(0, path.size()) == path) 2690 | code(file.substr(path.size())); 2691 | } 2692 | 2693 | UnionFolder::UnionFolder(Folder &parent) : 2694 | parent_(parent) 2695 | { 2696 | } 2697 | 2698 | void UnionFolder::Save(const std::string &path, bool edit, const void *flag, const Functor &code) { 2699 | return parent_.Save(Map(path), edit, flag, code); 2700 | } 2701 | 2702 | bool UnionFolder::Look(const std::string &path) const { 2703 | auto file(resets_.find(path)); 2704 | if (file != resets_.end()) 2705 | return true; 2706 | return parent_.Look(Map(path)); 2707 | } 2708 | 2709 | void UnionFolder::Open(const std::string &path, const Functor &code) const { 2710 | auto file(resets_.find(path)); 2711 | if (file == resets_.end()) 2712 | return parent_.Open(Map(path), code); 2713 | auto &entry(file->second); 2714 | 2715 | auto &data(*entry.data_); 2716 | auto length(data.pubseekoff(0, std::ios::end, std::ios::in)); 2717 | data.pubseekpos(0, std::ios::in); 2718 | code(data, length, entry.flag_); 2719 | } 2720 | 2721 | void UnionFolder::Find(const std::string &path, const Functor &code, const Functor &)> &link) const { 2722 | for (auto &reset : resets_) 2723 | Map(path, code, reset.first, fun([&](const Functor &code) { 2724 | auto &entry(reset.second); 2725 | auto &data(*entry.data_); 2726 | auto length(data.pubseekoff(0, std::ios::end, std::ios::in)); 2727 | data.pubseekpos(0, std::ios::in); 2728 | code(data, length, entry.flag_); 2729 | })); 2730 | 2731 | for (auto &remap : remaps_) 2732 | Map(path, code, remap.first, fun([&](const Functor &code) { 2733 | parent_.Open(remap.second, fun([&](std::streambuf &data, size_t length, const void *flag) { 2734 | code(data, length, flag); 2735 | })); 2736 | })); 2737 | 2738 | parent_.Find(path, fun([&](const std::string &name) { 2739 | if (deletes_.find(path + name) == deletes_.end()) 2740 | code(name); 2741 | }), fun([&](const std::string &name, const Functor &read) { 2742 | if (deletes_.find(path + name) == deletes_.end()) 2743 | link(name, read); 2744 | })); 2745 | } 2746 | 2747 | #ifndef LDID_NOTOOLS 2748 | static void copy(std::streambuf &source, std::streambuf &target, size_t length, const Progress &progress) { 2749 | progress(0); 2750 | size_t total(0); 2751 | for (;;) { 2752 | char data[4096 * 4]; 2753 | size_t writ(source.sgetn(data, sizeof(data))); 2754 | if (writ == 0) 2755 | break; 2756 | _assert(target.sputn(data, writ) == writ); 2757 | total += writ; 2758 | progress(double(total) / length); 2759 | } 2760 | } 2761 | 2762 | #ifndef LDID_NOPLIST 2763 | static plist_t plist(const std::string &data) { 2764 | if (data.empty()) 2765 | return plist_new_dict(); 2766 | plist_t plist(NULL); 2767 | if (Starts(data, "bplist00")) 2768 | plist_from_bin(data.data(), data.size(), &plist); 2769 | else 2770 | plist_from_xml(data.data(), data.size(), &plist); 2771 | _assert(plist != NULL); 2772 | return plist; 2773 | } 2774 | 2775 | static void plist_d(std::streambuf &buffer, size_t length, const Functor &code) { 2776 | std::stringbuf data; 2777 | copy(buffer, data, length, dummy_); 2778 | auto node(plist(data.str())); 2779 | _scope({ plist_free(node); }); 2780 | _assert(plist_get_node_type(node) == PLIST_DICT); 2781 | code(node); 2782 | } 2783 | 2784 | static std::string plist_s(plist_t node) { 2785 | _assert(node != NULL); 2786 | _assert(plist_get_node_type(node) == PLIST_STRING); 2787 | char *data; 2788 | plist_get_string_val(node, &data); 2789 | _scope({ free(data); }); 2790 | return data; 2791 | } 2792 | #endif 2793 | 2794 | enum Mode { 2795 | NoMode, 2796 | OptionalMode, 2797 | OmitMode, 2798 | NestedMode, 2799 | TopMode, 2800 | }; 2801 | 2802 | class Expression { 2803 | private: 2804 | regex_t regex_; 2805 | std::vector matches_; 2806 | 2807 | public: 2808 | Expression(const std::string &code) { 2809 | _assert_(regcomp(®ex_, code.c_str(), REG_EXTENDED) == 0, "regcomp()"); 2810 | matches_.resize(regex_.re_nsub + 1); 2811 | } 2812 | 2813 | ~Expression() { 2814 | regfree(®ex_); 2815 | } 2816 | 2817 | bool operator ()(const std::string &data) { 2818 | regmatch_t matches[matches_.size()]; 2819 | auto value(regexec(®ex_, data.c_str(), matches_.size(), matches, 0)); 2820 | if (value == REG_NOMATCH) 2821 | return false; 2822 | _assert_(value == 0, "regexec()"); 2823 | for (size_t i(0); i != matches_.size(); ++i) 2824 | matches_[i].assign(data.data() + matches[i].rm_so, matches[i].rm_eo - matches[i].rm_so); 2825 | return true; 2826 | } 2827 | 2828 | const std::string &operator [](size_t index) const { 2829 | return matches_[index]; 2830 | } 2831 | }; 2832 | 2833 | struct Rule { 2834 | unsigned weight_; 2835 | Mode mode_; 2836 | std::string code_; 2837 | 2838 | mutable std::auto_ptr regex_; 2839 | 2840 | Rule(unsigned weight, Mode mode, const std::string &code) : 2841 | weight_(weight), 2842 | mode_(mode), 2843 | code_(code) 2844 | { 2845 | } 2846 | 2847 | Rule(const Rule &rhs) : 2848 | weight_(rhs.weight_), 2849 | mode_(rhs.mode_), 2850 | code_(rhs.code_) 2851 | { 2852 | } 2853 | 2854 | void Compile() const { 2855 | regex_.reset(new Expression(code_)); 2856 | } 2857 | 2858 | bool operator ()(const std::string &data) const { 2859 | _assert(regex_.get() != NULL); 2860 | return (*regex_)(data); 2861 | } 2862 | 2863 | bool operator <(const Rule &rhs) const { 2864 | if (weight_ > rhs.weight_) 2865 | return true; 2866 | if (weight_ < rhs.weight_) 2867 | return false; 2868 | return mode_ > rhs.mode_; 2869 | } 2870 | }; 2871 | 2872 | struct RuleCode { 2873 | bool operator ()(const Rule *lhs, const Rule *rhs) const { 2874 | return lhs->code_ < rhs->code_; 2875 | } 2876 | }; 2877 | 2878 | #ifndef LDID_NOPLIST 2879 | 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) { 2880 | // XXX: this is a miserable fail 2881 | std::stringbuf temp; 2882 | put(temp, prefix, size); 2883 | copy(buffer, temp, length - size, progress); 2884 | // XXX: this is a stupid hack 2885 | pad(temp, 0x10 - (length & 0xf)); 2886 | auto data(temp.str()); 2887 | 2888 | HashProxy proxy(hash, save); 2889 | return Sign(data.data(), data.size(), proxy, identifier, entitlements, merge, requirements, key, slots, flags, platform, progress); 2890 | } 2891 | 2892 | struct State { 2893 | std::map files; 2894 | std::map links; 2895 | 2896 | void Merge(const std::string &root, const State &state) { 2897 | for (const auto &entry : state.files) 2898 | files[root + entry.first] = entry.second; 2899 | for (const auto &entry : state.links) 2900 | links[root + entry.first] = entry.second; 2901 | } 2902 | }; 2903 | 2904 | Bundle Sign(const std::string &root, Folder &parent, const std::string &key, State &local, const std::string &requirements, const Functor &alter, const Progress &progress) { 2905 | std::string executable; 2906 | std::string identifier; 2907 | 2908 | bool mac(false); 2909 | 2910 | std::string info("Info.plist"); 2911 | 2912 | SubFolder folder(parent, [&]() { 2913 | if (parent.Look(info)) 2914 | return ""; 2915 | mac = true; 2916 | if (false); 2917 | else if (parent.Look("Contents/" + info)) 2918 | return "Contents/"; 2919 | else if (parent.Look("Resources/" + info)) { 2920 | info = "Resources/" + info; 2921 | return ""; 2922 | } else _assert_(false, "cannot find Info.plist"); 2923 | }()); 2924 | 2925 | folder.Open(info, fun([&](std::streambuf &buffer, size_t length, const void *flag) { 2926 | plist_d(buffer, length, fun([&](plist_t node) { 2927 | executable = plist_s(plist_dict_get_item(node, "CFBundleExecutable")); 2928 | identifier = plist_s(plist_dict_get_item(node, "CFBundleIdentifier")); 2929 | })); 2930 | })); 2931 | 2932 | if (mac && info == "Info.plist") 2933 | executable = "MacOS/" + executable; 2934 | 2935 | progress(root + "*"); 2936 | 2937 | std::string entitlements; 2938 | folder.Open(executable, fun([&](std::streambuf &buffer, size_t length, const void *flag) { 2939 | // XXX: this is a miserable fail 2940 | std::stringbuf temp; 2941 | copy(buffer, temp, length, progress); 2942 | // XXX: this is a stupid hack 2943 | pad(temp, 0x10 - (length & 0xf)); 2944 | auto data(temp.str()); 2945 | entitlements = alter(root, Analyze(data.data(), data.size())); 2946 | })); 2947 | 2948 | static const std::string directory("_CodeSignature/"); 2949 | static const std::string signature(directory + "CodeResources"); 2950 | 2951 | std::map> versions; 2952 | 2953 | auto &rules1(versions[""]); 2954 | auto &rules2(versions["2"]); 2955 | 2956 | const std::string resources(mac ? "Resources/" : ""); 2957 | 2958 | if (true) { 2959 | rules1.insert(Rule{1, NoMode, "^" + (resources == "" ? ".*" : resources)}); 2960 | rules1.insert(Rule{1000, OptionalMode, "^" + resources + ".*\\.lproj/"}); 2961 | rules1.insert(Rule{1100, OmitMode, "^" + resources + ".*\\.lproj/locversion.plist$"}); 2962 | rules1.insert(Rule{1010, NoMode, "^" + resources + "Base\\.lproj/"}); 2963 | rules1.insert(Rule{1, NoMode, "^version.plist$"}); 2964 | } 2965 | 2966 | if (true) { 2967 | rules2.insert(Rule{11, NoMode, ".*\\.dSYM($|/)"}); 2968 | if (mac) rules2.insert(Rule{20, NoMode, "^" + resources}); 2969 | rules2.insert(Rule{2000, OmitMode, "^(.*/)?\\.DS_Store$"}); 2970 | if (mac) rules2.insert(Rule{10, NestedMode, "^(Frameworks|SharedFrameworks|PlugIns|Plug-ins|XPCServices|Helpers|MacOS|Library/(Automator|Spotlight|LoginItems))/"}); 2971 | rules2.insert(Rule{1, NoMode, "^.*"}); 2972 | rules2.insert(Rule{1000, OptionalMode, "^" + resources + ".*\\.lproj/"}); 2973 | rules2.insert(Rule{1100, OmitMode, "^" + resources + ".*\\.lproj/locversion.plist$"}); 2974 | if (!mac) rules2.insert(Rule{1010, NoMode, "^Base\\.lproj/"}); 2975 | rules2.insert(Rule{20, OmitMode, "^Info\\.plist$"}); 2976 | rules2.insert(Rule{20, OmitMode, "^PkgInfo$"}); 2977 | if (mac) rules2.insert(Rule{10, NestedMode, "^[^/]+$"}); 2978 | rules2.insert(Rule{20, NoMode, "^embedded\\.provisionprofile$"}); 2979 | if (mac) rules2.insert(Rule{1010, NoMode, "^" + resources + "Base\\.lproj/"}); 2980 | rules2.insert(Rule{20, NoMode, "^version\\.plist$"}); 2981 | } 2982 | 2983 | std::string failure(mac ? "Contents/|Versions/[^/]*/Resources/" : ""); 2984 | Expression nested("^(Frameworks/[^/]*\\.framework|PlugIns/[^/]*\\.appex(()|/[^/]*.app))/(" + failure + ")Info\\.plist$"); 2985 | std::map bundles; 2986 | 2987 | folder.Find("", fun([&](const std::string &name) { 2988 | if (!nested(name)) 2989 | return; 2990 | auto bundle(Split(name).dir); 2991 | if (mac) { 2992 | _assert(!bundle.empty()); 2993 | bundle = Split(bundle.substr(0, bundle.size() - 1)).dir; 2994 | } 2995 | SubFolder subfolder(folder, bundle); 2996 | 2997 | State remote; 2998 | bundles[nested[1]] = Sign(root + bundle, subfolder, key, remote, "", Starts(name, "PlugIns/") ? alter : 2999 | static_cast &>(fun([&](const std::string &, const std::string &) -> std::string { return entitlements; })) 3000 | , progress); 3001 | local.Merge(bundle, remote); 3002 | }), fun([&](const std::string &name, const Functor &read) { 3003 | })); 3004 | 3005 | std::set excludes; 3006 | 3007 | auto exclude([&](const std::string &name) { 3008 | // BundleDiskRep::adjustResources -> builder.addExclusion 3009 | if (name == executable || Starts(name, directory) || Starts(name, "_MASReceipt/") || name == "CodeResources") 3010 | return true; 3011 | 3012 | for (const auto &bundle : bundles) 3013 | if (Starts(name, bundle.first + "/")) { 3014 | excludes.insert(name); 3015 | return true; 3016 | } 3017 | 3018 | return false; 3019 | }); 3020 | 3021 | folder.Find("", fun([&](const std::string &name) { 3022 | if (exclude(name)) 3023 | return; 3024 | 3025 | if (local.files.find(name) != local.files.end()) 3026 | return; 3027 | auto &hash(local.files[name]); 3028 | 3029 | folder.Open(name, fun([&](std::streambuf &data, size_t length, const void *flag) { 3030 | progress(root + name); 3031 | 3032 | union { 3033 | struct { 3034 | uint32_t magic; 3035 | uint32_t count; 3036 | }; 3037 | 3038 | uint8_t bytes[8]; 3039 | } header; 3040 | 3041 | auto size(most(data, &header.bytes, sizeof(header.bytes))); 3042 | 3043 | if (name != "_WatchKitStub/WK" && size == sizeof(header.bytes)) 3044 | switch (Swap(header.magic)) { 3045 | case FAT_MAGIC: 3046 | // Java class file format 3047 | if (Swap(header.count) >= 40) 3048 | break; 3049 | case FAT_CIGAM: 3050 | case MH_MAGIC: case MH_MAGIC_64: 3051 | case MH_CIGAM: case MH_CIGAM_64: 3052 | folder.Save(name, true, flag, fun([&](std::streambuf &save) { 3053 | Slots slots; 3054 | Sign(header.bytes, size, data, hash, save, identifier, "", false, "", key, slots, length, 0, false, Progression(progress, root + name)); 3055 | })); 3056 | return; 3057 | } 3058 | 3059 | folder.Save(name, false, flag, fun([&](std::streambuf &save) { 3060 | HashProxy proxy(hash, save); 3061 | put(proxy, header.bytes, size); 3062 | copy(data, proxy, length - size, progress); 3063 | })); 3064 | })); 3065 | }), fun([&](const std::string &name, const Functor &read) { 3066 | if (exclude(name)) 3067 | return; 3068 | 3069 | local.links[name] = read(); 3070 | })); 3071 | 3072 | auto plist(plist_new_dict()); 3073 | _scope({ plist_free(plist); }); 3074 | 3075 | for (const auto &version : versions) { 3076 | auto files(plist_new_dict()); 3077 | plist_dict_set_item(plist, ("files" + version.first).c_str(), files); 3078 | 3079 | for (const auto &rule : version.second) 3080 | rule.Compile(); 3081 | 3082 | bool old(&version.second == &rules1); 3083 | 3084 | for (const auto &hash : local.files) 3085 | for (const auto &rule : version.second) 3086 | if (rule(hash.first)) { 3087 | if (!old && mac && excludes.find(hash.first) != excludes.end()); 3088 | else if (old && rule.mode_ == NoMode) 3089 | plist_dict_set_item(files, hash.first.c_str(), plist_new_data(reinterpret_cast(hash.second.sha1_), sizeof(hash.second.sha1_))); 3090 | else if (rule.mode_ != OmitMode) { 3091 | auto entry(plist_new_dict()); 3092 | plist_dict_set_item(entry, "hash", plist_new_data(reinterpret_cast(hash.second.sha1_), sizeof(hash.second.sha1_))); 3093 | if (!old) 3094 | plist_dict_set_item(entry, "hash2", plist_new_data(reinterpret_cast(hash.second.sha256_), sizeof(hash.second.sha256_))); 3095 | if (rule.mode_ == OptionalMode) 3096 | plist_dict_set_item(entry, "optional", plist_new_bool(true)); 3097 | plist_dict_set_item(files, hash.first.c_str(), entry); 3098 | } 3099 | 3100 | break; 3101 | } 3102 | 3103 | if (!old) 3104 | for (const auto &link : local.links) 3105 | for (const auto &rule : version.second) 3106 | if (rule(link.first)) { 3107 | if (rule.mode_ != OmitMode) { 3108 | auto entry(plist_new_dict()); 3109 | plist_dict_set_item(entry, "symlink", plist_new_string(link.second.c_str())); 3110 | if (rule.mode_ == OptionalMode) 3111 | plist_dict_set_item(entry, "optional", plist_new_bool(true)); 3112 | plist_dict_set_item(files, link.first.c_str(), entry); 3113 | } 3114 | 3115 | break; 3116 | } 3117 | 3118 | if (!old && mac) 3119 | for (const auto &bundle : bundles) { 3120 | auto entry(plist_new_dict()); 3121 | plist_dict_set_item(entry, "cdhash", plist_new_data(reinterpret_cast(bundle.second.hash.sha256_), sizeof(bundle.second.hash.sha256_))); 3122 | plist_dict_set_item(entry, "requirement", plist_new_string("anchor apple generic")); 3123 | plist_dict_set_item(files, bundle.first.c_str(), entry); 3124 | } 3125 | } 3126 | 3127 | for (const auto &version : versions) { 3128 | auto rules(plist_new_dict()); 3129 | plist_dict_set_item(plist, ("rules" + version.first).c_str(), rules); 3130 | 3131 | std::multiset ordered; 3132 | for (const auto &rule : version.second) 3133 | ordered.insert(&rule); 3134 | 3135 | for (const auto &rule : ordered) 3136 | if (rule->weight_ == 1 && rule->mode_ == NoMode) 3137 | plist_dict_set_item(rules, rule->code_.c_str(), plist_new_bool(true)); 3138 | else { 3139 | auto entry(plist_new_dict()); 3140 | plist_dict_set_item(rules, rule->code_.c_str(), entry); 3141 | 3142 | switch (rule->mode_) { 3143 | case NoMode: 3144 | break; 3145 | case OmitMode: 3146 | plist_dict_set_item(entry, "omit", plist_new_bool(true)); 3147 | break; 3148 | case OptionalMode: 3149 | plist_dict_set_item(entry, "optional", plist_new_bool(true)); 3150 | break; 3151 | case NestedMode: 3152 | plist_dict_set_item(entry, "nested", plist_new_bool(true)); 3153 | break; 3154 | case TopMode: 3155 | plist_dict_set_item(entry, "top", plist_new_bool(true)); 3156 | break; 3157 | } 3158 | 3159 | if (rule->weight_ >= 10000) 3160 | plist_dict_set_item(entry, "weight", plist_new_uint(rule->weight_)); 3161 | else if (rule->weight_ != 1) 3162 | plist_dict_set_item(entry, "weight", plist_new_real(rule->weight_)); 3163 | } 3164 | } 3165 | 3166 | folder.Save(signature, true, NULL, fun([&](std::streambuf &save) { 3167 | HashProxy proxy(local.files[signature], save); 3168 | char *xml(NULL); 3169 | uint32_t size; 3170 | plist_to_xml(plist, &xml, &size); 3171 | _scope({ free(xml); }); 3172 | put(proxy, xml, size); 3173 | })); 3174 | 3175 | Bundle bundle; 3176 | bundle.path = folder.Path(executable); 3177 | 3178 | folder.Open(executable, fun([&](std::streambuf &buffer, size_t length, const void *flag) { 3179 | progress(root + executable); 3180 | folder.Save(executable, true, flag, fun([&](std::streambuf &save) { 3181 | Slots slots; 3182 | slots[1] = local.files.at(info); 3183 | slots[3] = local.files.at(signature); 3184 | bundle.hash = Sign(NULL, 0, buffer, local.files[executable], save, identifier, entitlements, false, requirements, key, slots, length, 0, false, Progression(progress, root + executable)); 3185 | })); 3186 | })); 3187 | 3188 | return bundle; 3189 | } 3190 | 3191 | Bundle Sign(const std::string &root, Folder &folder, const std::string &key, const std::string &requirements, const Functor &alter, const Progress &progress) { 3192 | State local; 3193 | return Sign(root, folder, key, local, requirements, alter, progress); 3194 | } 3195 | #endif 3196 | 3197 | #endif 3198 | } 3199 | 3200 | std::string Hex(const uint8_t *data, size_t size) { 3201 | std::string hex; 3202 | hex.reserve(size * 2); 3203 | for (size_t i(0); i != size; ++i) { 3204 | hex += "0123456789abcdef"[data[i] >> 4]; 3205 | hex += "0123456789abcdef"[data[i] & 0xf]; 3206 | } 3207 | return hex; 3208 | } 3209 | 3210 | static void usage(const char *argv0) { 3211 | fprintf(stderr, "usage: %s -S[entitlements.xml] \n", argv0); 3212 | fprintf(stderr, " %s -e MobileSafari\n", argv0); 3213 | fprintf(stderr, " %s -S cat\n", argv0); 3214 | fprintf(stderr, " %s -Stfp.xml gdb\n", argv0); 3215 | } 3216 | 3217 | #ifndef LDID_NOTOOLS 3218 | int main(int argc, char *argv[]) { 3219 | #ifndef LDID_NOSMIME 3220 | OpenSSL_add_all_algorithms(); 3221 | #endif 3222 | 3223 | union { 3224 | uint16_t word; 3225 | uint8_t byte[2]; 3226 | } endian = {1}; 3227 | 3228 | little_ = endian.byte[0]; 3229 | 3230 | bool flag_r(false); 3231 | bool flag_e(false); 3232 | bool flag_q(false); 3233 | 3234 | bool flag_H(false); 3235 | bool flag_h(false); 3236 | 3237 | #ifndef LDID_NOFLAGT 3238 | bool flag_T(false); 3239 | #endif 3240 | 3241 | bool flag_S(false); 3242 | bool flag_s(false); 3243 | 3244 | bool flag_D(false); 3245 | bool flag_d(false); 3246 | 3247 | bool flag_A(false); 3248 | bool flag_a(false); 3249 | 3250 | bool flag_u(false); 3251 | 3252 | bool flag_M(false); 3253 | 3254 | uint32_t flags(0); 3255 | bool platform(false); 3256 | 3257 | uint32_t flag_CPUType(_not(uint32_t)); 3258 | uint32_t flag_CPUSubtype(_not(uint32_t)); 3259 | 3260 | const char *flag_I(NULL); 3261 | 3262 | #ifndef LDID_NOFLAGT 3263 | bool timeh(false); 3264 | uint32_t timev(0); 3265 | #endif 3266 | 3267 | Map entitlements; 3268 | Map requirements; 3269 | Map key; 3270 | ldid::Slots slots; 3271 | 3272 | std::vector files; 3273 | 3274 | if (argc == 1) { 3275 | usage(argv[0]); 3276 | return 0; 3277 | } 3278 | 3279 | for (int argi(1); argi != argc; ++argi) 3280 | if (argv[argi][0] != '-') 3281 | files.push_back(argv[argi]); 3282 | else switch (argv[argi][1]) { 3283 | case 'r': 3284 | _assert(!flag_s); 3285 | _assert(!flag_S); 3286 | flag_r = true; 3287 | break; 3288 | 3289 | case 'e': flag_e = true; break; 3290 | 3291 | case 'E': { 3292 | const char *string = argv[argi] + 2; 3293 | const char *colon = strchr(string, ':'); 3294 | _assert(colon != NULL); 3295 | Map file(colon + 1, O_RDONLY, PROT_READ, MAP_PRIVATE); 3296 | char *arge; 3297 | unsigned number(strtoul(string, &arge, 0)); 3298 | _assert(arge == colon); 3299 | auto &slot(slots[number]); 3300 | for (Algorithm *algorithm : GetAlgorithms()) 3301 | (*algorithm)(slot, file.data(), file.size()); 3302 | } break; 3303 | 3304 | case 'q': flag_q = true; break; 3305 | 3306 | case 'H': { 3307 | const char *hash = argv[argi] + 2; 3308 | 3309 | if (!flag_H) { 3310 | flag_H = true; 3311 | 3312 | do_sha1 = false; 3313 | do_sha256 = false; 3314 | 3315 | fprintf(stderr, "WARNING: -H is only present for compatibility with a fork of ldid\n"); 3316 | fprintf(stderr, " you should NOT be manually specifying the hash algorithm\n"); 3317 | } 3318 | 3319 | if (false); 3320 | else if (strcmp(hash, "sha1") == 0) 3321 | do_sha1 = true; 3322 | else if (strcmp(hash, "sha256") == 0) 3323 | do_sha256 = true; 3324 | else _assert(false); 3325 | } break; 3326 | 3327 | case 'h': flag_h = true; break; 3328 | 3329 | case 'Q': { 3330 | const char *xml = argv[argi] + 2; 3331 | requirements.open(xml, O_RDONLY, PROT_READ, MAP_PRIVATE); 3332 | } break; 3333 | 3334 | case 'D': flag_D = true; break; 3335 | case 'd': flag_d = true; break; 3336 | 3337 | case 'a': flag_a = true; break; 3338 | 3339 | case 'A': 3340 | _assert(!flag_A); 3341 | flag_A = true; 3342 | if (argv[argi][2] != '\0') { 3343 | const char *cpu = argv[argi] + 2; 3344 | const char *colon = strchr(cpu, ':'); 3345 | _assert(colon != NULL); 3346 | char *arge; 3347 | flag_CPUType = strtoul(cpu, &arge, 0); 3348 | _assert(arge == colon); 3349 | flag_CPUSubtype = strtoul(colon + 1, &arge, 0); 3350 | _assert(arge == argv[argi] + strlen(argv[argi])); 3351 | } 3352 | break; 3353 | 3354 | case 'C': { 3355 | const char *name = argv[argi] + 2; 3356 | if (false); 3357 | else if (strcmp(name, "host") == 0) 3358 | flags |= kSecCodeSignatureHost; 3359 | else if (strcmp(name, "adhoc") == 0) 3360 | flags |= kSecCodeSignatureAdhoc; 3361 | else if (strcmp(name, "hard") == 0) 3362 | flags |= kSecCodeSignatureForceHard; 3363 | else if (strcmp(name, "kill") == 0) 3364 | flags |= kSecCodeSignatureForceKill; 3365 | else if (strcmp(name, "expires") == 0) 3366 | flags |= kSecCodeSignatureForceExpiration; 3367 | else if (strcmp(name, "restrict") == 0) 3368 | flags |= kSecCodeSignatureRestrict; 3369 | else if (strcmp(name, "enforcement") == 0) 3370 | flags |= kSecCodeSignatureEnforcement; 3371 | else if (strcmp(name, "library-validation") == 0) 3372 | flags |= kSecCodeSignatureLibraryValidation; 3373 | else if (strcmp(name, "runtime") == 0) 3374 | flags |= kSecCodeSignatureRuntime; 3375 | else _assert(false); 3376 | } break; 3377 | 3378 | case 'P': 3379 | platform = true; 3380 | break; 3381 | 3382 | case 's': 3383 | _assert(!flag_r); 3384 | _assert(!flag_S); 3385 | flag_s = true; 3386 | break; 3387 | 3388 | case 'S': 3389 | _assert(!flag_r); 3390 | _assert(!flag_s); 3391 | flag_S = true; 3392 | if (argv[argi][2] != '\0') { 3393 | const char *xml = argv[argi] + 2; 3394 | entitlements.open(xml, O_RDONLY, PROT_READ, MAP_PRIVATE); 3395 | } 3396 | break; 3397 | 3398 | case 'M': 3399 | flag_M = true; 3400 | break; 3401 | 3402 | case 'K': 3403 | if (argv[argi][2] != '\0') 3404 | key.open(argv[argi] + 2, O_RDONLY, PROT_READ, MAP_PRIVATE); 3405 | break; 3406 | 3407 | #ifndef LDID_NOFLAGT 3408 | case 'T': { 3409 | flag_T = true; 3410 | if (argv[argi][2] == '-') 3411 | timeh = true; 3412 | else { 3413 | char *arge; 3414 | timev = strtoul(argv[argi] + 2, &arge, 0); 3415 | _assert(arge == argv[argi] + strlen(argv[argi])); 3416 | } 3417 | } break; 3418 | #endif 3419 | 3420 | case 'u': { 3421 | flag_u = true; 3422 | } break; 3423 | 3424 | case 'I': { 3425 | flag_I = argv[argi] + 2; 3426 | } break; 3427 | 3428 | default: 3429 | usage(argv[0]); 3430 | return 1; 3431 | break; 3432 | } 3433 | 3434 | _assert(flag_S || key.empty()); 3435 | _assert(flag_S || flag_I == NULL); 3436 | 3437 | if (flag_d && !flag_h) { 3438 | flag_h = true; 3439 | fprintf(stderr, "WARNING: -d also (temporarily) does the behavior of -h for compatibility with a fork of ldid\n"); 3440 | } 3441 | 3442 | if (files.empty()) 3443 | return 0; 3444 | 3445 | size_t filei(0), filee(0); 3446 | _foreach (file, files) try { 3447 | std::string path(file); 3448 | 3449 | struct stat info; 3450 | _syscall(stat(path.c_str(), &info)); 3451 | 3452 | if (S_ISDIR(info.st_mode)) { 3453 | _assert(flag_S); 3454 | #ifndef LDID_NOPLIST 3455 | ldid::DiskFolder folder(path + "/"); 3456 | path += "/" + Sign("", folder, key, requirements, ldid::fun([&](const std::string &, const std::string &) -> std::string { return entitlements; }), dummy_).path; 3457 | #else 3458 | _assert(false); 3459 | #endif 3460 | } else if (flag_S || flag_r) { 3461 | Map input(path, O_RDONLY, PROT_READ, MAP_PRIVATE); 3462 | 3463 | std::filebuf output; 3464 | Split split(path); 3465 | auto temp(Temporary(output, split)); 3466 | 3467 | if (flag_r) 3468 | ldid::Unsign(input.data(), input.size(), output, dummy_); 3469 | else { 3470 | std::string identifier(flag_I ?: split.base.c_str()); 3471 | ldid::Sign(input.data(), input.size(), output, identifier, entitlements, flag_M, requirements, key, slots, flags, platform, dummy_); 3472 | } 3473 | 3474 | Commit(path, temp); 3475 | } 3476 | 3477 | bool modify(false); 3478 | #ifndef LDID_NOFLAGT 3479 | if (flag_T) 3480 | modify = true; 3481 | #endif 3482 | if (flag_s) 3483 | modify = true; 3484 | 3485 | Map mapping(path, modify); 3486 | FatHeader fat_header(mapping.data(), mapping.size()); 3487 | 3488 | _foreach (mach_header, fat_header.GetMachHeaders()) { 3489 | struct linkedit_data_command *signature(NULL); 3490 | struct encryption_info_command *encryption(NULL); 3491 | 3492 | if (flag_A) { 3493 | if (mach_header.GetCPUType() != flag_CPUType) 3494 | continue; 3495 | if (mach_header.GetCPUSubtype() != flag_CPUSubtype) 3496 | continue; 3497 | } 3498 | 3499 | if (flag_a) 3500 | printf("cpu=0x%x:0x%x\n", mach_header.GetCPUType(), mach_header.GetCPUSubtype()); 3501 | 3502 | _foreach (load_command, mach_header.GetLoadCommands()) { 3503 | uint32_t cmd(mach_header.Swap(load_command->cmd)); 3504 | 3505 | if (false); 3506 | else if (cmd == LC_CODE_SIGNATURE) 3507 | signature = reinterpret_cast(load_command); 3508 | else if (cmd == LC_ENCRYPTION_INFO || cmd == LC_ENCRYPTION_INFO_64) 3509 | encryption = reinterpret_cast(load_command); 3510 | else if (cmd == LC_LOAD_DYLIB) { 3511 | volatile struct dylib_command *dylib_command(reinterpret_cast(load_command)); 3512 | const char *name(reinterpret_cast(load_command) + mach_header.Swap(dylib_command->dylib.name)); 3513 | 3514 | if (strcmp(name, "/System/Library/Frameworks/UIKit.framework/UIKit") == 0) { 3515 | if (flag_u) { 3516 | Version version; 3517 | version.value = mach_header.Swap(dylib_command->dylib.current_version); 3518 | printf("uikit=%u.%u.%u\n", version.major, version.minor, version.patch); 3519 | } 3520 | } 3521 | } 3522 | #ifndef LDID_NOFLAGT 3523 | else if (cmd == LC_ID_DYLIB) { 3524 | volatile struct dylib_command *dylib_command(reinterpret_cast(load_command)); 3525 | 3526 | if (flag_T) { 3527 | uint32_t timed; 3528 | 3529 | if (!timeh) 3530 | timed = timev; 3531 | else { 3532 | dylib_command->dylib.timestamp = 0; 3533 | timed = hash(reinterpret_cast(mach_header.GetBase()), mach_header.GetSize(), timev); 3534 | } 3535 | 3536 | dylib_command->dylib.timestamp = mach_header.Swap(timed); 3537 | } 3538 | } 3539 | #endif 3540 | } 3541 | 3542 | if (flag_d && encryption != NULL) { 3543 | printf("cryptid=%d\n", mach_header.Swap(encryption->cryptid)); 3544 | } 3545 | 3546 | if (flag_D) { 3547 | _assert(encryption != NULL); 3548 | encryption->cryptid = mach_header.Swap(0); 3549 | } 3550 | 3551 | if (flag_e) { 3552 | _assert(signature != NULL); 3553 | 3554 | uint32_t data = mach_header.Swap(signature->dataoff); 3555 | 3556 | uint8_t *top = reinterpret_cast(mach_header.GetBase()); 3557 | uint8_t *blob = top + data; 3558 | struct SuperBlob *super = reinterpret_cast(blob); 3559 | 3560 | for (size_t index(0); index != Swap(super->count); ++index) 3561 | if (Swap(super->index[index].type) == CSSLOT_ENTITLEMENTS) { 3562 | uint32_t begin = Swap(super->index[index].offset); 3563 | struct Blob *entitlements = reinterpret_cast(blob + begin); 3564 | fwrite(entitlements + 1, 1, Swap(entitlements->length) - sizeof(*entitlements), stdout); 3565 | } 3566 | } 3567 | 3568 | if (flag_q) { 3569 | _assert(signature != NULL); 3570 | 3571 | uint32_t data = mach_header.Swap(signature->dataoff); 3572 | 3573 | uint8_t *top = reinterpret_cast(mach_header.GetBase()); 3574 | uint8_t *blob = top + data; 3575 | struct SuperBlob *super = reinterpret_cast(blob); 3576 | 3577 | for (size_t index(0); index != Swap(super->count); ++index) 3578 | if (Swap(super->index[index].type) == CSSLOT_REQUIREMENTS) { 3579 | uint32_t begin = Swap(super->index[index].offset); 3580 | struct Blob *requirement = reinterpret_cast(blob + begin); 3581 | fwrite(requirement, 1, Swap(requirement->length), stdout); 3582 | } 3583 | } 3584 | 3585 | if (flag_s) { 3586 | _assert(signature != NULL); 3587 | 3588 | uint32_t data = mach_header.Swap(signature->dataoff); 3589 | 3590 | uint8_t *top = reinterpret_cast(mach_header.GetBase()); 3591 | uint8_t *blob = top + data; 3592 | struct SuperBlob *super = reinterpret_cast(blob); 3593 | 3594 | for (size_t index(0); index != Swap(super->count); ++index) 3595 | if (Swap(super->index[index].type) == CSSLOT_CODEDIRECTORY) { 3596 | uint32_t begin = Swap(super->index[index].offset); 3597 | struct CodeDirectory *directory = reinterpret_cast(blob + begin + sizeof(Blob)); 3598 | 3599 | uint8_t (*hashes)[LDID_SHA1_DIGEST_LENGTH] = reinterpret_cast(blob + begin + Swap(directory->hashOffset)); 3600 | uint32_t pages = Swap(directory->nCodeSlots); 3601 | 3602 | if (pages != 1) 3603 | for (size_t i = 0; i != pages - 1; ++i) 3604 | LDID_SHA1(top + PageSize_ * i, PageSize_, hashes[i]); 3605 | if (pages != 0) 3606 | LDID_SHA1(top + PageSize_ * (pages - 1), ((data - 1) % PageSize_) + 1, hashes[pages - 1]); 3607 | } 3608 | } 3609 | 3610 | if (flag_h) { 3611 | _assert(signature != NULL); 3612 | 3613 | auto algorithms(GetAlgorithms()); 3614 | 3615 | uint32_t data = mach_header.Swap(signature->dataoff); 3616 | 3617 | uint8_t *top = reinterpret_cast(mach_header.GetBase()); 3618 | uint8_t *blob = top + data; 3619 | struct SuperBlob *super = reinterpret_cast(blob); 3620 | 3621 | struct Candidate { 3622 | CodeDirectory *directory_; 3623 | size_t size_; 3624 | Algorithm &algorithm_; 3625 | std::string hash_; 3626 | }; 3627 | 3628 | std::map candidates; 3629 | 3630 | for (size_t index(0); index != Swap(super->count); ++index) { 3631 | auto type(Swap(super->index[index].type)); 3632 | if ((type == CSSLOT_CODEDIRECTORY || type >= CSSLOT_ALTERNATE) && type != CSSLOT_SIGNATURESLOT) { 3633 | uint32_t begin = Swap(super->index[index].offset); 3634 | uint32_t end = index + 1 == Swap(super->count) ? Swap(super->blob.length) : Swap(super->index[index + 1].offset); 3635 | struct CodeDirectory *directory = reinterpret_cast(blob + begin + sizeof(Blob)); 3636 | auto type(directory->hashType); 3637 | _assert(type > 0 && type <= algorithms.size()); 3638 | auto &algorithm(*algorithms[type - 1]); 3639 | uint8_t hash[algorithm.size_]; 3640 | algorithm(hash, blob + begin, end - begin); 3641 | candidates.insert({type, {directory, end - begin, algorithm, Hex(hash, 20)}}); 3642 | } 3643 | } 3644 | 3645 | _assert(!candidates.empty()); 3646 | auto best(candidates.end()); 3647 | --best; 3648 | 3649 | const auto directory(best->second.directory_); 3650 | const auto flags(Swap(directory->flags)); 3651 | 3652 | std::string names; 3653 | if (flags & kSecCodeSignatureHost) 3654 | names += ",host"; 3655 | if (flags & kSecCodeSignatureAdhoc) 3656 | names += ",adhoc"; 3657 | if (flags & kSecCodeSignatureForceHard) 3658 | names += ",hard"; 3659 | if (flags & kSecCodeSignatureForceKill) 3660 | names += ",kill"; 3661 | if (flags & kSecCodeSignatureForceExpiration) 3662 | names += ",expires"; 3663 | if (flags & kSecCodeSignatureRestrict) 3664 | names += ",restrict"; 3665 | if (flags & kSecCodeSignatureEnforcement) 3666 | names += ",enforcement"; 3667 | if (flags & kSecCodeSignatureLibraryValidation) 3668 | names += ",library-validation"; 3669 | if (flags & kSecCodeSignatureRuntime) 3670 | names += ",runtime"; 3671 | 3672 | printf("CodeDirectory v=%x size=%zd flags=0x%x(%s) hashes=%d+%d location=embedded\n", 3673 | Swap(directory->version), best->second.size_, flags, names.empty() ? "none" : names.c_str() + 1, Swap(directory->nCodeSlots), Swap(directory->nSpecialSlots)); 3674 | printf("Hash type=%s size=%d\n", best->second.algorithm_.name(), directory->hashSize); 3675 | 3676 | std::string choices; 3677 | for (const auto &candidate : candidates) { 3678 | auto choice(candidate.second.algorithm_.name()); 3679 | choices += ','; 3680 | choices += choice; 3681 | printf("CandidateCDHash %s=%s\n", choice, candidate.second.hash_.c_str()); 3682 | } 3683 | printf("Hash choices=%s\n", choices.c_str() + 1); 3684 | 3685 | printf("CDHash=%s\n", best->second.hash_.c_str()); 3686 | } 3687 | } 3688 | 3689 | ++filei; 3690 | } catch (const char *) { 3691 | ++filee; 3692 | ++filei; 3693 | } 3694 | 3695 | return filee; 3696 | } 3697 | #endif 3698 | --------------------------------------------------------------------------------