X-Git-Url: https://git.cameronkatri.com/ldid.git/blobdiff_plain/1adec13f09b0b0310bcb741853fbe9a73b078b22..9685c0d6ce74c677b1b3141a8a885f73e137de31:/ldid.cpp diff --git a/ldid.cpp b/ldid.cpp index 13e34ff..d188458 100644 --- a/ldid.cpp +++ b/ldid.cpp @@ -20,6 +20,7 @@ **/ /* }}} */ +#include #include #include #include @@ -43,36 +44,16 @@ #include #include -#ifndef LDID_NOSMIME #include # if OPENSSL_VERSION_MAJOR >= 3 # include # endif #include #include -#include #include #include #include -#endif -#ifdef __APPLE__ -#include - -#define LDID_SHA1_DIGEST_LENGTH CC_SHA1_DIGEST_LENGTH -#define LDID_SHA1 CC_SHA1 -#define LDID_SHA1_CTX CC_SHA1_CTX -#define LDID_SHA1_Init CC_SHA1_Init -#define LDID_SHA1_Update CC_SHA1_Update -#define LDID_SHA1_Final CC_SHA1_Final - -#define LDID_SHA256_DIGEST_LENGTH CC_SHA256_DIGEST_LENGTH -#define LDID_SHA256 CC_SHA256 -#define LDID_SHA256_CTX CC_SHA256_CTX -#define LDID_SHA256_Init CC_SHA256_Init -#define LDID_SHA256_Update CC_SHA256_Update -#define LDID_SHA256_Final CC_SHA256_Final -#else #include #define LDID_SHA1_DIGEST_LENGTH SHA_DIGEST_LENGTH @@ -88,13 +69,8 @@ #define LDID_SHA256_Init SHA256_Init #define LDID_SHA256_Update SHA256_Update #define LDID_SHA256_Final SHA256_Final -#endif -#ifndef LDID_NOPLIST #include -#elif __APPLE__ -#include -#endif #include "ldid.hpp" @@ -151,9 +127,8 @@ #define _packed \ __attribute__((packed)) -#ifndef LDID_NOSMIME std::string password; -#endif +std::vector cleanup; template struct Iterator_ { @@ -549,41 +524,6 @@ static inline void pad(std::streambuf &stream, size_t size) { put(stream, padding, size); } -/* - * Heavily based on zsign's _GenerateASN1Type(): https://github.com/zhlynn/zsign/blob/44f15cae53e4a5a000fa7486dd72f472a4c75ee4/openssl.cpp#L116 - * SPDX-License-Identifier: BSD-3-Clause OR AGPL-3.0-only - */ -static ASN1_TYPE *GenerateASN1Type(const std::string &value) -{ - std::string asn1String = "asn1=SEQUENCE:A\n[A]\nC=OBJECT:sha256\nB=FORMAT:HEX,OCT:" + value + "\n"; - - BIO *bio = BIO_new(BIO_s_mem()); - BIO_puts(bio, asn1String.c_str()); - _scope({ BIO_free(bio); }); - - CONF *conf = NCONF_new(NULL); - _scope({ NCONF_free(conf); }); - - long line = -1; - int result = NCONF_load_bio(conf, bio, &line); - if (result <= 0) - { - printf("Error generating ASN1 Type: %d (Line %ld)\n", result, line); - ERR_print_errors_fp(stdout); - return NULL; - } - - char *string = NCONF_get_string(conf, "default", "asn1"); - if (string == NULL) - { - ERR_print_errors_fp(stdout); - return NULL; - } - - ASN1_TYPE *type = ASN1_generate_nconf(string, conf); - return type; -} - template Type_ Align(Type_ value, size_t align) { value += align - 1; @@ -662,7 +602,6 @@ static std::string der(const std::pair &value) { 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: { @@ -746,7 +685,6 @@ static std::string der(plist_t data) { } break; } } -#endif static inline uint16_t Swap_(uint16_t value) { return @@ -1183,9 +1121,6 @@ enum MatchOperation { #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 struct Algorithm { size_t size_; @@ -1347,14 +1282,6 @@ class Map { void *data_; size_t size_; - void clear() { - if (data_ == NULL) - return; - _syscall(munmap(data_, size_)); - data_ = NULL; - size_ = 0; - } - public: Map() : data_(NULL), @@ -1402,6 +1329,14 @@ class Map { open(path, O_RDONLY, PROT_READ, MAP_PRIVATE); } + void clear() { + if (data_ == NULL) + return; + _syscall(munmap(data_, size_)); + data_ = NULL; + size_ = 0; + } + void *data() const { return data_; } @@ -1414,13 +1349,11 @@ class Map { return std::string(static_cast(data_), size_); } }; -#endif +#endif // LDID_NOTOOLS namespace ldid { -#ifndef LDID_NOPLIST static plist_t plist(const std::string &data); -#endif void Analyze(const MachHeader &mach_header, const Functor &entitle) { _foreach (load_command, mach_header.GetLoadCommands()) @@ -1449,7 +1382,10 @@ std::string Analyze(const void *data, size_t size) { if (entitlements.empty()) entitlements.assign(data, size); else - _assert(entitlements.compare(0, entitlements.size(), data, size) == 0); + if (entitlements.compare(0, entitlements.size(), data, size) != 0) { + fprintf(stderr, "ldid: Entitlements do not match\n"); + exit(1); + } })); return entitlements; @@ -1469,8 +1405,7 @@ static void Allocate(const void *idata, size_t isize, std::streambuf &output, co _foreach (load_command, mach_header.GetLoadCommands()) { uint32_t cmd(mach_header.Swap(load_command->cmd)); - if (false); - else if (cmd == LC_CODE_SIGNATURE) + if (cmd == LC_CODE_SIGNATURE) signature = reinterpret_cast(load_command); else if (cmd == LC_SYMTAB) symtab = reinterpret_cast(load_command); @@ -1765,7 +1700,6 @@ static size_t put(std::streambuf &output, uint32_t magic, const Blobs &blobs) { return offset; } -#ifndef LDID_NOSMIME class Buffer { private: BIO *bio_; @@ -1795,19 +1729,12 @@ class Buffer { Buffer(PKCS7 *pkcs) : Buffer() { - if(i2d_PKCS7_bio(bio_, pkcs) == 0){ + if (i2d_PKCS7_bio(bio_, pkcs) == 0){ fprintf(stderr, "ldid: An error occured while getting the PKCS12 file: %s\n", ERR_error_string(ERR_get_error(), NULL)); exit(1); } } - Buffer(CMS_ContentInfo *cms) : - Buffer() - { - _assert(i2d_CMS_bio(bio_, cms) != 0); - } - - ~Buffer() { BIO_free_all(bio_); } @@ -1835,7 +1762,7 @@ class Stuff { value_(d2i_PKCS12_bio(bio, NULL)), ca_(NULL) { - if(value_ == NULL){ + if (value_ == NULL){ fprintf(stderr, "ldid: An error occured while getting the PKCS12 file: %s\n", ERR_error_string(ERR_get_error(), NULL)); exit(1); } @@ -1846,18 +1773,18 @@ class Stuff { password = passbuf; } - if(PKCS12_parse(value_, password.c_str(), &key_, &cert_, &ca_) <= 0){ + if (PKCS12_parse(value_, password.c_str(), &key_, &cert_, &ca_) <= 0){ fprintf(stderr, "ldid: An error occured while parsing: %s\n", ERR_error_string(ERR_get_error(), NULL)); exit(1); } - if(key_ == NULL || cert_ == NULL){ + if (key_ == NULL || cert_ == NULL){ fprintf(stderr, "ldid: An error occured while parsing: %s\nYour p12 cert might not be valid\n", ERR_error_string(ERR_get_error(), NULL)); exit(1); } if (ca_ == NULL) ca_ = sk_X509_new_null(); - if(ca_ == NULL){ + if (ca_ == NULL){ fprintf(stderr, "ldid: An error occured while parsing: %s\n", ERR_error_string(ERR_get_error(), NULL)); exit(1); } @@ -1892,74 +1819,109 @@ class Stuff { } }; +// xina fix; +struct SEQUENCE_hash_sha1 { + uint8_t SEQUENCE[2] = {0x30, 0x1d}; // size + uint8_t OBJECT_IDENTIFIER[7] = {0x06, 0x05, 0x2B, 0x0E, 0x03, 0x02, 0x1A}; // OBJECT IDENTIFIER 1.3.14.3.2.26 sha1 (OIW) + uint8_t hash_size[2] = {0x04, 0x14}; + char hash[20]; +}; + +struct SEQUENCE_hash_sha256 { + uint8_t SEQUENCE[2] = {0x30, 0x2d}; // size + uint8_t OBJECT_IDENTIFIER[11] = {0x06 ,0x09 ,0x60, 0x86, 0x48, 0x01 ,0x65, 0x03, 0x04, 0x02, 0x01}; // 2.16.840.1.101.3.4.2.1 sha-256 (NIST Algorithm) + uint8_t hash_size[2] = {0x04, 0x20}; // hash size + char hash[32]; +}; + class Signature { private: - CMS_ContentInfo *value_; + PKCS7 *value_; public: - Signature(const Stuff &stuff, const Buffer &data, const std::string &xml,const std::vector& alternateCDSHA256) { - // - int flags = CMS_PARTIAL | CMS_DETACHED | CMS_NOSMIMECAP | CMS_BINARY; - //-------------------------------------------- - auto issuer_name(X509_get_issuer_name(stuff)); - _assert(issuer_name != NULL); - std::string issuer; - auto index(X509_NAME_get_index_by_NID(issuer_name, NID_commonName, -1)); - _assert(index >= 0); - auto next(X509_NAME_get_index_by_NID(issuer_name, NID_commonName, index)); - _assert(next == -1); - auto entry(X509_NAME_get_entry(issuer_name, index)); - _assert(entry != NULL); - auto asn(X509_NAME_ENTRY_get_data(entry)); - _assert(asn != NULL); - issuer.assign(reinterpret_cast(ASN1_STRING_get0_data(asn)), ASN1_STRING_length(asn)); - - CMS_ContentInfo *stream = CMS_sign(NULL, NULL, stuff, NULL, flags); - - CMS_SignerInfo *info = CMS_add1_signer(stream, stuff, stuff, EVP_sha256(), flags); - - - // Hash Agility - ASN1_OBJECT *obj = OBJ_txt2obj("1.2.840.113635.100.9.1", 1); - CMS_signed_add1_attr_by_OBJ(info, obj, 0x4, xml.c_str(), (int)xml.size()); - - // CDHashes (iOS 15.1+) - std::string sha256; - for (size_t i = 0; i < alternateCDSHA256.size(); i++) - { - char buf[16] = {0}; - sprintf(buf, "%02X", (uint8_t)alternateCDSHA256[i]); - sha256 += buf; + Signature(const Stuff &stuff, const Buffer &data, const std::string &xml, const std::vector& alternateCDSHA1, const std::vector& alternateCDSHA256) { + value_ = PKCS7_new(); + if (value_ == NULL){ + fprintf(stderr, "ldid: An error occured while getting creating PKCS7 file: %s\n", ERR_error_string(ERR_get_error(), NULL)); + exit(1); } - X509_ATTRIBUTE *attribute = X509_ATTRIBUTE_new(); + if (PKCS7_set_type(value_, NID_pkcs7_signed) == 0 || + PKCS7_content_new(value_, NID_pkcs7_data) == 0) { + fprintf(stderr, "ldid: An error occured while getting creating PKCS7 file: %s\n", ERR_error_string(ERR_get_error(), NULL)); + exit(1); + } + + STACK_OF(X509) *certs(stuff); + for (unsigned i(0), e(sk_X509_num(certs)); i != e; i++) { + if (PKCS7_add_certificate(value_, sk_X509_value(certs, e - i - 1)) == 0) { + fprintf(stderr, "ldid: An error occured while signing: %s\n", ERR_error_string(ERR_get_error(), NULL)); + exit(1); + } + } + auto info(PKCS7_sign_add_signer(value_, stuff, stuff, NULL, PKCS7_NOSMIMECAP)); + if (info == NULL){ + fprintf(stderr, "ldid: An error occured while signing: %s\n", ERR_error_string(ERR_get_error(), NULL)); + exit(1); + } + + X509_ATTRIBUTE *attribute = X509_ATTRIBUTE_new(); ASN1_OBJECT *obj2 = OBJ_txt2obj("1.2.840.113635.100.9.2", 1); X509_ATTRIBUTE_set1_object(attribute, obj2); - - ASN1_TYPE *type256 = GenerateASN1Type(sha256); - if (type256 != NULL) - { - X509_ATTRIBUTE_set1_data(attribute, V_ASN1_SEQUENCE, type256->value.asn1_string->data, type256->value.asn1_string->length); + // xina fix; + SEQUENCE_hash_sha1 seq1; + memcpy((void *)seq1.hash,(void *)alternateCDSHA1.data() ,alternateCDSHA1.size()); + X509_ATTRIBUTE_set1_data(attribute, V_ASN1_SEQUENCE,&seq1, sizeof(seq1)); + // xina fix; + SEQUENCE_hash_sha256 seq256; + memcpy((void *)seq256.hash,(void *)alternateCDSHA256.data() ,alternateCDSHA256.size()); + X509_ATTRIBUTE_set1_data(attribute, V_ASN1_SEQUENCE,&seq256, sizeof(seq256)); + + STACK_OF(X509_ATTRIBUTE) *sk = PKCS7_get_signed_attributes(info); + if (!sk_X509_ATTRIBUTE_push(sk, attribute)) { + fprintf(stderr, "ldid: sk_X509_ATTRIBUTE_push failed: %s\n", ERR_error_string(ERR_get_error(), NULL)); + exit(1); } - CMS_signed_add1_attr(info, attribute); + PKCS7_set_detached(value_, 1); - CMS_final(stream, data, NULL, flags); + ASN1_OCTET_STRING *string(ASN1_OCTET_STRING_new()); + if (string == NULL) { + fprintf(stderr, "ldid: %s\n", ERR_error_string(ERR_get_error(), NULL)); + exit(1); + } + + try { + if (ASN1_STRING_set(string, xml.data(), xml.size()) == 0) { + fprintf(stderr, "ldid: %s\n", ERR_error_string(ERR_get_error(), NULL)); + exit(1); + } + static auto nid(OBJ_create("1.2.840.113635.100.9.1", "", "")); + if (PKCS7_add_signed_attribute(info, nid, V_ASN1_OCTET_STRING, string) == 0) { + fprintf(stderr, "ldid: %s\n", ERR_error_string(ERR_get_error(), NULL)); + exit(1); + } + } catch (...) { + ASN1_OCTET_STRING_free(string); + throw; + } - value_ = stream; - _assert(value_ != NULL); + if (PKCS7_final(value_, data, PKCS7_BINARY) == 0) { + fprintf(stderr, "ldid: Failed to sign: %s\n", ERR_error_string(ERR_get_error(), NULL)); + exit(1); + } } ~Signature() { - CMS_ContentInfo_free(value_); + PKCS7_free(value_); } - operator CMS_ContentInfo *() const { + + operator PKCS7 *() const { return value_; } }; -#endif class NullBuffer : public std::streambuf @@ -2071,6 +2033,7 @@ static std::string Temporary(std::filebuf &file, const Split &split) { std::string temp(split.dir + ".ldid." + split.base); mkdir_p(split.dir); _assert_(file.open(temp.c_str(), std::ios::out | std::ios::trunc | std::ios::binary) == &file, "open(): %s", temp.c_str()); + cleanup.push_back(temp); return temp; } @@ -2084,24 +2047,35 @@ static void Commit(const std::string &path, const std::string &temp) { } _syscall(rename(temp.c_str(), path.c_str())); + cleanup.erase(std::remove(cleanup.begin(), cleanup.end(), temp), cleanup.end()); } -#endif +#endif // LDID_NOTOOLS namespace ldid { -#ifndef LDID_NOSMIME 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); + if (index < 0) { + fprintf(stderr, "ldid: An error occursed while parsing the certificate: %s\n", ERR_error_string(ERR_get_error(), NULL)); + exit(1); + } auto next(X509_NAME_get_index_by_NID(name, nid, index)); - _assert(next == -1); + if (next != -1) { + fprintf(stderr, "ldid: An error occursed while parsing the certificate: %s\n", ERR_error_string(ERR_get_error(), NULL)); + exit(1); + } auto entry(X509_NAME_get_entry(name, index)); - _assert(entry != NULL); + if (entry == NULL) { + fprintf(stderr, "ldid: An error occursed while parsing the certificate: %s\n", ERR_error_string(ERR_get_error(), NULL)); + exit(1); + } auto asn(X509_NAME_ENTRY_get_data(entry)); - _assert(asn != NULL); + if (asn == NULL) { + fprintf(stderr, "ldid: An error occursed while parsing the certificate: %s\n", ERR_error_string(ERR_get_error(), NULL)); + exit(1); + } value.assign(reinterpret_cast(ASN1_STRING_get0_data(asn)), ASN1_STRING_length(asn)); } -#endif static void req(std::streambuf &buffer, uint32_t value) { value = Swap(value); @@ -2130,18 +2104,16 @@ Hash Sign(const void *idata, size_t isize, std::streambuf &output, const std::st std::string team; std::string common; -#ifndef LDID_NOSMIME if (!key.empty()) { Stuff stuff(key); auto name(X509_get_subject_name(stuff)); - if(name == NULL){ + if (name == NULL){ fprintf(stderr, "ldid: Your certificate might not be valid: %s\n", ERR_error_string(ERR_get_error(), NULL)); exit(1); } get(team, name, NID_organizationalUnitName); get(common, name, NID_commonName); } -#endif std::stringbuf backing; @@ -2196,9 +2168,6 @@ Hash Sign(const void *idata, size_t isize, std::streambuf &output, const std::st alloc += sizeof(struct BlobIndex); alloc += backing.str().size(); -#ifdef LDID_NOPLIST - baton.entitlements_ = entitlements; -#else if (merge) Analyze(mach_header, fun([&](const char *data, size_t size) { baton.entitlements_.assign(data, size); @@ -2207,11 +2176,17 @@ Hash Sign(const void *idata, size_t isize, std::streambuf &output, const std::st if (!baton.entitlements_.empty() || !entitlements.empty()) { auto combined(plist(baton.entitlements_)); _scope({ plist_free(combined); }); - _assert(plist_get_node_type(combined) == PLIST_DICT); + if (plist_get_node_type(combined) != PLIST_DICT) { + fprintf(stderr, "ldid: Existing entitlements are in wrong format\n"); + exit(1); + }; auto merging(plist(entitlements)); _scope({ plist_free(merging); }); - _assert(plist_get_node_type(merging) == PLIST_DICT); + if (plist_get_node_type(merging) != PLIST_DICT) { + fprintf(stderr, "ldid: Entitlements need a root key of dict\n"); + exit(1); + }; plist_dict_iter iterator(NULL); plist_dict_new_iter(merging, &iterator); @@ -2236,7 +2211,6 @@ Hash Sign(const void *idata, size_t isize, std::streambuf &output, const std::st baton.entitlements_.assign(xml, size); } -#endif if (!baton.entitlements_.empty()) { special = std::max(special, CSSLOT_ENTITLEMENTS); @@ -2265,13 +2239,11 @@ Hash Sign(const void *idata, size_t isize, std::streambuf &output, const std::st 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); alloc += certificate; } -#endif return alloc; }), 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 { @@ -2290,7 +2262,6 @@ Hash Sign(const void *idata, size_t isize, std::streambuf &output, const std::st put(data, baton.entitlements_.data(), baton.entitlements_.size()); insert(blobs, CSSLOT_ENTITLEMENTS, CSMAGIC_EMBEDDED_ENTITLEMENTS, data); -#ifndef LDID_NOPLIST auto entitlements(plist(baton.entitlements_)); _scope({ plist_free(entitlements); }); if (plist_get_node_type(entitlements) != PLIST_DICT) { @@ -2321,7 +2292,6 @@ Hash Sign(const void *idata, size_t isize, std::streambuf &output, const std::st execs |= kSecCodeExecSegCanLoadCdHash; if (entitled("com.apple.private.amfi.can-execute-cdhash")) execs |= kSecCodeExecSegCanExecCdHash; -#endif } if (!baton.derformat_.empty()) { @@ -2424,25 +2394,15 @@ Hash Sign(const void *idata, size_t isize, std::streambuf &output, const std::st ++total; } -#ifndef LDID_NOSMIME if (!key.empty()) { -#ifdef LDID_NOPLIST - auto plist(CFDictionaryCreateMutable(kCFAllocatorDefault, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks)); - _scope({ CFRelease(plist); }); - - auto cdhashes(CFArrayCreateMutable(kCFAllocatorDefault, 0, &kCFTypeArrayCallBacks)); - _scope({ CFRelease(cdhashes); }); - - CFDictionarySetValue(plist, CFSTR("cdhashes"), cdhashes); -#else auto plist(plist_new_dict()); _scope({ plist_free(plist); }); auto cdhashes(plist_new_array()); plist_dict_set_item(plist, "cdhashes", cdhashes); -#endif std::vector alternateCDSHA256; + std::vector alternateCDSHA1; unsigned total(0); for (Algorithm *pointer : GetAlgorithms()) { @@ -2454,33 +2414,19 @@ Hash Sign(const void *idata, size_t isize, std::streambuf &output, const std::st std::vector hash; algorithm(hash, blob.data(), blob.size()); - hash.resize(20); - - if (algorithm.type_ == CS_HASHTYPE_SHA256_256){ + if (algorithm.type_ == CS_HASHTYPE_SHA256_256) alternateCDSHA256 = hash; - } - + else if (algorithm.type_ == CS_HASHTYPE_SHA160_160) + alternateCDSHA1 = hash; + hash.resize(20); -#ifdef LDID_NOPLIST - auto value(CFDataCreate(kCFAllocatorDefault, reinterpret_cast(hash.data()), hash.size())); - _scope({ CFRelease(value); }); - CFArrayAppendValue(cdhashes, value); -#else plist_array_append_item(cdhashes, plist_new_data(hash.data(), hash.size())); -#endif } -#ifdef LDID_NOPLIST - auto created(CFPropertyListCreateXMLData(kCFAllocatorDefault, plist)); - _scope({ CFRelease(created); }); - auto xml(reinterpret_cast(CFDataGetBytePtr(created))); - auto size(CFDataGetLength(created)); -#else char *xml(NULL); uint32_t size; plist_to_xml(plist, &xml, &size); _scope({ free(xml); }); -#endif std::stringbuf data; const std::string &sign(blobs[CSSLOT_CODEDIRECTORY]); @@ -2488,7 +2434,7 @@ Hash Sign(const void *idata, size_t isize, std::streambuf &output, const std::st Stuff stuff(key); Buffer bio(sign); - Signature signature(stuff, sign, std::string(xml, size), alternateCDSHA256); + Signature signature(stuff, sign, std::string(xml, size), alternateCDSHA1, alternateCDSHA256); Buffer result(signature); std::string value(result); put(data, value.data(), value.size()); @@ -2496,7 +2442,6 @@ Hash Sign(const void *idata, size_t isize, std::streambuf &output, const std::st const auto &save(insert(blobs, CSSLOT_SIGNATURESLOT, CSMAGIC_BLOBWRAPPER, data)); _assert(save.size() <= certificate); } -#endif return put(output, CSMAGIC_EMBEDDED_SIGNATURE, blobs); }), progress); @@ -2564,8 +2509,7 @@ void DiskFolder::Find(const std::string &root, const std::string &base, const Fu #ifdef __WIN32__ struct stat info; _syscall(stat((path + name).c_str(), &info)); - if (false); - else if (S_ISDIR(info.st_mode)) + if (S_ISDIR(info.st_mode)) directory = true; else if (S_ISREG(info.st_mode)) directory = false; @@ -2623,7 +2567,7 @@ void DiskFolder::Open(const std::string &path, const Functor &code, const Functor &)> &link) const { Find(path, "", code, link); } -#endif +#endif // LDID_NOTOOLS SubFolder::SubFolder(Folder &parent, const std::string &path) : parent_(parent), @@ -2733,7 +2677,6 @@ 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(); @@ -2742,7 +2685,10 @@ static plist_t plist(const std::string &data) { plist_from_bin(data.data(), data.size(), &plist); else plist_from_xml(data.data(), data.size(), &plist); - _assert(plist != NULL); + if (plist == NULL) { + fprintf(stderr, "ldid: Failed to parse plist\n"); + exit(1); + } return plist; } @@ -2751,19 +2697,25 @@ static void plist_d(std::streambuf &buffer, size_t length, const Functor\n"); + exit(1); + } code(node); } static std::string plist_s(plist_t node) { - _assert(node != NULL); - _assert(plist_get_node_type(node) == PLIST_STRING); + if (node == NULL) + return NULL; + if (plist_get_node_type(node) != PLIST_STRING) { + fprintf(stderr, "ldid: Unexpected plist type. Expected \n"); + exit(1); + } char *data; plist_get_string_val(node, &data); _scope({ free(data); }); return data; } -#endif enum Mode { NoMode, @@ -2849,7 +2801,6 @@ struct RuleCode { } }; -#ifndef LDID_NOPLIST 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) { // XXX: this is a miserable fail std::stringbuf temp; @@ -2887,8 +2838,7 @@ Bundle Sign(const std::string &root, Folder &parent, const std::string &key, Sta if (parent.Look(info)) return ""; mac = true; - if (false); - else if (parent.Look("Contents/" + info)) + if (parent.Look("Contents/" + info)) return "Contents/"; else if (parent.Look("Resources/" + info)) { info = "Resources/" + info; @@ -2901,8 +2851,18 @@ Bundle Sign(const std::string &root, Folder &parent, const std::string &key, Sta 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")); + plist_t nodebuf(plist_dict_get_item(node, "CFBundleExecutable")); + if (nodebuf == NULL) { + fprintf(stderr, "ldid: Cannot find key CFBundleExecutable\n"); + exit(1); + } + executable = plist_s(nodebuf); + nodebuf = plist_dict_get_item(node, "CFBundleIdentifier"); + if (nodebuf == NULL) { + fprintf(stderr, "ldid: Cannot find key CFBundleIdentifier\n"); + exit(1); + } + identifier = plist_s(nodebuf); })); })); @@ -3169,7 +3129,6 @@ Bundle Sign(const std::string &root, Folder &folder, const std::string &key, con State local; return Sign(root, folder, key, local, requirements, alter, progress); } -#endif #endif } @@ -3190,7 +3149,7 @@ static void usage(const char *argv0) { fprintf(stderr, " host | kill | library-validation | restrict | runtime]] [-D] [-d]\n"); fprintf(stderr, " [-Enum:file] [-e] [-H[sha1 | sha256]] [-h] [-Iname]\n"); fprintf(stderr, " [-Kkey.p12 [-Upassword]] [-M] [-P] [-Qrequirements.xml] [-q]\n"); - fprintf(stderr, " [-r | -Sfile.xml | -s] [-Ttimestamp] [-u] [-arch arch_type] file ...\n"); + fprintf(stderr, " [-r | -Sfile.xml | -s] [-u] [-arch arch_type] file ...\n"); fprintf(stderr, "Options:\n"); fprintf(stderr, " -S[file.xml] Pseudo-sign using the entitlements in file.xml\n"); fprintf(stderr, " -Kkey.p12 Sign using private key in key.p12\n"); @@ -3200,15 +3159,19 @@ static void usage(const char *argv0) { fprintf(stderr, "More information: 'man ldid'\n"); } +void cleanupfunc(void) { + for (const auto &temp : cleanup) + remove(temp.c_str()); +} + #ifndef LDID_NOTOOLS int main(int argc, char *argv[]) { -#ifndef LDID_NOSMIME + std::atexit(cleanupfunc); OpenSSL_add_all_algorithms(); # if OPENSSL_VERSION_MAJOR >= 3 OSSL_PROVIDER *legacy = OSSL_PROVIDER_load(NULL, "legacy"); OSSL_PROVIDER *deflt = OSSL_PROVIDER_load(NULL, "default"); # endif -#endif union { uint16_t word; @@ -3224,9 +3187,6 @@ int main(int argc, char *argv[]) { bool flag_H(false); bool flag_h(false); -#ifndef LDID_NOFLAGT - bool flag_T(false); -#endif bool flag_S(false); bool flag_s(false); @@ -3249,10 +3209,6 @@ int main(int argc, char *argv[]) { const char *flag_I(NULL); -#ifndef LDID_NOFLAGT - bool timeh(false); - uint32_t timev(0); -#endif Map entitlements; Map requirements; @@ -3305,11 +3261,17 @@ int main(int argc, char *argv[]) { case 'E': { const char *string = argv[argi] + 2; const char *colon = strchr(string, ':'); - _assert(colon != NULL); + if (colon == NULL) { + usage(argv[0]); + exit(1); + } Map file(colon + 1, O_RDONLY, PROT_READ, MAP_PRIVATE); char *arge; unsigned number(strtoul(string, &arge, 0)); - _assert(arge == colon); + if (arge != colon || (number == 0 && errno == EINVAL)) { + usage(argv[0]); + exit(1); + } auto &slot(slots[number]); for (Algorithm *algorithm : GetAlgorithms()) (*algorithm)(slot, file.data(), file.size()); @@ -3327,8 +3289,7 @@ int main(int argc, char *argv[]) { do_sha256 = false; } - if (false); - else if (strcmp(hash, "sha1") == 0) + if (strcmp(hash, "sha1") == 0) do_sha1 = true; else if (strcmp(hash, "sha256") == 0) do_sha256 = true; @@ -3359,19 +3320,27 @@ int main(int argc, char *argv[]) { if (argv[argi][2] != '\0') { const char *cpu = argv[argi] + 2; const char *colon = strchr(cpu, ':'); - _assert(colon != NULL); + if (colon == NULL) { + usage(argv[0]); + exit(1); + } char *arge; flag_CPUType = strtoul(cpu, &arge, 0); - _assert(arge == colon); + if (arge != colon || (flag_CPUType == 0 && errno == EINVAL)) { + usage(argv[0]); + exit(1); + } flag_CPUSubtype = strtoul(colon + 1, &arge, 0); - _assert(arge == argv[argi] + strlen(argv[argi])); + if (arge != argv[argi] + strlen(argv[argi]) || (flag_CPUSubtype == 0 && errno == EINVAL)) { + usage(argv[0]); + exit(1); + } } break; case 'C': { const char *name = argv[argi] + 2; - if (false); - else if (strcmp(name, "host") == 0) + if (strcmp(name, "host") == 0) flags |= kSecCodeSignatureHost; else if (strcmp(name, "adhoc") == 0) flags |= kSecCodeSignatureAdhoc; @@ -3405,6 +3374,8 @@ int main(int argc, char *argv[]) { exit(1); } flag_s = true; + entitlements.clear(); + flag_M = true; break; case 'S': @@ -3432,18 +3403,7 @@ int main(int argc, char *argv[]) { key.open(argv[argi] + 2, O_RDONLY, PROT_READ, MAP_PRIVATE); break; -#ifndef LDID_NOFLAGT - case 'T': { - flag_T = true; - if (argv[argi][2] == '-') - timeh = true; - else { - char *arge; - timev = strtoul(argv[argi] + 2, &arge, 0); - _assert(arge == argv[argi] + strlen(argv[argi])); - } - } break; -#endif + case 'T': break; case 'u': { flag_u = true; @@ -3459,12 +3419,9 @@ int main(int argc, char *argv[]) { break; } - _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 (flag_I != NULL && !flag_S) { + fprintf(stderr, "ldid: -I requires -S\n"); + exit(1); } if (files.empty()) @@ -3485,12 +3442,8 @@ int main(int argc, char *argv[]) { fprintf(stderr, "ldid: Only -S can be used on directories\n"); exit(1); } -#ifndef LDID_NOPLIST ldid::DiskFolder folder(path + "/"); path += "/" + Sign("", folder, key, requirements, ldid::fun([&](const std::string &, const std::string &) -> std::string { return entitlements; }), dummy_).path; -#else - _assert(false); -#endif } else if (flag_S || flag_r) { Map input(path, O_RDONLY, PROT_READ, MAP_PRIVATE); @@ -3508,15 +3461,7 @@ int main(int argc, char *argv[]) { Commit(path, temp); } - bool modify(false); -#ifndef LDID_NOFLAGT - if (flag_T) - modify = true; -#endif - if (flag_s) - modify = true; - - Map mapping(path, modify); + Map mapping(path, flag_D ? true : false); FatHeader fat_header(mapping.data(), mapping.size()); _foreach (mach_header, fat_header.GetMachHeaders()) { @@ -3536,8 +3481,7 @@ int main(int argc, char *argv[]) { _foreach (load_command, mach_header.GetLoadCommands()) { uint32_t cmd(mach_header.Swap(load_command->cmd)); - if (false); - else if (cmd == LC_CODE_SIGNATURE) + if (cmd == LC_CODE_SIGNATURE) signature = reinterpret_cast(load_command); else if (cmd == LC_ENCRYPTION_INFO || cmd == LC_ENCRYPTION_INFO_64) encryption = reinterpret_cast(load_command); @@ -3553,24 +3497,6 @@ int main(int argc, char *argv[]) { } } } -#ifndef LDID_NOFLAGT - else if (cmd == LC_ID_DYLIB) { - volatile struct dylib_command *dylib_command(reinterpret_cast(load_command)); - - if (flag_T) { - uint32_t timed; - - if (!timeh) - timed = timev; - else { - dylib_command->dylib.timestamp = 0; - timed = hash(reinterpret_cast(mach_header.GetBase()), mach_header.GetSize(), timev); - } - - dylib_command->dylib.timestamp = mach_header.Swap(timed); - } - } -#endif } if (flag_d && encryption != NULL) { @@ -3578,12 +3504,15 @@ int main(int argc, char *argv[]) { } if (flag_D) { - _assert(encryption != NULL); + if (encryption == NULL) { + fprintf(stderr, "ldid: -D requires an encrypted binary\n"); + exit(1); + } encryption->cryptid = mach_header.Swap(0); } - if ((flag_e || flag_q || flag_s || flag_h) && signature == NULL) { - fprintf(stderr, "ldid: -e, -q, -s, and -h requre a signed binary\n"); + if ((flag_e || flag_q || flag_h) && signature == NULL) { + fprintf(stderr, "ldid: -e, -q, and -h requre a signed binary\n"); exit(1); } @@ -3617,29 +3546,6 @@ int main(int argc, char *argv[]) { } } - if (flag_s) { - uint32_t data = mach_header.Swap(signature->dataoff); - - uint8_t *top = reinterpret_cast(mach_header.GetBase()); - uint8_t *blob = top + data; - struct SuperBlob *super = reinterpret_cast(blob); - - for (size_t index(0); index != Swap(super->count); ++index) - if (Swap(super->index[index].type) == CSSLOT_CODEDIRECTORY) { - uint32_t begin = Swap(super->index[index].offset); - struct CodeDirectory *directory = reinterpret_cast(blob + begin + sizeof(Blob)); - - uint8_t (*hashes)[LDID_SHA1_DIGEST_LENGTH] = reinterpret_cast(blob + begin + Swap(directory->hashOffset)); - uint32_t pages = Swap(directory->nCodeSlots); - - if (pages != 1) - for (size_t i = 0; i != pages - 1; ++i) - LDID_SHA1(top + PageSize_ * i, PageSize_, hashes[i]); - if (pages != 0) - LDID_SHA1(top + PageSize_ * (pages - 1), ((data - 1) % PageSize_) + 1, hashes[pages - 1]); - } - } - if (flag_h) { auto algorithms(GetAlgorithms()); @@ -3723,13 +3629,11 @@ int main(int argc, char *argv[]) { ++filei; } -#ifndef LDID_NOSMIME # if OPENSSL_VERSION_MAJOR >= 3 OSSL_PROVIDER_unload(legacy); OSSL_PROVIDER_unload(deflt); # endif -#endif return filee; } -#endif +#endif // LDID_NOTOOLS