]> git.ipfire.org Git - thirdparty/bind9.git/commitdiff
Size HMAC key generation buffers to the maximum block size
authorOndřej Surý <ondrej@isc.org>
Wed, 29 Apr 2026 14:23:10 +0000 (16:23 +0200)
committerOndřej Surý <ondrej@sury.org>
Thu, 30 Apr 2026 04:01:01 +0000 (06:01 +0200)
hmac_generate() declared its on-stack nonce buffer as
unsigned char data[ISC_MAX_MD_SIZE], i.e. 64 bytes. That is the maximum
digest size, but the buffer is filled up to the algorithm's HMAC block
size, which is 128 bytes for SHA-384 and SHA-512. Asking rndc-confgen
for an HMAC-SHA-384 or HMAC-SHA-512 key with -b > 512 (the documented
range allows up to 1024) wrote past the end of the stack buffer; on
hardened builds this aborted with a stack-smash detector firing
instead of producing a key.

Use the existing ISC_MAX_BLOCK_SIZE (128) for the buffer so the full
1..1024 range advertised by -A hmac-sha{384,512} works as documented.
The matching key_rawsecret[64] in confgen's generate_key() is enlarged
the same way so the generated key fits when dumped to the buffer.

Add a system test that exercises rndc-confgen across the previously
overflowing keysizes; with -Db_sanitize=address it caught the abort
before the fix.

Assisted-by: Claude:claude-opus-4-7
(cherry picked from commit 46f6bb6364db1dcbbfb2a2add72cff45fd1bda22)

bin/confgen/keygen.c
bin/tests/system/rndc_confgen/tests_rndc_confgen.py [new file with mode: 0644]
lib/dns/hmac_link.c

index c8832b5c4e0323a2b8724a273000a133a12a0425..c5cce21a57c72d8311100c48e242913d39d8c3a1 100644 (file)
@@ -20,6 +20,7 @@
 #include <isc/base64.h>
 #include <isc/buffer.h>
 #include <isc/file.h>
+#include <isc/md.h>
 #include <isc/mem.h>
 #include <isc/print.h>
 #include <isc/result.h>
@@ -97,7 +98,7 @@ generate_key(isc_mem_t *mctx, dns_secalg_t alg, int keysize,
        isc_result_t result = ISC_R_SUCCESS;
        isc_buffer_t key_rawbuffer;
        isc_region_t key_rawregion;
-       char key_rawsecret[64];
+       char key_rawsecret[ISC_MAX_BLOCK_SIZE];
        dst_key_t *key = NULL;
 
        switch (alg) {
diff --git a/bin/tests/system/rndc_confgen/tests_rndc_confgen.py b/bin/tests/system/rndc_confgen/tests_rndc_confgen.py
new file mode 100644 (file)
index 0000000..585e933
--- /dev/null
@@ -0,0 +1,48 @@
+# Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+#
+# SPDX-License-Identifier: MPL-2.0
+#
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0.  If a copy of the MPL was not distributed with this
+# file, you can obtain one at https://mozilla.org/MPL/2.0/.
+#
+# See the COPYRIGHT file distributed with this work for additional
+# information regarding copyright ownership.
+
+import base64
+import os
+import re
+
+import pytest
+
+import isctest
+
+
+def _extract_secret(stdout: bytes) -> bytes:
+    match = re.search(rb'secret\s+"([^"]+)"', stdout)
+    assert match is not None, f"no secret in output: {stdout!r}"
+    return base64.b64decode(match.group(1))
+
+
+@pytest.mark.parametrize(
+    "algorithm,bits",
+    [
+        ("hmac-sha256", 1),
+        ("hmac-sha256", 256),
+        ("hmac-sha256", 512),
+        ("hmac-sha384", 1),
+        ("hmac-sha384", 384),
+        ("hmac-sha384", 513),
+        ("hmac-sha384", 768),
+        ("hmac-sha384", 1024),
+        ("hmac-sha512", 1),
+        ("hmac-sha512", 512),
+        ("hmac-sha512", 513),
+        ("hmac-sha512", 1024),
+    ],
+)
+def test_rndc_confgen_hmac_keysize(algorithm, bits):
+    cmd = isctest.run.cmd([os.environ["RNDCCONFGEN"], "-A", algorithm, "-b", str(bits)])
+    secret = _extract_secret(cmd.proc.stdout)
+    assert len(secret) == (bits + 7) // 8
+    assert f"algorithm {algorithm};".encode() in cmd.proc.stdout
index 07c3090de9d3aceab3c303c965ea537262b2af36..60ad0de6329fb23b9d02f85621bbeab9eed54f3a 100644 (file)
@@ -280,7 +280,7 @@ hmac_generate(const isc_md_type_t *type, dst_key_t *key) {
        isc_buffer_t b;
        isc_result_t ret;
        unsigned int bytes, len;
-       unsigned char data[ISC_MAX_MD_SIZE] = { 0 };
+       unsigned char data[ISC_MAX_BLOCK_SIZE] = { 0 };
 
        len = isc_md_type_get_block_size(type);