Ошибка цифровой подписи приложения Mac за пределами Xcode

Я разрабатываю приложение для Mac с Qt5, поэтому вне Xcode. Я хочу, чтобы GateKeeper разрешил моему приложению запускаться на компьютерах клиентов, а не выдавать сообщение "Невозможно открыть, потому что предупреждение о неспособности разработчика не может быть подтверждено".

Я успешно подписал приложение с цифровой подписью, но GateKeeper по-прежнему приходит с этой жалобой. У меня есть сертификат разработчика Apple (я агент команды), и моя цепочка ключей говорит, что она действительна. Я также установил два корневых сертификата Apple.

Я использую утилиту командной строки codesign для цифровой подписи всех двоичных файлов внутри папки приложения и, кроме того, я сам подписываю папку приложения непосредственно. Во всех случаях реакция кодазначна и не содержит ошибок. С кодовым кодом я могу проверить, действительно ли все двоичные файлы подписаны, работает

$ codesign --verify --deep --verbose=2 MyApp.app

показывает, что все двоичные файлы проверяются. И кроме того, он сообщает:

MyApp.app: действует на диске
MyApp.app: удовлетворяет его назначенное требование

Продолжительность:

$ codesign -v --verbose=4 --display MyApp.app   

дает

Исполняемый файл =/Пользователи/xxx/trunk/yyy/deploy/release/MyApp.app/Содержание/MacOS/MyApp
Идентификатор = aaaa.MyApp
Формат = пакет с Mach-O тонким (x86_64)
CodeDirectory v = 20200 size = 12461 flags = 0x0 (none) хэши = 616 + 3 location = embedded
Тип хэша = размер sha1 = 20
CDHash = d1c12c783dac0e8d9a2b749fb896b11558cec8b6
Размер подписи = 8532
Полномочия = Идентификатор разработчика: XXXXX
Полномочия = Центр сертификации идентификатора удостоверения личности
Полномочия = Apple Root CA
Временная метка = 29 jul. 2015 12; 04: 40
Записи Info.plist = 8
TeamIdentifier = YYYYY
Версия Sealed Resources = 2 правила = 12 файлов = 10
Внутренние требования count = 1 размер = 180

который кажется ОК.

Выполнение

$ spctl -a -t exec -vv MyApp.app

для всех двоичных файлов дает результат

MyApp.app: принят
source = ID разработчика
origin = Идентификатор разработчика Приложение: XXXX

который также выглядит ОК

Запуск контрольной подписи инструмента командной строки XCode  в приложении или в двоичных файлах внутри папки приложения:

$ ./check-signature /Users/xxx/trunk/yyy/release/MyApp.app

дает результат

(c) 2014 Apple Inc. Все права защищены.
ДА

который во всех случаях является искомым результатом.

Но GateKeeper по-прежнему не принимает приложение и жалуется на то, что разработчик не может быть подтвержден.

[добавлено автором в пятницу 17 июля 2015 г.]

Думаю, я нашел проблему. Я не знаю, является ли это функцией или ошибкой OSX. Мне многое помогло stackoverflow вопрос 19551298.

Всякий раз, когда файл загружается из Интернета, он получает связанный с ним расширенный атрибут файла com.apple.quarantine. При двойном щелчке по этому загруженному файлу в Finder, GateKeeper имеет две возможности:

  • Когда файл не подписан, он выдает сообщение "Неизвестный разработчик и т.д."

  • Когда файл имеет цифровую подпись, он выдает сообщение "Разработчик не может быть подтвержден и т.д."

В обоих случаях MessageBox имеет только одну кнопку, кнопку OK. Когда эта кнопка нажата, ничего не происходит, кроме закрытия MessageBox.

Если расширенный атрибут удален (xattr -d), приложения запускаются, подписываются или нет.

Поведение отличается от того, когда приложения запускаются щелчком правой кнопки мыши в Finder в приложении, а затем нажмите "Открыть" действие меню. Снова появляется один из двух сообщений, но теперь добавлена ​​дополнительная кнопка, позволяющая пользователю открывать приложение в любом случае. Опять же, разница между подписанными и не подписанными - это сообщение "Неизвестно" или "Не подтверждено". Я не ожидаю, что мои клиенты смогут рассказать о различиях. В результате подписание приложения является бесполезным упражнением.

