手を動かしてDNSSECの検証をやってみよう

2020年12月09日 水曜日


【この記事を書いた人】
草場 健

2018年新卒入社でルータのファームウェアを開発しています。デバイスドライバやネットワークスタックなどの低レイヤーに興味があります。

「手を動かしてDNSSECの検証をやってみよう」のイメージ

IIJ 2020 TECHアドベントカレンダー 12/9(水)の記事です】

はじめに

DNSSECはDNSの応答が改ざんされていないかを確かめる仕組みです。
1997年にベースとなるRFC2065が発表された後も更新され、DNSSECに付随する議論は今でも様々な場で行われています。

お手元のdigコマンドで何かしらのレコードを引いてみてください。もしその応答のflagsにAD bitが立っていれば、裏でDNSSEC検証が行われています。

普段はリゾルバが行ってくれるこの検証、ぱっと見では何をやっているのか分かりづらいですが、実は公開鍵暗号とハッシュ関数の2つを扱う事で検証する事ができます。
というわけで、DNSSECの検証を自分の手でコマンドを打ってやってみましょう。

手を動かそう

さて、では早速手を動かしていきましょう。
今回検証するリソースレコードはこちら。

$ dig eng-blog.iij.ad.jp
...
;; ANSWER SECTION:
eng-blog.iij.ad.jp.     419     IN      A       203.180.155.24

電子署名を見てみよう

このAレコードの電子署名であるRRSIGレコードがこちらです。

$ dig eng-blog.iij.ad.jp +dnssec
...
eng-blog.iij.ad.jp.     1347    IN      RRSIG   A 8 4 86400 20201217151006 20201117151006 5628 iij.ad.jp. ITYLFLnc7s3rB0aZNVSrCsUNBs3vRztF87XjgFHf6Q8yQ2GPFX72s/w5 m5dUDeV/UJBEwB7udTAPxeNarqaoe/Ot0ExkjVpZ2u5zQXdO//ExbmBs 8YX/xCBTJJX6te0odwpJBzFmL2Ecxs6VNm71/xugV2EKIzzeI/vKLJkY Qhg=
...

フィールドに分けて出力してくれてはいますが、これだとなんだかよくわからないですね。というわけで対応するRFC4034を見てみましょう。
DNSSEC含むDNSに関連するRFCの一部はJPRS様による和訳が公開されています。
JPRS様に感謝しつつ、引用させていただきます。

3.1.  RRSIG RDATAのワイヤーフォーマット
 
   RRSIG RRのRDATAは、2オクテットの署名対象タイプ(Type Covered)、
   1オクテットのアルゴリズムフィールド、1オクテットのラベルフィールド、
   4オクテットのオリジナルTTLフィールド、4オクテットの有効期間終了
   フィールド、4オクテットの有効期間開始フィールド、2オクテットの
   鍵タグフィールド、署名者名フィールドおよび署名フィールドから構成される。
 
                        1 1 1 1 1 1 1 1 1 1 2 2 2 2 2 2 2 2 2 2 3 3
    0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   |        署名対象タイプ         | アルゴリズム  |    ラベル     |
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   |                         オリジナルTTL                         |
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   |                         有効期間終了                          |
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   |                         有効期間開始                          |
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   |            鍵タグ             |                               /
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+         署名者名              /
   /                                                               /
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   /                                                               /
   /                             署名                              /
   /                                                               /
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

digの出力内容を各フィールドと照らし合わせて見てみましょう。

フィールド名 説明
署名対象タイプ 署名対象のリソースレコードタイプ (eng-blog.iij.ad.jpの)Aレコード
アルゴリズム 署名に用いたアルゴリズム RSASHA256
ラベル 署名対象のラベル数 4つ (eng-blog, iij, ad, jp)
オリジナルTTL 署名対象のリソースレコードのTTL 86400
有効期間終了 署名の有効期間の終了時刻 2020年12月17日15時10分06秒
有効期間開始 署名の有効期間の開始時刻 2020年11月17日15時10分06秒
鍵タグ 署名に使われた鍵を絞るための値 5628
署名者名 署名に使われたDNSKEYの所有者名 iij.ad.jp
署名 電子署名 検証するための電子署名 (詳細は後ほど)

