Как правильно добавить подпись и нотариальное заверение MacOS в .app, созданный с помощью Qt - PullRequest
0 голосов
/ 27 мая 2020

У меня есть приложение (созданное с помощью Qt / QML), которое я пытаюсь подписать и нотариально заверить для распространения c Ad ho за пределами App Store (для внутреннего использования компанией). Apple подтверждает, что мое программное обеспечение было нотариально заверенным, и затем я сшиваю свой .app, но Gatekeeper по-прежнему останавливает запуск приложения и предупреждает пользователей:

Имя приложения не может быть открыт, потому что Apple не может проверить его на наличие вредоносного ПО.

Что я делаю не так? .

Вот шаги, которые я выполняю:

  1. Запуск QMake / Build в Qt Creator.

  2. Изменен ключ CFBundleIdentifier в сгенерированном файле Info.plist на com. myCompanyName . appName вместо com.yourcompany. appName сгенерировано Qt.

  3. cd в мою директорию сборки.

  4. Ran macdeployqt:
    /Users/<user>/Qt/5.13.0/clang_64/bin/macdeployqt <appName>.app -qmldir=<project source code dir>.

  5. Знак кода:
    codesign --deep -f -s "Developer ID Application: <company name> (<team id>)" --options "runtime" "<appName>.app/"
    (где идентификатор разработчика имя, как оно отображается в KeychainAccess).

  6. Подтверждено, что подпись:
    codesign -dv --verbose=4 <appName>.app
    Возвращает:

    * 105 6 *

    Или, если я посмотрю на (выбранный наугад) исполняемый файл из фреймворка Qt внутри пакета приложений:
    codesign -dv --verbose=4 <appName>.app/Contents/Frameworks/QtCore.framework/Versions/5/QtCore
    Возвращает:

    Executable=<build dir>/<app name>.app/Contents/Frameworks/QtCore.framework/Versions/5/QtCore
    Identifier=org.qt-project.QtCore
    Format=bundle with Mach-O thin (x86_64)
    CodeDirectory v=20500 size=49057 flags=0x10000(runtime) hashes=1526+3 location=embedded
    VersionPlatform=1
    VersionMin=658432
    VersionSDK=658944
    Hash type=sha256 size=32
    CandidateCDHash sha256=*************************************
    CandidateCDHashFull sha256=*************************************
    Hash choices=sha256
    CMSDigest=*************************************
    CMSDigestType=2
    Page size=4096
    CDHash=*************************************
    Signature size=8990
    Authority=Developer ID Application: <my company name> (<my team ID>)
    Authority=Developer ID Certification Authority
    Authority=Apple Root CA
    Timestamp=May 27, 2020 at 2:35:37 PM
    Info.plist entries=8
    TeamIdentifier=V7L2LD4Q9S
    Runtime Version=10.14.0
    Sealed Resources version=2 rules=13 files=1
    Internal requirements count=1 size=184
    
  7. zip: ditto -ck --rsrc --sequesterRsrc "<appName>.app" "<appName>.zip"

  8. Загрузить для нотариального заверения:
    xcrun altool --notarize-app -t osx -f <appName>.zip --primary-bundle-id="com.<my company name>.<appName>" -u "<develpper ID @ company name> -p "<app specific password>"

  9. Получить электронное письмо что «Ваше программное обеспечение Ma c было успешно нотариально заверено».

  10. Скрепка: xcrun stapler staple "<appName>.app"
    Возвращает: The staple and validate action worked!

  11. Распространить:

    1. Создать пустой образ диска с разреженным пакетом.
    2. Скопируйте в него пакет appName .app (вместе с ярлыком в /Applications).
    3. Конвертировать только для чтения.
    4. Распространить среди пользователей.


Если я посмотрю в Console. app - я вижу в журналах, что приложение не открывается:
default 15:10:56.549137-0400    runningboardd   Invalidating assertion 294-139-3156 (target:executable<<appName>(501)>) from originator 139
default 15:11:01.061942-0400    runningboardd   [executable<<appName>(501)>:4893] Death sentinel fired!

В консоли ничего нет с XprotectService as this SO ответ предполагает.


Если я попытаюсь использовать spctl для проверки подписи, это не удастся:

