]> git.saurik.com Git - ldid.git/blobdiff - ldid.cpp
Update build environment to support sbigner's era.
[ldid.git] / ldid.cpp
index a774c5ec9bcd8616581343a90a515a516a1b6993..6d03d1b131301b03111aa1ffedf0848fd15e3f0a 100644 (file)
--- a/ldid.cpp
+++ b/ldid.cpp
@@ -85,6 +85,8 @@
 
 #ifndef LDID_NOPLIST
 #include <plist/plist.h>
+#elif __APPLE__
+#include <CoreFoundation/CoreFoundation.h>
 #endif
 
 #include "ldid.hpp"
@@ -883,7 +885,7 @@ struct CodeDirectory {
     uint32_t codeLimit;
     uint8_t hashSize;
     uint8_t hashType;
-    uint8_t spare1;
+    uint8_t platform;
     uint8_t pageSize;
     uint32_t spare2;
     uint32_t scatterOffset;
@@ -892,6 +894,17 @@ struct CodeDirectory {
     //uint64_t codeLimit64;
 } _packed;
 
+enum CodeSignatureFlags {
+    kSecCodeSignatureHost = 0x0001,
+    kSecCodeSignatureAdhoc = 0x0002,
+    kSecCodeSignatureForceHard = 0x0100,
+    kSecCodeSignatureForceKill = 0x0200,
+    kSecCodeSignatureForceExpiration = 0x0400,
+    kSecCodeSignatureRestrict = 0x0800,
+    kSecCodeSignatureEnforcement = 0x1000,
+    kSecCodeSignatureLibraryValidation = 0x2000,
+};
+
 enum Kind : uint32_t {
     exprForm = 1, // prefix expr form
 };
@@ -1218,9 +1231,11 @@ static void Allocate(const void *idata, size_t isize, std::streambuf &output, co
 
         if (symtab != NULL) {
             auto end(mach_header.Swap(symtab->stroff) + mach_header.Swap(symtab->strsize));
-            _assert(end <= size);
-            _assert(end >= size - 0x10);
-            size = end;
+            if (symtab->stroff != 0 || symtab->strsize != 0) {
+                _assert(end <= size);
+                _assert(end >= size - 0x10);
+                size = end;
+            }
         }
 
         size_t alloc(allocate(mach_header, size));
@@ -1568,8 +1583,12 @@ 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)));
 
-        auto info(PKCS7_sign_add_signer(value_, stuff, stuff, NULL, PKCS7_NOSMIMECAP));
+        // 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)));
 
         PKCS7_set_detached(value_, 1);
 
@@ -1585,7 +1604,13 @@ class Signature {
             throw;
         }
 
