Build and codesign on MacOS Sierra 10.12, but "the identity of the developer cannot be confirmed."
-
Codesigning my app appears to work correctly, but Sierra 10.12.3 doesn't like it on first run after download. My original question involving building and codesigning on Yosemite is here, but I'm posting this as a different question since in an effort to make Sierra happy, now I'm building on Sierra with Xcode 8.2.1.
I have created a minimal example to illustrate the issue. Here is my minimal application:
test_codesign.pro:QT += core gui greaterThan(QT_MAJOR_VERSION, 4): QT += widgets TARGET = TestCodesign TEMPLATE = app SOURCES += main.cpp
main.cpp:
#include <QApplication> #include <QtWidgets/QMessageBox> int main(int argc, char *argv[]) { QApplication a(argc, argv); QMessageBox w(QMessageBox::Information, "Hello", "Hello world!"); w.show(); return a.exec(); }
Here is my minimal build script:
#!/bin/sh # Minimal test: this script goes in the same directory as the application code files (test_codesign.pro and main.cpp). # Before executing this script, set two variables: # export QTDIR=/path/to/qtbase # export MYID="[id to codesign with]" pushd `dirname "${0%}"` MYDIR=`pwd -P` popd # Establish our build tool environment QMAKE=$QTDIR/bin/qmake SDKBARE=MacOSX10.12 QMAKEARGS="-r CONFIG+=release DEFINES+=QMAKE_MAC_SDK=$SDKBARE" # Build the app in the "release-build" subdir rm -rf "$MYDIR/release-build" mkdir -p "$MYDIR/release-build" pushd "$MYDIR/release-build" $QMAKE "$MYDIR/test_codesign.pro" -r CONFIG+=release DEFINES+=QMAKE_MAC_SDK=$SDKBARE make -j2 -w popd # Create the disk image folder. "pkg-root" is our working folder to assemble everything. The final product goes in "out". rm -rf "$MYDIR/pkg-root" rm -rf "$MYDIR/out" mkdir -p "$MYDIR/pkg-root/Applications" # Copy the application bundle cp -afv "$MYDIR/release-build/TestCodesign.app" "$MYDIR/pkg-root/Applications/" # Run the Qt Mac deploy tool, which resolves the linkage of the Qt frameworks "$QTDIR/bin/macdeployqt" "$MYDIR/pkg-root/Applications/TestCodesign.app" defaults write "$MYDIR/pkg-root/Applications/TestCodesign.app/Contents/Info" CFBundleName 'TestCodesign' defaults write "$MYDIR/pkg-root/Applications/TestCodesign.app/Contents/Info" CFBundleIdentifier 'com.fmosoft.TestCodesign' find ./pkg-root -name '*.DS_Store' -depth -type f -delete # Add a symbolic link to the Applications folder to the disk image. # Use a space as the destination name, because I haven't found a way to localize "Applications" in the dmg. # Apparently using a space is a common solution to this problem from what I found in a couple of google searches. ln -s /Applications "$MYDIR/pkg-root/Applications/ " # Create a clean backup of the .app cp -R "$MYDIR/pkg-root/Applications/TestCodesign.app" "$MYDIR/pkg-root/Applications/TestCodesignUnsigned.app" # repeat signing TestCodesign.app until the exit value is true (i.e. no crash) until codesign --deep --force --verify --verbose --sign "$MYID" "$MYDIR/pkg-root/Applications/TestCodesign.app"; do echo Failure. Trying again... rm -rf "$MYDIR/pkg-root/Applications/TestCodesign.app" cp -R "$MYDIR/pkg-root/Applications/TestCodesignUnsigned.app" "$MYDIR/pkg-root/Applications/TestCodesign.app" done # Delete the backup .app rm -rf "$MYDIR/pkg-root/Applications/TestCodesignUnsigned.app" # Verify the bundle's signature codesign --verify --verbose=4 --deep "$MYDIR/pkg-root/Applications/TestCodesign.app" # Create our disk image mkdir -p "$MYDIR/out" hdiutil create -srcfolder "$MYDIR/pkg-root/Applications" -fs HFS+ -fsargs "-c c=64,a=16,e=16" -format UDRW -volname TestCodesign -ov -attach "$MYDIR/out/TestCodesign.uncompressed.dmg" echo done first dmg echo ' tell application "Finder" tell disk "TestCodesign" open set current view of container window to icon view set toolbar visible of container window to false set statusbar visible of container window to false set the bounds of container window to {100, 100, 600, 450} set theViewOptions to the icon view options of container window set arrangement of theViewOptions to not arranged set icon size of theViewOptions to 96 set position of item "TestCodesign.app" of container window to {100, 90} set position of item "TestCodesign.app" of container window to {100, 90} close open set position of item " " of container window to {400, 160} set position of item " " of container window to {400, 160} close open update without registering applications delay 5 eject end tell end tell ' | osascript #sleep 10 hdiutil convert "$MYDIR/out/TestCodesign.uncompressed.dmg" -format UDZO -o "$MYDIR/out/test_codesign.dmg" # code sign the final .dmg, and verify the signature codesign --verify --verbose --sign "$MYID" "$MYDIR/out/test_codesign.dmg" spctl -a -t open --context context:primary-signature -v "$MYDIR/out/test_codesign.dmg" # remove the uncompressed .dmg rm "$MYDIR/out/TestCodesign.uncompressed.dmg" # We are done! The file to distribute is $MYDIR/out/test_codesign.dmg
EDIT: removed stray $X variable from script.
The script runs fine, and the codesign tests in the script report that everything looks good.
But, when I upload test_codesign.dmg to Dropbox and then download it (on the same Sierra 10.12.3 computer), double-click the downloaded .dmg, drag the app to /Applications, then double-click the app in /Applications: I get the message that the identity of the developer cannot be confirmed.
Any idea what I need to do to my application/.dmg so Sierra's Gatekeeper will be happy?
-
@davidb Hi! Few questions ..
-
Do you have a valid developer certificate from apple? Are you up to date on your payments to apple for it?
-
Check out https://developer.apple.com/library/content/technotes/tn2206/_index.html it has a lot of info on signing applications.
-
Why do you enter a code signing loop until "it doesn't crash"? If that is necessary you may have found your problem right there, lol.
-
-
@ambershark : good questions, I probably should have mentioned the answers in the original post.
- Do you have a valid developer certificate from apple? Are you up to date on your payments to apple for it?
Yes, as far as I can tell. The certificate doesn't expire until December 12, 2017, according to what Keychain Access shows me. We had let our Apple Developer Program membership lapse, but that was renewed a few days ago. It is my understanding that current membership in Apple's Developer Program is not required anyway, as long as the certificate is still valid. Building and signing on Yosemite (10.10.3) works fine, if I run on Yosemite - even before renewing our membership. But of course I can't insist my users run Yosemite, hence my question.
- Check out https://developer.apple.com/library/content/technotes/tn2206/_index.html it has a lot of info on signing applications.
Thanks, I have been studying that document, as well as this one. Since nothing I tried met with success, I created the minimal example, hoping someone could point out a problem or perhaps test it and suggest what works for them.
- Why do you enter a code signing loop until "it doesn't crash"? If that is necessary you may have found your problem right there, lol.
Perhaps that loop is no longer necessary, but it doesn't seem to me that leaving the loop in place should cause a problem. There used to be a concurrency issue in Apple's code somewhere that required this workaround. We found this workaround to be necessary when building/signing on 10.10.3. See this SO question and this Apple forum question. For the record, in all my tests I've NOT noticed this loop to be necessary on Sierra - the script has not executed the
echo Failure. Trying again...
command, so it seems likely that Apple fixed the issue sometime after 10.10.3.The only thing I'm doing that I see is not recommended is that I'm using
--deep
to sign the bundle. Here's the relevant quote from the Apple technote you mention:Important: While the
--deep
option can be applied to a signing operation, this is not recommended. We recommend that you sign code inside out in individual stages (as Xcode does automatically). Signing with --deep is for emergency repairs and temporary adjustments only.I'm not sure what "signing code inside out in individual stages" looks like for my minimal example. I understand it is something like starting at the most deeply nested files that require signing, and signing each one individually, and moving back toward the root of the bundle. But I don't understand exactly what order that means for Frameworks, main app, dylibs, etc. If that's really required, I'd think someone would have a bash script code sample that loops through and signs everything in the correct order, but I've not found anything like that.
In any case, Apple's warning about signing with
--deep
implies that--deep
should work, since you can use it for emergency repairs and temporary adjustments. And when I run Apple's recommended checks usingcodesign --verify
andspctl
, they pass. So I'm not sure--deep
is the issue at all.I'm hoping someone who knows more than I do about this stuff can steer me in the right direction. If
--deep
is the issue, then what files should be signed in my minimal example, and in what order should they be signed? -
@davidb Well it sounds like your covered all the stuff I would have thought was going wrong.
The biggest thing is it works with yosemite but not with sierra. Maybe focus on the gatekeeper changes in sierra.
I haven't done a signed application in sierra so I haven't experienced this problem before. I'll let someone else with more experience here come in the thread and help if they can. If not I can maybe do a quick signed app later on to test and see if it happens to me too.
-
@ambershark thanks - at this point I'm wondering if it's even possible for a Qt-based app to make Sierra's Gatekeeper happy. If anyone has done it, I'd sure appreciate knowing that, and of course knowing how they did it would be really great, too!
-
Not sure how I missed this, but here's what has solved the issue:
After building the app, use
otool -l
on each Qt framework in the app and look for LC_RPATH to somewhere outside the bundle. For example:otool -l path/to/app/Contents/Frameworks/QtConcurrent.framework/Versions/5/QtConcurrent
Then in the build script, for each framework with an LC_RPATH outside the bundle, add this command to remove it:
install_name_tool -delete_rpath [the rpath] "path/to/app/Contents/Frameworks/QtConcurrent.framework/Versions/5/QtConcurrent"
That worked for me. I also codesign the .dmg, not sure if that makes a difference for Gatekeeper.
-
Glad you found out and thanks for sharing !
Can you post the original paths you had that were triggering the bug ?
-
@davidb In our case we had to remove the rpath "@loader_path/../../../../lib" from the Assistant-executable, which pointed outside our app. We added the Qt-Assistant in our app, in the MacOs-map. (we also had to add the rpath "@loader_path/../Frameworks" in the Assistant-executable to get that work correctly.)