/*
- * Copyright (c) 2007 Apple Inc. All Rights Reserved.
+ * Copyright (c) 2006-2010 Apple Inc. All Rights Reserved.
*
* @APPLE_LICENSE_HEADER_START@
*
#include <CoreFoundation/CFBundlePriv.h>
#include "renum.h"
#include "machorep.h"
+#include "csutilities.h"
#include <security_utilities/unix++.h>
#include <security_utilities/unixchild.h>
#include <security_utilities/cfmunge.h>
{
rep = code->diskRep()->base();
this->prepare(flags);
+ PreSigningContext context(*this);
if (Universal *fat = state.mNoMachO ? NULL : rep->mainExecutableImage()) {
- signMachO(fat);
+ signMachO(fat, context);
} else {
- signArchitectureAgnostic();
+ signArchitectureAgnostic(context);
}
}
rep = code->diskRep();
if (Universal *fat = state.mNoMachO ? NULL : rep->mainExecutableImage()) {
// architecture-sensitive removal
- MachOEditor editor(rep->writer(), *fat, rep->mainExecutablePath());
+ MachOEditor editor(rep->writer(), *fat, kSecCodeSignatureNoHash, rep->mainExecutablePath());
editor.allocate(); // create copy
editor.commit(); // commit change
} else {
// work out the canonical identifier
identifier = state.mIdentifier;
if (identifier.empty()) {
- identifier = rep->recommendedIdentifier();
+ identifier = rep->recommendedIdentifier(state);
if (identifier.find('.') == string::npos)
identifier = state.mIdentifierPrefix + identifier;
+ if (identifier.find('.') == string::npos && state.isAdhoc())
+ identifier = identifier + "-" + uniqueName();
secdebug("signer", "using default identifier=%s", identifier.c_str());
} else
secdebug("signer", "using explicit identifier=%s", identifier.c_str());
} else {
cdFlags = 0;
if (infoDict)
- if (CFTypeRef csflags = CFDictionaryGetValue(infoDict, CFSTR("CSFlags")))
+ if (CFTypeRef csflags = CFDictionaryGetValue(infoDict, CFSTR("CSFlags"))) {
if (CFGetTypeID(csflags) == CFNumberGetTypeID()) {
cdFlags = cfNumber<uint32_t>(CFNumberRef(csflags));
secdebug("signer", "using numeric cdFlags=0x%x from Info.plist", cdFlags);
secdebug("signer", "using text cdFlags=0x%x from Info.plist", cdFlags);
} else
MacOSError::throwMe(errSecCSBadDictionaryFormat);
+ }
}
if (state.mSigner == SecIdentityRef(kCFNull)) // ad-hoc signing requested...
cdFlags |= kSecCodeSignatureAdhoc; // ... so note that
// finally, ask the DiskRep for its default
if (!resourceRules)
- resourceRules.take(rep->defaultResourceRules());
+ resourceRules.take(rep->defaultResourceRules(state));
// build the resource directory
- ResourceBuilder resources(rpath, cfget<CFDictionaryRef>(resourceRules, "rules"));
+ ResourceBuilder resources(rpath, cfget<CFDictionaryRef>(resourceRules, "rules"), digestAlgorithm());
rep->adjustResources(resources); // DiskRep-specific adjustments
CFRef<CFDictionaryRef> rdir = resources.build();
resourceDirectory.take(CFPropertyListCreateXMLData(NULL, rdir));
signingTime = time;
}
- pagesize = state.mPageSize ? cfNumber<size_t>(state.mPageSize) : rep->pageSize();
+ pagesize = state.mPageSize ? cfNumber<size_t>(state.mPageSize) : rep->pageSize(state);
+
+ // Timestamping setup
+ CFRef<SecIdentityRef> mTSAuth; // identity for client-side authentication to the Timestamp server
}
// treat them as architectural binaries containing (only) one architecture - that
// interpretation is courtesy of the Universal/MachO support classes.
//
-void SecCodeSigner::Signer::signMachO(Universal *fat)
+void SecCodeSigner::Signer::signMachO(Universal *fat, const Requirement::Context &context)
{
// Mach-O executable at the core - perform multi-architecture signing
auto_ptr<ArchEditor> editor(state.mDetached
? static_cast<ArchEditor *>(new BlobEditor(*fat, *this))
- : new MachOEditor(rep->writer(), *fat, rep->mainExecutablePath()));
+ : new MachOEditor(rep->writer(), *fat, this->digestAlgorithm(), rep->mainExecutablePath()));
assert(editor->count() > 0);
if (!editor->attribute(writerNoGlobal)) // can store architecture-common components
populate(*editor);
for (MachOEditor::Iterator it = editor->begin(); it != editor->end(); ++it) {
MachOEditor::Arch &arch = *it->second;
arch.source.reset(fat->architecture(it->first));
- arch.ireqs(state.mRequirements, rep->defaultRequirements(&arch.architecture));
+ arch.ireqs(state.mRequirements, rep->defaultRequirements(&arch.architecture, state), context);
if (editor->attribute(writerNoGlobal)) // can't store globally, add per-arch
populate(arch);
populate(arch.cdbuilder, arch, arch.ireqs,
// Sign a binary that has no notion of architecture.
// That currently means anything that isn't Mach-O format.
//
-void SecCodeSigner::Signer::signArchitectureAgnostic()
+void SecCodeSigner::Signer::signArchitectureAgnostic(const Requirement::Context &context)
{
// non-Mach-O executable - single-instance signing
RefPointer<DiskRep::Writer> writer = state.mDetached ?
(new DetachedBlobWriter(*this)) : rep->writer();
- CodeDirectory::Builder builder;
+ CodeDirectory::Builder builder(state.mDigestAlgorithm);
InternalRequirements ireqs;
- ireqs(state.mRequirements, rep->defaultRequirements(NULL));
+ ireqs(state.mRequirements, rep->defaultRequirements(NULL, state), context);
populate(*writer);
populate(builder, *writer, ireqs, rep->signingBase(), rep->signingLimit());
builder.flags(cdFlags);
builder.identifier(identifier);
- if (CFDataRef data = rep->component(cdInfoSlot))
- builder.special(cdInfoSlot, data);
+ if (CFRef<CFDataRef> data = rep->component(cdInfoSlot))
+ builder.specialSlot(cdInfoSlot, data);
if (ireqs) {
CFRef<CFDataRef> data = makeCFData(*ireqs);
writer.component(cdRequirementsSlot, data);
- builder.special(cdRequirementsSlot, data);
+ builder.specialSlot(cdRequirementsSlot, data);
}
if (resourceDirectory)
- builder.special(cdResourceDirSlot, resourceDirectory);
+ builder.specialSlot(cdResourceDirSlot, resourceDirectory);
#if NOT_YET
if (state.mApplicationData)
- builder.special(cdApplicationSlot, state.mApplicationData);
+ builder.specialSlot(cdApplicationSlot, state.mApplicationData);
#endif
if (state.mEntitlementData) {
writer.component(cdEntitlementSlot, state.mEntitlementData);
- builder.special(cdEntitlementSlot, state.mEntitlementData);
+ builder.specialSlot(cdEntitlementSlot, state.mEntitlementData);
}
writer.addDiscretionary(builder);
}
+#include <Security/tsaSupport.h>
//
// Generate the CMS signature for a (finished) CodeDirectory.
CFDataRef SecCodeSigner::Signer::signCodeDirectory(const CodeDirectory *cd)
{
assert(state.mSigner);
-
+ CFRef<CFMutableDictionaryRef> defaultTSContext = NULL;
+
// a null signer generates a null signature blob
if (state.mSigner == SecIdentityRef(kCFNull))
return CFDataCreate(NULL, NULL, 0);
}
MacOSError::check(CMSEncoderUpdateContent(cms, cd, cd->length()));
+
+ // Set up to call Timestamp server if requested
+
+ if (state.mWantTimeStamp)
+ {
+ CFRef<CFErrorRef> error = NULL;
+ defaultTSContext = SecCmsTSAGetDefaultContext(&error.aref());
+ if (error)
+ MacOSError::throwMe(errSecDataNotAvailable);
+
+ if (state.mNoTimeStampCerts || state.mTimestampService) {
+ if (state.mTimestampService)
+ CFDictionarySetValue(defaultTSContext, kTSAContextKeyURL, state.mTimestampService);
+ if (state.mNoTimeStampCerts)
+ CFDictionarySetValue(defaultTSContext, kTSAContextKeyNoCerts, kCFBooleanTrue);
+ }
+
+ CmsMessageSetTSAContext(cms, defaultTSContext);
+ }
+
CFDataRef signature;
MacOSError::check(CMSEncoderCopyEncodedContent(cms, &signature));
+
return signature;
}
}
+//
+// Generate a unique string from our underlying DiskRep.
+// We could get 90%+ of the uniquing benefit by just generating
+// a random string here. Instead, we pick the (hex string encoding of)
+// the source rep's unique identifier blob. For universal binaries,
+// this is the canonical local architecture, which is a bit arbitrary.
+// This provides us with a consistent unique string for all architectures
+// of a fat binary, *and* (unlike a random string) is reproducible
+// for identical inputs, even upon resigning.
+//
+std::string SecCodeSigner::Signer::uniqueName() const
+{
+ CFRef<CFDataRef> identification = rep->identification();
+ const UInt8 *ident = CFDataGetBytePtr(identification);
+ const unsigned int length = CFDataGetLength(identification);
+ string result;
+ for (unsigned int n = 0; n < length; n++) {
+ char hex[3];
+ snprintf(hex, sizeof(hex), "%02x", ident[n]);
+ result += hex;
+ }
+ return result;
+}
+
+
} // end namespace CodeSigning
} // end namespace Security