Mac App Store以外でmacOSアプリを配布するときは、Developer ID Application証明書でアプリに署名する。公証(notarization)に提出するアプリにも、この証明書による署名が必要である。

ここでは、opensslで秘密鍵とCSRを作り、Apple Developerで証明書を発行して、キーチェーンに登録するまでの手順を紹介する。実行例はmacOS 27.0.1のもの。Apple Developer Programに加入済みであることを前提とする。

$ security find-identity -v -p codesigning
  1) [SHA-1ハッシュ] "Developer ID Application: [名前] ([Team ID])"
     1 valid identities found

上のようにDeveloper ID Applicationが表示されれば、署名の準備は完了である。

Developer ID ApplicationとDeveloper ID Installerの違い

Developer IDの証明書には、2つの種類がある。

証明書署名の対象
Developer ID Applicationアプリ(.app)や実行ファイル
Developer ID Installerインストーラパッケージ(.pkg)

zipやdmgでアプリを配布する場合は、Developer ID Applicationだけで足りる。.pkgで配布する場合は、Developer ID Installerも必要になる。

Developer ID証明書を作成できるのは、チームのAccount Holderである。Developer ID Applicationは、最大5つまで作成できる。

参考: Developer ID certificates - Apple Developer

秘密鍵とCSRを作る

証明書の発行には、CSR(Certificate Signing Request)を使う。秘密鍵は手元に残し、秘密鍵から作ったCSRだけをAppleに送る。

Keychain Accessの証明書アシスタントでもCSRを作成できる。ここでは手順をコマンドで完結させるため、opensslを使う。

opensslは、macOS標準の/usr/bin/openssl(LibreSSL)を使う。Homebrewでopensslを入れていると、which opensslの結果が/opt/homebrew/bin/opensslになる。後述の.p12の作成で問題になるため、パスを明示して実行する。

$ which -a openssl
/opt/homebrew/bin/openssl
/usr/bin/openssl
$ /usr/bin/openssl version
LibreSSL 3.3.6

作業用のディレクトリで、RSA 2048bitの秘密鍵を作る。

$ mkdir ~/developer-id && cd ~/developer-id
$ umask 077
$ /usr/bin/openssl genrsa -out developer_id.key 2048

umask 077で、作成するファイルを自分だけが読み書きできるようにしている。続けて、秘密鍵からCSRを作る。

$ /usr/bin/openssl req -new -key developer_id.key -out developer_id.csr \
    -subj "/emailAddress=[メールアドレス]/CN=[名前] Developer ID/C=JP"

CSRの内容と署名は、次のコマンドで確認できる。

$ /usr/bin/openssl req -in developer_id.csr -noout -subject -verify
verify OK
subject=/emailAddress=[メールアドレス]/CN=[名前] Developer ID/C=JP

証明書を発行してダウンロードする

Apple Developerのサイトで、証明書を発行する。

  1. 「Certificates, Identifiers & Profiles」の「Certificates」を開き、左上の「+」を押す
  2. 「Software」の「Developer ID Application」を選んで「Continue」を押す

証明書の種類の選択

  1. 「Select a Developer ID Certificate Intermediary」で、「G2 Sub-CA (Xcode 11.4.1 or later)」を選ぶ

Sub-CAの選択

「Profile Type」の既定は「Previous Sub-CA」である。画面の説明には、前のSub-CAに関連付けた証明書は2027年2月1日に失効すると書かれている。Xcode 11.4.1以降で使う場合は、「G2 Sub-CA」を選ぶ。

  1. 「Choose File」でdeveloper_id.csrを選び、「Continue」を押す

CSRのアップロード

  1. 「Download」を押して、.cerファイルを保存する

証明書のダウンロード

「Expiration Date」には、証明書の有効期限が表示される。発行から約5年後の日付である。保存した.cerは、既定では~/Downloads/developerID_application.cerになる。

.cerと秘密鍵を.p12にまとめてキーチェーンに登録する

ダウンロードした.cerには、公開鍵の証明書だけが入っている。署名には、対応する秘密鍵が必要である。今回の秘密鍵は、opensslで作ったファイルである。キーチェーンには入っていない。証明書と秘密鍵を.p12ファイルにまとめてから、キーチェーンに登録する。

まず、.cerをPEM形式に変換する。

