CyberFix Note
セキュアコーディング

コード署名の仕組みと署名鍵の管理。誰が作ったかを証明する仕掛けと、鍵が漏れた後に起きること

対象の目安: ソフトウェアを配布する開発者とリリース担当 / 実務

リク編集長 / セキュリティ全般・戦略
・ 約52分で読めます
コード署名の仕組みと署名鍵の管理。誰が作ったかを証明する仕掛けと、鍵が漏れた後に起きること

インストーラをダブルクリックしたときに「発行元: 株式会社なんとか」と表示されると、その画面は安心の合図として受け取られます。しかし表示が伝えているのは、このファイルにその会社の秘密鍵で署名が付いていて、署名後にファイルが変わっていないという二点だけです。中身が安全かどうかについて、署名は何も言っていません。

この差は理屈の話ではありません。CISAのアドバイザリAA20-352Aによれば、SolarWinds Orionの事案では悪意あるDLLがSolarWinds自身の正規のコード署名証明書で署名された状態で配布されました。署名の検証はすべて通り、それでも中身はバックドアでした。署名鍵は盗まれていません。汚染されていたのは、署名される前の入力です。

この記事は、自社のソフトウェアやファームウェアを外部へ配布する開発者とリリース担当に向けて、コード署名が成立する機構を分解し、署名鍵をどこにどう置くか、署名を実行する権限をどう分けるか、そして鍵が漏れた後に何が壊れて何が残るかを実務の手順に落とします。CA/Browser Forumの基準文書、RFC、NISTの刊行物、Microsoft、Apple、Sigstore、SLSAの公式資料、CISAのアドバイザリを一次情報として使い、確認できた範囲だけを書きます。記述は執筆時点(2026年9月4日)に参照できた版に基づきます。

コード署名が答える問いと答えない問い

受け手が署名を検証したときに確定する事実は四つです。この配布物は特定の秘密鍵の保持者が署名したこと。その公開鍵を含む証明書が、受け手の信頼する認証局の連鎖につながること。証明書の組織名は認証局が身元確認した結果であること。そして署名後にバイト列が1バイトも変わっていないこと。

ここに含まれない事実がいくつもあります。そのコードに脆弱性がないこと、利用者の意図しない動作をしないこと、正規の開発工程を経て作られたこと。どれも署名からは導けません。

NISTのサイバーセキュリティホワイトペーパー「Security Considerations for Code Signing」は、この点を役割の分解として説明しています。同文書は関与者を開発者、署名者、検証者の三つに分け、署名者について「署名者は技術的および手続き的な統制によって、認可されたコードのみが署名されることを保証する」と書いています。署名対象が信頼に足るかを担保するのは暗号ではなく、署名の手前に置かれた承認プロセスです。暗号はその承認結果を改ざん不能な形で受け手へ運ぶ配管にすぎません。

NISTサイバーセキュリティホワイトペーパー「Security Considerations for Code Signing」(2018年1月26日)は、コード署名がdata integrity(コードが改変されていないことの証明)とsource authentication(署名時にコードを管理していた者の識別)の二つを提供すると定義しています。論理構成をCode Signing System(CSS)、認証局、Time Stamp Authority、検証者の4要素に分けています。脅威としては、秘密署名鍵の窃取、不正なコード署名証明書の発行、証明書や鍵への誤った信頼、認可されていないコードや悪意あるコードへの署名、脆弱な暗号の使用の5点を挙げています。

この整理から、守る対象が二層に分かれることが見えてきます。下の層は鍵そのものの秘匿で、上の層は「何に署名するか」を決める意思決定の統制です。下の層だけを固めても、上の層が緩ければSolarWindsと同じ結末になります。

公開鍵暗号とデジタル署名の関係を先に押さえておきたい場合は、次の記事で整理しています。

あわせて読みたい

暗号化の基礎。共通鍵・公開鍵・ハッシュ・TLSはどう情報を守るのか

ハッシュと秘密鍵と証明書がつながる順序

署名の生成で秘密鍵が処理する対象は、ファイル全体ではありません。まずファイルからハッシュ値を計算し、そのハッシュ値に署名アルゴリズムを適用します。ファイルが数百メガバイトあっても署名対象は数十バイトに縮まります。署名処理をHSMのような遅いデバイスへ委ねられるのはこのためです。

WindowsのAuthenticodeでは、この署名がPKCS #7のSignedData構造として実行ファイルの中へ格納されます。SignedDataには対象コンテンツの情報、証明書とCRLの集合、そしてSignerInfo署名ブロックが入り、SignerInfoには署名者の証明書を特定する発行者名とシリアル番号、暗号化されたダイジェスト、認証済み属性と未認証属性が含まれます。

Authenticodeのハッシュ計算には実務で効いてくる性質があります。App Control for Businessの解説によれば、Authenticode/PEイメージハッシュは一般的なフラットファイルハッシュと違い、ファイルのチェックサム、Certificate Table、Attribute Certificate Tableを計算対象から除きます。そのため署名やタイムスタンプを変更しても、署名を取り外しても、ハッシュ値は変わりません。同じバイナリに再署名しても実行制御ポリシーのハッシュルールを書き換えずに済むのは、この設計のおかげです。

macOSやLinuxの署名は形式が異なりますが、原理は共通です。どの実装でも、ハッシュを取る対象の範囲がそのまま「改ざんを検知できる範囲」になります。実行ファイルが実行時に読み込む外部DLL、アプリバンドルへ後から追加されたリソース、パッケージの中でハッシュが取られていないファイルは、いずれも署名の外側です。

署名済みという表示を安全と読み違える場面

Windowsの利用者がまず見るのはSmartScreenの画面です。Microsoft Learnの説明では、SmartScreenは発行元の評判とファイルハッシュの評判という二つのシグナルを評価します。署名されていても、そのハッシュや発行元証明書が十分な良好評価を蓄積するまでは警告が出ます。逆に言えば、警告が出ないことは「多くの利用者が実行して問題が報告されていない」という統計的な事実であって、コードの検査結果ではありません。

同じページには、長らく誤解されてきた点についての明示があります。かつてExtended Validation(EV)コード署名証明書で署名するとSmartScreenの評価が初期から良好になりましたが、この挙動はもう存在しません。

