Skip to content

Enable codesigning by default in the simulator #18469

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

Open
rolfbjarne opened this issue Jun 20, 2023 · 14 comments · May be fixed by #20824
Open

Enable codesigning by default in the simulator #18469

rolfbjarne opened this issue Jun 20, 2023 · 14 comments · May be fixed by #20824
Assignees
Labels
bug If an issue is a bug or a pull request a bug fix
Milestone

Comments

@rolfbjarne
Copy link
Member

rolfbjarne commented Jun 20, 2023

It seems the simulator won't load launch screens unless the app is signed.

Ref: https://dev.azure.com/devdiv/DevDiv/_workitems/edit/1834468

Since most apps have launch screens, it might make sense to enable code signing in the simulator by default.

Note: we should look into what Xcode does if you don't have a Developer Account.

However, some additional testing might be required, because simply setting EnableCodeSigning=true doesn't work as expected:

$ dotnet build /p:EnableCodeSigning=true
[...] error : The "Codesign" task was not given a value for the required parameter "SigningKey", nor was there a "CodesignSigningKey" metadata on the resource [...]

OK, let's try giving the build a code signing key:

$ dotnet build /p:EnableCodeSigning=true /p:CodesignKey='Apple Development: Rolf Kvinge (CZ9YXM2X9A)'
[...] error : The "Codesign" task was not given a value for the required parameter "SigningKey", nor was there a "CodesignSigningKey" metadata on the resource [...]

No change!

what gets us passed that error is actually setting CodesignRequireProvisioningProfile=true, although it runs into another one:

$ dotnet build /p:EnableCodeSigning=true /p:CodesignRequireProvisioningProfile=true
[...]
_CodesignVerify:
  /usr/bin/codesign --verify -vvvv "-R=anchor apple generic and certificate 1[field.1.2.840.113635.100.6.2.1] exists and (certificate leaf[field.1.2.840.113635.100.6.1.2] exists or certificate leaf[field.1.2.840.113635.100.6.1.4] exists)" bin/iPhoneSimulator/Debug/TestLaunchScreen.iOS.app
  bin/iPhoneSimulator/Debug/TestLaunchScreen.iOS.app: valid on disk
  bin/iPhoneSimulator/Debug/TestLaunchScreen.iOS.app: satisfies its Designated Requirement
  test-requirement: code failed to satisfy specified code requirement(s)
error MSB6006: "codesign" exited with code 3.

So what actually makes the app build successfully is passing DisableCodesignVerification=true as well:

$ dotnet build /p:EnableCodeSigning=true /p:CodesignRequireProvisioningProfile=true /p:DisableCodesignVerification=true
[...]

From looking at the source code, this is what happens (don't take this as truth, it needs verification when implementing any fixes) for the simulator in the DetectSigningIdentity task:

  • If a provisioning profile is needed, then the task will report '-' as the signing identity.
    • Bug A: Even if a specific signing identity was specified. I'm not sure if's ever a valid thing to pass a specific signing identity on the simulator though, testing would be needed in XCode
  • If a provisioning profile is not needed, then the task will not return anything as the signing identity.
    • Bug B: Even if a specific signing identity was specified. This is rather odd behavior no matter how you look at it - if a signing identity is always wrong for the simulator, then at least a warning should be reported, otherwise the signing identity should be used.

Setting CodesignRequireProvisioningProfile=true got us passed these two issues, but there's a third:

  • Bug C: the signing process does not produce a verifiable app bundle when using '-' as the signing identity, so we should probably skip the CodesignVerify task in that case (or adjust what's verified).

TLDR;

Add the following to the csproj to work around this:

<PropertyGroup>
    <EnableCodeSigning>true</EnableCodeSigning>
    <CodesignRequireProvisioningProfile>true</CodesignRequireProvisioningProfile>
    <DisableCodesignVerification>true</DisableCodesignVerification>
</PropertyGroup>

This should work on device as well:

  • EnableCodeSigning defaults to true for device, so nothing changes.
  • CodesignRequireProvisioningProfile also defaults to true for device
  • DisableCodesignVerification: assuming the code signing configuration in the project is correct, it shouldn't matter that the verification is skipped (and if it's broken, the app will fail to install on device anyways).
@rolfbjarne rolfbjarne added the bug If an issue is a bug or a pull request a bug fix label Jun 20, 2023
@rolfbjarne rolfbjarne added this to the .NET 9 milestone Jun 20, 2023
@ithiredguns
Copy link

Didn't work for Xamarin Forms adding the above in property Group .. Also, I signed the App with a Distribution Certificate and with an AdHoc Profile and distributed it through AppCenter ... It still has the black splash screen
downloadFromAppCenter

blackScreen.mp4

@rolfbjarne
Copy link
Member Author

@ithiredguns if the problem occurs on device, then it's a different problem (because device builds are always signed, there's no way to install unsigned builds on device), so please open a new issue and attach a test project we can use to reproduce the problem.

@ithiredguns
Copy link

ithiredguns commented Aug 31, 2023

