DNSフルリゾルバの実装への DNSSEC の組み込み – DNSSEC と反復検索
2024年04月24日 水曜日
CONTENTS
研究開発中のフルリゾルバ実装の実用性を向上する目的で、 DNSSEC検証機能を実装しました。
反復検索と DNSSEC の関係について説明した後に実装について紹介します。
ゾーンの階層とフルリゾルバの反復検索
DNSでは、ドメイン名全体が成す木構造を分散して管理します。
上位から下位へと部分木の管理を委任することで、管理を分割します。
この管理単位をゾーン(zone)と呼びます(図: ゾーンの階層)。
ゾーンは上位から下位へ、委任情報によって紐付けられます。
委任情報は、委任先のゾーンの権威サーバの情報1を提供します。
名前解決を必要とするクライアントアプリケーションの要求を直接処理するのがDNSフルリゾルバの役割です。
フルリゾルバは委任情報を辿りながらゾーンの階層に沿って解決を行います。これを反復検索と言います。
以下(図: 反復検索)は iij.ad.jp の A レコードを解決する例です。
名前解決の結果は、ドメイン名と(A, NS といった)タイプに対して決まります。
結果のリソースレコード(RR)2が存在するとき、それが一つとは限らず複数存在することがあります。
ドメイン名とタイプに対して決まる、空でない RR の集合を RRset と言います。
反復検索と DNSSEC の認証の連鎖
DNSSECで検証することができるのは、次の 2種類です。
- (1)
- 上位ゾーンから下位ゾーンへのDNSSECで署名されているゾーンへの委任が存在すること(2024/04/30:下線部分を追記)
- (2)
- ゾーンを管理する権威サーバから返答される RRset が正しいこと
DNSSEC検証をともなう反復検索では、この 2種類の検証を “.” ゾーンから繰り返し、連鎖を確認することで、最終的な返答内容の正しさを確認します。
これは認証の連鎖3と呼ばれます。
DNSSEC検証を行なうための RR として、DNSKEY、DS(Delegation Signer)、RRSIG があります。
DNSKEY は公開鍵の情報を格納し、RRsetに対する署名を格納する RRSIG とともに利用することで、RRset を署名検証することができます。DS は DNSKEY のダイジェスト値を格納し、上位のゾーンに登録されます。
(1)の委任の存在を検証するために必要な RR は DS と DNSKEY です。
委任先ゾーンが DNSSEC で署名されている場合、委任元から返る委任情報には DS RR が含まれています
(委任先ゾーンが未署名の場合には、DS RR は有りません。その場合には認証の連鎖は途切れることになり、最終的な返答内容を検証することはできなくなります)。
委任先ゾーンの DNSKEY RR のうち、そのダイジェスト値が、委任情報の DS RR と一致するものがあれば、DNSSECで署名されているゾーンへの委任が存在することになります(2024/04/30:下線部分を追記)。
ダイジェスト値が一致する DNSKEY を SEP(Secure Entry Point)と言います(図: 委任とDNSSEC)。
委任元に DS があるにもかかわらず、SEP が見つからない場合は検証失敗です。
(2)の返答される RRset が正しいことを検証するために必要な RR は DNSKEY と RRSIG(RRset の署名値) です。
委任先ゾーンの DNSKEY RRset の署名を SEP DNSKEY で検証することで、DNSKEY RRset が正しいことが確認できます。
ここまでで、委任先の権威サーバから返る RRset が正しいかを確認できる準備ができたことになります。
なぜならば、ゾーン内の RRset は DNSKEY RRset 内のいずれかの DNSKEY で署名検証できるためです。
これは、DS RRset についても同様で、さらに下位の署名されているゾーンへ委任がある場合、その委任情報に含まれる DS RRset の署名を検証することができます(図: 委任とDNSSEC)。
フルリゾルバ実装 bowline の反復検索への DNSSEC の組み込み
我々はプログラミング言語HaskellでDNSライブラリ群dnsext4 と
bowlineという名前のフルリゾルバを開発56しています。
今回、dnsextライブラリにDNSSEC検証7の機能を実装し、フルリゾルバの反復検索にその検証機能を組み込みました
反復検索への組み込みでは、具体的には委任の処理に以下の手順を組み込みます。
- 委任情報を取得
- 委任元 DNSKEY で DS の署名を検証
- 委任先 DNSKEY を取得
- 委任元 DS と 委任先 DNSKEY を照合して委任先 SEP DNSKEY を決定
- 委任先 SEP DNSKEY で DNSKEY の署名を検証
もともと委任情報は次のようなデータ型だと考えることができます。
data Delegation = data Delegation = Delegation { delegationZone :: Domain {- 委任先ゾーン頂点 -} , delegationNS :: [DEntry] {- NS と A/AAAA のリスト -} }
これを次のようなデータ型に拡張します。
委任情報に含まれる DS と、委任先の DNSKEY RRset を保持できるようになり、DNSSEC 付きの反復検索を実現できます。
data Delegation = Delegation { delegationZone :: Domain {- 委任先ゾーン頂点 -} , delegationNS :: [DEntry] {- NS と A/AAAA のリスト -} , delegationDS :: [RD_DS] {- 委任元 DS RRset -} , delegationDNSKEY :: [RD_DNSKEY] {- DS による SEP の照合、SEP による署名検証済みの DNSKEY RRset -} }
反復検索で得られた、最終的な委任先が DNSSEC 署名されている場合には、そのゾーンの DNSKEY で、結果の RRset を署名検証することができます。
ここまでで、肯定的な応答に対する DNSSEC の検証が完了します。なお、DNSSEC の否定応答については、別途記事を執筆しています。
署名検証を行なう際には、RRsetのワイヤーフォーマットの正規形を再計算し、正規順序に並び換える必要があります。
当初の実装では、この正規順序の並び換え時に、RR の可変データ部の長さを含めてしまうバグ8がありました。
複数の NS の名前の長さが同じゾーン(ex. {ns1,ns2,ns3}.example.com.)では再現しない問題のため、気付きにくいバグとなっていました。
最後に、検証用に用意したdugコマンド9を紹介します。
dug は bind9 付属の dig コマンドと似た DNSクライアントのコマンドで、通常のテキスト出力の他にJSON出力に対応しています。
また、dig コマンドは DNS トランスポートとして、UDP、TCP、TLS、HTTP/2、HTTP/2(TLS無し)を利用できますが、dug はそれに加えて QUIC と HTTP/3 に対応しています。
さらに、bowlineで使われている反復検索アルゴリズムを使ってDNSを検索できます。これには‘-i’オプションを指定します。
以下が、www.iij.ad.jp. A への DNSSEC検証付き反復検索の実行例です。認証の連鎖が繋って、最終結果の署名検証が成功する様子が確認できます。
% dug -v 1 -i www.iij.ad.jp. A +dnssec ... root-priming: verification success - RRSIG of NS: "." "a.root-servers.net." [198.41.0.4,2001:503:ba3e::2:30] "b.root-servers.net." [170.247.170.2,2801:1b8:10::b] ... delegation - verification success - RRSIG of DS: "." -> "jp." zone: "jp.": "a.dns.jp." [203.119.1.1,2001:dc4::1] "b.dns.jp." [202.12.30.131,2001:dc2::1] ... fillDelegationDNSKEY: query ("jp.",DNSKEY) servers: 210.138.175.244 2001:502:ad09::5 ... no delegation: "jp." -> "ad.jp." ... delegation - verification success - RRSIG of DS: "jp." -> "iij.ad.jp." zone: "iij.ad.jp.": "dns0.iij.ad.jp." [210.130.0.5,2001:240::105] "dns1.iij.ad.jp." [210.130.1.5,2001:240::115] fillDelegationDNSKEY: query ("iij.ad.jp.",DNSKEY) servers: 210.130.1.5 2001:240::105 ... iterative: query ("www.iij.ad.jp.",A) servers: 210.130.0.5 2001:240::115 ... no delegation: "iij.ad.jp." -> "www.iij.ad.jp." ... verification success - RRSIG of "www.iij.ad.jp." A ;; 41usec ;; HEADER SECTION: ;Standard query, NoError, id: 0 ;Flags: Recursion Desired, Recursion Available ;; QUESTION SECTION: ;www.iij.ad.jp. IN A ;; ANSWER SECTION: www.iij.ad.jp. 300(5 mins) IN A 202.232.2.180 www.iij.ad.jp. 300(5 mins) IN RRSIG RD_RRSIG {rrsig_type = A, rrsig_pubalg = RSASHA256, rrsig_num_labels = 4, rrsig_ttl = 300(5 mins), rrsig_expiration = Fri, 19 Apr 2024 15:10:04 GMT, rrsig_inception = Wed, 20 Mar 2024 15:10:04 GMT, rrsig_key_tag = 54096, rrsig_zone = "iij.ad.jp.", rrsig_signature = \# 128 9c1fc9d353b3dae7269dde50051d737c94d31edbab0c1390406a5194b83813eb9a3d5c8d420cd2a57a94f3c1a8670271d81b51aa256b70309056f0319e55fe10b6d251fc08469a47e2ac613d712d90e5198cfeb1512295c32f6f6bb0498efb3d5c56ea9bbf1fbc0d1b2fdacc20ab8c4ea76cedb1f55782876315270a61b7dfb8} ;; AUTHORITY SECTION: ;; ADDITIONAL SECTION:
- 委任情報には、委任先のゾーンの権威サーバの名前(NS)が含まれています。さらに、委任元から見て NS がサブドメイン名のときには、NS に対応する A あるいは AAAA レコードが委任情報に含まれます。これをグルー(glue)レコードと言います。委任元から見て NS がサブドメイン名でないときには、グルーが利用できないため、反復検索自身を再帰します。↩︎
- RFC 1034 section 3.6 – Resource Records↩︎
- RFC 4033 section 2 – Authentication Chain↩︎
- dnsextライブラリ群のレポジトリです(https://github.com/kazu-yamamoto/dnsext/)。↩︎
- フルリゾルバ実装については以前の記事[DNS の反復的な名前解決の仕組みとフルリゾルバの実装]をご覧ください。↩︎
- bowline の実装は dnsext内のサブディレクトリに置いています(https://github.com/kazu-yamamoto/dnsext/tree/main/dnsext-bowline/bowline/)。↩︎
- 検証機能のライブラリ実装については以前の記事 [DNSSECの基本的な検証機能とその実装]をご覧ください。↩︎
- https://github.com/kazu-yamamoto/dnsext/pull/129↩︎
- https://github.com/kazu-yamamoto/dnsext/tree/main/dnsext-bowline/dug/↩︎