无法在Xcode外部以数字方式签署Mac应用程序

问题描述 投票:15回答:5

我开发了一个带有Qt5的Mac应用,所以在Xcode之外。我希望GateKeeper允许我的应用程序在客户端的计算机上运行,​​而不是发出“无法打开,因为无法确认开发人员的身份”警告。

我已成功对该应用程序进行了数字签名,但GateKeeper仍然附带此投诉。我有一个Apple开发人员证书(我是团队代理),我的钥匙串说它是有效的。我还安装了两个Apple根证书。

我使用命令行实用程序codesign对app文件夹中的所有二进制文件进行数字签名,此外我还对app文件夹本身进行了数字签名。在所有情况下,协同设计的响应都是信息性的,并且没有显示错误。使用codesign我可以检查确实所有二进制文件都已签名,正在运行

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

显示所有二进制文件都已验证。此外,它报告:

MyApp.app:在磁盘上有效 MyApp.app:满足其指定要求

运行:

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

可执行= /用户/ XXX /中继/ YYY /部署/释放/ MyApp.app /内容/ MacOS的/ MyApp的 标识符= aaaa.MyApp 格式=与Mach-O薄的捆绑(x86_64) CodeDirectory v = 20200 size = 12461 flags = 0x0(none)hashes = 616 + 3 location = embedded 哈希类型= sha1大小= 20 CDHash = d1c12c783dac0e8d9a2b749fb896b11558cec8b6 签名尺寸= 8532 Authority =开发者ID应用程序:XXXXX Authority =开发者ID证书颁发机构 Authority = Apple Root CA. 时间戳= 29岁。 2015 12; 04:40 Info.plist条目= 8 TeamIdentifier = YYYYY 密封资源版本= 2规则= 12个文件= 10 内部要求计数= 1大小= 180

这似乎没问题。

运行

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

在所有二进制文件上给出结果

MyApp.app:接受了 source =开发者ID origin =开发者ID申请:XXXX

这也似乎没问题

在应用程序或app文件夹内的二进制文件上运行XCode命令行工具检查签名:

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

给出结果

(c)2014 Apple Inc.保留所有权利。 是

在所有情况下都是理想的结果。

但GateKeeper仍然不接受该应用程序,并抱怨开发人员无法确认。

[作者于2015年7月17日星期五]添加]

我想我已经找到了问题。我不知道它是一个功能还是一个OSX错误。 stackoverflow question 19551298给了我很多帮助。

每当从互联网上下载文件时,它都会获得与之关联的扩展文件属性com.apple.quarantine。在Finder中双击此下载的文件时,GateKeeper有两种可能:

  1. 当文件未签名时,它会发出“Unidentified developer etc”消息
  2. 当文件经过数字签名时,它会发出“Developer not be determined etc”消息

在这两种情况下,MessageBox只有一个按钮,一个OK按钮。单击此按钮时,除了MessageBox关闭之外没有任何反应。

如果删除了扩展属性(xattr -d),则应用程序运行,签名或不签名。

通过在应用程序上的Finder中单击鼠标右键然后单击“打开”菜单操作启动应用程序时,行为会有所不同。再次显示了两个消息框中的一个,但现在有一个额外的按钮,允许用户打开应用程序。签名和未签名之间的唯一区别是“未识别”或“未确认”消息。我不希望我的客户能够分辨出差异。因此签署该应用程序是徒劳的。

Apple Support Documentation的基础上,我预计当双击下载的应用程序时GateKeeper的另一个更好的行为(可能是文档已过时,或者我误读了它):

  1. 如果应用程序已签名,GateKeeper应显示一个MessageBox,其中包含“从Internet上下载等”和一个“仍然继续进行”的按钮?
  2. 如果应用程序没有使用单个“确定”按钮和“未识别的开发人员等”文本对MessageBox进行签名。
xcode macos cocoa code-signing osx-gatekeeper
5个回答
16
投票

很抱歉回答我自己的问题,但我没有别的办法,因为编辑原始问题会导致意大利面条文字。

我终于解决了我的问题。首先是信用:(i)我的其他stackoverflow question的答案非常有用,(ii)我通过提交所谓的技术支持事件(TSI)得到了Apple官方开发人员的非常好(付费)的建议。

基于这一切,我现在能够在这里给出一个非常简洁的方法,说明如何通过GateKeeper成功处理您的Mac应用程序。详细说明食谱后,我将展示我原来的错误。

