bpf.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
From: Daniel Hodges <git@danielhodges.dev>
To: bpf@vger.kernel.org
Cc: ast@kernel.org, andrii@kernel.org, daniel@iogearbox.net,
	vadim.fedorenko@linux.dev, song@kernel.org, yatsenko@meta.com,
	martin.lau@linux.dev, eddyz87@gmail.com, haoluo@google.com,
	jolsa@kernel.org, john.fastabend@gmail.com, kpsingh@kernel.org,
	sdf@fomichev.me, yonghong.song@linux.dev,
	herbert@gondor.apana.org.au, davem@davemloft.net,
	linux-crypto@vger.kernel.org, linux-kernel@vger.kernel.org,
	linux-kselftest@vger.kernel.org,
	Daniel Hodges <git@danielhodges.dev>
Subject: [PATCH bpf-next v3 6/6] selftests/bpf: Add tests for ECDSA signature verification kfuncs
Date: Sun,  7 Dec 2025 22:01:17 -0500	[thread overview]
Message-ID: <20251208030117.18892-7-git@danielhodges.dev> (raw)
In-Reply-To: <20251208030117.18892-1-git@danielhodges.dev>

Add selftests to validate the ECDSA signature verification kfuncs
introduced in the BPF crypto subsystem. The tests verify both valid
signature acceptance and invalid signature rejection using the
context-based ECDSA API.

The tests use RFC 6979 test vectors for NIST P-256 (secp256r1) with
well-known valid signatures. The algorithm "p1363(ecdsa-nist-p256)"
is used to handle standard r||s signature format.

Signed-off-by: Daniel Hodges <git@danielhodges.dev>
---
 tools/testing/selftests/bpf/config            |   1 +
 .../selftests/bpf/prog_tests/ecdsa_verify.c   |  75 ++++++++
 .../selftests/bpf/progs/ecdsa_verify.c        | 160 ++++++++++++++++++
 3 files changed, 236 insertions(+)
 create mode 100644 tools/testing/selftests/bpf/prog_tests/ecdsa_verify.c
 create mode 100644 tools/testing/selftests/bpf/progs/ecdsa_verify.c

diff --git a/tools/testing/selftests/bpf/config b/tools/testing/selftests/bpf/config
index d168b3073cba..c99811d3f61f 100644
--- a/tools/testing/selftests/bpf/config
+++ b/tools/testing/selftests/bpf/config
@@ -15,6 +15,7 @@ CONFIG_CRYPTO_HMAC=y
 CONFIG_CRYPTO_HASH2=y
 CONFIG_CRYPTO_SHA256=y
 CONFIG_CRYPTO_SHA512=y
+CONFIG_CRYPTO_ECDSA=y
 CONFIG_CRYPTO_USER_API=y
 CONFIG_CRYPTO_USER_API_HASH=y
 CONFIG_CRYPTO_USER_API_SKCIPHER=y
