All of lore.kernel.org
 help / color / mirror / Atom feed
From: Daniel Hodges <git@danielhodges.dev>
To: bpf@vger.kernel.org
Cc: Alexei Starovoitov <ast@kernel.org>,
	Andrii Nakryiko <andrii@kernel.org>,
	Daniel Borkmann <daniel@iogearbox.net>,
	Vadim Fedorenko <vadim.fedorenko@linux.dev>,
	Song Liu <song@kernel.org>, Mykyta Yatsenko <yatsenko@meta.com>,
	Martin KaFai Lau <martin.lau@linux.dev>,
	Eduard Zingerman <eddyz87@gmail.com>, Hao Luo <haoluo@google.com>,
	Jiri Olsa <jolsa@kernel.org>,
	John Fastabend <john.fastabend@gmail.com>,
	KP Singh <kpsingh@kernel.org>,
	Stanislav Fomichev <sdf@fomichev.me>,
	Yonghong Song <yonghong.song@linux.dev>,
	Herbert Xu <herbert@gondor.apana.org.au>,
	"David S . Miller" <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 v4 5/6] bpf: Add ECDSA signature verification kfuncs
Date: Mon,  5 Jan 2026 12:37:54 -0500	[thread overview]
Message-ID: <20260105173755.22515-6-git@danielhodges.dev> (raw)
In-Reply-To: <20260105173755.22515-1-git@danielhodges.dev>

Add support for ECDSA signature verification in BPF programs through
the unified bpf_crypto_ctx API.

Changes:
- Add enum bpf_crypto_type_id for efficient type checking
- Update all crypto type modules to set type_id field
- Implement bpf_ecdsa_verify() for signature verification
- Add bpf_ecdsa_keysize(), bpf_ecdsa_digestsize(), bpf_ecdsa_maxsize()
  helper functions for querying context properties
- Add type_id checks in all ECDSA kfuncs for type safety
- Register ECDSA kfuncs for SCHED_CLS and XDP program types

ECDSA contexts are created using bpf_crypto_ctx_create() with
type="sig" and appropriate algorithm (e.g., "p1363(ecdsa-nist-p256)").
The public key is passed via the key/key_len fields in bpf_crypto_params.

This enables BPF programs to perform cryptographic signature verification
for use cases such as packet authentication and content validation.

Signed-off-by: Daniel Hodges <git@danielhodges.dev>
---
 crypto/bpf_crypto_shash.c    |   1 +
 crypto/bpf_crypto_sig.c      |   1 +
 crypto/bpf_crypto_skcipher.c |   1 +
 include/linux/bpf_crypto.h   |   7 +++
 kernel/bpf/crypto.c          | 115 +++++++++++++++++++++++++++++++++++
 5 files changed, 125 insertions(+)

diff --git a/crypto/bpf_crypto_shash.c b/crypto/bpf_crypto_shash.c
index 95c178ec0ce8..6e9b0d757ec9 100644
--- a/crypto/bpf_crypto_shash.c
+++ b/crypto/bpf_crypto_shash.c
@@ -74,6 +74,7 @@ static const struct bpf_crypto_type bpf_crypto_shash_type = {
 	.digestsize	= bpf_crypto_shash_digestsize,
 	.get_flags	= bpf_crypto_shash_get_flags,
 	.owner		= THIS_MODULE,
+	.type_id	= BPF_CRYPTO_TYPE_HASH,
 	.name		= "hash",
 };
 
diff --git a/crypto/bpf_crypto_sig.c b/crypto/bpf_crypto_sig.c
index ad0d3810df8e..c6e67338cd40 100644
--- a/crypto/bpf_crypto_sig.c
+++ b/crypto/bpf_crypto_sig.c
@@ -38,6 +38,7 @@ static const struct bpf_crypto_type bpf_crypto_sig_type = {
 	.get_flags	= bpf_crypto_sig_get_flags,
 	.setkey		= bpf_crypto_sig_setkey,
 	.owner		= THIS_MODULE,
+	.type_id	= BPF_CRYPTO_TYPE_SIG,
 	.name		= "sig",
 };
 
diff --git a/crypto/bpf_crypto_skcipher.c b/crypto/bpf_crypto_skcipher.c
index a88798d3e8c8..79d310fbcc48 100644
--- a/crypto/bpf_crypto_skcipher.c
+++ b/crypto/bpf_crypto_skcipher.c
@@ -63,6 +63,7 @@ static const struct bpf_crypto_type bpf_crypto_lskcipher_type = {
 	.statesize	= bpf_crypto_lskcipher_statesize,
 	.get_flags	= bpf_crypto_lskcipher_get_flags,
 	.owner		= THIS_MODULE,
+	.type_id	= BPF_CRYPTO_TYPE_SKCIPHER,
 	.name		= "skcipher",
 };
 
