X-Git-Url: https://git.cameronkatri.com/ldid.git/blobdiff_plain/2edb2a9307f1bd3909dadc20e80857c6e40c00c5..51e674a2579adcdb43fa949d5d094fceef9c2037:/ldid.cpp?ds=sidebyside diff --git a/ldid.cpp b/ldid.cpp index da4c0c7..23b07a4 100644 --- a/ldid.cpp +++ b/ldid.cpp @@ -43,10 +43,15 @@ #include #ifndef LDID_NOSMIME +#include +# if OPENSSL_VERSION_MAJOR >= 3 +# include +# endif #include #include #include #include +#include #endif #ifdef __APPLE__ @@ -91,6 +96,8 @@ #include "ldid.hpp" +#include "machine.h" + #define _assert___(line) \ #line #define _assert__(line) \ @@ -129,7 +136,8 @@ for (auto success : (long[]) {EINTR, __VA_ARGS__}) \ if (error == success) \ return (decltype(expr)) -success; \ - _assert_(false, "errno=%u", error); \ + fprintf(stderr, "ldid: %s: %s\n", __func__, strerror(error)); \ + exit(1); \ } }() #define _trace() \ @@ -141,6 +149,10 @@ #define _packed \ __attribute__((packed)) +#ifndef LDID_NOSMIME +std::string password; +#endif + template struct Iterator_ { typedef typename Type_::const_iterator Result; @@ -187,27 +199,6 @@ Scope _scope(const Function_ &function) { #define _scope(function) \ _scope_(__COUNTER__, function) -#define CPU_ARCH_MASK uint32_t(0xff000000) -#define CPU_ARCH_ABI64 uint32_t(0x01000000) - -#define CPU_TYPE_ANY uint32_t(-1) -#define CPU_TYPE_VAX uint32_t( 1) -#define CPU_TYPE_MC680x0 uint32_t( 6) -#define CPU_TYPE_X86 uint32_t( 7) -#define CPU_TYPE_MC98000 uint32_t(10) -#define CPU_TYPE_HPPA uint32_t(11) -#define CPU_TYPE_ARM uint32_t(12) -#define CPU_TYPE_MC88000 uint32_t(13) -#define CPU_TYPE_SPARC uint32_t(14) -#define CPU_TYPE_I860 uint32_t(15) -#define CPU_TYPE_POWERPC uint32_t(18) - -#define CPU_TYPE_I386 CPU_TYPE_X86 - -#define CPU_TYPE_ARM64 (CPU_ARCH_ABI64 | CPU_TYPE_ARM) -#define CPU_TYPE_POWERPC64 (CPU_ARCH_ABI64 | CPU_TYPE_POWERPC) -#define CPU_TYPE_X86_64 (CPU_ARCH_ABI64 | CPU_TYPE_X86) - struct fat_header { uint32_t magic; uint32_t nfat_arch; @@ -515,6 +506,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 +528,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 +558,159 @@ 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: { + fprintf(stderr, "ldid: Invalid plist entry type\n"); + exit(1); + } break; + + case PLIST_DATE: { + fprintf(stderr, "ldid: Invalid plist entry type\n"); + exit(1); + } 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: { + fprintf(stderr, "ldid: Unsupported plist type %d", type); + exit(1); + } break; + } +} +#endif + static inline uint16_t Swap_(uint16_t value) { return ((value >> 8) & 0x00ff) | @@ -691,7 +843,8 @@ class MachHeader : break; default: - _assert(false); + fprintf(stderr, "ldid: Unknown header magic\nAre you sure that is a Mach-O?\n"); + exit(1); } void *post = mach_header_ + 1; @@ -699,12 +852,13 @@ class MachHeader : post = (uint32_t *) post + 1; load_command_ = (struct load_command *) post; - _assert( - Swap(mach_header_->filetype) == MH_EXECUTE || - Swap(mach_header_->filetype) == MH_DYLIB || - Swap(mach_header_->filetype) == MH_DYLINKER || - Swap(mach_header_->filetype) == MH_BUNDLE - ); + if (Swap(mach_header_->filetype) != MH_EXECUTE && + Swap(mach_header_->filetype) != MH_DYLIB && + Swap(mach_header_->filetype) != MH_DYLINKER && + Swap(mach_header_->filetype) != MH_BUNDLE) { + fprintf(stderr, "ldid: Unsupported Mach-O type\n"); + exit(1); + } } bool Bits64() const { @@ -843,6 +997,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 +1007,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,6 +1249,7 @@ static const std::vector &GetAlgorithms() { struct Baton { std::string entitlements_; + std::string derformat_; }; struct CodesignAllocation { @@ -1134,8 +1292,11 @@ class File { } void open(const char *path, int flags) { - _assert(file_ == -1); - file_ = _syscall(::open(path, flags)); + file_ = ::open(path, flags); + if (file_ == -1) { + fprintf(stderr, "ldid: %s: %s\n", path, strerror(errno)); + exit(1); + } } int file() const { @@ -1312,6 +1473,7 @@ static void Allocate(const void *idata, size_t isize, std::streambuf &output, co break; case CPU_TYPE_ARM: case CPU_TYPE_ARM64: + case CPU_TYPE_ARM64_32: align = 0xe; break; default: @@ -1339,6 +1501,9 @@ static void Allocate(const void *idata, size_t isize, std::streambuf &output, co case CPU_TYPE_ARM64: arch = "arm64"; break; + case CPU_TYPE_ARM64_32: + arch = "arm64_32"; + break; } offset = Align(offset, 1 << align); @@ -1593,7 +1758,10 @@ class Buffer { Buffer(PKCS7 *pkcs) : Buffer() { - _assert(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() { @@ -1623,15 +1791,32 @@ class Stuff { value_(d2i_PKCS12_bio(bio, NULL)), ca_(NULL) { - _assert(value_ != NULL); - _assert(PKCS12_parse(value_, "", &key_, &cert_, &ca_) != 0); + 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); + } - _assert(key_ != NULL); - _assert(cert_ != NULL); + if (!PKCS12_verify_mac(value_, "", 0) && password.empty()) { + char passbuf[2048]; + UI_UTIL_read_pw_string(passbuf, 2048, "Enter password: ", 0); + password = passbuf; + } + + 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){ + 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(); - _assert(ca_ != NULL); + if(ca_ == NULL){ + fprintf(stderr, "ldid: An error occured while parsing: %s\n", ERR_error_string(ERR_get_error(), NULL)); + exit(1); + } } Stuff(const std::string &data) : @@ -1670,7 +1855,10 @@ class Signature { public: Signature(const Stuff &stuff, const Buffer &data, const std::string &xml) { value_ = PKCS7_new(); - _assert(value_ != NULL); + 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); + } _assert(PKCS7_set_type(value_, NID_pkcs7_signed)); _assert(PKCS7_content_new(value_, NID_pkcs7_data)); @@ -1679,12 +1867,10 @@ class Signature { for (unsigned i(0), e(sk_X509_num(certs)); i != e; i++) _assert(PKCS7_add_certificate(value_, sk_X509_value(certs, e - i - 1))); - // XXX: this is the same as PKCS7_sign_add_signer(value_, stuff, stuff, NULL, PKCS7_NOSMIMECAP) - _assert(X509_check_private_key(stuff, stuff)); - auto info(PKCS7_add_signature(value_, stuff, stuff, EVP_sha1())); - _assert(info != NULL); - _assert(PKCS7_add_certificate(value_, stuff)); - _assert(PKCS7_add_signed_attribute(info, NID_pkcs9_contentType, V_ASN1_OBJECT, OBJ_nid2obj(NID_pkcs7_data))); + 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)); + } PKCS7_set_detached(value_, 1); @@ -1700,13 +1886,7 @@ class Signature { throw; } - // XXX: this is the same as PKCS7_final(value_, data, PKCS7_BINARY) - BIO *bio(PKCS7_dataInit(value_, NULL)); - _assert(bio != NULL); - _scope({ BIO_free_all(bio); }); - SMIME_crlf_copy(data, bio, PKCS7_BINARY); - BIO_flush(bio); - _assert(PKCS7_dataFinal(value_, bio)); + _assert(PKCS7_final(value_, data, PKCS7_BINARY)); } ~Signature() { @@ -1857,7 +2037,7 @@ static void get(std::string &value, X509_NAME *name, int nid) { _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)); + value.assign(reinterpret_cast(ASN1_STRING_get0_data(asn)), ASN1_STRING_length(asn)); } #endif @@ -1892,7 +2072,10 @@ Hash Sign(const void *idata, size_t isize, std::streambuf &output, const std::st if (!key.empty()) { Stuff stuff(key); auto name(X509_get_subject_name(stuff)); - _assert(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); } @@ -1951,50 +2134,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); - char *xml(NULL); - uint32_t size; - plist_to_xml(combined, &xml, &size); - _scope({ free(xml); }); + auto merging(plist(entitlements)); + _scope({ plist_free(merging); }); + _assert(plist_get_node_type(merging) == PLIST_DICT); - baton.entitlements_.assign(xml, size); + 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)); } -#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); @@ -2003,6 +2183,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); @@ -2044,7 +2231,10 @@ Hash Sign(const void *idata, size_t isize, std::streambuf &output, const std::st #ifndef LDID_NOPLIST auto entitlements(plist(baton.entitlements_)); _scope({ plist_free(entitlements); }); - _assert(plist_get_node_type(entitlements) == PLIST_DICT); + if (plist_get_node_type(entitlements) != PLIST_DICT) { + fprintf(stderr, "ldid: Entitlements should be a plist dicionary\n"); + exit(1); + } const auto entitled([&](const char *key) { auto item(plist_dict_get_item(entitlements, key)); @@ -2072,6 +2262,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) { @@ -2331,8 +2527,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; @@ -2471,6 +2666,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); @@ -2543,7 +2740,7 @@ struct Rule { Mode mode_; std::string code_; - mutable std::auto_ptr regex_; + mutable std::unique_ptr regex_; Rule(unsigned weight, Mode mode, const std::string &code) : weight_(weight), @@ -2609,7 +2806,7 @@ struct State { } }; -Bundle Sign(const std::string &root, Folder &parent, const std::string &key, State &remote, const std::string &requirements, const Functor &alter, const Progress &progress) { +Bundle Sign(const std::string &root, Folder &parent, const std::string &key, State &local, const std::string &requirements, const Functor &alter, const Progress &progress) { std::string executable; std::string identifier; @@ -2627,7 +2824,10 @@ Bundle Sign(const std::string &root, Folder &parent, const std::string &key, Sta else if (parent.Look("Resources/" + info)) { info = "Resources/" + info; return ""; - } else _assert_(false, "cannot find Info.plist"); + } else { + fprintf(stderr, "ldid: Could not find Info.plist\n"); + exit(1); + } }()); folder.Open(info, fun([&](std::streambuf &buffer, size_t length, const void *flag) { @@ -2688,8 +2888,6 @@ Bundle Sign(const std::string &root, Folder &parent, const std::string &key, Sta rules2.insert(Rule{20, NoMode, "^version\\.plist$"}); } - State local; - std::string failure(mac ? "Contents/|Versions/[^/]*/Resources/" : ""); Expression nested("^(Frameworks/[^/]*\\.framework|PlugIns/[^/]*\\.appex(()|/[^/]*.app))/(" + failure + ")Info\\.plist$"); std::map bundles; @@ -2697,16 +2895,18 @@ Bundle Sign(const std::string &root, Folder &parent, const std::string &key, Sta folder.Find("", fun([&](const std::string &name) { if (!nested(name)) return; - auto bundle(root + Split(name).dir); + auto bundle(Split(name).dir); if (mac) { _assert(!bundle.empty()); bundle = Split(bundle.substr(0, bundle.size() - 1)).dir; } SubFolder subfolder(folder, bundle); - bundles[nested[1]] = Sign(bundle, subfolder, key, local, "", Starts(name, "PlugIns/") ? alter : + State remote; + bundles[nested[1]] = Sign(root + bundle, subfolder, key, remote, "", Starts(name, "PlugIns/") ? alter : static_cast &>(fun([&](const std::string &, const std::string &) -> std::string { return entitlements; })) , progress); + local.Merge(bundle, remote); }), fun([&](const std::string &name, const Functor &read) { })); @@ -2893,7 +3093,6 @@ Bundle Sign(const std::string &root, Folder &parent, const std::string &key, Sta })); })); - remote.Merge(root, local); return bundle; } @@ -2917,16 +3116,29 @@ std::string Hex(const uint8_t *data, size_t size) { } static void usage(const char *argv0) { - fprintf(stderr, "usage: %s -S[entitlements.xml] \n", argv0); - fprintf(stderr, " %s -e MobileSafari\n", argv0); - fprintf(stderr, " %s -S cat\n", argv0); - fprintf(stderr, " %s -Stfp.xml gdb\n", argv0); + fprintf(stderr, "Link Identity Editor %s\n\n", LDID_VERSION); + fprintf(stderr, "Usage: %s [-Acputype:subtype] [-a] [-C[adhoc | enforcement | expires | hard |\n", 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, "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"); + fprintf(stderr, " -Upassword Use password to unlock key.p12\n"); + fprintf(stderr, " -M Merge entitlements with any existing\n"); + fprintf(stderr, " -h Print CDHash of file\n\n"); + fprintf(stderr, "More information: 'man ldid'\n"); } #ifndef LDID_NOTOOLS int main(int argc, char *argv[]) { #ifndef LDID_NOSMIME 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 { @@ -2988,10 +3200,34 @@ int main(int argc, char *argv[]) { for (int argi(1); argi != argc; ++argi) if (argv[argi][0] != '-') files.push_back(argv[argi]); - else switch (argv[argi][1]) { + else if (strcmp(argv[argi], "-arch") == 0) { + bool foundarch = false; + flag_A = true; + argi++; + if (argi == argc) { + fprintf(stderr, "ldid: -arch must be followed by an architecture string\n"); + exit(1); + } + for (int i = 0; archs[i].name != NULL; i++) { + if (strcmp(archs[i].name, argv[argi]) == 0) { + flag_CPUType = archs[i].cputype; + flag_CPUSubtype = archs[i].cpusubtype; + foundarch = true; + } + if (foundarch) + break; + } + + if (!foundarch) { + fprintf(stderr, "error: unknown architecture specification flag: -arch %s\n", argv[argi]); + exit(1); + } + } else switch (argv[argi][1]) { case 'r': - _assert(!flag_s); - _assert(!flag_S); + if (flag_s || flag_S) { + fprintf(stderr, "ldid: Can only specify one of -r, -S, -s\n"); + exit(1); + } flag_r = true; break; @@ -3020,9 +3256,6 @@ int main(int argc, char *argv[]) { do_sha1 = false; do_sha256 = false; - - fprintf(stderr, "WARNING: -H is only present for compatibility with a fork of ldid\n"); - fprintf(stderr, " you should NOT be manually specifying the hash algorithm\n"); } if (false); @@ -3030,7 +3263,10 @@ int main(int argc, char *argv[]) { do_sha1 = true; else if (strcmp(hash, "sha256") == 0) do_sha256 = true; - else _assert(false); + else { + fprintf(stderr, "ldid: only sha1 and sha256 are supported at this time\n"); + exit(1); + } } break; case 'h': flag_h = true; break; @@ -3046,7 +3282,10 @@ int main(int argc, char *argv[]) { case 'a': flag_a = true; break; case 'A': - _assert(!flag_A); + if (flag_A) { + fprintf(stderr, "ldid: -A can only be specified once\n"); + exit(1); + } flag_A = true; if (argv[argi][2] != '\0') { const char *cpu = argv[argi] + 2; @@ -3081,7 +3320,10 @@ int main(int argc, char *argv[]) { flags |= kSecCodeSignatureLibraryValidation; else if (strcmp(name, "runtime") == 0) flags |= kSecCodeSignatureRuntime; - else _assert(false); + else { + fprintf(stderr, "ldid: -C: Unsupported option\n"); + exit(1); + } } break; case 'P': @@ -3089,14 +3331,18 @@ int main(int argc, char *argv[]) { break; case 's': - _assert(!flag_r); - _assert(!flag_S); + if (flag_r || flag_S) { + fprintf(stderr, "ldid: Can only specify one of -r, -S, -s\n"); + exit(1); + } flag_s = true; break; case 'S': - _assert(!flag_r); - _assert(!flag_s); + if (flag_r || flag_s) { + fprintf(stderr, "ldid: Can only specify one of -r, -S, -s\n"); + exit(1); + } flag_S = true; if (argv[argi][2] != '\0') { const char *xml = argv[argi] + 2; @@ -3108,6 +3354,10 @@ int main(int argc, char *argv[]) { flag_M = true; break; + case 'U': + password = argv[argi] + 2; + break; + case 'K': if (argv[argi][2] != '\0') key.open(argv[argi] + 2, O_RDONLY, PROT_READ, MAP_PRIVATE); @@ -3156,10 +3406,16 @@ int main(int argc, char *argv[]) { std::string path(file); struct stat info; - _syscall(stat(path.c_str(), &info)); + if (stat(path.c_str(), &info) == -1) { + fprintf(stderr, "ldid: %s: %s\n", path.c_str(), strerror(errno)); + exit(1); + } if (S_ISDIR(info.st_mode)) { - _assert(flag_S); + if (!flag_S) { + 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; @@ -3257,9 +3513,12 @@ int main(int argc, char *argv[]) { encryption->cryptid = mach_header.Swap(0); } - if (flag_e) { - _assert(signature != NULL); + if ((flag_e || flag_q || flag_s || flag_h) && signature == NULL) { + fprintf(stderr, "ldid: -e, -q, -s, and -h requre a signed binary\n"); + exit(1); + } + if (flag_e) { uint32_t data = mach_header.Swap(signature->dataoff); uint8_t *top = reinterpret_cast(mach_header.GetBase()); @@ -3275,8 +3534,6 @@ int main(int argc, char *argv[]) { } if (flag_q) { - _assert(signature != NULL); - uint32_t data = mach_header.Swap(signature->dataoff); uint8_t *top = reinterpret_cast(mach_header.GetBase()); @@ -3292,8 +3549,6 @@ int main(int argc, char *argv[]) { } if (flag_s) { - _assert(signature != NULL); - uint32_t data = mach_header.Swap(signature->dataoff); uint8_t *top = reinterpret_cast(mach_header.GetBase()); @@ -3317,8 +3572,6 @@ int main(int argc, char *argv[]) { } if (flag_h) { - _assert(signature != NULL); - auto algorithms(GetAlgorithms()); uint32_t data = mach_header.Swap(signature->dataoff); @@ -3401,6 +3654,13 @@ 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