X-Git-Url: https://git.saurik.com/ldid.git/blobdiff_plain/803b4bc92ff17691d9bb22334e3f4968158e3fc8..a23f0faadd29ec00a6b7fb2498c3d15af15a7100:/ldid.cpp?ds=sidebyside diff --git a/ldid.cpp b/ldid.cpp index bd8fb5b..0d4cb73 100644 --- a/ldid.cpp +++ b/ldid.cpp @@ -515,6 +515,10 @@ static std::streamsize read(std::streambuf &stream, void *data, size_t size) { return writ; } +static inline void put(std::streambuf &stream, uint8_t value) { + _assert(stream.sputc(value) != EOF); +} + static inline void get(std::streambuf &stream, void *data, size_t size) { _assert(read(stream, data, size) == size); } @@ -533,6 +537,10 @@ static inline void put(std::streambuf &stream, const void *data, size_t size, co } } +static inline void put(std::streambuf &stream, const std::string &data) { + return put(stream, data.data(), data.size()); +} + static size_t most(std::streambuf &stream, void *data, size_t size) { size_t total(size); while (size > 0) @@ -559,6 +567,156 @@ Type_ Align(Type_ value, size_t align) { static const uint8_t PageShift_(0x0c); static const uint32_t PageSize_(1 << PageShift_); +static inline unsigned bytes(uint64_t value) { + return (64 - __builtin_clzll(value) + 7) / 8; +} + +static void put(std::streambuf &stream, uint64_t value, size_t length) { + length *= 8; + do put(stream, uint8_t(value >> (length -= 8))); + while (length != 0); +} + +static void der(std::streambuf &stream, uint64_t value) { + if (value < 128) + put(stream, value); + else { + unsigned length(bytes(value)); + put(stream, 0x80 | length); + put(stream, value, length); + } +} + +static std::string der(uint8_t tag, const char *value, size_t length) { + std::stringbuf data; + put(data, tag); + der(data, length); + put(data, value, length); + return data.str(); +} + +static std::string der(uint8_t tag, const char *value) { + return der(tag, value, strlen(value)); } +static std::string der(uint8_t tag, const std::string &value) { + return der(tag, value.data(), value.size()); } + +template +static void der_(std::stringbuf &data, const Type_ &values) { + size_t size(0); + for (const auto &value : values) + size += value.size(); + der(data, size); + for (const auto &value : values) + put(data, value); +} + +static std::string der(const std::vector &values) { + std::stringbuf data; + put(data, 0x30); + der_(data, values); + return data.str(); +} + +static std::string der(const std::multiset &values) { + std::stringbuf data; + put(data, 0x31); + der_(data, values); + return data.str(); +} + +static std::string der(const std::pair &value) { + const auto key(der(0x0c, value.first)); + std::stringbuf data; + put(data, 0x30); + der(data, key.size() + value.second.size()); + put(data, key); + put(data, value.second); + return data.str(); +} + +#ifndef LDID_NOPLIST +static std::string der(plist_t data) { + switch (const auto type = plist_get_node_type(data)) { + case PLIST_BOOLEAN: { + uint8_t value(0); + plist_get_bool_val(data, &value); + + std::stringbuf data; + put(data, 0x01); + der(data, 1); + put(data, value != 0 ? 1 : 0); + return data.str(); + } break; + + case PLIST_UINT: { + uint64_t value; + plist_get_uint_val(data, &value); + const auto length(bytes(value)); + + std::stringbuf data; + put(data, 0x02); + der(data, length); + put(data, value, length); + return data.str(); + } break; + + case PLIST_REAL: { + _assert(false); + } break; + + case PLIST_DATE: { + _assert(false); + } break; + + case PLIST_DATA: { + char *value; + uint64_t length; + plist_get_data_val(data, &value, &length); + _scope({ free(value); }); + return der(0x04, value, length); + } break; + + case PLIST_STRING: { + char *value; + plist_get_string_val(data, &value); + _scope({ free(value); }); + return der(0x0c, value); + } break; + + case PLIST_ARRAY: { + std::vector values; + for (auto e(plist_array_get_size(data)), i(decltype(e)(0)); i != e; ++i) + values.push_back(der(plist_array_get_item(data, i))); + return der(values); + } break; + + case PLIST_DICT: { + std::multiset values; + + plist_dict_iter iterator(NULL); + plist_dict_new_iter(data, &iterator); + _scope({ free(iterator); }); + + for (;;) { + char *key(NULL); + plist_t value(NULL); + plist_dict_next_item(data, iterator, &key, &value); + if (key == NULL) + break; + _scope({ free(key); }); + values.insert(der(std::make_pair(key, der(value)))); + } + + return der(values); + } break; + + default: { + _assert_(false, "unsupported plist type %d", type); + } break; + } +} +#endif + static inline uint16_t Swap_(uint16_t value) { return ((value >> 8) & 0x00ff) | @@ -843,6 +1001,7 @@ class FatHeader : #define CSMAGIC_EMBEDDED_SIGNATURE uint32_t(0xfade0cc0) #define CSMAGIC_EMBEDDED_SIGNATURE_OLD uint32_t(0xfade0b02) #define CSMAGIC_EMBEDDED_ENTITLEMENTS uint32_t(0xfade7171) +#define CSMAGIC_EMBEDDED_DERFORMAT uint32_t(0xfade7172) // name? #define CSMAGIC_DETACHED_SIGNATURE uint32_t(0xfade0cc1) #define CSMAGIC_BLOBWRAPPER uint32_t(0xfade0b01) @@ -852,6 +1011,8 @@ class FatHeader : #define CSSLOT_RESOURCEDIR uint32_t(0x00003) #define CSSLOT_APPLICATION uint32_t(0x00004) #define CSSLOT_ENTITLEMENTS uint32_t(0x00005) +#define CSSLOT_REPSPECIFIC uint32_t(0x00006) // name? +#define CSSLOT_DERFORMAT uint32_t(0x00007) // name? #define CSSLOT_ALTERNATE uint32_t(0x01000) #define CSSLOT_SIGNATURESLOT uint32_t(0x10000) @@ -1092,11 +1253,12 @@ static const std::vector &GetAlgorithms() { struct Baton { std::string entitlements_; + std::string derformat_; }; struct CodesignAllocation { FatMachHeader mach_header_; - uint32_t offset_; + uint64_t offset_; uint32_t size_; uint64_t limit_; uint32_t alloc_; @@ -1361,14 +1523,27 @@ static void Allocate(const void *idata, size_t isize, std::streambuf &output, co put(output, &fat_header, sizeof(fat_header)); position += sizeof(fat_header); + // XXX: support fat_arch_64 (not in my toolchain) + // probably use C++14 generic lambda (not in my toolchain) + + _assert_(![&]() { + _foreach (allocation, allocations) { + const auto offset(allocation.offset_); + const auto size(allocation.limit_ + allocation.alloc_); + if (uint32_t(offset) != offset || uint32_t(size) != size) + return true; + } + return false; + }(), "FAT slice >=4GiB not currently supported"); + _foreach (allocation, allocations) { auto &mach_header(allocation.mach_header_); fat_arch fat_arch; fat_arch.cputype = Swap(mach_header->cputype); fat_arch.cpusubtype = Swap(mach_header->cpusubtype); - fat_arch.offset = Swap(allocation.offset_); - fat_arch.size = Swap(allocation.limit_ + allocation.alloc_); + fat_arch.offset = Swap(uint32_t(allocation.offset_)); + fat_arch.size = Swap(uint32_t(allocation.limit_ + allocation.alloc_)); fat_arch.align = Swap(allocation.align_); put(output, &fat_arch, sizeof(fat_arch)); position += sizeof(fat_arch); @@ -1938,50 +2113,47 @@ Hash Sign(const void *idata, size_t isize, std::streambuf &output, const std::st alloc += sizeof(struct BlobIndex); alloc += backing.str().size(); - if (!merge) - baton.entitlements_ = entitlements; - else { -#ifndef LDID_NOPLIST +#ifdef LDID_NOPLIST + baton.entitlements_ = entitlements; +#else + if (merge) Analyze(mach_header, fun([&](const char *data, size_t size) { baton.entitlements_.assign(data, size); })); - if (baton.entitlements_.empty()) - baton.entitlements_ = entitlements; - else if (!entitlements.empty()) { - auto combined(plist(baton.entitlements_)); - _scope({ plist_free(combined); }); - _assert(plist_get_node_type(combined) == PLIST_DICT); - - auto merging(plist(entitlements)); - _scope({ plist_free(merging); }); - _assert(plist_get_node_type(merging) == PLIST_DICT); - - plist_dict_iter iterator(NULL); - plist_dict_new_iter(merging, &iterator); - _scope({ free(iterator); }); - - for (;;) { - char *key(NULL); - plist_t value(NULL); - plist_dict_next_item(merging, iterator, &key, &value); - if (key == NULL) - break; - _scope({ free(key); }); - plist_dict_set_item(combined, key, plist_copy(value)); - } + if (!baton.entitlements_.empty() || !entitlements.empty()) { + auto combined(plist(baton.entitlements_)); + _scope({ plist_free(combined); }); + _assert(plist_get_node_type(combined) == PLIST_DICT); + + auto merging(plist(entitlements)); + _scope({ plist_free(merging); }); + _assert(plist_get_node_type(merging) == PLIST_DICT); - char *xml(NULL); - uint32_t size; - plist_to_xml(combined, &xml, &size); - _scope({ free(xml); }); + plist_dict_iter iterator(NULL); + plist_dict_new_iter(merging, &iterator); + _scope({ free(iterator); }); - baton.entitlements_.assign(xml, size); + for (;;) { + char *key(NULL); + plist_t value(NULL); + plist_dict_next_item(merging, iterator, &key, &value); + if (key == NULL) + break; + _scope({ free(key); }); + plist_dict_set_item(combined, key, plist_copy(value)); } -#else - _assert(false); -#endif + + baton.derformat_ = der(combined); + + char *xml(NULL); + uint32_t size; + plist_to_xml(combined, &xml, &size); + _scope({ free(xml); }); + + baton.entitlements_.assign(xml, size); } +#endif if (!baton.entitlements_.empty()) { special = std::max(special, CSSLOT_ENTITLEMENTS); @@ -1990,6 +2162,13 @@ Hash Sign(const void *idata, size_t isize, std::streambuf &output, const std::st alloc += baton.entitlements_.size(); } + if (!baton.derformat_.empty()) { + special = std::max(special, CSSLOT_DERFORMAT); + alloc += sizeof(struct BlobIndex); + alloc += sizeof(struct Blob); + alloc += baton.derformat_.size(); + } + size_t directory(0); directory += sizeof(struct BlobIndex); @@ -2059,6 +2238,12 @@ Hash Sign(const void *idata, size_t isize, std::streambuf &output, const std::st #endif } + if (!baton.derformat_.empty()) { + std::stringbuf data; + put(data, baton.derformat_.data(), baton.derformat_.size()); + insert(blobs, CSSLOT_DERFORMAT, CSMAGIC_EMBEDDED_DERFORMAT, data); + } + Slots posts(slots); mach_header.ForSection(fun([&](const char *segment, const char *section, void *data, size_t size) { @@ -2318,8 +2503,7 @@ void DiskFolder::Find(const std::string &root, const std::string &base, const Fu void DiskFolder::Save(const std::string &path, bool edit, const void *flag, const Functor &code) { if (!edit) { - // XXX: use nullbuf - std::stringbuf save; + NullBuffer save; code(save); } else { std::filebuf save; @@ -2458,6 +2642,8 @@ static void copy(std::streambuf &source, std::streambuf &target, size_t length, #ifndef LDID_NOPLIST static plist_t plist(const std::string &data) { + if (data.empty()) + return plist_new_dict(); plist_t plist(NULL); if (Starts(data, "bplist00")) plist_from_bin(data.data(), data.size(), &plist); @@ -2938,6 +3124,7 @@ int main(int argc, char *argv[]) { bool flag_s(false); bool flag_D(false); + bool flag_d(false); bool flag_A(false); bool flag_a(false); @@ -3027,6 +3214,7 @@ int main(int argc, char *argv[]) { } break; case 'D': flag_D = true; break; + case 'd': flag_d = true; break; case 'a': flag_a = true; break; @@ -3128,6 +3316,11 @@ int main(int argc, char *argv[]) { _assert(flag_S || key.empty()); _assert(flag_S || flag_I == NULL); + if (flag_d && !flag_h) { + flag_h = true; + fprintf(stderr, "WARNING: -d also (temporarily) does the behavior of -h for compatibility with a fork of ldid\n"); + } + if (files.empty()) return 0; @@ -3138,9 +3331,9 @@ int main(int argc, char *argv[]) { struct stat info; _syscall(stat(path.c_str(), &info)); - if (flag_S && S_ISDIR(info.st_mode)) { + if (S_ISDIR(info.st_mode)) { + _assert(flag_S); #ifndef LDID_NOPLIST - _assert(!flag_r); ldid::DiskFolder folder(path + "/"); path += "/" + Sign("", folder, key, requirements, ldid::fun([&](const std::string &, const std::string &) -> std::string { return entitlements; }), dummy_).path; #else @@ -3228,6 +3421,10 @@ int main(int argc, char *argv[]) { #endif } + if (flag_d && encryption != NULL) { + printf("cryptid=%d\n", mach_header.Swap(encryption->cryptid)); + } + if (flag_D) { _assert(encryption != NULL); encryption->cryptid = mach_header.Swap(0);