diff --git a/include/linux/bpf_crypto.h b/include/linux/bpf_crypto.h
index c84371cc4e47..cf2c66f9782b 100644
--- a/include/linux/bpf_crypto.h
+++ b/include/linux/bpf_crypto.h
@@ -3,6 +3,12 @@
 #ifndef _BPF_CRYPTO_H
 #define _BPF_CRYPTO_H
 
+enum bpf_crypto_type_id {
+	BPF_CRYPTO_TYPE_SKCIPHER = 1,
+	BPF_CRYPTO_TYPE_HASH,
+	BPF_CRYPTO_TYPE_SIG,
+};
+
 struct bpf_crypto_type {
 	void *(*alloc_tfm)(const char *algo);
 	void (*free_tfm)(void *tfm);
@@ -17,6 +23,7 @@ struct bpf_crypto_type {
 	unsigned int (*digestsize)(void *tfm);
 	u32 (*get_flags)(void *tfm);
 	struct module *owner;
+	enum bpf_crypto_type_id type_id;
 	char name[14];
 };
 
diff --git a/kernel/bpf/crypto.c b/kernel/bpf/crypto.c
index f593e7910d3d..3c57a8c31ea2 100644
--- a/kernel/bpf/crypto.c
+++ b/kernel/bpf/crypto.c
@@ -9,6 +9,7 @@
 #include <linux/scatterlist.h>
 #include <linux/skbuff.h>
 #include <crypto/skcipher.h>
+#include <crypto/sig.h>
 
 struct bpf_crypto_type_list {
 	const struct bpf_crypto_type *type;
@@ -57,6 +58,7 @@ struct bpf_crypto_ctx {
 	refcount_t usage;
 };
 
+
 int bpf_crypto_register_type(const struct bpf_crypto_type *type)
 {
 	struct bpf_crypto_type_list *node;
@@ -400,6 +402,109 @@ __bpf_kfunc int bpf_crypto_hash(struct bpf_crypto_ctx *ctx,
 }
 #endif /* CONFIG_CRYPTO_HASH2 */
 
+#if IS_ENABLED(CONFIG_CRYPTO_ECDSA)
+/**
+ * bpf_ecdsa_verify() - Verify ECDSA signature using pre-allocated context
+ * @ctx: ECDSA context created by bpf_crypto_ctx_create() with type "sig"
+ * @message: bpf_dynptr to the message hash to verify. Must be a trusted pointer.
+ * @signature: bpf_dynptr to the ECDSA signature in r || s format. Must be a trusted pointer.
+ *             Must be 64 bytes for P-256, 96 for P-384, 132 for P-521
+ *
+ * Verifies an ECDSA signature using a pre-allocated context. This function
+ * does not allocate memory and can be used in non-sleepable BPF programs.
+ * Uses bpf_dynptr to ensure safe memory access without risk of page faults.
+ */
+__bpf_kfunc int bpf_ecdsa_verify(struct bpf_crypto_ctx *ctx,
+				 const struct bpf_dynptr *message,
+				 const struct bpf_dynptr *signature)
+{
+	const struct bpf_dynptr_kern *msg_kern = (struct bpf_dynptr_kern *)message;
+	const struct bpf_dynptr_kern *sig_kern = (struct bpf_dynptr_kern *)signature;
+	struct crypto_sig *sig_tfm;
+	const u8 *msg_ptr, *sig_ptr;
+	u32 msg_len, sig_len;
+
+	if (!ctx)
+		return -EINVAL;
+
+	if (ctx->type->type_id != BPF_CRYPTO_TYPE_SIG)
+		return -EINVAL;
+
+	msg_len = __bpf_dynptr_size(msg_kern);
+	sig_len = __bpf_dynptr_size(sig_kern);
+
+	if (msg_len == 0 || sig_len == 0)
+		return -EINVAL;
+
+	msg_ptr = __bpf_dynptr_data(msg_kern, msg_len);
+	if (!msg_ptr)
+		return -EINVAL;
+
+	sig_ptr = __bpf_dynptr_data(sig_kern, sig_len);
+	if (!sig_ptr)
+		return -EINVAL;
+
+	sig_tfm = (struct crypto_sig *)ctx->tfm;
+	return crypto_sig_verify(sig_tfm, sig_ptr, sig_len, msg_ptr, msg_len);
+}
+
+/**
+ * bpf_ecdsa_keysize() - Get the key size for ECDSA context
+ * @ctx: ECDSA context
+ *
+ * Returns: Key size in bits, or negative error code on failure
+ */
+__bpf_kfunc int bpf_ecdsa_keysize(struct bpf_crypto_ctx *ctx)
+{
+	struct crypto_sig *sig_tfm;
+
+	if (!ctx)
+		return -EINVAL;
+
+	if (ctx->type->type_id != BPF_CRYPTO_TYPE_SIG)
+		return -EINVAL;
+
+	sig_tfm = (struct crypto_sig *)ctx->tfm;
+	return crypto_sig_keysize(sig_tfm);
+}
+
+/**
+ * bpf_ecdsa_digestsize() - Get the maximum digest size for ECDSA context
+ * @ctx: ECDSA context
+ */
+__bpf_kfunc int bpf_ecdsa_digestsize(struct bpf_crypto_ctx *ctx)
+{
+	struct crypto_sig *sig_tfm;
+
+	if (!ctx)
+		return -EINVAL;
+
+	if (ctx->type->type_id != BPF_CRYPTO_TYPE_SIG)
+		return -EINVAL;
+
+	sig_tfm = (struct crypto_sig *)ctx->tfm;
+	return crypto_sig_digestsize(sig_tfm);
+}
+
+/**
+ * bpf_ecdsa_maxsize() - Get the maximum signature size for ECDSA context
+ * @ctx: ECDSA context
+ */
+__bpf_kfunc int bpf_ecdsa_maxsize(struct bpf_crypto_ctx *ctx)
+{
+	struct crypto_sig *sig_tfm;
+
+	if (!ctx)
+		return -EINVAL;
+
+	if (ctx->type->type_id != BPF_CRYPTO_TYPE_SIG)
+		return -EINVAL;
+
+	sig_tfm = (struct crypto_sig *)ctx->tfm;
+	return crypto_sig_maxsize(sig_tfm);
+}
+#endif /* CONFIG_CRYPTO_ECDSA */
+
 __bpf_kfunc_end_defs();
 
 BTF_KFUNCS_START(crypt_init_kfunc_btf_ids)
@@ -419,6 +524,12 @@ BTF_ID_FLAGS(func, bpf_crypto_encrypt, KF_RCU)
 #if IS_ENABLED(CONFIG_CRYPTO_HASH2)
 BTF_ID_FLAGS(func, bpf_crypto_hash, KF_RCU)
 #endif
+#if IS_ENABLED(CONFIG_CRYPTO_ECDSA)
+BTF_ID_FLAGS(func, bpf_ecdsa_verify, KF_RCU)
+BTF_ID_FLAGS(func, bpf_ecdsa_keysize, 0)
+BTF_ID_FLAGS(func, bpf_ecdsa_digestsize, 0)
+BTF_ID_FLAGS(func, bpf_ecdsa_maxsize, 0)
+#endif
 BTF_KFUNCS_END(crypt_kfunc_btf_ids)
 
 static const struct btf_kfunc_id_set crypt_kfunc_set = {
@@ -447,6 +558,10 @@ static int __init crypto_kfunc_init(void)
 	ret = ret ?: register_btf_kfunc_id_set(BPF_PROG_TYPE_SYSCALL, &crypt_kfunc_set);
 	ret = ret ?: register_btf_kfunc_id_set(BPF_PROG_TYPE_SYSCALL,
 					       &crypt_init_kfunc_set);
+	ret = ret ?: register_btf_kfunc_id_set(BPF_PROG_TYPE_SCHED_CLS,
+					       &crypt_init_kfunc_set);
+	ret = ret ?: register_btf_kfunc_id_set(BPF_PROG_TYPE_XDP,
+					       &crypt_init_kfunc_set);
 	return  ret ?: register_btf_id_dtor_kfuncs(bpf_crypto_dtors,
 						   ARRAY_SIZE(bpf_crypto_dtors),
 						   THIS_MODULE);
-- 
2.51.0


  parent reply	other threads:[~2026-01-05 17:44 UTC|newest]

Thread overview: 12+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-01-05 17:37 [PATCH bpf-next v4 0/6] Add cryptographic hash and signature verification kfuncs to BPF Daniel Hodges
2026-01-05 17:37 ` [PATCH bpf-next v4 1/6] crypto: Add BPF hash algorithm type registration module Daniel Hodges
2026-01-06 21:57   ` Vadim Fedorenko
2026-01-05 17:37 ` [PATCH bpf-next v4 2/6] crypto: Add BPF signature " Daniel Hodges
2026-01-06 22:08   ` Vadim Fedorenko
2026-01-05 17:37 ` [PATCH bpf-next v4 3/6] bpf: Add hash kfunc for cryptographic hashing Daniel Hodges
2026-01-06 22:12   ` Vadim Fedorenko
2026-01-05 17:37 ` [PATCH bpf-next v4 4/6] selftests/bpf: Add tests for bpf_crypto_hash kfunc Daniel Hodges
2026-01-05 17:37 ` Daniel Hodges [this message]
2026-01-06 22:17   ` [PATCH bpf-next v4 5/6] bpf: Add ECDSA signature verification kfuncs Vadim Fedorenko
2026-01-06 23:11   ` Vadim Fedorenko
2026-01-05 17:37 ` [PATCH bpf-next v4 6/6] selftests/bpf: Add tests for " Daniel Hodges

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=20260105173755.22515-6-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 an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.