Closed CendioOssman closed 2 weeks ago
I think this issue is related to your other issue (#148). It is likely there's a bug somewhere in bundle traversal that is causing things to get misidentified. Please provide more technical details so we can debug this.
I'm going to call this a duplicate of #148 because the issues are intricately linked.
Actually, this issue may be subtly different.
Ok. I think I know what's happening.
First, fuller logs:
signing 1 nested bundles in the following order:
Contents/lib/tlclient/vncviewer.app
entering nested bundle Contents/lib/tlclient/vncviewer.app
...
signing main executable Contents/MacOS/vncviewer
leaving nested bundle Contents/lib/tlclient/vncviewer.app
...
signing Mach-O file Contents/lib/tlclient/unfsd
signing Mach-O file Contents/lib/tlclient/vncviewer.app/Contents/MacOS/vncviewer
signing main executable Contents/MacOS/tlclient
In non-shallow signing mode, we enter the nested bundle and sign Contents/lib/tlclient/vncviewer.app/Contents/MacOS/vncviewer
.
Then later on when signing the main bundle we sign Contents/lib/tlclient/vncviewer.app/Contents/MacOS/vncviewer
again!
I haven't verified this but I'm willing to bet that the second signing- which signs the Mach-O in the context of a regular Mach-O file and not the bundle's main executable - is setting the wrong identifier because of this fact.
We have special logic that looks for nested bundles. But only if the CodeResources
rules entry has the nested
flag set. In this case:
Contents/lib/tlclient/vncviewer.app matches rules2 CodeResourcesRule { pattern: "^.*", exclude: false, nested: false, omit: false, optional: false, weight: None, re: Regex("^.*") }
So essentially the CodeResources
rules say the directory isn't special - can't be a bundle - and we proceed to walk it.
I initially wanted to say the structure of this bundle is malformed and the nested bundle must exist in a different directory.
But if Apple verifies/notarizes the bundle, then the bundle is seemingly correct. That's the test that matters.
I haven't verified this, but I'm willing to bet that because the nested
flag isn't set that Apple's codesign
will sign individual files in this bundle as files in the CodeResources
file. Contrast with a single entry for the bundle's main executable's signature in the CodeResources
file.
What we may need to do here is register nested bundles in an exclusion list as they are signed. Then when we go to sign the outer bundle, we ignore re-signing files we've seen before.
I need to think about this a bit more before I author a code change. But I'm optimistic I understand what's happening.
Confirmed that Apple's codesign
descends into the child bundle - outside a directory flagged as nested
- and proceeds to sign its files as files, not a bundle.
<key>lib/tlclient/vncviewer.app/Contents/Info.plist</key>
<dict>
<key>hash</key>
<data>
VO6GT2ZWUznPmmykkuNWho2q+NU=
</data>
<key>hash2</key>
<data>
yRiSShAnwwfzYe+5VeFF0cSEGXq/BUrl0pt1asqkNOA=
</data>
</dict>
<key>lib/tlclient/vncviewer.app/Contents/MacOS/vncviewer</key>
<dict>
<key>hash</key>
<data>
JeobnwK4ckgax0mgQQemKKO49jE=
</data>
<key>hash2</key>
<data>
YsVpcsFB4DdiN0ud7ySVxJXvksHgKDd4muxXkQkOOxQ=
</data>
</dict>
So we need some mechanism to avoid signing entities that have already been signed as part of signing a child bundle. But we still need to capture those files in the parent's bundle.
We may have a simular(or same) issue with nested bundles. We have a in-Unity web browser plugin, which file structure looks like: VuplexWebViewMac.bundle
|-- Contents
|-- Frameworks
|-- Vuplex WebView.app
|-- Contents
|-- Frameworks
|-- Vuplex WebView Helper (GPU).app
|-- Vuplex WebView Helper (Plugin).app
|-- Vuplex WebView Helper (Renderer).app
|-- Vuplex WebView Helper.app
So if I just try to sign it once for all from the top level, during the code sign, it will show message like:
entering nested bundle Contents/PlugIns/VuplexWebViewMac.bundle/Contents/Frameworks/Vuplex WebView.app
signing bundle at ./[filePath]/Contents/PlugIns/VuplexWebViewMac.bundle/Contents/Frameworks/Vuplex WebView.app into ./[filePath]/Contents/PlugIns/VuplexWebViewMac.bundle/Contents/Frameworks/Vuplex WebView.app
could not find main executable of presumed nested bundle: Contents/Frameworks/Vuplex WebView Helper (GPU).app
could not find main executable of presumed nested bundle: Contents/Frameworks/Vuplex WebView Helper (Plugin).app
could not find main executable of presumed nested bundle: Contents/Frameworks/Vuplex WebView Helper (Renderer).app
could not find main executable of presumed nested bundle: Contents/Frameworks/Vuplex WebView Helper.app
signing Mach-O file Contents/MacOS/Vuplex WebView
creating cryptographic signature with certificate [deleted]
bundle has no main executable to sign specially
leaving nested bundle Contents/PlugIns/VuplexWebViewMac.bundle/Contents/Frameworks/Vuplex WebView.app
And when notary, it will give "The signature of the binary is invalid." error for all the Mach-O file in the nested app, like below:
notary log> {
notary log> "architecture": "x86_64",
notary log> "code": null,
notary log> "docUrl": "https://developer.apple.com/documentation/security/notarizing_macos_software_before_distribution/resolving_common_notarization_issues#3087735",
notary log> "message": "The signature of the binary is invalid.",
notary log> "path": "[filePath]/Contents/PlugIns/VuplexWebViewMac.bundle/Contents/Frameworks/Vuplex WebView.app/Contents/Frameworks/Vuplex WebView Helper (Plugin).app/Contents/MacOS/Vuplex WebView Helper (Plugin)",
notary log> "severity": "error"
notary log> },
Forget to mention, we're trying to sign our application on Linux. I tried to manually notary the files on Mac, using the traditional way(sign the last level of nested apps first, then sign their parent, then the parent of parent), and this method works. I checked this issue and related ones, it looks like closed to my problem but I'm not versy sure about it: Is the fix e04ddb2 suitable for my case too?
@Yuuon aspects of your issue look to overlap with this issue.
If you are able to run a build of the main branch and report feedback, it would be helpful. You can download rcodesign executables from GitHub Actions from the rcodesign workflow.
If you still experience issues or can't test, please open a new issue and we can triage there.
I can confirm that the current main
successfully signs our complex bundle in a way that macOS accepts! Thanks for all your work!
We have an application bundle that has another application bundle nested within it. rcodesign properly detects this, but it messes up the signature in a way that makes Apple reject the notarization:
The issue is the identifier used on the main binary for that nested bundle. It gets the generic one (
"vncviewer"
), rather than one of the bundle identifiers¹.The workaround is to sign the nested bundle separately (although #148 caused some friction there).
¹ Apple seems to accept either identifier from
ThinLinc Client Notarized.app
orvncviewer.app