目标:在Xcode之外开发了一个Mac应用程序,让GateKeeper发出警告“从互联网下载...”,有三个按钮,其中一个是“打开”。

失败:当GateKeeper发出警告时,文本“.. unidentified developer ..”或文本“..未经证实的开发人员......” - 在两种情况下 - 带有一个OK按钮的消息框。

获取应用程序GateKeeper就绪包括三个步骤:

  • 使您的应用程序独立,没有不可接受的外部依赖性。唯一可接受的外部依赖是系统库。应将所有其他依赖项复制到MyApp.app文件夹。 GateKeeper拒绝任何具有非系统外部依赖性的应用程序
  • 二进制文件不应位于MyApp.app文件夹内的非法位置。库进入MyApp / Contents / Frameworks,可执行文件进入MyApp / Contents / MacOS
  • MyApp中的所有二进制文件都应进行数字签名。然后应签署MyApp.app文件夹。对于此签名,Apple“Developer ID Application ...”证书是必需的

我们的食谱是自动的。所有工作都由一个脚本完成。在Qt Creator的情况下,我们使用qmake脚本,我们通过$$system命令访问系统shell。当使用(Xcode)系统命令codesignspctlcheck-signature中的任何一个时,我们假设您已将stderr重定向到stdout,如answer to question中所述。否则,在运行这些实用程序时,您将无法捕获系统响应。在下文中,我们不会明确显示此重定向。

这是我们的食谱

A.使应用程序独立:

  1. 将所有需要的二进制文件(带脚本)复制到MyApp.folder
  2. 运行(使用脚本)qazxsw poi和qazxsw poi,以便app中的所有依赖项都是相对类型install_name_tool -changeinstall_name_tool -id
  3. 在MyApp.app文件夹中的所有二进制文件上运行(使用脚本)@executable_path/../MacOS..并标记任何非法依赖,例如“@rpath ...”或绝对文件路径不是系统路径。请注意,@executable_path/../Frameworks无法保证找到所有依赖项。插件往往超出otool -L的视野。这就是你需要下一次检查的原因。
  4. 在“MyApp.app/Contents/MacOS”位置启动终端。运行otool -L。然后在同一终端窗口otool内运行。您的终端将填满数百个已加载的库。再次检查此列表是否有禁止的库(计算机上存在的库,但客户的计算机上没有)。
  5. 布丁的证据就在吃。我们使用export DYLD_PRINT_LIBRARIES=1并检查我们的应用程序是否在那里运行。替代解决方案可能是不是开发人员的亲属的Mac。或者您也可以在自己的Mac上创建新用户(“测试”)并将应用程序复制到其下载(或桌面文件夹,或...)。在后一种情况下,您必须临时重命名IDE的根文件夹,否则用户“test”将在那里找到丢失的二进制文件。

B签署应用程序

  1. 签名:使用我们的脚本,我们在应用程序中的所有二进制文件上运行./MyApp,然后在app文件夹本身上运行。在每种情况下都会捕获系统响应。它应该在每种情况下都包含字符串“signed Mach-O thin”。
  2. 验证:在应用程序中的每个二进制文件和应用程序本身上运行(使用脚本)命令MacInCloud virtual machines并捕获系统响应。它应该在每种情况下包含字符串“在磁盘上有效”和“满足其指定要求”。
  3. GateKeeper检查:在每个二进制文件和app文件夹本身上运行(使用脚本)codesign --force --verify --verbose --sign \"Developer ID Application: ....\" \"/path/to/binary\"。捕获系统响应。它应该在所有情况下都包含字符串“accepted source”。
  4. check-signature:在每个二进制文件和app文件夹本身上运行(使用脚本)codesign --verify --verbose \"/path/to/binary\"。捕获系统响应。在每种情况下,它应包含字符串“YES”。

C外部检查

  1. 将您的应用压缩到一个zip文件中。上传到您的某个云服务器
  2. GateKeepers在其一般的守门员角色上保留了一长串的例外(通常是数百项)。如果要测试GateKeeper,您的应用必须不在该列表中。而不是编辑此列表更简单的技巧是在Mac上创建新用户。登录该用户并从Internet云服务器下载zip文件。 Finder会自动解压缩它。点击它。如果GateKeeper告诉您它可以打开应用程序,但它会在从Internet下载的同时向您发出警告,那么现在是时候抓一个(白色)啤酒了。

