Recent

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

rossh_lz

  • New Member
  • *
  • Posts: 21
CodeSign and Notarize procedures
« on: July 31, 2019, 03:34:22 pm »
*Update*  2.5 years later (Feb 2022):   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:


Setup:
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 (now seem to be pre-installed via XCode).  You might already have these installed.  Install these to your KeyChain too.

Assemble your app bundle.   Described here:  https://developer.apple.com/library/archive/documentation/CoreFoundation/Conceptual/CFBundles/BundleTypes/BundleTypes.html#//apple_ref/doc/uid/10000123i-CH101-SW1


Signing:
5/  Sign your .app bundle:
/usr/bin/codesign -f -o runtime --timestamp -s "Developer ID Application: My Software Corp." /path/to/my/app/bundle.app
(use your real developer 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


Notarizing:
9/  Upload the finished dmg file to Apple:
/usr/bin/xcrun altool --notarize-app --primary-bundle-id "com.software.myapp.random" -u "me@mysoftware.com" -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 "me@mysoftware.com" -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

Done.

To verify, install the app and call
/usr/bin/spctl -a -v /Applications/my_installed_app.app
...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.


***************

Notes:
Step  9 requires you to have a new 2FA application sign in's. see:
https://support.apple.com/en-us/HT204397

Apples guide to notarizing:
https://developer.apple.com/documentation/security/notarizing_your_app_before_distribution/customizing_the_notarization_workflow?language=objc


Entitlements:
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 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/bundle.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" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
   <key>com.apple.security.cs.allow-dyld-environment-variables</key>
   <true/>   
</dict>
</plist>


The above enables the "Allow DYLD Environment Variables", which is sufficient to use the openssl packages.  You might also need the "Disable Library Validation" (com.apple.security.cs.disable-library-validation).    All available options are listed here under "Hardened Runtime":
https://developer.apple.com/documentation/bundleresources/entitlements?language=objc

#Aug 30th, 2019 - procedure updated
#July 11th, 2020 - added info.
#Feb 27th, 2022 - updated info.
Packages app: http://s.sudre.free.fr/Software/Packages/about.html
« Last Edit: February 27, 2022, 10:36:31 am by rossh_lz »

jwdietrich

  • Hero Member
  • *****
  • Posts: 1232
    • 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; // xkcd.com
begin
  GetRandomNumber := 4; // chosen by fair dice roll. Guaranteed to be random.
end;

http://www.formatio-reticularis.de

Lazarus 2.2.6 | FPC 3.2.2 | PPC, Intel, ARM | macOS, Windows, Linux

ChrisR

  • Full Member
  • ***
  • Posts: 247
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?

trev

  • Global Moderator
  • Hero Member
  • *****
  • Posts: 2020
  • 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:

Quote
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
<http://www.apple.com/developer/>

---------------------------------------------------------------------------
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">
<dict>
    …
    <key>CFBundleIdentifier</key>
    <string>com.example.apple-samplecode.Test715194488</string>
    …
</dict>
</plist>

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.

Hansaplast

  • Hero Member
  • *****
  • Posts: 674
  • Tweaking4All.com
    • 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!  ;)

MISV

  • Hero Member
  • *****
  • Posts: 783
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 »

Igor Kokarev

  • Sr. Member
  • ****
  • Posts: 370
Re: CodeSign and Notarize procedures
« Reply #6 on: October 27, 2020, 01:56:49 pm »
How to correctly install codesign certificates on second Mac?

I have first Mac where I successfully sign and notarize my app for macOS outside AppStore.

On second Mac I downloaded existing "Developer ID Installer" and "Developer ID Application" certificates and installed in KeyChain.
Also I downloaded and installed Intermediate Certificate.

When I try to sign anything on second Mac I see the error:
Code: Pascal  [Select][+][-]
  1. "error: The specified item could not be found in the keychain."

Also I have a file "CertificateSigningRequest.certSigningRequest" saved from first Mac. No idea how to use it.

What I missed in this nightmare to get it work?
« Last Edit: October 27, 2020, 01:58:27 pm by Igor Kokarev »

trev

  • Global Moderator
  • Hero Member
  • *****
  • Posts: 2020
  • Former Delphi 1-7, 10.2 user
Re: CodeSign and Notarize procedures
« Reply #7 on: October 28, 2020, 12:39:06 am »
I suspect that your second computer is missing your private key. Try:

Code: [Select]
security find-identity -p codesigning
which I believe will show no valid identities. To fix this:

* On the first computer, open the  Keychain Access application and create a new keychain. Now select your existing login keychain, and then My Certificates. Your certificate should be shown on the right. There should be a disclosure arrow on the left side, and selecting that should reveal your private key.  Select the certificate, and copy and paste (do not drag or you'll remove it from your login keychain) it into your new keychain.

* Copy the newly created keychain from your first computer to your new computer, open it with the Keychain Access application and copy/paste/drag the certificate to your second computer's login keychain.

Let me know how you go.

Igor Kokarev

  • Sr. Member
  • ****
  • Posts: 370
Re: CodeSign and Notarize procedures
« Reply #8 on: October 28, 2020, 06:13:01 pm »
trev,

Thanks for your advice! Now I can codesign my app on second Mac.

By the way, I also found alternate solution via Xcode:

"Go to Xcode > Preferences > Accounts, select your account, and then choose Export Apple ID and Code Signing Assets. Then do the reverse on your other Mac."

trev

  • Global Moderator
  • Hero Member
  • *****
  • Posts: 2020
  • Former Delphi 1-7, 10.2 user
Re: CodeSign and Notarize procedures
« Reply #9 on: October 29, 2020, 12:00:22 pm »
I've added both methods to the Wiki article. Thanks for the Xcode version!

VTwin

  • Hero Member
  • *****
  • Posts: 1215
  • Former Turbo Pascal 3 user
Re: CodeSign and Notarize procedures
« Reply #10 on: February 21, 2022, 11:43:41 pm »
I know this is an old thread, but the following may be useful to someone.

I had no luck with manual ad hoc code signing of an application bundle:

Code: Pascal  [Select][+][-]
  1. codesign --force --deep -s - MyApp.app

But came across this:

https://stackoverflow.com/questions/65258043/codesigning-modified-binaries-apple-silicon-m1

"It's a known bug in the codesign tool. To work around it, make a copy of your modified executable, sign the copy, then replace the original executable with the signed copy and it should work."

That worked for me.



“Talk is cheap. Show me the code.” -Linus Torvalds

Free Pascal Compiler 3.2.2
macOS 12.1: Lazarus 2.2.6 (64 bit Cocoa M1)
Ubuntu 18.04.3: Lazarus 2.2.6 (64 bit on VBox)
Windows 7 Pro SP1: Lazarus 2.2.6 (64 bit on VBox)

trev

  • Global Moderator
  • Hero Member
  • *****
  • Posts: 2020
  • Former Delphi 1-7, 10.2 user
Re: CodeSign and Notarize procedures
« Reply #11 on: February 22, 2022, 01:46:11 am »
If as the SO post indicated, the binary is changed after signing, then to prevent it being resigned after being altered seems sensible to me.

It does cause issues sometimes with recompiling binaries if they re-use the same inode because as noted in my Wiki article Updating a signed file :

Quote
... the code signing information (code directory hash) is hung off the vnode within the kernel, and modifying the file behind that cache will cause problems. You need a new vnode, which means a new file, that is, a new inode. Documented in WWDC 2019 Session 703 All About Notarization

 

TinyPortal © 2005-2018