Notarized app starts if downloaded via curl, but not if downloaded via browser

Via jpackage from java jdk (17.0.2) we generated a .dmg on a Mac Monterey (12.3.1), including codesigning (using fresh Apple Development Id certificate). Then we notarized and stapled it and uploaded the resulting .dmg to our webserver.

The problem:

  • if downloaded the .dmg in the terminal app via curl -O https://xxxxx/my.dmg, click the downloaded .dmg and the application icon in the window that opens, the app starts as expected.

  • if downloaded the .dmg via the same URL in a web browser (e. g. Safari or Chrome), click the downloaded .dmg and the application icon in the windows that opens, the dock icon keeps bumping and the app doesn't show up, without any error messages.

For both downloads, spctl shows source=Notarized Developer ID, and no issues were reported in the notarytool log. Further, both downloads are binary equal.

How comes that the "normal" download does not launch?

The Notarization is invalid. It passes the initial checks but it is failing the lower-level runtime checks when the software is executed. Usually the problem here is with dynamic libraries. Those cross-platform app-generation tools just can't ever seem to do Notarization properly. They always do unusual things with dynamic libraries. It is now your job to find out what those are. You might be able to just add one of those entitlements to make it work. But in some cases, the problems go deeper than that.

You might be able to find an error message if you run Console.app. You just have to be very quick. Click the "start streaming" button and then immediately try to run your app. Don't let it sit there for more than a couple of seconds. Jump back to Console and stop streaming. Then review the log file. If you can do all of this in 10 seconds or so, then you'll only have a few thousand log entries to review. Maybe one of them will tell you where it is failing.

Thanks for the answer. Seems that jpackage and Apple are not best friends, and I wish that "Write once, run everywhere" would still be true in 2022.

Thank you for the "streaming" hint, I will just try this out. I'm still wondering why there are different lower-level runtime checks being applied dependent on the kind of download (curl vs. web browser). Which leads me to the question: How can I be sure that my Notarization is valid? Is there any reliable tutorial, or at least a way to check a notarized app for validity without uploading and downloading for each test cycle?

@nk_kennedy (or anybody else): I'd like you to ask for little more help to solve the problem. My questions are:

  1. How are chances that I'm on the right track (see below)?
  2. What should I do next (So far, I didn't find anything useful in the internet)?

Thank you very much for any help.


According to your hint I took two log snapshots - one for the running, and one for the non-running app launch. Only in the non-running one I found one "entitlement"-related hint for pid 1250, followed by an GKQuarantineResolver, as shown here:

...

standard 18:47:18.138921+0200 loginwindow -[ApplicationManager checkInAppContext:eventData:] | ApplicationManager: Checked in app : NAME_OF_OUR_APP.app

standard 18:47:18.165987+0200 distnoted register name: com.apple.sharedfilelist.change object: com.apple.LSSharedFileList.RecentApplications token: 300000002 pid: 1250

...

standard 18:47:18.301726+0200 CoreServicesUIAgent Connection from process 1250 does not have the required entitlement com.apple.private.iscsuia

standard 18:47:18.306516+0200 CoreServicesUIAgent : progressed to 0.00%

standard 18:47:18.306582+0200 CoreServicesUIAgent : progressed to 60.00%

standard 18:47:18.310178+0200 CoreServicesUIAgent -[GKQuarantineResolver malwareCheckEnded:result:forURL:]: XProtect defer executable analysis: true

standard 18:47:18.310425+0200 CoreServicesUIAgent : progressed to 60.00%

standard 18:47:18.310389+0200 CoreServicesUIAgent dismissing after minimum display time of 2.0000s, actual display time of -4.9936s

standard 18:47:18.310817+0200 CoreServicesUIAgent -[GKQuarantineResolver malwareChecksFinished]_block_invoke: XProtect suppress first launch warning: true

standard 18:47:18.312305+0200 open Entering exit handler.

standard 18:47:18.312516+0200 open Exiting exit handler.

...

There aren't different lower-level runtime checks being performed between curl vs. a web browser. When you use curl, there are no checks being done at all. Gatekeeper works by having the web browser attach a quarantine flag to the downloaded file.

Then, when you double-click a file to run it, the operating system looks for a quarantine flag. If it finds one, it performs a notarization check before, and somewhat during, the launch of the app.

Caveat #1: If there is no quarantine flag, nothing gets checked. M1 machines have slightly different behavior. They may require a signature, but this is murky.

Caveat #2: There is different behavior depending on if the app is a double-clickable app vs a command line tool. An app may give you one or more dialogs about where the app was downloaded from and whether or not Apple checked it for malware. A command line tool won't display that interface. These cross-platform tools often generate apps that are a mixture of proper apps and command line tools.

I admit I am a bit unsure of exactly what transpires when notarization fails. I don't use any of those cross-platform tool builders so any notarization problems are extremely rare and when they do happen, they are extremely easy to find and fix.

The problems you encounter will almost always involve dynamic libraries. Entitlement are the solution. The log messages are never going to mention entitlement (i.e. the solution). They are only going to complain about what isn't working. If all else fails, you can just go through the list Hardened Runtime Exceptions and try them one-by-one, or some combination thereof. In your case, the cause could be one or more of the items listed in the "Runtime Exceptions" list.

@nk_kennedy: Thanks for your answer. Last two days I checked everything you said again and again. I built a minimal reproducable app according to all tutorials I cound find, added and verified all Hardened Runtime Exceptions, signed all dylibs, jars, app, dmg. Everything works without any errors. But, the problem exactly remains: I cannot download and start apps as .dmg via the browser - I just keep getting that error message above from CoreServicesUIAgent: "Connection from process XXXX does not have the required entitlement com.apple.private.iscsuia". And as I found out by chance, the exact same error comes with all tested standard apps that are available as .dmg download in the internet (I downloaded it via Safari and Chrome):

https://www.mozilla.org/de/firefox/mac/ https://dbeaver.io/download/ https://www.openoffice.de/openoffice_download_macosx.php

So, I guess that my code signing and notarization works actually well, but my MacOS Monterey is errorneous after the update to 12.3.1.

What do you suggest, should I upgrade, downgrade, or something else? Could you try to download and install one of those apps to verify if they are not broken? Btw., the checkbox "Allow downloads from App Store and trusted developers" is of course checked.

Thank you so much for further assistance!

I’ve been working on a cluster of posts explaining how to investigate trusted execution issues. The place to start is Resolving Trusted Execution Problems. However, in this case I think something is borked on your system. I’ll respond over on your other thread the next time I swing by DevForums for real (probably on Monday).

Share and Enjoy

Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@" + "apple.com"

Notarized app starts if downloaded via curl, but not if downloaded via browser
 
 
Q