]> git.saurik.com Git - apple/security.git/blobdiff - OSX/libsecurity_codesigning/lib/CodeSigner.cpp
Security-59754.80.3.tar.gz
[apple/security.git] / OSX / libsecurity_codesigning / lib / CodeSigner.cpp
index ee8045f98601d8c74fd5c74112ff80c2b76f20af..8cbc67f88d8a16cbcf728a12f566d8fa5bf0e23e 100644 (file)
@@ -34,6 +34,7 @@
 #include <Security/SecCertificate.h>
 #include <Security/SecCertificatePriv.h>
 #include <vector>
+#include <errno.h>
 
 namespace Security {
 
@@ -58,6 +59,53 @@ public:
                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;
+       }
 };
 
 
@@ -65,7 +113,7 @@ public:
 // Construct a SecCodeSigner
 //
 SecCodeSigner::SecCodeSigner(SecCSFlags flags)
-       : mOpFlags(flags), mLimitedAsync(NULL)
+       : mOpFlags(flags), mLimitedAsync(NULL), mRuntimeVersionOverride(0)
 {
 }
 
@@ -73,7 +121,7 @@ SecCodeSigner::SecCodeSigner(SecCSFlags flags)
 //
 // Clean up a SecCodeSigner
 //
-SecCodeSigner::~SecCodeSigner() throw()
+SecCodeSigner::~SecCodeSigner() _NOEXCEPT
 try {
        delete mLimitedAsync;
 } catch (...) {
@@ -122,8 +170,9 @@ std::string SecCodeSigner::getTeamIDFromSigner(CFArrayRef certs)
 //
 bool SecCodeSigner::valid() const
 {
-       if (mOpFlags & kSecCSRemoveSignature)
+       if (mOpFlags & (kSecCSRemoveSignature | kSecCSEditSignature)) {
                return true;
+       }
        return mSigner;
 }
 
@@ -133,13 +182,20 @@ bool SecCodeSigner::valid() const
 //
 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);
@@ -181,6 +237,29 @@ void SecCodeSigner::returnDetachedSignature(BlobCore *blob, Signer &signer)
 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)
@@ -204,7 +283,7 @@ SecCodeSigner::Parser::Parser(SecCodeSigner &state, CFDictionaryRef parameters)
        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)) {
@@ -257,15 +336,11 @@ SecCodeSigner::Parser::Parser(SecCodeSigner &state, CFDictionaryRef parameters)
                        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
@@ -280,6 +355,18 @@ SecCodeSigner::Parser::Parser(SecCodeSigner &state, CFDictionaryRef parameters)
        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);
 }