$ /usr/bin/openssl x509 -inform DER -in ~/Downloads/developerID_application.cer -out developer_id.pem

証明書と秘密鍵が対応していることを、モジュラスのハッシュ値で確認する。2つの値が同じであれば、対応している。

$ /usr/bin/openssl x509 -in developer_id.pem -noout -modulus | /usr/bin/openssl md5
[ハッシュ値]
$ /usr/bin/openssl rsa -in developer_id.key -noout -modulus | /usr/bin/openssl md5
[ハッシュ値]

証明書と秘密鍵を.p12にまとめる。パスワードの入力を求められるので、任意のパスワードを設定する。

$ /usr/bin/openssl pkcs12 -export -inkey developer_id.key -in developer_id.pem \
    -name "Developer ID Application" -out developer_id.p12
Enter Export Password:
Verifying - Enter Export Password:

.p12をログインキーチェーンに登録する。-T /usr/bin/codesignは、codesignによる秘密鍵へのアクセスを許可する。

$ security import developer_id.p12 -k ~/Library/Keychains/login.keychain-db \
    -P '[.p12のパスワード]' -T /usr/bin/codesign
1 identity imported.

Apple Developerの画面には、秘密鍵と公開鍵のバックアップを安全な場所に保存するよう書かれている。developer_id.keyとdeveloper_id.p12を失うと、同じ証明書で署名できなくなる。

キーチェーンに登録された証明書を確認する

署名に使える証明書の一覧は、security find-identityで表示できる。

$ security find-identity -v -p codesigning
  1) [SHA-1ハッシュ] "Developer ID Application: [名前] ([Team ID])"
     1 valid identities found

すでにDeveloper ID Applicationの証明書がある環境では、同じ名前の証明書が2行並ぶ。名前だけでは見分けられないため、SHA-1ハッシュで区別する。今回発行した証明書のSHA-1ハッシュは、opensslで確認できる。

$ /usr/bin/openssl x509 -in developer_id.pem -noout -fingerprint -sha1
SHA1 Fingerprint=[コロン区切りのSHA-1ハッシュ]

security find-identityの表示は、コロンを除いた大文字の16進数である。表示を見比べて、今回の証明書を特定する。

署名するときは、証明書の名前ではなくSHA-1ハッシュを指定すると、意図しない証明書で署名するのを防げる。

$ codesign -f -s [SHA-1ハッシュ] --options runtime --timestamp [署名するアプリ]

Homebrewのopensslで作った.p12はインポートに失敗する

which opensslが/opt/homebrew/bin/opensslを指す環境で、opensslのパスを省略して.p12を作ると、security importが失敗する。Homebrewのopenssl(OpenSSL 3.6.0)で試すと、次のエラーになる。

$ /opt/homebrew/bin/openssl pkcs12 -export -inkey developer_id.key -in developer_id.pem \
    -name "Developer ID Application" -out developer_id.p12
$ security import developer_id.p12 -k ~/Library/Keychains/login.keychain-db -P '[.p12のパスワード]'
security: SecKeychainItemImport: MAC verification failed during PKCS12 import (wrong password?)

パスワードは正しいにもかかわらず、wrong password?と表示される。原因は暗号方式の違いである。OpenSSL 3の既定は新しい方式で、macOSのsecurity importでは読み込めない。.p12の暗号方式は、openssl pkcs12 -infoで確認できる。

$ /opt/homebrew/bin/openssl pkcs12 -info -in developer_id.p12 -noout
MAC: sha256, Iteration 2048
...
PKCS7 Encrypted data: PBES2, PBKDF2, AES-256-CBC, Iteration 2048, PRF hmacWithSHA256

-legacyを付けると、従来の暗号方式で.p12を作成する。このときは、security importが成功する。

$ /opt/homebrew/bin/openssl pkcs12 -export -legacy -inkey developer_id.key -in developer_id.pem \
    -name "Developer ID Application" -out developer_id.p12
$ security import developer_id.p12 -k ~/Library/Keychains/login.keychain-db -P '[.p12のパスワード]'
1 identity imported.

/usr/bin/openssl(LibreSSL)で作った.p12には、-legacyは不要である。

参考: 【xcodebuild】Developer ID署名でアーカイブしてエクスポートする

参考: 【GitHub Actions】一時keychainに証明書をインポートして署名する