Microsoft Learnの「SmartScreen reputation for Windows app developers」(2026年8月17日更新)は、SmartScreenが評価する二つのシグナルを、発行元の評判(署名されているか、署名証明書が既知の信頼できる発行元か)とファイルハッシュの評判(悪意ある挙動の兆候なくダウンロードされてきたか)としています。署名済みでも新しいバイナリは十分な良好評価を蓄積するまで警告が出ることがあり、評判が積み上がるまでには数週間と幅広い利用者による数百件のクリーンなインストールを要することがあると記載しています。EV証明書については「EV certificates no longer bypass SmartScreen」として、以前は既定で良好評価が付いたがこの挙動はもはや存在しないと述べています。

macOSでは、Gatekeeperと公証(notarization)の関係が誤解されがちです。Appleの開発者向けドキュメントは、公証について「macOSソフトウェアの公証はApp Reviewではありません」と明記したうえで、悪意あるコンテンツを自動でスキャンしコード署名の問題を確認する自動化されたシステムだと説明しています。

Appleの「Notarizing macOS software before distribution」は、公証の前提として、配布するすべての実行可能ファイルに有効なコード署名が付いていること、Developer IDの証明書を使うこと、Hardened Runtimeを有効にすること、コード署名にsecure timestampを含めることを挙げています。同ページは公証がApp Reviewではないと明記し、問題が無ければチケットが発行され、開発者がそれをソフトウェアにstapleでき、公証サービスがチケットをオンラインにも公開すると説明しています。macOS 10.15以降では、2019年6月1日以降にビルドされDeveloper IDで配布されるすべてのソフトウェアが公証を要すると記載されています。

ビルド来歴の分野でも同じ注意が必要です。SLSAの公式解説は、SLSAがソースコードを書いた開発者がセキュアコーディングの実践に従ったかどうかを示さないこと、意図的に悪意あるソフトウェアを作る組織には対処しないことを自ら明記しています。

三つの実装に共通する構図はこうです。署名や公証や来歴は「誰の責任で出たものか」を受け手が確定するための仕掛けであり、責任の所在が確定することと中身が良質であることは別です。責任の所在が確定するからこそ、事後に失効や排除という手段が使えるという点が効用の実体です。

タイムスタンプが期限切れを越えて署名を生かす仕組み

コード署名の証明書には有効期間があります。何もしなければ、期限が切れた瞬間に過去のリリースもすべて検証に失敗します。3年前に配ったインストーラが今日から未署名扱いになる、という事態です。これを避けるのがタイムスタンプです。

Microsoft Learnのタイムスタンプ解説は効果を端的に述べています。タイムスタンプが無いと署名証明書の期限切れ時点で署名は無効になり、Windowsはそのバイナリを未署名として扱う。カウンタ署名方式のタイムスタンプがあれば、署名証明書が期限切れになった後や失効した後でも署名の検証が可能になる。実装としては、元の署名(SignerInfoのencryptedDigest)をタイムスタンプサーバへ送り、返ってきたSignerInfoをPKCS #9のカウンタ署名として元のSignedDataへ差し込みます。カウンタ署名は未認証属性なので、署名済みのファイルに後から追加できます。

Microsoft Learnの「Time Stamping Authenticode Signatures」(2026年7月17日更新)は、Authenticodeのタイムスタンプが標準のPKCS #7カウンタ署名に基づくと説明し、「Authenticodeの署名には常にタイムスタンプを付けてください。タイムスタンプが無いと、署名証明書が期限切れになった時点で署名は無効になり、Windowsはそのバイナリを未署名として扱います」と記載しています。推奨設定はダイジェストアルゴリズムがSHA-256(/fd SHA256)、タイムスタンププロトコルがRFC 3161(/trフラグと/td SHA256)です。カウンタ署名方式は、署名証明書が期限切れになった後や失効した後でも署名の検証を可能にすると述べています。

タイムスタンプの信頼はTSA側の運用に依存します。RFC 3161(2001年8月)は、TSAへの要件として、信頼できる時刻源を使うこと、各トークンに信頼できる時刻値と一意な整数を含めること、データそのものではなくハッシュ表現のみにタイムスタンプを付けること、トークンに要求元の識別情報を含めないこと、この目的のためだけに生成した鍵で署名することなどを挙げています。要求元を記録しないという要件は、TSAが誰が何に署名したかの一覧を持たないことを意味します。

RFC 3161「Internet X.509 Public Key Infrastructure Time-Stamp Protocol (TSP)」(2001年8月)は、Time Stamping Authority(TSA)への要求と応答の形式、およびTSAの運用要件を定めています。タイムスタンプトークンには対象データのハッシュ、一意なシリアル番号、UTCでの生成時刻(genTime)、TSAのポリシー識別子、TSAの署名が含まれます。第2.1節はTSAへの要件として、信頼できる時刻源の使用、各トークンへの信頼できる時刻値と一意な整数の付与、データのハッシュ表現のみへのタイムスタンプ付与、トークンへの要求元識別情報の非包含、この用途専用に生成した鍵での署名などを列挙しています。

TSA側の鍵にも基準があります。CA/Browser ForumのCode Signing Baseline Requirementsは、2025年4月15日以降、有効期間が72か月を超えるタイムスタンプ関連のCA証明書の秘密鍵を、オフラインまたは他のネットワークから分離した高セキュリティゾーンのハードウェア暗号モジュールで生成し保護することを求めています。タイムスタンプ証明書の有効期間は135か月以内、TSAは証明書のnotBeforeから15か月を超えてその秘密鍵を使ってはならないとされています。長期にわたって過去の署名を裏書きし続ける役割ゆえの厳しさです。

CA/Browser Forumが定める署名鍵の保護要件

公的に信頼されるコード署名証明書を発行する認証局が従う基準が、CA/Browser ForumのBaseline Requirements for the Issuance and Management of Publicly-Trusted Code Signing Certificatesです。公式ページに掲載されている執筆時点の版はVersion 3.11.0、日付は2026年6月16日です。

中核となるのは第6.2.7.4.1節です。2023年6月1日以降、コード署名証明書の加入者秘密鍵は、FIPS 140-2 Level 2またはCommon Criteria EAL 4+以上に適合すると認証されたハードウェア暗号モジュールで生成し保護することを、認証局が契約上の表明として加入者から取得しなければなりません。認められる形は三つです。要件を満たすハードウェア暗号モジュールを使うこと。クラウドベースの鍵生成保護ソリューションを使うこと(鍵の生成と保管と使用がそのハードウェア暗号モジュールの境界内にとどまり、鍵を守るリソースへのすべてのアクセスと操作と設定変更をログに記録する構成であること)。または第6.2.7.3節の要件を満たす署名サービスを使うこと。

