TT Lab
はじめる
学ぶ 学習パス コース

ビルドは緑だったのに、あのライブラリを入れたのは誰か

検証が失敗すべき4つの場合を作る

TT Labで続きを見る

目標

リリースの成果物に直接署名して、検証が失敗するべき場合を手で作ってみます。改ざん・別の鍵・取り消した鍵・キーリングにない鍵の4つをすべて拒否する検証器を作ります。

なぜ重要なのか

「署名を付けた」という文は、何も保証しません。保証は、検証が失敗する場所で生まれます。そのため、署名の仕組みを導入するときに最初にやることは、署名ではなく、失敗するべき場合をすべて書き出して、1つずつ実際に失敗させることです。特に、最後の2つがよく抜けます。署名自体は数学的に問題がないのに、その鍵を私たちがもう信頼していない場合です。生の鍵には期限がないので、いつまで信頼するかは、外に別に書く必要があります。sigstoreが短命な証明書と透明性ログを使う理由が、ここにあります。検証する側が、署名した人の鍵管理の習慣に頼らないようにするためです。

ステップ

  1. 成果物を/root/sign/distに置いて、フィンガープリントを/root/sign/01-digest.txtに書きます。
  2. P-256の鍵ペアを/root/sign/release.keyと/root/sign/release.pubに作ります。
  3. 成果物に署名して、/root/sign/dist/paygate-1.4.2.js.sigを作ります。
  4. 検証の出力を/root/sign/04-verify.txtに残します。
  5. 改ざんしたものを作って、失敗の出力を/root/sign/05-tamper.txtに残します。
  6. 取り消した古い鍵で署名して、失敗の出力を/root/sign/06-oldkey.txtに残します。
  7. 2つの鍵を、期限とフィンガープリントとともに/root/sign/keyring.jsonに登録します。
  8. /root/sign/verify-release.shを作って、4つの場合の終了コードを/root/sign/08-checks.jsonに書きます。

参考

署名するものを1か所に置いて、フィンガープリントを取る

/opt/fixtures/sbom/release/paygate-1.4.2.jsを/root/sign/dist/paygate-1.4.2.jsにコピーして、そのファイルのSHA-256を、小文字の16進64文字の1行として/root/sign/01-digest.txtに保存してください。

署名は、ファイル全体ではなくダイジェストに対して行うものです。先にその値を手に持って始めれば、あとで何が変わったかを目で確認できます。

リリースの鍵ペアを作る

prime256v1(P-256)曲線で鍵ペアを作って、秘密鍵を/root/sign/release.keyに、公開鍵を/root/sign/release.pubに保存してください。パスフレーズを掛ける秘密鍵は使いません。

openssl ecparamで曲線を指定して秘密鍵を作り、openssl ecに-puboutを与えれば、同じ鍵から公開鍵が出てきます。

ダイジェストに署名する

/root/sign/release.keyで/root/sign/dist/paygate-1.4.2.jsに署名して、/root/sign/dist/paygate-1.4.2.js.sigに保存してください。ハッシュはSHA-256です。

openssl dgstは、-signを与えれば署名を、-verifyを与えれば検証を行います。出力はバイナリなので、-outでファイルに受け取ってください。

検証が通ることを記録する

/root/sign/release.pubで/root/sign/dist/paygate-1.4.2.jsと/root/sign/dist/paygate-1.4.2.js.sigを検証して、opensslが出した出力を/root/sign/04-verify.txtに保存してください。

通るとき、opensslは1行だけを出力します。その1行が、このステップの証拠です。

成果物を1文字直すとどうなるかを見る

/root/sign/dist/paygate-1.4.2.jsを/root/sign/tampered/paygate-1.4.2.jsにコピーしたあとで内容を変え、元の署名/root/sign/dist/paygate-1.4.2.js.sigで検証して、失敗の出力を/root/sign/05-tamper.txtに保存してください。

署名はダイジェストに掛かっています。1バイトだけ違っても、ダイジェストがまるごと変わるので、同じ署名では合わせられません。

去年使って取り消した鍵で署名されたものを作る

P-256の鍵ペアをもう1つ作って/root/sign/old-release.keyと/root/sign/old-release.pubに保存し、その鍵で/root/sign/dist/paygate-1.4.2.jsに署名して、/root/sign/dist/paygate-1.4.2.js.oldsigを作ってください。そのあと、/root/sign/release.pubでその署名を検証して、失敗の出力を/root/sign/06-oldkey.txtに保存してください。

この署名は偽造ではありません。数学的に問題のない署名で、その鍵の公開鍵なら通ります。問題は「その鍵を今も信頼しているか」であり、それは署名アルゴリズムが答えてくれません。

どの鍵をいつまで信頼するかを書いておく

/root/sign/keyring.jsonに、keys配列として2つの鍵を登録してください。各項目はid・file・fingerprint・not_before・not_after・ownerです。release.pubは、id release-2026、期限は2026-01-01から2026-12-31まで、old-release.pubは、id release-2025、期限は2025-01-01から2025-12-31までで、ownerは両方ともpayments-platformです。fileは/root/signの中のファイル名だけを書き、fingerprintは、その公開鍵をDERで取り出して求めたSHA-256の小文字16進です。

生の鍵には期限がありません。そのため、「いつまで信頼するか」を外に別に書く必要があり、これがsigstoreが短命な証明書を使う理由でもあります。

キーリングを見る検証器を作って、4つの場合を判定する

/root/sign/verify-release.shを作ってください。bash /root/sign/verify-release.sh <산출물> <서명> <키id>で呼び出すと、/root/sign/keyring.jsonからその鍵を探して、基準日2026-09-11に期限が有効かを見て、有効ならその公開鍵で署名を検証します(プレースホルダーは、順に成果物、署名、鍵IDです)。通れば0、キーリングになかったり、期限が切れていたり、検証が失敗したりすれば1で終了します。そのあと、4つの場合を実行して、終了コードを/root/sign/08-checks.jsonにgood・tampered・old_key・unknown_keyとして保存してください。goodは、正常な成果物と署名にrelease-2026、tamperedは、改ざんしたものに同じ署名とrelease-2026、old_keyは、正常な成果物に.oldsigとrelease-2025、unknown_keyは、キーリングにないrelease-2024です。

検証器が答える質問は2つです。署名がこのバイト列に合っているか、そしてその鍵を今信頼してよいか。どちらか1つだけを見ると、取り消した鍵で署名されたものが、そのまま通ります。