Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Can't sign lib_burst_generated.bundle within macOS app #95

Closed
markshep-wbg opened this issue Nov 6, 2023 · 12 comments
Closed

Can't sign lib_burst_generated.bundle within macOS app #95

markshep-wbg opened this issue Nov 6, 2023 · 12 comments
Labels
apple-codesign apple-codesign crate and rcodesign CLI tool bug Something isn't working

Comments

@markshep-wbg
Copy link

I'm working on a macOS app made with Unity. When making a build Unity generates a macOS app that's been adhoc signed and I want to sign that with a Apple-issued certificate, ultimately a "Developer ID Application" distribution certificate ready for notarization, but for now I'm just using an "Apple Development" certificate.

When signing the app with rcodesign it appears to work, but running codesign --verify --verbose=2 whatever.app on the app shows that the signature on the file Contents/Plugins/lib_burst_generated.bundle within the app is invalid. This file gets generated by Unity using its Burst compiler.

I've attached a minimal reproduction case with a cut-down app containing only an executable, Info.plist and lib_burst_generated.bundle along with a shell script that does the signing, signature diffing and verification. To make this work for you the shell script will need the IDENTITY variable setting to an identity that has a corresponding certificate & private key in your keychain and that also needs to have been exported to a .p12 file alongside the script with the basename of the file being the identity.

I'm using the official 0.23.0 release on macOS.

Here's the reproduction case:
test.tar.gz

And here's the output I get on my machine when running the script:

Signing with codesign
---------------------

TrivialProject.app/Contents/Plugins/lib_burst_generated.bundle: replacing existing signature
TrivialProject.app/Contents/Plugins/lib_burst_generated.bundle: signed Mach-O universal (x86_64 arm64) [lib_burst_generated]
TrivialProject.app: replacing existing signature
TrivialProject.app: signed app bundle with Mach-O universal (x86_64 arm64) [com.DefaultCompany.TrivialProject]

Signing with rcodesign
----------------------

registering signing key
automatically registered Apple CA certificate: Apple Worldwide Developer Relations Certification Authority
automatically registered Apple CA certificate: Apple Root CA
using time-stamp protocol server http://timestamp.apple.com/ts01
automatically setting team ID from signing certificate: TJXK3JV9VB
signing TrivialProject.app in place
signing bundle at TrivialProject.app
signing bundle at TrivialProject.app into TrivialProject.app
signing Mach-O file Contents/PlugIns/lib_burst_generated.bundle
creating cryptographic signature with certificate Apple Development: Mark Sheppard (CJ8VWSTTKT)
creating cryptographic signature with certificate Apple Development: Mark Sheppard (CJ8VWSTTKT)
signing main executable Contents/MacOS/TrivialProject
creating cryptographic signature with certificate Apple Development: Mark Sheppard (CJ8VWSTTKT)
creating cryptographic signature with certificate Apple Development: Mark Sheppard (CJ8VWSTTKT)

Diffing signatures
------------------

-rw-r--r-- 1 mark.sheppard staff 46715 Nov  6 18:35 diff

Checking codesign
-----------------

--prepared:/Users/mark.sheppard/test/codesign/TrivialProject.app/Contents/PlugIns/lib_burst_generated.bundle
--validated:/Users/mark.sheppard/test/codesign/TrivialProject.app/Contents/PlugIns/lib_burst_generated.bundle
codesign/TrivialProject.app: valid on disk
codesign/TrivialProject.app: satisfies its Designated Requirement

Checking rcodesign
------------------

rcodesign/TrivialProject.app: nested code is modified or invalid
file modified: /Users/mark.sheppard/test/rcodesign/TrivialProject.app/Contents/PlugIns/lib_burst_generated.bundle

@indygreg indygreg added bug Something isn't working apple-codesign apple-codesign crate and rcodesign CLI tool labels Nov 7, 2023
@indygreg
Copy link
Owner

indygreg commented Nov 7, 2023

Thank you for the bug report and going the extra mile to code up a shell script to reproduce the failures! This should hopefully be pretty easy to track down.

On first glance, there are several subtle differences in the signatures. But the one that stands out as a likely cause of the problem is this:

     - '    <key>PlugIns/lib_burst_generated.bundle</key>'
     - '    <dict>'
     - '      <key>cdhash</key>'
     - '      <data>'
-    - '      1W5f4lvSjOk4fusuqNA/5Q8aHFs='
+    - '      zVctgYO3aNANxB/j0C73bLuSfL4='
     - '      </data>'
     - '      <key>requirement</key>'
-    - '      <string>cdhash H"7c4057e8f2675c118297176b510749bbe2752d28" or cdhash H"d56e5fe25bd28ce9387eeb2ea8d03fe50f1a1c5b" or cdhash H"ceb50aaf5360712c177aa6fe36d071dbc1677b80" or cdhash H"ec47d4d25dd0911863ba12512f4d8c75c5090f09"</string>'
+    - '      <string>(cdhash H"cd572d8183b768d00dc41fe3d02ef76cbb927cbe") or (cdhash H"c12d14379b8f8d21c5e3f339ca8ee64dcf9628e4")</string>'
     - '    </dict>'

(It also appears rcodesign is adding entitlements where Apple's tooling isn't - that warrants investigation as well.)

