Size HMAC key generation buffers to the maximum block size

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 46f6bb6364)
This commit is contained in:
Ondřej Surý 2026-04-29 16:23:10 +02:00 committed by Ondřej Surý
parent dc5eb3fe25
commit 45ea92ea4b
No known key found for this signature in database
GPG key ID: 2820F37E873DEA41
3 changed files with 51 additions and 2 deletions

View 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/result.h>
#include <isc/string.h>
@ -96,7 +97,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) {

View file

@ -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

View file

@ -283,7 +283,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);