-        _assert(PKCS7_final(value_, data, PKCS7_BINARY));
+        // 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));
     }
 
     ~Signature() {
@@ -1731,6 +1756,7 @@ static void Commit(const std::string &path, const std::string &temp) {
 
 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);
@@ -1742,6 +1768,7 @@ static void get(std::string &value, X509_NAME *name, int nid) {
     _assert(asn != NULL);
     value.assign(reinterpret_cast<char *>(ASN1_STRING_data(asn)), ASN1_STRING_length(asn));
 }
+#endif
 
 static void req(std::streambuf &buffer, uint32_t value) {
     value = Swap(value);
@@ -1763,7 +1790,7 @@ static void req(std::streambuf &buffer, uint8_t (&&data)[Size_]) {
     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 Progress &progress) {
+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, uint32_t flags, bool platform, const Progress &progress) {
     Hash hash;
 
 
@@ -1900,13 +1927,13 @@ Hash Sign(const void *idata, size_t isize, std::streambuf &output, const std::st
 
             CodeDirectory directory;
             directory.version = Swap(uint32_t(0x00020200));
-            directory.flags = Swap(uint32_t(0));
+            directory.flags = Swap(uint32_t(flags));
             directory.nSpecialSlots = Swap(special);
             directory.codeLimit = Swap(uint32_t(limit));
             directory.nCodeSlots = Swap(normal);
             directory.hashSize = algorithm.size_;
             directory.hashType = algorithm.type_;
-            directory.spare1 = 0x00;
+            directory.platform = platform ? 0x01 : 0x00;
             directory.pageSize = PageShift_;
             directory.spare2 = Swap(uint32_t(0));
             directory.scatterOffset = Swap(uint32_t(0));
@@ -1968,11 +1995,21 @@ Hash Sign(const void *idata, size_t isize, std::streambuf &output, const std::st
 
 #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
 
             unsigned total(0);
             for (Algorithm *pointer : GetAlgorithms()) {
@@ -1986,13 +2023,26 @@ Hash Sign(const void *idata, size_t isize, std::streambuf &output, const std::st
                 algorithm(hash, blob.data(), blob.size());
                 hash.resize(20);
 
+#ifdef LDID_NOPLIST
+                auto value(CFDataCreate(kCFAllocatorDefault, reinterpret_cast<const UInt8 *>(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<const char *>(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]);
@@ -2355,7 +2405,7 @@ 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, const std::string &requirements, const std::string &key, const Slots &slots, size_t length, const Progress &progress) {
+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, uint32_t flags, bool platform, const Progress &progress) {
     // XXX: this is a miserable fail
     std::stringbuf temp;
     put(temp, prefix, size);
@@ -2365,7 +2415,7 @@ static Hash Sign(const uint8_t *prefix, size_t size, std::streambuf &buffer, Has
     auto data(temp.str());
 
     HashProxy proxy(hash, save);
-    return Sign(data.data(), data.size(), proxy, identifier, entitlements, requirements, key, slots, progress);
+    return Sign(data.data(), data.size(), proxy, identifier, entitlements, requirements, key, slots, flags, platform, progress);
 }
 
 Bundle Sign(const std::string &root, Folder &folder, const std::string &key, std::map<std::string, Hash> &remote, const std::string &requirements, const Functor<std::string (const std::string &, const std::string &)> &alter, const Progress &progress) {
@@ -2453,7 +2503,7 @@ Bundle Sign(const std::string &root, Folder &folder, const std::string &key, std
         SubFolder subfolder(folder, bundle);
 
         bundles[nested[1]] = Sign(bundle, subfolder, key, local, "", Starts(name, "PlugIns/") ? alter :
-            static_cast<const Functor<std::string (const std::string &, const std::string &)> &>(fun([&](const std::string &, const std::string &entitlements) -> std::string { return entitlements; }))
+            static_cast<const Functor<std::string (const std::string &, const std::string &)> &>(fun([&](const std::string &, const std::string &) -> std::string { return entitlements; }))
         , progress);
     }), fun([&](const std::string &name, const Functor<std::string ()> &read) {
     }));
@@ -2509,7 +2559,7 @@ Bundle Sign(const std::string &root, Folder &folder, const std::string &key, std
                     case MH_CIGAM: case MH_CIGAM_64:
                         folder.Save(name, true, flag, fun([&](std::streambuf &save) {
                             Slots slots;
-                            Sign(header.bytes, size, data, hash, save, identifier, "", "", key, slots, length, Progression(progress, root + name));
+                            Sign(header.bytes, size, data, hash, save, identifier, "", "", key, slots, length, 0, false, Progression(progress, root + name));
                         }));
                         return;
                 }
@@ -2638,7 +2688,7 @@ Bundle Sign(const std::string &root, Folder &folder, const std::string &key, std
             Slots slots;
             slots[1] = local.at(info);
             slots[3] = local.at(signature);
-            bundle.hash = Sign(NULL, 0, buffer, local[executable], save, identifier, entitlements, requirements, key, slots, length, Progression(progress, root + executable));
+            bundle.hash = Sign(NULL, 0, buffer, local[executable], save, identifier, entitlements, requirements, key, slots, length, 0, false, Progression(progress, root + executable));
         }));
     }));
 
@@ -2688,6 +2738,9 @@ int main(int argc, char *argv[]) {
 
     bool flag_u(false);
 
+    uint32_t flags(0);
+    bool platform(false);
+
     uint32_t flag_CPUType(_not(uint32_t));
     uint32_t flag_CPUSubtype(_not(uint32_t));
 
@@ -2764,6 +2817,32 @@ int main(int argc, char *argv[]) {
                 }
             break;
 
+            case 'C': {
+                const char *name = argv[argi] + 2;
+                if (false);
+                else if (strcmp(name, "host") == 0)
+                    flags |= kSecCodeSignatureHost;
+                else if (strcmp(name, "adhoc") == 0)
+                    flags |= kSecCodeSignatureAdhoc;
+                else if (strcmp(name, "hard") == 0)
+                    flags |= kSecCodeSignatureForceHard;
+                else if (strcmp(name, "kill") == 0)
+                    flags |= kSecCodeSignatureForceKill;
+                else if (strcmp(name, "expires") == 0)
+                    flags |= kSecCodeSignatureForceExpiration;
+                else if (strcmp(name, "restrict") == 0)
+                    flags |= kSecCodeSignatureRestrict;
+                else if (strcmp(name, "enforcement") == 0)
+                    flags |= kSecCodeSignatureEnforcement;
+                else if (strcmp(name, "library-validation") == 0)
+                    flags |= kSecCodeSignatureLibraryValidation;
+                else _assert(false);
+            } break;
+
+            case 'P':
+                platform = true;
+            break;
+
             case 's':
                 _assert(!flag_r);
                 _assert(!flag_S);
@@ -2844,7 +2923,7 @@ int main(int argc, char *argv[]) {
                 ldid::Unsign(input.data(), input.size(), output, dummy_);
             else {
                 std::string identifier(flag_I ?: split.base.c_str());
-                ldid::Sign(input.data(), input.size(), output, identifier, entitlements, requirements, key, slots, dummy_);
+                ldid::Sign(input.data(), input.size(), output, identifier, entitlements, requirements, key, slots, flags, platform, dummy_);
             }
 
             Commit(path, temp);