Claude Media
Claude Code GPG署名検証 — manifestとコード署名の確認手順

Claude Code GPG署名検証 — manifestとコード署名の確認手順

Claude Codeのリリースバイナリが改ざんされていないかを、manifest.jsonの検出署名とプラットフォーム別のコード署名で検証する手順をまとめます。

Claude Codeのバイナリは、リリースごとのmanifest.jsonにGPG署名が付いています。この署名を検証し、手元のバイナリのSHA256をmanifestの値と突き合わせれば、改ざんされていないことを確認できます。手順はmacOS(Apple Silicon)にインストールしたv2.1.287で実際に通し、出力もそのまま載せています。通常のインストール手順はClaude Code install完全ガイド、機能全体はClaude Code完全ガイドにあります。

manifest署名とコード署名は何を保証するのか

検証には性質の違う2種類の署名が関わります。どちらを見るかで、確かめられる範囲が変わります。

くらべる

2つの署名の守備範囲

全OS共通

manifest.jsonのGPG署名

Anthropicの鍵で署名されたmanifest.jsonが改ざんされていないことを確かめます。manifestには全プラットフォームのSHA256が載っていて、manifestの署名を検証すれば載っている全バイナリを間接的に検証したことになります。そのため、手元のバイナリのハッシュと一致すれば、そのバイナリはAnthropicが公開したものと同一です。直接ダウンロードやネイティブインストーラーで入れたLinuxでは、確認できる手段はこれだけです。

macOS・Windows

OS標準のコード署名

バイナリ1つ1つに付いた署名で、OSの仕組みで検証します。macOSでは署名者が「Anthropic PBC」で、Appleの公証も受けています。GPGもcurlも要りませんが、確かめられるのは手元のファイル単体です。

Linuxのバイナリには個別のコード署名がありません。apt・dnf・apkで入れた場合は、パッケージマネージャーがリポジトリの署名鍵で自動的に検証するので、以下の手順を手作業でなぞる必要はありません。リポジトリ経由の導入はClaude Code apt installでのLinuxパッケージ導入と更新にまとめています。

署名鍵を取り込み、fingerprintを照合する

manifestの検証には、gpgとcurlが使えるPOSIXシェルが要ります。Windowsの場合はGit BashかWSLで実行します。最後のハッシュ比較だけは、Windows PowerShellでも実行できます。

最初の手順は鍵の取り込みです。普段使いのキーリングに混ぜたくないときは、先にGNUPGHOMEを一時ディレクトリへ向けておくと、検証後にディレクトリごと捨てられます。

export GNUPGHOME="$(mktemp -d)"
curl -fsSL https://downloads.claude.ai/keys/claude-code.asc | gpg --import
gpg --fingerprint security@anthropic.com

v2.1.287を検証した環境(LC_ALL=C)での--fingerprintの出力は次のとおりです。

pub   rsa4096 2026-03-30 [SCE]
      31DD DE24 DDFA B679 F42D  7BD2 BAA9 29FF 1A7E CACE
uid           [ unknown] Anthropic Claude Code Release Signing <security@anthropic.com>

鍵は4096ビットのRSAで、作成日は2026-03-30、用途は署名・認証・証明(SCE)です。照合する値は31DD DE24 DDFA B679 F42D 7BD2 BAA9 29FF 1A7E CACEで、公式ページの記載と一致しました。4桁ずつ区切られていますが、5組目と6組目のあいだだけ空白が2つ入ります。目視で比べるときは空白の数に引っかからないようにしてください。

この照合を飛ばすと、以降の署名検証は「誰の鍵か分からない署名を確かめている」ことになります。

manifestと署名を取得して検証する

検証したいリリースをVERSIONに入れ、manifestと検出署名(detached signature)を取得します。

REPO=https://downloads.claude.ai/claude-code-releases
VERSION=2.1.287
curl -fsSLO "$REPO/$VERSION/manifest.json"
curl -fsSLO "$REPO/$VERSION/manifest.json.sig"
gpg --verify manifest.json.sig manifest.json

署名ファイルが先、対象ファイルが後です。v2.1.287では次の出力になりました。

gpg: Signature made Fri Oct  2 01:28:04 2026 JST
gpg:                using RSA key 31DDDE24DDFAB679F42D7BD2BAA929FF1A7ECACE
gpg: Good signature from "Anthropic Claude Code Release Signing <security@anthropic.com>" [unknown]
gpg: WARNING: This key is not certified with a trusted signature!
gpg:          There is no indication that the signature belongs to the owner.

