"""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)
import base64
import unittest
-
+import os
import dns.tsig
import dns.tsigkeyring
+import pytest
text_keyring = {"keyname.": ("hmac-sha256.", "NjHwPsMKjdN++dOfE5iAiQ==")}
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):
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")
+ )