这里是所需的GateKeeper警告:spctl -a -t exec -vv /path/to/binary\"

我的错

我做了大量的安装和签名,没有明确检查每个二进制文件的结果。之后我会在一些二进制文件上使用check-signature \"/path/to/banary\"但不是全部。我错过了从早期的Qt版本升级到Qt 5.5的事实,二进制enter image description here获得了额外的依赖,即:otool -L。我没有注意到它,但GateKeeper做到了。

Qt开发人员可能想知道为什么我们不只是使用libqminimal.dylib在Mac上部署Qt应用程序。首先,我们不喜欢不使用记录不良的黑盒实用程序。在互联网论坛上,有很多人报道QtDBus的问题。此外,在比较不同的Qt版本时,Qt库可以具有不同的安装位置(由macdeployqt报告)。当我们有一个新的Qt版本时,我们的脚本将立即开始对禁止的依赖关系大喊大叫。通过这种方式,我们可以获得有关此新版本中已更改内容的信息。


1
投票

adlag的问题和自我回答对于帮助我克服同样的问题非常宝贵。然而,和他的食谱一样好,有些陈述不太正确,所以我想提供一些额外的观点。

  • 没有必要用@executable_path语句替换二进制文件和动态库中的@rpath条目。只要嵌入在二进制文件中的实际rpath条目不是绝对的,@rpath语句就可以了。您可以找到许多使用rpath的有效Qt应用程序包。你可以按照adlag的说法开展工作,但你可能正在为自己工作。
  • 请参阅上面的jil评论,了解如何使用macdeployqtotool-L检查和删除二进制文件和库中的嵌入路径
  • 请参阅otool -l $file | grep -A2 LC_RPATH,以清楚解释为什么GateKeeper会抱怨二进制文件中的路径,以及如何在syslog中查看特定的投诉。
  • 如果你有绝对路径问题,你应该首先尝试修复你的构建,而不是在事后使用install_name_tool -delete_rpath $path $file
  • 如果你正在使用cmake,这可能会有所帮助:https://developer.apple.com/library/content/technotes/tn2206/_index.html#//apple_ref/doc/uid/DTS40007919-CH1-TNTAG207
  • 不要在dylib文件上运行install_name_tool。您将收到有关资源信封的错误。这是预期的,而不是问题。
  • 根据我的经验,https://cmake.org/Wiki/CMake_RPATH_handling#Mac_OS_X_and_the_RPATH工作正常。我通过更改构建来解决问题,这样绝对路径没有进入有问题的dylib文件(libquazip)。我仍然使用spctl -a -t exec -vv /path/to/binary删除Qt安装的绝对路径。然后我使用macdeployqt创建捆绑包,签署捆绑包并创建DMG文件。

1
投票

我的两位:

  1. 要真正验证代码签名,我必须将我的DMG上传到服务器并使用浏览器下载或手动设置隔离属性: install_name_tool 如果您的应用程序已正确签名,您应该会看到一个带有“打开”按钮的系统对话框。 我通过查看从互联网上下载的另一个.app找到了隔离属性的值。我不知道这个价值意味着什么。 我真的不明白为什么spctl命令说“已接受”,即使Gatekeeper服务拒绝打开应用程序。
  2. 我有“未识别的开发人员”消息框,因为我的Qt框架被引用为“@ rpath / QtCore.framework”。使用install_name_tool将其更改为“@application_path /../ Frameworks / QtCore.framework”修复了我的应用中的问题。

0
投票

经过多次尝试后想出了问题。

在我的情况下:Pop消息 - 损坏的应用程序是由于库缺失。我使用QT创建了.app文件。要生成dmg,我使用的是deploymacqt命令工具。 deploymacqt工具在.app中创建动态库,所以基本上如果我们在创建dmg之前进行协同编码,这个alter会操纵代码符号。所以正确的解决方法是。

macdeployqt

once you are done with these, you will not see pop message saying app is damaged or broken or unidentified developer.


0
投票

您需要使用可执行文件的命令行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" 和您的Frameworks验证所有rpath。如果你的可执行文件中有一个本地rpath(例如:/ user / name / Qt /),则将其删除(使用此命令# Create dmg using deploymacqt <yourapp.app> -dmg # Open resulted dmg file, copy <yourapp.app> to different folder(let's 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> )。

© www.soinside.com 2019 - 2024. All rights reserved.