Good signatureの行が署名の妥当性、直前のfingerprint照合が鍵の真正性をそれぞれ担います。WARNINGは、取り込んだだけで署名していない鍵に付くもので、失敗を意味しません。

日本語ロケールのシェルでは、同じ結果が「"Anthropic Claude Code Release Signing <security@anthropic.com>"からの正しい署名[不明の]」のように出ます。Good signatureを文字列で探すスクリプトでは、LC_ALL=Cを付けて実行すると結果が揃います。

manifestの中身とプラットフォームのキー

v2.1.287のmanifestは2,144バイトのJSONで、トップレベルにversion・commit・buildDate・platformsなどがあります。バイナリを選ぶ鍵になるのはplatformsのキーです。

数字

v2.1.287のmanifest.json

  • platformsのキー数

    8

  • 各プラットフォームの値(binary・checksum・size)

    3項目

  • darwin-arm64のバイト数

    227,827,120

キーはdarwin-arm64・darwin-x64・linux-arm64・linux-x64・linux-arm64-musl・linux-x64-musl・win32-x64・win32-arm64の8つです。Alpineのようなmusl系のLinuxを使う場合の導入はClaude Code Alpine Linuxセットアップで扱っています。Apple Siliconのmacではuname -mがarm64を返すので、darwin-arm64を使います。

インストール済みのバイナリをmanifestと突き合わせる

ネイティブインストーラーで入れたバイナリは、~/.local/share/claude/versions/の下にバージョン名のファイルとして置かれます。手元の環境では~/.local/bin/claudeがそのうちの2.1.287へのシンボリックリンクでした。

このディレクトリの古いバージョンは、ネイティブインストーラーが自動で削除します。ランチャーが指すバージョンと同じマシンで動作中のバージョンに加え、新しい2つを残して消えます。カスタムランチャーでは全バージョンが残り、掃除は利用者の仕事です。消えたバージョンのバイナリも、claude-code-releasesのバケットから直接取得すれば、同じmanifestの署名で検証できます。

NFSのようにホームを複数のマシンで共有していると、削除されたバージョンを別のマシンのセッションが実行中のことがあり、そのセッションはバイナリを失います。

ハッシュを計算してmanifestの値と比べます。

shasum -a 256 ~/.local/share/claude/versions/2.1.287
jq -r '.platforms["darwin-arm64"].checksum' manifest.json
6eab8333fe2121553100d8f40bfada384a3e989b94f947e18ba6677a6fcb41ea  .../versions/2.1.287
6eab8333fe2121553100d8f40bfada384a3e989b94f947e18ba6677a6fcb41ea

2つのハッシュは完全に一致しました。ファイルサイズもls -lで227,827,120バイトとなり、manifestのsizeと同じです。Linuxならsha256sum、Windows PowerShellなら(Get-FileHash claude.exe -Algorithm SHA256).Hash.ToLower()で同じ比較ができます。

macOSのコード署名を確認する

GPGとは別に、macOS版のバイナリはAppleのコード署名を受けています。codesignとspctlで確認した結果です。

codesign --verify --verbose ~/.local/share/claude/versions/2.1.287
codesign -dvv ~/.local/share/claude/versions/2.1.287 2>&1 | grep -E "Identifier|Authority|TeamIdentifier"
spctl --assess --type install -v ~/.local/share/claude/versions/2.1.287
.../versions/2.1.287: valid on disk
.../versions/2.1.287: satisfies its Designated Requirement
Identifier=com.anthropic.claude-code
Authority=Developer ID Application: Anthropic PBC (Q6L2SF6YDW)
Authority=Developer ID Certification Authority
Authority=Apple Root CA
TeamIdentifier=Q6L2SF6YDW
.../versions/2.1.287: accepted
source=Notarized Developer ID

署名者は「Developer ID Application: Anthropic PBC」で、証明書の連鎖はApple Root CAまで続いています。spctlはsource=Notarized Developer IDと答え、Appleの公証済みであることが読み取れます。

同じファイルをspctl --assess --type execute -vで調べると、rejected (the code is valid but does not seem to be an app)と表示されました。--type executeではアプリとして扱われないため、単体のコマンドラインバイナリは不合格になります。署名が壊れているわけではないので、単体バイナリの確認には--type installを使います。

WindowsはGet-AuthenticodeSignature .\claude.exeで署名者が「Anthropic, PBC」であることを確かめます。

検証をスクリプト化してCIに置く

手順をCIのデプロイゲートに組み込むときは、fingerprintをスクリプト内の定数にして、人の目の照合を機械の比較に置き換えます。gpg --with-colonsの出力はfpr行の10番目の欄が空白なしのfingerprintなので、awkで取り出して比べられます。次のスクリプトは、v2.1.287とmacOSのバイナリで実際に通しました。