@rolfbjarne I am still having issues on the simulator ( as well as device) I am using pdf files ( for background and logo ) for my launch screen .... I have uploaded a test project for you to verify... Please help :) I have a deployment soon ... If pdf is the issue, can you give me a different workaround ?

*** update****
Changed to png , but still didn't fix

xamarinforms-game-store.zip

@rolfbjarne
Copy link
Member Author

If you look at the console log when you install the app, this shows up:

splashboardd[9594] : Error generating launch image for com.companyname.XFGamingStore: <XBLaunchImageError: 0xbc8924d50; domain: XBLaunchStoryboardErrorDomain; code: 6; reason: "[com.companyname.XFGamingStore] Estimated size (32833536) is over limit (25000000)">

@ithiredguns
Copy link

Wow ! Thanks for the feedback @rolfbjarne . What worked was changing the pdf images to png, shrinking the images and also, moving the images away from Assets.xcassets to Resources folder and updating the LaunchScreen.storyboard to reflect the new png files (instead of pdf) , delete the app & restarting the simulator, cleaning the iOS folder by deleting the bin & obj ... Looks like Apple restricts the size of LaunchScreen images to be less than 25 MB ...

@FreakyAli
Copy link

When I do this in Maui it forces me to use a developer certificate even when I just want to run on a simulator... Which I don't have right now...

@rolfbjarne
Copy link
Member Author

When I do this in Maui it forces me to use a developer certificate even when I just want to run on a simulator... Which I don't have right now...

AFAIK there's no way around this right now if you want the launch screen to show up. When we fix this issue, we'll investigate and see if there's a way to implement code signing without requiring a developer account.

@FreakyAli
Copy link

When I do this in Maui it forces me to use a developer certificate even when I just want to run on a simulator... Which I don't have right now...

AFAIK there's no way around this right now if you want the launch screen to show up. When we fix this issue, we'll investigate and see if there's a way to implement code signing without requiring a developer account.

Damn that sucks, anyways can you please update here once there is a solution for this or even a workaround i guess

@rolfbjarne
Copy link
Member Author

  • Bug C: the signing process does not produce a verifiable app bundle when using '-' as the signing identity, so we should probably skip the CodesignVerify task in that case (or adjust what's verified).

If I try to validate the signature of an app built for the simulator by Xcode it doesn't pass our code signing verification either, so it seems ignoring the verification step in this case is the right thing to do.

@rolfbjarne
Copy link
Member Author

rolfbjarne commented Nov 20, 2023

I've experimented a bit with Xcode, and found the following:

  • I have not been able to use a specific signing certificate, the generic - certificate is always used.
  • The app is not signed with any custom entitlements, the one and only entitlement is com.apple.security.get-task-allow=true no matter how many capabilities I add to the Xcode project. This would also mean no provisioning profile is used either.
  • However, the entitlements are:
    • Embedded in the executable in a custom section named __TEXT, __entitlements:

      -Xlinker -sectcreate -Xlinker __TEXT -Xlinker __entitlements -Xlinker /path/to/iostest.app-Simulated.xcent
      
    • Embedded again in DER form, in the __TEXT, __ents_der section:

      -Xlinker -sectcreate -Xlinker __TEXT -Xlinker __ents_der -Xlinker /path/to/iostest.app-Simulated.xcent.der
      
    • The entitlements are converted to der using:

      /usr/bin/derq query -f xml -i /path/to/iostest.app-Simulated.xcent -o /path/to/iostest.app-Simulated.xcent.der --raw
      

rolfbjarne added a commit that referenced this issue Nov 21, 2023
We'll soon start signing simulator builds by default, and simulator apps
aren't verifiable (with the default signing configuration), which means we'd
need some new logic to determine when to verify the code signature and when
not to. Ref #18469.

Xcode doesn't do any signature verification during/after the build as far as I
can see.

And lastly, the verification doesn't really contribute anything important. For
device builds, the app installation will fail anyway if the signature is
incorrect (and if the signature is correct, and the verification is wrong, we
failed the build for no good reason). For App Store builds, the app store will
also complain if the signature isn't correct.

So just remove the whole signature verification.

Another bonus is that this will speed up the build. There's nothing faster
than doing nothing at all!

Partial fix for #18469.
Fixes #10641.
dustin-wojciechowski pushed a commit to dustin-wojciechowski/xamarin-macios that referenced this issue Apr 10, 2024
We'll soon start signing simulator builds by default, and simulator apps
aren't verifiable (with the default signing configuration), which means we'd
need some new logic to determine when to verify the code signature and when
not to. Ref dotnet#18469.

Xcode doesn't do any signature verification during/after the build as far as I
can see.

And lastly, the verification doesn't really contribute anything important. For
device builds, the app installation will fail anyway if the signature is
incorrect (and if the signature is correct, and the verification is wrong, we
failed the build for no good reason). For App Store builds, the app store will
also complain if the signature isn't correct.

So just remove the whole signature verification.

Another bonus is that this will speed up the build. There's nothing faster
than doing nothing at all!

Partial fix for dotnet#18469.
Fixes dotnet#10641.
@rolfbjarne rolfbjarne self-assigned this Jun 7, 2024
rolfbjarne added a commit to rolfbjarne/xamarin-macios that referenced this issue Jun 7, 2024
@zijianhuang
Copy link

zijianhuang commented Jul 28, 2024

I have tested on real iPad of browserstack, 11, 12 and 13 are OK with:

	<ItemGroup>
		<MauiSplashScreen Include="Resources\storyboard1536x2048.svg" />
	</ItemGroup>

, but 14 and above give me black screen .

on real iPhone, the same.

Therefore, it is a problem in 14, 15 and 16, while the latest xcode supports only minimum 15.

@ToolmakerSteve
Copy link

ToolmakerSteve commented Apr 10, 2025

FYI: Despite years of developing in .Net for iOS (at first via Xamarin Native / iOS), I had trouble recently getting Splash Screen to work. Posted a StackOverflow Q & A with the steps that I went through:

Using .Net 8 for iOS [NOT MAUI], add a LaunchScreen with logo image and background color.

There is a reference in that, back to this issue, which solved one of the problems.

@FreakyAli
Copy link

@ToolmakerSteve Hey, you got this working somehow?

@ToolmakerSteve
Copy link

ToolmakerSteve commented Apr 15, 2025

@ToolmakerSteve Hey, you got this working somehow?

Yes. Added answer: https://stackoverflow.com/a/79565661/199364

BOTTOM LINE: Rofl's lines to "fake" code-sign work, to show on simulator.

To get the storyboard file correct, I used Xcode to create a tiny native app (Swift app, specifying "storyboard" for LaunchScreen). Used Xcode's UI to modify LaunchScreen.storyboard. (There's an auto-constraint button somewhere at bottom, that sets the constraints to fill the screen minus "safe" margins.) Copied LaunchScreen.storyboard from that, into my project's Resources folder. Along with the .png referenced by that storyboard.