На основе Документация поддержки Apple Я ожидал другого, гораздо более приятного поведения GateKeeper при двойном щелчке загруженного приложения (возможно, документации устарел или я его неправильно понял):

  • Если приложение подписано, GateKeeper должен показать MessageBox с "Загруженным из Интернета и т.д." и кнопкой "Продолжить?"

  • если приложение не подписало MessageBox с одной кнопкой OK и текстом "Неизвестный разработчик и т.д."

Ответы

Ответ 1

Извините за ответ на мой собственный вопрос, но я не вижу другого способа, поскольку редактирование исходного вопроса приведет к тексту спагетти.

Я, наконец, решил свою проблему. Сначала кредит: (i) Ответ на мой другой stackoverflow question был очень полезен и (ii) я получил очень хороший (оплаченный) совет от официального разработчика Apple, путем подачи так называемого инцидента технической поддержки (TSI).

На основе всего этого я теперь могу привести здесь очень краткий рецепт того, как получить приложение Mac успешно обработано GateKeeper. После подробного описания рецепта я покажу, какова была моя первоначальная ошибка.

Цель: после разработки приложения Mac вне Xcode, чтобы GateKeeper выдавал предупреждение "Загружено из Интернета..." тремя кнопками, один из которых "открыт".

Отказ: когда GateKeeper выдает предупреждение с текстом ".. unidentified developer.." или текст ".. неподтвержденный разработчик.." с - в обоих случаях - сообщение с одной кнопкой OK.

Получение вашего приложения готовым к использованию GateKeeper включает в себя три шага:

  • Сделайте свое приложение автономным без каких-либо неприемлемых внешних зависимостей. Единственными приемлемыми внешними зависимостями являются системные библиотеки. Все другие зависимости должны быть скопированы в вашу папку MyApp.app. GateKeeper отклоняет любое приложение, которое имеет несистемные внешние зависимости.
  • Запрещается размещать двоичные файлы на незаконных позициях внутри папки MyApp.app. Библиотеки входят в MyApp/Contents/Framework, и исполняемый файл переходит в MyApp/Contents/MacOS
  • Все двоичные файлы внутри MyApp должны иметь цифровую подпись. Затем должна быть подписана папка MyApp.app. Для этого подписания необходим сертификат Apple Developer Application Application...

Наш рецепт автоматический. Все работы выполняются одним script. В случае Qt Creator мы используем qmake script, где мы получаем доступ к системной оболочке с помощью команды $$system. При использовании любой из системных команд (Xcode) codesign, spctl или check-signature предполагается, что вы перенаправили stderr на stdout, как указано в answer на вопрос. В противном случае вы не сможете поймать системный ответ при запуске этих утилит. Ниже мы не будем явно показывать это перенаправление.

ЗДЕСЬ НАШ РЕЦЕПТ

а. Создание автономного приложения:

  • скопируйте (с помощью script) все необходимые двоичные файлы в папку MyApp.folder
  • запустите (с script) install_name_tool -change и install_name_tool -id таким образом, чтобы все зависимости внутри приложения относились к типу @executable_path/../MacOS.. или @executable_path/../Frameworks
  • запустите (с script) otool -L во всех двоичных файлах внутри папки MyApp.app и отметьте любую незаконную зависимость, такую ​​как "@rpath..." или абсолютные пути к файлу, не являющиеся системными путями. Обратите внимание, что otool -L не гарантируется найти все зависимости. Плагины часто выходят за горизонт otool. Вот почему вам нужна следующая проверка.
  • запустите терминал в папке "MyApp.app/Contents/MacOS". Запустите export DYLD_PRINT_LIBRARIES=1. Затем запустите внутри одного окна терминала ./MyApp. Ваш терминал будет заполнен более ста загруженными библиотеками. Повторите этот список для запрещенных библиотек (библиотеки присутствуют на вашем компьютере, но не на компьютере ваших клиентов).
  • доказательство пудинга в еде. Мы используем виртуальные машины MacInCloud и проверяем, работает ли там наше приложение. Альтернативным решением может быть Mac родственника, который не является разработчиком. Или вы также можете создать нового пользователя ( "тест" ) на своем Mac и скопировать приложение в папку "Загрузить" (или "Рабочий стол" или...). В последнем случае вы должны временно переименовать корневую папку вашей среды IDE, так как иначе пользовательский "тест" найдет там отсутствующие двоичные файлы.