@indygreg
Copy link
Owner

indygreg commented Nov 7, 2023

I modified the sign script to perform adhoc signing (changed IDENTITY to - and removed p12 arguments) and interestingly codesign says the adhoc bundle verifies! The rabbit holes grows deeper.

indygreg added a commit that referenced this issue Nov 7, 2023
This is what Apple's tooling does. Before, if we had both SHA-1 and SHA-256
CDs, we only emitted the SHA-256 variant.

There may still be subtle bugs here. So I'm not closing the issue (#95)
just yet.
@indygreg
Copy link
Owner

indygreg commented Nov 7, 2023

There's a fix on the main branch to emit the missing cdhash values. I'm still verifying if additional work is needed.

indygreg added a commit that referenced this issue Nov 7, 2023
This is what Apple's tooling does. Before, if we had both SHA-1 and SHA-256
CDs, we only emitted the SHA-256 variant.

There may still be subtle bugs here. So I'm not closing the issue (#95)
just yet.
@indygreg
Copy link
Owner

indygreg commented Nov 7, 2023

Your automated reproduction case keeps delivering new bugs. I love it.

I'm using a self-signed code signing certificate and noticed the derived designated requirements are different:

-        - 'designated(3): 0: (identifier "com.DefaultCompany.TrivialProject") and (anchor -1 H"e1c7216e46533c923b7cfc94e86c7043790b96e9");'
+        - 'designated(3): 0: (identifier "com.DefaultCompany.TrivialProject") and ((anchor apple generic) and ((certificate leaf[subject.CN] = "Apple Development: RSA Apple Development (test)") and (certificate 1[field.1.2.840.113635.100.6.2.1] /* exists */)));'

That anchor apple generic is wrong (the cert isn't signed by an Apple CA).

Out of curiosity, were you using a self-signed certificate?

Other variances:

  • Team name is in code directory whereas Apple doesn't do this. Maybe that's conditional on Apple signed certs?

And in Contents/PlugIns/lib_burst_generated.bundle:

  • Code directory version is 0x20500 vs Apple's 0x20400
  • CD identifier is ed4f3b081ef20e079e2308d1c409246a-555549444c4c443355553144a137dae86fe1eaf7 vs lib_burst_generated
  • Runtime version of 10.9.0 is getting added by us.
  • Entitlements plist is getting embedded when it is empty on Apple.
  • Our CMS signature has a time-stamp token where's Apple's doesn't. (Maybe only the root entity needs a TST?)

I'll try to work through all of these this week to get things working. Clearly there's a handful of small bugs here.

@markshep-wbg
Copy link
Author

Out of curiosity, were you using a self-signed certificate?

No - it was an "Apple Development" certificate that I generated at https://developer.apple.com/account/resources/certificates/list.

indygreg added a commit that referenced this issue Nov 8, 2023
It shows:

* Different entitlements applied to different settings scopes works
* Embedded entitlements are preserved when signing bundles

This test also mostly reproduces the failure in #95. I'm still not sure
why validation is failing. But I'm pretty confident it isn't entitlements.
@indygreg
Copy link
Owner

indygreg commented Nov 8, 2023

OK. A lot of the drift was due to codesign not preserving metadata by default. Once I corrected for that, we're down to #98 as the lone obvious reason why validation is failing. Hopefully fixing that will fix things.

@indygreg
Copy link
Owner

indygreg commented Nov 8, 2023

After chasing down every other lead, the issue appears to have to do with something I wasn't expecting: incorrect handling of the code signature in the __LINKEDIT segment. I'm still trying to track things down. But it kinda looks like we're softly corrupting the Mach-O binary somehow. Strangely, codesign says the individual Mach-O is signed correctly but validation in a bundle fails.

@indygreg
Copy link
Owner

indygreg commented Nov 8, 2023

Ok, I have some progress.

The original bundle / binaries you gave me have code signatures. If you strip the code signatures with codesign --remove-signature before signing, the rcodesign version validates. At least on the main branch.

I'm still trying to figure out why this is happening. IMO rcodesign's Mach-O is more pure than Apple's because we write 0s to EOF whereas Apple's can preserve the leftover signature data (if the signature is shorter than it was before).

But clearly there is a bug in our code somewhere because Apple is failing to validate the file. But I still haven't found the source of why the binary when in a bundle - and only when it is in a bundle - fails validation with Apple tooling. It is very perplexing to me.

@indygreg
Copy link
Owner

indygreg commented Nov 8, 2023

I was grasping at straws and tested signing a single arch Mach-O binary instead of a fat/universal binary and that works. So the bug has something to do with fat/universal Mach-O files. Good times.

@indygreg
Copy link
Owner

indygreg commented Nov 8, 2023

I think the problem has to do with the Mach file headers / __LINKEDIT segment / segment load commands not agreeing on the total file size. I think this is confusing Apple's (and likely other) Mach-O parsers. I'll look into this more tomorrow and hopefully get a fix in.

@markshep-wbg
Copy link
Author

Thanks for the quick turnaround on this - 0.24.0 has got me past that problem. I'll open another issue for the next problem!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
apple-codesign apple-codesign crate and rcodesign CLI tool bug Something isn't working
Projects
None yet
Development

No branches or pull requests

2 participants