この日付の前後で業界の実態は変わりました。それ以前の非EV証明書は、秘密鍵をソフトウェアで生成してファイルとして持ち回ることが許されていました。ビルドサーバの中に.pfxファイルを置き、パスフレーズを環境変数で渡す構成は、当時は基準違反ではありませんでした。今は違います。

CA/Browser Forumが公開するCode Signing Baseline Requirementsの最新版ページには、Version 3.11.0、日付2026年6月16日と記載されています。第6.2.7.4.1節は、2023年6月1日以降、加入者の秘密鍵をFIPS 140-2 Level 2またはCommon Criteria EAL 4+以上に適合するハードウェア暗号モジュールで生成し保護することを認証局が契約上の表明として取得しなければならないと定め、モジュールの直接利用、条件を満たすクラウドベースの鍵生成保護ソリューション、第6.2.7.3節の要件を満たす署名サービスの3つを示しています。第6.2.7.3節は署名サービスに対して、コード署名の実行と認可に多要素認証またはサーバ間認証を強制すること、加入者の秘密鍵をFIPS 140-2 Level 3またはCommon Criteria EAL 4+以上のモジュールで保護することを求めています。第6.2.7.1節は認証局自身の鍵についてFIPS 140-2 Level 3、FIPS 140-3 Level 3、またはEAL 4以上を要求しています。第6.3.2節は、2026年3月1日より前に発行された証明書の有効期間は39か月以内、同日以降に発行されたものは460日以内と定めています。第4.9.1.1節は、加入者の秘密鍵が危殆化した証拠を得た場合や証明書が疑わしいコードの署名に使われたと合理的に確信できる場合、認証局が24時間以内に失効させなければならないとしています。第7.2.2節に関する適用日一覧には、2022年7月1日以降、コード署名証明書についてInvalidity Date CRLエントリ拡張に符号化される時刻がCRLエントリのrevocationDateフィールドの時刻と等しくなければならないと記載されています。

要求水準が主体ごとに階段状になっている点は見ておく価値があります。認証局自身の鍵はFIPS 140-2 Level 3相当、署名サービスが預かる加入者鍵も同じ水準、加入者が自分で持つ鍵はLevel 2相当。鍵1本が守る対象の広さに応じて水準が上がる構造で、他者の鍵を預かる立場になった時点で要求は一段厳しくなります。

有効期間の短縮も運用に直接効きます。第6.3.2節は2026年3月1日以降に発行する証明書の有効期間を460日以内と定めました。それ以前は39か月まで許されていたので、3年に1度で済んでいた更新作業がおよそ15か月に1度へ変わります。手作業の更新を前提にした運用は、この頻度では持ちません。

鍵の置き場所を三つの方式で比べる

基準が求める水準を満たす置き場所は、実務では三つに整理できます。

方式鍵の所在署名を実行する場所主な運用負荷
自社運用のHSM自社データセンタ内の物理モジュールHSMに接続した署名専用ホスト物理管理、バックアップ、災害対策、監査
クラウドの鍵管理サービス事業者のHSM境界内呼び出し元のCIジョブIAM設計、ネットワーク到達性、ログ収集
マネージド署名サービス提供者のHSM境界内サービス側身元確認の更新、ロール割り当て、署名履歴の監視

Microsoftが自社の推奨として提示しているのは三つ目です。Windows向け配布の公式ページは、Microsoft Store以外の経路で配布する開発者にAzure Artifact Signing(旧Trusted Signing)を推奨し、費用は月額約9.99ドル、物理トークンは不要でCI/CDパイプラインへ直接組み込めると説明しています。ただし提供地域は組織向けが米国、カナダ、欧州連合、英国、個人開発者向けは米国とカナダに限られます。日本の組織は現時点でこの選択肢を取れないため、従来型のOV証明書と自社側の鍵保護を組み合わせる構成が現実的です。同ページはOV証明書について、2023年6月以降CA/Browser Forumの要求により秘密鍵をハードウェアセキュリティモジュールまたはハードウェアトークンに保管する必要があり、多くの認証局が互換のUSBトークンまたはクラウドHSMの選択肢を提供していると記載しています。

マネージド署名サービスの設計思想は、使えるかどうかとは別に参考になります。公式FAQは、署名プロファイルで使われるAuthenticode証明書が利用者へ渡されることは決してなく、すべての証明書はサービス内に保管され署名の瞬間にのみアクセス可能だと述べています。コンプライアンス水準はFIPS 140-3 Level 3です。

Azure Artifact Signing(旧Trusted Signing)の公式FAQ(2026年8月14日更新)は、コンプライアンス水準を「FIPS 140-3 Level 3」と明記しています。証明書の扱いについては「署名プロファイルで使われるAuthenticode証明書が利用者に渡されることはありません。すべての証明書はサービス内に安全に保管され、署名の時点でのみアクセスできます」と記載しています。マルウェア対策のELAM構成の項では、マルウェア対策バイナリ署名用に発行されるAuthenticode証明書はセキュリティのため有効期間が3日だと述べています。証明書プロファイルを削除しても既に発行された証明書は失効せず、その署名も無効にならないとも明記されています。EV証明書は発行せず、今後も発行する計画は無いとされています。

FAQのもう一つの記述も見逃せません。証明書プロファイルを削除しても、既に発行済みの証明書は失効せず署名も無効にならない、という一文です。署名サービスの利用をやめても過去の署名は生き続けます。撤収は失効ではありません。

秘密情報をどこに置くかという設計は、コード署名鍵に限らず共通の課題です。

あわせて読みたい

シークレット管理の実務。APIキー・認証情報をハードコードせず、Vaultやマネージドサービスで守りローテーションする

ビルドサーバに秘密鍵を置かない構成へ移す手順

