[LTP] [PATCH v2 20/33] keyctl28: Negative and boundary tests for KEYCTL_DH_COMPUTE
Andrea Cervesato
andrea.cervesato@suse.de
Fri Sep 4 14:09:09 CEST 2026
From: Andrea Cervesato <andrea.cervesato@suse.com>
Test error and boundary conditions of KEYCTL_DH_COMPUTE using a
parameterized tcase table: buffer smaller than secret (EOVERFLOW),
bogus prime key (ENOKEY), non-user key (EOPNOTSUPP), NULL buffer
(EINVAL), non-zero __spare (EINVAL), buflen > 1024 (EMSGSIZE),
otherinfolen > 64 (EMSGSIZE), and unknown KDF hash name (ENOENT).
Signed-off-by: Andrea Cervesato <andrea.cervesato@suse.com>
---
runtest/syscalls | 1 +
testcases/kernel/syscalls/keyctl/.gitignore | 1 +
testcases/kernel/syscalls/keyctl/keyctl28.c | 140 ++++++++++++++++++++++++++++
3 files changed, 142 insertions(+)
diff --git a/runtest/syscalls b/runtest/syscalls
index d23461c4b..6fdbbea17 100644
--- a/runtest/syscalls
+++ b/runtest/syscalls
@@ -745,6 +745,7 @@ keyctl24 keyctl24
keyctl25 keyctl25
keyctl26 keyctl26
keyctl27 keyctl27
+keyctl28 keyctl28
kcmp01 kcmp01
kcmp02 kcmp02
diff --git a/testcases/kernel/syscalls/keyctl/.gitignore b/testcases/kernel/syscalls/keyctl/.gitignore
index 720ba1de6..139e480b3 100644
--- a/testcases/kernel/syscalls/keyctl/.gitignore
+++ b/testcases/kernel/syscalls/keyctl/.gitignore
@@ -25,3 +25,4 @@
/keyctl25
/keyctl26
/keyctl27
+/keyctl28
diff --git a/testcases/kernel/syscalls/keyctl/keyctl28.c b/testcases/kernel/syscalls/keyctl/keyctl28.c
new file mode 100644
index 000000000..f62aeb582
--- /dev/null
+++ b/testcases/kernel/syscalls/keyctl/keyctl28.c
@@ -0,0 +1,140 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (c) 2026 Andrea Cervesato <andrea.cervesato@suse.com>
+ */
+
+/*\
+ * Negative and boundary test cases for ``KEYCTL_DH_COMPUTE`` of :manpage:`keyctl(2)`.
+ *
+ * [Algorithm]
+ *
+ * - verify ``EOVERFLOW`` when buffer is smaller than secret size (255 < 256)
+ * - verify ``ENOKEY`` when prime key id does not exist
+ * - verify ``EOPNOTSUPP`` when prime key is not of "user" type
+ * - verify ``EINVAL`` when buffer is ``NULL`` with non-zero buflen
+ * - verify ``EINVAL`` when KDF ``__spare`` field contains non-zero data
+ * - verify ``EMSGSIZE`` when KDF requested output length exceeds 1024
+ * - verify ``EMSGSIZE`` when KDF otherinfo length exceeds 64
+ * - verify ``ENOENT`` when KDF hash algorithm name is unknown
+ */
+
+#include "keyctl_common.h"
+#include "keyctl_dh_data.h"
+
+static struct keyctl_dh_params *dh_params;
+static struct keyctl_dh_params *dh_bogus_prime;
+static struct keyctl_dh_params *dh_nonuser_prime;
+
+static struct keyctl_kdf_params *kdf_valid;
+static struct keyctl_kdf_params *kdf_spare_nonzero;
+static struct keyctl_kdf_params *kdf_oi_toolarge;
+static struct keyctl_kdf_params *kdf_unknown_hash;
+
+static unsigned char out_buf[1025];
+
+static struct tcase {
+ struct keyctl_dh_params **params;
+ void *buffer;
+ size_t buflen;
+ struct keyctl_kdf_params **kdf;
+ int exp_errno;
+ const char *desc;
+} tcases[] = {
+ { &dh_params, out_buf, 255, NULL,
+ EOVERFLOW, "buffer smaller than secret size (255 < 256)" },
+
+ { &dh_bogus_prime, out_buf, 256, NULL,
+ ENOKEY, "bogus prime key ID" },
+
+ { &dh_nonuser_prime, out_buf, 256, NULL,
+ EOPNOTSUPP, "non-user key as prime parameter" },
+
+ { &dh_params, NULL, 256, NULL,
+ EINVAL, "NULL buffer with non-zero buflen" },
+
+ { &dh_params, out_buf, 32, &kdf_spare_nonzero,
+ EINVAL, "KDF non-zero __spare field" },
+
+ { &dh_params, out_buf, 1025, &kdf_valid,
+ EMSGSIZE, "KDF output length > 1024" },
+
+ { &dh_params, out_buf, 32, &kdf_oi_toolarge,
+ EMSGSIZE, "KDF otherinfolen > 64" },
+
+ { &dh_params, out_buf, 32, &kdf_unknown_hash,
+ ENOENT, "unknown KDF hash algorithm name" },
+};
+
+static void setup(void)
+{
+ key_serial_t key_priv, key_prime, key_base;
+
+ SAFE_KEYCTL(KEYCTL_JOIN_SESSION_KEYRING, 0, 0, 0, 0);
+
+ key_priv = new_user_key("dh_priv", dh_priv, sizeof(dh_priv),
+ KEY_SPEC_PROCESS_KEYRING);
+ key_prime = new_user_key("dh_prime", dh_prime, sizeof(dh_prime),
+ KEY_SPEC_PROCESS_KEYRING);
+ key_base = new_user_key("dh_base", dh_base, sizeof(dh_base),
+ KEY_SPEC_PROCESS_KEYRING);
+
+ dh_params->priv = key_priv;
+ dh_params->prime = key_prime;
+ dh_params->base = key_base;
+
+ *dh_bogus_prime = *dh_params;
+ dh_bogus_prime->prime = INT32_MAX;
+
+ *dh_nonuser_prime = *dh_params;
+ dh_nonuser_prime->prime = KEY_SPEC_PROCESS_KEYRING;
+
+ kdf_valid->hashname = "sha256";
+ kdf_valid->otherinfo = "info";
+ kdf_valid->otherinfolen = 4;
+
+ *kdf_spare_nonzero = *kdf_valid;
+ kdf_spare_nonzero->__spare[0] = 1;
+
+ *kdf_oi_toolarge = *kdf_valid;
+ kdf_oi_toolarge->otherinfolen = 65;
+
+ *kdf_unknown_hash = *kdf_valid;
+ kdf_unknown_hash->hashname = "sha9000";
+}
+
+static void verify_negative(unsigned int n)
+{
+ struct tcase *tc = &tcases[n];
+ struct keyctl_dh_params *p = *tc->params;
+ struct keyctl_kdf_params *kdf = tc->kdf ? *tc->kdf : NULL;
+
+ TST_EXP_FAIL2(keyctl(KEYCTL_DH_COMPUTE, (unsigned long)p,
+ (unsigned long)tc->buffer, tc->buflen,
+ (unsigned long)kdf),
+ tc->exp_errno,
+ "KEYCTL_DH_COMPUTE with %s", tc->desc);
+}
+
+static struct tst_test test = {
+ .setup = setup,
+ .test = verify_negative,
+ .tcnt = ARRAY_SIZE(tcases),
+ .min_kver = "4.12",
+ .needs_kconfigs = (const char *[]) {
+ "CONFIG_KEYS=y",
+ "CONFIG_KEY_DH_OPERATIONS=y",
+ "CONFIG_CRYPTO_DH",
+ "CONFIG_CRYPTO_SHA256",
+ NULL
+ },
+ .bufs = (struct tst_buffers []) {
+ {&dh_params, .size = sizeof(*dh_params)},
+ {&dh_bogus_prime, .size = sizeof(*dh_bogus_prime)},
+ {&dh_nonuser_prime, .size = sizeof(*dh_nonuser_prime)},
+ {&kdf_valid, .size = sizeof(*kdf_valid)},
+ {&kdf_spare_nonzero, .size = sizeof(*kdf_spare_nonzero)},
+ {&kdf_oi_toolarge, .size = sizeof(*kdf_oi_toolarge)},
+ {&kdf_unknown_hash, .size = sizeof(*kdf_unknown_hash)},
+ {},
+ },
+};
--
2.51.0
More information about the ltp
mailing list