Nominate our 2022 Qt Champions!

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:

    QT       += core gui
    greaterThan(QT_MAJOR_VERSION, 4): QT += widgets
    TARGET = TestCodesign
    TEMPLATE = app
    SOURCES += main.cpp


    #include <QApplication>
    #include <QtWidgets/QMessageBox>
    int main(int argc, char *argv[])
      QApplication a(argc, argv);
      QMessageBox w(QMessageBox::Information, "Hello", "Hello world!");;
      return a.exec();

    Here is my minimal build script:

    # Minimal test:  this script goes in the same directory as the application code files ( 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`
    # Establish our build tool environment
    # Build the app in the "release-build" subdir
    rm -rf "$MYDIR/release-build"
    mkdir -p "$MYDIR/release-build"
    pushd "$MYDIR/release-build"
    make -j2 -w
    # 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/" "$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/"
    defaults write "$MYDIR/pkg-root/Applications/" CFBundleName 'TestCodesign'
    defaults write "$MYDIR/pkg-root/Applications/" 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/" "$MYDIR/pkg-root/Applications/"
    # repeat signing until the exit value is true (i.e. no crash)
    until codesign --deep --force --verify --verbose --sign "$MYID" "$MYDIR/pkg-root/Applications/"; do
      echo Failure. Trying again...
      rm -rf "$MYDIR/pkg-root/Applications/"
      cp -R "$MYDIR/pkg-root/Applications/" "$MYDIR/pkg-root/Applications/"
    # Delete the backup .app
    rm -rf "$MYDIR/pkg-root/Applications/"
    # Verify the bundle's signature
    codesign --verify --verbose=4 --deep "$MYDIR/pkg-root/Applications/"
    # 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"
          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 "" of container window to {100, 90}
          set position of item "" of container window to {100, 90}
          set position of item " " of container window to {400, 160}
          set position of item " " of container window to {400, 160}
          update without registering applications
          delay 5
        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 ..

    1. Do you have a valid developer certificate from apple? Are you up to date on your payments to apple for it?

    2. Check out it has a lot of info on signing applications.

    3. 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.

    1. 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.

    1. Check out 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.

    1. 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 using codesign --verify and spctl, 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!

  • @davidb AFAIK it's possible to sign any application, including Qt ones. If nobody else comes along with a solution I can run some tests and see if I can get one working with sierra.

  • 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.

  • Lifetime Qt Champion

    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.)

  • Lifetime Qt Champion

    @WJWJ thanks for the additional trick !

Log in to reply