署名の検証に使う鍵を見てみよう

では、この署名の検証に使うための公開鍵を探しましょう。署名者名は iij.ad.jp なので、iij.ad.jpのDNSKEYレコードを引いてみます。

$ dig iij.ad.jp dnskey
...
;; ANSWER SECTION:
iij.ad.jp.              1488    IN      DNSKEY  256 3 8 AwEAAbdSiZ0RxmtsZUbE1v5kJWi3tXYBQYmZZmYVyw5QgSI7zSoOIcdW 2NoSX+rarklHdnBZKHgBE/lylRxxEi5pGQaJFLVEMBbUo5leb9nmikWG +GxWJL6dZic5LIt3hyAZ0r9jNJN/apzbQh16X41X8gE4lMymlMDXRf6W SbfKReW9
iij.ad.jp.              1488    IN      DNSKEY  257 3 8 AwEAAfByl5y3fBxdJ+ALSWRc55A8Dp8ZBr+7JxJcml1Ys/bmvVRvG72e s+DvOBR1jjS1l1j74e2eP89ClInWPVajZKc4AX69/btKQznfwC35secx Jniud6VctkF35xqfVZZnXOetF4+QtJtSYhVNg/hirc7HuSpgnzggqt75 X2qaA6THYR9oVBuV+Bu/CrN+KV3qs//r0Fcr7b6Q2VMRWWZe+uqFy5ij PUQq+nXGHgpYxY1CgWH4wRK8WWzUXzE55otuajaBhTH3pi7tz9nKqi7J gBs/l051Ezg7rFfrj857kprMWUu5oacLs3WfZOA0T6fx8aO792HkgEEr Th0LvVWVMqU=
...

こちらもRFC4034の説明を引用してみてみましょう。

2.1.  DNSKEY RDATAのワイヤーフォーマット
 
   DNSKEY RRのRDATAは、2オクテットのフラグフィールド、1オクテットの
   プロトコルフィールド、1オクテットのアルゴリズムフィールドおよび
   公開鍵フィールドから構成される。
 
                        1 1 1 1 1 1 1 1 1 1 2 2 2 2 2 2 2 2 2 2 3 3
    0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   |             フラグ            |  プロトコル   | アルゴリズム  |
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   /                                                               /
   /                              公開鍵                           /
   /                                                               /
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

鍵が2つあります。どちらが署名に使われた鍵でしょうか?
フラグが256の方がZSK(Zone Signing Key)であることを知っていると一目瞭然ですが、RRSIGには署名に使われた鍵を絞るための 鍵タグ フィールドがあります。
これはチェックサムのようなもので、計算方法はRFC4034の付録Bに記載があります。
今回はPythonスクリプトを用意したので、これで計算してみましょう。

import sys
import base64
 
if len(sys.argv) < 5:
    print(f'usage: {sys.argv[0]} <flag> <protocol> <algorithm> <data...>')
    sys.exit(1)
 
flag = int(sys.argv[1])
protocol = int(sys.argv[2])
algorithm = int(sys.argv[3])
data = ''.join(sys.argv[4:])
 
key = base64.b64decode(data)
ac = flag + (protocol << 8) + algorithm
 
for i in range(len(key)):
    if i % 2 == 0:
        ac += (key[i] << 8)
    else:
        ac += key[i]
    
    ac += (ac >> 16) & 0xFFFF
    ac &= 0xFFFF
 
