#include "codesign.h"
#include "cs_utils.h"
#include <Security/Security.h>
#include <Security/SecCodeSigner.h>
#include <Security/SecCodePriv.h>
#include <Security/SecRequirementPriv.h>
#include <Security/CSCommonPriv.h>
#include <security_utilities/blob.h>
#include <security_utilities/cfmunge.h>
#include <cstdio>
#include <cmath>
using namespace UnixPlusPlus;
static CFMutableDictionaryRef parameters; static SecCodeSignerRef signerRef;
void prepareToSign()
{
parameters = makeCFMutableDictionary();
SecCSFlags flags = kSecCSDefaultFlags;
if (signer)
CFDictionaryAddValue(parameters,
kSecCodeSignerIdentity, signer);
else
flags |= kSecCSRemoveSignature;
if (uniqueIdentifier)
CFDictionaryAddValue(parameters,
kSecCodeSignerIdentifier, CFTempString(uniqueIdentifier));
if (identifierPrefix)
CFDictionaryAddValue(parameters,
kSecCodeSignerIdentifierPrefix, CFTempString(identifierPrefix));
if (internalReq)
CFDictionaryAddValue(parameters,
kSecCodeSignerRequirements, readRequirements(internalReq));
if (signatureSize)
CFDictionaryAddValue(parameters, CFSTR("cmssize"), CFTempNumber(signatureSize));
if (pagesize != pagesizeUnspecified)
CFDictionaryAddValue(parameters, kSecCodeSignerPageSize, CFTempNumber(pagesize));
if (cdFlags)
CFDictionaryAddValue(parameters, kSecCodeSignerFlags, CFTempNumber(cdFlags));
if (digestAlgorithm)
CFDictionaryAddValue(parameters, kSecCodeSignerDigestAlgorithm, CFTempNumber(digestAlgorithm));
if (signingTime)
CFDictionaryAddValue(parameters, kSecCodeSignerSigningTime, signingTime);
if (detached)
CFDictionaryAddValue(parameters, kSecCodeSignerDetached, CFTempURL(detached));
else if (detachedDb)
CFDictionaryAddValue(parameters, kSecCodeSignerDetached, kCFNull);
if (timestampRequest) {
CFDictionaryAddValue(parameters, kSecCodeSignerRequireTimestamp, timestampRequest);
if (signingTime && signingTime != CFDateRef(kCFNull))
fail("explicit signing time not allowed with timestamp service");
}
if (tsaURL)
CFDictionaryAddValue(parameters, kSecCodeSignerTimestampServer, CFTempURL(tsaURL));
if (noTSAcerts)
CFDictionaryAddValue(parameters, kSecCodeSignerTimestampOmitCertificates, kCFBooleanTrue);
if (resourceRules) {
if (CFRef<CFDataRef> data = cfLoadFile(resourceRules)) {
CFDictionaryAddValue(parameters, kSecCodeSignerResourceRules,
CFRef<CFDictionaryRef>(makeCFDictionaryFrom(data)));
} else
fail("%s: cannot read resources", resourceRules);
}
if (!sdkRoot)
if (const char *envroot = getenv("SDKDIR"))
sdkRoot = envroot;
if (sdkRoot) {
struct stat st;
if (::stat(sdkRoot, &st))
fail("%s: %s", sdkRoot, strerror(errno));
CFDictionaryAddValue(parameters, kSecCodeSignerSDKRoot, CFTempURL(sdkRoot, true));
}
if (entitlements) {
if (CFRef<CFDataRef> data = cfLoadFile(entitlements)) { if (CFRef<CFDictionaryRef> dict = makeCFDictionaryFrom(data)) {
BlobWrapper *wrap = BlobWrapper::alloc(CFDataGetBytePtr(data), CFDataGetLength(data), kSecCodeMagicEntitlement);
CFDictionaryAddValue(parameters, kSecCodeSignerEntitlements, CFTempData(*(BlobCore*)wrap));
::free(wrap);
} else {
const BlobCore *blob = reinterpret_cast<const BlobCore *>(CFDataGetBytePtr(data));
if (blob->magic() != kSecCodeMagicEntitlement)
note(0, "%s: unrecognized blob type (accepting blindly)", entitlements);
if (blob->length() != CFDataGetLength(data))
fail("%s: invalid length in entitlement blob", entitlements);
CFDictionaryAddValue(parameters, kSecCodeSignerEntitlements, CFTempData(*blob));
}
} else
fail("%s: cannot read entitlement data", entitlements);
}
if (dryrun)
CFDictionaryAddValue(parameters, kSecCodeSignerDryRun, kCFBooleanTrue);
MacOSError::check(SecCodeSignerCreate(parameters, flags, &signerRef));
}
void sign(const char *target)
{
secdebug("codesign", "BEGIN SIGNING %s", target);
CFRef<SecStaticCodeRef> code = staticCodePath(target, architecture, bundleVersion);
CFRef<CFDictionaryRef> dict;
switch (OSStatus rc = SecCodeCopySigningInformation(code,
preserveMetadata ? SecCSFlags(kSecCSRequirementInformation|kSecCSInternalInformation) : kSecCSDefaultFlags,
&dict.aref())) {
case noErr:
if (CFDictionaryGetValue(dict, kSecCodeInfoIdentifier)) { if (detached || detachedDb)
note(0, "%s: not disturbing embedded signature", target);
else if (force)
note(0, "%s: replacing existing signature", target);
else if (signer)
fail("%s: is already signed", target);
}
break;
default:
if (detached)
note(0, "%s: ignoring invalid embedded signature", target);
else if (force)
note(0, "%s: replacing invalid existing signature", target);
else if (signer)
fail("%s: is already signed", target);
break;
}
CFCopyRef<SecCodeSignerRef> currentSigner = signerRef; if (preserveMetadata && dict) {
CFRef<CFMutableDictionaryRef> param = CFDictionaryCreateMutableCopy(NULL, 0, parameters);
if ((preserveMetadata & kPreserveRequirements) && !CFDictionaryGetValue(param, kSecCodeSignerRequirements))
if (CFTypeRef ireqs = CFDictionaryGetValue(dict, kSecCodeInfoRequirementData))
CFDictionaryAddValue(param, kSecCodeSignerRequirements, ireqs);
if ((preserveMetadata & kPreserveEntitlements) && !CFDictionaryGetValue(param, kSecCodeSignerEntitlements))
if (CFTypeRef entitlements = CFDictionaryGetValue(dict, kSecCodeInfoEntitlements))
CFDictionaryAddValue(param, kSecCodeSignerEntitlements, entitlements);
if ((preserveMetadata & kPreserveIdentifier) && !uniqueIdentifier) if (CFTypeRef identifier = CFDictionaryGetValue(dict, kSecCodeInfoIdentifier))
CFDictionaryAddValue(param, kSecCodeSignerIdentifier, identifier);
if ((preserveMetadata & kPreserveResourceRules) && !CFDictionaryGetValue(param, kSecCodeSignerResourceRules))
if (CFTypeRef resourceDirectory = CFDictionaryGetValue(dict, kSecCodeInfoResourceDirectory))
CFDictionaryAddValue(param, kSecCodeSignerResourceRules, resourceDirectory);
MacOSError::check(SecCodeSignerCreate(param, kSecCSDefaultFlags, ¤tSigner.aref()));
}
ErrorCheck check;
check(SecCodeSignerAddSignatureWithErrors(currentSigner, code, kSecCSDefaultFlags, check));
SecCSFlags flags = kSecCSSigningInformation;
if (modifiedFiles)
flags |= kSecCSContentInformation;
MacOSError::check(SecCodeCopySigningInformation(code, flags, &dict.aref()));
note(1, "%s: signed %s [%s]", target,
cfString(CFStringRef(CFDictionaryGetValue(dict, kSecCodeInfoFormat))).c_str(),
cfString(CFStringRef(CFDictionaryGetValue(dict, kSecCodeInfoIdentifier))).c_str()
);
CFRef<CFLocaleRef> userLocale = CFLocaleCopyCurrent();
CFRef<CFDateFormatterRef> format = CFDateFormatterCreate(NULL, userLocale,
kCFDateFormatterMediumStyle, kCFDateFormatterMediumStyle);
CFDateRef softTime = CFDateRef(CFDictionaryGetValue(dict, kSecCodeInfoTime));
CFDateRef hardTime = CFDateRef(CFDictionaryGetValue(dict, kSecCodeInfoTimestamp));
if (hardTime) {
if (softTime) {
CFAbsoluteTime slop = abs(CFDateGetAbsoluteTime(softTime) - CFDateGetAbsoluteTime(hardTime));
if (slop > timestampSlop)
fail("%s: timestamps differ by %g seconds - check your system clock", target, slop);
} else {
CFAbsoluteTime slop = abs(CFAbsoluteTimeGetCurrent() - CFDateGetAbsoluteTime(hardTime));
if (slop > timestampSlop)
note(0, "%s: WARNING: local time diverges from timestamp by %g seconds - check your system clock", target, slop);
}
}
if (modifiedFiles)
writeFileList(CFArrayRef(CFDictionaryGetValue(dict, kSecCodeInfoChangedFiles)), modifiedFiles, "a");
}