X-Git-Url: https://git.saurik.com/ldid.git/blobdiff_plain/4f63b59016d6952f0ddf408a3b1be97f10febc13..f1df48331fb84ccca058563bad51529107533f1c:/ldid.cpp?ds=sidebyside diff --git a/ldid.cpp b/ldid.cpp index a4dc725..4ad9b2f 100644 --- a/ldid.cpp +++ b/ldid.cpp @@ -94,23 +94,27 @@ #define _assert__(line) \ _assert___(line) +#ifndef $ +#define $(value) value +#endif + #ifdef __EXCEPTIONS #define _assert_(expr, format, ...) \ do if (!(expr)) { \ - fprintf(stderr, "%s(%u): _assert(): " format "\n", __FILE__, __LINE__, ## __VA_ARGS__); \ - throw __FILE__ "(" _assert__(__LINE__) "): _assert(" #expr ")"; \ + fprintf(stderr, $("%s(%u): _assert(): " format "\n"), __FILE__, __LINE__, ## __VA_ARGS__); \ + throw $(__FILE__ "(" _assert__(__LINE__) "): _assert(" #expr ")"); \ } while (false) #else // XXX: this is not acceptable #define _assert_(expr, format, ...) \ do if (!(expr)) { \ - fprintf(stderr, "%s(%u): _assert(): " format "\n", __FILE__, __LINE__, ## __VA_ARGS__); \ + fprintf(stderr, $("%s(%u): _assert(): " format "\n"), __FILE__, __LINE__, ## __VA_ARGS__); \ exit(-1); \ } while (false) #endif #define _assert(expr) \ - _assert_(expr, "%s", #expr) + _assert_(expr, "%s", $(#expr)) #define _syscall(expr, ...) [&] { for (;;) { \ auto _value(expr); \ @@ -127,7 +131,7 @@ } }() #define _trace() \ - fprintf(stderr, "_trace(%s:%u): %s\n", __FILE__, __LINE__, __FUNCTION__) + fprintf(stderr, $("_trace(%s:%u): %s\n"), __FILE__, __LINE__, $(__FUNCTION__)) #define _not(type) \ ((type) ~ (type) 0) @@ -475,6 +479,8 @@ struct encryption_info_command { #define BIND_OPCODE_DO_BIND_ADD_ADDR_IMM_SCALED 0xb0 #define BIND_OPCODE_DO_BIND_ULEB_TIMES_SKIPPING_ULEB 0xc0 +static auto dummy([](double) {}); + static std::streamsize read(std::streambuf &stream, void *data, size_t size) { auto writ(stream.sgetn(static_cast(data), size)); _assert(writ >= 0); @@ -489,6 +495,16 @@ static inline void put(std::streambuf &stream, const void *data, size_t size) { _assert(stream.sputn(static_cast(data), size) == size); } +static inline void put(std::streambuf &stream, const void *data, size_t size, const ldid::Functor &percent) { + percent(0); + for (size_t total(0); total != size;) { + auto writ(std::min(size - total, size_t(4096 * 4))); + _assert(stream.sputn(static_cast(data) + total, writ) == writ); + total += writ; + percent(double(total) / size); + } +} + static size_t most(std::streambuf &stream, void *data, size_t size) { size_t total(size); while (size > 0) @@ -807,10 +823,14 @@ class FatHeader : #define CSSLOT_RESOURCEDIR uint32_t(0x00003) #define CSSLOT_APPLICATION uint32_t(0x00004) #define CSSLOT_ENTITLEMENTS uint32_t(0x00005) +#define CSSLOT_ALTERNATE uint32_t(0x01000) #define CSSLOT_SIGNATURESLOT uint32_t(0x10000) -#define CS_HASHTYPE_SHA1 1 +#define CS_HASHTYPE_SHA160_160 1 +#define CS_HASHTYPE_SHA256_256 2 +#define CS_HASHTYPE_SHA256_160 3 +#define CS_HASHTYPE_SHA386_386 4 struct BlobIndex { uint32_t type; @@ -843,21 +863,141 @@ struct CodeDirectory { uint32_t spare2; uint32_t scatterOffset; uint32_t teamIDOffset; - uint32_t spare3; - uint64_t codeLimit64; + //uint32_t spare3; + //uint64_t codeLimit64; } _packed; +enum Kind : uint32_t { + exprForm = 1, // prefix expr form +}; + +enum ExprOp : uint32_t { + opFalse, // unconditionally false + opTrue, // unconditionally true + opIdent, // match canonical code [string] + opAppleAnchor, // signed by Apple as Apple's product + opAnchorHash, // match anchor [cert hash] + opInfoKeyValue, // *legacy* - use opInfoKeyField [key; value] + opAnd, // binary prefix expr AND expr [expr; expr] + opOr, // binary prefix expr OR expr [expr; expr] + opCDHash, // match hash of CodeDirectory directly [cd hash] + opNot, // logical inverse [expr] + opInfoKeyField, // Info.plist key field [string; match suffix] + opCertField, // Certificate field [cert index; field name; match suffix] + opTrustedCert, // require trust settings to approve one particular cert [cert index] + opTrustedCerts, // require trust settings to approve the cert chain + opCertGeneric, // Certificate component by OID [cert index; oid; match suffix] + opAppleGenericAnchor, // signed by Apple in any capacity + opEntitlementField, // entitlement dictionary field [string; match suffix] + opCertPolicy, // Certificate policy by OID [cert index; oid; match suffix] + opNamedAnchor, // named anchor type + opNamedCode, // named subroutine + opPlatform, // platform constraint [integer] + exprOpCount // (total opcode count in use) +}; + +enum MatchOperation { + matchExists, // anything but explicit "false" - no value stored + matchEqual, // equal (CFEqual) + matchContains, // partial match (substring) + matchBeginsWith, // partial match (initial substring) + matchEndsWith, // partial match (terminal substring) + matchLessThan, // less than (string with numeric comparison) + matchGreaterThan, // greater than (string with numeric comparison) + matchLessEqual, // less or equal (string with numeric comparison) + matchGreaterEqual, // greater or equal (string with numeric comparison) +}; + +#define OID_ISO_MEMBER 42 +#define OID_US OID_ISO_MEMBER, 134, 72 +#define APPLE_OID OID_US, 0x86, 0xf7, 0x63 +#define APPLE_ADS_OID APPLE_OID, 0x64 +#define APPLE_EXTENSION_OID APPLE_ADS_OID, 6 + #ifndef LDID_NOFLAGT extern "C" uint32_t hash(uint8_t *k, uint32_t length, uint32_t initval); #endif -static void sha1(uint8_t *hash, const void *data, size_t size) { - LDID_SHA1(static_cast(data), size, hash); -} +struct Algorithm { + size_t size_; + uint8_t type_; + + Algorithm(size_t size, uint8_t type) : + size_(size), + type_(type) + { + } + + virtual const uint8_t *operator [](const ldid::Hash &hash) const = 0; + + virtual void operator ()(uint8_t *hash, const void *data, size_t size) const = 0; + virtual void operator ()(ldid::Hash &hash, const void *data, size_t size) const = 0; + virtual void operator ()(std::vector &hash, const void *data, size_t size) const = 0; +}; + +struct AlgorithmSHA1 : + Algorithm +{ + AlgorithmSHA1() : + Algorithm(LDID_SHA1_DIGEST_LENGTH, CS_HASHTYPE_SHA160_160) + { + } + + virtual const uint8_t *operator [](const ldid::Hash &hash) const { + return hash.sha1_; + } + + void operator ()(uint8_t *hash, const void *data, size_t size) const { + LDID_SHA1(static_cast(data), size, hash); + } + + void operator ()(ldid::Hash &hash, const void *data, size_t size) const { + return operator()(hash.sha1_, data, size); + } + + void operator ()(std::vector &hash, const void *data, size_t size) const { + hash.resize(LDID_SHA1_DIGEST_LENGTH); + return operator ()(reinterpret_cast(hash.data()), data, size); + } +}; + +struct AlgorithmSHA256 : + Algorithm +{ + AlgorithmSHA256() : + Algorithm(LDID_SHA256_DIGEST_LENGTH, CS_HASHTYPE_SHA256_256) + { + } + + virtual const uint8_t *operator [](const ldid::Hash &hash) const { + return hash.sha256_; + } -static void sha1(std::vector &hash, const void *data, size_t size) { - hash.resize(LDID_SHA1_DIGEST_LENGTH); - sha1(reinterpret_cast(hash.data()), data, size); + void operator ()(uint8_t *hash, const void *data, size_t size) const { + LDID_SHA256(static_cast(data), size, hash); + } + + void operator ()(ldid::Hash &hash, const void *data, size_t size) const { + return operator()(hash.sha256_, data, size); + } + + void operator ()(std::vector &hash, const void *data, size_t size) const { + hash.resize(LDID_SHA256_DIGEST_LENGTH); + return operator ()(reinterpret_cast(hash.data()), data, size); + } +}; + +static const std::vector &GetAlgorithms() { + static AlgorithmSHA1 sha1; + static AlgorithmSHA256 sha256; + + static Algorithm *array[] = { + &sha1, + &sha256, + }; + + static std::vector algorithms(array, array + sizeof(array) / sizeof(array[0])); + return algorithms; } struct CodesignAllocation { @@ -982,7 +1122,35 @@ class Map { namespace ldid { -static void Allocate(const void *idata, size_t isize, std::streambuf &output, const Functor &allocate, const Functor &save) { +std::string Analyze(const void *data, size_t size) { + std::string entitlements; + + FatHeader fat_header(const_cast(data), size); + _foreach (mach_header, fat_header.GetMachHeaders()) + _foreach (load_command, mach_header.GetLoadCommands()) + if (mach_header.Swap(load_command->cmd) == LC_CODE_SIGNATURE) { + auto signature(reinterpret_cast(load_command)); + auto offset(mach_header.Swap(signature->dataoff)); + auto pointer(reinterpret_cast(mach_header.GetBase()) + offset); + auto super(reinterpret_cast(pointer)); + + for (size_t index(0); index != Swap(super->count); ++index) + if (Swap(super->index[index].type) == CSSLOT_ENTITLEMENTS) { + auto begin(Swap(super->index[index].offset)); + auto blob(reinterpret_cast(pointer + begin)); + auto writ(Swap(blob->length) - sizeof(*blob)); + + if (entitlements.empty()) + entitlements.assign(reinterpret_cast(blob + 1), writ); + else + _assert(entitlements.compare(0, entitlements.size(), reinterpret_cast(blob + 1), writ) == 0); + } + } + + return entitlements; +} + +static void Allocate(const void *idata, size_t isize, std::streambuf &output, const Functor &allocate, const Functor &)> &save, const Functor &percent) { FatHeader source(const_cast(idata), isize); size_t offset(0); @@ -1162,13 +1330,13 @@ static void Allocate(const void *idata, size_t isize, std::streambuf &output, co std::string overlap(altern.str()); overlap.append(top + overlap.size(), Align(overlap.size(), 0x1000) - overlap.size()); - put(output, top + (position - begin), allocation.size_ - (position - begin)); + put(output, top + (position - begin), allocation.size_ - (position - begin), percent); position = begin + allocation.size_; pad(output, allocation.limit_ - allocation.size_); position += allocation.limit_ - allocation.size_; - size_t saved(save(mach_header, output, allocation.limit_, overlap, top)); + size_t saved(save(mach_header, output, allocation.limit_, overlap, top, percent)); if (allocation.alloc_ > saved) pad(output, allocation.alloc_ - saved); else @@ -1286,8 +1454,13 @@ class Stuff { { _assert(value_ != NULL); _assert(PKCS12_parse(value_, "", &key_, &cert_, &ca_) != 0); + _assert(key_ != NULL); _assert(cert_ != NULL); + + if (ca_ == NULL) + ca_ = sk_X509_new_null(); + _assert(ca_ != NULL); } Stuff(const std::string &data) : @@ -1324,10 +1497,35 @@ class Signature { PKCS7 *value_; public: - Signature(const Stuff &stuff, const Buffer &data) : - value_(PKCS7_sign(stuff, stuff, stuff, data, PKCS7_BINARY | PKCS7_DETACHED)) - { + Signature(const Stuff &stuff, const Buffer &data, const std::string &xml) { + value_ = PKCS7_new(); _assert(value_ != NULL); + + _assert(PKCS7_set_type(value_, NID_pkcs7_signed)); + _assert(PKCS7_content_new(value_, NID_pkcs7_data)); + + STACK_OF(X509) *certs(stuff); + for (unsigned i(0), e(sk_X509_num(certs)); i != e; i++) + _assert(PKCS7_add_certificate(value_, sk_X509_value(certs, e - i - 1))); + + auto info(PKCS7_sign_add_signer(value_, stuff, stuff, NULL, PKCS7_NOSMIMECAP)); + _assert(info != NULL); + + PKCS7_set_detached(value_, 1); + + ASN1_OCTET_STRING *string(ASN1_OCTET_STRING_new()); + _assert(string != NULL); + try { + _assert(ASN1_STRING_set(string, xml.data(), xml.size())); + + static auto nid(OBJ_create("1.2.840.113635.100.9.1", "", "")); + _assert(PKCS7_add_signed_attribute(info, nid, V_ASN1_OCTET_STRING, string)); + } catch (...) { + ASN1_OCTET_STRING_free(string); + throw; + } + + _assert(PKCS7_final(value_, data, PKCS7_BINARY)); } ~Signature() { @@ -1353,27 +1551,22 @@ class NullBuffer : } }; -class Hash { +class Digest { public: - char sha1_[LDID_SHA1_DIGEST_LENGTH]; - char sha256_[LDID_SHA256_DIGEST_LENGTH]; - - operator std::vector() const { - return {sha1_, sha1_ + sizeof(sha1_)}; - } + uint8_t sha1_[LDID_SHA1_DIGEST_LENGTH]; }; class HashBuffer : public std::streambuf { private: - Hash &hash_; + ldid::Hash &hash_; LDID_SHA1_CTX sha1_; LDID_SHA256_CTX sha256_; public: - HashBuffer(Hash &hash) : + HashBuffer(ldid::Hash &hash) : hash_(hash) { LDID_SHA1_Init(&sha1_); @@ -1407,7 +1600,7 @@ class HashProxy : std::streambuf &buffer_; public: - HashProxy(Hash &hash, std::streambuf &buffer) : + HashProxy(ldid::Hash &hash, std::streambuf &buffer) : HashBuffer(hash), buffer_(buffer) { @@ -1478,39 +1671,107 @@ static void Commit(const std::string &path, const std::string &temp) { namespace ldid { -std::vector Sign(const void *idata, size_t isize, std::streambuf &output, const std::string &identifier, const std::string &entitlements, const std::string &requirement, const std::string &key, const Slots &slots) { - std::vector hash(LDID_SHA1_DIGEST_LENGTH); +static void get(std::string &value, X509_NAME *name, int nid) { + auto index(X509_NAME_get_index_by_NID(name, nid, -1)); + _assert(index >= 0); + auto next(X509_NAME_get_index_by_NID(name, nid, index)); + _assert(next == -1); + auto entry(X509_NAME_get_entry(name, index)); + _assert(entry != NULL); + auto asn(X509_NAME_ENTRY_get_data(entry)); + _assert(asn != NULL); + value.assign(reinterpret_cast(ASN1_STRING_data(asn)), ASN1_STRING_length(asn)); +} + +static void req(std::streambuf &buffer, uint32_t value) { + value = Swap(value); + put(buffer, &value, sizeof(value)); +} + +static void req(std::streambuf &buffer, const std::string &value) { + req(buffer, value.size()); + put(buffer, value.data(), value.size()); + static uint8_t zeros[] = {0,0,0,0}; + put(buffer, zeros, 3 - (value.size() + 3) % 4); +} + +template +static void req(std::streambuf &buffer, uint8_t (&&data)[Size_]) { + req(buffer, Size_); + put(buffer, data, Size_); + static uint8_t zeros[] = {0,0,0,0}; + put(buffer, zeros, 3 - (Size_ + 3) % 4); +} + +Hash Sign(const void *idata, size_t isize, std::streambuf &output, const std::string &identifier, const std::string &entitlements, const std::string &requirements, const std::string &key, const Slots &slots, const Functor &percent) { + Hash hash; + std::string team; + std::string common; #ifndef LDID_NOSMIME if (!key.empty()) { Stuff stuff(key); auto name(X509_get_subject_name(stuff)); _assert(name != NULL); - auto index(X509_NAME_get_index_by_NID(name, NID_organizationalUnitName, -1)); - _assert(index >= 0); - auto next(X509_NAME_get_index_by_NID(name, NID_organizationalUnitName, index)); - _assert(next == -1); - auto entry(X509_NAME_get_entry(name, index)); - _assert(entry != NULL); - auto asn(X509_NAME_ENTRY_get_data(entry)); - _assert(asn != NULL); - team.assign(reinterpret_cast(ASN1_STRING_data(asn)), ASN1_STRING_length(asn)); + get(team, name, NID_organizationalUnitName); + get(common, name, NID_commonName); } #endif + + std::stringbuf backing; + + if (!requirements.empty()) { + put(backing, requirements.data(), requirements.size()); + } else { + Blobs blobs; + + std::stringbuf requirement; + req(requirement, exprForm); + req(requirement, opAnd); + req(requirement, opIdent); + req(requirement, identifier); + req(requirement, opAnd); + req(requirement, opAppleGenericAnchor); + req(requirement, opAnd); + req(requirement, opCertField); + req(requirement, 0); + req(requirement, "subject.CN"); + req(requirement, matchEqual); + req(requirement, common); + req(requirement, opCertGeneric); + req(requirement, 1); + req(requirement, (uint8_t []) {APPLE_EXTENSION_OID, 2, 1}); + req(requirement, matchExists); + insert(blobs, 3, CSMAGIC_REQUIREMENT, requirement); + + put(backing, CSMAGIC_REQUIREMENTS, blobs); + } + + + // XXX: this is just a "sufficiently large number" + size_t certificate(0x3000); + Allocate(idata, isize, output, fun([&](const MachHeader &mach_header, size_t size) -> size_t { size_t alloc(sizeof(struct SuperBlob)); + uint32_t normal((size + PageSize_ - 1) / PageSize_); + uint32_t special(0); + _foreach (slot, slots) + special = std::max(special, slot.first); + + mach_header.ForSection(fun([&](const char *segment, const char *section, void *data, size_t size) { + if (strcmp(segment, "__TEXT") == 0 && section != NULL && strcmp(section, "__info_plist") == 0) + special = std::max(special, CSSLOT_INFOSLOT); + })); + special = std::max(special, CSSLOT_REQUIREMENTS); alloc += sizeof(struct BlobIndex); - if (requirement.empty()) - alloc += 0xc; - else - alloc += requirement.size(); + alloc += backing.str().size(); if (!entitlements.empty()) { special = std::max(special, CSSLOT_ENTITLEMENTS); @@ -1519,47 +1780,33 @@ std::vector Sign(const void *idata, size_t isize, std::streambuf &output, alloc += entitlements.size(); } - special = std::max(special, CSSLOT_CODEDIRECTORY); - alloc += sizeof(struct BlobIndex); - alloc += sizeof(struct Blob); - alloc += sizeof(struct CodeDirectory); - alloc += identifier.size() + 1; + size_t directory(0); + + directory += sizeof(struct BlobIndex); + directory += sizeof(struct Blob); + directory += sizeof(struct CodeDirectory); + directory += identifier.size() + 1; if (!team.empty()) - alloc += team.size() + 1; + directory += team.size() + 1; + for (Algorithm *algorithm : GetAlgorithms()) + alloc = Align(alloc + directory + (special + normal) * algorithm->size_, 16); + +#ifndef LDID_NOSMIME if (!key.empty()) { alloc += sizeof(struct BlobIndex); alloc += sizeof(struct Blob); - // XXX: this is just a "sufficiently large number" - alloc += 0x3000; + alloc += certificate; } +#endif - _foreach (slot, slots) - special = std::max(special, slot.first); - - mach_header.ForSection(fun([&](const char *segment, const char *section, void *data, size_t size) { - if (strcmp(segment, "__TEXT") == 0 && section != NULL && strcmp(section, "__info_plist") == 0) - special = std::max(special, CSSLOT_INFOSLOT); - })); - - uint32_t normal((size + PageSize_ - 1) / PageSize_); - alloc = Align(alloc + (special + normal) * LDID_SHA1_DIGEST_LENGTH, 16); return alloc; - }), fun([&](const MachHeader &mach_header, std::streambuf &output, size_t limit, const std::string &overlap, const char *top) -> size_t { + }), fun([&](const MachHeader &mach_header, std::streambuf &output, size_t limit, const std::string &overlap, const char *top, const Functor &percent) -> size_t { Blobs blobs; if (true) { - std::stringbuf data; - - if (requirement.empty()) { - Blobs requirements; - put(data, CSMAGIC_REQUIREMENTS, requirements); - } else { - put(data, requirement.data(), requirement.size()); - } - - insert(blobs, CSSLOT_REQUIREMENTS, data); + insert(blobs, CSSLOT_REQUIREMENTS, backing); } if (!entitlements.empty()) { @@ -1568,15 +1815,21 @@ std::vector Sign(const void *idata, size_t isize, std::streambuf &output, insert(blobs, CSSLOT_ENTITLEMENTS, CSMAGIC_EMBEDDED_ENTITLEMENTS, data); } - if (true) { - std::stringbuf data; + Slots posts(slots); + + mach_header.ForSection(fun([&](const char *segment, const char *section, void *data, size_t size) { + if (strcmp(segment, "__TEXT") == 0 && section != NULL && strcmp(section, "__info_plist") == 0) { + auto &slot(posts[CSSLOT_INFOSLOT]); + for (Algorithm *algorithm : GetAlgorithms()) + (*algorithm)(slot, data, size); + } + })); - Slots posts(slots); + unsigned total(0); + for (Algorithm *pointer : GetAlgorithms()) { + Algorithm &algorithm(*pointer); - mach_header.ForSection(fun([&](const char *segment, const char *section, void *data, size_t size) { - if (strcmp(segment, "__TEXT") == 0 && section != NULL && strcmp(section, "__info_plist") == 0) - sha1(posts[CSSLOT_INFOSLOT], data, size); - })); + std::stringbuf data; uint32_t special(0); _foreach (blob, blobs) @@ -1591,14 +1844,14 @@ std::vector Sign(const void *idata, size_t isize, std::streambuf &output, directory.nSpecialSlots = Swap(special); directory.codeLimit = Swap(uint32_t(limit)); directory.nCodeSlots = Swap(normal); - directory.hashSize = LDID_SHA1_DIGEST_LENGTH; - directory.hashType = CS_HASHTYPE_SHA1; + directory.hashSize = algorithm.size_; + directory.hashType = algorithm.type_; directory.spare1 = 0x00; directory.pageSize = PageShift_; directory.spare2 = Swap(uint32_t(0)); directory.scatterOffset = Swap(uint32_t(0)); - directory.spare3 = Swap(uint32_t(0)); - directory.codeLimit64 = Swap(uint64_t(0)); + //directory.spare3 = Swap(uint32_t(0)); + //directory.codeLimit64 = Swap(uint64_t(0)); uint32_t offset(sizeof(Blob) + sizeof(CodeDirectory)); @@ -1612,75 +1865,107 @@ std::vector Sign(const void *idata, size_t isize, std::streambuf &output, offset += team.size() + 1; } - offset += LDID_SHA1_DIGEST_LENGTH * special; + offset += special * algorithm.size_; directory.hashOffset = Swap(uint32_t(offset)); - offset += LDID_SHA1_DIGEST_LENGTH * normal; + offset += normal * algorithm.size_; put(data, &directory, sizeof(directory)); put(data, identifier.c_str(), identifier.size() + 1); - put(data, team.c_str(), team.size() + 1); + if (!team.empty()) + put(data, team.c_str(), team.size() + 1); - uint8_t storage[special + normal][LDID_SHA1_DIGEST_LENGTH]; - uint8_t (*hashes)[LDID_SHA1_DIGEST_LENGTH] = storage + special; + std::vector storage((special + normal) * algorithm.size_); + auto *hashes(&storage[special * algorithm.size_]); - memset(storage, 0, sizeof(*storage) * special); + memset(storage.data(), 0, special * algorithm.size_); _foreach (blob, blobs) { auto local(reinterpret_cast(&blob.second[0])); - sha1((uint8_t *) (hashes - blob.first), local, Swap(local->length)); + algorithm(hashes - blob.first * algorithm.size_, local, Swap(local->length)); } - _foreach (slot, posts) { - _assert(sizeof(*hashes) == slot.second.size()); - memcpy(hashes - slot.first, slot.second.data(), slot.second.size()); - } + _foreach (slot, posts) + memcpy(hashes - slot.first * algorithm.size_, algorithm[slot.second], algorithm.size_); + percent(0); if (normal != 1) - for (size_t i = 0; i != normal - 1; ++i) - sha1(hashes[i], (PageSize_ * i < overlap.size() ? overlap.data() : top) + PageSize_ * i, PageSize_); + for (size_t i = 0; i != normal - 1; ++i) { + algorithm(hashes + i * algorithm.size_, (PageSize_ * i < overlap.size() ? overlap.data() : top) + PageSize_ * i, PageSize_); + percent(double(i) / normal); + } if (normal != 0) - sha1(hashes[normal - 1], top + PageSize_ * (normal - 1), ((limit - 1) % PageSize_) + 1); + algorithm(hashes + (normal - 1) * algorithm.size_, top + PageSize_ * (normal - 1), ((limit - 1) % PageSize_) + 1); + percent(1); + + put(data, storage.data(), storage.size()); - put(data, storage, sizeof(storage)); + const auto &save(insert(blobs, total == 0 ? CSSLOT_CODEDIRECTORY : CSSLOT_ALTERNATE + total - 1, CSMAGIC_CODEDIRECTORY, data)); + algorithm(hash, save.data(), save.size()); - const auto &save(insert(blobs, CSSLOT_CODEDIRECTORY, CSMAGIC_CODEDIRECTORY, data)); - sha1(hash, save.data(), save.size()); + ++total; } #ifndef LDID_NOSMIME if (!key.empty()) { + auto plist(plist_new_dict()); + _scope({ plist_free(plist); }); + + auto cdhashes(plist_new_array()); + plist_dict_set_item(plist, "cdhashes", cdhashes); + + unsigned total(0); + for (Algorithm *pointer : GetAlgorithms()) { + Algorithm &algorithm(*pointer); + (void) algorithm; + + const auto &blob(blobs[total == 0 ? CSSLOT_CODEDIRECTORY : CSSLOT_ALTERNATE + total - 1]); + ++total; + + std::vector hash; + algorithm(hash, blob.data(), blob.size()); + hash.resize(20); + + plist_array_append_item(cdhashes, plist_new_data(hash.data(), hash.size())); + } + + char *xml(NULL); + uint32_t size; + plist_to_xml(plist, &xml, &size); + _scope({ free(xml); }); + std::stringbuf data; const std::string &sign(blobs[CSSLOT_CODEDIRECTORY]); Stuff stuff(key); Buffer bio(sign); - Signature signature(stuff, sign); + Signature signature(stuff, sign, std::string(xml, size)); Buffer result(signature); std::string value(result); put(data, value.data(), value.size()); - insert(blobs, CSSLOT_SIGNATURESLOT, CSMAGIC_BLOBWRAPPER, data); + const auto &save(insert(blobs, CSSLOT_SIGNATURESLOT, CSMAGIC_BLOBWRAPPER, data)); + _assert(save.size() <= certificate); } #endif return put(output, CSMAGIC_EMBEDDED_SIGNATURE, blobs); - })); + }), percent); return hash; } #ifndef LDID_NOTOOLS -static void Unsign(void *idata, size_t isize, std::streambuf &output) { +static void Unsign(void *idata, size_t isize, std::streambuf &output, const Functor &percent) { Allocate(idata, isize, output, fun([](const MachHeader &mach_header, size_t size) -> size_t { return 0; - }), fun([](const MachHeader &mach_header, std::streambuf &output, size_t limit, const std::string &overlap, const char *top) -> size_t { + }), fun([](const MachHeader &mach_header, std::streambuf &output, size_t limit, const std::string &overlap, const char *top, const Functor &percent) -> size_t { return 0; - })); + }), percent); } -std::string DiskFolder::Path(const std::string &path) { +std::string DiskFolder::Path(const std::string &path) const { return path_ + "/" + path; } @@ -1711,7 +1996,7 @@ std::string readlink(const std::string &path) { } #endif -void DiskFolder::Find(const std::string &root, const std::string &base, const Functor &)> &)> &code, const Functor &)> &link) { +void DiskFolder::Find(const std::string &root, const std::string &base, const Functor &code, const Functor &)> &link) const { std::string path(Path(root) + base); DIR *dir(opendir(path.c_str())); @@ -1756,37 +2041,38 @@ void DiskFolder::Find(const std::string &root, const std::string &base, const Fu if (directory) Find(root, base + name + "/", code, link); else - code(base + name, fun([&](const Functor &code) { - std::string access(root + base + name); - Open(access, fun([&](std::streambuf &data, const void *flag) { - auto from(path + name); - std::filebuf save; - commit_[from] = Temporary(save, from); - code(data, save); - })); - })); + code(base + name); } } -void DiskFolder::Save(const std::string &path, const void *flag, const Functor &code) { - std::filebuf save; - auto from(Path(path)); - commit_[from] = Temporary(save, from); - code(save); +void DiskFolder::Save(const std::string &path, bool edit, const void *flag, const Functor &code) { + if (!edit) { + // XXX: use nullbuf + std::stringbuf save; + code(save); + } else { + std::filebuf save; + auto from(Path(path)); + commit_[from] = Temporary(save, from); + code(save); + } } -bool DiskFolder::Look(const std::string &path) { +bool DiskFolder::Look(const std::string &path) const { return _syscall(access(Path(path).c_str(), R_OK), ENOENT) == 0; } -void DiskFolder::Open(const std::string &path, const Functor &code) { +void DiskFolder::Open(const std::string &path, const Functor &code) const { std::filebuf data; auto result(data.open(Path(path).c_str(), std::ios::binary | std::ios::in)); _assert_(result == &data, "DiskFolder::Open(%s)", path.c_str()); - code(data, NULL); + + auto length(data.pubseekoff(0, std::ios::end, std::ios::in)); + data.pubseekpos(0, std::ios::in); + code(data, length, NULL); } -void DiskFolder::Find(const std::string &path, const Functor &)> &)> &code, const Functor &)> &link) { +void DiskFolder::Find(const std::string &path, const Functor &code, const Functor &)> &link) const { Find(path, "", code, link); } #endif @@ -1797,38 +2083,32 @@ SubFolder::SubFolder(Folder &parent, const std::string &path) : { } -void SubFolder::Save(const std::string &path, const void *flag, const Functor &code) { - return parent_.Save(path_ + path, flag, code); +void SubFolder::Save(const std::string &path, bool edit, const void *flag, const Functor &code) { + return parent_.Save(path_ + path, edit, flag, code); } -bool SubFolder::Look(const std::string &path) { +bool SubFolder::Look(const std::string &path) const { return parent_.Look(path_ + path); } -void SubFolder::Open(const std::string &path, const Functor &code) { +void SubFolder::Open(const std::string &path, const Functor &code) const { return parent_.Open(path_ + path, code); } -void SubFolder::Find(const std::string &path, const Functor &)> &)> &code, const Functor &)> &link) { +void SubFolder::Find(const std::string &path, const Functor &code, const Functor &)> &link) const { return parent_.Find(path_ + path, code, link); } -std::string UnionFolder::Map(const std::string &path) { +std::string UnionFolder::Map(const std::string &path) const { auto remap(remaps_.find(path)); if (remap == remaps_.end()) return path; return remap->second; } -void UnionFolder::Map(const std::string &path, const Functor &)> &)> &code, const std::string &file, const Functor &)> &save) { +void UnionFolder::Map(const std::string &path, const Functor &code, const std::string &file, const Functor &)> &save) const { if (file.size() >= path.size() && file.substr(0, path.size()) == path) - code(file.substr(path.size()), fun([&](const Functor &code) { - save(fun([&](std::streambuf &data, const void *flag) { - parent_.Save(file, flag, fun([&](std::streambuf &save) { - code(data, save); - })); - })); - })); + code(file.substr(path.size())); } UnionFolder::UnionFolder(Folder &parent) : @@ -1836,64 +2116,68 @@ UnionFolder::UnionFolder(Folder &parent) : { } -void UnionFolder::Save(const std::string &path, const void *flag, const Functor &code) { - return parent_.Save(Map(path), flag, code); +void UnionFolder::Save(const std::string &path, bool edit, const void *flag, const Functor &code) { + return parent_.Save(Map(path), edit, flag, code); } -bool UnionFolder::Look(const std::string &path) { +bool UnionFolder::Look(const std::string &path) const { auto file(resets_.find(path)); if (file != resets_.end()) return true; return parent_.Look(Map(path)); } -void UnionFolder::Open(const std::string &path, const Functor &code) { +void UnionFolder::Open(const std::string &path, const Functor &code) const { auto file(resets_.find(path)); if (file == resets_.end()) return parent_.Open(Map(path), code); auto &entry(file->second); - auto &data(entry.first); + auto &data(*entry.data_); + auto length(data.pubseekoff(0, std::ios::end, std::ios::in)); data.pubseekpos(0, std::ios::in); - code(data, entry.second); + code(data, length, entry.flag_); } -void UnionFolder::Find(const std::string &path, const Functor &)> &)> &code, const Functor &)> &link) { - parent_.Find(path, fun([&](const std::string &name, const Functor &)> &save) { - if (deletes_.find(path + name) == deletes_.end()) - code(name, save); - }), fun([&](const std::string &name, const Functor &read) { - if (deletes_.find(path + name) == deletes_.end()) - link(name, read); - })); - +void UnionFolder::Find(const std::string &path, const Functor &code, const Functor &)> &link) const { for (auto &reset : resets_) - Map(path, code, reset.first, fun([&](const Functor &code) { + Map(path, code, reset.first, fun([&](const Functor &code) { auto &entry(reset.second); - entry.first.pubseekpos(0, std::ios::in); - code(entry.first, entry.second); + auto &data(*entry.data_); + auto length(data.pubseekoff(0, std::ios::end, std::ios::in)); + data.pubseekpos(0, std::ios::in); + code(data, length, entry.flag_); })); for (auto &remap : remaps_) - Map(path, code, remap.first, fun([&](const Functor &code) { - parent_.Open(remap.second, fun([&](std::streambuf &data, const void *flag) { - code(data, flag); + Map(path, code, remap.first, fun([&](const Functor &code) { + parent_.Open(remap.second, fun([&](std::streambuf &data, size_t length, const void *flag) { + code(data, length, flag); })); })); + + parent_.Find(path, fun([&](const std::string &name) { + if (deletes_.find(path + name) == deletes_.end()) + code(name); + }), fun([&](const std::string &name, const Functor &read) { + if (deletes_.find(path + name) == deletes_.end()) + link(name, read); + })); } #ifndef LDID_NOTOOLS -static size_t copy(std::streambuf &source, std::streambuf &target) { +static void copy(std::streambuf &source, std::streambuf &target, size_t length, const ldid::Functor &percent) { + percent(0); size_t total(0); for (;;) { - char data[4096]; + char data[4096 * 4]; size_t writ(source.sgetn(data, sizeof(data))); if (writ == 0) break; _assert(target.sputn(data, writ) == writ); total += writ; + percent(double(total) / length); } - return total; } #ifndef LDID_NOPLIST @@ -1907,9 +2191,9 @@ static plist_t plist(const std::string &data) { return plist; } -static void plist_d(std::streambuf &buffer, const Functor &code) { +static void plist_d(std::streambuf &buffer, size_t length, const Functor &code) { std::stringbuf data; - copy(buffer, data); + copy(buffer, data, length, ldid::fun(dummy)); auto node(plist(data.str())); _scope({ plist_free(node); }); _assert(plist_get_node_type(node) == PLIST_DICT); @@ -2011,18 +2295,20 @@ struct RuleCode { }; #ifndef LDID_NOPLIST -static std::vector Sign(const uint8_t *prefix, size_t size, std::streambuf &buffer, Hash &hash, std::streambuf &save, const std::string &identifier, const std::string &entitlements, const std::string &requirement, const std::string &key, const Slots &slots) { +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, const std::string &requirements, const std::string &key, const Slots &slots, size_t length, const Functor &percent) { // XXX: this is a miserable fail std::stringbuf temp; put(temp, prefix, size); - copy(buffer, temp); + copy(buffer, temp, length - size, percent); + // XXX: this is a stupid hack + pad(temp, 0x10 - (length & 0xf)); auto data(temp.str()); HashProxy proxy(hash, save); - return Sign(data.data(), data.size(), proxy, identifier, entitlements, requirement, key, slots); + return Sign(data.data(), data.size(), proxy, identifier, entitlements, requirements, key, slots, percent); } -Bundle Sign(const std::string &root, Folder &folder, const std::string &key, std::map &remote, const std::string &entitlements, const std::string &requirement) { +Bundle Sign(const std::string &root, Folder &folder, const std::string &key, std::map &remote, const std::string &requirements, const Functor &alter, const Functor &progress, const Functor &percent) { std::string executable; std::string identifier; @@ -2034,8 +2320,8 @@ Bundle Sign(const std::string &root, Folder &folder, const std::string &key, std info = "Resources/" + info; } - folder.Open(info, fun([&](std::streambuf &buffer, const void *flag) { - plist_d(buffer, fun([&](plist_t node) { + folder.Open(info, fun([&](std::streambuf &buffer, size_t length, const void *flag) { + plist_d(buffer, length, fun([&](plist_t node) { executable = plist_s(plist_dict_get_item(node, "CFBundleExecutable")); identifier = plist_s(plist_dict_get_item(node, "CFBundleIdentifier")); })); @@ -2046,6 +2332,17 @@ Bundle Sign(const std::string &root, Folder &folder, const std::string &key, std mac = true; } + std::string entitlements; + folder.Open(executable, fun([&](std::streambuf &buffer, size_t length, const void *flag) { + // XXX: this is a miserable fail + std::stringbuf temp; + copy(buffer, temp, length, percent); + // XXX: this is a stupid hack + pad(temp, 0x10 - (length & 0xf)); + auto data(temp.str()); + entitlements = alter(root, Analyze(data.data(), data.size())); + })); + static const std::string directory("_CodeSignature/"); static const std::string signature(directory + "CodeResources"); @@ -2058,10 +2355,9 @@ Bundle Sign(const std::string &root, Folder &folder, const std::string &key, std if (true) { rules1.insert(Rule{1, NoMode, "^" + resources}); - if (!mac) rules1.insert(Rule{10000, OmitMode, "^(Frameworks/[^/]+\\.framework/|PlugIns/[^/]+\\.appex/|PlugIns/[^/]+\\.appex/Frameworks/[^/]+\\.framework/|())SC_Info/[^/]+\\.(sinf|supf|supp)$"}); rules1.insert(Rule{1000, OptionalMode, "^" + resources + ".*\\.lproj/"}); rules1.insert(Rule{1100, OmitMode, "^" + resources + ".*\\.lproj/locversion.plist$"}); - if (!mac) rules1.insert(Rule{10000, OmitMode, "^Watch/[^/]+\\.app/(Frameworks/[^/]+\\.framework/|PlugIns/[^/]+\\.appex/|PlugIns/[^/]+\\.appex/Frameworks/[^/]+\\.framework/)SC_Info/[^/]+\\.(sinf|supf|supp)$"}); + rules1.insert(Rule{1010, NoMode, "^Base\\.lproj/"}); rules1.insert(Rule{1, NoMode, "^version.plist$"}); } @@ -2069,14 +2365,13 @@ Bundle Sign(const std::string &root, Folder &folder, const std::string &key, std rules2.insert(Rule{11, NoMode, ".*\\.dSYM($|/)"}); rules2.insert(Rule{20, NoMode, "^" + resources}); rules2.insert(Rule{2000, OmitMode, "^(.*/)?\\.DS_Store$"}); - if (!mac) rules2.insert(Rule{10000, OmitMode, "^(Frameworks/[^/]+\\.framework/|PlugIns/[^/]+\\.appex/|PlugIns/[^/]+\\.appex/Frameworks/[^/]+\\.framework/|())SC_Info/[^/]+\\.(sinf|supf|supp)$"}); rules2.insert(Rule{10, NestedMode, "^(Frameworks|SharedFrameworks|PlugIns|Plug-ins|XPCServices|Helpers|MacOS|Library/(Automator|Spotlight|LoginItems))/"}); rules2.insert(Rule{1, NoMode, "^.*"}); rules2.insert(Rule{1000, OptionalMode, "^" + resources + ".*\\.lproj/"}); rules2.insert(Rule{1100, OmitMode, "^" + resources + ".*\\.lproj/locversion.plist$"}); + rules2.insert(Rule{1010, NoMode, "^Base\\.lproj/"}); rules2.insert(Rule{20, OmitMode, "^Info\\.plist$"}); rules2.insert(Rule{20, OmitMode, "^PkgInfo$"}); - if (!mac) rules2.insert(Rule{10000, OmitMode, "^Watch/[^/]+\\.app/(Frameworks/[^/]+\\.framework/|PlugIns/[^/]+\\.appex/|PlugIns/[^/]+\\.appex/Frameworks/[^/]+\\.framework/)SC_Info/[^/]+\\.(sinf|supf|supp)$"}); rules2.insert(Rule{10, NestedMode, "^[^/]+$"}); rules2.insert(Rule{20, NoMode, "^embedded\\.provisionprofile$"}); rules2.insert(Rule{20, NoMode, "^version\\.plist$"}); @@ -2088,13 +2383,16 @@ Bundle Sign(const std::string &root, Folder &folder, const std::string &key, std Expression nested("^(Frameworks/[^/]*\\.framework|PlugIns/[^/]*\\.appex(()|/[^/]*.app))/(" + failure + ")Info\\.plist$"); std::map bundles; - folder.Find("", fun([&](const std::string &name, const Functor &)> &code) { + folder.Find("", fun([&](const std::string &name) { if (!nested(name)) return; auto bundle(root + Split(name).dir); bundle.resize(bundle.size() - resources.size()); SubFolder subfolder(folder, bundle); - bundles[nested[1]] = Sign(bundle, subfolder, key, local, "", ""); + + bundles[nested[1]] = Sign(bundle, subfolder, key, local, "", Starts(name, "PlugIns/") ? alter : + static_cast &>(fun([&](const std::string &, const std::string &entitlements) -> std::string { return entitlements; })) + , progress, percent); }), fun([&](const std::string &name, const Functor &read) { })); @@ -2116,7 +2414,7 @@ Bundle Sign(const std::string &root, Folder &folder, const std::string &key, std std::map links; - folder.Find("", fun([&](const std::string &name, const Functor &)> &code) { + folder.Find("", fun([&](const std::string &name) { if (exclude(name)) return; @@ -2124,7 +2422,9 @@ Bundle Sign(const std::string &root, Folder &folder, const std::string &key, std return; auto &hash(local[name]); - code(fun([&](std::streambuf &data, std::streambuf &save) { + folder.Open(name, fun([&](std::streambuf &data, size_t length, const void *flag) { + progress(root + name); + union { struct { uint32_t magic; @@ -2145,14 +2445,18 @@ Bundle Sign(const std::string &root, Folder &folder, const std::string &key, std case FAT_CIGAM: case MH_MAGIC: case MH_MAGIC_64: case MH_CIGAM: case MH_CIGAM_64: - Slots slots; - Sign(header.bytes, size, data, hash, save, identifier, "", "", key, slots); + folder.Save(name, true, flag, fun([&](std::streambuf &save) { + Slots slots; + Sign(header.bytes, size, data, hash, save, identifier, "", "", key, slots, length, percent); + })); return; } - HashProxy proxy(hash, save); - put(proxy, header.bytes, size); - copy(data, proxy); + folder.Save(name, false, flag, fun([&](std::streambuf &save) { + HashProxy proxy(hash, save); + put(proxy, header.bytes, size); + copy(data, proxy, length - size, percent); + })); })); }), fun([&](const std::string &name, const Functor &read) { if (exclude(name)) @@ -2178,12 +2482,12 @@ Bundle Sign(const std::string &root, Folder &folder, const std::string &key, std if (rule(hash.first)) { if (!old && mac && excludes.find(hash.first) != excludes.end()); else if (old && rule.mode_ == NoMode) - plist_dict_set_item(files, hash.first.c_str(), plist_new_data(hash.second.sha1_, sizeof(hash.second.sha1_))); + plist_dict_set_item(files, hash.first.c_str(), plist_new_data(reinterpret_cast(hash.second.sha1_), sizeof(hash.second.sha1_))); else if (rule.mode_ != OmitMode) { auto entry(plist_new_dict()); - plist_dict_set_item(entry, "hash", plist_new_data(hash.second.sha1_, sizeof(hash.second.sha1_))); + plist_dict_set_item(entry, "hash", plist_new_data(reinterpret_cast(hash.second.sha1_), sizeof(hash.second.sha1_))); if (!old) - plist_dict_set_item(entry, "hash2", plist_new_data(hash.second.sha256_, sizeof(hash.second.sha256_))); + plist_dict_set_item(entry, "hash2", plist_new_data(reinterpret_cast(hash.second.sha256_), sizeof(hash.second.sha256_))); if (rule.mode_ == OptionalMode) plist_dict_set_item(entry, "optional", plist_new_bool(true)); plist_dict_set_item(files, hash.first.c_str(), entry); @@ -2209,7 +2513,7 @@ Bundle Sign(const std::string &root, Folder &folder, const std::string &key, std if (!old && mac) for (const auto &bundle : bundles) { auto entry(plist_new_dict()); - plist_dict_set_item(entry, "cdhash", plist_new_data(bundle.second.hash.data(), bundle.second.hash.size())); + plist_dict_set_item(entry, "cdhash", plist_new_data(reinterpret_cast(bundle.second.hash.sha256_), sizeof(bundle.second.hash.sha256_))); plist_dict_set_item(entry, "requirement", plist_new_string("anchor apple generic")); plist_dict_set_item(files, bundle.first.c_str(), entry); } @@ -2254,7 +2558,7 @@ Bundle Sign(const std::string &root, Folder &folder, const std::string &key, std } } - folder.Save(signature, NULL, fun([&](std::streambuf &save) { + folder.Save(signature, true, NULL, fun([&](std::streambuf &save) { HashProxy proxy(local[signature], save); char *xml(NULL); uint32_t size; @@ -2266,12 +2570,13 @@ Bundle Sign(const std::string &root, Folder &folder, const std::string &key, std Bundle bundle; bundle.path = executable; - folder.Open(executable, fun([&](std::streambuf &buffer, const void *flag) { - folder.Save(executable, flag, fun([&](std::streambuf &save) { + folder.Open(executable, fun([&](std::streambuf &buffer, size_t length, const void *flag) { + progress(root + executable); + folder.Save(executable, true, flag, fun([&](std::streambuf &save) { Slots slots; slots[1] = local.at(info); slots[3] = local.at(signature); - bundle.hash = Sign(NULL, 0, buffer, local[executable], save, identifier, entitlements, requirement, key, slots); + bundle.hash = Sign(NULL, 0, buffer, local[executable], save, identifier, entitlements, requirements, key, slots, length, percent); })); })); @@ -2281,9 +2586,9 @@ Bundle Sign(const std::string &root, Folder &folder, const std::string &key, std return bundle; } -Bundle Sign(const std::string &root, Folder &folder, const std::string &key, const std::string &entitlements, const std::string &requirement) { +Bundle Sign(const std::string &root, Folder &folder, const std::string &key, const std::string &requirements, const Functor &alter, const Functor &progress, const Functor &percent) { std::map local; - return Sign(root, folder, key, local, entitlements, requirement); + return Sign(root, folder, key, local, requirements, alter, progress, percent); } #endif @@ -2332,7 +2637,7 @@ int main(int argc, char *argv[]) { #endif Map entitlements; - Map requirement; + Map requirements; Map key; ldid::Slots slots; @@ -2359,21 +2664,23 @@ int main(int argc, char *argv[]) { case 'e': flag_e = true; break; case 'E': { - const char *slot = argv[argi] + 2; - const char *colon = strchr(slot, ':'); + const char *string = argv[argi] + 2; + const char *colon = strchr(string, ':'); _assert(colon != NULL); Map file(colon + 1, O_RDONLY, PROT_READ, MAP_PRIVATE); char *arge; - unsigned number(strtoul(slot, &arge, 0)); + unsigned number(strtoul(string, &arge, 0)); _assert(arge == colon); - sha1(slots[number], file.data(), file.size()); + auto &slot(slots[number]); + for (Algorithm *algorithm : GetAlgorithms()) + (*algorithm)(slot, file.data(), file.size()); } break; case 'q': flag_q = true; break; case 'Q': { const char *xml = argv[argi] + 2; - requirement.open(xml, O_RDONLY, PROT_READ, MAP_PRIVATE); + requirements.open(xml, O_RDONLY, PROT_READ, MAP_PRIVATE); } break; case 'D': flag_D = true; break; @@ -2460,7 +2767,9 @@ int main(int argc, char *argv[]) { #ifndef LDID_NOPLIST _assert(!flag_r); ldid::DiskFolder folder(path); - path += "/" + Sign("", folder, key, entitlements, requirement).path; + path += "/" + Sign("", folder, key, requirements, ldid::fun([&](const std::string &, const std::string &) -> std::string { return entitlements; }) + , ldid::fun([&](const std::string &) {}), ldid::fun(dummy) + ).path; #else _assert(false); #endif @@ -2472,10 +2781,10 @@ int main(int argc, char *argv[]) { auto temp(Temporary(output, split)); if (flag_r) - ldid::Unsign(input.data(), input.size(), output); + ldid::Unsign(input.data(), input.size(), output, ldid::fun(dummy)); else { std::string identifier(flag_I ?: split.base.c_str()); - ldid::Sign(input.data(), input.size(), output, identifier, entitlements, requirement, key, slots); + ldid::Sign(input.data(), input.size(), output, identifier, entitlements, requirements, key, slots, ldid::fun(dummy)); } Commit(path, temp); @@ -2604,9 +2913,9 @@ int main(int argc, char *argv[]) { if (pages != 1) for (size_t i = 0; i != pages - 1; ++i) - sha1(hashes[i], top + PageSize_ * i, PageSize_); + LDID_SHA1(top + PageSize_ * i, PageSize_, hashes[i]); if (pages != 0) - sha1(hashes[pages - 1], top + PageSize_ * (pages - 1), ((data - 1) % PageSize_) + 1); + LDID_SHA1(top + PageSize_ * (pages - 1), ((data - 1) % PageSize_) + 1, hashes[pages - 1]); } } }