#!/usr/bin/env bash
set -euo pipefail
VERSION="$1"; PLATFORM="$2"; BIN="$3"
EXPECTED_FPR="31DDDE24DDFAB679F42D7BD2BAA929FF1A7ECACE"
REPO=https://downloads.claude.ai/claude-code-releases
export GNUPGHOME="$(mktemp -d)"; WORK="$(mktemp -d)"
trap 'rm -rf "$GNUPGHOME" "$WORK"' EXIT
 
curl -fsSL https://downloads.claude.ai/keys/claude-code.asc | gpg --batch --import 2>/dev/null
ACTUAL_FPR="$(gpg --with-colons --fingerprint security@anthropic.com | awk -F: '/^fpr/ {print $10; exit}')"
[ "$ACTUAL_FPR" = "$EXPECTED_FPR" ] || { echo "fingerprint mismatch: $ACTUAL_FPR"; exit 1; }
 
curl -fsSL "$REPO/$VERSION/manifest.json" -o "$WORK/manifest.json"
curl -fsSL "$REPO/$VERSION/manifest.json.sig" -o "$WORK/manifest.json.sig"
gpg --batch --verify "$WORK/manifest.json.sig" "$WORK/manifest.json" 2>/dev/null
 
WANT="$(jq -r --arg p "$PLATFORM" '.platforms[$p].checksum' "$WORK/manifest.json")"
GOT="$(shasum -a 256 "$BIN" | awk '{print $1}')"
[ "$WANT" = "$GOT" ] || { echo "checksum mismatch"; exit 1; }
echo "OK: $VERSION $PLATFORM"

./verify-claude.sh 2.1.287 darwin-arm64 ~/.local/share/claude/versions/2.1.287はOK: 2.1.287 darwin-arm64を返して終了コード0になりました。Linuxのランナーではshasum -a 256をsha256sumに替えます。set -eが効いているので、fingerprint・署名・ハッシュのどれか1つでも失敗すればデプロイが止まります。

検証が失敗したときの症状別の切り分け

失敗の出方は原因ごとに違います。次の3つは、いずれも検証用の一時ディレクトリで意図的に再現した出力です。

手順

症状から原因をたどる

  1. 1

    BAD signatureが出る

    manifest.jsonを1か所書き換えて検証すると、gpg: BAD signature from "Anthropic Claude Code Release Signing <security@anthropic.com>"と出ました。manifestか.sigのどちらかが元のものと違っています。両方を同じVERSIONで取り直して再検証し、それでも出るならそのmanifestは使えません。

  2. 2

    「有効なOpenPGPデータが見つかりません」が出る

    gpg --verify manifest.json manifest.json.sigと引数の順序を逆にすると、日本語ロケールではgpg: 有効なOpenPGPデータが見つかりません。と出ました。署名ファイルを先に渡す順序に直せば解決します。鍵の取り込み(gpg --import)で同じ文言が出たときは、ダウンロードが失敗したか別の内容が返っています。downloads.claude.aiに接続できるかを確かめます。

  3. 3

    checksum mismatchが出る

    署名は通るのにハッシュが合わないときは、まずplatformsのキーが合っているかを疑います。arm64のmacのバイナリをdarwin-x64のチェックサムと比べると、スクリプトはchecksum mismatchで止まりました。キーを直しても合わないなら、ダウンロードを取り直し、それでも一致しない環境ではインストールを保留して社内のセキュリティ窓口に回します。

fingerprintが手元の記録と食い違う場合は、鍵の取得経路を疑います。取得元がdownloads.claude.aiであることを確かめ、鍵を取り直して、一致するまで以降の手順に進みません。

v2.1.89より前のリリースには署名がない

manifestの署名が付くのはv2.1.89以降のリリースです。それより前のリリースは、manifest.jsonにチェックサムだけが載り、.sigはありません。

実測では、v2.1.80・v2.1.86・v2.1.87はmanifest.jsonが取得でき、manifest.json.sigはHTTP 404でした。v2.1.88だけはmanifest.jsonも404で、単独の欠番になっています。v2.1.89では両方が200で取得できます。古いバージョンを検証するときは、.sigが取得できるかどうかで署名付きのリリースかを判断できます。

まとめ

どの経路で入れたかで、検証が要るかどうかが決まります。apt・dnf・apkなら自動で検証され、直接ダウンロードやネイティブインストーラーなら、上のスクリプトをCIに置くと手作業を減らせます。

この記事を共有:XはてブLinkedIn