spctl -v -a -t open --context context:primary-signature <appName>.app
Возврат:

opal.app: rejected
source=Unnotarized Developer ID

spctl -a -t exec -vv <appName>.app produces
Возврат:

<appName>.app: rejected
source=Unnotarized Developer ID
origin=Developer ID Application: <my company name> (<team ID>)
produces: invalid API object reference


Однако, если я использую степлер для проверки приложения, он проходит:
stapler validate <appName>.app
Возвращает:
Processing: /<build dir>/<appName>.app
The validate action worked!


О моей среде:

MacOS 10.15.3
Qt 5.13
Xcode 11.4

1 Ответ

0 голосов
/ 29 мая 2020

Проблема в том, что, поскольку вы распространяете с использованием .dmg, вам также необходимо нотариально заверить .dmg. Пожалуйста, выполните следующие действия:

1) Добавьте нотариально заверенное и скрепленное приложение в .dmg.

2) Заверьте свой файл .dmg.

3) Прикрепите нотариальное заверение к файл .dmg.

Вы можете использовать следующий сценарий bash, который я создал, который позволяет вам создать запрос нотариального заверения, проверить статус запроса нотариального заверения и скрепить нотариальное заверение:

#!/bin/bash

usage()
{
    # Display Help

   echo "*********************************************************************************************************************************************************"
   echo "  MacOS Application Notarization Script"
   echo "*********************************************************************************************************************************************************"
   echo
   echo "   Requirements"
   echo "    - XCode Installed"
   echo "    - Apple Id Account app-specific Password (https://support.apple.com/en-us/HT204397)"
   echo "    - Apple Developer ID Application Certificate created and installed in keychain (https://developer.apple.com/support/developer-id/)"
   echo
   echo "   Instructions"
   echo "    1. Run notarize option to code sign application and create notarization request"
   echo "    2. Run check option with the request UUID of the previous step to check the notarization status"
   echo "    3. Run staple option only if the notarization status was successful and package was approved"
   echo "    4. You are now ready to distribute, if you want to create an installer you can use this option https://github.com/sindresorhus/create-dmg."
   echo "       Note that if you distribute your app in a .dmg, follow these steps:"
   echo
   echo "      - Add your notarized and stapled app to the DMG."
   echo "      - Notarize your .dmg file."
   echo "             Example: sh $0 --notarize -a MyApp.dmg  -b com.company.myapp  -u myappleaccount@gmail.com -p aaaa-aaaa-aaaa-aaa -v FFFFFFFF)"
   echo "      - Staple the notarization to the .dmg file: xcrun stapler staple MyApp.dmg."
   echo "             Example: sh $0 --staple --file MyApp.dmg"
   echo "________________________________________________________________________________________________________________________________________________________"
   echo
   echo "  Usage"
   echo "   $0 [-n|s|c] [ -a APP_NAME ] [ -i SIGNING_IDENTITY ] [ -e ENTITLEMENTS ]  [ -b BUNDLE_ID ] [ -u USERNAME ] [ -p PASSWORD ] [ -v PROVIDER ] [ -k UUID ]"
   echo
   echo "________________________________________________________________________________________________________________________________________________________"
   echo
   echo "  Options:"
   echo
   notarizeHelp
   checkHelp
   stapleHelp

  return
}
notarizeHelp()
{
   echo "    ======================================================================="
   echo "    -n | --notarize  Notarize file"
   echo "    ======================================================================="
   echo "    Syntax:"
   echo "              [ -n | --notarize ] [ -a | --file APP_NAME ] [ -i SIGNING_IDENTITY ] [ -e ENTITLEMENTS ]  [ -b BUNDLE_ID ] [ -u USERNAME ] [ -p PASSWORD ] [ -v PROVIDER ]"
   echo "    Parameters:"
   echo "              [ -a | --file  ]        - File name"
   echo "              [ -i ]                  - Apple Signing identity"
   echo "              [ -e ]                  - Application entitlements file"
   echo "              [ -b ]                  - Application Bundle identifier"
   echo "              [ -u ]                  - Apple Developer ID Username"
   echo "              [ -p ]                  - Application Specific password"
   echo "              [ -v ]                  - Access Provider"
   echo "    Example:"
   echo "       .app   sh $0 --notarize -a MyApp.app  -b com.company.myapp  -u myappleaccount@gmail.com -p aaaa-aaaa-aaaa-aaa -v FFFFFFFF -e App.entitlements -i \"Developer ID Application: COMPANY\""
   echo "       .zip   sh $0 --notarize -a MyApp.app.zip  -b com.company.myapp  -u myappleaccount@gmail.com -p aaaa-aaaa-aaaa-aaa -v FFFFFFFF"
   echo "       .dmg   sh $0 --notarize -a MyApp.dmg  -b com.company.myapp  -u myappleaccount@gmail.com -p aaaa-aaaa-aaaa-aaa -v FFFFFFFF"
   echo
}
checkHelp()
{
   echo "    ======================================================================="
   echo "    -c | --check     Check notarization status"
   echo "    ======================================================================="
   echo "    Syntax:"
   echo "              [ -c | --check ] [ -u USERNAME ] [ -p PASSWORD ] [ -k UUID ]"
   echo "    Parameters:"
   echo "              [ -u ]                  - Apple Developer ID Username"
   echo "              [ -p ]                  - Application Specific password"
   echo "              [ -k ]                  - Notarization Request UUID"
   echo "    Example:"
   echo "              sh $0 --check  -u myappleaccount@gmail.com -p aaaa-aaaa-aaaa-aaa -k ffff-ffffff-ffffff-ffffffffff"
   echo
}
stapleHelp()
{
   echo "    ======================================================================="
   echo "    -s | --staple    Staple file"
   echo "    ======================================================================="
   echo "    Syntax:"
   echo "              [ -s | --staple ] [ -a | --file APP_NAME ]"
   echo "    Parameters:"
   echo "              [ -a | --file  ]        - File name"
   echo "    Example:"
   echo "              sh $0 --staple --file MyApp.app"
   echo
}

