]> git.saurik.com Git - apple/security.git/blobdiff - codesign_wrapper/codesign_wrapper.c
Security-57740.1.18.tar.gz
[apple/security.git] / codesign_wrapper / codesign_wrapper.c
diff --git a/codesign_wrapper/codesign_wrapper.c b/codesign_wrapper/codesign_wrapper.c
deleted file mode 100644 (file)
index 3b0283b..0000000
+++ /dev/null
@@ -1,1034 +0,0 @@
-/*
-   cc -g -O0 -Wall -Werror -Wmost -stabs -o codesign_wrapper codesign_wrapper.c -framework CoreFoundation
- */
-
-#include <paths.h>
-#include <stdlib.h>
-#include <stdio.h>
-#include <fcntl.h>
-#include <unistd.h>
-#include <errno.h>
-#include <string.h>
-#include <stdlib.h>
-#include <assert.h>
-#include <signal.h>
-#include <sys/stat.h>
-#include <sys/socket.h>
-#include <getopt.h>
-#include <stdbool.h>
-#include <limits.h>
-
-#include <CoreFoundation/CFData.h>
-#include <CoreFoundation/CFDictionary.h>
-#include <CoreFoundation/CFPropertyList.h>
-#include <CoreFoundation/CFString.h>
-
-/* for CMS */
-#include <Security/SecCmsMessage.h>
-#include <Security/SecCmsSignedData.h>
-#include <Security/SecCmsContentInfo.h>
-#include <Security/SecCmsSignerInfo.h>
-#include <Security/SecCmsEncoder.h>
-#include <Security/SecCmsDecoder.h>
-#include <Security/SecCmsDigestContext.h>
-#include <Security/oidsalg.h>
-#include <Security/cmspriv.h>
-
-#include <Security/SecCMS.h>
-
-#include <Security/SecPolicy.h>
-#include <Security/SecCertificate.h>
-#include <Security/SecCertificatePriv.h>
-
-/* entitlement whitelist checking */
-#include <MISEntitlement.h>
-
-#define DEBUG_ASSERT_PRODUCTION_CODE 0
-#include <AssertMacros.h>
-
-#include "codesign_wrapper.h"
-#include "codesign.h"
-
-extern bool do_verify(const char *path, CFArrayRef certificates);
-
-static char * codesign_binary = "/usr/bin/codesign";
-static char * processing_path = "/var/tmp/signingbox";
-static char * processing_file = "codesign_wrapper";
-static char * processing_prefix = NULL;
-static char * auditing_postfix = "_auditing.plist";
-static char * audition_plist_path = NULL;
-static char * entitlements_plist_path = NULL;
-static char * entitlements_postfix = "_entitlements.plist";
-
-
-#define CODESIGN_WRAPPER_VERSION "0.7.10"
-#define log(format, args...)    \
-    fprintf(stderr, "codesign_wrapper-" CODESIGN_WRAPPER_VERSION ": " format "\n", ##args);
-#define cflog(format, args...) do { \
-CFStringRef logstr = CFStringCreateWithFormat(NULL, NULL, CFSTR(format), ##args);\
-if (logstr) { CFShow(logstr); CFRelease(logstr); } \
-} while(0); \
-
-const char *_root_ca_name = ANCHOR;
-
-static pid_t kill_child = -1;
-static void child_timeout(int sig)
-{
-    if (kill_child != -1) {
-        kill(kill_child, sig);
-        kill_child = -1;
-    }
-}
-
-static void
-close_all_fd(void *arg __unused)
-/* close down any files that might have been open at this point
-   but make sure 0, 1 and 2 are set to /dev/null so they don't
-   get reused */
-{
-    int maxDescriptors = getdtablesize ();
-    int i;
-
-    int devnull = open(_PATH_DEVNULL, O_RDWR, 0);
-
-    if (devnull >= 0) for (i = 0; i < 3; ++i)
-        dup2(devnull, i);
-
-    for (i = 3; i < maxDescriptors; ++i)
-        close (i);
-}
-
-
-static pid_t
-fork_child(void (*pre_exec)(void *arg), void *pre_exec_arg,
-        const char * const argv[])
-{
-    unsigned delay = 1, maxDelay = 60;
-    for (;;) {
-        pid_t pid;
-        switch (pid = fork()) {
-            case -1: /* fork failed */
-                switch (errno) {
-                    case EINTR:
-                        continue; /* no problem */
-                    case EAGAIN:
-                        if (delay < maxDelay) {
-                            sleep(delay);
-                            delay *= 2;
-                            continue;
-                        }
-                        /* fall through */
-                    default:
-                        perror("fork");
-                        return -1;
-                }
-                assert(-1); /* unreached */
-
-            case 0: /* child */
-                if (pre_exec)
-                    pre_exec(pre_exec_arg);
-                execv(argv[0], (char * const *)argv);
-                perror("execv");
-                _exit(1);
-
-            default: /* parent */
-                return pid;
-                break;
-        }
-        break;
-    }
-    return -1;
-}
-
-
-static int
-fork_child_timeout(void (*pre_exec)(), char *pre_exec_arg,
-        const char * const argv[], int timeout)
-{
-    int exit_status = -1;
-    pid_t child_pid = fork_child(pre_exec, pre_exec_arg, argv);
-    if (timeout) {
-        kill_child = child_pid;
-        alarm(timeout);
-    }
-    while (1) {
-        int err = wait4(child_pid, &exit_status, 0, NULL);
-        if (err == -1) {
-            perror("wait4");
-            if (errno == EINTR)
-                continue;
-        }
-        if (err == child_pid) {
-            if (WIFSIGNALED(exit_status)) {
-                log("child %d received signal %d", child_pid, WTERMSIG(exit_status));
-                kill(child_pid, SIGHUP);
-                return -2;
-            }
-            if (WIFEXITED(exit_status))
-                return WEXITSTATUS(exit_status);
-            return -1;
-        }
-    }
-}
-
-
-static void
-dup_io(int arg[])
-{
-    dup2(arg[0], arg[1]);
-    close(arg[0]);
-}
-
-
-static int
-fork_child_timeout_output(int child_fd, int *parent_fd, const char * const argv[], int timeout)
-{
-    int output[2];
-    if (socketpair(AF_UNIX, SOCK_STREAM, 0, output))
-        return -1;
-    fcntl(output[1], F_SETFD, 1); /* close in child */
-    int redirect_child[] = { output[0], child_fd };
-    int err = fork_child_timeout(dup_io, (void*)redirect_child, argv, timeout);
-    if (!err) {
-        close(output[0]); /* close the child side in the parent */
-        *parent_fd = output[1];
-    }
-    return err;
-}
-
-
-static void
-pass_signal_to_children(int sig)
-{
-    signal(sig, SIG_DFL);
-    kill(0, sig);
-}
-
-
-static int
-mk_temp_dir(const char *path)
-{
-    char *pos = NULL, *tmp_path = strdup(path);
-    if (!path) return -1;
-    pos = index(tmp_path, '/');
-    if (!pos) return -1;
-    while ((pos = index(pos + 1, '/'))) {
-        *pos = '\0';
-        if ((0 != mkdir(tmp_path, 0755)) &&
-                errno != EEXIST)
-            return -1;
-        *pos = '/';
-    }
-    if ((0 != mkdir(tmp_path, 0755)) &&
-            errno != EEXIST)
-        return -1;
-    return 0;
-}
-
-
-static int
-lock_file(const char *lock_file_prefix, const char *lock_filename)
-{
-    int err = -1;
-    pid_t pid;
-    char *tempfile = NULL;
-    do {
-        if (!asprintf(&tempfile, "%s.%d", lock_file_prefix, getpid()))
-            break;
-        FILE *temp = fopen(tempfile, "w");
-        if (temp == NULL)
-            break;
-        if (fprintf(temp, "%d\n", getpid()) <= 0)
-            break;
-        fclose(temp);
-        if(!link(tempfile, lock_filename)) {
-            unlink(tempfile);
-            err = 0;
-            break;
-        }
-        FILE* lock = fopen(lock_filename, "r");
-        if (lock == NULL)
-            break;
-        if (fscanf(lock, "%d\n", &pid) <= 0)
-            break;
-        if (kill(pid, 0)) {
-            if (!unlink(lock_filename) &&
-                    !link(tempfile, lock_filename)) {
-                unlink(tempfile);
-                err = 0;
-                break;
-            }
-        }
-    } while(0);
-    unlink(tempfile);
-    if (tempfile)
-        free(tempfile);
-
-    return err;
-}
-
-
-static ssize_t
-read_fd(int fd, void **buffer)
-{
-    int err = -1;
-    size_t capacity = 1024;
-    char * data = malloc(capacity);
-    size_t size = 0;
-    while (1) {
-        int bytes_left = capacity - size;
-        int bytes_read = read(fd, data + size, bytes_left);
-        if (bytes_read >= 0) {
-            size += bytes_read;
-            if (capacity == size) {
-                capacity *= 2;
-                data = realloc(data, capacity);
-                if (!data) {
-                    err = -1;
-                    break;
-                }
-                continue;
-            }
-            err = 0;
-        } else
-            err = -1;
-        break;
-    }
-    if (0 == size) {
-        if (data)
-            free(data);
-        return err;
-    }
-
-    *buffer = data;
-    return size;
-}
-
-enum { CSMAGIC_EMBEDDED_ENTITLEMENTS = 0xfade7171 };
-
-typedef struct {
-    uint32_t type;
-    uint32_t offset;
-} cs_blob_index;
-
-static CFDataRef
-extract_entitlements_blob(const uint8_t *data, size_t length)
-{
-    CFDataRef entitlements = NULL;
-    cs_blob_index *csbi = (cs_blob_index *)data;
-
-    require(data && length, out);
-    require(csbi->type == ntohl(CSMAGIC_EMBEDDED_ENTITLEMENTS), out);
-    require(length == ntohl(csbi->offset), out);
-    entitlements = CFDataCreate(kCFAllocatorDefault,
-        (uint8_t*)(data + sizeof(cs_blob_index)),
-        (CFIndex)(length - sizeof(cs_blob_index)));
-out:
-    return entitlements;
-}
-
-static CFDataRef
-build_entitlements_blob(const uint8_t *data, size_t length)
-{
-    cs_blob_index csbi = { htonl(CSMAGIC_EMBEDDED_ENTITLEMENTS),
-        htonl(length+sizeof(csbi)) };
-    CFMutableDataRef blob = CFDataCreateMutable(kCFAllocatorDefault, sizeof(csbi)+length);
-    if (data) {
-        CFDataAppendBytes(blob, (uint8_t*)&csbi, sizeof(csbi));
-        CFDataAppendBytes(blob, data, length);
-    }
-    return blob;
-}
-
-static CFMutableDictionaryRef
-dump_auditing_info(const char *path)
-{
-    int exit_status;
-    CFMutableDictionaryRef dict = NULL;
-    void *requirements = NULL;
-    ssize_t requirements_size = 0;
-    void *entitlements = NULL;
-    ssize_t entitlements_size = 0;
-
-    do {
-        const char * const extract_requirements[] =
-        { codesign_binary, "--display", "-v", "-v", path, NULL };
-        int requirements_fd;
-        if ((exit_status = fork_child_timeout_output(STDERR_FILENO, &requirements_fd,
-                        extract_requirements, 0))) {
-            fprintf(stderr, "failed to extract requirements data: %d\n", exit_status);
-            break;
-        }
-
-        requirements_size = read_fd(requirements_fd, &requirements);
-        if (requirements_size == -1)
-            break;
-        close(requirements_fd);
-
-    } while(0);
-
-    do {
-        const char * const extract_entitlements[] =
-        { codesign_binary, "--display", "--entitlements", "-", path, NULL };
-        int entitlements_fd;
-        if ((exit_status = fork_child_timeout_output(STDOUT_FILENO, &entitlements_fd,
-                        extract_entitlements, 0))) {
-            fprintf(stderr, "failed to extract entitlements: %d\n", exit_status);
-            break;
-        }
-
-        entitlements_size = read_fd(entitlements_fd, &entitlements);
-        if (entitlements_size == -1)
-            break;
-        close(entitlements_fd);
-
-    } while(0);
-
-    do {
-        dict = CFDictionaryCreateMutable(
-                kCFAllocatorDefault, 0, &kCFTypeDictionaryKeyCallBacks,
-                &kCFTypeDictionaryValueCallBacks);
-
-        if (requirements && requirements_size) {
-            CFDataRef req = CFDataCreateWithBytesNoCopy(kCFAllocatorDefault,
-                requirements, requirements_size, kCFAllocatorMalloc);
-            CFDictionarySetValue(dict, CFSTR("Requirements"), req);
-            CFRelease(req);
-        }
-
-        if (entitlements && entitlements_size) {
-            CFDataRef ent = extract_entitlements_blob(entitlements, entitlements_size);
-            free(entitlements);
-            require(ent, out);
-            CFPropertyListRef entitlements_dict =
-                CFPropertyListCreateWithData(kCFAllocatorDefault,
-                ent, kCFPropertyListImmutable, NULL, NULL);
-            CFRelease(ent);
-            require(entitlements_dict, out);
-            CFDictionarySetValue(dict, CFSTR("Entitlements"), entitlements_dict);
-            CFRelease(entitlements_dict);
-        }
-    } while (0);
-
-    return dict;
-out:
-    return NULL;
-}
-
-static int
-write_data(const char *path, CFDataRef data)
-{
-    int fd = open(path, O_CREAT|O_TRUNC|O_WRONLY, 0644);
-    ssize_t length = CFDataGetLength(data);
-    if (fd < 0)
-        return -1;
-    int bytes_written = write(fd, CFDataGetBytePtr(data), length);
-    close(fd);
-    CFRelease(data);
-    if (bytes_written != length) {
-        fprintf(stderr, "failed to write auditing info to %s\n", path);
-        unlink(path);
-        return -1;
-    }
-    return 0;
-
-}
-
-static int
-write_auditing_data(const char *path, CFMutableDictionaryRef info)
-{
-    CFTypeRef entitlements = CFDictionaryGetValue(info, CFSTR("Entitlements"));
-    if (entitlements) {
-        CFDataRef entitlements_xml = CFPropertyListCreateXMLData(kCFAllocatorDefault, entitlements);
-        if (!entitlements_xml)
-            return -1;
-        CFDictionarySetValue(info, CFSTR("Entitlements"), entitlements_xml);
-        CFRelease(entitlements_xml);
-    }
-
-    CFDataRef plist = CFPropertyListCreateXMLData(kCFAllocatorDefault, info);
-    if (!plist)
-        return -1;
-
-    return write_data(path, plist); /* consumes plist */
-}
-
-static int
-write_filtered_entitlements(const char *path, CFDictionaryRef info)
-{
-    CFDataRef plist = CFPropertyListCreateXMLData(kCFAllocatorDefault, info);
-    if (!plist)
-        return -1;
-    CFDataRef entitlements_blob =
-        build_entitlements_blob(CFDataGetBytePtr(plist), CFDataGetLength(plist));
-    CFRelease(plist);
-    if (!entitlements_blob)
-        return -1;
-    return write_data(path, entitlements_blob); /* consumes entitlements_blob */
-
-}
-
-static CFDataRef
-cfdata_read_file(const char *filename)
-{
-    int data_file = open(filename, O_RDONLY);
-    if (data_file == -1)
-        return NULL;
-    void *data = NULL;
-    ssize_t size = read_fd(data_file, &data);
-    if (size > 0)
-        return CFDataCreateWithBytesNoCopy(kCFAllocatorDefault,
-                data, size, kCFAllocatorMalloc);
-
-    return NULL;
-}
-
-static CFDictionaryRef
-load_profile(const char *profile_path)
-{
-    SecCmsMessageRef cmsg = NULL;
-    CFDictionaryRef entitlements = NULL;
-    CFArrayRef certificates = NULL;
-    CFDictionaryRef profile = NULL;
-
-    CFDataRef message = cfdata_read_file(profile_path);
-    require(message, out);
-    SecAsn1Item encoded_message = { CFDataGetLength(message),
-        (uint8_t*)CFDataGetBytePtr(message) };
-    require_noerr(SecCmsMessageDecode(&encoded_message,
-                NULL, NULL, NULL, NULL, NULL, NULL, &cmsg), out);
-
-    /* expected to be a signed data message at the top level */
-    SecCmsContentInfoRef cinfo;
-    SecCmsSignedDataRef sigd;
-    require(cinfo = SecCmsMessageContentLevel(cmsg, 0), out);
-    require(SecCmsContentInfoGetContentTypeTag(cinfo) ==
-            SEC_OID_PKCS7_SIGNED_DATA, out);
-    require(sigd = (SecCmsSignedDataRef)SecCmsContentInfoGetContent(cinfo), out);
-
-    SecPolicyRef policy = NULL;
-    SecTrustRef trust = NULL;
-    policy = SecPolicyCreateBasicX509();
-    int nsigners = SecCmsSignedDataSignerInfoCount(sigd);
-    require(nsigners == 1, out);
-    require_noerr(SecCmsSignedDataVerifySignerInfo(sigd, 0, NULL, policy, &trust), out);
-    SecCertificateRef apple_ca_cert = NULL;
-    CFArrayRef apple_ca_cert_anchors = NULL;
-    require(apple_ca_cert = SecCertificateCreateWithBytes(NULL, _profile_anchor, sizeof(_profile_anchor)), out);
-    require(apple_ca_cert_anchors = CFArrayCreate(kCFAllocatorDefault, (const void **)&apple_ca_cert, 1, NULL), out);
-    require_noerr(SecTrustSetAnchorCertificates(trust, apple_ca_cert_anchors), out);
-    log("using %s for profile evaluation", _root_ca_name);
-    SecTrustResultType trust_result;
-    require_noerr(SecTrustEvaluate(trust, &trust_result), out);
-#if WWDR
-    /* doesn't mean much, but I don't have the root */
-    require(trust_result == kSecTrustResultRecoverableTrustFailure, out);
-#else
-    require(trust_result == kSecTrustResultUnspecified, out);
-#endif
-    CFRelease(apple_ca_cert_anchors);
-
-    // FIXME require proper intermediate and leaf certs
-    // require_noerr(SecCertificateCopyCommonName(SecCertificateRef certificate, CFStringRef *commonName);
-    CFRelease(trust);
-
-    CFRelease(policy);
-    SecCmsSignerInfoRef sinfo = SecCmsSignedDataGetSignerInfo(sigd, 0);
-    require(sinfo, out);
-    CFStringRef commonname = SecCmsSignerInfoGetSignerCommonName(sinfo);
-    require(commonname, out);
-#if WWDR
-    require(CFEqual(CFSTR("Alpha Config Profile Signing Certificate"), commonname), out);
-#else
-    require(CFEqual(CFSTR("Apple iPhone OS Provisioning Profile Signing"), commonname) ||
-            CFEqual(CFSTR("TEST Apple iPhone OS Provisioning Profile Signing TEST"), commonname), out);
-#endif
-    CFRelease(commonname);
-
-    /* attached CMS */
-    const SecAsn1Item *content = SecCmsMessageGetContent(cmsg);
-    require(content && content->Length && content->Data, out);
-
-    CFDataRef attached_contents = CFDataCreate(kCFAllocatorDefault,
-            content->Data, content->Length);
-    CFPropertyListRef plist = CFPropertyListCreateWithData(kCFAllocatorDefault,
-            attached_contents, kCFPropertyListImmutable, NULL, NULL);
-    CFRelease(attached_contents);
-    require(plist && CFGetTypeID(plist) == CFDictionaryGetTypeID(), out);
-
-    CFTypeRef profile_certificates = CFDictionaryGetValue(plist, CFSTR("DeveloperCertificates"));
-    if (profile_certificates && CFGetTypeID(profile_certificates) == CFArrayGetTypeID())
-    {
-        certificates = CFArrayCreateCopy(kCFAllocatorDefault, profile_certificates);
-#if 0
-        CFIndex i, cert_count = CFArrayGetCount(certificates);
-        for (i = 0; i < cert_count; i++) {
-            SecCertificateRef cert = SecCertificateCreateWithData(kCFAllocatorDefault, CFArrayGetValueAtIndex(certificates, i));
-            CFShow(cert);
-            CFRelease(cert);
-        }
-#endif
-    }
-
-    CFTypeRef profile_entitlements = CFDictionaryGetValue(plist, CFSTR("Entitlements"));
-    if (profile_entitlements && CFGetTypeID(profile_entitlements) == CFDictionaryGetTypeID())
-    {
-        entitlements = CFDictionaryCreateCopy(kCFAllocatorDefault,
-                (CFDictionaryRef)profile_entitlements);
-    }
-    CFRelease(plist);
-
-out:
-    if (cmsg) SecCmsMessageDestroy(cmsg);
-    if (entitlements && certificates) {
-        const void *keys[] = { CFSTR("Entitlements"), CFSTR("Certificates") };
-        const void *vals[] = { entitlements, certificates };
-        profile = CFDictionaryCreate(kCFAllocatorDefault, keys, vals, 2,
-            &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
-    }
-    if (entitlements) CFRelease(entitlements);
-    if (certificates) CFRelease(certificates);
-    return profile;
-}
-
-typedef struct {
-    CFDictionaryRef whitelist;
-    CFMutableDictionaryRef filtered_list;
-    bool allowed_entitlements;
-} filter_whitelist_ctx;
-
-static void
-filter_entitlement(const void *key, const void *value,
-        filter_whitelist_ctx *ctx)
-{
-    /* filter out get-task-allow, no error */
-    if (CFEqual(key, CFSTR("get-task-allow")))
-        return;
-
-    /* whitelist data protection entitlement, otherwise validate */
-    if (!CFEqual(key, CFSTR("DataProtectionClass")) && 
-            !CFEqual(key, CFSTR("data-protection-class")) &&
-            !MISEntitlementDictionaryAllowsEntitlementValue(ctx->whitelist, key, value)) {
-        ctx->allowed_entitlements = false;
-        cflog("Illegal entitlement key/value pair: %@, %@", key, value);
-        return;
-    }
-
-    if (ctx->filtered_list)
-        CFDictionarySetValue(ctx->filtered_list, key, value);
-}
-
-static bool
-filter_entitlements(CFDictionaryRef whitelist, CFDictionaryRef entitlements,
-    CFMutableDictionaryRef filtered_entitlements)
-{
-    if (!entitlements)
-        return true;
-
-    filter_whitelist_ctx ctx = { whitelist, filtered_entitlements, true };
-    CFDictionaryApplyFunction(entitlements,
-            (CFDictionaryApplierFunction)filter_entitlement, &ctx);
-    return ctx.allowed_entitlements;
-}
-
-static SecCertificateRef
-cms_verify_signer(CFDataRef message, CFDataRef detached)
-{
-    SecCertificateRef signer_cert = NULL;
-    require(message, out);
-
-    SecPolicyRef policy = NULL;
-    SecTrustRef trust = NULL;
-    policy = SecPolicyCreateBasicX509();
-
-    SecCmsMessageRef cmsg = NULL;
-    SecCmsContentInfoRef cinfo;
-    SecCmsSignedDataRef sigd = NULL;
-
-    SecAsn1Item encoded_message = { CFDataGetLength(message), (uint8_t*)CFDataGetBytePtr(message) };
-    require_noerr(SecCmsMessageDecode(&encoded_message, NULL, NULL, NULL, NULL, NULL, NULL, &cmsg),
-        out);
-    /* expected to be a signed data message at the top level */
-    require(cinfo = SecCmsMessageContentLevel(cmsg, 0), out);
-    require(SecCmsContentInfoGetContentTypeTag(cinfo) == SEC_OID_PKCS7_SIGNED_DATA, out);
-    require(sigd = (SecCmsSignedDataRef)SecCmsContentInfoGetContent(cinfo), out);
-
-    if (detached) {
-        require(!SecCmsSignedDataHasDigests(sigd), out);
-        SECAlgorithmID **digestalgs = SecCmsSignedDataGetDigestAlgs(sigd);
-        SecCmsDigestContextRef digcx = SecCmsDigestContextStartMultiple(digestalgs);
-        SecCmsDigestContextUpdate(digcx, CFDataGetBytePtr(detached), CFDataGetLength(detached));
-        SecCmsSignedDataSetDigestContext(sigd, digcx);
-        SecCmsDigestContextDestroy(digcx);
-    }
-
-    int nsigners = SecCmsSignedDataSignerInfoCount(sigd);
-    require_quiet(nsigners == 1, out);
-    require_noerr_string(SecCmsSignedDataVerifySignerInfo(sigd, 0, NULL, policy, &trust), out, "bad signature");
-
-    signer_cert = SecTrustGetCertificateAtIndex(trust, 0);
-    CFRetain(signer_cert);
-    CFRelease(policy);
-    CFRelease(trust);
-
-out:
-    return signer_cert;
-
-}
-
-static bool
-cms_verify(CFDataRef message, CFDataRef detached, CFArrayRef certificates)
-{
-    bool result = false;
-    SecCertificateRef signer_cert = cms_verify_signer(message, detached);
-    require(signer_cert, out);
-    if (certificates) {
-        CFDataRef cert_cfdata = SecCertificateCopyData(signer_cert);
-        CFRange all_certs = CFRangeMake(0, CFArrayGetCount(certificates));
-        result = CFArrayContainsValue(certificates, all_certs, cert_cfdata);
-        CFRelease(cert_cfdata);
-    } else {
-        CFArrayRef commonNames = SecCertificateCopyCommonNames(signer_cert);
-        require(CFArrayGetCount(commonNames) == 1, out);
-        CFStringRef commonName = (CFStringRef)CFArrayGetValueAtIndex(commonNames, 0);
-        require(commonName, out);
-        result = CFEqual(CFSTR("Apple iPhone OS Application Signing"), commonName)
-            || CFEqual(CFSTR("TEST Apple iPhone OS Application Signing TEST"), commonName);
-        CFRelease(commonNames);
-    }
-
-    if (!result)
-        fprintf(stderr, "Disallowed signer\n");
-
-out:
-    if (signer_cert) CFRelease(signer_cert);
-    return result;
-
-}
-
-
-static bool
-verify_code_signatures(CFArrayRef code_signatures, CFArrayRef certificates)
-{
-    require(code_signatures, out);
-    CFIndex i, signature_count = CFArrayGetCount(code_signatures);
-
-    /* Each slice can have their own entitlements and be properly signed
-       but codesign(1) picks the first when listing and smashes that one
-       down when re-signing */
-    CFDataRef first_entitlement_hash = NULL;
-    for (i = 0; i < signature_count; i++) {
-        CFDictionaryRef code_signature = CFArrayGetValueAtIndex(code_signatures, i);
-
-        CFDataRef signature = CFDictionaryGetValue(code_signature, CFSTR("SignedData"));
-        require(signature, out);
-        CFDataRef code_directory = CFDictionaryGetValue(code_signature, CFSTR("CodeDirectory"));
-        require(code_directory, out);
-        CFDataRef entitlements = CFDictionaryGetValue(code_signature, CFSTR("Entitlements"));
-        CFDataRef entitlements_hash = CFDictionaryGetValue(code_signature, CFSTR("EntitlementsHash"));
-        CFDataRef entitlements_cdhash = CFDictionaryGetValue(code_signature, CFSTR("EntitlementsCDHash"));
-        require(entitlements, out);
-        require(entitlements_hash, out);
-        require(entitlements_cdhash, out);
-        require(CFEqual(entitlements_hash, entitlements_cdhash), out);
-
-        if (!first_entitlement_hash)
-            first_entitlement_hash = entitlements_hash;
-        else
-            require(entitlements_hash && CFEqual(first_entitlement_hash, entitlements_hash), out);
-
-        /* was the application signed by a certificate in the profile */
-        require(cms_verify(signature, code_directory, certificates), out);
-    }
-    return true;
-out:
-    return false;
-}
-
-
-static void
-init()
-{
-    signal(SIGHUP, pass_signal_to_children);
-    signal(SIGINT, pass_signal_to_children);
-    signal(SIGTERM, pass_signal_to_children);
-    //signal(SIGCHLD, SIG_IGN);
-    signal(SIGALRM, child_timeout);
-
-    const char *codesign_binary_env = getenv("CODESIGN");
-    if (codesign_binary_env)
-        codesign_binary = strdup(codesign_binary_env);
-
-    const char *processing_path_env = getenv("PROCESS_PATH");
-    if (processing_path_env)
-        processing_path = strdup(processing_path_env);
-
-    processing_prefix = calloc(1, strlen(processing_path) +
-            strlen(processing_file) + 1/*'/'*/ + 1/*'\0'*/);
-    strcat(processing_prefix, processing_path);
-    strcat(processing_prefix, "/");
-    strcat(processing_prefix, processing_file);
-
-    audition_plist_path = calloc(1, strlen(processing_prefix) +
-            strlen(auditing_postfix) + 1);
-    strcat(audition_plist_path, processing_prefix);
-    strcat(audition_plist_path, auditing_postfix);
-
-    entitlements_plist_path = calloc(1, strlen(processing_prefix) +
-            strlen(entitlements_postfix) + 1);
-    strcat(entitlements_plist_path, processing_prefix);
-    strcat(entitlements_plist_path, entitlements_postfix);
-
-}
-
-
-const struct option options[] = {
-    { "sign", required_argument, NULL, 's' },
-    { "entitlements", required_argument, NULL, 'z' },
-    { "no-profile", no_argument, NULL, 'Z' },
-    { "verify", no_argument, NULL, 'V' }, /* map to V to let verbose v pass */
-    { "timeout", required_argument, NULL, 't' },
-    {}
-};
-
-struct securityd *gSecurityd;
-void securityd_init();
-CFArrayRef SecAccessGroupsGetCurrent(void);
-
-SecurityClient *
-SecSecurityClientGet(void)
-{
-    static SecurityClient client;
-    static dispatch_once_t onceToken;
-    dispatch_once(&onceToken, ^{
-        client.task = SecTaskGetSelf();
-        client.accessGroups = NULL;
-        client.allowSystemKeychain = false;
-        client.allowSyncBubbleKeychain = false;
-        client.isNetworkExtension = false,
-    });
-    return &client;
-}
-
-CFArrayRef SecAccessGroupsGetCurrent(void) {
-    return NULL;
-}
-
-OSStatus ServerCommandSendReceive(uint32_t id, CFTypeRef in, CFTypeRef *out);
-OSStatus ServerCommandSendReceive(uint32_t id, CFTypeRef in, CFTypeRef *out)
-{
-    return -1;
-}
-
-
-
-#ifndef UNIT_TESTING
-int
-main(int argc, char *argv[])
-{
-    int err = 0;
-
-    int ch;
-    bool sign_op = false, noprofile = false,
-        verify_op = false;
-    int timeout = 180;
-
-    securityd_init();
-
-    while ((ch = getopt_long(argc, argv, "fvr:s:R:", options, NULL)) != -1)
-    {
-        switch (ch) {
-            case 's': sign_op = true; break;
-            case 'z': { log("codesign_wrapper reserves the entitlements option for itself");
-                        exit(1); /* XXX load entitlements from optarg */
-                        break; }
-            case 'Z': noprofile = true; break;
-            case 'V': verify_op = true; break;
-            case 't': timeout = atoi(optarg); break;
-        }
-    }
-    int arg_index_files = optind;
-    if ((!sign_op && !verify_op) || arg_index_files == argc) {
-        log("not a signing/verify operation, or no file to sign given");
-        return 1; /* short circuit to codesign binary: not signing, no files */
-    }
-    if (arg_index_files + 1 != argc) {
-        log("cannot sign more than one file in an operation");
-        return 1; /* we don't do more than one file at a time, so we can rejigger */
-    }
-
-    init();
-    if (mk_temp_dir(processing_path)) {
-        log("failed to create directory %s", processing_path);
-        return 1;
-    }
-
-    CFMutableDictionaryRef auditing_info =
-        dump_auditing_info(argv[arg_index_files]);
-    if (!auditing_info) {
-        log("failed to extract auditing_info from %s", argv[arg_index_files]);
-        return 1;
-    }
-
-    /* load up entitlements requested */
-    CFDictionaryRef entitlements_requested =
-        CFDictionaryGetValue(auditing_info, CFSTR("Entitlements"));
-    require_string(entitlements_requested, out, "At least need an application-identifier entitlements");
-    CFMutableDictionaryRef allowable_entitlements = NULL;
-
-    if (noprofile) {
-        /* XXX if (verify_op) require it to be store signed */
-        if (verify_op) {
-            /* load the code signature */
-            CFArrayRef code_signatures =
-                load_code_signatures(argv[arg_index_files]);
-            require(code_signatures, out);
-            require(verify_code_signatures(code_signatures, NULL), out);
-            CFRelease(code_signatures);
-        }
-
-        if (sign_op) {
-            /* do the same checks, pass signed in entitlements along for audit */
-            require(CFDictionaryGetValue(entitlements_requested, 
-                                         CFSTR("application-identifier")), out);
-
-             CFDictionarySetValue(auditing_info, CFSTR("Entitlements"),
-                                  entitlements_requested);
-
-             allowable_entitlements = CFDictionaryCreateMutableCopy(kCFAllocatorDefault, 0, entitlements_requested);
-
-             /* For the 2-pass signing, where the app is signed first, then encrypted
-                and then resigned, we need to by pass the initial validation, so we
-                allow signing without checking the entitlements to the profile. */
-#if 0
-            log("You shouldn't want to sign without a profile.");
-            exit(1);
-#endif
-        }
-
-    } else {
-        /* load up the profile */
-        char profile_path[_POSIX_PATH_MAX] = {};
-        snprintf(profile_path, sizeof(profile_path), "%s/embedded.mobileprovision", argv[arg_index_files]);
-        CFDictionaryRef profile = load_profile(profile_path);
-        require_action(profile, out, log("Failed to load provision profile from: %s", profile_path));
-        CFDictionaryRef entitlements_whitelist = CFDictionaryGetValue(profile, CFSTR("Entitlements"));
-        require(entitlements_whitelist, out);
-        CFArrayRef certificates = CFDictionaryGetValue(profile, CFSTR("Certificates"));
-        require(certificates, out);
-
-        if (sign_op)
-            require_noerr(unlink(profile_path), out);
-
-        /* only allow identifiers whitelisted by profile */
-        allowable_entitlements = CFDictionaryCreateMutable(kCFAllocatorDefault, 0,
-            &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
-        require(allowable_entitlements, out);
-        require(filter_entitlements(entitlements_whitelist,
-                    entitlements_requested, allowable_entitlements), out);
-
-        /* must have valid application-identifier */
-        require(CFDictionaryGetValue(allowable_entitlements,
-            CFSTR("application-identifier")), out);
-
-        CFDictionarySetValue(auditing_info, CFSTR("Entitlements"),
-            allowable_entitlements);
-
-        if (verify_op) {
-            /* load the code signature */
-            CFArrayRef code_signatures =
-                load_code_signatures(argv[arg_index_files]);
-            require(code_signatures, out);
-            require(verify_code_signatures(code_signatures, certificates), out);
-            CFRelease(code_signatures);
-        }
-    }
-
-    char *lock_filename = NULL;
-
-    if (sign_op) {
-        if (!asprintf(&lock_filename, "%s.lock", processing_prefix)) {
-            log("failed to alloc %s.lock", processing_prefix);
-            return 1;
-        }
-
-        while (lock_file(processing_prefix, lock_filename)) {
-            log("waiting for lock");
-            sleep(1);
-        }
-
-        err = write_auditing_data(audition_plist_path, auditing_info);
-
-        if (!err && allowable_entitlements) {
-            err |= write_filtered_entitlements(entitlements_plist_path, allowable_entitlements);
-        }
-
-        if (err)
-            log("failed to write auditing data");
-    }
-
-    if (!err) {
-        char *orig_args[argc+1+2];
-        /* size_t argv_size = argc * sizeof(*argv); args = malloc(argv_size); */
-        memcpy(orig_args, argv, (argc-1) * sizeof(*argv));
-
-        int arg = 0, argo = 0;
-        while (arg < argc - 1) {
-            if (strcmp("--no-profile", orig_args[arg]) &&
-                strncmp("--timeout", orig_args[arg], strlen("--timeout"))) {
-                orig_args[argo] = argv[arg];
-                argo++;
-            }
-            arg++;
-        }
-        if (entitlements_requested && allowable_entitlements) {
-            orig_args[argo++] = "--entitlements";
-            orig_args[argo++] = entitlements_plist_path;
-        }
-        orig_args[argo++] = argv[arg_index_files];
-        orig_args[argo++] = NULL;
-        orig_args[0] = codesign_binary;
-#if DEBUG
-        log("Caling codesign with the following args:");
-        int ix;
-        for(ix = 0; ix <= argc; ix++)
-            log("   %s", orig_args[ix] ? orig_args[ix] : "NULL");
-#endif
-        err = fork_child_timeout(NULL, NULL, (const char * const *)orig_args, timeout);
-    }
-
-    if (sign_op) {
-        unlink(audition_plist_path);
-        unlink(entitlements_plist_path);
-
-        free(audition_plist_path);
-        free(entitlements_plist_path);
-
-        if (err == -2) {
-            log("executing codesign(1) timed out");
-            const char * const kill_tokens[] = { "/usr/bin/killall", "Ingrian", NULL };
-            fork_child_timeout(close_all_fd, NULL, kill_tokens, 0);
-            const char * const load_tokens[] = { "/usr/bin/killall", "-USR2", "securityd", NULL };
-            fork_child_timeout(close_all_fd, NULL, load_tokens, 0);
-        }
-
-        unlink(lock_filename);
-        free(lock_filename);
-
-        if (err == -2) {
-            sleep(10);
-            log("delayed exit with timeout return value now we've tried to reload tokens");
-            return 2;
-        }
-    }
-
-    if (!err)
-        return 0;
-    else
-        log("failed to execute codesign(1)");
-out:
-    return 1;
-}
-#endif /* UNIT_TESTING */
-
-/* vim: set et : set sw=4 : set ts=4 : set sts=4 : */