Frameworks included in an umbrella framework are not re-signed when copied

Originator:jhankin
Number:rdar://31203101 Date Originated:3/22/2016
Status:Open Resolved:
Product:Xcode Product Version:8.2.1
Classification:Bug Reproducible:Always
 
Summary:
We are working on building an iOS SDK that will include a few of our internal frameworks as dependencies.  The structure is:

SDK.framework/
    SDK (executable)
    Resources.bundle
    Frameworks/
        InternalDependency1.framework
        InternalDependency2.framework

When a developer pulls SDK.framework into their iOS app, Xcode will re-sign SDK.framework with the certificate used to sign their app, but InternalDependency1.framework and InternalDependency2.framework will not be re-signed.  This results in a crash at runtime with a "dyld: Library not loaded" error because the code signatures do not match.  The dependencies are not meant for individual consumption, so we want to ship the SDK as an umbrella framework to hide the complexity from the developers that will use the SDK.

Since Xcode supports re-signing frameworks when they are copied into an app, it should also code-sign all the nested frameworks within that framework. 

Steps to Reproduce:
1. Build a framework that includes other frameworks as dependencies.  Xcode will code-sign the framework at build time, but not the dependent frameworks, so you will need an additional build step that runs a script like this:

for filename in "${BUILT_PRODUCTS_DIR}/${PRODUCT_NAME}.framework/Frameworks/*.framework"; do
    codesign --force --sign "${CODE_SIGN_IDENTITY}" $filename
done

2. Drag the built framework into the "Embedded Binaries" section of a new iOS app.
3. Build and run the app on device, signing it with a different certificate from the one used to code-sign the original framework. 

Expected Results:
I expected the new app to run normally.

Actual Results:
The app crashes immediately after launch with a message like:

dyld: Library not loaded: @rpath/InternalDependency1.framework/InternalDependency1
  Referenced from: /private/var/containers/Bundle/Application/8CD981C1-F929-4A21-A59C-71F0607B09B6/TestProject.app/Frameworks/SDK.framework/SDK.framework

  Reason: no suitable image found.  Did find:

       /private/var/containers/Bundle/Application/8CD981C1-F929-4A21-A59C-71F0607B09B6/TestProject.app/Frameworks/SDK.framework/Frameworks/InternalDependency1.framework/InternalDependency1: code signature invalid for '/private/var/containers/Bundle/Application/8CD981C1-F929-4A21-A59C-71F0607B09B6/TestProject.app/Frameworks/SDK.framework/Frameworks/InternalDependency1.framework/InternalDependency1'

Version:
Xcode Version 8.2.1 (8C1002), macOS Sierra 10.12.3 (16D32)

Notes:
The only workaround we've found so far is to ship a shell script within the framework that will re-sign the dependencies with the same cert the developer uses to sign their app, then instruct the developers to add a Run Script phase to their build that calls that shell script.  Needless to say, this workflow is less than ideal.

Configuration:
This occurs when building for device (iPad or iPhone).  

Attachments:

Comments


Please note: Reports posted here will not necessarily be seen by Apple. All problems should be submitted at bugreport.apple.com before they are posted here. Please only post information for Radars that you have filed yourself, and please do not include Apple confidential information in your posts. Thank you!