#Help Dictionary 
helpFunction()
{

   echo ""
   usage
   exit 1 
}

# Transform long options to short ones
for arg in "$@"; do
  shift
  case "$arg" in
    "--notarize") set -- "$@" "-n" ;;
    "--staple")   set -- "$@" "-s" ;;
    "--check")    set -- "$@" "-c" ;;
    "--file")     set -- "$@" "-a" ;;
    *)            set -- "$@" "$arg"
  esac
done


while getopts "nsca:i:e:b:v:u:k:p:" option
do
case "${option}"
in
n) ACTION=NOTARIZE;;
s) ACTION=STAPLE;;
c) ACTION=CHECK;;
a) APP_NAME=${OPTARG};;
i) SIGNING_IDENTITY=${OPTARG};;
e) ENTITLEMENTS=${OPTARG};;
b) BUNDLE_ID=${OPTARG};;
p) PASSWORD=${OPTARG};;
v) PROVIDER=${OPTARG};;
u) USERNAME=${OPTARG};;
k) UUID=${OPTARG};;
?) helpFunction ;;
esac
done


do_check()
{
    echo "$UUID"
    if [ -z "${UUID}" ]; then
        echo "[Error] Didn't specify notarization request UUID";
    fi

    if [ -z "${USERNAME}" ]; then
        echo "[Error] Apple ID username is required";
    fi

    if [ -z "${PASSWORD}" ]; then
        echo "[Error] App Specific password is required";
    fi

    if [ -z "${UUID}" ] || [ -z "${USERNAME}" ] || [ -z "${PASSWORD}" ]; then
        echo
        checkHelp
        exit 1 
    fi
    echo "[INFO] Checking Notarization status for $UUID"
    xcrun altool --notarization-info "$UUID" -u "$USERNAME" -p "$PASSWORD" --output-format xml

    exit 1
}