B Подписывание приложения

  1. Подписание: с помощью нашего script мы запускаем codesign --force --verify --verbose --sign \"Developer ID Application: ....\" \"/path/to/binary\" во всех двоичных файлах приложения, а затем в самой папке приложения. В каждом случае происходит отладка системы. Он должен содержать в каждом случае строку "подписанный Mach-O thin".
  2. Проверка: Запустите (с помощью команды script) codesign --verify --verbose \"/path/to/binary\" в каждом бинарном приложении и в самом приложении и поймите системный ответ. Он должен в каждом случае содержать строки, "действующие на диске" и "удовлетворяет его назначенным требованиям".
  3. Проверка GateKeeper: запустите (с script) spctl -a -t exec -vv /path/to/binary\" в каждом двоичном файле и в самой папке приложения. Системный отклик пойман. Он должен содержать во всех случаях строку "принятый источник".
  4. check-signature: Запустите (с script) check-signature \"/path/to/banary\" в каждом двоичном файле и в самой папке приложения. Системный отклик пойман. Он должен содержать строку "ДА" в каждом случае.

C Внешняя проверка

  1. Запишите свое приложение в один ZIP файл. Загрузка на один из ваших облачных серверов

  2. GateKeepers хранит длинный список (обычно сотни элементов) исключений из своей общей роли gate-keeper. Ваше приложение не должно быть в этом списке, если вы хотите проверить GateKeeper. Вместо редактирования этого списка гораздо более простой трюк - это создание нового пользователя на вашем Mac. Войдите в систему этого пользователя и загрузите zip файл с интернет-сервера облаков. Finder автоматически распакует его. Нажмите здесь. Если GateKeeper сообщает вам, что он может открыть приложение, но он одновременно предупреждает вас, что он загружен из Интернета, пришло время захватить (белое) пиво.

Здесь требуется предупреждение GateKeeper: введите описание изображения здесь

Моя ошибка

Я сделал большую часть установки и подписания без явной проверки результата для каждого двоичного файла. После этого я использовал бы otool -L для нескольких двоичных файлов, но не для всех. Я пропустил тот факт, что при обновлении до Qt 5.5 из более ранней версии Qt двоичный libqminimal.dylib приобрел дополнительную зависимость, а именно: QtDBus. Я этого не заметил, но GateKeeper сделал.

Разработчики Qt могут задаться вопросом, почему мы не просто используем macdeployqt для развертывания приложения Qt на Mac. В первую очередь нам не нравится не использовать плохо документированные утилиты "черного ящика". На интернет-форумах существует довольно много людей, которые сообщают о проблемах с macdeployqt. Кроме того, при сравнении разных версий Qt библиотеки Qt могут иметь разные места установки (как сообщается otool-L). Когда у нас будет новая версия Qt, наш script сразу начнет кричать о запрещенных зависимостях. Таким образом мы получаем информацию о том, что изменилось в этой новой версии.

Ответ 2

