]> git.ipfire.org Git - thirdparty/dnspython.git/commitdiff
Open tsig key file (#1271)
authorRemi Jouannet <remijouannet@gmail.com>
Sat, 27 Jun 2026 18:02:43 +0000 (20:02 +0200)
committerGitHub <noreply@github.com>
Sat, 27 Jun 2026 18:02:43 +0000 (11:02 -0700)
* add tsigkeyring.from_file to use key file generate by tsig-keygen

* add tsigkeyring.from_file to use key file generate by tsig-keygen

dns/tsigkeyring.py
tests/test_tsigkeyring.py
tests/tsigkeys/1.key [new file with mode: 0644]
tests/tsigkeys/2.key [new file with mode: 0644]
tests/tsigkeys/3.key [new file with mode: 0644]
tests/tsigkeys/4.key [new file with mode: 0644]
tests/tsigkeys/5.key [new file with mode: 0644]

index d4f2dcbf899cc078a285a51f84c12ffc03a98c62..2f18bed62246cd83c99c58f9d473e2ec987adde9 100644 (file)
 """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)
index f8c889e815c033a5cdd08cb0afe8f6c08836e3c9..e29e2d246bc0bdfc01162c3959d64d918c62bcec 100644 (file)
@@ -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==")}
 
@@ -18,6 +19,39 @@ rich_keyring = {key.name: key}
 
 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):
@@ -56,3 +90,30 @@ class TSIGKeyRingTestCase(unittest.TestCase):
         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")
+            )
diff --git a/tests/tsigkeys/1.key b/tests/tsigkeys/1.key
new file mode 100644 (file)
index 0000000..8415d94
--- /dev/null
@@ -0,0 +1 @@
+key "aaa-test" {algorithm hmac-sha512;secret "WklIGweRJDBzgYJAfFAt3ln7NJAyz66W56/fpoeepVn5yqs3i3iiXFIS6GXpuFw0TyRfADBcnap8Vvl7TokfYA==";};
diff --git a/tests/tsigkeys/2.key b/tests/tsigkeys/2.key
new file mode 100644 (file)
index 0000000..5526322
--- /dev/null
@@ -0,0 +1 @@
+key"b-key"{algorithm"hmac-sha256";secret"KykTutSQNZYc+o8rqfMPH7ce2a9SruvKgPAqfn8EER8=";};
diff --git a/tests/tsigkeys/3.key b/tests/tsigkeys/3.key
new file mode 100644 (file)
index 0000000..49cfee9
--- /dev/null
@@ -0,0 +1,3 @@
+key example.com {
+    secret "WklIGweRJDBzgYJAfFAt3ln7NJAyz66W56/fpoeepVn5yqs3i3iiXFIS6GXpuFw0TyRfADBcnap8Vvl7TokfYA==";
+};
diff --git a/tests/tsigkeys/4.key b/tests/tsigkeys/4.key
new file mode 100644 (file)
index 0000000..149b379
--- /dev/null
@@ -0,0 +1,4 @@
+key bh- {
+    algorithm hmac-sha512;
+    secret "WklIGweRJDBzgYJAfFAt3ln7NJAyz66W56/fpoeepVn5yqs3i3iiXFIS6GXpuFw0TyRfADBcnap8Vvl7TokfYA==";
+};
diff --git a/tests/tsigkeys/5.key b/tests/tsigkeys/5.key
new file mode 100644 (file)
index 0000000..b964aa6
--- /dev/null
@@ -0,0 +1 @@
+key bh