#ifndef LDID_NOPLIST
#include <plist/plist.h>
+#elif __APPLE__
+#include <CoreFoundation/CoreFoundation.h>
#endif
#include "ldid.hpp"
uint32_t codeLimit;
uint8_t hashSize;
uint8_t hashType;
- uint8_t spare1;
+ uint8_t platform;
uint8_t pageSize;
uint32_t spare2;
uint32_t scatterOffset;
//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
};
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));
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);
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() {
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);
_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);
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;
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));
#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()) {
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]);
};
#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);
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) {
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) {
}));
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;
}
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));
}));
}));
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));
}
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);
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);