既存のリリース工程に.pfx.p12がファイルとして存在している場合、置き換えは段階的に進めます。いきなり本番の署名を止めると出荷が止まるため、並行運用の期間を取ります。

  1. 1

    署名している対象と署名鍵を棚卸しする

    実行ファイル、インストーラ、ドライバ、コンテナイメージ、スクリプト、パッケージ、ファームウェアのうち、どれに署名しているかを一覧にします。その署名に使っている鍵と証明書が何本あるか、どこに保管され、誰がアクセスできるかを記録します。開発用のテスト鍵と本番鍵が同じルートにつながっていないかもここで確認します。
  2. 2

    ビルドサーバとリポジトリを鍵の痕跡で検索する

    リポジトリの履歴、CIの環境変数、コンテナイメージのレイヤ、ビルドエージェントのディスク、共有ストレージを対象に、pfxやp12やkeyやpemといった拡張子と、証明書のシリアル番号や指紋で検索します。過去のコミットに一度でも入ったものは削除しても履歴から取り出せます。見つかった鍵は漏えい済みとして扱うのが安全側の判断です。
  3. 3

    署名を実行する専用の経路を1本作る

    ハードウェアトークン、HSM、クラウドの鍵管理サービス、マネージド署名サービスのいずれかを選び、署名処理をそこへ集約します。ビルドジョブは成果物のハッシュを送って署名を受け取るだけにし、鍵にも証明書にも触れない形にします。この経路は本番専用とし、開発用の署名は別系統の鍵で行います。
  4. 4

    新旧の経路で並行して署名し、検証結果を比較する

    同じ成果物に旧経路と新経路の両方で署名し、受け手側の検証コマンドで両者が同じように通ることを確認します。Windowsならsigntool verify、macOSならcodesignとspctl、Linuxならパッケージマネージャの検証結果を突き合わせます。タイムスタンプが付いていることもここで確認します。
  5. 5

    旧鍵での署名を停止して鍵を破棄する

    切り替え後、旧鍵での署名を止めます。ファイルとして存在していた鍵は保管場所とバックアップの両方から確実に消します。証明書自体を失効させるかどうかは、その鍵で署名した過去のリリースへの影響を評価してから決めます。停止した日付を記録に残します。
  6. 6

    署名ログの監視と定期レビューを組み込む

    誰がいつ何に署名したかの記録を収集し、想定外の署名イベントに気づける状態にします。証明書の有効期限、身元確認の有効期限、ロール割り当ての妥当性を定期的に見直す運用を決めます。有効期間が460日以内になったことで、更新は定常業務として計画に組み込む必要があります。

棚卸しは次のような検索から始められます。対象は自組織が管理するリポジトリと環境に限ってください。

# リポジトリの現在のツリーとhistoryの両方から鍵ファイルの痕跡を探す
git ls-files | grep -Ei '\.(pfx|p12|pem|key|jks|keystore)$'
git rev-list --objects --all | \
  git cat-file --batch-check='%(objecttype) %(objectname) %(rest)' | \
  grep '^blob' | grep -Ei '\.(pfx|p12|pem|key)$'

# 成果物の署名とタイムスタンプを確認する
signtool verify /pa /v /all MyApp.exe                    # Windows
codesign --verify --deep --strict --verbose=2 MyApp.app  # macOS
spctl --assess --type execute --verbose MyApp.app        # macOS(Gatekeeper判定)
rpm --checksig package.rpm                               # RPM

署名を実行する権限の分離と承認の設計

鍵をHSMへ入れても、その鍵で誰でも署名できるなら守りの効果は限られます。NISTのホワイトペーパーが挙げる推奨事項はこの点に集中しています。コードを署名できる者と署名を依頼できる者を識別し認証すること。誰がどのコードを提出できるかを一覧で管理し定期的に見直すこと。署名の承認に2名を要求することや多要素認証の利用を検討すること。CSSの管理者役割と署名依頼者役割を別の人物へ割り当てること。開発用のCSSを物理的または論理的に分け、開発鍵が本番鍵と同じルート鍵につながらないようにすること。

役割分離はクラウドのマネージドサービスにも実装されています。Azure Artifact SigningのFAQには、身元確認を行うIdentity Verifierロールと、署名を実行するCertificate Profile Signerロールが登場します。身元を通す人と署名を打つ人を別のロールへ割り当てられる構造です。自社でHSMを運用する場合も、この二つの権限は別の人物に持たせます。

NIST SP 800-218「Secure Software Development Framework (SSDF) Version 1.1」のPS.1.1は、すべての形態のコードを最小権限の原則に基づいて保管することを求め、実装例としてリポジトリのコミット署名の使用とコード署名による実行ファイルの完全性保護を挙げています。PS.2「Provide a Mechanism for Verifying Software Release Integrity」の実装例には、リリースファイルの暗号学的ハッシュを十分に保護されたWebサイトへ掲示すること、利用者のOSやツールが署名の有効性を確認できるよう確立された認証局をコード署名に使うこと、証明書の更新、ローテーション、失効、保護を含むコード署名プロセスを定期的に見直すことが並んでいます。

承認プロセスで決めるべきことは四点に集約できます。署名対象をタグ名やブランチ名ではなくコミットハッシュと成果物ハッシュで特定すること。承認者を複数にして、1アカウントの乗っ取りで統制が消えない形にすること。承認の記録を署名サービス側の履歴とチケットシステムで突き合わせられる形に残すこと。そして緊急時の例外経路を設計すること。例外経路が無いと現場で迂回路が作られ、例外経路が緩いとそこが常用されます。

CIパイプラインのどこで何に署名するか

署名を挟む位置は、パイプラインの中で二か所あります。ビルドの直後と、配布の直前です。

ビルド直後に署名する構成は、成果物がビルド環境を出る瞬間から保護されます。ただし署名鍵を呼び出す権限がビルドジョブに与えられるため、ビルドスクリプトを書き換えられる人が実質的に署名できることになります。プルリクエストのマージ権限が署名権限と同義になる、と言い換えられます。

配布直前に署名する構成は、テストと承認を通過した後で署名するため、承認と署名の対応が明確になります。一方でビルドからリリースまでの間、成果物は署名されていない状態でアーティファクトストアに置かれます。この区間の完全性は、ストア側のアクセス制御とハッシュの記録で守る必要があります。

NIST SP 800-204Dは、この区間を証跡で埋める考え方を示しています。最終ビルド成果物とファイルとライブラリのハッシュ、および全イベントを収集し、それを開発者の制御下にないビルドフレームワークの信頼されたコンポーネントがデジタル証明書で署名してアテステーションを作る、という設計です。署名する主体をビルドを書いた人から切り離すことで、消費者側が生産者から独立して検証できるようにします。