Troubleshooting: Sometimes simulator fails to show updated launch screen. (Including not showing the change from "black screen" to "now I have the needed files - works on device".) I list various steps that might be needed. Launch screen is tricky, because device or simulator seems to cache for each app that has been run. Power off/on helps.

CAVEAT: the "fake" code-signing (for Debug build) may not work on a physical device.
There doesn't seem to be a way for .csproj to explicitly test whether building for "device" or "simulator".

CAVEAT # 2: I Seem to need certificate on both mac and pc. (Might be related to how this Apple team was originally set up.) Still trying to get a good "recipe" for the certificate+provisioning process. However, once it works for a device attached via USB to the Mac (Building on PC via Pair to Mac), then getting it to work on simulator now seems to be easy, by changing to those "fake" code-sign lines.

rolfbjarne added a commit that referenced this issue May 5, 2025
When building for the simulator:

* Signing is enabled by default.
* Any entitlements the app requests will be embedded in the native executable in
  an `__ents_der` Mach-O section.
* The actual app signature only demands the "com.apple.security.get-task-allow"
  entitlement.
* No provisioning profiles are used.

Also:

* Unify the code to detect signing identity, so that it's as equal as possible
  between our platforms.


Fixes #18469.
rolfbjarne added a commit that referenced this issue May 8, 2025
Enable signing by default for all platforms, because that's what Xcode does.

This fixes an issue for simulator builds, where certain features don't work unless
the app is signed (#18469).

It also simplifies and unifies our code to detect signing identities, so that it's
much more shared/equal beteween platforms.

However, simulator builds have a few peculiarities:

* The placeholder code signing certificate ("-", or what Xcode calls "Sign to
  Run Locally") is always used.
* Any entitlements the app requests will be embedded in the native executable in
  a Mach-O section named `__ents_der`.
* The actual app signature only demands the
  "com.apple.security.get-task-allow" entitlement (which seems to be allowed
  without a provisioning profile when using the placeholder code signing
  certificate).
* No provisioning profiles are used.

In order to provide a fairly decent way of restoring old behavior (not signing simulator
builds), I created a public property to determine whether we're building for the
simulator (SdkIsSimulator), and added documentation on how to use this new property
to disable code signing.

Fixes #18469.
rolfbjarne added a commit that referenced this issue May 9, 2025
Enable signing by default for all platforms, because that's what Xcode does.

This fixes an issue for simulator builds, where certain features don't work unless
the app is signed (#18469).

It also simplifies and unifies our code to detect signing identities, so that it's
much more shared/equal beteween platforms.

However, simulator builds have a few peculiarities:

* The placeholder code signing certificate ("-", or what Xcode calls "Sign to
  Run Locally") is always used.
* Any entitlements the app requests will be embedded in the native executable in
  a Mach-O section named `__ents_der`.
* The actual app signature only demands the
  "com.apple.security.get-task-allow" entitlement (which seems to be allowed
  without a provisioning profile when using the placeholder code signing
  certificate).
* No provisioning profiles are used.

In order to provide a fairly decent way of restoring old behavior (not signing simulator
builds), I created a public property to determine whether we're building for the
simulator (SdkIsSimulator), and added documentation on how to use this new property
to disable code signing.

Fixes #18469.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment