アプリの署名が正しく付いているか、公証の前に確認したいときは、codesignの2つのオプションを使う。署名の内容は-dvで表示し、署名の整合性は--verifyで検証する。
$ codesign -dv --verbose=4 [アプリ名].app
$ codesign --verify --deep --strict --verbose=2 [アプリ名].app
実行例はXcode 27.0、macOS 27.0.1のもの。
- 前の記事: 【xcodebuild】Developer ID署名でアーカイブしてエクスポートする
- 親記事: GitHubを使い、macOSアプリを署名・公証・自動アップデート付きで公開する
- 次の記事: 【notarytool】App用パスワードで公証用の認証情報を保存する
-dvで署名の内容を表示する
codesign -dは署名の情報を表示し、-vを重ねると詳細になる。-dv --verbose=4で、署名に関するほぼすべての情報が表示される。出力は標準エラー出力に書かれるため、grepなどで絞り込むときは2>&1を付ける。
$ codesign -dv --verbose=4 [アプリ名].app
Executable=[アプリ名].app/Contents/MacOS/[アプリ名]
Identifier=[Bundle ID]
Format=app bundle with Mach-O thin (arm64)
CodeDirectory v=20500 size=488 flags=0x10000(runtime) hashes=4+7 location=embedded
...
CDHash=[CDHash]
Signature size=9044
Authority=Developer ID Application: [名前] ([Team ID])
Authority=Developer ID Certification Authority
Authority=Apple Root CA
Timestamp=Oct 4, 2026 at 7:30:10
Info.plist entries=19
TeamIdentifier=[Team ID]
Runtime Version=27.0.0
Sealed Resources version=2 rules=13 files=0
Internal requirements count=1 size=220
Total signatures=1
Chosen signature=1
公証の前に確認したい行は、次の4つである。
| 行 | 見方 |
|---|---|
flags=0x10000(runtime) | Hardened Runtimeが有効である。公証に必要 |
Authority=Developer ID Application: ... | Developer ID Applicationで署名されている。Authorityの行は、署名に使った証明書から、中間CA、ルートCAへと連なる |
Timestamp=... | セキュアタイムスタンプが付いている。公証に必要 |
TeamIdentifier=... | 署名したTeam |
IdentifierはBundle IDである。CDHashは、署名の対象になったコードのハッシュ値である。
公証してstapler stapleでチケットを添付したアプリには、Notarization Ticket=stapledの行も表示される。
セキュアタイムスタンプの有無
セキュアタイムスタンプは、署名時にAppleのタイムスタンプサーバーが付ける時刻の証明である。付いていると、Timestamp=の行が表示される。Xcodeで開発用の証明書(Apple Development)で署名したアプリには付かず、Signed Time=の行だけが表示される。
$ codesign -dv --verbose=4 [Apple Developmentで署名したアプリ].app 2>&1 | grep -E 'flags|Authority|Time'
CodeDirectory v=20400 size=768 flags=0x0(none) hashes=13+7 location=embedded
Authority=Apple Development: [名前] ([ID])
Authority=Apple Worldwide Developer Relations Certification Authority
Authority=Apple Root CA
Signed Time=Oct 4, 2026 at 7:29:19
Timestamp=がないアプリは、公証でInvalidになる。codesignで署名するときは、--timestampを付ける。
署名に使われた証明書を特定する
Authorityには、証明書の名前だけが表示される。同じ名前の証明書が複数ある場合は、署名に使われた証明書を--extract-certificatesで取り出して、SHA-1ハッシュを確認する。
$ mkdir certs && cd certs
$ codesign -d --extract-certificates=cert [アプリ名].app
$ /usr/bin/openssl x509 -inform DER -in cert0 -noout -fingerprint -sha1
SHA1 Fingerprint=[コロン区切りのSHA-1ハッシュ]
cert0が署名に使った証明書で、cert1以降が中間CAとルートCAである。
Designated Requirementを表示する
-d -r-で、署名のDesignated Requirement(このアプリだと判定するための条件)を表示できる。
$ codesign -d -r- [アプリ名].app
designated => anchor apple generic and identifier "[Bundle ID]" and (certificate leaf[field.1.2.840.113635.100.6.1.9] /* exists */ or certificate 1[field.1.2.840.113635.100.6.2.6] /* exists */ and certificate leaf[field.1.2.840.113635.100.6.1.13] /* exists */ and certificate leaf[subject.OU] = [Team ID])
Appleが発行した証明書で、Bundle IDとTeam IDが一致するアプリである、という条件が書かれている。
entitlementsを表示する
署名に埋め込まれたentitlementsは、--entitlements -で表示できる。
$ codesign -d --entitlements - [アプリ名].app
[Dict]
[Key] com.apple.security.files.user-selected.read-only
[Value]
[Bool] true
公証では、com.apple.security.get-task-allowがtrueのアプリがInvalidになる。entitlementsは、署名後のアプリで確認する。
--verifyで署名の整合性を検証する
codesign --verifyは、署名とアプリの中身が一致しているかを検証する。問題がなければ、何も表示されないか、--verbose=2でメッセージが表示される。
$ codesign --verify --deep --strict --verbose=2 [アプリ名].app
[アプリ名].app: valid on disk
[アプリ名].app: satisfies its Designated Requirement
オプションの意味は次のとおりである。
| オプション | 意味 |
|---|---|
--verify | 署名を検証する |
--deep | アプリに入っているフレームワークやXPCサービスなども検証する |
--strict | 検証を厳密にする |
--verbose=2 | 検証の結果を表示する |
valid on diskは署名とファイルの内容が一致していること、satisfies its Designated Requirementは署名がDesignated Requirementを満たしていることを表す。
フレームワークやXPCサービスも検証される
Sparkleのように、フレームワークやXPCサービスを同梱したアプリでは、--deepによって内部のコードも検証される。--verbose=2では、検証の準備と結果が--prepared:と--validated:で表示される。
$ codesign --verify --deep --strict --verbose=2 [アプリ名].app
--prepared:[アプリ名].app/Contents/Frameworks/Sparkle.framework/Versions/Current/XPCServices/Downloader.xpc
--validated:[アプリ名].app/Contents/Frameworks/Sparkle.framework/Versions/Current/XPCServices/Downloader.xpc
--prepared:[アプリ名].app/Contents/Frameworks/Sparkle.framework/Versions/Current/XPCServices/Installer.xpc
--validated:[アプリ名].app/Contents/Frameworks/Sparkle.framework/Versions/Current/XPCServices/Installer.xpc
--prepared:[アプリ名].app/Contents/Frameworks/Sparkle.framework/Versions/Current/Updater.app
--validated:[アプリ名].app/Contents/Frameworks/Sparkle.framework/Versions/Current/Updater.app
--prepared:[アプリ名].app/Contents/Frameworks/Sparkle.framework/Versions/Current/Autoupdate
--validated:[アプリ名].app/Contents/Frameworks/Sparkle.framework/Versions/Current/Autoupdate
[アプリ名].app: valid on disk
[アプリ名].app: satisfies its Designated Requirement
内部のコードの署名が欠けていると、公証でInvalidになる。内部のコードも、-dvでDeveloper IDの署名とタイムスタンプ、runtimeのフラグが付いているかを確認できる。Xcodeでエクスポートしたアプリは、同梱したSparkleのコードにも、同じ署名が付く。
$ codesign -dv --verbose=2 [アプリ名].app/Contents/Frameworks/Sparkle.framework/Versions/B/Autoupdate 2>&1 | grep -E 'flags|Authority=Dev|Timestamp'
CodeDirectory v=20500 size=1023 flags=0x10000(runtime) hashes=20+7 location=embedded
Authority=Developer ID Application: [名前] ([Team ID])
Timestamp=Oct 4, 2026 at 8:01:36
署名後にファイルを変更すると検証に失敗する
署名の後でファイルを追加したり、書き換えたりすると、検証に失敗する。
$ cp -R [アプリ名].app tamper.app
$ echo x >> tamper.app/Contents/Resources/extra.txt
$ codesign --verify --deep --strict --verbose=2 tamper.app
tamper.app: a sealed resource is missing or invalid
file added: tamper.app/Contents/Resources/extra.txt
$ echo $?
1
a sealed resource is missing or invalidは、署名で封印したリソースが変更されたことを表す。追加されたファイルは、file added:で表示される。終了コードは1である。
署名後にアプリの中身を変更する処理(Info.plistの書き換えなど)は、署名の前に済ませる。
内部のコードに署名がないアプリの検証
内部のフレームワークや実行ファイルの署名が欠けていると、--deepの検証が失敗する。
$ codesign --remove-signature [アプリ名].app/Contents/Frameworks/Sparkle.framework/Versions/B/Autoupdate
$ codesign --verify --deep --strict --verbose=2 [アプリ名].app
[アプリ名].app: code object is not signed at all
In subcomponent: [アプリ名].app/Contents/Frameworks/Sparkle.framework/Versions/Current/Autoupdate
In architecture: arm64
署名のないコードを含むアプリを公証に提出すると、結果がInvalidになる。公証のログには、署名のないバイナリのパスと、The binary is not signed.が記録される。
署名を無効にしたビルドの検証
署名を無効にしてビルドしたアプリは、完全には無署名にならない。CODE_SIGNING_ALLOWED=NOでビルドすると、リンカーが実行ファイルにad hoc署名を付ける。
$ xcodebuild -project [プロジェクト名].xcodeproj -scheme [スキーム名] -configuration Release \
CODE_SIGNING_ALLOWED=NO build
$ codesign -dv --verbose=2 [アプリ名].app
Identifier=[アプリ名]
Format=app bundle with Mach-O thin (arm64)
CodeDirectory v=20400 size=1671 flags=0x20002(adhoc,linker-signed) hashes=49+0 location=embedded
Signature=adhoc
Info.plist=not bound
TeamIdentifier=not set
Sealed Resources=none
Internal requirements=none
$ codesign --verify --deep --strict --verbose=2 [アプリ名].app
[アプリ名].app: code has no resources but signature indicates they must be present
IdentifierがBundle IDではなく実行ファイルの名前になり、TeamIdentifierも設定されない。署名はアプリ全体ではなく、実行ファイルだけに付いている。配布用の署名とは別物である。
参考: 【notarytool】アプリを公証してstaple(公証チケットを添付)する
参考: 【notarytool】公証に失敗した理由をログから調べる
