#include <Security/SecCertificate.h>
#include <Security/SecCertificatePriv.h>
#include <vector>
+#include <errno.h>
namespace Security {
else
return false;
}
+
+ uint32_t parseRuntimeVersion(std::string& runtime)
+ {
+ uint32_t version = 0;
+ char* cursor = const_cast<char*>(runtime.c_str());
+ char* end = cursor + runtime.length();
+ char* nxt = NULL;
+ long component = 0;
+ int component_shift = 16;
+
+ // x should convert to 0x00XX0000
+ // x.y should convert to 0x00XXYY00
+ // x.y.z should covert to 0x00XXYYZZ
+ // 0, 0.0, and 0.0.0 are rejected
+ // anything else should be rejected
+ while (cursor < end) {
+ nxt = NULL;
+ errno = 0;
+ component = strtol(cursor, &nxt, 10);
+ if (cursor == nxt ||
+ (errno != 0) ||
+ (component < 0 || component > UINT8_MAX)) {
+ secdebug("signer", "Runtime version: %s is invalid", runtime.c_str());
+ MacOSError::throwMe(errSecCSInvalidRuntimeVersion);
+ }
+ version |= (component & 0xff) << component_shift;
+ component_shift -= 8;
+
+ if (*nxt == '\0') {
+ break;
+ }
+
+ if (*nxt != '.' || component_shift < 0 || (nxt + 1) == end) {
+ // Catch a trailing "."
+ secdebug("signer", "Runtime version: %s is invalid", runtime.c_str());
+ MacOSError::throwMe(errSecCSInvalidRuntimeVersion);
+ }
+ cursor = nxt + 1;
+ }
+
+ if (version == 0) {
+ secdebug("signer","Runtime version: %s is a version of zero", runtime.c_str());
+ MacOSError::throwMe(errSecCSInvalidRuntimeVersion);
+ }
+
+ return version;
+ }
};
// Construct a SecCodeSigner
//
SecCodeSigner::SecCodeSigner(SecCSFlags flags)
- : mOpFlags(flags), mLimitedAsync(NULL)
+ : mOpFlags(flags), mLimitedAsync(NULL), mRuntimeVersionOverride(0)
{
}
//
// Clean up a SecCodeSigner
//
-SecCodeSigner::~SecCodeSigner() throw()
+SecCodeSigner::~SecCodeSigner() _NOEXCEPT
try {
delete mLimitedAsync;
} catch (...) {
//
bool SecCodeSigner::valid() const
{
- if (mOpFlags & kSecCSRemoveSignature)
+ if (mOpFlags & (kSecCSRemoveSignature | kSecCSEditSignature)) {
return true;
+ }
return mSigner;
}
//
void SecCodeSigner::sign(SecStaticCode *code, SecCSFlags flags)
{
- code->setValidationFlags(flags);
- if (code->isSigned() && (flags & kSecCSSignPreserveSignature))
+ //Never preserve a linker signature.
+ if (code->isSigned() &&
+ (flags & kSecCSSignPreserveSignature) &&
+ !code->flag(kSecCodeSignatureLinkerSigned)) {
return;
+ }
+ code->setValidationFlags(flags);
Signer operation(*this, code);
if ((flags | mOpFlags) & kSecCSRemoveSignature) {
secinfo("signer", "%p will remove signature from %p", this, code);
operation.remove(flags);
+ } else if ((flags | mOpFlags) & kSecCSEditSignature) {
+ secinfo("signer", "%p will edit signature of %p", this, code);
+ operation.edit(flags);
} else {
if (!valid())
MacOSError::throwMe(errSecCSInvalidObjectRef);
SecCodeSigner::Parser::Parser(SecCodeSigner &state, CFDictionaryRef parameters)
: CFDictionary(parameters, errSecCSBadDictionaryFormat)
{
+ CFNumberRef editCpuType = get<CFNumberRef>(kSecCodeSignerEditCpuType);
+ CFNumberRef editCpuSubtype = get<CFNumberRef>(kSecCodeSignerEditCpuSubtype);
+ if (editCpuType != NULL && editCpuSubtype != NULL) {
+ state.mEditArch = Architecture(cfNumber<uint32_t>(editCpuType),
+ cfNumber<uint32_t>(editCpuSubtype));
+ }
+
+ state.mEditCMS = get<CFDataRef>(kSecCodeSignerEditCMS);
+
+ state.mDryRun = getBool(kSecCodeSignerDryRun);
+
+ state.mSDKRoot = get<CFURLRef>(kSecCodeSignerSDKRoot);
+
+ state.mPreserveAFSC = getBool(kSecCodeSignerPreserveAFSC);
+
+ if (state.mOpFlags & kSecCSEditSignature) {
+ return;
+ /* Everything below this point is irrelevant for
+ * Signature Editing, which does not create any
+ * parts of the signature, only replaces them.
+ */
+ }
+
// the signer may be an identity or null
state.mSigner = SecIdentityRef(get<CFTypeRef>(kSecCodeSignerIdentity));
if (state.mSigner)
if (CFNumberRef cmsSize = get<CFNumberRef>(CFSTR("cmssize")))
state.mCMSSize = cfNumber<size_t>(cmsSize);
else
- state.mCMSSize = 9000; // likely big enough
+ state.mCMSSize = 18000; // big enough for now, not forever.
// metadata preservation options
if (CFNumberRef preserve = get<CFNumberRef>(kSecCodeSignerPreserveMetadata)) {
MacOSError::throwMe(errSecCSInvalidObjectRef);
}
- state.mDryRun = getBool(kSecCodeSignerDryRun);
-
state.mResourceRules = get<CFDictionaryRef>(kSecCodeSignerResourceRules);
state.mApplicationData = get<CFDataRef>(kSecCodeSignerApplicationData);
state.mEntitlementData = get<CFDataRef>(kSecCodeSignerEntitlements);
- state.mSDKRoot = get<CFURLRef>(kSecCodeSignerSDKRoot);
-
if (CFBooleanRef timestampRequest = get<CFBooleanRef>(kSecCodeSignerRequireTimestamp)) {
state.mWantTimeStamp = timestampRequest == kCFBooleanTrue;
} else { // pick default
state.mTimestampAuthentication = get<SecIdentityRef>(kSecCodeSignerTimestampAuthentication);
state.mTimestampService = get<CFURLRef>(kSecCodeSignerTimestampServer);
state.mNoTimeStampCerts = getBool(kSecCodeSignerTimestampOmitCertificates);
+
+ if (CFStringRef runtimeVersionOverride = get<CFStringRef>(kSecCodeSignerRuntimeVersion)) {
+ std::string runtime = cfString(runtimeVersionOverride);
+ if (runtime.empty()) {
+ MacOSError::throwMe(errSecCSInvalidRuntimeVersion);
+ }
+ state.mRuntimeVersionOverride = parseRuntimeVersion(runtime);
+ }
+
+ // Don't add the adhoc flag, even if no signer identity was specified.
+ // Useful for editing in the CMS at a later point.
+ state.mOmitAdhocFlag = getBool(kSecCodeSignerOmitAdhocFlag);
}