NIST SP 800-204D「Software Supply Chain Security in DevSecOps CI/CD Pipelines」(2024年2月)は、ビルドに関するアテステーションを環境、プロセス、材料、成果物の4種類に分類しています。証跡の生成については、最終ビルド成果物やファイル、ライブラリ、その他の材料のハッシュおよび全イベントを収集し、それを開発者の制御下にないビルドフレームワークの信頼されたコンポーネントがデジタル証明書で署名してアテステーションを作ることを求めています。署名された証跡の要件として、アテステーションが安全な鍵で暗号学的に署名されること、保管場所が改ざん耐性を持ち堅牢なアクセス制御で保護されることを挙げています。

実務上の折衷案としては、自動署名の対象と承認後にのみ署名する対象を分けます。開発ビルドやナイトリービルドは開発用の鍵で自動署名し、公開リリースだけを別の鍵と承認経路に通す形です。この分離は前節の「開発用CSSを分ける」推奨と同じ考え方です。

CIパイプライン全体をどう守るかという話は、次の記事で扱っています。

あわせて読みたい

サプライチェーン攻撃の構造と防御の考え方。ソフト・ハード・サービス経由の侵入をどう減らすか

SLSAのビルド来歴とSigstoreの鍵を持たない署名

署名が「誰が」を答えるのに対し、ビルド来歴(provenance)は「どうやって作られたか」を答えます。SLSAは、この来歴の生成と検証を段階的な要求水準として整理した枠組みです。

SLSA v1.1のSecurity Levelsページは、Buildトラックを4段階に定義しています。Build L0は保証無し、Build L1は「どのように作られたかを示す来歴」の存在を求めるが不完全または未署名の来歴でもよく偽造は容易だと明記されています。Build L2はビルドプラットフォーム自身が来歴を生成して署名することを求め、ビルド後の改ざんを防ぎます。Build L3はビルド実行間の隔離と、利用者定義のビルドステップからのシークレットの分離という強い統制を求め、ビルド中の改ざんを防ぎます。来歴の真正性については、署名以外の手段による検証も許容されると記載されています。

来歴の中身も定義されています。SLSA v1.1のProvenanceはbuildDefinitionとrunDetailsの二つの部分から成り、前者にはビルドの種類を示すbuildType、利用者が制御し検証対象となるexternalParameters、初期化と実行の過程で取得された成果物を記録するresolvedDependenciesが、後者には信頼されたビルドプラットフォームの識別子であるbuilder.idや実行の開始終了時刻が入ります。ただしSLSAの公式解説は、この枠組みがソースコードの品質や悪意の有無を扱わないことを自ら明記しています。来歴の検証は「宣言どおりのビルド環境から出たか」を確かめるものです。

SLSA v1.1のAboutページは、SLSAを「段階的に採用可能なサプライチェーンセキュリティのガイドライン集」と位置付けています。適用範囲の限界として、SLSAがソースコードを書いた開発者がセキュアコーディングの実践に従ったかどうかを示さないこと、意図的に悪意あるソフトウェアを作る組織には対処しないことを明記しています。また、成果物とその推移的依存関係の両方をまとめて表す単一のセキュリティレベルは提供できないとしています。

長期の署名鍵を安全に保管し続けることが難しいなら、鍵を長期に保持しなければよい。Sigstoreはこの発想を実装した仕組みです。署名者は一時的な鍵ペアをメモリ上で生成し、OpenID Connectで身元を認証したトークンをFulcioへ提示します。Fulcioは身元と一時公開鍵を結び付けた有効期間10分の証明書を発行します。署名を行った後、一時秘密鍵は直ちに破棄されます。

Sigstoreの公式ドキュメントは、Fulcioを「誰でも利用できる短命の証明書を提供するために作られた無料のコード署名認証局」と説明し、Fulcioが発行する証明書は有効期間が10分だと記載しています。身元の結び付けはOpenID Connectを通じて行われ、FulcioはOpenID Connectのメールアドレスに基づいてX.509証明書に署名します。証明書透明性ログによって監査可能な公開サービスとして設計されており、自己ホストによる運用にも対応するとされています。

有効期間10分の証明書で署名したものが10分後に検証できなくなっては困ります。ここを埋めるのがRekorです。Rekorは追記専用のMerkleツリー構造を持つ透明性ログで、署名イベントを検証可能な形で記録します。検証者は、証明書が既に期限切れであっても、その署名がログに記録された時刻で証明書が有効だったことを確認できます。役割はRFC 3161のTSAと同じ位置ですが、記録が公開の追記専用ログである点が異なります。自分の身元で署名が行われたことが公開ログに残るため、身元を乗っ取られた場合に本人がそれを検知できます。

Sigstoreの公式ドキュメントは、Rekorを「ソフトウェアプロジェクトのサプライチェーンで生成されたメタデータについて、不変で改ざん耐性のある台帳を提供することを目指す」ものと説明しています。Trillianによる検証可能なデータ構造(Merkleツリー)を用い、ログが追記専用でエントリが変更または削除されることは決してないとしています。署名者は自分の身元がログに現れることを監視でき、想定外の署名イベントが起きたことを知ることができるとされています。

検証側では注意点があります。cosignでkeylessの署名を検証するとき、公式ドキュメントの例はcosign verify <image URI> --certificate-identity=name@example.com --certificate-oidc-issuer=https://accounts.example.comという形です。この二つの制約を書かなければ、Sigstoreで署名されたものなら誰の署名でも通ってしまいます。誰でも10分の証明書を取れる仕組みなので、検証条件は「署名されていること」ではなく「特定の身元で署名されていること」にします。

# keyless署名の検証。身元と発行者を必ず固定する
cosign verify ghcr.io/example/app:1.2.3 \
  --certificate-identity-regexp '^https://github.com/example/app/\.github/workflows/release\.yml@refs/tags/' \
  --certificate-oidc-issuer https://token.actions.githubusercontent.com

来歴と成分表を組み合わせると、事故時の対応速度が変わります。成分表の作り方と使い方は次の記事で整理しています。

あわせて読みたい

2026年版の最小要素で見直すSBOMの作り方と脆弱性管理での使い方

受け手側で署名の検証を強制する設定

