はじめに
先日「Installer Sweeper」というフォルダ内の使用済みインストーラーを一括削除するWindowsアプリを個人で開発し,Microsoft Storeでリリースしました。
公開にあたっては,Win32デスクトップアプリをMSIX形式でパッケージ化して提出する形を取ったんですが,アプリストアというものでアプリを公開するのが初めてだったので,コード署名ってやつをどうするかというところで少し悩みました。
結論としては,MSIX形式でパッケージ化する場合は自己署名証明書での署名でよく,別途コード署名証明書を購入する必要はありません。この点自体は既にいくつかの記事で紹介されています。ただし,なぜ自己署名で通るのか,未パッケージ化(MSI/EXE)提出とは何が違うのかまで踏み込んで書かれたものは見当たらなかったため,実際に公開した経験も踏まえて整理しておきます。
そもそもコード署名とは何か
アプリの実行ファイルやパッケージに対して,証明書の秘密鍵を使ってデジタル署名を付与することを指します。目的は大きく2つです。
- 改竄検知:署名後に中身が1バイトでも変わると署名が無効になるため,配布経路の途中で改竄されていないことを保証する。
-
発行者の身元証明:証明書のSubject(
CN=...)が「誰が作ったか」を示す。信頼されたCAが発行した証明書であれば,その身元の信頼性が担保される。
Windowsでは,この身元の信頼性(Microsoft Trusted Root Program傘下のCAに認証されている)がOS/SmartScreen(未知の実行ファイルを警告・ブロックするWindows標準の保護機能)にも引き継がれます。EXEやMSIは署名なしでも(警告は出るものの)インストール可能ですが,MSIX/APPXではOSレベルで署名が強制されており,署名が付いていないパッケージはそもそもインストールできません。逆に署名さえあればオレオレ証明書による署名でもインストールできますが,その場合はSubjectを誰でも自由に名乗れるため,「改竄されていないこと」は保証できても「本当にこの人(組織)が作った」という身元の信頼性までは担保されません。
提出方式ごとの署名要件
Microsoft Storeへのアプリ提出方法は大きく2つあります。
-
MSIXパッケージ化(
.msix/.appx/.appxuploadなどをアップロード) -
未パッケージ化(
.msi/.exeを直接提出)
この2つで,署名の要件は次のように大きく異なります。
| MSIXパッケージ化 | 未パッケージ化(MSI/EXE) | |
|---|---|---|
| 署名 | 開発者は任意の証明書(自己署名でも可)で署名するだけでよく,Store側が審査後に無料で自動的に再署名してくれる | Storeは再署名しない。Microsoft Trusted Root Programに連なるCAが発行した証明書での署名が提出者自身に必須(自己署名不可) |
| 署名コスト | 実質0円(自己署名で足りる) | 年$150〜300程度のOV証明書などが必要(選択肢は後述) |
| その他の制約 | 特になし | サイレントインストール必須,自前でHTTPSダウンロードURLをホストし続ける必要あり,提出後のバイナリ変更禁止,など |
未パッケージ化でStore提出する際に検討しうる署名の選択肢を,Code signing options for Windows app developersの内容を基に整理し直すと,以下の通りです1。
| 選択肢 | コスト | Store提出に使えるか | 備考 |
|---|---|---|---|
| OV証明書(DigiCert/Sectigo/GlobalSign等) | 年$150〜300程度 | ✅ 使える | Microsoft Trusted Root Program傘下のCA発行なら可。2023年以降,秘密鍵をHSM/ハードウェアトークンに格納することが必須2 |
| EV証明書 | 年$400〜 | ✅ 使える | 2024年以降SmartScreen即時信頼の特典は廃止,OVと実質同等。OV同様,秘密鍵をHSM/ハードウェアトークンに格納することが必須2 |
| Azure Artifact Signing(旧称: Trusted Signing) | 月$9.99程度 | ❌ 使えない | 非Store配布向け。ハードウェアトークン不要でOV/EVより低コストだが,Store提出には使えない。 |
これから新規にWindowsアプリを作ってStoreに出す場合,署名まわりのコスト・手間だけを見ても,特別な理由がない限りMSIXパッケージ化を選ぶ方が圧倒的に楽です。この違いがなぜ生まれるのかを次に見ていきます。
※ちなみに,MSIXであっても提出物自体には何らかの署名が必須で,未署名のまま提出することはできません。理由は次の2つです。
- MSIXを正規の手順(Visual StudioやMakeAppx)でビルドする限り,署名を省略した成果物を作る経路がそもそも存在しない3
- Storeの審査(認定)プロセス自体が,Microsoftによる再署名より前の,開発者自身が署名したパッケージに対して行われる。審査には実機・VM上でのインストール確認が含まれるため,その時点で通常の手順でインストールできる状態,つまり有効な署名がある状態である必要がある
なぜ違いが生まれるのか
上で見たような署名要件の差が生まれる原因は,Microsoft Storeが提出されたパッケージの実体を持っているかどうかにあります。
MSIXパッケージは,開発者がビルドした.msixupload/.appxuploadそのものをPartner Centerにアップロードします。審査を通過すると,Microsoftはこのパッケージを自社の証明書で再署名してから配布します。パッケージの実体をStore自身が保有しているからこそ,配布直前に署名を差し替えられます。開発者側の自己署名は,ローカルでビルド・動作確認する際に「署名なしではインストールできない」というMSIXのOSレベルの制約を満たすためだけに必要で(証明書のSubjectをPackage.appxmanifestのPublisher属性と一致させる必要があります),Store提出後の中身には影響しません。
一方MSI/EXE(未パッケージ化)は,バイナリの実体を開発者自身がホストし続け,StoreにはダウンロードURLを登録するだけです。Storeはファイルの実体を持たないため,再署名という選択肢自体が存在しません。提出者が付けた署名がそのままエンドユーザーに渡るため,「本当にこの人(組織)が作ったものである」という身元証明を,提出者自身がMicrosoft Trusted Root Program傘下のCAによって担保する必要があります。
ただ,これだけでは「Storeはパッケージを保有しているから再署名できる」という説明にとどまり,なぜMicrosoftがわざわざその手間を引き受けているのかまでは説明できません。なので,もう少し踏み込んで考察してみます。
まず,事実として,SmartScreenの信頼は証明書・ファイルハッシュ単位の累積ダウンロード実績で積み上がる仕組みになっています。新規に発行された証明書は,正規のCAが発行したOV/EV証明書であっても実績ゼロから始まるため,最初はSmartScreen警告が出ます4。新しく作ったアプリは定義上ダウンロード実績がないので,開発者個人の力でこれを解決するのは原理的に不可能です。
Microsoftが自社の証明書1本でStore経由の全MSIXアプリを再署名すれば,個々の新規アプリも,OS全体で圧倒的な実績を持つこの証明書の信頼をそのまま引き継げます。これは個々の開発者では再現できない規模の話で,多数のアプリを束ねるStoreだからこそ提供できる価値です。
Microsoftにとっての動機はおそらく,証明書コスト・実績構築の手間を理由に個人/小規模開発者がStore公開を諦めるのを防ぎ,Storeに並ぶアプリの数と多様性を確保することにあると考えられます。Apple App Storeも開発者個々の証明書ではなくApple自身の署名・公証で全アプリの信頼を一元的に担保しており,プラットフォーム型ストアに共通する設計だと言えそうです。
まとめ
- Store提出方式(MSIXパッケージ化 or 未パッケージ化)によって,署名の要件はまったく異なる。個人開発ならMSIXの方がコスト・手間ともに軽い
- その違いの理由は「Storeが提出物を再署名するかどうか」。MSIXは再署名されるため自己署名で足り,MSI/EXEは再署名されないため提出者自身がCA証明書で身元証明する必要がある
参考
- コード署名(コードサイニング)とは - IT用語辞典 e-Words
- Code signing options for Windows app developers - Windows apps | Microsoft Learn
- SmartScreen reputation for Windows app developers - Windows apps | Microsoft Learn
- App package requirements for MSI/EXE app - Windows apps | Microsoft Learn
- Create a certificate for package signing - MSIX | Microsoft Learn
- App package requirements for MSIX app - Windows apps | Microsoft Learn
- Create an unsigned MSIX package - MSIX | Microsoft Learn
- What is the correct way to publish apps in the Microsoft Store? - Microsoft Q&A
- Tauriで作ったアプリをMicrosoft Storeへリリースする [コード署名無料]
- WindowsアプリをMicrosoft Storeに公開するための署名証明書を作る方法
- 個人開発者がコード署名を取得して Microsoft Store に出すまでの全記録:想像以上に大変だった話<前編> #アプリ開発 - Qiita
-
参照元の比較表ではOV/EV証明書も「Store eligible: ❌ No」と記載されており,上表と食い違って見えます。これは同記事が非Store配布向けの選択肢比較に主眼を置いているための表記のようで(記事冒頭に「Everything else in this article applies to apps distributed outside the Microsoft Store」との断り書きがあります),実際の提出要件を定めたApp package requirements for MSI/EXEでは,証明書の種類を問わずMicrosoft Trusted Root Program傘下のCA発行であることのみが条件とされています。上表はこちらの実際の提出要件に基づいています。 ↩
-
CA/Browser ForumのCode Signing Baseline Requirementsにより,2023年6月1日以降に発行されるコード署名証明書(EV/非EVとも)は,秘密鍵をFIPS 140-2 Level 2またはCommon Criteria EAL 4+相当のハードウェア暗号モジュール(HSM/USBトークン等)に格納し,エクスポート不可とすることが義務付けられている。 ↩ ↩2
-
未署名パッケージを作る唯一の方法は,マニフェストの
Identity要素に特殊なOID値を仕込む裏技。Create an unsigned MSIX packageによると,インストールにもAdd-AppxPackage -AllowUnsignedという専用フラグ(実行可能コードを含む場合は管理者権限も)が必要で,同記事も「Don't use this feature to distribute your app widely」と明記するローカルテスト専用の機能。この特殊OIDはStore提出に必須の正規のPublisher識別子とも両立しない。 ↩ -
SmartScreen reputation for Windows app developersによると,SmartScreenは「発行者(証明書)の信頼」と「ファイルハッシュの信頼」を別々に評価する。ファイルハッシュ側の実績はバージョンごとにゼロから積み上がるのに対し,証明書側の実績は同じ証明書で署名し続ける限りリリースをまたいで引き継がれる。 ↩