コード署名の仕組みと署名鍵の管理。誰が作ったかを証明する仕掛けと、鍵が漏れた後に起きること
対象の目安: ソフトウェアを配布する開発者とリリース担当 / 実務

インストーラをダブルクリックしたときに「発行元: 株式会社なんとか」と表示されると、その画面は安心の合図として受け取られます。しかし表示が伝えているのは、このファイルにその会社の秘密鍵で署名が付いていて、署名後にファイルが変わっていないという二点だけです。中身が安全かどうかについて、署名は何も言っていません。
この差は理屈の話ではありません。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」は、この点を役割の分解として説明しています。同文書は関与者を開発者、署名者、検証者の三つに分け、署名者について「署名者は技術的および手続き的な統制によって、認可されたコードのみが署名されることを保証する」と書いています。署名対象が信頼に足るかを担保するのは暗号ではなく、署名の手前に置かれた承認プロセスです。暗号はその承認結果を改ざん不能な形で受け手へ運ぶ配管にすぎません。
この整理から、守る対象が二層に分かれることが見えてきます。下の層は鍵そのものの秘匿で、上の層は「何に署名するか」を決める意思決定の統制です。下の層だけを固めても、上の層が緩ければ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の評価が初期から良好になりましたが、この挙動はもう存在しません。
macOSでは、Gatekeeperと公証(notarization)の関係が誤解されがちです。Appleの開発者向けドキュメントは、公証について「macOSソフトウェアの公証はApp Reviewではありません」と明記したうえで、悪意あるコンテンツを自動でスキャンしコード署名の問題を確認する自動化されたシステムだと説明しています。
ビルド来歴の分野でも同じ注意が必要です。SLSAの公式解説は、SLSAがソースコードを書いた開発者がセキュアコーディングの実践に従ったかどうかを示さないこと、意図的に悪意あるソフトウェアを作る組織には対処しないことを自ら明記しています。
三つの実装に共通する構図はこうです。署名や公証や来歴は「誰の責任で出たものか」を受け手が確定するための仕掛けであり、責任の所在が確定することと中身が良質であることは別です。責任の所在が確定するからこそ、事後に失効や排除という手段が使えるという点が効用の実体です。
タイムスタンプが期限切れを越えて署名を生かす仕組み
コード署名の証明書には有効期間があります。何もしなければ、期限が切れた瞬間に過去のリリースもすべて検証に失敗します。3年前に配ったインストーラが今日から未署名扱いになる、という事態です。これを避けるのがタイムスタンプです。
Microsoft Learnのタイムスタンプ解説は効果を端的に述べています。タイムスタンプが無いと署名証明書の期限切れ時点で署名は無効になり、Windowsはそのバイナリを未署名として扱う。カウンタ署名方式のタイムスタンプがあれば、署名証明書が期限切れになった後や失効した後でも署名の検証が可能になる。実装としては、元の署名(SignerInfoのencryptedDigest)をタイムスタンプサーバへ送り、返ってきたSignerInfoをPKCS #9のカウンタ署名として元のSignedDataへ差し込みます。カウンタ署名は未認証属性なので、署名済みのファイルに後から追加できます。
タイムスタンプの信頼はTSA側の運用に依存します。RFC 3161(2001年8月)は、TSAへの要件として、信頼できる時刻源を使うこと、各トークンに信頼できる時刻値と一意な整数を含めること、データそのものではなくハッシュ表現のみにタイムスタンプを付けること、トークンに要求元の識別情報を含めないこと、この目的のためだけに生成した鍵で署名することなどを挙げています。要求元を記録しないという要件は、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ファイルを置き、パスフレーズを環境変数で渡す構成は、当時は基準違反ではありませんでした。今は違います。
要求水準が主体ごとに階段状になっている点は見ておく価値があります。認証局自身の鍵は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です。
FAQのもう一つの記述も見逃せません。証明書プロファイルを削除しても、既に発行済みの証明書は失効せず署名も無効にならない、という一文です。署名サービスの利用をやめても過去の署名は生き続けます。撤収は失効ではありません。
秘密情報をどこに置くかという設計は、コード署名鍵に限らず共通の課題です。
あわせて読みたい
シークレット管理の実務。APIキー・認証情報をハードコードせず、Vaultやマネージドサービスで守りローテーションする
ビルドサーバに秘密鍵を置かない構成へ移す手順
既存のリリース工程に.pfxや.p12がファイルとして存在している場合、置き換えは段階的に進めます。いきなり本番の署名を止めると出荷が止まるため、並行運用の期間を取ります。
- 1
署名している対象と署名鍵を棚卸しする
実行ファイル、インストーラ、ドライバ、コンテナイメージ、スクリプト、パッケージ、ファームウェアのうち、どれに署名しているかを一覧にします。その署名に使っている鍵と証明書が何本あるか、どこに保管され、誰がアクセスできるかを記録します。開発用のテスト鍵と本番鍵が同じルートにつながっていないかもここで確認します。 - 2
ビルドサーバとリポジトリを鍵の痕跡で検索する
リポジトリの履歴、CIの環境変数、コンテナイメージのレイヤ、ビルドエージェントのディスク、共有ストレージを対象に、pfxやp12やkeyやpemといった拡張子と、証明書のシリアル番号や指紋で検索します。過去のコミットに一度でも入ったものは削除しても履歴から取り出せます。見つかった鍵は漏えい済みとして扱うのが安全側の判断です。 - 3
署名を実行する専用の経路を1本作る
ハードウェアトークン、HSM、クラウドの鍵管理サービス、マネージド署名サービスのいずれかを選び、署名処理をそこへ集約します。ビルドジョブは成果物のハッシュを送って署名を受け取るだけにし、鍵にも証明書にも触れない形にします。この経路は本番専用とし、開発用の署名は別系統の鍵で行います。 - 4
新旧の経路で並行して署名し、検証結果を比較する
同じ成果物に旧経路と新経路の両方で署名し、受け手側の検証コマンドで両者が同じように通ることを確認します。Windowsならsigntool verify、macOSならcodesignとspctl、Linuxならパッケージマネージャの検証結果を突き合わせます。タイムスタンプが付いていることもここで確認します。 - 5
旧鍵での署名を停止して鍵を破棄する
切り替え後、旧鍵での署名を止めます。ファイルとして存在していた鍵は保管場所とバックアップの両方から確実に消します。証明書自体を失効させるかどうかは、その鍵で署名した過去のリリースへの影響を評価してから決めます。停止した日付を記録に残します。 - 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を運用する場合も、この二つの権限は別の人物に持たせます。
承認プロセスで決めるべきことは四点に集約できます。署名対象をタグ名やブランチ名ではなくコミットハッシュと成果物ハッシュで特定すること。承認者を複数にして、1アカウントの乗っ取りで統制が消えない形にすること。承認の記録を署名サービス側の履歴とチケットシステムで突き合わせられる形に残すこと。そして緊急時の例外経路を設計すること。例外経路が無いと現場で迂回路が作られ、例外経路が緩いとそこが常用されます。
CIパイプラインのどこで何に署名するか
署名を挟む位置は、パイプラインの中で二か所あります。ビルドの直後と、配布の直前です。
ビルド直後に署名する構成は、成果物がビルド環境を出る瞬間から保護されます。ただし署名鍵を呼び出す権限がビルドジョブに与えられるため、ビルドスクリプトを書き換えられる人が実質的に署名できることになります。プルリクエストのマージ権限が署名権限と同義になる、と言い換えられます。
配布直前に署名する構成は、テストと承認を通過した後で署名するため、承認と署名の対応が明確になります。一方でビルドからリリースまでの間、成果物は署名されていない状態でアーティファクトストアに置かれます。この区間の完全性は、ストア側のアクセス制御とハッシュの記録で守る必要があります。
NIST SP 800-204Dは、この区間を証跡で埋める考え方を示しています。最終ビルド成果物とファイルとライブラリのハッシュ、および全イベントを収集し、それを開発者の制御下にないビルドフレームワークの信頼されたコンポーネントがデジタル証明書で署名してアテステーションを作る、という設計です。署名する主体をビルドを書いた人から切り離すことで、消費者側が生産者から独立して検証できるようにします。
実務上の折衷案としては、自動署名の対象と承認後にのみ署名する対象を分けます。開発ビルドやナイトリービルドは開発用の鍵で自動署名し、公開リリースだけを別の鍵と承認経路に通す形です。この分離は前節の「開発用CSSを分ける」推奨と同じ考え方です。
CIパイプライン全体をどう守るかという話は、次の記事で扱っています。
あわせて読みたい
サプライチェーン攻撃の構造と防御の考え方。ソフト・ハード・サービス経由の侵入をどう減らすか
SLSAのビルド来歴とSigstoreの鍵を持たない署名
署名が「誰が」を答えるのに対し、ビルド来歴(provenance)は「どうやって作られたか」を答えます。SLSAは、この来歴の生成と検証を段階的な要求水準として整理した枠組みです。
来歴の中身も定義されています。SLSA v1.1のProvenanceはbuildDefinitionとrunDetailsの二つの部分から成り、前者にはビルドの種類を示すbuildType、利用者が制御し検証対象となるexternalParameters、初期化と実行の過程で取得された成果物を記録するresolvedDependenciesが、後者には信頼されたビルドプラットフォームの識別子であるbuilder.idや実行の開始終了時刻が入ります。ただしSLSAの公式解説は、この枠組みがソースコードの品質や悪意の有無を扱わないことを自ら明記しています。来歴の検証は「宣言どおりのビルド環境から出たか」を確かめるものです。
長期の署名鍵を安全に保管し続けることが難しいなら、鍵を長期に保持しなければよい。Sigstoreはこの発想を実装した仕組みです。署名者は一時的な鍵ペアをメモリ上で生成し、OpenID Connectで身元を認証したトークンをFulcioへ提示します。Fulcioは身元と一時公開鍵を結び付けた有効期間10分の証明書を発行します。署名を行った後、一時秘密鍵は直ちに破棄されます。
有効期間10分の証明書で署名したものが10分後に検証できなくなっては困ります。ここを埋めるのがRekorです。Rekorは追記専用のMerkleツリー構造を持つ透明性ログで、署名イベントを検証可能な形で記録します。検証者は、証明書が既に期限切れであっても、その署名がログに記録された時刻で証明書が有効だったことを確認できます。役割はRFC 3161のTSAと同じ位置ですが、記録が公開の追記専用ログである点が異なります。自分の身元で署名が行われたことが公開ログに残るため、身元を乗っ取られた場合に本人がそれを検知できます。
検証側では注意点があります。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を組み合わせたもので、特定の認証局が特定の企業へ発行した証明書を信頼する形になります。
ハッシュルールと署名者ルールにはトレードオフがあります。ハッシュルールはバイナリが1バイトでも変わればポリシー更新が必要です。署名者ルールは新しいバージョンを自動的に許可するため更新は不要ですが、その発行元が今後出すすべてのバイナリを事前に信頼することになります。署名鍵が漏れた発行元を署名者ルールで許可していた場合、攻撃者が署名した任意のバイナリが許可されます。
macOS側ではGatekeeperが既定の検証者です。Appleのプラットフォームセキュリティガイドは、Gatekeeperがソフトウェアについて識別された開発者のものであること、既知の悪意あるコンテンツを含まないとAppleが公証したこと、改変されていないことを検証すると述べています。既定では、ダウンロードされたすべてのソフトウェアがApp Storeによって署名されているか、登録済み開発者によって署名されAppleによって公証されている必要があります。
Linuxのパッケージリポジトリでは、個々のパッケージではなくリポジトリのメタデータに署名を付ける方式が使われます。Debian WikiのSecureAptの解説によれば、検証は三段の連鎖です。個々のパッケージのチェックサムがPackagesファイルに載り、Packagesファイルのチェックサムが Releaseファイルに載り、ReleaseファイルにOpenPGPの署名が付きます。この方式が守るのは「リポジトリの管理者が承認した内容が配信経路で書き換えられていないこと」であって、パッケージの中身の安全性ではありません。
どの環境でも、検証を有効にしただけでは足りません。検証が失敗したときに何が起きるかを確認します。警告を出して続行する構成になっていると、実質的に検証していないのと変わりません。
署名鍵が漏れたときに実際に起きること
鍵が攻撃者の手に渡った場合に起きることは三つです。
第一に、攻撃者は任意のバイナリに正規の発行元名で署名を付けられます。受け手のOSは発行元名を表示し、実行制御ポリシーが署名者ルールでその発行元を許可していれば、そのバイナリは実行を許可されます。
第二に、正規のリリースと攻撃者のバイナリを署名だけでは区別できなくなります。両方とも同じ証明書で有効な署名を持ちます。区別できるのは、正規のリリースとして自社が記録したハッシュ値と突き合わせた場合だけです。署名履歴のログとリリースごとのハッシュ台帳を持っているかどうかが、ここで効いてきます。
第三に、対応の選択肢が「証明書を失効させる」ことに集約されます。そして失効は、攻撃者のバイナリだけを狙って止めることができません。
ただし、鍵が漏れなくても同じ結果になる経路があります。冒頭で触れた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
署名履歴と成果物ハッシュを突き合わせる
署名サービスやHSMの監査ログから期間内の署名一覧を取り出し、自社のリリース台帳のハッシュ値と突き合わせます。身に覚えのない署名が見つかれば、その最も古い時刻が危殆化の下限になります。ログが無ければ開始時刻を特定できず、失効日を保守的に古く取らざるを得なくなります。 - 2
その鍵で署名した配布物と配布先を洗い出す
自社のダウンロードサイト、ミラー、パッケージリポジトリ、ソフトウェア配布ツール、OEM経由の同梱、既に導入済みのバージョンまでを列挙します。失効させた場合に検証が壊れる対象がここに並びます。オフラインのエンドポイントや失効情報を取得できない環境の存在も確認します。 - 3
新しい鍵と証明書を先に用意する
失効を要求する前に、新しい鍵ペアをハードウェア暗号モジュール内で生成し証明書を取得しておきます。身元確認に日数がかかるため、失効してから申請すると再配布までの空白が伸びます。新しい鍵は、危殆化した経路とは独立した保管と権限設計にします。 - 4
失効の日時を決めて認証局へ報告する
調査で得た危殆化の時刻と、その日以降の正規リリースの本数を並べて境界線を決め、決定の根拠を記録に残します。認証局へは判断材料としてこの調査結果を添えて報告します。認証局は基準に従って24時間以内に失効させます。 - 5
影響を受けるリリースを再署名して配り直す
失効日以降にタイムスタンプされた正規のリリースは、新しい証明書で再署名し新しいタイムスタンプを付けて再配布します。告知には旧証明書のシリアル番号と失効日、新しい証明書の指紋を明記します。利用者が実行制御ポリシーで旧証明書を許可している場合、その更新も依頼します。 - 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年後も同じ検証コードで検証されます。検証側のコードを後から書き換えられない機器では、署名アルゴリズムを後から変えることができません。
実務としては、まず自社が署名に使っているアルゴリズムと鍵長を棚卸しし、検証側のコードを更新できる経路があるかを確認します。ファームウェアのように後から変えられない対象と、アプリケーションのように配布のたびに検証系ごと更新できる対象とでは、移行の緊急度が違います。
移行の全体像は、次の記事で整理しています。
あわせて読みたい
ポスト量子暗号(PQC)への移行。量子コンピュータが暗号を破る前に備える
署名鍵管理の点検リスト
ここまでの内容を、自組織の現状確認に使える形に並べます。
コード署名の運用点検
- 署名している対象(実行ファイル、インストーラ、ドライバ、コンテナイメージ、パッケージ、ファームウェア、スクリプト)を一覧化し、それぞれに使っている鍵と証明書を対応付けた
- すべての署名鍵がハードウェア暗号モジュール、または鍵が外へ出ないクラウドサービスの中で生成され、エクスポートできない状態であることを確認した
- リポジトリの履歴、CIの環境変数、コンテナイメージ、ビルドエージェントのディスクを鍵ファイルの拡張子と証明書の指紋で検索し、平文の鍵が残っていないことを確認した
- 開発用の署名鍵と本番用の署名鍵を分け、両者が同じルート証明書につながっていないことを確認した
- 署名を依頼できる人と承認できる人と署名基盤を管理できる人を別の役割として定義し、実際の権限割り当てが定義どおりであることを確認した
- すべての署名にRFC 3161のタイムスタンプを付けており、タイムスタンプサーバの到達性が監視されていることを確認した
- 証明書の有効期間が460日以内になったことを踏まえ、更新の予定日と担当者と手順を年次の計画に組み込んだ
- 署名の実行ログを収集し、リリース台帳のハッシュ値と突き合わせられる形で保管していることを確認した
- 自社が配布した各リリースの成果物ハッシュを、配布後も参照できる形で記録していることを確認した
- 鍵の危殆化を疑った場合の連絡先(認証局の届出窓口)、失効日の決定手順、再署名と再配布の手順を文書にした
- 受け手側でパッケージやコンテナの署名検証を有効にし、検証失敗時に処理が止まる設定になっていることを確認した
- 実行制御ポリシーを署名者ルールで組んでいる場合、ユーザーモードのバイナリまで検証対象に含めているかを確認した
- 署名しているソフトウェアが読み込む外部モジュールについて、絶対パス指定や署名検証などのサイドローディング対策を実装しているか確認した
- 使用中の署名アルゴリズムと鍵長を棚卸しし、検証側のコードを後から更新できない配布対象を特定した
署名は身元の記録であって品質の証明ではない
コード署名の運用を組み立てるときに立ち返る前提は、冒頭に書いた一点に尽きます。署名は「誰が出したか」と「途中で変わっていないか」を受け手が確かめるための仕組みであって、中身の性質については何も述べていません。
この前提を受け入れると、投資先の優先順位が自然に決まります。鍵をハードウェア暗号モジュールへ入れることは、CA/Browser Forumの基準が要求する最低線であり、そこは満たすべきです。しかし鍵を守るだけでは署名される内容は守れません。何に署名するかを決める承認の経路、署名した記録を残す監査ログ、署名された成果物のハッシュ台帳。この三つが揃って初めて、事故が起きたときに「どこまでが正規で、どこからが偽物か」を言えるようになります。
言えるようになることが、対応の速度を決めます。署名履歴とハッシュ台帳が無ければ危殆化の時刻を特定できず、失効日を保守的に古く取るしかなくなります。すると無事だった正規のリリースまで無効になり、再署名と再配布の対象が膨らみます。ログを残す作業は普段は何の役にも立ちませんが、事故の日には影響範囲を数分の一に縮める働きをします。
証明書の有効期間は短くなり続け、更新の頻度は上がっています。署名鍵の保護要件は基準として明文化され、ハードウェアでの保管が前提になりました。マネージド署名サービスは鍵を利用者に渡さない設計へ進み、Sigstoreは長期の鍵そのものを持たない方向へ舵を切りました。どの流れも「鍵を長く手元に置くほど危ない」という一つの認識から出ています。手元に置く期間を短くする方向で自社の構成を見直すことが、この分野で最も確実な改善になります。
出典・参考
- Latest Code Signing Baseline Requirements | CA/Browser Forum
- RFC 3161: Internet X.509 Public Key Infrastructure Time-Stamp Protocol (TSP)
- NIST Cybersecurity White Paper: Security Considerations for Code Signing
- NIST SP 800-218: Secure Software Development Framework (SSDF) Version 1.1
- NIST SP 800-204D: Software Supply Chain Security in DevSecOps CI/CD Pipelines
- NIST SP 800-208: Recommendation for Stateful Hash-Based Signature Schemes
- Time Stamping Authenticode Signatures | Microsoft Learn
- Code signing options for Windows app developers | Microsoft Learn
- SmartScreen reputation for Windows app developers | Microsoft Learn
- Artifact Signing FAQ | Microsoft Learn
- Understand App Control for Business policy rules and file rules | Microsoft Learn
- Notarizing macOS software before distribution | Apple Developer Documentation
- Gatekeeper and runtime protection in macOS | Apple Platform Security
- Fulcio: certificate authority overview | Sigstore
- Rekor: transparency log overview | Sigstore
- Verifying signatures with cosign | Sigstore
- SLSA v1.1: About SLSA
- SLSA v1.1: Security Levels
- CISA AA20-352A: Advanced Persistent Threat Compromise of Government Agencies, Critical Infrastructure, and Private Sector Organizations
- CISA Alert: Supply Chain Attack Against 3CXDesktopApp
- SecureApt | Debian Wiki
- FIPS 204: Module-Lattice-Based Digital Signature Standard | NIST
- FIPS 205: Stateless Hash-Based Digital Signature Standard | NIST
関連する記事
サプライチェーン攻撃の構造と防御の考え方。ソフト・ハード・サービス経由の侵入をどう減らすか
自社が直接狙われなくても、取引先やライブラリ、サービス経由で侵入されるのがサプライチェーン攻撃です。実例をもとに攻撃の構造を分解し、信頼の前提を見直すための実務的な防御の考え方を解説します。
2026年版の最小要素で見直すSBOMの作り方と脆弱性管理での使い方
SBOMはソフトウェアの部品表です。2026年7月に日本を含む各国が共同署名した国際ガイダンスの最小要素、SPDXとCycloneDXの選び分け、ビルド時生成の理由、VEXとの突合、そして調達契約で規定すべき事項までを一次情報にもとづいて整理します。
DLLサイドローディングとは何か。署名済み正規アプリが悪用される仕組みと対策
DLLサイドローディング(DLL side-loading)は、署名済みの正規アプリケーションがWindowsのDLL検索順序を悪用され、悪意あるDLLを読み込まされる攻撃であり検知回避の手口でもあります。MITRE ATT&CK T1574.001とMicrosoft公式資料をもとに仕組みと対策を整理します。


