内核扩展公证指南(附脚本)

1,680 阅读8分钟

背景

image-20201112094329457 苹果对于Mac OSX10.15及以上的内核扩展必须要公证才能允许加载,不过内核扩展也快要废弃了,已经被系统扩展给替代,这个是后话了。还有很多MacOS应用毅然使用着内核扩展,并且低版本系统不受影响。因此,针对Mac OSX10.15的内核扩展公证迫在眉睫。

内核扩展公证

官网在Mac App Store外分发应用公证指南中,官网也给出了相应的可通过脚本控制的自定义公证流程。但对于内核扩展是否也实用与该流程,并未明确说明,不过在苹果开发者论坛中,苹果公证团队人员给出了答复,具体如下:

The question about how to notarise an installer package (.pkg) containing a KEXT has come up on a number of threads [1] over the past few weeks.  Unfortunately my answers have been less than clear, so I sat down with the notarisation team to fix that.
The fundamental question here is the order in which you notarise things.  Do you:
1. Sign the KEXT, wrap the KEXT in a signed installer package, then notarise the package, then staple the ticket to the package (option A).
2. Sign the KEXT, then notarise it, then staple the ticket to the KEXT, then wrap the KEXT in a signed installer package, then notarise the package, then staple the ticket to the package (option B).

通过回复可确定内核扩展是可以单独公证的。

具体公证的摸索实践流程: 前置条件:

  1. xcode10及以上
  2. 内核扩展已使用Develop ID签名,且开启了timestampHardened Runtime
  3. 可访问苹果服务器的网络环境

签名

具体签名可使用codesign工具

codesign --timestamp -f -s "Developer ID Application: xxxx (xxxxx)" xxx.kext

其中需要添加--timestamp开启时间戳。

验证内核扩展是否已签名且开启timestamp

sudo codesign -vvd xxxx.kext

获取结果中包含Timestamp字段且存在date,或者Signed Time不包含date,如下:

Executable=/Users/fengyunsky/Desktop/notarize/xxxx.kext/Contents/MacOS/xxxx
Identifier=xxxx
Format=bundle with generic
CodeDirectory v=20200 size=214 flags=0x0(none) hashes=1+3 location=embedded
Signature size=8998
Authority=Developer ID Application:xxx(xxxx)
Authority=Developer ID Certification Authority
Authority=Apple Root CA
Timestamp=xxxxx  //包含该字段
Info.plist entries=10
TeamIdentifier=xxxx
Sealed Resources version=2 rules=13 files=0
Internal requirements count=1 size=184

开启Harden Runtime

可使用codesign --option runtime来开启,具体的Hardened Runtime介绍可见Hardened Runtime

归档内核文件

公证上传不支持.app 内核扩展,因为本身为文件夹,需要压缩文件,具体为

# Create a ZIP archive suitable for altool.
/usr/bin/ditto -c -k --keepParent xxxxx.kext xxxxx.kext.zip

上传内核压缩文件到公证服务

可以通过xcrun altool命令并指定--notarize-app选项:

xcrun altool --notarize-app
               --primary-bundle-id "com.example.ote.zip"
               --username "AC_USERNAME"
               --password "@keychain:AC_PASSWORD"
               --asc-provider <ProviderShortname>
               --file

其中

  • primary-bundle-id指定标识符,以帮助您跟踪来自公证服务的自动通信。您提供的值不需要与提交的应用程序的捆绑包标识符匹配,也不必具有任何特定值。它只需要对您有意义。每当公证服务通过电子邮件向您发送有关给定altool提交的信息时,便会包含该值;
  • username为关联到开发者账号中的appleid账号;
  • passworkd为appleid的应用专属密码(若直接提供明文密码,则直接为密码,可关联keychain来避免暴露密码明文,具体见官网教程),具体如何开启见使用应用专用密码
  • asc-provider为关联的appleid账号的提供者简称,如果appleid账号关联了多个团队,可通过altool工具中的list-providers选项来获取(目前只支持xcode11及以上)

xcrun altool --list-providers --username "xxx(username)" --password "xxx"

具体命令如下:

xcrun altool --notarize-app --primary-bundle-id "xxx" --username "xxxx" --password "xxxxx" --asc-provider "xxxxx" --file xxx

得到的结果如下:

ProviderName                                      ProviderShortname                 WWDRTeamID
------------------------------------------------- --------------------------------- ----------
xxxx Networks (Shenzhen) Co.,Ltd. - xxx xxxx                        xxxx
xxxx Technologies Company Limited              xxxxTechnologiesCompanyLimited xxxx

其中使用ProviderShortname名称即可,即"xxxxTechnologiesCompanyLimited"

如果公证成功,则altool输出请求标识符:

2019-11-08 21:01:53.689 altool[22159:5299986] No errors uploading 'xxxx.kext.zip'.
RequestUUID = 77d717d7-ec86-4d24-9bad-edfe58b2a9f2

其中RequestUUID可用于获取请求信息,见下文

查看请求状态

上载您的应用程序后,公证过程通常需要不到一个小时的时间。该过程完成后,您会收到一封电子邮件,指出结果。此外,您可以使用altoolnotarization-history标志来检查所有公证请求的状态:

xcrun altool --notarization-history 0 --username "xxxx" --password "xxxx" --asc-provider "xxxxTechnologiesCompanyLimited"

此处若账号关联了多个团队,需要指定 --asc-provider

Notarization History - page 0

