2026年6月18日
2026年6月18日
DoT (DNS over TLS) の署名チェック手順|サーバー証明書の連鎖・TLS の署名・SPKI ピンを確かめる
DoT で「署名」を確かめるとは、DNS の応答そのものではなく、接続先の DoT サーバーが本物であることを示す証明書の署名の連鎖と、TLS ハンドシェイクでサーバーが行う署名を確かめることです。この記事では、openssl と kdig を使って、証明書の連鎖が信頼できる認証局までつながっているか、署名のアルゴリズムが適切か、ピン留め(SPKI ピン)に使う値が正しいかを順に確認する手順を説明します。
なお、DNS の応答データに付く署名(RRSIG)は DNSSEC の仕組みで、DoT とは別物です。混同すると「DoT にしたから応答は改ざんされない」と誤解しやすいため、最後の章で役割の違いを整理します。
DoT で確かめる「署名」は3種類ある
DoT の接続で出てくる署名は、次の3つに分けて考えると整理しやすくなります。
- 証明書への署名:サーバー証明書は中間認証局が、中間証明書はルート認証局が署名しています。この連鎖をたどって、端末が信頼するルートに行き着くかを確かめます。
- ハンドシェイクでの署名:TLS 1.3 では、サーバーが証明書に対応する秘密鍵で通信の内容に署名し(CertificateVerify)、秘密鍵を持っていることを示します。証明書だけを盗んでも、秘密鍵がなければ成りすませないのはこのためです。
- ピン留めとの照合:RFC 7858 では、証明書の公開鍵(SPKI)のハッシュをあらかじめ端末に登録しておき、接続時に照合する方式が定められています。認証局を経由せずに相手を確かめる方法です。
端末の設定がどの方式で相手を確かめているかによって、点検すべき項目が変わります。Android のプライベート DNS や systemd-resolved のようにホスト名で証明書を照合する方式なら1と2、Stubby のようにピンで照合する方式なら3が中心です。
手順1:証明書の連鎖を取り出して検証する
まず、サーバーが送ってくる証明書の連鎖を保存します。例では DoT サーバーを dns.example.com(203.0.113.53)としています。
openssl s_client -connect 203.0.113.53:853 \
-servername dns.example.com -showcerts </dev/null 2>/dev/null \
| awk '/BEGIN CERTIFICATE/{n++; p=1} p{print > ("cert" n ".pem")} /END CERTIFICATE/{p=0}'
ls cert*.pem
cert1.pem がサーバー証明書、cert2.pem 以降が中間証明書です。サーバーがルート証明書まで送っている場合もあります。続いて、端末が信頼する CA の一覧を使って連鎖を検証します。
# Debian/Ubuntu の場合の CA ファイル。ディストリビューションにより場所は異なる
openssl verify -CAfile /etc/ssl/certs/ca-certificates.crt \
-untrusted cert2.pem cert1.pem
cert1.pem: OK と表示されれば、サーバー証明書から信頼済みのルートまで署名がつながっています。中間証明書が複数ある場合は、それらを1つのファイルにまとめて -untrusted に渡します。
つまずきやすいのは、-untrusted を付けずに cert1.pem だけを検証して失敗し、証明書が壊れていると思い込むケースです。逆に、手元では中間証明書がキャッシュされていて成功するのに、サーバーが中間証明書を送っていないために一部の端末だけ失敗することもあります。-showcerts の出力で、サーバーが何枚送っているかを見ておくと切り分けが早くなります。
手順2:署名アルゴリズムと名前・期限を確かめる
openssl x509 -in cert1.pem -noout -subject -issuer -enddate -ext subjectAltName
openssl x509 -in cert1.pem -noout -text | grep -E "Signature Algorithm|Public Key Algorithm"
確認するのは次の点です。
- subjectAltName に端末が照合する名前があるか:DoT の端末設定に入れる名前(例
dns.example.com)が含まれていなければ、ホスト名で照合する端末は接続を拒否します。サブジェクトの CN だけを見て判断しないようにします。 - 署名アルゴリズム:
sha256WithRSAEncryptionやecdsa-with-SHA256などが一般的です。SHA-1 による署名は現在の主要な認証局からは発行されず、多くの環境で拒否されます。 - 有効期限:DoT 用の証明書は Web サーバーとは別のプロセスが読み込んでいることが多く、更新後に再読み込みされず古い証明書が残る漏れが起きやすい箇所です。
次に、ハンドシェイクでの署名を確かめます。
openssl s_client -connect 203.0.113.53:853 -servername dns.example.com \
-verify_hostname dns.example.com -verify_return_error </dev/null 2>&1 \
| grep -E "Protocol|Peer signing digest|Peer signature type|Verify return code"
Verify return code: 0 (ok) で連鎖と名前の照合が通り、Peer signature type にサーバーが使った署名の方式が表示されます。表示の項目名や書式は OpenSSL の版によって異なるため、見当たらない場合は grep を外して全体を確認してください。-verify_return_error を付けているので、検証に失敗すると接続自体が止まり、失敗を見逃しにくくなります。
手順3:SPKI ピンの値を計算し、照合を試す
ピンで照合する端末を使う場合は、サーバー証明書の公開鍵から SHA-256 のハッシュを Base64 で計算します。
openssl x509 -in cert1.pem -pubkey -noout \
| openssl pkey -pubin -outform der \
| openssl dgst -sha256 -binary \
| openssl enc -base64
得られた値を kdig の +tls-pin に渡すと、その値で照合して問い合わせられます。
# 計算したピンで照合(値は例。上のコマンドの出力に置き換える)
kdig @203.0.113.53 +tls-pin=your-spki-pin-base64 example.com A
# 名前で照合する方式も試しておく
kdig @203.0.113.53 +tls-ca +tls-hostname=dns.example.com example.com A
どちらの照合でも、正しくない値で失敗することを併せて確かめます。ピンの文字を1つ変える、違うホスト名を渡す、といった操作で接続が拒否されれば、照合が働いています。違う値でも応答が返る場合は、オプションの指定が誤っているか、照合が行われていません。
ピンは証明書ではなく公開鍵のハッシュなので、証明書を更新しても同じ秘密鍵を使い続ければ値は変わりません。逆に、鍵を作り直すと値が変わり、ピンを登録した端末はすべて接続できなくなります。運用では、次に使う鍵のピンも事前に配っておき、端末側に2つ以上のピンを登録しておくのが一般的です。
手順4:結果を記録して定期的に繰り返す
署名の確認は一度で終わりではありません。証明書の自動更新、中間証明書の切り替え、サーバーの移設のたびに結果が変わり得ます。次の項目を記録し、変更のたびに比べると差分に気づきやすくなります。
- サーバーが送る証明書の枚数と、それぞれの発行者
openssl verifyの結果と、subjectAltName に含まれる名前- 署名アルゴリズムと有効期限
- SPKI ピンの値(現在の鍵と、次に使う鍵)
- 正しい値で成功し、誤った値で失敗すること
DoT のサーバー設定や証明書を入れ替える前には、現在の設定ファイルと証明書・秘密鍵をバックアップし、可能ならステージング環境で同じ手順を通してから本番に反映してください。
DoT の署名と DNSSEC の署名は守るものが違う
ここまで確かめた署名は、通信相手が本物かを保証するものです。DoT のサーバーが受け取った応答を正しく中継しているかまでは保証しません。サーバー自体が上流から偽の応答を受け取っていれば、その応答は暗号化されたまま端末に届きます。
応答データが正しいかを確かめるのは DNSSEC の役割です。DNSSEC の署名(RRSIG)は、ゾーンの持ち主が鍵で署名したもので、どの経路で運ばれても検証できます。DoT のサーバーが DNSSEC の検証を行っているかは、署名されたドメインに +dnssec を付けて問い合わせ、応答のフラグに ad が付くかで確かめられます。
kdig @203.0.113.53 +tls-ca +tls-hostname=dns.example.com +dnssec example.com SOA
DoT で経路を、DNSSEC でデータを守る、という役割分担を前提にすると、どちらの署名を確かめているのかを取り違えずに済みます。kdig のオプションや出力の形式は Knot DNS の版によって異なることがあるため、手元の版の kdig -h やマニュアルで確認してください(2026年10月現在)。
まとめ
- DoT の署名チェックは、証明書の連鎖・ハンドシェイクでの署名・SPKI ピンの3点で考える。
openssl s_client -showcertsで連鎖を取り出し、openssl verify -untrustedで信頼済みのルートまでつながるかを確かめる。- subjectAltName・署名アルゴリズム・有効期限を確認し、
-verify_return_error付きの接続で名前の照合も通す。 - ピンで照合する端末向けには公開鍵のハッシュを計算し、正しい値で成功・誤った値で失敗することを kdig で確かめる。
- DoT は通信相手を、DNSSEC は応答データを守る。応答の正しさは DNSSEC の検証で別に確かめる。