Author Topic: CodeSign and Notarize procedures  (Read 3574 times)


  • New member
  • *
  • Posts: 8
CodeSign and Notarize procedures
« on: July 31, 2019, 03:34:22 pm »
*Update*  1 year later (July 2020):   This procedure is still valid and correct, and required of course.


Now Apple have added App Bundle notarizing, where they co-sign and validate the bundle.  From 10.14.x (Mojave) onwards, this is becoming enforced in various ways.

This procedure below applies to making and assembling your own app bundle, then placing it in a Package (.pkg) installer file, and then wrapping it all in a .dmg file for distribution.

The procedure I am using now is:

1/  Join the Mac Dev Center through Appstore.  $119 a year - suck it up.
2/  In the Dev center, go to the certificate section, and create 2 new certificates:  Go to: Certificates ->  + to create new  There are now many choices.   Here I'm selecting "Developer ID Installer" and "Developer ID Application".   We use these when making app's that we sign and distribute ourselves.  You do this creating cert's in conjunction with KeyChain utility program and its Assistant and request a cert (use the saved to disk method)
3/  Download those two certs and install into your KeyChain (click the cer file).
4/  Download the Intermediate certs - Look for the Intermediate certs and get the WWDR and Developer ID Intermediate cert.  You might already have these installed.  Install these to your KeyChain too.

Assemble your app bundle.   Described here:

5/  Sign your .app bundle:
/usr/bin/codesign -f -o runtime --timestamp -s "Developer ID Application: My Software Corp." /path/to/my/app/
(use your real devel ID name per the cert).

Note:  If you are using outside libraries, including linking to inbuilt 3rd party things like openssl through fcl-web package, then you may need to include entitlements - see below.

6/  Make your package file with your signed .app bundle above.   I use the Packages utility (3rd party install making tool [link below]).  Instead try the pkgbuild and productbuild command line tools.

7/  Sign your .pkg file:
/usr/bin/productsign --sign "Developer ID Installer: MyCoName inc." /input/path/to/package.pkg  /OUTPUT/path/for/the/result.pkg
(use your real install ID name per the cert).

8/  Make your .dmg file as required.   I use the command line tool
hdiutil create -ov -scrub -srcfolder  /bundle_dir/  -volname dmgvolname  /OUTPUT/path/for/the/result.dmg

9/  Upload the finished dmg file to Apple:
/usr/bin/xcrun altool --notarize-app --primary-bundle-id "" -u "" -p "my_password" -t osx -f /path/to/my/dmg/file.dmg

10/  wait.... check the progress with:
/usr/bin/xcrun altool --notarization-history 0 -u "" -p "my_password"

11/  After the above step registers "Package Approved", have Apple staple notarized signature to the dmg file with
/usr/bin/xcrun stapler staple  /path/to/my/dmg/file.dmg


To verify, install the app and call
/usr/bin/spctl -a -v /Applications/
...which will return "Notarized" and "accepted" if all is OK.
Most important... test the app by putting it in the Applications directory.  It's treated differently by the OS (ATS/Gatekeeper) when in the "installed" location.
Effective 10.15, your app will generate errors messages and refuse to run, if any errors exist in the process above.


Step  9 requires you to have a new 2FA application sign in's. see:

Apples guide to notarizing:

Using the codesign's "-o runtime" option, enables the "hardened runtime" on the binary, which is required for notarizing.  But it also limits variables passed into and the calling of .dylib files.   If the external libraries are signed and notarized by you or Apple, then entitlements are not needed.  The normal framework libraries are signed by Apple.  But many third party .dylib's are not fully signed/notarized, or signed by third party but not you, so an entitlement is required to allow proper variable passing / library loading.  For these you will need to add an entitlements file to the project and add it to the codesign'n process of the .app bundle, as follows.

Step 5 above becomes:
/usr/bin/codesign -f -o runtime --entitlements path/to/my/app.entitlements  --timestamp -s "Developer ID Application: My Software Corp." /path/to/my/app/

The "app.entitlements" file does not ship with the bundle - it's for the code sign process only.  The app.entitlements file looks like this:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "">
<plist version="1.0">

