iOSアプリのプロビジョニングプロファイル、証明書について解説

iOSアプリ開発をすると、一度は証明書やプロビジョニングプロファイルでつまづいたことがあるのではないでしょうか。「iOS端末でアプリを実行するためには、証明書とプロビジョニングプロファイルが必要なことはわかったけれど、2つの違いは何なのか?」と疑問に感じたことが一度はあると思います。検索してみると、証明書、プロビジョニングプロファイルを作成する手順を解説しているブログ記事はありますが、その中身について詳しく解説している記事は少ないようです。本記事では、証明書、プロビジョニングプロファイルに格納されている情報や、その役割について解説します。

本記事では、秘密鍵、公開鍵、デジタル署名、証明書についての基本的な知識があることを前提としています。これらは広く使われている技術で、iOSに特化したものではありません。もしその知識がないようでしたら「暗号技術入門 第3版　秘密の国のアリス」の9章、10章の解説がわかりやすいので、そちらを読むことをおすすめします。それらの技術がiOS開発の証明書、プロビジョニングプロファイルにどのように使われているかを解説します。

実際の開発では、CLIで証明書やプロビジョニングプロファイルを作成してgitで管理できる [match](https://docs.fastlane.tools/actions/match/) がよく使われています。その場合は記事で解説している知識は必ずしも必要ではありませんが、エラーが起きたときにエラーメッセージの内容を理解できなかったり、エラーを解決するのに時間がかかったりしてしまいます。iOSアプリの開発をするとプロジェクトの異動、証明書の更新、デバイスの追加などにより、半年に1回程度の頻度で証明書のエラーや実機ビルドができないなどで、対応が必要になることがあります。そのような場合に仕組みを理解しておくことが役に立つのでないかと考えています。

それでは証明書、プロビジョニングプロファイルを作成しながら、中身を確認していきます。

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1669077/bae70ab7-f030-e9d1-e74e-4c8eae518e5e.png" width="800px">

## 1. 公開鍵、秘密鍵、CSRファイルの作成
公開鍵、秘密鍵、CSRファイルを作成します。

キーチェーンアクセス -> 証明書アシスタント -> 認証局に証明書を要求 でキーチェーンに公開鍵と秘密鍵(下図)、指定したパスにCSRファイルが作成されます。

- 証明書情報
  - ユーザのメールアドレス: 自分のメールアドレス
  - 通称: `cer-test1` (ここではテスト用の名前にしています)
  - ディクスに保存
  - 鍵ペア情報を指定

- 鍵ペア情報
  - 鍵のサイズ: 2048ビット
  - アルゴリズム: RSA

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1669077/a8dee8f0-61f5-b611-8be7-8d740b94d648.png" width="800px">

公開鍵と秘密鍵は特に解説は不要かと思いますが、 CSRファイルについてはあまり馴染みがないのではないでしょうか。 `openssl` コマンドを使って中身を確認してみると、公開鍵とハッシュ値があることがわかります。CSRは、Certificate Signing Requestの頭文字で、Appleに署名を要求しています。

```
$ openssl req -in CertificateSigningRequest.certSigningRequest -noout -text

Certificate Request:
    Data:
        Version: 0 (0x0)
        Subject: emailAddress=******, CN=cer-test1, C=JP
        Subject Public Key Info:
            Public Key Algorithm: rsaEncryption
                Public-Key: (2048 bit)
                Modulus:
                    ...省略...
                Exponent: 65537 (0x10001)
        Attributes:
            a0:00
    Signature Algorithm: sha256WithRSAEncryption
         ...省略...
```

## 2. CSRファイルのアップロード
Apple Developer Programにログインして、Certificates, Identifiers & Profiles -> Certificates -> Apple Development、と進んで、CSRファイルをアップロードします。

## 3. 証明書のダウンロード
CSRファイルをアップロードすると、証明書をダウンロードできるようになります。Macにダウンロードした証明書をダブルクリックするとキーチェーンアクセスの[自分の証明書]にインポートされます。

以下のコマンドで証明書の中身を見ると、`Public-Key` にアップロードした公開鍵があり、Issuer(証明書の発行者)がAppleであることが確認できます。

```
$ openssl x509 -inform der -in development.cer -noout -text

Certificate:
    Data:
        Version: 3 (0x2)
        Serial Number:
            ...
    Signature Algorithm: sha256WithRSAEncryption
        Issuer: CN=Apple Worldwide Developer Relations Certification Authority, OU=G3, O=Apple Inc., C=US
        Validity
            Not Before: May 24 12:41:46 2021 GMT
            Not After : May 24 12:41:45 2022 GMT
        Subject: UID=..., CN=Apple Development: ..., OU=G3, O=..., C=US
        Subject Public Key Info:
            Public Key Algorithm: rsaEncryption
                Public-Key: (2048 bit)
                Modulus:
                    ...省略... // 1で作成した公開鍵
                Exponent: 65537 (0x10001)
        X509v3 extensions:
            X509v3 Basic Constraints: critical
                CA:FALSE
            X509v3 Authority Key Identifier: 
                keyid:...

            Authority Information Access: 
                CA Issuers - URI:http://certs.apple.com/wwdrg3.der
                OCSP - URI:http://ocsp.apple.com/ocsp03-wwdrg304

            X509v3 Certificate Policies: 
                Policy: 1.2.840.113635.100.5.1
                  User Notice:
                    Explicit Text: Reliance on this certificate by any party assumes acceptance of the then applicable standard terms and conditions of use, certificate policy and certification practice statements.
                  CPS: https://www.apple.com/certificateauthority/

            X509v3 Extended Key Usage: critical
                Code Signing
            X509v3 Subject Key Identifier: 
                ...
            X509v3 Key Usage: critical
                Digital Signature
            1.2.840.113635.100.6.1.2: critical
                ..
            1.2.840.113635.100.6.1.12: critical
                ..
    Signature Algorithm: sha256WithRSAEncryption
         ...省略...
```

それぞれの階層の意味はこちら
https://www.ipa.go.jp/security/pki/033.html#_Toc3020768

## 3. p12ファイルの作成
一人で開発をするのであればこの手順は不要ですが、複数人や複数のMacで開発をする場合は証明書と秘密鍵を共有する必要があります。証明書はApple Developer Programからダウンロードできますが、秘密鍵はキーチェーンで秘密鍵を生成したMacにしかないのでダウンロードできません。そのため秘密鍵と証明書と一つにまとめたPKCS#12形式を使います。

キーチェーン -> 自分の証明書 -> 証明書を右クリックして、書き出すを選択

p12ファイルの中身をみると、証明書(CERTIFICATE)と秘密鍵(PRIVATE KEY)が含まれてていることが確認できます。

```
$ openssl pkcs12 -info -in cer.p12 -nodes

MAC Iteration 1
MAC verified OK
PKCS7 Encrypted data: pbeWithSHA1And40BitRC2-CBC, Iteration 2048
Certificate bag
Bag Attributes
    friendlyName: Apple Development: ...
    localKeyID: ...
subject=/UID=...735QQ/CN=Apple Development: .../OU=.../O=.../C=US
issuer=/CN=Apple Worldwide Developer Relations Certification Authority/OU=G3/O=Apple Inc./C=US
-----BEGIN CERTIFICATE-----
...省略...
-----END CERTIFICATE-----
PKCS7 Data
Shrouded Keybag: pbeWithSHA1And3-KeyTripleDES-CBC, Iteration 2048
Bag Attributes
    friendlyName: cer-test1
    localKeyID: ... 
Key Attributes: <No Attributes>
-----BEGIN PRIVATE KEY-----
...省略...
-----END PRIVATE KEY-----
```

## 4. プロビジョニングプロファイルのダウンロード
次にprovisioning profileを作成します。作成のフローの中で証明書を選択する画面があるので、先ほどの証明書を選択します。

ダウンロードしたプロビジョニングプロファイルに、どんな情報があるのかを確認してみます。

```
$ security cms -D -i certest1.mobileprovision

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
	<key>AppIDName</key>
	<string>certest1</string>
	<key>ApplicationIdentifierPrefix</key>
	<array>
	<string>...</string>
	</array>
	<key>CreationDate</key>
	<date>2021-05-24T13:54:10Z</date>
	<key>Platform</key>
	<array>
		<string>iOS</string>
	</array>
	<key>IsXcodeManaged</key>
	<false/>
	<key>DeveloperCertificates</key>
	<array>
		<data>...省略...</data>
	</array>

																						
	<key>Entitlements</key>
	<dict>
																						
				<key>application-identifier</key>
		<string>...</string>
				
				<key>keychain-access-groups</key>
		<array>
				<string>....*</string>
				<string>com.apple.token</string>
		</array>
				
				<key>get-task-allow</key>
		<true/>
				
				<key>com.apple.developer.team-identifier</key>
		<string>...</string>
														
	</dict>
	<key>ExpirationDate</key>
	<date>2022-05-24T13:54:10Z</date>
	<key>Name</key>
	<string>certest1</string>
	<key>ProvisionedDevices</key>
	<array>
		<string>...</string>
	</array>
	<key>TeamIdentifier</key>
	<array>
		<string>...</string>
	</array>
	<key>TeamName</key>
	<string>...</string>
	<key>TimeToLive</key>
	<integer>365</integer>
	<key>UUID</key>
	<string>...e</string>
	<key>Version</key>
	<integer>1</integer>
</dict>
</plist>
```

上記ではマスクしてありますが、アプリケーションIDや有効期限などの情報があります。その他に`DeveloperCertificates` というKeyに開発者証明書があります。

```
	<key>DeveloperCertificates</key>
	<array>
		<data>...省略...</data>
	</array>
```

3でダウンロードした証明書をpem形式に変換すると、プロビジョニングプロファイルの `DeveloperCertificates` の証明書と同じものです。そこから、プロビジョニングプロファイルの作成フローで選択した証明書が、プロビジョニングプロファイルに埋め込まれていることが確認できます。

```
// pem形式への変換
$ openssl x509 -in development.cer -out ios_development.pem -inform der
```

## コード署名
上記の手順で作成した証明書はコード署名で使います。コード署名については、ドキュメントでこのように解説されています。

> Code signing (or signing) an app allows the system to identify who signed the app and to verify that the app has not been modified since it was signed.

https://help.apple.com/xcode/mac/current/#/dev3a05256b8 のcode signsのポップアップ画面から引用

> Code signing is a macOS security technology that you use to certify that an app was created by you. Once an app is signed, the system can detect any change to the app—whether the change is introduced accidentally or by malicious code.

https://developer.apple.com/library/archive/documentation/Security/Conceptual/CodeSigningGuide/Introduction/Introduction.html#//apple_ref/doc/uid/TP40005929-CH1-SW1 から引用

### ビルド
ソースコードをビルドする際に、秘密鍵を使いコード署名をして、署名を検証できるように証明書も付けます。そうすることで、証明書(公開鍵)とそれに対応する秘密鍵を持つ開発者だけが、有効なコード署名ができます。

実行ファイルにどのように署名されているのかは、[iOSのコード署名について](https://engineering.linecorp.com/ja/blog/ios-code-signing/) で詳しく解説されています。

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1669077/e0ca418b-7001-5dd6-6337-ee4d93fbf3a0.png" width="600px">

### コード署名の検証
証明書の署名の検証、コード署名を検証することで、Appleに登録済みの開発者がアプリを作成したこと、アプリに改ざんがないことを確認できます。そうすることで、Appleが承認したアプリだけが実行できます。App Storeで配布しているアプリを改ざんして実行することはできません。

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1669077/bfde44d6-b335-17f1-b9d2-2b3637139310.png" width="500px">

開発用のアプリの場合は上記のようになりますが、App Storeでアプリを配布する場合はもう少し複雑で、開発者がコード署名したものをAppleが再署名しています。[What is the value of iOS code signing?](https://krausefx.com/blog/the-developer-part-of-ios-code-signing-doesnt-add-any-security-to-anything) ではその仕組みや問題点などが解説されています。

## 参考文献
- [What is app signing?](https://help.apple.com/xcode/mac/current/#/dev3a05256b8)
- [About Code Signing](https://developer.apple.com/library/archive/documentation/Security/Conceptual/CodeSigningGuide/Introduction/Introduction.html#//apple_ref/doc/uid/TP40005929-CH1-SW1)