print(ac)
$ python3 key.py 256 3 8 AwEAAbdSiZ0RxmtsZUbE1v5kJWi3tXYBQYmZZmYVyw5QgSI7zSoOIcdW 2NoSX+rarklHdnBZKHgBE/lylRxxEi5pGQaJFLVEMBbUo5leb9nmikWG +GxWJL6dZic5LIt3hyAZ0r9jNJN/apzbQh16X41X8gE4lMymlMDXRf6W SbfKReW9
5628
 
$ python3 key.py 257 3 8 AwEAAfByl5y3fBxdJ+ALSWRc55A8Dp8ZBr+7JxJcml1Ys/bmvVRvG72e s+DvOBR1jjS1l1j74e2eP89ClInWPVajZKc4AX69/btKQznfwC35secx Jniud6VctkF35xqfVZZnXOetF4+QtJtSYhVNg/hirc7HuSpgnzggqt75 X2qaA6THYR9oVBuV+Bu/CrN+KV3qs//r0Fcr7b6Q2VMRWWZe+uqFy5ij PUQq+nXGHgpYxY1CgWH4wRK8WWzUXzE55otuajaBhTH3pi7tz9nKqi7J gBs/l051Ezg7rFfrj857kprMWUu5oacLs3WfZOA0T6fx8aO792HkgEEr Th0LvVWVMqU=
48472

RRSIGレコードの方に署名に用いた鍵の鍵タグは5628とあるので、確かにフラグが256の方の鍵を使うことがこれで確認できました。
// ちなみに unique にDNSKEYが定まらない場合もあります。その時はどっちも試してください(-_-;;)

検証してみよう

アルゴリズムを見てみる

RRSIGのアルゴリズムフィールドを見るとRSASHA256が利用されているようです。まずはこのアルゴリズムがどのようになっているかを確認しましょう。RFC5702を見てみます。

3.  RRSIGリソースレコード
...
   ハッシュ = SHA-XXX(データ)
...
   署名 = ( 00 | 01 | FF* | 00 | プレフィックス | ハッシュ ) ** e (mod n)
  
   ここで"|"は連結(concatenation)であり、"00"、"01"、"FF"、"00"は、16進数で
   表記された固定オクテット値である。"e"は署名に使用するRSA鍵の秘密鍵の指数
   (private exponent)であり、"n"は署名鍵のモジュラス(public modulus)である。
   FF値を採るオクテットは丸括弧内の各項の長さが署名者の公開鍵のビット列表現
   ("n")と同じ長さになるまで繰り返されなければならない(MUST)。
...
   プレフィックスはASN.1 DER SHA-256のアルゴリズム指定プレフィックスであり、
   PKCS #1 v2.1 [RFC3447]で規定される。
 
   (0x)30 31 30 0d 06 09 60 86 48 01 65 03 04 02 01 05 00 04 20

また署名対象となるデータはRFC4034に書いてあります。

3.1.8.1.  署名の計算
...
         署名 = sign(RRSIG_RDATA | RR(1) | RR(2)... )
 
            "|"は連結(concatenation)を表す。
 
            RRSIG_RDATAは、RRSIG RDATAフィールドの署名者名フィールドを
               正規形式にし、更に署名フィールドを取り除いた残りの部分を
               ワイヤーフォーマットで表現したもの。
 
            RR(i) = 所有者名 | タイプ | クラス | TTL | RDATA長 | RDATA

署名の検証には以下2つのハッシュが一致するかを確認します。

  • RRSIGの署名を復号して得られるハッシュ
  • RRSIGの署名以外の部分 + 署名対象のAレコードのデータから得られるハッシュ

署名を復号してハッシュを確認する

この署名はRSAで暗号化されているだけなので、公開鍵から必要な情報を取り出して復号してみましょう。公開鍵のフォーマットはRFC3110に書いてあります。