adlag вопрос и самостоятельный ответ были неоценимы, помогая мне преодолеть одну и ту же проблему. Однако, как и его рецепт, некоторые утверждения не совсем правильные, поэтому я хотел бы предложить несколько дополнительных пунктов.

  • Не нужно заменять записи @rpath в ваших двоичных файлах и динамических библиотеках с помощью операторов @executable_path. Операторы @rpath хороши, пока фактические записи rpath, встроенные в двоичные файлы, не являются абсолютными. Вы можете найти множество действительных наборов приложений Qt, которые используют rpath. Вы можете заставить его работать над тем, что сказал adlag, но вы можете делать работу самостоятельно.
  • См. комментарий jil выше о том, как использовать otool -l $file | grep -A2 LC_RPATH и install_name_tool -delete_rpath $path $file для проверки и удаления внедренных путей в ваших двоичных файлах и библиотеках.
  • См. https://developer.apple.com/library/content/technotes/tn2206/_index.html#//apple_ref/doc/uid/DTS40007919-CH1-TNTAG207 для четкого объяснения того, почему GateKeeper жалуется на пути в ваших двоичных файлах и как вы можете увидеть конкретную жалобу в системный журнал.
  • Если у вас есть проблема с абсолютными путями, сначала попробуйте исправить вашу сборку, а не использовать install_name_tool после факта.
  • Если вы используете cmake, это, вероятно, полезно: https://cmake.org/Wiki/CMake_RPATH_handling#Mac_OS_X_and_the_RPATH
  • Не запускайте spctl -a -t exec -vv /path/to/binary в файлах dylib. Вы получите ошибки о конверте ресурсов. Ожидается, что это не проблема.
  • По моему опыту, macdeployqt работает нормально. Я решил проблему, изменив мою сборку, так что абсолютные пути не попали в файл dylib для нарушителя (libquazip). Я все еще использовал install_name_tool, чтобы удалить абсолютные пути к установке Qt. Затем я использовал macdeployqt для создания пакета, подписи пакета и создания файла DMG.

Ответ 3

Выяснил проблему после множества попыток.

В моем случае: Поврежденное приложение Pop Message появилось из-за отсутствия библиотек. Я создал файл .app с помощью QT. Для генерации dmg я использовался инструмент команды deploymacqt. Инструмент deploymacqt создает динамические библиотеки внутри .app, поэтому в основном, если мы координируем перед созданием dmg, этот alter будет манипулировать знаком кода. Итак, правильное исправление.

# Create dmg using 
    deploymacqt <yourapp.app> -dmg

# Open resulted dmg file, copy <yourapp.app> to different folder(let say /Documents/<yourapp.app>)

# Codesign the /Documents/<yourapp.app> using 
    codesign --deep --force --verify --verbose --sign "Developer ID Application: <developerid>" <yourapp.app>

# Verify using
    codesign --verify --verbose=4 <yourapp.app>
 * you should see something like this
    <yourapp.app>: valid on disk
    <yourapp.app>: satisfies its Designated Requirement

# Now create again the dmg file using dropdmg(https://c-command.com/dropdmg/) application, download, install dropdmg. set the cofiguration preferences with your developer id certificate in signing option.

# drag and drop <yourapp.app> to dropdmg app, wait for creation of dmg to complete. voila you have now successfully created dmg with proper developer id certification.

# verify resulted dmg again using   
     codesign --verify --verbose=4 <yourapp.dmg>
# you can also verify with gatekeeper
     spctl -a -t exec -vv <yourapp.dmg>

После того, как вы закончите с этим, вы не увидите сообщение pop, говорящее, что приложение повреждено или сломано или неизвестно разработчику.

Ответ 4

Мои два бита:

  • Чтобы действительно проверить кодовое кодирование, мне пришлось либо загрузить мой DMG на сервера и загрузите его с помощью браузера или установите атрибут карантина вручную:

    APP_PATH="Any.app"
    xattr -w com.apple.quarantine '0081;5a37dc6a;Google Chrome;F15F7E1C-F894-4B7D-91B4-E110D11C4858' "$APP_PATH"
    xattr -l "$APP_PATH" # You should see the quarantine attribute here
    open "$APP_PATH"
    

    Если ваше приложение правильно подписано, вы увидите системный диалог с кнопка "Открыть".

    Я нашел значение атрибута карантина, посмотрев на другое .app скачан из Интернета. Я не знаю, что значение означает.

    Я действительно не понимаю, почему команда spctl говорит "принято" даже если служба Gatekeeper отказывает в открытии приложения.

  • У меня появилось окно сообщения "Неизвестный разработчик", потому что мои рамки Qt были указаны как " @rpath/QtCore.framework". Меняя его на " @application_path/../Frameworks/QtCore.framework" с помощью install_name_tool, исправлена ​​проблема в моем приложении.