Date                      RequestUUID                          Status      Status Code Status Message
------------------------- ------------------------------------ ----------- ----------- ----------------
2019-11-08 13:01:54 +0000 77d717d7-ec86-4d24-9bad-edfe58b2a9f2 success     0           Package Approved
2019-11-08 09:42:30 +0000 0f798eb9-e172-413e-8115-5034351bf072 success     0           Package Approved
2019-05-15 08:10:14 +0000 c67e58fc-16c4-4320-911b-50476813b94c invalid
2019-05-15 07:57:44 +0000 cf14f23a-b6f4-4617-8274-1f086efaae19 in progress

若成功,则状态statussuccess,其他可能为in progress正在处理中,需要等待一段时间,Invalid为失败。

也可以通过上文中的RequestUUID指定特定的提交详细信息:

xcrun altool --notarization-info 0f798eb9-e172-413e-8115-5034351bf072 -u "xxxx" -p "xxxx"

在其他详细信息中,该工具报告了一个日志文件URL,可用于下载JSON格式的日志文件:

xcrun altool --notarization-info 0f798eb9-e172-413e-8115-5034351bf072 -u "xxxx" -p "xxxx"
2019-11-08 17:50:21.544 altool[20136:5241851] No errors getting notarization info.

   RequestUUID: 0f798eb9-e172-413e-8115-5034351bf072
          Date: 2019-11-08 09:42:30 +0000
        Status: success
    LogFileURL: https://osxapps-ssl.itunes.apple.com/itunes-assets/Enigma123/v4/d5/e5/3c/d5e53c62-adc7-b5e2-5f6b-fe8123f68a5a/developer_log.json?accessKey=1573401021_7752465551566842091_%2BXIivRbX9%2FGWmjU37YSzrBC7sQsSwz0h%2FAlL%2Fb2STQnqpre%2BCbrnCFUiPb%2BlC46uZYvv2szz%2FV63dBucI4cuaaXC%2BhrvZL0UXr52NevwAzvwzQ0HQRYhgfm%2FBudIDpTCXXsirVsS3Uw07tOxxxxx //已屏蔽路径
   Status Code: 0
Status Message: Package Approved

其中存在LogFileURL字段用于获取请求结果,包括公证出现的问题:

{
  "logFormatVersion": 1,
  "jobId": "0f798eb9-e172-413e-8115-5034351bf072",
  "status": "Accepted",
  "statusSummary": "Ready for distribution",
  "statusCode": 0,
  "archiveFilename": "xxxxx.kext.zip",
  "uploadDate": "2019-11-08T09:42:30Z",
  "sha256": "ace3d935a99681fc285589963470e479373c67ec2d8f3b89576a92dc2fc63603",
  "ticketContents": [
    {
      "path": "xxx.kext.zip/xxxx.kext",
      "digestAlgorithm": "SHA-256",
      "cdhash": "389a646d27a9ef7b4c872f4f7a752be555f82ac9",
      "arch": null
    },
    {
      "path": "xxx.kext.zip/xxx.kext/Contents/MacOS/xxxx",
      "digestAlgorithm": "SHA-256",
      "cdhash": "389a646d27a9ef7b4c872f4f7a752be555f82ac9",
      "arch": null
    }
  ],
  "issues": null
}

上述为成功的结果。

注意:即使公证成功,也要始终检查日志文件,因为该日志文件可能包含警告,您可以在下一次提交之前进行修复。

装订

装订是公证过程的最后一步,该过程允许经公证的应用程序在macOS上运行,而无需检入Apple服务器。

一旦对应用程序进行了公证,Apple便为开发人员提供了“票证”,可以将其“装订”到经过公证的对象上。如果未装订应用程序或kext ,则在加载应用程序/ kext时,macOS会使用Apple服务器签入,以查看是否可以正常运行,这需要Internet连接。

具体可通过stapler工具来装订:

sudo xcrun stapler staple xxxx.kext

Processing: /Users/fengyunsky/Desktop/notarize/xxxx.kext
Processing: /Users/fengyunsky/Desktop/notarize/xxx.kext
The staple and validate action worked!

成功则显示“The staple and validate action worked!” 可通过stapler validate验证有效性:

sudo xcrun stapler validate xxxxx.kext

Processing: /Users/fengyunsky/Desktop/notarize/xxxx.kext
The validate action worked!

成功则显示"The validate action worked!",查看详细信息可使用:

sudo xcrun stapler validate -q -v xxxx.kext

验证

验证公证结果:

spctl -a -vv -t install xxx.kext
image-20201112094329457

成功的如下:

image-20201112094408443

注意source字段为Notarized Developer ID

测试加载的前提条件为:

  1. 启用Gatekeeper并选择“”appstore和被认可的开发者"

sudo spctl --master-enable //来开启Gatekeeper

  1. 启用SIP(系统完整性保护) 具体可参见macOS 开启或关闭 SIP

具体加载内核扩展命令如下:

sudo kextload -t xxxx.kext

具体查看错误信息:

sudo kextutil -t xxxxxx.kext

脚本路径:github.com/FengyunSky/…

友情感谢

解决常见的公证问题

Mac App Store外分发应用公证指南

自定义公证流程

分发前对应用程序进行公证

公证包含KEXT的安装程序包

macOS app 实现自动化 notarize 脚本

应用公证:快速入门

Apple-Mac-Notarized-script--公证开源脚本

Using app-specific passwords-官方专属密码设定

Mac开发-公证流程记录Notarizaiton-附带脚本

How to bypass Mojave 10.14.5’s new kext security