Can I update a resouce in a signed app and then just resign the updated resource?

Hi,


I have an automated build process that produces custom apps for different customers. The only thing that is customized is a resource in the app.


I would like to be able to just code sign the entire app once and then for each customer just update and code sign the resource.


After doing the initial code signing of the app "codesign -vvv --deep --strict myapp.app" shows that everything is OK.


I then replace myapp.app//Contents/Resources/CustomFile with a new one and code sign it:
codesign -f -s "Developer ID Application: MY Company" --options runtime --keychain "Buildsystem" "myapp.app/Contents/Resources/CustomFile"


But then "codesign -vvv --deep --strict myapp.app" shows there is a problem:

myapp.app: a sealed resource is missing or invalid

file modified: myapp.app/Contents/Resources/CustomFile


Can anybody explain why this doesn't work?


My work around is to always update the resource in an unsigned app and then code sign the entire thing.

Replies

You can't sign just one file. You have to re-sign the entire thing. And don't use "--deep", or "--force".

Thanks for your reply but I think I have found out how to get this to work.

(If the app were small I would not bother with this but it contains a lot of resources and code signing can take a bit of time.)


The trick is that you need to reseal the app after updating and signing the resource. From my experiments the app seems to be sealed and the "_CodeSignature/CodeResources" file created when the bundles exactable is signed.


So the following works after updating the file "myapp.app/Contents/Resources/CustomFile":


codesign -f --s "Developer ID Application: MY Company" --options runtime --keychain "Buildsystem" "myapp.app/Contents/Resources/CustomFile"

codesign -f -s "Developer ID Application: MY Company" --options runtime --keychain "Buildsystem" "myapp.app/Contents/MacOS/myapp"


Note the '-f' option to force the resigning.


If there is a better way to reseal the app maybe someone can tell me I couldn't find any documentation saying what triggers the sealing of the app.


If what I am doing is 'bad' then maybe someone can tell me why I shouldn't do this.

If what I am doing is 'bad' then maybe someone can tell me why I shouldn't do this.

I think that’s the wrong way to approach this. Code signing is a complex ***** and playing around in its guts is going to consume a lot of your time. If the only reason you’re doing this is to speed up code signing, there’s a much easier solution: Move your “lot of resources” into a separate signable item (probably a framework) and sign that once. If that item is embedded correctly, re-signing your main app will be fast.

Share and Enjoy

Quinn “The Eskimo!”
Apple Developer Relations, Developer Technical Support, Core OS/Hardware

let myEmail = "eskimo" + "1" + "@apple.com"

I am not sure why it should be OK to skip signing the frameworks because they have already been signed but not to skip signing the other parts of the bundle even though they have also already been signed.


Code signing on OS X is definitely a ***** which tends to bite you if you poke it. I wish someone could tame it.

I am not sure why it should be OK to skip signing the frameworks because they have already been signed but not to skip signing the other parts of the bundle even though they have also already been signed.

Because each code item carries its own signature, but that’s not true for resources. When the sign the framework it sets up the framework’s code signature. When you sign the app, it sets up the app’s code signature, and that includes a reference to the framework. It doesn’t need to re-do the code signature of the framework because of the way code signatures reference nested code.

Consider this:

  1. Create a Mac app.

  2. Create a framework target within that app.

  3. Sign everything.

  4. Look at the Mac app’s

    Contents/_CodeSignature/CodeResources
    file. A resource reference will look like this:
    <key>Resources/MainMenu.nib</key>
    <dict>
        <key>hash2</key>
        <data>
        Sa53xgI65G1TsnRiEUIR6fckj7oVIgd+exipGCEoo4U=
        </data>
    </dict>

    Note how it reference’s the resource’s hash directly. In contrast, a code item’s reference will look like this:

    <key>Frameworks/MyFramework.framework</key>
    <dict>
        <key>cdhash</key>
        <data>
        dxhJZ3+z00kM8JCE4+zwHE78aiY=
        </data>
        <key>requirement</key>
        <string>identifier "com.example.apple-samplecode.MyFramework" and anchor apple generic and certificate leaf[subject.CN] = "Apple Development: Quinn Quinn (7XFU7D52S4)" and certificate 1[field.1.2.840.113635.100.6.2.1] /* exists */</string>
    </dict>

    It reference’s the framework’s cdhash (code directory hash) and designated requirement (DR), but of which are embedded in the framework’s code signature.

Share and Enjoy

Quinn “The Eskimo!”
Apple Developer Relations, Developer Technical Support, Core OS/Hardware

let myEmail = "eskimo" + "1" + "@apple.com"

Thanks for the help for answers

  • You're welcome!

Add a Comment

How about a file in "myapp.app/Contents/Resources/" that needs to be modified during runtime?

I noticed that when that for a notarized app, once a file in "Resources" is modified, the notarization breaks?

Is it possible to save and modify runtime custom files in "Resources" without breaking the notarization or is it the case the "Resources" is not the right place for those kind of files?