sign()
{
    if [ -z "${APP_NAME}" ]; then
        echo "[Error] Didn't specify a filename";
    fi
    if [ -z "${SIGNING_IDENTITY}" ]; then
        echo "[Error] Didn't specify signing identity";
    fi
    if [ -z "${ENTITLEMENTS}" ]; then
        echo "[Error] Didn't specify entitlements file";
    fi
    if [ -z "${BUNDLE_ID}" ]; then
        echo "[Error] Didn't specify bundle identifier";
    fi
    if [ -z "${PROVIDER}" ]; then
        echo "[Error] Didn't specify access provider";
    fi
    if [ -z "${USERNAME}" ]; then
        echo "[Error] Apple ID username is required";
    fi
    if [ -z "${PASSWORD}" ]; then
        echo "[Error] App Specific password is required";
    fi

    if  [ -z "${APP_NAME}" ] || [ -z "${USERNAME}" ] || [ -z "${PASSWORD}" ] || [ -z "${PROVIDER}" ]  || [ -z "${ENTITLEMENTS}" ] || [ -z "${SIGNING_IDENTITY}" ]; then
        echo
        notarizeHelp
        exit 1 
    fi

    echo "[INFO] Signing app contents"
    find "$APP_NAME/Contents"|while read fname; do
        if [[ -f $fname ]]; then
            echo "[INFO] Signing $fname"
            codesign --force --timestamp --options=runtime --entitlements "$ENTITLEMENTS" --sign "$SIGNING_IDENTITY" $fname
        fi
    done

    echo "[INFO] Signing app file"


    codesign --force --timestamp --options=runtime --entitlements "$ENTITLEMENTS" --sign "$SIGNING_IDENTITY" "$APP_NAME"

    echo "[INFO] Verifying Code Sign"

    codesign --verify --verbose "$APP_NAME"

    echo "[INFO] Zipping $APP_NAME to ${APP_NAME}.zip"

    ditto -c -k --rsrc --keepParent "$APP_NAME" "${APP_NAME}.zip"

    #echo "[INFO] Uploading $APP_NAME for notarization"

    #xcrun altool --notarize-app -t osx -f "${APP_NAME}.zip" --primary-bundle-id "$BUNDLE_ID" -u "$USERNAME" -p "$PASSWORD" --asc-provider "$PROVIDER"  --output-format xml

    notarizationUpload "${APP_NAME}.zip"
}

notarize()
{

    if [ -z "${APP_NAME}" ]; then
        echo "[Error] Didn't specify a filename";
    fi
    if [ -z "${BUNDLE_ID}" ]; then
        echo "[Error] Didn't specify bundle identifier";
    fi
    if [ -z "${PROVIDER}" ]; then
        echo "[Error] Didn't specify access provider";
    fi
    if [ -z "${USERNAME}" ]; then
        echo "[Error] Apple ID username is required";
    fi
    if [ -z "${PASSWORD}" ]; then
        echo "[Error] App Specific password is required";
    fi

    if  [ -z "${APP_NAME}" ] || [ -z "${USERNAME}" ] || [ -z "${BUNDLE_ID}" ] || [ -z "${PASSWORD}" ] || [ -z "${PROVIDER}" ]; then
        echo
        notarizeHelp
        exit 1 
    fi


case "$APP_NAME" in
    *.app)  sign;;
    *.zip)  notarizationUpload "$APP_NAME";;
    *.dmg)  notarizationUpload "$APP_NAME";;
esac


}

notarizationUpload()
{
    echo "[INFO] Uploading $APP_NAME for notarization"
    xcrun altool --notarize-app -t osx -f "$1" --primary-bundle-id "$BUNDLE_ID" -u "$USERNAME" -p "$PASSWORD" --asc-provider "$PROVIDER"  --output-format xml

}

do_staple()
{

    if [ -z "${APP_NAME}" ]; then
        echo "[Error] Didn't specify a filename";
        echo
        stapleHelp
        exit 1 
    fi

    echo "[INFO] Stapling $APP_NAME"
    xcrun stapler staple "$APP_NAME"
    echo "[INFO] Validating Staple for $APP_NAME"
    xcrun stapler validate "$APP_NAME"
}



#Excute Action base on the option  -s -n -c
case $ACTION in
STAPLE) do_staple;;
CHECK) do_check;;
NOTARIZE) notarize;;
*) helpFunction;
esac



unset APP_NAME ACTION SIGNING_IDENTITY BUNDLE_ID ENTITLEMENTS USERNAME PASSWORD PROVIDER UUID
...