署名を付ける側の努力は、受け手が検証しなければ効果を生みません。NISTのホワイトペーパーが検証者への推奨として挙げているのは、証明書の検証(署名が有効で認可された認証局からのものであること、有効期間と鍵用途フィールドの確認)、タイムスタンプの検証、署名の検証、そして失効の確認です。失効については、検証者が失効を確認できるか、あるいはトラストアンカーを安全に更新する仕組みを持つべきだとしています。

Windowsで組織的に強制する手段がApp Control for Business(旧WDAC)です。ポリシーのファイルルールレベルは、ハッシュ単位の限定的なものから証明書単位の広いものまで段階が用意されています。Publisherレベルは、PCA証明書(通常はルートの1つ下)とリーフ証明書のCommon Nameを組み合わせたもので、特定の認証局が特定の企業へ発行した証明書を信頼する形になります。

Microsoft LearnのApp Control for Businessのルール解説(2026年3月31日更新)は、ファイルルールレベルとしてHash、FileName、FilePath、SignedVersion、Publisher、FilePublisher、LeafCertificate、PcaCertificate、WHQLなどを定義しています。Hashレベルはバイナリごとに個別のAuthenticode/PEイメージハッシュを指定する最も限定的なレベルで、バイナリが更新されるたびにポリシーの更新が必要になると記載されています。LeafCertificateレベルは、新バージョンでハッシュ値が変わっても署名証明書は通常同じであるという利点があると説明されています。ポリシールールオプションの0番(Enabled:UMCI)は、既定ではカーネルモードのバイナリのみが制限対象であり、有効にするとユーザーモードの実行ファイルとスクリプトも検証されるとしています。20番(Enabled:Revoked Expired As Unsigned)は、失効した証明書や期限切れ証明書で署名されたバイナリを未署名として扱うオプションです。Authenticode/PEイメージハッシュの計算はファイルのチェックサム、Certificate Table、Attribute Certificate Tableを除外するため、署名やタイムスタンプが変更されてもハッシュは変わらないと記載されています。

ハッシュルールと署名者ルールにはトレードオフがあります。ハッシュルールはバイナリが1バイトでも変わればポリシー更新が必要です。署名者ルールは新しいバージョンを自動的に許可するため更新は不要ですが、その発行元が今後出すすべてのバイナリを事前に信頼することになります。署名鍵が漏れた発行元を署名者ルールで許可していた場合、攻撃者が署名した任意のバイナリが許可されます。

macOS側ではGatekeeperが既定の検証者です。Appleのプラットフォームセキュリティガイドは、Gatekeeperがソフトウェアについて識別された開発者のものであること、既知の悪意あるコンテンツを含まないとAppleが公証したこと、改変されていないことを検証すると述べています。既定では、ダウンロードされたすべてのソフトウェアがApp Storeによって署名されているか、登録済み開発者によって署名されAppleによって公証されている必要があります。

Appleのプラットフォームセキュリティガイド「Gatekeeper and runtime protection in macOS」は、Gatekeeperがソフトウェアについて、識別された開発者のものであること、既知の悪意あるコンテンツを含まないとAppleが公証したこと、改変されていないことを検証すると記載しています。既定の設定では、ダウンロードされたすべてのソフトウェアはApp Storeによって署名されているか、登録済みの開発者によって署名されAppleによって公証されている必要があるとされています。macOS上のすべてのソフトウェアは、到達経路にかかわらず初回起動時に既知の悪意あるコンテンツの有無を確認されると述べています。

Linuxのパッケージリポジトリでは、個々のパッケージではなくリポジトリのメタデータに署名を付ける方式が使われます。Debian WikiのSecureAptの解説によれば、検証は三段の連鎖です。個々のパッケージのチェックサムがPackagesファイルに載り、Packagesファイルのチェックサムが Releaseファイルに載り、ReleaseファイルにOpenPGPの署名が付きます。この方式が守るのは「リポジトリの管理者が承認した内容が配信経路で書き換えられていないこと」であって、パッケージの中身の安全性ではありません。

Debian WikiのSecureAptの解説は、aptの検証が三段の連鎖で成り立つことを説明しています。Releaseファイルにはアーカイブ内の他のファイルのチェックサムが含まれ、Packagesファイルの中にはそこに列挙された各パッケージのチェックサムが入っています。署名されていないReleaseファイルでは意味が無いため、secure aptはReleaseファイルに対するOpenPGP署名を追加し、それをReleaseファイルと並んで配布されるRelease.gpgというファイルに格納します。secure aptはReleaseファイルをダウンロードするときに常にRelease.gpgもダウンロードし、取得できない場合や署名が不正な場合は警告するとされています。信頼するキーの設定は利用者の責任で、公式のDebianアーカイブについてはdebian-archive-keyringパッケージが用いられます。

どの環境でも、検証を有効にしただけでは足りません。検証が失敗したときに何が起きるかを確認します。警告を出して続行する構成になっていると、実質的に検証していないのと変わりません。

署名鍵が漏れたときに実際に起きること

鍵が攻撃者の手に渡った場合に起きることは三つです。

第一に、攻撃者は任意のバイナリに正規の発行元名で署名を付けられます。受け手のOSは発行元名を表示し、実行制御ポリシーが署名者ルールでその発行元を許可していれば、そのバイナリは実行を許可されます。

第二に、正規のリリースと攻撃者のバイナリを署名だけでは区別できなくなります。両方とも同じ証明書で有効な署名を持ちます。区別できるのは、正規のリリースとして自社が記録したハッシュ値と突き合わせた場合だけです。署名履歴のログとリリースごとのハッシュ台帳を持っているかどうかが、ここで効いてきます。

第三に、対応の選択肢が「証明書を失効させる」ことに集約されます。そして失効は、攻撃者のバイナリだけを狙って止めることができません。

ただし、鍵が漏れなくても同じ結果になる経路があります。冒頭で触れたSolarWinds Orionの事案がそれです。署名処理そのものは正常に動作しました。署名される前の入力が汚染されていたためです。

CISAのアドバイザリAA20-352A「Advanced Persistent Threat Compromise of Government Agencies, Critical Infrastructure, and Private Sector Organizations」(最終改訂2021年4月15日)は、攻撃者がsolarwinds.orion.core.businesslayer.dllの悪意あるバージョンをSolarWindsのソフトウェアライフサイクルへ追加し、それが正規のSolarWindsコード署名証明書で署名されたと記載しています。同アドバイザリはこれをSolarWinds Orion製品のサプライチェーン侵害と位置付け、悪意あるコードが公開後ではなくソフトウェア開発ライフサイクルの過程で挿入されたことを説明しています。

