Sign GrandOrgue for MacOS
Closed this issue · 23 comments
Signing is mandatory for Apple/M1. #1831 (comment)
For signing we need
- To obtain a signing certificate from Apple for GrandOrgue.
- To adopt the build scripts for signing.
- To create a Github enviroment for signing.
@rousseldenis Could you help us with (1.)? Which rules are there for open source projects supported by a community? Should the certificate be a personal or one issued for organisation? Anyway could you communicate with Apple and obtain a certificate suitable for GrandOrge?
@willeke1234 Because you have built GrandOrgue locally and it works, I suppose you already have a personal developer certificate from apple. I doubt you may share it for a foreign project hosted on github, but you obviosly may test the build processus locally with your certificate and participate in (2.). Do you agree?
For (3.) there is some additional information https://docs.github.com/en/actions/deployment/deploying-xcode-applications/installing-an-apple-certificate-on-macos-runners-for-xcode-development
A similar issue exists in Windows #836 but there is a workaround: to force OS to allow run GrandOrgue despite it is not signed.
Originally posted by @willeke1234 in #1831 (comment)
Which library is modified? Could you post here the full error message or a screenshot?
All libraries are modified. The creation and modification dates are the changed and when I verify the code signature I get:
invalid signature (code or signature have been modified)
- How do you verify the code signature for paticular libraries?
- Are only dates different, but not the library content?
- What policy is there for libraries: should GrandOrgue sign them or their own original signatures are still valid?
But I found the difference (paths). The following commands must be executed to code sign everything. I found Using cmake to sign target but in which script do I add what?
https://github.com/GrandOrgue/grandorgue/blob/master/cmake/BuildExecutable.cmake
You have to add
ADD_CUSTOM_COMMAND(TARGET ${TARGET} POST_BUILD COMMAND codesign --force -s "${CMAKE_CURRENT_BINARY_DIR}/$<TARGET_FILE_NAME:${TARGET}>")
of course, only for apple build.
Other questions:
What does the workaround in build-scripts/for-osx/prepare-osx.sh do? Is it still necessary?
Yes, it is. This script installs the all necessary build environment, tools and libraries to your mac. If we need some additional tools for code signing, installing them should be added to build-scripts/for-osx/prepare-osx.sh.
Does this affect other projects on my Mac?
Usually installing anything does not affect other projects. So it must not do this.
In build-on-osx.sh: "-DCMAKE_OSX_DEPLOYMENT_TARGET=12.1" is this still necessary? Or was it added with the workaround for macOS 10.15?
It allows GrandOrgue built on macOs 12.3 to run on 12.1.
@oleg, @rousseldenis We don't need a signing certificate from Apple ($99/year) and I don't have one. Ad-hoc signing (free and without a certificate) will do. All it takes is running a command.
If you are talking about an online signing, we need some way to identify us by apple. Otherwise any malware could be signed ad-hoc as well.
Ad-hoc signing does not use an identity or signing certificate at all. GrandOrgue on Intel is currently unsigned but on ARM, macOS refuses to run unsigned apps. GrandOrgue will be signed at minimum to keep macOS happy. Or rather, I know it runs on my Mac, I'm not really sure it'll run on other Macs.
Step 1: tweak the build scripts so GrandOrgue builds and runs on my Mac (I'm working on it)
Step 2: build on GitHub and run on my Mac
Step 3: build on GitHub and run on other Macs without developer tools
Let's worry about a signing certificate when we're sure we need it.
GrandOrgue builds and runs on my Mac but…
-
Extra files are added:
GrandOrgue.app/Contents/Resources/GOIcon.ico
GrandOrgue.app/Contents/Resources/GrandOrgue.iconset
GrandOrgue.app/Contents/Resources/GrandOrgue.manifest
GrandOrgue.app/Contents/Resources/GrandOrgue.rc -
The app on the disk image (.dmg) isn't signed. I tried several CPack variables but CPack doesn't sign the app. The app must be signed after adding all files to the bundle and before adding the bundle to the disk image.
-
HomeBrew installs in
/usr/local
on Intel and in/opt/homebrew
on ARM. The workaround in prepare-osx.sh:
for F in $(grep -l '(, weak)\?' /usr/local/Cellar/cmake/*/share/cmake/Modules/GetPrerequisites.cmake); do
I assume the workaround doesn't work at the moment but the app appears to work.
How do I fix all this? I don't want to change things haphazardly.
I get a lot of build warnings, including warnings about errors. Do you have any tips for finding the errors and warnings I have to fix?
The discussion moved back to #1831. This issue can be closed.
@oleg ok, I'll ask my questions where I think they belong.
I've been digging through CPack's documentation and source code. I think the CPack DragNDrop Generator builds the app but can't sign it and the CPack Bundle Generator can sign but doesn't build the app. Questions:
- Which script/tool/function is adding the libs to the regular app and app on the .dmg?
- Is it possible to add a final build step, executed on both apps?
- What is the difference between the two apps?
- Which script/tool/function is adding the libs to the regular app and app on the .dmg?
https://github.com/GrandOrgue/grandorgue/blob/master/cmake/FixupBundle.cmake
- Is it possible to add a final build step, executed on both apps?
https://cmake.org/cmake/help/v3.5/command/install.html#custom-installation-logic
- What is the difference between the two apps?
What two apps are you interested by?
What two apps are you interested by?
GrandOrgueBuild/build/osx/GrandOrgue.app
/Volumes/grandorgue-3.7.5.1-0.local.osx.arm64/GrandOrgue.app (= GrandOrgueBuild/build/osx/grandorgue-3.7.5.1-0.local.osx.arm64.dmg)
Do I have to sign them separately in a build step and an install step? How do I make sure this is the last step?
I see that building for MacOS differs significantly from building for other OSes. I thought that it should be at install step, but ./GrandOrgue.app
is created during simple make
.
So I suggest you to find where FixupBundle is called and to add a step after it.
At the end of grandorgue/src/grandorgue/CMakeLists.txt I added:
if(APPLE)
ADD_CUSTOM_COMMAND(TARGET "GrandOrgue" POST_BUILD
COMMAND codesign --force --sign - "${CMAKE_BINARY_DIR}/${PROJECT_NAME}.app/Contents/Frameworks/*.*" "${CMAKE_BINARY_DIR}/${PROJECT_NAME}.app/Contents/MacOS/GrandOrguePerfTest" "${CMAKE_BINARY_DIR}/${PROJECT_NAME}.app/Contents/MacOS/GrandOrgueTool" "${CMAKE_BINARY_DIR}/${PROJECT_NAME}.app")
endif()
The app appears to be signed and macOS doesn't complain but when I verify the app, I get:
grandorgue@Virtuele-machine-van-GrandOrgue GrandOrgueBuild % codesign --verify --verbose 1 --deep /Users/grandorgue/Documents/Projects/GrandOrgue_3.13/GrandOrgueBuild/build/osx/GrandOrgue.app
1: dynamically valid
1: valid on disk
1: satisfies its Designated Requirement
/Users/grandorgue/Documents/Projects/GrandOrgue_3.13/GrandOrgueBuild/build/osx/GrandOrgue.app: a sealed resource is missing or invalid
file modified: /Users/grandorgue/Documents/Projects/GrandOrgue_3.13/GrandOrgueBuild/build/osx/GrandOrgue.app/Contents/Resources/GrandOrgue.iconset/icon_32x32.png
file modified: /Users/grandorgue/Documents/Projects/GrandOrgue_3.13/GrandOrgueBuild/build/osx/GrandOrgue.app/Contents/Resources/GrandOrgue.iconset/icon_1024x1024.png
file modified: /Users/grandorgue/Documents/Projects/GrandOrgue_3.13/GrandOrgueBuild/build/osx/GrandOrgue.app/Contents/Resources/GrandOrgue.iconset/icon_16x16.png
If I do PARALLEL_PRMS="-j1"
then I get an error:
/Users/grandorgue/Documents/Projects/GrandOrgue_3.13/GrandOrgueBuild/build/osx/GrandOrgue.app/Contents/MacOS/GrandOrguePerfTest: No such file or directory
codesign
is executed before the app is completely built. The ADD_CUSTOM_COMMAND
commands in the subdirectories aren't ready yet. Signing the app in Build-on-osx.sh works, but this is not very useful when developing. On the other hand, not many people build GrandOrgue on macOS.
To sign the app on the .dmg I added in grandorgue/CMakeLists.txt after set(CPACK_GENERATOR DragNDrop)
:
file(WRITE "${CMAKE_BINARY_DIR}/sign_package.cmake"
"EXECUTE_PROCESS(COMMAND codesign --force --sign - \"\${CPACK_TEMPORARY_INSTALL_DIRECTORY}/ALL_IN_ONE/${PROJECT_NAME}.app/Frameworks/*.*\")\n")
file(APPEND "${CMAKE_BINARY_DIR}/sign_package.cmake"
"EXECUTE_PROCESS(COMMAND codesign --force --sign - \"\${CPACK_TEMPORARY_INSTALL_DIRECTORY}/ALL_IN_ONE/${PROJECT_NAME}.app/Contents/MacOS/GrandOrguePerfTest\")\n")
file(APPEND "${CMAKE_BINARY_DIR}/sign_package.cmake"
"EXECUTE_PROCESS(COMMAND codesign --force --sign - \"\${CPACK_TEMPORARY_INSTALL_DIRECTORY}/ALL_IN_ONE/${PROJECT_NAME}.app/Contents/MacOS/GrandOrgueTool\")\n")
file(APPEND "${CMAKE_BINARY_DIR}/sign_package.cmake"
"EXECUTE_PROCESS(COMMAND codesign --force --sign - \"\${CPACK_TEMPORARY_INSTALL_DIRECTORY}/ALL_IN_ONE/${PROJECT_NAME}.app\")\n")
set(CPACK_PRE_BUILD_SCRIPTS "${CMAKE_BINARY_DIR}/sign_package.cmake")
The app is signed but some or all libs aren't signed, maybe a race condition or caching problem. In the log I get
-- 54/56: fixing up '//Users/grandorgue/Documents/GitHub/GrandOrgueBuild/build/osx/_CPack_Packages/macOS/DragNDrop/grandorgue-3.14.0-0.local.macOS.arm64/ALL_IN_ONE/GrandOrgue.app/Contents/Frameworks/libwx_osx_cocoau_html-3.2.0.2.2.dylib'
/Library/Developer/CommandLineTools/usr/bin/install_name_tool: warning: changes being made to the file will invalidate the code signature in: //Users/grandorgue/Documents/GitHub/GrandOrgueBuild/build/osx/_CPack_Packages/macOS/DragNDrop/grandorgue-3.14.0-0.local.macOS.arm64/ALL_IN_ONE/GrandOrgue.app/Contents/Frameworks/libwx_osx_cocoau_html-3.2.0.2.2.dylib
-- 55/56: fixing up '//Users/grandorgue/Documents/GitHub/GrandOrgueBuild/build/osx/_CPack_Packages/macOS/DragNDrop/grandorgue-3.14.0-0.local.macOS.arm64/ALL_IN_ONE/GrandOrgue.app/Contents/Frameworks/libyaml-cpp.0.8.0.dylib'
/Library/Developer/CommandLineTools/usr/bin/install_name_tool: warning: changes being made to the file will invalidate the code signature in: //Users/grandorgue/Documents/GitHub/GrandOrgueBuild/build/osx/_CPack_Packages/macOS/DragNDrop/grandorgue-3.14.0-0.local.macOS.arm64/ALL_IN_ONE/GrandOrgue.app/Contents/Frameworks/libyaml-cpp.0.8.0.dylib
-- 56/56: fixing up '//Users/grandorgue/Documents/GitHub/GrandOrgueBuild/build/osx/_CPack_Packages/macOS/DragNDrop/grandorgue-3.14.0-0.local.macOS.arm64/ALL_IN_ONE/GrandOrgue.app/Contents/Frameworks/libzstd.1.5.5.dylib'
/Library/Developer/CommandLineTools/usr/bin/install_name_tool: warning: changes being made to the file will invalidate the code signature in: //Users/grandorgue/Documents/GitHub/GrandOrgueBuild/build/osx/_CPack_Packages/macOS/DragNDrop/grandorgue-3.14.0-0.local.macOS.arm64/ALL_IN_ONE/GrandOrgue.app/Contents/Frameworks/libzstd.1.5.5.dylib
-- fixup_bundle: cleaning up...
-- fixup_bundle: verifying...
-- fixup_bundle: done
CPack: - Install component: resources
CPack: - Install component: demo
CPack: Executing pre-build script: /Users/grandorgue/Documents/GitHub/GrandOrgueBuild/build/osx/sign_package.cmake
/Users/grandorgue/Documents/GitHub/GrandOrgueBuild/build/osx/_CPack_Packages/macOS/DragNDrop/grandorgue-3.14.0-0.local.macOS.arm64/ALL_IN_ONE/GrandOrgue.app/Contents/Frameworks/*.*: No such file or directory
/Users/grandorgue/Documents/GitHub/GrandOrgueBuild/build/osx/_CPack_Packages/macOS/DragNDrop/grandorgue-3.14.0-0.local.macOS.arm64/ALL_IN_ONE/GrandOrgue.app/Contents/MacOS/GrandOrguePerfTest: replacing existing signature
/Users/grandorgue/Documents/GitHub/GrandOrgueBuild/build/osx/_CPack_Packages/macOS/DragNDrop/grandorgue-3.14.0-0.local.macOS.arm64/ALL_IN_ONE/GrandOrgue.app/Contents/MacOS/GrandOrgueTool: replacing existing signature
/Users/grandorgue/Documents/GitHub/GrandOrgueBuild/build/osx/_CPack_Packages/macOS/DragNDrop/grandorgue-3.14.0-0.local.macOS.arm64/ALL_IN_ONE/GrandOrgue.app: replacing existing signature
Checking code signature...
/Users/grandorgue/Documents/GitHub/GrandOrgueBuild/build/osx/_CPack_Packages/macOS/DragNDrop/grandorgue-3.14.0-0.local.macOS.arm64/ALL_IN_ONE/GrandOrgue.app: invalid signature (code or signature have been modified)
In subcomponent: /Users/grandorgue/Documents/GitHub/GrandOrgueBuild/build/osx/_CPack_Packages/macOS/DragNDrop/grandorgue-3.14.0-0.local.macOS.arm64/ALL_IN_ONE/GrandOrgue.app/Contents/Frameworks/libwx_baseu-3.2.0.2.2.dylib
In architecture: arm64
CPack: Create package
install_name_tool
can find the libs but codesign
can't.
Any idea how to fix this?
Have you tred to use the --deep
switch with codesign for signing all files in all subdirectories?
Have you tred to use the --deep switch with codesign for signing all files in all subdirectories?
--deep
shouldn't be used.
from man codesign
:
--deep (DEPRECATED for signing as of macOS 13.0)
Official documentation: Avoid deep code signing
If it could be used then the problem is still the same, codesign
must run after the app is completely built.
I tried the build by @MStraeten and I get
Maybe it's because I already have an ad-hoc signed GrandOrgue.
Maybe it's because I already have an ad-hoc signed GrandOrgue.
I think because ad-hoc signed applications cannot run on another computers.
Signing the app on the .dmg now works and the GitHub build works on my Mac. It behaves like an unsigned app:
And Open from the context menu:
If anyone wants to try (at your own risk):
Apple Silicon: https://github.com/willeke1234/grandorgue/actions/runs/8403203222/attempts/2
Intel: https://github.com/willeke1234/grandorgue/actions/runs/8403203222
Scroll to the bottom
I didn't test the Intel one.
Maybe it's because I already have an ad-hoc signed GrandOrgue.
It’s because it’s within a zip file and was downloaded from somewhere in the internet.
Signing the dmg gives a further level of trust. That’s the best you can get without an apple developer id
As far as I know, the .dmg is not signed.
I tested on a new virtual Mac with the same result.
The intel version works on this virtual Mac with Rosetta.
I was able to create a universal code-signed app using my apple cert.
For some reason the app gets bundled with a bunch of symlinks in Contents/Frameworks, so I will move those temporarily:
mkdir links
for frame in GrandOrgue.app/Contents/Frameworks/* ; do
echo $frame
if [ -L $frame ] ; then
mv $frame links
fi
done
Join the architectures together with lipo
:
# Create Universal App (the other arch. app is on the Desktop)
for lib in GrandOrgue.app/Contents/Frameworks/* ; do
lipo -create -output $(basename $lib) ~/Desktop/GrandOrgue.app/Contents/Frameworks/$(basename $lib) GrandOrgue.app/Contents/Frameworks/$(basename $lib)
echo $lib
done
mv *dylib GrandOrgue.app/Contents/Frameworks
for bins in GrandOrgue.app/Contents/MacOS/* ; do
lipo -create -output $(basename $bins) ~/Desktop/GrandOrgue.app/Contents/MacOS/$(basename $bins) GrandOrgue.app/Contents/MacOS/$(basename $bins)
echo $bins
done
mv GrandOrgue *PerfTest *Tool GrandOrgue.app/Contents/MacOS
mv links/* GrandOrgue.app/Contents/Frameworks
Codesign recursively without --deep
:
# Codesign the app
echo "Codesigning Application."
for frame in GrandOrgue.app/Contents/Frameworks/* ; do
echo $frame
codesign --preserve-metadata=identifier --force --timestamp --strict -v -s "${CODESIGNID}" -i com.our-organ.GrandOrgue $frame
done
for resource in GrandOrgue.app/Contents/Resources/* ; do
echo $resource
if [ ! -d $resource ]; then
codesign --preserve-metadata=identifier --force --timestamp --strict -v -s "${CODESIGNID}" -i com.our-organ.GrandOrgue $resource
else
for subresource in GrandOrgue.app/Contents/Resources/$(basename $resource)/* ; do
if [ ! -d $subresource ]; then
codesign --preserve-metadata=identifier --force --timestamp --strict -v -s "${CODESIGNID}" -i com.our-organ.GrandOrgue $subresource
fi
done
fi
done
for macOS in GrandOrgue.app/Contents/MacOS/* ; do
echo $macOS
codesign --preserve-metadata=identifier --force --timestamp --strict -v -s "${CODESIGNID}" -i com.our-organ.GrandOrgue $macOS
done
codesign --preserve-metadata=identifier --force --timestamp --strict -v -s "${CODESIGNID}" -i com.our-organ.GrandOrgue GrandOrgue.app
spctl -a -vvvv GrandOrgue.app
Built a dmg with create-dmg/create-dmg:
mkdir GrandOrgue
mv GrandOrgue.app GrandOrgue
create-dmg --app-drop-link 50 50 --eula ../LICENSE grandorgue3.14.0.dmg GrandOrgue
Signed it also:
sudo codesign --preserve-metadata=identifier --force --timestamp --strict -v -s $CODESIGNID -i com.our-organ.GrandOrgue grandorgue3.14.0.dmg
Universal app runs on Intel (macOS 12.7+) and Apple Silicon (macOS 13.3+)
If you would like to test this build, it is available in my shared folder: https://r42.us/go
- FWIW, program runs fine on arm64 but I didn't have enough RAM to load the big organs, so I went to build it on intel also.
How do we proceed:
- Who is going to build the macOS GrandOrgue app?
- Who is going to sign the macOS GrandOrgue app and how?
- Who is going to distribute the macOS GrandOrgue app?
- One universal app or an Intel app and an Apple Silicon app?
- Which macOS's are supported?
Also you may wish for the app to support hardening for notarization. As it is now the libraries load relative to @executable_path.