2. KEYリソースレコードへのRSA公開鍵格納
...
         フィールド                   サイズ
         ----------                   ------
         指数長(exponent length)      1または3オクテット(本文参照)
         指数(exponent)               "指数長"フィールドで指定された長さ
         モジュラス(modulus)          残りの領域
 
   相互運用性を維持するため、指数フィールドとモジュラスフィールドは、
   それぞれ4096ビット長に制限される。公開鍵の指数は可変長の符号なし
   (unsigned)整数である。公開鍵の指数のオクテット長は、1から255バイトの範囲に
   ある場合は1オクテットで表現され、255バイトより長い場合には、0で埋められた
   オクテットに、符号なしで長さを示す2オクテットが続く形によって表現される
   (訳注: したがって3オクテットになる)。公開鍵のモジュラスフィールドは
   多倍精度の符号なし整数である。モジュラス長は、RDLENGTHと指数までの
   RDATAフィールドの長さから決定可能である。指数フィールドおよび
   モジュラスフィールドを値0のオクテットで開始することは禁止される。

DNSKEYレコードの公開鍵の部分をhexdumpして照らし合わせてみましょう。

$ echo -n AwEAAe0OG6iepFGCUQn8RuQrP7bRpn9nO7v16h5EQh27/zTbZ8JCs84i WhdWg+MePuiNTGNjmM3Nh1gHAeeLz74bZWxTxbshhJ++BkPn6rfqEc7w UQhhCFPcEAPRW6A4AqzaDHyOzmq46mjv8nCOYKsxO2aP+sxSZC9vhK4h jomRmmzh | base64 -id | hexdump -C
00000000  03 01 00 01 ed 0e 1b a8  9e a4 51 82 51 09 fc 46  |..........Q.Q..F|
00000010  e4 2b 3f b6 d1 a6 7f 67  3b bb f5 ea 1e 44 42 1d  |.+?....g;....DB.|
00000020  bb ff 34 db 67 c2 42 b3  ce 22 5a 17 56 83 e3 1e  |..4.g.B.."Z.V...|
00000030  3e e8 8d 4c 63 63 98 cd  cd 87 58 07 01 e7 8b cf  |>..Lcc....X.....|
00000040  be 1b 65 6c 53 c5 bb 21  84 9f be 06 43 e7 ea b7  |..elS..!....C...|
00000050  ea 11 ce f0 51 08 61 08  53 dc 10 03 d1 5b a0 38  |....Q.a.S....[.8|
00000060  02 ac da 0c 7c 8e ce 6a  b8 ea 68 ef f2 70 8e 60  |....|..j..h..p.`|
00000070  ab 31 3b 66 8f fa cc 52  64 2f 6f 84 ae 21 8e 89  |.1;f...Rd/o..!..|
00000080  91 9a 6c e1                                       |..l.|
00000084
フィールド名
指数長 3 bytes
指数 65537
モジュラス 0xed から始まる128bytes(=1024 bits)

あとは暗号文の65537乗をmodulo (上記のモジュラス)で計算すれば復号できます。

from base64 import b64decode
 
key = b64decode(input("dnskey: "))
explen = key[0]
exponent = int.from_bytes(key[1:(explen+1)], 'big')
modulus = int.from_bytes(key[(explen+1):], 'big')
 
sign = int.from_bytes(b64decode(input("sign: ")), 'big')

print(hex(pow(sign, exponent, modulus)))
$ python3 decrypt.py
dnskey: AwEAAbdSiZ0RxmtsZUbE1v5kJWi3tXYBQYmZZmYVyw5QgSI7zSoOIcdW 2NoSX+rarklHdnBZKHgBE/lylRxxEi5pGQaJFLVEMBbUo5leb9nmikWG +GxWJL6dZic5LIt3hyAZ0r9jNJN/apzbQh16X41X8gE4lMymlMDXRf6W SbfKReW9
sign: ITYLFLnc7s3rB0aZNVSrCsUNBs3vRztF87XjgFHf6Q8yQ2GPFX72s/w5 m5dUDeV/UJBEwB7udTAPxeNarqaoe/Ot0ExkjVpZ2u5zQXdO//ExbmBs 8YX/xCBTJJX6te0odwpJBzFmL2Ecxs6VNm71/xugV2EKIzzeI/vKLJkY Qhg=
0x1ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff003031300d060960864801650304020105000420c7b0d6d4cfef7d0db0939b400ca37d810e6bfb773e47d2dab543887ccecaaa13

頭についている大量の0xffやprefixを除くと、ハッシュが c7b0d6d4cfef7d0db0939b400ca37d810e6bfb773e47d2dab543887ccecaaa13  であることがわかります。

リソースレコードからハッシュを計算する

RRSIGのRDATA部分と署名対象のAレコードのデータを並べてsha-256を計算します。
Pythonスクリプトを書き疲れたので、printfを使って対象のバイナリをベタ書きします。

$ cat hash.sh
# RRSIG RECORD
printf "\x00\x01"                # record type
printf "\x08"                    # algorithm
printf "\x04"                    # labels
printf "\x00\x01\x51\x80"        # original ttl
printf "\x5f\xdb\x74\xce"        # expiration
printf "\x5f\xb3\xe7\xce"        # inception
printf "\x15\xfc"                # key tag
printf "\x03iij\x02ad\x02jp\x00" # signer name
 
# A RECORD
printf "\x08eng-blog\x03iij\x02ad\x02jp\x00" # name
printf "\x00\x01"                            # record type
printf "\x00\x01"                            # class
printf "\x00\x01\x51\x80"                    # ttl
printf "\x00\x04"                            # rdata length
printf "\xcb\xb4\x9b\x18"                    # rdata(=203.180.155.24)
 
$ bash hash.sh | sha256sum
c7b0d6d4cfef7d0db0939b400ca37d810e6bfb773e47d2dab543887ccecaaa13  -

署名から得たハッシュと一致していますね。
これにより、ZSKを信頼出来ると仮定すれば、eng-blog.iij.ad.jpのAレコードを信頼出来ることになります。

信頼の連鎖を繋ごう

ZSKが格納されているDNSKEYレコードにも同様に対応するRRSIGレコードがあります。

$ dig iij.ad.jp dnskey +dnssec
...
iij.ad.jp.              2176    IN      RRSIG   DNSKEY 8 3 86400 20201217151006 20201117151006 48472 iij.ad.jp. IvflOJImlu9iSR7LO80wv9o4FJsmy0UDB1gmIPzbqaTIa+z9ePG+tSYa z6HEck75SWWeZeXM0zbAuYX5/had7qTh+IFhO1m9GcIg9+KTdHrKR9jP 9DuVvk3IGJXTpO/L5fPfwsFPrSqfktO9ug6mnwrXshqKIk16NcTggpdd k22Wt1ksDDgZ/61p9j5Zk0CTR2t8/I/rwCcWc7zUsyLAF2rbcBufpsn/ PEz/qPnCgFRjSRkeDln0MaX9NH+48A5vYbthLhtGgc2pviIACc6EYaw2 HSggSD2zR1mJLy7P4APvgu1ijSKXpgF4SpRmhqeuYLkGMbvKnK87N5LK vL7VKg==

手順は同様なので詳細は割愛しますが、こちらは先ほど使われなかった方のDNSKEYであるKSK(=Key Signing Key)を使って署名されています。
則ち、KSKを信頼出来ると仮定すれば、ZSKを信頼出来ることになります。

ではKSKはどのように信頼するのかというと、親ゾーンであるad.jpで管理されているiij.ad.jpのDSレコードにiij.ad.jpのKSKのハッシュが登録されています。以下のレコードです。

$ dig iij.ad.jp ds
...
iij.ad.jp.              1292    IN      DS      48472 8 2 7E73B74DD5BF727B67C7D62A2D8CA3C02FECF00DBC2848DB7C57A99B 515D0D0E

RFC4034を見て、当てはめてみましょう。

5.1.  DS RDATAのワイヤーフォーマット

   DS RRのRDATAは2オクテットの鍵タグフィールド、1オクテットのアルゴリズム
   フィールド、1オクテットのダイジェストタイプフィールドおよびダイジェスト
   フィールドから構成される。

                        1 1 1 1 1 1 1 1 1 1 2 2 2 2 2 2 2 2 2 2 3 3
    0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   |             鍵タグ            | アルゴリズム  |ダイジェストタイプ|
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   /                                                               /
   /                           ダイジェスト                        /
   /                                                               /
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
...
5.1.4.  ダイジェストフィールド
 
   DS RRはDNSKEY RRのダイジェストを持つことにより、そのDNSKEY RRを参照
   する。
 
   ダイジェストタイプは、正規形式のDNSKEY RRの所有者名のFQDN表記と、
   そのDNSKEYのRDATAを連結したものにダイジェストアルゴリズムを適用して
   算出する。
  
     ダイジェスト = ダイジェストアルゴリズム(DNSKEY所有者名 | DNSKEY RDATA);
 
      "|"は連結(concatenation)を表す。
 
     DNSKEY RDATA = フラグ | プロトコル | アルゴリズム | 公開鍵
フィールド名 説明
鍵タグ 対象のDNSKEYレコードの鍵タグ 48472 (=KSKの鍵タグ)
アルゴリズム 対象のDNSKEYレコードのアルゴリズム 8 (=KSKと同じ)
ダイジェストタイプ 利用するハッシュの種類 2: SHA-256
ダイジェスト ハッシュ 7E73…

ハッシュを計算する dnssec-dsfromkey というコマンドがありますが、それは使わずにDNSKEYレコードに対応するハッシュ値を計算してみましょう。またもprintfでゴリ押しします。

$ cat ds.sh
printf "\x03iij\x02ad\x02jp\x00" # name
printf "\x01\x01"                # flag
printf "\x03"                    # protocol
printf "\x08"                    # algorithm
 
# public key
echo -n AwEAAfByl5y3fBxdJ+ALSWRc55A8Dp8ZBr+7JxJcml1Ys/bmvVRvG72e s+DvOBR1jjS1l1j74e2eP89ClInWPVajZKc4AX69/btKQznfwC35secx Jniud6VctkF35xqfVZZnXOetF4+QtJtSYhVNg/hirc7HuSpgnzggqt75 X2qaA6THYR9oVBuV+Bu/CrN+KV3qs//r0Fcr7b6Q2VMRWWZe+uqFy5ij PUQq+nXGHgpYxY1CgWH4wRK8WWzUXzE55otuajaBhTH3pi7tz9nKqi7J gBs/l051Ezg7rFfrj857kprMWUu5oacLs3WfZOA0T6fx8aO792HkgEEr Th0LvVWVMqU= | base64 -id
 
$ bash ds.sh | sha256sum
7e73b74dd5bf727b67c7d62a2d8ca3c02fecf00dbc2848db7c57a99b515d0d0e  -

大文字小文字が違うので見づらいですが、これはiij.ad.jpのDSレコードの中身と一致していますね。
これで(ad.jpの権威サーバが持つ)iij.ad.jpのDSレコードが信頼出来ると仮定すると、iij.ad.jpのKSKが信頼出来ることがわかります。これで連鎖が繋がりました。

トラストアンカーをチェックしよう

次はDSレコードのRRSIG、ad.jpのDNSKEYのRRSIG… と検証を繰り返すことによって、最終的には「あとはルートゾーンのKSKが信頼出来ればOK」というところまでたどり着きます。

DNSSECを検証しているレゾルバは、予め信頼するルートゾーンのKSKの情報(=トラストアンカー)を保持しています。そのため、トラストアンカーからルートゾーンのKSKを信頼する事が出来れば検証が完了します。

最新のトラストアンカーは http://data.iana.org/root-anchors/root-anchors.xml から入手出来ます。

...
<KeyDigest id="Klajeyz" validFrom="2017-02-02T00:00:00+00:00">
<KeyTag>20326</KeyTag>
<Algorithm>8</Algorithm>
<DigestType>2</DigestType>
<Digest>E06D44B80B8F1D39A95C0B0D7C65D08458E880409BBC683457104237C7F8EC8D</Digest>
</KeyDigest>
...

ではルートゾーンのKSKのハッシュを計算してみましょう。

$ dig . dnskey
...
;; ANSWER SECTION:
.                       1288    IN      DNSKEY  257 3 8 AwEAAaz/tAm8yTn4Mfeh5eyI96WSVexTBAvkMgJzkKTOiW1vkIbzxeF3 +/4RgWOq7HrxRixHlFlExOLAJr5emLvN7SWXgnLh4+B5xQlNVz8Og8kv ArMtNROxVQuCaSnIDdD5LKyWbRd2n9WGe2R8PzgCmr3EgVLrjyBxWezF 0jLHwVN8efS3rCj/EWgvIWgb9tarpVUDK/b58Da+sqqls3eNbuv7pr+e oZG+SrDK6nWeL3c6H5Apxz7LjVc1uTIdsIXxuOLYA4/ilBmSVIzuDWfd RUfhHdY6+cn8HFRm+2hM8AnXGXws9555KrUB5qihylGa8subX2Nn6UwN R1AkUTV74bU=
...
$ cat rootds.sh
printf "\x00" # dnskey
printf "\x01\x01" # flag
printf "\x03" # protocol
printf "\x08" # algorithm
 
echo -n AwEAAaz/tAm8yTn4Mfeh5eyI96WSVexTBAvkMgJzkKTOiW1vkIbzxeF3 +/4RgWOq7HrxRixHlFlExOLAJr5emLvN7SWXgnLh4+B5xQlNVz8Og8kv ArMtNROxVQuCaSnIDdD5LKyWbRd2n9WGe2R8PzgCmr3EgVLrjyBxWezF 0jLHwVN8efS3rCj/EWgvIWgb9tarpVUDK/b58Da+sqqls3eNbuv7pr+e oZG+SrDK6nWeL3c6H5Apxz7LjVc1uTIdsIXxuOLYA4/ilBmSVIzuDWfd RUfhHdY6+cn8HFRm+2hM8AnXGXws9555KrUB5qihylGa8subX2Nn6UwN R1AkUTV74bU= | base64 -id
 
$ bash rootds.sh | sha256sum
e06d44b80b8f1d39a95c0b0d7c65d08458e880409bbc683457104237c7f8ec8d  -

またもや大文字小文字が違うので見づらいですが… 一致していますね!

というわけでこのようにして、eng-blog.iij.ad.jpのAレコードを検証する事ができました。

まとめ

リソースレコードをDNSSEC検証する方法を紹介しました。

今回は検証にあたってRFCを3つ紹介しましたが、DNSSECのRFCは他にもまだ多く存在しますし、今も増え続けています。
JPRS様がDNSに関連するRFCの和訳を公開されていますので、今回の記事でDNS(SEC)に興味を持った方は是非RFCを読んでみてください。また、エンジニアブログでも過去にDNS(SEC)関連の記事があります。

ここまでお読みいただき、ありがとうございました。

IIJ Engineers blog読者プレゼントキャンペーン
  • Twitterフォロー&条件付きツイートで「IoT米」を抽選で20名にプレゼント!
    応募期間は2020/12/01~2020/12/31まで。詳細はこちらをご覧ください。
    今すぐツイートするならこちら→ フォローもお忘れなく!

草場 健

2020年12月09日 水曜日

2018年新卒入社でルータのファームウェアを開発しています。デバイスドライバやネットワークスタックなどの低レイヤーに興味があります。

Related
関連記事