[LTP] [PATCH v2 26/33] keyctl33: Negative tests for KEYCTL_PKEY_*
Andrea Cervesato
andrea.cervesato@suse.de
Fri Sep 4 14:09:15 CEST 2026
From: Andrea Cervesato <andrea.cervesato@suse.com>
Add negative and boundary test cases for KEYCTL_PKEY_* operations
(QUERY, ENCRYPT, DECRYPT, SIGN, VERIFY), testing invalid key serials,
unsupported key types, invalid info strings, and buffer size limits.
Signed-off-by: Andrea Cervesato <andrea.cervesato@suse.com>
---
runtest/syscalls | 1 +
testcases/kernel/syscalls/keyctl/.gitignore | 1 +
testcases/kernel/syscalls/keyctl/keyctl33.c | 247 ++++++++++++++++++++++++++++
3 files changed, 249 insertions(+)
diff --git a/runtest/syscalls b/runtest/syscalls
index d4007f7a6..7658ac859 100644
--- a/runtest/syscalls
+++ b/runtest/syscalls
@@ -750,6 +750,7 @@ keyctl29 keyctl29
keyctl30 keyctl30
keyctl31 keyctl31
keyctl32 keyctl32
+keyctl33 keyctl33
kcmp01 kcmp01
kcmp02 kcmp02
diff --git a/testcases/kernel/syscalls/keyctl/.gitignore b/testcases/kernel/syscalls/keyctl/.gitignore
index 8b1627bee..0f209d7e0 100644
--- a/testcases/kernel/syscalls/keyctl/.gitignore
+++ b/testcases/kernel/syscalls/keyctl/.gitignore
@@ -30,3 +30,4 @@
/keyctl30
/keyctl31
/keyctl32
+/keyctl33
diff --git a/testcases/kernel/syscalls/keyctl/keyctl33.c b/testcases/kernel/syscalls/keyctl/keyctl33.c
new file mode 100644
index 000000000..5e9418f50
--- /dev/null
+++ b/testcases/kernel/syscalls/keyctl/keyctl33.c
@@ -0,0 +1,247 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (c) 2026 Andrea Cervesato <andrea.cervesato@suse.com>
+ */
+
+/*\
+ * Negative and boundary test cases for ``KEYCTL_PKEY_*`` of :manpage:`keyctl(2)`.
+ *
+ * Requires root (CAP_SYS_MODULE) to load the ``x509_key_parser`` and
+ * ``pkcs8_key_parser`` modules.
+ *
+ * [Algorithm]
+ *
+ * - verify ``KEYCTL_PKEY_QUERY`` with non-zero ``arg3`` fails with ``EINVAL``
+ * - verify ``KEYCTL_PKEY_QUERY`` with bogus key serial fails with ``ENOKEY``
+ * - verify ``KEYCTL_PKEY_QUERY`` with non-asymmetric key fails with ``EOPNOTSUPP``
+ * - verify ``KEYCTL_PKEY_QUERY`` with invalid info string fails with ``EINVAL``
+ * - verify ``KEYCTL_PKEY_ENCRYPT`` with bogus key serial fails with ``ENOKEY``
+ * - verify ``KEYCTL_PKEY_ENCRYPT`` with non-asymmetric key fails with ``EOPNOTSUPP``
+ * - verify ``KEYCTL_PKEY_ENCRYPT`` with invalid info string fails with ``EINVAL``
+ * - verify ``KEYCTL_PKEY_ENCRYPT`` with ``in_len`` exceeding limit fails with ``EINVAL``
+ * - verify ``KEYCTL_PKEY_DECRYPT`` on public key certificate fails with ``EINVAL``
+ * - verify ``KEYCTL_PKEY_DECRYPT`` with ``in_len`` exceeding limit fails with ``EINVAL``
+ * - verify ``KEYCTL_PKEY_SIGN`` on public key certificate fails with ``EINVAL``
+ * - verify ``KEYCTL_PKEY_SIGN`` with ``in_len`` exceeding limit fails with ``EINVAL``
+ * - verify ``KEYCTL_PKEY_VERIFY`` with non-asymmetric key fails with ``EOPNOTSUPP``
+ * - verify ``KEYCTL_PKEY_VERIFY`` with ``in2_len`` exceeding limit fails with ``EINVAL``
+ */
+
+#include "keyctl_common.h"
+#include "keyctl_pkey_data.h"
+#include "tst_module.h"
+
+static key_serial_t cert_key, priv_key, user_key;
+static key_serial_t bogus_key = INT32_MAX;
+
+static struct keyctl_pkey_query *query_buf;
+static struct keyctl_pkey_params *params;
+
+static unsigned char in_buf[512];
+static unsigned char out_buf[512];
+
+static struct tcase {
+ int op;
+ key_serial_t *key;
+ unsigned long arg3;
+ const char *info;
+ uint32_t in_len;
+ uint32_t out_in2_len;
+ int exp_errno;
+ const char *desc;
+} tcases[] = {
+ {
+ .op = KEYCTL_PKEY_QUERY,
+ .key = &cert_key,
+ .arg3 = 1,
+ .info = "enc=pkcs1",
+ .exp_errno = EINVAL,
+ .desc = "PKEY_QUERY with non-zero arg3",
+ },
+ {
+ .op = KEYCTL_PKEY_QUERY,
+ .key = &bogus_key,
+ .info = "enc=pkcs1",
+ .exp_errno = ENOKEY,
+ .desc = "PKEY_QUERY with bogus key serial",
+ },
+ {
+ .op = KEYCTL_PKEY_QUERY,
+ .key = &user_key,
+ .info = "enc=pkcs1",
+ .exp_errno = EOPNOTSUPP,
+ .desc = "PKEY_QUERY with non-asymmetric key",
+ },
+ {
+ .op = KEYCTL_PKEY_QUERY,
+ .key = &cert_key,
+ .info = "bogus_opt",
+ .exp_errno = EINVAL,
+ .desc = "PKEY_QUERY with invalid info string",
+ },
+ {
+ .op = KEYCTL_PKEY_ENCRYPT,
+ .key = &bogus_key,
+ .info = "enc=pkcs1",
+ .in_len = 32,
+ .out_in2_len = 256,
+ .exp_errno = ENOKEY,
+ .desc = "PKEY_ENCRYPT with bogus key serial",
+ },
+ {
+ .op = KEYCTL_PKEY_ENCRYPT,
+ .key = &user_key,
+ .info = "enc=pkcs1",
+ .in_len = 32,
+ .out_in2_len = 256,
+ .exp_errno = EOPNOTSUPP,
+ .desc = "PKEY_ENCRYPT with non-asymmetric key",
+ },
+ {
+ .op = KEYCTL_PKEY_ENCRYPT,
+ .key = &cert_key,
+ .info = "invalid_info",
+ .in_len = 32,
+ .out_in2_len = 256,
+ .exp_errno = EINVAL,
+ .desc = "PKEY_ENCRYPT with invalid info string",
+ },
+ {
+ .op = KEYCTL_PKEY_ENCRYPT,
+ .key = &cert_key,
+ .info = "enc=pkcs1",
+ .in_len = 500,
+ .out_in2_len = 256,
+ .exp_errno = EINVAL,
+ .desc = "PKEY_ENCRYPT with in_len exceeding limit",
+ },
+ {
+ .op = KEYCTL_PKEY_DECRYPT,
+ .key = &cert_key,
+ .info = "enc=pkcs1",
+ .in_len = 256,
+ .out_in2_len = 256,
+ .exp_errno = EINVAL,
+ .desc = "PKEY_DECRYPT on public key certificate",
+ },
+ {
+ .op = KEYCTL_PKEY_DECRYPT,
+ .key = &priv_key,
+ .info = "enc=pkcs1",
+ .in_len = 500,
+ .out_in2_len = 256,
+ .exp_errno = EINVAL,
+ .desc = "PKEY_DECRYPT with in_len exceeding limit",
+ },
+ {
+ .op = KEYCTL_PKEY_SIGN,
+ .key = &cert_key,
+ .info = "enc=pkcs1 hash=sha256",
+ .in_len = 32,
+ .out_in2_len = 256,
+ .exp_errno = EINVAL,
+ .desc = "PKEY_SIGN on public key certificate",
+ },
+ {
+ .op = KEYCTL_PKEY_SIGN,
+ .key = &priv_key,
+ .info = "enc=pkcs1 hash=sha256",
+ .in_len = 500,
+ .out_in2_len = 256,
+ .exp_errno = EINVAL,
+ .desc = "PKEY_SIGN with in_len exceeding limit",
+ },
+ {
+ .op = KEYCTL_PKEY_VERIFY,
+ .key = &user_key,
+ .info = "enc=pkcs1 hash=sha256",
+ .in_len = 32,
+ .out_in2_len = 256,
+ .exp_errno = EOPNOTSUPP,
+ .desc = "PKEY_VERIFY with non-asymmetric key",
+ },
+ {
+ .op = KEYCTL_PKEY_VERIFY,
+ .key = &cert_key,
+ .info = "enc=pkcs1 hash=sha256",
+ .in_len = 32,
+ .out_in2_len = 500,
+ .exp_errno = EINVAL,
+ .desc = "PKEY_VERIFY with in2_len exceeding limit",
+ },
+};
+
+static void setup(void)
+{
+ SAFE_KEYCTL(KEYCTL_JOIN_SESSION_KEYRING, 0, 0, 0, 0);
+
+ tst_modprobe("x509_key_parser", NULL);
+ tst_modprobe("pkcs8_key_parser", NULL);
+
+ user_key = new_user_key("ltp_user", "data", 4,
+ KEY_SPEC_PROCESS_KEYRING);
+
+ cert_key = add_asymmetric_key_or_tconf("cert", rsa2048_cert,
+ sizeof(rsa2048_cert),
+ "CONFIG_X509_CERTIFICATE_PARSER");
+ priv_key = add_asymmetric_key_or_tconf("priv", rsa2048_pkcs8,
+ sizeof(rsa2048_pkcs8),
+ "CONFIG_PKCS8_PRIVATE_KEY_PARSER");
+}
+
+static void run(unsigned int n)
+{
+ struct tcase *tc = &tcases[n];
+
+ if (tc->op == KEYCTL_PKEY_QUERY) {
+ TST_EXP_FAIL(keyctl(KEYCTL_PKEY_QUERY, (unsigned long)*tc->key,
+ tc->arg3, (unsigned long)tc->info,
+ (unsigned long)query_buf),
+ tc->exp_errno,
+ "%s", tc->desc);
+ return;
+ }
+
+ memset(params, 0, sizeof(*params));
+ params->key_id = *tc->key;
+ params->in_len = tc->in_len;
+ params->out_len = tc->out_in2_len;
+
+ if (tc->op == KEYCTL_PKEY_VERIFY) {
+ TST_EXP_FAIL(keyctl(tc->op, (unsigned long)params,
+ (unsigned long)tc->info,
+ (unsigned long)in_buf,
+ (unsigned long)out_buf),
+ tc->exp_errno,
+ "%s", tc->desc);
+ } else {
+ TST_EXP_FAIL2(keyctl(tc->op, (unsigned long)params,
+ (unsigned long)tc->info,
+ (unsigned long)in_buf,
+ (unsigned long)out_buf),
+ tc->exp_errno,
+ "%s", tc->desc);
+ }
+}
+
+static struct tst_test test = {
+ .setup = setup,
+ .test = run,
+ .tcnt = ARRAY_SIZE(tcases),
+ .min_kver = "4.20",
+ .needs_root = 1,
+ .needs_kconfigs = (const char *[]) {
+ "CONFIG_KEYS=y",
+ "CONFIG_ASYMMETRIC_KEY_TYPE=y",
+ "CONFIG_X509_CERTIFICATE_PARSER",
+ "CONFIG_PKCS8_PRIVATE_KEY_PARSER",
+ "CONFIG_CRYPTO_RSA",
+ "CONFIG_CRYPTO_SHA256",
+ NULL
+ },
+ .bufs = (struct tst_buffers []) {
+ {&query_buf, .size = sizeof(*query_buf)},
+ {¶ms, .size = sizeof(*params)},
+ {},
+ },
+};
--
2.51.0
More information about the ltp
mailing list