同様の構図は繰り返し観測されています。CISAは2023年3月30日のアラートで、音声およびビデオ会議アプリである3CXDesktopAppがトロイの木馬化され、脆弱なアプリを使う利用者に対する多段階の攻撃につながる可能性があると告知しました。配布されたインストーラはベンダー自身の正規の署名を持っていました。

この二つの事例が示すのは、鍵の保護と署名対象の統制が別々の防御だということです。鍵をFIPS 140-3 Level 3のHSMへ入れても、そのHSMへ送られてくるバイトが汚染されていれば、HSMは正しく署名を返します。

失効の日付が影響範囲を決める理由

失効の難しさは時間の扱いにあります。証明書失効リスト(CRL)のエントリには失効日時を示すrevocationDateがあります。CA/Browser ForumのCode Signing Baseline Requirementsは、2022年7月1日以降、コード署名証明書についてInvalidity Date CRLエントリ拡張の時刻がCRLエントリのrevocationDateフィールドの時刻と等しくなければならないと定めています。失効は「この日時から無効」という遡及的な意味を持ちます。

ここにタイムスタンプが絡みます。失効日時より前にタイムスタンプされた署名は有効なまま残り、後にタイムスタンプされた署名は無効になります。この境界線をどこに引くかが、対応の設計そのものになります。境界線を鍵の危殆化が疑われる日に引くと、その日以降に出荷した正規のリリースもすべて無効になります。境界線を今日に引くと、攻撃者が既に署名して配布したバイナリは有効なまま残ります。どちらを選んでも痛みが伴います。

注意

失効の日時は自社の一存では決まりません。CA/Browser Forumの基準は、加入者の秘密鍵が危殆化した証拠を認証局が得た場合、認証局が24時間以内に証明書を失効させなければならないと定めています。証明書が疑わしいコードの署名に使われたと合理的に確信できる場合も同じです。危殆化を認証局へ報告した時点で、失効のタイミングと日付は認証局側の判断に移ります。報告の前に影響範囲の試算と再署名の準備を進めておく必要があります。

タイムスタンプが付いていない署名の場合、話はもっと単純です。証明書が失効した瞬間、あるいは期限切れになった瞬間に、その証明書で署名したすべての成果物が未署名扱いになります。タイムスタンプの有無は、事故のときに最も効いてきます。

鍵の危殆化を疑った場合の手順は次のとおりです。

  1. 1

    署名履歴と成果物ハッシュを突き合わせる

    署名サービスやHSMの監査ログから期間内の署名一覧を取り出し、自社のリリース台帳のハッシュ値と突き合わせます。身に覚えのない署名が見つかれば、その最も古い時刻が危殆化の下限になります。ログが無ければ開始時刻を特定できず、失効日を保守的に古く取らざるを得なくなります。
  2. 2

    その鍵で署名した配布物と配布先を洗い出す

    自社のダウンロードサイト、ミラー、パッケージリポジトリ、ソフトウェア配布ツール、OEM経由の同梱、既に導入済みのバージョンまでを列挙します。失効させた場合に検証が壊れる対象がここに並びます。オフラインのエンドポイントや失効情報を取得できない環境の存在も確認します。
  3. 3

    新しい鍵と証明書を先に用意する

    失効を要求する前に、新しい鍵ペアをハードウェア暗号モジュール内で生成し証明書を取得しておきます。身元確認に日数がかかるため、失効してから申請すると再配布までの空白が伸びます。新しい鍵は、危殆化した経路とは独立した保管と権限設計にします。
  4. 4

    失効の日時を決めて認証局へ報告する

    調査で得た危殆化の時刻と、その日以降の正規リリースの本数を並べて境界線を決め、決定の根拠を記録に残します。認証局へは判断材料としてこの調査結果を添えて報告します。認証局は基準に従って24時間以内に失効させます。
  5. 5

    影響を受けるリリースを再署名して配り直す

    失効日以降にタイムスタンプされた正規のリリースは、新しい証明書で再署名し新しいタイムスタンプを付けて再配布します。告知には旧証明書のシリアル番号と失効日、新しい証明書の指紋を明記します。利用者が実行制御ポリシーで旧証明書を許可している場合、その更新も依頼します。
  6. 6

    受け手側の許可リストと監視を更新する

    自社が管理するエンドポイントでは、実行制御ポリシーの署名者ルールから旧証明書を外し新しい証明書を追加します。旧証明書で署名されたバイナリの実行を検知したらアラートを上げる監視をしばらく残します。旧証明書のシリアル番号と指紋は脅威情報として社内へ配布します。

Appleのエコシステムには、証明書の失効とは別の手段があります。開発者向けドキュメントは、公証がDeveloper IDの署名鍵が露出した場合にも利用者を保護すると述べ、公証サービスがその署名鍵で配布されたソフトウェアの監査証跡を保持していること、許可していないバージョンが見つかった場合はAppleと連携してそれらのバージョンに紐づくチケットを失効できることを説明しています。証明書全体を失効させずに特定のビルドだけを止められる仕組みで、個別のビルドを狙って止められるかどうかは事故対応の柔軟性を大きく変えます。

署名済みの正規バイナリが悪用されるサイドローディング

署名を付けることには副作用があります。正規の署名を持つ実行ファイルは、攻撃者にとって使い道のある部品になります。

DLLサイドローディングは、署名済みの正規アプリケーションを起動させ、そのアプリケーションが読み込む外部DLLを攻撃者の用意したものに差し替える手法です。実行を始めるプロセスは正規の署名を持つため、署名者ルールで許可された実行制御ポリシーを通過します。悪意ある処理は、署名の対象外であるDLLの側に置かれます。

対策として実行制御ポリシーを署名者ルールで組む場合、この抜け道を意識する必要があります。Publisherレベルのルールはその発行元の署名を持つすべてのバイナリを許可します。App Control for Businessでユーザーモードのバイナリまで検証対象にするには、ポリシールールオプションの0番(Enabled:UMCI)を有効にする必要があります。既定ではカーネルモードのバイナリだけが制限対象です。

自社が配布するソフトウェアの側でできることもあります。読み込む外部モジュールのパスを絶対パスで指定すること、読み込むDLLの署名を自前で検証すること、配布物に含める依存ライブラリを最小限にすること。署名を付けた実行ファイルが第三者の攻撃の踏み台にされることは、自社ブランドの毀損として跳ね返ります。

