公証がThe binary uses an SDK older than the 10.9 SDK.で失敗したときは、バイナリのビルドバージョンをvtoolで確認する。vtool -show-buildで、バイナリのデプロイメントターゲット(minos)とビルドに使ったSDK(sdk)が表示される。
$ xcrun vtool -show-build [バイナリ名]
ビルドし直せないバイナリでは、vtool -set-build-versionでSDKのバージョンを書き換えて、署名し直せば公証が通る。
実行例はXcode 27.0、macOS 27.0.1のもの。
ビルドバージョンを確認する (-show-build)
vtool -show-buildは、Mach-OバイナリのLC_BUILD_VERSIONを表示する。
$ xcrun vtool -show-build [バイナリ名]
[バイナリ名]:
Load command 10
cmd LC_BUILD_VERSION
cmdsize 32
platform MACOS
minos 27.0
sdk 27.0
ntools 1
tool LD
version 27037.1
主な項目は次のとおりである。
| 項目 | 内容 |
|---|---|
platform | 対象のプラットフォーム。MACOSなど |
minos | 動作する最小のOSバージョン(デプロイメントターゲット) |
sdk | ビルドに使ったSDKのバージョン |
tool | バイナリを作ったツールとバージョン。LDはリンカー |
Intel MacとApple siliconの両方に対応したユニバーサルバイナリでは、アーキテクチャごとに表示される。
$ xcrun vtool -show-build [ユニバーサルバイナリ名]
[ユニバーサルバイナリ名] (architecture x86_64):
Load command 10
cmd LC_BUILD_VERSION
cmdsize 32
platform MACOS
minos 27.0
sdk 27.0
ntools 1
tool LD
version 27037.1
[ユニバーサルバイナリ名] (architecture arm64):
Load command 10
cmd LC_BUILD_VERSION
cmdsize 32
platform MACOS
minos 27.0
sdk 27.0
ntools 1
tool LD
version 27037.1
-archでアーキテクチャを絞り込める。
$ xcrun vtool -arch arm64 -show-build [ユニバーサルバイナリ名]
Mach-Oではないファイルを指定すると、エラーメッセージが表示されて終了コードが1になる。
$ xcrun vtool -show-build /etc/hosts
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/vtool error: /etc/hosts file is not mach-o
$ echo $?
1
-showを指定すると、ビルドバージョン以外のロードコマンドも表示される。
公証で「SDKが古い」と言われる
公証に提出したバイナリのSDKが10.9より古いと、公証がInvalidになる。notarytool logで取得したログのissuesには、次のメッセージが記録される。
{
"status": "Invalid",
"statusSummary": "Archive contains critical validation errors",
"statusCode": 4000,
"archiveFilename": "[バイナリ名].zip",
"ticketContents": null,
"issues": [
{
"severity": "error",
"code": null,
"path": "[バイナリ名].zip/[ディレクトリ名]/[バイナリ名]",
"message": "The binary uses an SDK older than the 10.9 SDK.",
"docUrl": "https://developer.apple.com/documentation/security/notarizing_macos_software_before_distribution/resolving_common_notarization_issues#3087723",
"architecture": "arm64"
}
]
}
参考: 【notarytool】公証に失敗した理由をログから調べる
Appleのドキュメントによると、macOS 10.9より前はコード署名の仕組みが大きく異なるため、公証は10.9以降のSDKでリンクされたバイナリにだけ対応する。新しいSDKでビルドしても、以前のmacOSとの互換性には影響しない。互換性はデプロイメントターゲットで決まる。
参考: 公証に関するよくある問題の解決
minosとsdkのどちらが判定に使われるか
minosとsdkの組み合わせを変えたバイナリを、Developer IDで署名して公証に提出した結果は次のとおりである。
| minos | sdk | 公証の結果 |
|---|---|---|
| 27.0 | 27.0 | Accepted |
| 10.8 | 27.0 | Accepted |
| 27.0 | 10.8 | Invalid |
| 10.8 | 10.8 | Invalid |
minosが10.8でも、sdkが新しければ公証が通る。sdkが10.8であれば、minosによらず失敗する。判定に使われるのはsdkである。
SDKが古いバイナリに対処する
新しいSDKでビルドし直す
自分でビルドしたバイナリであれば、新しいXcodeでビルドし直す。古いmacOSもサポートする場合は、デプロイメントターゲットで下限を指定する。
vtoolでSDKを書き換える
サードパーティのバイナリなどビルドし直せない場合は、vtool -set-build-versionでSDKのバージョンを書き換える。引数は[プラットフォーム] [minos] [sdk]の順である。出力先は-outputで指定する。
$ xcrun vtool -set-build-version macos 10.8 10.9 -output [出力先のバイナリ名] [入力のバイナリ名]
$ xcrun vtool -show-build [出力先のバイナリ名] | grep -E "minos|sdk"
minos 10.8
sdk 10.9
SDKは10.9を指定すれば公証が通る。sdkが10.9のバイナリは、Developer IDで署名して提出するとAcceptedになる。
Developer IDなどで署名済みのバイナリをvtoolで書き換えると、署名が無効になる。vtoolは書き換え時に警告を表示する。
$ xcrun vtool -set-build-version macos 10.8 10.8 -output [出力先のバイナリ名] [署名済みのバイナリ名]
.../vtool warning: code signature will be invalid for [出力先のバイナリ名]
$ codesign -v [出力先のバイナリ名]
[出力先のバイナリ名]: invalid signature (code or signature have been modified)
In architecture: arm64
署名が無効になったバイナリは、実行すると強制終了される。終了コードは137(128にSIGKILLのシグナル番号9を足した値)である。
$ ./[出力先のバイナリ名]
$ echo $?
137
書き換えた後は、codesignで署名し直す。公証に提出するには、Hardened Runtimeの有効化とセキュアタイムスタンプが必要である。
$ codesign --force --options runtime --timestamp -s "[署名ID]" [出力先のバイナリ名]
[出力先のバイナリ名]: replacing existing signature
$ codesign -v [出力先のバイナリ名]
$ echo $?
0
署名し直したバイナリをzipにして、公証に提出する。ファイルを--keepParentでzipにすると、親ディレクトリの名前もzip内のパスに含まれる。
$ ditto -c -k --keepParent [出力先のバイナリ名] [出力先のバイナリ名].zip
$ xcrun notarytool submit [出力先のバイナリ名].zip --keychain-profile "[プロファイル名]" --wait
...
status: Accepted
参考: 【notarytool】アプリを公証してstaple(公証チケットを添付)する
vtoolが変更するのは、ロードコマンドに記録されたバージョン情報である。新しいSDKでリンクし直したわけではないため、新しいSDKに依存する挙動は有効にならない。ビルドし直せるバイナリは、ビルドし直す方が望ましい。
clangがリンク時に付けるad-hoc署名(linker-signed)だけのバイナリでは、vtoolが署名を付け直すため、警告は表示されない。公証に提出するには、いずれの場合もDeveloper IDで署名し直す。
vtoolの書き換えオプション
-set-build-version以外にも、バージョン情報を操作するオプションがある。
| オプション | 内容 |
|---|---|
-set-build-version [プラットフォーム] [minos] [sdk] | LC_BUILD_VERSIONを書き換える |
-set-version-min [プラットフォーム] [minos] [sdk] | 古い形式のLC_VERSION_MIN_MACOSXなどに書き換える |
-remove-build-version [プラットフォーム] | LC_BUILD_VERSIONを削除する |
-arch [アーキテクチャ] | ユニバーサルバイナリの指定したアーキテクチャだけを対象にする |
-output [出力先] | 出力先のファイル。書き換えでは必須 |
-outputを省略すると、error: one output file must be specifiedで失敗する。入力と同じファイルを-outputに指定すると、上書きできる。
ユニバーサルバイナリは、-archで指定したアーキテクチャだけが書き換わる。
$ xcrun vtool -arch x86_64 -set-build-version macos 10.8 10.8 -output [出力先のバイナリ名] [ユニバーサルバイナリ名]
$ xcrun vtool -show-build [出力先のバイナリ名] | grep -E "architecture|minos|sdk"
[出力先のバイナリ名] (architecture x86_64):
minos 10.8
sdk 10.8
[出力先のバイナリ名] (architecture arm64):
minos 27.0
sdk 27.0
-set-version-minで書き換えたバイナリには、LC_BUILD_VERSIONの代わりにLC_VERSION_MIN_MACOSXが記録される。-show-buildでは次のように表示される。
$ xcrun vtool -set-version-min macos 10.8 10.8 -output [出力先のバイナリ名] [入力のバイナリ名]
$ xcrun vtool -show-build [出力先のバイナリ名]
[出力先のバイナリ名]:
Load command 16
cmd LC_VERSION_MIN_MACOSX
cmdsize 16
version 10.8
sdk 10.8