The above enables the "Allow DYLD Environment Variables", which is sufficient to use the openssl packages.  You might also need the "Disable Library Validation" (    All available options are listed here under "Hardened Runtime":

#Aug 30th, 2019 - procedure updated
#July 11th, 2020 - added info.
Packages app:
« Last Edit: July 11, 2020, 03:56:33 pm by rossh_lz »


  • Hero Member
  • *****
  • Posts: 1137
    • formatio reticularis
Re: CodeSign and Notarize procedures
« Reply #1 on: August 10, 2019, 06:57:15 am »
Thanks for providing this important information. Would you mind to update the corresponding wiki page?
function GetRandomNumber: integer; //
  GetRandomNumber := 4; // chosen by fair dice roll. Guaranteed to be random.

Lazarus 2.0.10 | FPC 3.2.0 | PPC, Intel, ARM | macOS, Windows, Linux


  • Full Member
  • ***
  • Posts: 165
Re: CodeSign and Notarize procedures
« Reply #2 on: August 24, 2019, 01:11:38 pm »
This is really useful. Do you or anyone else in this community know how to notarize command line executables?


  • Global Moderator
  • Hero Member
  • *****
  • Posts: 994
  • Former Delphi 1-7, 10.2 User
Re: CodeSign and Notarize procedures
« Reply #3 on: August 26, 2019, 12:05:10 pm »
Regarding command line tools and notarizing, this is the response I received from the TSI I lodged with Apple:

I’m responding to your report of problems notarising your command-line tool.  You wrote:

> However, there is obviously no "primary-bundle-id" because there are
> no `.app` bundles.

The notarisation system does not currently use this bundle ID for much.  You can supply any value that’s meaningful to you, although I recommend that you choose a sensible bundle ID by combining a DNS name that you control and your product name (for example, `org.domain.great-cow-basic`).

Having said that, command-line tools /can/ support a bundle ID and I recommend that you apply the bundle to your command-line tool as follows:

* When you build your tool, embed an `Info.plist` containing your bundle ID in the executable using the `-sectcreate` option with the segment name being `__TEXT` / `__info_plist`.  To learn more about this, follow the instructions I’ve included at the end of this response.

* When you sign your tool, set the code signing identifier to this bundle ID via the `-i` option to `codesign`.

* When you notarise your tool, pass this bundle ID to the notarisation system via the `--primary-bundle-id` option.

Share and Enjoy
Quinn “The Eskimo!”
Apple Developer Relations, Developer Technical Support, Core OS/Hardware

The best way to learn how to give a command-line tool an `Info.plist` is to copy what Xcode does:
1. Create a dummy command-line tool project in Xcode.

2. Add an `Info.plist` file to the project.  If you’re not sure how to set this up, copy the file from a new, dummy Mac app project.

3. Configure it appropriately.  If your `Info.plist` file references build settings, make sure those settings are configured in your target.  Of specific note is the Product Bundle Identifier (`PRODUCT_BUNDLE_IDENTIFIER`) build setting.

4. Set the Info.plist File (`INFOPLIST_FILE`) and Create Info.plist Section in Binary (`CREATE_INFOPLIST_SECTION_IN_BINARY`) build settings.

5. Build the project.

6. Use `otool` to confirm that the section was created correctly.

$ otool -s __TEXT __info_plist -v Test715194488
Contents of (__TEXT,__info_plist) section
<?xml version="1.0" encoding="UTF-8"?>

<plist version="1.0">

7. Look at the build transcript to see how Xcode created it.

As the command line tool I have been distributing is the Great Cow BASIC compiler for macOS, generated by a combination of FreeBASIC and gcc, it was not immediately obvious to me how these instructions would resolve my issue and I haven't had time to look at it in any detail since.
o Lazarus v2.1.0 r63871, FPC v3.3.1 r46876, macOS 10.14.6 (with sup update), Xcode 11.3.1
o Lazarus v2.1.0 r61574, FPC v3.3.1 r42318, FreeBSD 12.1 amd64 (VMware Fusion VM)
o FPC 3.0.4, FreeBSD 12.2-STABLE r365646 amd64
o Lazarus v2.1.0 r61574, FPC v3.0.4, Ubuntu 18.04 (Parallels VM)


  • Hero Member
  • *****
  • Posts: 599
    • Tweaking4All
Re: CodeSign and Notarize procedures
« Reply #4 on: September 11, 2019, 03:29:11 pm »
Thanks rossh_lz!
Worked like a charm for notarizing my apps!  ;)


  • Hero Member
  • *****
  • Posts: 701
Re: CodeSign and Notarize procedures
« Reply #5 on: October 27, 2019, 11:20:57 pm »
Sorry for bumbing this thread.

I already sign + have a complete plist file.

However... I do not believe i do anything for "hardened runtime" part - I will need to investigate that.

I do load OpenSSL dylib thrugh Indy so that may be an issue with regarrds to notarization?

I ship my products in .zip file but I believe I have read Apple supports that for notarization. (Good)

I can see Apple says we should link against macOS 10.9 or later SDK.... So that is kinda troublesome. That will leave some older rmacOS  machines unable to use applications.  I currently link against 10.8 currently using custom options in Lazarus to target -VM10.8


Wasn't there something building a Lazarus addin that could: Strip. Move Executable into correct .app. Sign. Zip. Notarize? 

How do you manage the process? Unfortunately I have many sibling tools (share same codebase and forms but different defines) so I have to repeat the above process many times which often causes me to make an error at some point.... Maybe I should make some script files...

« Last Edit: October 27, 2019, 11:55:17 pm by MISV »


TinyPortal © 2005-2018