この手法の詳細と対策は、次の記事で扱っています。

あわせて読みたい

DLLサイドローディングとは何か。署名済み正規アプリが悪用される仕組みと対策

署名アルゴリズムの耐量子移行という次の課題

署名鍵の管理には、もう一つの時間軸があります。使っている署名アルゴリズムそのものの寿命です。

NISTはFIPS 204(Module-Lattice-Based Digital Signature Standard、ML-DSA)とFIPS 205(Stateless Hash-Based Digital Signature Standard、SLH-DSA)を確定しました。いずれも量子計算機を持つ攻撃者に対しても安全と考えられる署名方式です。前述のNISTホワイトペーパーも、脅威の一つとして「暗号学的に意味のある量子計算機の開発」が既に配備されたシステムを安全でなくする可能性を挙げています。

コード署名は、この移行で特に扱いが難しい領域です。理由は寿命の長さにあります。今日署名したファームウェアは10年後も同じ検証コードで検証されます。検証側のコードを後から書き換えられない機器では、署名アルゴリズムを後から変えることができません。

NIST SP 800-208「Recommendation for Stateful Hash-Based Signature Schemes」は、ステートフルなハッシュベース署名方式が慎重な状態管理を必要とするため一般用途には適さないとしています。主な対象用途として、近い将来にデジタル署名方式を実装する必要があること、その実装が長い寿命を持つこと、一度配備した後に別の署名方式へ移行することが現実的でないことの3つの特性を持つ場合を挙げ、この条件に合致しうる例として制約デバイス向けのファームウェア更新の認証を示しています。近い将来に配備される制約デバイスの中には数十年にわたって使われるものがあり、更新の署名を検証するコードを配備後に変更することが現実的でない場合があると述べています。状態管理については、同じ一回限り署名(OTS)鍵で2つの異なるメッセージの署名が得られると任意のメッセージへの署名偽造が計算上可能になるため、OTS鍵の再利用を決して起こさないよう細心の注意が必要だとしています。

実務としては、まず自社が署名に使っているアルゴリズムと鍵長を棚卸しし、検証側のコードを更新できる経路があるかを確認します。ファームウェアのように後から変えられない対象と、アプリケーションのように配布のたびに検証系ごと更新できる対象とでは、移行の緊急度が違います。

移行の全体像は、次の記事で整理しています。

あわせて読みたい

ポスト量子暗号(PQC)への移行。量子コンピュータが暗号を破る前に備える

署名鍵管理の点検リスト

ここまでの内容を、自組織の現状確認に使える形に並べます。

コード署名の運用点検

  • 署名している対象(実行ファイル、インストーラ、ドライバ、コンテナイメージ、パッケージ、ファームウェア、スクリプト)を一覧化し、それぞれに使っている鍵と証明書を対応付けた
  • すべての署名鍵がハードウェア暗号モジュール、または鍵が外へ出ないクラウドサービスの中で生成され、エクスポートできない状態であることを確認した
  • リポジトリの履歴、CIの環境変数、コンテナイメージ、ビルドエージェントのディスクを鍵ファイルの拡張子と証明書の指紋で検索し、平文の鍵が残っていないことを確認した
  • 開発用の署名鍵と本番用の署名鍵を分け、両者が同じルート証明書につながっていないことを確認した
  • 署名を依頼できる人と承認できる人と署名基盤を管理できる人を別の役割として定義し、実際の権限割り当てが定義どおりであることを確認した
  • すべての署名にRFC 3161のタイムスタンプを付けており、タイムスタンプサーバの到達性が監視されていることを確認した
  • 証明書の有効期間が460日以内になったことを踏まえ、更新の予定日と担当者と手順を年次の計画に組み込んだ
  • 署名の実行ログを収集し、リリース台帳のハッシュ値と突き合わせられる形で保管していることを確認した
  • 自社が配布した各リリースの成果物ハッシュを、配布後も参照できる形で記録していることを確認した
  • 鍵の危殆化を疑った場合の連絡先(認証局の届出窓口)、失効日の決定手順、再署名と再配布の手順を文書にした
  • 受け手側でパッケージやコンテナの署名検証を有効にし、検証失敗時に処理が止まる設定になっていることを確認した
  • 実行制御ポリシーを署名者ルールで組んでいる場合、ユーザーモードのバイナリまで検証対象に含めているかを確認した
  • 署名しているソフトウェアが読み込む外部モジュールについて、絶対パス指定や署名検証などのサイドローディング対策を実装しているか確認した
  • 使用中の署名アルゴリズムと鍵長を棚卸しし、検証側のコードを後から更新できない配布対象を特定した

署名は身元の記録であって品質の証明ではない

コード署名の運用を組み立てるときに立ち返る前提は、冒頭に書いた一点に尽きます。署名は「誰が出したか」と「途中で変わっていないか」を受け手が確かめるための仕組みであって、中身の性質については何も述べていません。

この前提を受け入れると、投資先の優先順位が自然に決まります。鍵をハードウェア暗号モジュールへ入れることは、CA/Browser Forumの基準が要求する最低線であり、そこは満たすべきです。しかし鍵を守るだけでは署名される内容は守れません。何に署名するかを決める承認の経路、署名した記録を残す監査ログ、署名された成果物のハッシュ台帳。この三つが揃って初めて、事故が起きたときに「どこまでが正規で、どこからが偽物か」を言えるようになります。

言えるようになることが、対応の速度を決めます。署名履歴とハッシュ台帳が無ければ危殆化の時刻を特定できず、失効日を保守的に古く取るしかなくなります。すると無事だった正規のリリースまで無効になり、再署名と再配布の対象が膨らみます。ログを残す作業は普段は何の役にも立ちませんが、事故の日には影響範囲を数分の一に縮める働きをします。

証明書の有効期間は短くなり続け、更新の頻度は上がっています。署名鍵の保護要件は基準として明文化され、ハードウェアでの保管が前提になりました。マネージド署名サービスは鍵を利用者に渡さない設計へ進み、Sigstoreは長期の鍵そのものを持たない方向へ舵を切りました。どの流れも「鍵を長く手元に置くほど危ない」という一つの認識から出ています。手元に置く期間を短くする方向で自社の構成を見直すことが、この分野で最も確実な改善になります。

出典・参考

この記事をシェア

関連する記事