From: Vadim Fedorenko <vadim.fedorenko@linux.dev>
To: Daniel Hodges <git@danielhodges.dev>, bpf@vger.kernel.org
Cc: Alexei Starovoitov <ast@kernel.org>,
Andrii Nakryiko <andrii@kernel.org>,
Daniel Borkmann <daniel@iogearbox.net>,
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
Subject: Re: [PATCH bpf-next v4 5/6] bpf: Add ECDSA signature verification kfuncs
Date: Tue, 6 Jan 2026 22:17:34 +0000 [thread overview]
Message-ID: <60ecd12b-3c57-4eb1-ac7a-143249d25b47@linux.dev> (raw)
In-Reply-To: <20260105173755.22515-6-git@danielhodges.dev>
On 05/01/2026 17:37, Daniel Hodges wrote:
> 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)
Why keysize/digestsize/maxsize are introduced as kfuncs? My
understanding is that only bpf_sig_verify() has to be introduced. And no
ECDSA in the name as it's one of the types of signature algos.
> +#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);
I'm pretty sure it will fail because init functions have sleepable
*alloc() calls in the implementation and cannot be called in XDP/SCHED
context.
> return ret ?: register_btf_id_dtor_kfuncs(bpf_crypto_dtors,
> ARRAY_SIZE(bpf_crypto_dtors),
> THIS_MODULE);
next prev parent reply other threads:[~2026-01-06 22:17 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 ` [PATCH bpf-next v4 5/6] bpf: Add ECDSA signature verification kfuncs Daniel Hodges
2026-01-06 22:17 ` Vadim Fedorenko [this message]
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=60ecd12b-3c57-4eb1-ac7a-143249d25b47@linux.dev \
--to=vadim.fedorenko@linux.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=git@danielhodges.dev \
--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=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