diff --git a/tools/testing/selftests/bpf/prog_tests/ecdsa_verify.c b/tools/testing/selftests/bpf/prog_tests/ecdsa_verify.c
new file mode 100644
index 000000000000..4e88b3eeb3eb
--- /dev/null
+++ b/tools/testing/selftests/bpf/prog_tests/ecdsa_verify.c
@@ -0,0 +1,75 @@
+// SPDX-License-Identifier: GPL-2.0
+/* Copyright (c) 2025 Meta Platforms, Inc. and affiliates. */
+
+#include <test_progs.h>
+#include "ecdsa_verify.skel.h"
+
+static void test_ecdsa_verify_valid_signature(void)
+{
+	struct ecdsa_verify *skel;
+	int err, prog_fd;
+
+	LIBBPF_OPTS(bpf_test_run_opts, topts);
+
+	skel = ecdsa_verify__open_and_load();
+	if (!ASSERT_OK_PTR(skel, "ecdsa_verify__open_and_load"))
+		return;
+
+	prog_fd = bpf_program__fd(skel->progs.test_ecdsa_verify_valid);
+	err = bpf_prog_test_run_opts(prog_fd, &topts);
+	ASSERT_OK(err, "test_ecdsa_verify_valid");
+	ASSERT_EQ(skel->data->ctx_create_status, 0, "ctx_create_status");
+	ASSERT_EQ(skel->data->verify_result, 0, "verify_valid_signature");
+
+	ecdsa_verify__destroy(skel);
+}
+
+static void test_ecdsa_verify_invalid_signature(void)
+{
+	struct ecdsa_verify *skel;
+	int err, prog_fd;
+
+	LIBBPF_OPTS(bpf_test_run_opts, topts);
+
+	skel = ecdsa_verify__open_and_load();
+	if (!ASSERT_OK_PTR(skel, "ecdsa_verify__open_and_load"))
+		return;
+
+	prog_fd = bpf_program__fd(skel->progs.test_ecdsa_verify_invalid);
+	err = bpf_prog_test_run_opts(prog_fd, &topts);
+	ASSERT_OK(err, "test_ecdsa_verify_invalid");
+	ASSERT_NEQ(skel->data->verify_invalid_result, 0, "verify_invalid_signature_rejected");
+
+	ecdsa_verify__destroy(skel);
+}
+
+static void test_ecdsa_size_queries(void)
+{
+	struct ecdsa_verify *skel;
+	int err, prog_fd;
+
+	LIBBPF_OPTS(bpf_test_run_opts, topts);
+
+	skel = ecdsa_verify__open_and_load();
+	if (!ASSERT_OK_PTR(skel, "ecdsa_verify__open_and_load"))
+		return;
+
+	prog_fd = bpf_program__fd(skel->progs.test_ecdsa_size_queries);
+	err = bpf_prog_test_run_opts(prog_fd, &topts);
+	ASSERT_OK(err, "test_ecdsa_size_queries");
+	ASSERT_EQ(skel->data->keysize_result, 256, "keysize_p256");
+	ASSERT_EQ(skel->data->digestsize_result, 64, "digestsize_p256");
+	ASSERT_EQ(skel->data->maxsize_result, 64, "maxsize_p256");
+
+	ecdsa_verify__destroy(skel);
+}
+
+void test_ecdsa_verify(void)
+{
+	if (test__start_subtest("verify_valid_signature"))
+		test_ecdsa_verify_valid_signature();
+	if (test__start_subtest("verify_invalid_signature"))
+		test_ecdsa_verify_invalid_signature();
+	if (test__start_subtest("size_queries"))
+		test_ecdsa_size_queries();
+}
diff --git a/tools/testing/selftests/bpf/progs/ecdsa_verify.c b/tools/testing/selftests/bpf/progs/ecdsa_verify.c
new file mode 100644
index 000000000000..e2a94ff80774
--- /dev/null
+++ b/tools/testing/selftests/bpf/progs/ecdsa_verify.c
@@ -0,0 +1,160 @@
+// SPDX-License-Identifier: GPL-2.0
+/* Copyright (c) 2025 Meta Platforms, Inc. and affiliates. */
+
+#include "vmlinux.h"
+#include <bpf/bpf_helpers.h>
+#include "bpf_misc.h"
+
+struct bpf_ecdsa_ctx;
+extern struct bpf_ecdsa_ctx *
+bpf_ecdsa_ctx_create(const struct bpf_dynptr *algo_name,
+		     const struct bpf_dynptr *public_key, int *err) __ksym;
+extern int bpf_ecdsa_verify(struct bpf_ecdsa_ctx *ctx,
+			    const struct bpf_dynptr *message,
+			    const struct bpf_dynptr *signature) __ksym;
+extern int bpf_ecdsa_keysize(struct bpf_ecdsa_ctx *ctx) __ksym;
+extern int bpf_ecdsa_digestsize(struct bpf_ecdsa_ctx *ctx) __ksym;
+extern int bpf_ecdsa_maxsize(struct bpf_ecdsa_ctx *ctx) __ksym;
+extern void bpf_ecdsa_ctx_release(struct bpf_ecdsa_ctx *ctx) __ksym;
+
+/* NIST P-256 test vector
+ * This is a known valid ECDSA signature for testing purposes
+ */
+
+/* Algorithm name for P-256 with p1363 format (standard r||s signature) */
+char algo_p256[] = "p1363(ecdsa-nist-p256)";
+
+/* Public key in uncompressed format: 0x04 || x || y (65 bytes) */
+unsigned char pubkey_p256[65] = {
+	0x04, /* Uncompressed point indicator */
+	/* X coordinate (32 bytes) */
+	0x60, 0xfe, 0xd4, 0xba, 0x25, 0x5a, 0x9d, 0x31,
+	0xc9, 0x61, 0xeb, 0x74, 0xc6, 0x35, 0x6d, 0x68,
+	0xc0, 0x49, 0xb8, 0x92, 0x3b, 0x61, 0xfa, 0x6c,
+	0xe6, 0x69, 0x62, 0x2e, 0x60, 0xf2, 0x9f, 0xb6,
+	/* Y coordinate (32 bytes) */
+	0x79, 0x03, 0xfe, 0x10, 0x08, 0xb8, 0xbc, 0x99,
+	0xa4, 0x1a, 0xe9, 0xe9, 0x56, 0x28, 0xbc, 0x64,
+	0xf2, 0xf1, 0xb2, 0x0c, 0x2d, 0x7e, 0x9f, 0x51,
+	0x77, 0xa3, 0xc2, 0x94, 0xd4, 0x46, 0x22, 0x99
+};
+
+/* Message hash (32 bytes) - SHA-256 of "sample" */
+unsigned char message_hash[32] = {
+	0xaf, 0x2b, 0xdb, 0xe1, 0xaa, 0x9b, 0x6e, 0xc1,
+	0xe2, 0xad, 0xe1, 0xd6, 0x94, 0xf4, 0x1f, 0xc7,
+	0x1a, 0x83, 0x1d, 0x02, 0x68, 0xe9, 0x89, 0x15,
+	0x62, 0x11, 0x3d, 0x8a, 0x62, 0xad, 0xd1, 0xbf
+};
+
+/* Valid signature r || s (64 bytes) */
+unsigned char valid_signature[64] = {
+	/* r component (32 bytes) */
+	0xef, 0xd4, 0x8b, 0x2a, 0xac, 0xb6, 0xa8, 0xfd,
+	0x11, 0x40, 0xdd, 0x9c, 0xd4, 0x5e, 0x81, 0xd6,
+	0x9d, 0x2c, 0x87, 0x7b, 0x56, 0xaa, 0xf9, 0x91,
+	0xc3, 0x4d, 0x0e, 0xa8, 0x4e, 0xaf, 0x37, 0x16,
+	/* s component (32 bytes) */
+	0xf7, 0xcb, 0x1c, 0x94, 0x2d, 0x65, 0x7c, 0x41,
+	0xd4, 0x36, 0xc7, 0xa1, 0xb6, 0xe2, 0x9f, 0x65,
+	0xf3, 0xe9, 0x00, 0xdb, 0xb9, 0xaf, 0xf4, 0x06,
+	0x4d, 0xc4, 0xab, 0x2f, 0x84, 0x3a, 0xcd, 0xa8
+};
+
+/* Invalid signature (modified r component) for negative test */
+unsigned char invalid_signature[64] = {
+	/* r component (32 bytes) - first byte modified */
+	0xff, 0xd4, 0x8b, 0x2a, 0xac, 0xb6, 0xa8, 0xfd,
+	0x11, 0x40, 0xdd, 0x9c, 0xd4, 0x5e, 0x81, 0xd6,
+	0x9d, 0x2c, 0x87, 0x7b, 0x56, 0xaa, 0xf9, 0x91,
+	0xc3, 0x4d, 0x0e, 0xa8, 0x4e, 0xaf, 0x37, 0x16,
+	/* s component (32 bytes) */
+	0xf7, 0xcb, 0x1c, 0x94, 0x2d, 0x65, 0x7c, 0x41,
+	0xd4, 0x36, 0xc7, 0xa1, 0xb6, 0xe2, 0x9f, 0x65,
+	0xf3, 0xe9, 0x00, 0xdb, 0xb9, 0xaf, 0xf4, 0x06,
+	0x4d, 0xc4, 0xab, 0x2f, 0x84, 0x3a, 0xcd, 0xa8
+};
+
+/* Test results */
+int verify_result = -1;
+int verify_invalid_result = -1;
+int ctx_create_status = -1;
+int keysize_result = -1;
+int digestsize_result = -1;
+int maxsize_result = -1;
+
+SEC("syscall")
+int test_ecdsa_verify_valid(void *ctx)
+{
+	struct bpf_ecdsa_ctx *ecdsa_ctx;
+	struct bpf_dynptr algo_ptr, key_ptr, msg_ptr, sig_ptr;
+	int err = 0;
+
+	bpf_dynptr_from_mem(algo_p256, sizeof(algo_p256) - 1, 0, &algo_ptr);
+	bpf_dynptr_from_mem(pubkey_p256, sizeof(pubkey_p256), 0, &key_ptr);
+
+	ecdsa_ctx = bpf_ecdsa_ctx_create(&algo_ptr, &key_ptr, &err);
+	if (!ecdsa_ctx) {
+		ctx_create_status = err;
+		return 0;
+	}
+	ctx_create_status = 0;
+
+	bpf_dynptr_from_mem(message_hash, sizeof(message_hash), 0, &msg_ptr);
+	bpf_dynptr_from_mem(valid_signature, sizeof(valid_signature), 0, &sig_ptr);
+
+	verify_result = bpf_ecdsa_verify(ecdsa_ctx, &msg_ptr, &sig_ptr);
+
+	bpf_ecdsa_ctx_release(ecdsa_ctx);
+
+	return 0;
+}
+
+SEC("syscall")
+int test_ecdsa_verify_invalid(void *ctx)
+{
+	struct bpf_ecdsa_ctx *ecdsa_ctx;
+	struct bpf_dynptr algo_ptr, key_ptr, msg_ptr, sig_ptr;
+	int err = 0;
+
+	bpf_dynptr_from_mem(algo_p256, sizeof(algo_p256) - 1, 0, &algo_ptr);
+	bpf_dynptr_from_mem(pubkey_p256, sizeof(pubkey_p256), 0, &key_ptr);
+
+	ecdsa_ctx = bpf_ecdsa_ctx_create(&algo_ptr, &key_ptr, &err);
+	if (!ecdsa_ctx)
+		return 0;
+
+	bpf_dynptr_from_mem(message_hash, sizeof(message_hash), 0, &msg_ptr);
+	bpf_dynptr_from_mem(invalid_signature, sizeof(invalid_signature), 0, &sig_ptr);
+
+	verify_invalid_result = bpf_ecdsa_verify(ecdsa_ctx, &msg_ptr, &sig_ptr);
+
+	bpf_ecdsa_ctx_release(ecdsa_ctx);
+
+	return 0;
+}
+
+SEC("syscall")
+int test_ecdsa_size_queries(void *ctx)
+{
+	struct bpf_ecdsa_ctx *ecdsa_ctx;
+	struct bpf_dynptr algo_ptr, key_ptr;
+	int err = 0;
+
+	bpf_dynptr_from_mem(algo_p256, sizeof(algo_p256) - 1, 0, &algo_ptr);
+	bpf_dynptr_from_mem(pubkey_p256, sizeof(pubkey_p256), 0, &key_ptr);
+
+	ecdsa_ctx = bpf_ecdsa_ctx_create(&algo_ptr, &key_ptr, &err);
+	if (!ecdsa_ctx)
+		return 0;
+
+	keysize_result = bpf_ecdsa_keysize(ecdsa_ctx);
+	digestsize_result = bpf_ecdsa_digestsize(ecdsa_ctx);
+	maxsize_result = bpf_ecdsa_maxsize(ecdsa_ctx);
+
+	bpf_ecdsa_ctx_release(ecdsa_ctx);
+
+	return 0;
+}
+
+char __license[] SEC("license") = "GPL";
-- 
2.51.0


      parent reply	other threads:[~2025-12-08  3:04 UTC|newest]

