Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
37 changes: 36 additions & 1 deletion dns/tsigkeyring.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,11 +18,46 @@
"""A place to store TSIG keys."""

import base64
import re
from typing import Any

from pathlib import Path
import dns.name
import dns.tsig

TSIG_KEY_FILE_RE = re.compile(
r"key\s*"
r'(?:"([^"]*)"' # group 1: quoted name
r"|([^{\s]+))" # group 2: unquoted name
r"\s*\{\s*"
r"(?:algorithm\s*" # --- algorithm block (optional) ---
r'(?:"([^"]*)"' # group 3: quoted algo
r"|([^;\s}]+))" # group 4: unquoted algo
r"\s*;\s*)?" # --- end optional block ---
r"secret\s*"
r'(?:"([^"]*)"' # group 5: quoted secret
r"|([^;\s}]+))" # group 6: unquoted secret
r"\s*;?\s*\}?"
)


def from_file(key_file: str) -> dict[dns.name.Name, Any]:
"""Open a tsig key file generate by tsig-keygen
and parse to retrieve key, algo and secret
@rtype: dict"""

content = Path(key_file).read_text().replace("\n", "").strip()

if m := TSIG_KEY_FILE_RE.match(content):
key_name = m.group(1) or m.group(2)
algorithm = m.group(3) or m.group(4)
secret = m.group(5) or m.group(6)
if algorithm:
return from_text({key_name: (algorithm, secret)})
else:
return from_text({key_name: secret})
else:
raise Exception(f"Error while parsing {key_file}")


def from_text(textring: dict[str, Any]) -> dict[dns.name.Name, Any]:
"""Convert a dictionary containing (textual DNS name, base64 secret)
Expand Down
63 changes: 62 additions & 1 deletion tests/test_tsigkeyring.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,10 @@

import base64
import unittest

import os
import dns.tsig
import dns.tsigkeyring
import pytest

text_keyring = {"keyname.": ("hmac-sha256.", "NjHwPsMKjdN++dOfE5iAiQ==")}

Expand All @@ -18,6 +19,39 @@

old_rich_keyring = {key.name: key.secret}

keyring_file_1 = {
dns.name.from_text("aaa-test"): dns.tsig.Key(
dns.name.from_text("aaa-test"),
"WklIGweRJDBzgYJAfFAt3ln7NJAyz66W56/fpoeepVn5yqs3i3iiXFIS6GXpuFw0TyRfADBcnap8Vvl7TokfYA==",
"hmac-sha512",
)
}

keyring_file_2 = {
dns.name.from_text("b-key"): dns.tsig.Key(
dns.name.from_text("b-key"),
"KykTutSQNZYc+o8rqfMPH7ce2a9SruvKgPAqfn8EER8=",
"hmac-sha256",
)
}

keyring_file_3 = {
dns.name.from_text("example.com"): dns.tsig.Key(
dns.name.from_text("example.com"),
"WklIGweRJDBzgYJAfFAt3ln7NJAyz66W56/fpoeepVn5yqs3i3iiXFIS6GXpuFw0TyRfADBcnap8Vvl7TokfYA==",
).secret
}

keyring_file_4 = {
dns.name.from_text("bh-"): dns.tsig.Key(
dns.name.from_text("bh-"),
"WklIGweRJDBzgYJAfFAt3ln7NJAyz66W56/fpoeepVn5yqs3i3iiXFIS6GXpuFw0TyRfADBcnap8Vvl7TokfYA==",
"hmac-sha512",
)
}

TEST_DIR = os.path.dirname(os.path.abspath(__file__))


class TSIGKeyRingTestCase(unittest.TestCase):
def test_from_text(self):
Expand Down Expand Up @@ -56,3 +90,30 @@ def test_old_from_and_to_text(self):
rkeyring = dns.tsigkeyring.from_text(old_text_keyring)
tkeyring = dns.tsigkeyring.to_text(rkeyring)
self.assertEqual(tkeyring, old_text_keyring)

def test_from_file_1(self):
"""test to parse key file 1.key"""
keyring = dns.tsigkeyring.from_file(os.path.join(TEST_DIR, "./tsigkeys/1.key"))
self.assertEqual(keyring, keyring_file_1)

def test_from_file_2(self):
"""test to parse key file 2.key"""
keyring = dns.tsigkeyring.from_file(os.path.join(TEST_DIR, "./tsigkeys/2.key"))
self.assertEqual(keyring, keyring_file_2)

def test_from_file_3(self):
"""test to parse key file 3.key"""
keyring = dns.tsigkeyring.from_file(os.path.join(TEST_DIR, "./tsigkeys/3.key"))
self.assertEqual(keyring, keyring_file_3)

def test_from_file_4(self):
"""test to parse key file 4.key"""
keyring = dns.tsigkeyring.from_file(os.path.join(TEST_DIR, "./tsigkeys/4.key"))
self.assertEqual(keyring, keyring_file_4)

def test_from_file_error(self):
"""test to parse key file 5.key"""
with pytest.raises(Exception):
keyring = dns.tsigkeyring.from_file(
os.path.join(TEST_DIR, "./tsigkeys/5.key")
)
1 change: 1 addition & 0 deletions tests/tsigkeys/1.key
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
key "aaa-test" {algorithm hmac-sha512;secret "WklIGweRJDBzgYJAfFAt3ln7NJAyz66W56/fpoeepVn5yqs3i3iiXFIS6GXpuFw0TyRfADBcnap8Vvl7TokfYA==";};
1 change: 1 addition & 0 deletions tests/tsigkeys/2.key
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
key"b-key"{algorithm"hmac-sha256";secret"KykTutSQNZYc+o8rqfMPH7ce2a9SruvKgPAqfn8EER8=";};
3 changes: 3 additions & 0 deletions tests/tsigkeys/3.key
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
key example.com {
secret "WklIGweRJDBzgYJAfFAt3ln7NJAyz66W56/fpoeepVn5yqs3i3iiXFIS6GXpuFw0TyRfADBcnap8Vvl7TokfYA==";
};
4 changes: 4 additions & 0 deletions tests/tsigkeys/4.key
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
key bh- {
algorithm hmac-sha512;
secret "WklIGweRJDBzgYJAfFAt3ln7NJAyz66W56/fpoeepVn5yqs3i3iiXFIS6GXpuFw0TyRfADBcnap8Vvl7TokfYA==";
};
1 change: 1 addition & 0 deletions tests/tsigkeys/5.key
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
key bh