Thread overview: 9+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2025-12-08  3:01 [PATCH bpf-next v3 0/6] Add cryptographic hash and signature verification kfuncs to BPF Daniel Hodges
2025-12-08  3:01 ` [PATCH bpf-next v3 1/6] bpf: Extend bpf_crypto_type with hash operations Daniel Hodges
2025-12-08  3:01 ` [PATCH bpf-next v3 2/6] crypto: Add BPF hash algorithm type registration module Daniel Hodges
2025-12-08  3:25   ` bot+bpf-ci
2025-12-08  3:01 ` [PATCH bpf-next v3 3/6] bpf: Add SHA hash kfunc for cryptographic hashing Daniel Hodges
2025-12-13  4:08   ` Mykyta Yatsenko
2025-12-08  3:01 ` [PATCH bpf-next v3 4/6] selftests/bpf: Add tests for bpf_crypto_hash kfunc Daniel Hodges
2025-12-08  3:01 ` [PATCH bpf-next v3 5/6] bpf: Add ECDSA signature verification kfuncs Daniel Hodges
2025-12-08  3:01 ` Daniel Hodges [this message]

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20251208030117.18892-7-git@danielhodges.dev \
    --to=git@danielhodges.dev \
    --cc=andrii@kernel.org \
    --cc=ast@kernel.org \
    --cc=bpf@vger.kernel.org \
    --cc=daniel@iogearbox.net \
    --cc=davem@davemloft.net \
    --cc=eddyz87@gmail.com \
    --cc=haoluo@google.com \
    --cc=herbert@gondor.apana.org.au \
    --cc=john.fastabend@gmail.com \
    --cc=jolsa@kernel.org \
    --cc=kpsingh@kernel.org \
    --cc=linux-crypto@vger.kernel.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=linux-kselftest@vger.kernel.org \
    --cc=martin.lau@linux.dev \
    --cc=sdf@fomichev.me \
    --cc=song@kernel.org \
    --cc=vadim.fedorenko@linux.dev \
    --cc=yatsenko@meta.com \
    --cc=yonghong.song@linux.dev \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).