* [PATCH bpf-next v4 0/6] Add cryptographic hash and signature verification kfuncs to BPF
@ 2026-01-05 17:37 Daniel Hodges
2026-01-05 17:37 ` [PATCH bpf-next v4 1/6] crypto: Add BPF hash algorithm type registration module Daniel Hodges
` (5 more replies)
0 siblings, 6 replies; 12+ messages in thread
From: Daniel Hodges @ 2026-01-05 17:37 UTC (permalink / raw)
To: bpf
Cc: Alexei Starovoitov, Andrii Nakryiko, Daniel Borkmann,
Vadim Fedorenko, Song Liu, Mykyta Yatsenko, Martin KaFai Lau,
Eduard Zingerman, Hao Luo, Jiri Olsa, John Fastabend, KP Singh,
Stanislav Fomichev, Yonghong Song, Herbert Xu, David S . Miller,
linux-crypto, linux-kernel, linux-kselftest, Daniel Hodges
This patch series enhances BPF's cryptographic functionality by introducing
kernel functions for SHA hashing and ECDSA signature verification. The changes
enable BPF programs to verify data integrity and authenticity across
networking, security, and observability use cases.
The series addresses two gaps in BPF's cryptographic toolkit:
1. Cryptographic hashing - supports content verification and message digest
preparation
2. Asymmetric signature verification - allows validation of signed data
without requiring private keys in the datapath
Use cases include:
- Verifying signed network packets or application data in XDP/TC programs
- Integrity checks within tracing and security monitoring
- Zero-trust security models with BPF-based credential verification
- Content-addressed storage in BPF-based filesystems
The implementation leverages existing BPF patterns: it uses bpf_dynptr for
memory safety, reuses kernel crypto libraries (lib/crypto/sha256.c and
crypto/ecdsa.c) rather than reimplementing algorithms, and provides
context-based APIs supporting multiple program types.
v2:
- Fixed redundant __bpf_dynptr_is_rdonly() checks (Vadim)
- Added BPF hash algorithm type registration module in crypto/ subsystem
- Added CONFIG_CRYPTO_HASH2 guards around bpf_crypto_hash() kfunc and its
BTF registration, matching the pattern used for CONFIG_CRYPTO_ECDSA
- Added mandatory digestsize validation for hash operations
v3:
- Fixed patch ordering - header changes now in separate first commit before
crypto module to ensure bisectability (bot+bpf-ci)
- Fixed type mismatch - changed u32 to u64 for dynptr sizes in
bpf_crypto_hash() to match __bpf_dynptr_size() return type (Mykyta)
- Added CONFIG_CRYPTO_ECDSA to selftest config (Song)
- Refactored test code duplication with setup_skel() helper (Song)
- Added copyright notices to all new files
v4:
- Reused common bpf_crypto_ctx structure for hash and signature operations
instead of separate context types (Song)
- Fixed integer truncation in bpf_crypto_hash when data_len > UINT_MAX
- Corrected KF_RCU flags for ECDSA kfuncs (only bpf_ecdsa_verify needs KF_RCU)
- Updated MAINTAINERS file in test patches
- Refactored selftests to use crypto_common.h for kfunc declarations
Daniel Hodges (6):
crypto: Add BPF hash algorithm type registration module
crypto: Add BPF signature algorithm type registration module
bpf: Add hash kfunc for cryptographic hashing
selftests/bpf: Add tests for bpf_crypto_hash kfunc
bpf: Add ECDSA signature verification kfuncs
selftests/bpf: Add tests for ECDSA signature verification kfuncs
MAINTAINERS | 6 +
crypto/Makefile | 6 +
crypto/bpf_crypto_shash.c | 96 +++++++++
crypto/bpf_crypto_sig.c | 60 ++++++
crypto/bpf_crypto_skcipher.c | 1 +
include/linux/bpf_crypto.h | 7 +
kernel/bpf/crypto.c | 193 +++++++++++++++++-
tools/testing/selftests/bpf/config | 3 +
.../selftests/bpf/prog_tests/crypto_hash.c | 147 +++++++++++++
.../selftests/bpf/prog_tests/ecdsa_verify.c | 75 +++++++
.../selftests/bpf/progs/crypto_common.h | 7 +
.../testing/selftests/bpf/progs/crypto_hash.c | 136 ++++++++++++
.../selftests/bpf/progs/ecdsa_verify.c | 157 ++++++++++++++
13 files changed, 886 insertions(+), 8 deletions(-)
create mode 100644 crypto/bpf_crypto_shash.c
create mode 100644 crypto/bpf_crypto_sig.c
create mode 100644 tools/testing/selftests/bpf/prog_tests/crypto_hash.c
create mode 100644 tools/testing/selftests/bpf/prog_tests/ecdsa_verify.c
create mode 100644 tools/testing/selftests/bpf/progs/crypto_hash.c
create mode 100644 tools/testing/selftests/bpf/progs/ecdsa_verify.c
--
2.51.0
^ permalink raw reply [flat|nested] 12+ messages in thread
* [PATCH bpf-next v4 1/6] crypto: Add BPF hash algorithm type registration module
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 ` 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
` (4 subsequent siblings)
5 siblings, 1 reply; 12+ messages in thread
From: Daniel Hodges @ 2026-01-05 17:37 UTC (permalink / raw)
To: bpf
Cc: Alexei Starovoitov, Andrii Nakryiko, Daniel Borkmann,
Vadim Fedorenko, Song Liu, Mykyta Yatsenko, Martin KaFai Lau,
Eduard Zingerman, Hao Luo, Jiri Olsa, John Fastabend, KP Singh,
Stanislav Fomichev, Yonghong Song, Herbert Xu, David S . Miller,
linux-crypto, linux-kernel, linux-kselftest, Daniel Hodges
Add bpf_crypto_shash module that registers a hash type with the BPF
crypto infrastructure, enabling BPF programs to access kernel hash
algorithms through a unified interface.
Update the bpf_crypto_type interface with hash-specific callbacks:
- alloc_tfm: Allocates crypto_shash context with proper descriptor size
- free_tfm: Releases hash transform and context memory
- has_algo: Checks algorithm availability via crypto_has_shash()
- hash: Performs single-shot hashing via crypto_shash_digest()
- digestsize: Returns the output size for the hash algorithm
- get_flags: Exposes transform flags to BPF programs
Update bpf_shash_ctx to contain crypto_shash transform and shash_desc
descriptor to accommodate algorithm-specific descriptor requirements.
Signed-off-by: Daniel Hodges <git@danielhodges.dev>
---
MAINTAINERS | 1 +
crypto/Makefile | 3 ++
crypto/bpf_crypto_shash.c | 95 +++++++++++++++++++++++++++++++++++++++
3 files changed, 99 insertions(+)
create mode 100644 crypto/bpf_crypto_shash.c
diff --git a/MAINTAINERS b/MAINTAINERS
index 70c2b73b3941..05e0aee5693c 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -4712,6 +4712,7 @@ BPF [CRYPTO]
M: Vadim Fedorenko <vadim.fedorenko@linux.dev>
L: bpf@vger.kernel.org
S: Maintained
+F: crypto/bpf_crypto_shash.c
F: crypto/bpf_crypto_skcipher.c
F: include/linux/bpf_crypto.h
F: kernel/bpf/crypto.c
diff --git a/crypto/Makefile b/crypto/Makefile
index 16a35649dd91..853dff375906 100644
--- a/crypto/Makefile
+++ b/crypto/Makefile
@@ -30,6 +30,9 @@ obj-$(CONFIG_CRYPTO_ECHAINIV) += echainiv.o
crypto_hash-y += ahash.o
crypto_hash-y += shash.o
obj-$(CONFIG_CRYPTO_HASH2) += crypto_hash.o
+ifeq ($(CONFIG_BPF_SYSCALL),y)
+obj-$(CONFIG_CRYPTO_HASH2) += bpf_crypto_shash.o
+endif
obj-$(CONFIG_CRYPTO_AKCIPHER2) += akcipher.o
obj-$(CONFIG_CRYPTO_SIG2) += sig.o
diff --git a/crypto/bpf_crypto_shash.c b/crypto/bpf_crypto_shash.c
new file mode 100644
index 000000000000..95c178ec0ce8
--- /dev/null
+++ b/crypto/bpf_crypto_shash.c
@@ -0,0 +1,95 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/* Copyright (c) 2025 Meta Platforms, Inc. and affiliates. */
+#include <linux/types.h>
+#include <linux/module.h>
+#include <linux/bpf_crypto.h>
+#include <crypto/hash.h>
+
+struct bpf_shash_ctx {
+ struct crypto_shash *tfm;
+ struct shash_desc desc;
+};
+
+static void *bpf_crypto_shash_alloc_tfm(const char *algo)
+{
+ struct bpf_shash_ctx *ctx;
+ struct crypto_shash *tfm;
+
+ tfm = crypto_alloc_shash(algo, 0, 0);
+ if (IS_ERR(tfm))
+ return tfm;
+
+ ctx = kzalloc(sizeof(*ctx) + crypto_shash_descsize(tfm), GFP_KERNEL);
+ if (!ctx) {
+ crypto_free_shash(tfm);
+ return ERR_PTR(-ENOMEM);
+ }
+
+ ctx->tfm = tfm;
+ ctx->desc.tfm = tfm;
+
+ return ctx;
+}
+
+static void bpf_crypto_shash_free_tfm(void *tfm)
+{
+ struct bpf_shash_ctx *ctx = tfm;
+
+ crypto_free_shash(ctx->tfm);
+ kfree(ctx);
+}
+
+static int bpf_crypto_shash_has_algo(const char *algo)
+{
+ return crypto_has_shash(algo, 0, 0);
+}
+
+static int bpf_crypto_shash_hash(void *tfm, const u8 *data, u8 *out,
+ unsigned int len)
+{
+ struct bpf_shash_ctx *ctx = tfm;
+
+ return crypto_shash_digest(&ctx->desc, data, len, out);
+}
+
+static unsigned int bpf_crypto_shash_digestsize(void *tfm)
+{
+ struct bpf_shash_ctx *ctx = tfm;
+
+ return crypto_shash_digestsize(ctx->tfm);
+}
+
+static u32 bpf_crypto_shash_get_flags(void *tfm)
+{
+ struct bpf_shash_ctx *ctx = tfm;
+
+ return crypto_shash_get_flags(ctx->tfm);
+}
+
+static const struct bpf_crypto_type bpf_crypto_shash_type = {
+ .alloc_tfm = bpf_crypto_shash_alloc_tfm,
+ .free_tfm = bpf_crypto_shash_free_tfm,
+ .has_algo = bpf_crypto_shash_has_algo,
+ .hash = bpf_crypto_shash_hash,
+ .digestsize = bpf_crypto_shash_digestsize,
+ .get_flags = bpf_crypto_shash_get_flags,
+ .owner = THIS_MODULE,
+ .name = "hash",
+};
+
+static int __init bpf_crypto_shash_init(void)
+{
+ return bpf_crypto_register_type(&bpf_crypto_shash_type);
+}
+
+static void __exit bpf_crypto_shash_exit(void)
+{
+ int err = bpf_crypto_unregister_type(&bpf_crypto_shash_type);
+
+ WARN_ON_ONCE(err);
+}
+
+module_init(bpf_crypto_shash_init);
+module_exit(bpf_crypto_shash_exit);
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("Hash algorithm support for BPF");
--
2.51.0
^ permalink raw reply related [flat|nested] 12+ messages in thread
* [PATCH bpf-next v4 2/6] crypto: Add BPF signature algorithm type registration module
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-05 17:37 ` 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
` (3 subsequent siblings)
5 siblings, 1 reply; 12+ messages in thread
From: Daniel Hodges @ 2026-01-05 17:37 UTC (permalink / raw)
To: bpf
Cc: Alexei Starovoitov, Andrii Nakryiko, Daniel Borkmann,
Vadim Fedorenko, Song Liu, Mykyta Yatsenko, Martin KaFai Lau,
Eduard Zingerman, Hao Luo, Jiri Olsa, John Fastabend, KP Singh,
Stanislav Fomichev, Yonghong Song, Herbert Xu, David S . Miller,
linux-crypto, linux-kernel, linux-kselftest, Daniel Hodges
Add a new bpf_crypto_sig module that registers signature verification
algorithms with the BPF crypto type system. This enables signature
operations (like ECDSA) to use the unified bpf_crypto_ctx structure
instead of requiring separate context types.
The module provides:
- alloc_tfm/free_tfm for crypto_sig transform lifecycle
- has_algo to check algorithm availability
- get_flags for crypto API flags
This allows ECDSA and other signature verification operations to
integrate with the existing BPF crypto infrastructure.
Signed-off-by: Daniel Hodges <git@danielhodges.dev>
---
MAINTAINERS | 1 +
crypto/Makefile | 3 +++
crypto/bpf_crypto_sig.c | 59 +++++++++++++++++++++++++++++++++++++++++
3 files changed, 63 insertions(+)
create mode 100644 crypto/bpf_crypto_sig.c
diff --git a/MAINTAINERS b/MAINTAINERS
index 05e0aee5693c..fdf451bad869 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -4713,6 +4713,7 @@ M: Vadim Fedorenko <vadim.fedorenko@linux.dev>
L: bpf@vger.kernel.org
S: Maintained
F: crypto/bpf_crypto_shash.c
+F: crypto/bpf_crypto_sig.c
F: crypto/bpf_crypto_skcipher.c
F: include/linux/bpf_crypto.h
F: kernel/bpf/crypto.c
diff --git a/crypto/Makefile b/crypto/Makefile
index 853dff375906..c9ab98b57bc0 100644
--- a/crypto/Makefile
+++ b/crypto/Makefile
@@ -36,6 +36,9 @@ endif
obj-$(CONFIG_CRYPTO_AKCIPHER2) += akcipher.o
obj-$(CONFIG_CRYPTO_SIG2) += sig.o
+ifeq ($(CONFIG_BPF_SYSCALL),y)
+obj-$(CONFIG_CRYPTO_SIG2) += bpf_crypto_sig.o
+endif
obj-$(CONFIG_CRYPTO_KPP2) += kpp.o
obj-$(CONFIG_CRYPTO_HKDF) += hkdf.o
diff --git a/crypto/bpf_crypto_sig.c b/crypto/bpf_crypto_sig.c
new file mode 100644
index 000000000000..ad0d3810df8e
--- /dev/null
+++ b/crypto/bpf_crypto_sig.c
@@ -0,0 +1,59 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/* Copyright (c) 2025 Meta Platforms, Inc. and affiliates. */
+#include <linux/types.h>
+#include <linux/module.h>
+#include <linux/bpf_crypto.h>
+#include <linux/crypto.h>
+#include <crypto/sig.h>
+
+static void *bpf_crypto_sig_alloc_tfm(const char *algo)
+{
+ return crypto_alloc_sig(algo, 0, 0);
+}
+
+static void bpf_crypto_sig_free_tfm(void *tfm)
+{
+ crypto_free_sig(tfm);
+}
+
+static int bpf_crypto_sig_has_algo(const char *algo)
+{
+ return crypto_has_alg(algo, CRYPTO_ALG_TYPE_SIG, CRYPTO_ALG_TYPE_MASK);
+}
+
+static u32 bpf_crypto_sig_get_flags(void *tfm)
+{
+ return crypto_tfm_get_flags(crypto_sig_tfm(tfm));
+}
+
+static int bpf_crypto_sig_setkey(void *tfm, const u8 *key, unsigned int keylen)
+{
+ return crypto_sig_set_pubkey(tfm, key, keylen);
+}
+
+static const struct bpf_crypto_type bpf_crypto_sig_type = {
+ .alloc_tfm = bpf_crypto_sig_alloc_tfm,
+ .free_tfm = bpf_crypto_sig_free_tfm,
+ .has_algo = bpf_crypto_sig_has_algo,
+ .get_flags = bpf_crypto_sig_get_flags,
+ .setkey = bpf_crypto_sig_setkey,
+ .owner = THIS_MODULE,
+ .name = "sig",
+};
+
+static int __init bpf_crypto_sig_init(void)
+{
+ return bpf_crypto_register_type(&bpf_crypto_sig_type);
+}
+
+static void __exit bpf_crypto_sig_exit(void)
+{
+ int err = bpf_crypto_unregister_type(&bpf_crypto_sig_type);
+
+ WARN_ON_ONCE(err);
+}
+
+module_init(bpf_crypto_sig_init);
+module_exit(bpf_crypto_sig_exit);
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("Signature algorithm support for BPF");
--
2.51.0
^ permalink raw reply related [flat|nested] 12+ messages in thread
* [PATCH bpf-next v4 3/6] bpf: Add hash kfunc for cryptographic hashing
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-05 17:37 ` [PATCH bpf-next v4 2/6] crypto: Add BPF signature " Daniel Hodges
@ 2026-01-05 17:37 ` 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
` (2 subsequent siblings)
5 siblings, 1 reply; 12+ messages in thread
From: Daniel Hodges @ 2026-01-05 17:37 UTC (permalink / raw)
To: bpf
Cc: Alexei Starovoitov, Andrii Nakryiko, Daniel Borkmann,
Vadim Fedorenko, Song Liu, Mykyta Yatsenko, Martin KaFai Lau,
Eduard Zingerman, Hao Luo, Jiri Olsa, John Fastabend, KP Singh,
Stanislav Fomichev, Yonghong Song, Herbert Xu, David S . Miller,
linux-crypto, linux-kernel, linux-kselftest, Daniel Hodges
Extend bpf_crypto_type structure with hash operations:
- hash(): Performs hashing operation
- digestsize(): Returns hash output size
Update bpf_crypto_ctx_create() to support keyless operations:
- Hash algorithms don't require keys, unlike ciphers
- Only validates key presence if type->setkey is defined
- Conditionally sets IV/state length for cipher operations only
Add bpf_crypto_hash() kfunc that works with any hash algorithm
registered in the kernel's crypto API through the BPF crypto type
system. This enables BPF programs to compute cryptographic hashes for
use cases such as content verification, integrity checking, and data
authentication.
Signed-off-by: Daniel Hodges <git@danielhodges.dev>
---
kernel/bpf/crypto.c | 78 ++++++++++++++++++++++++++++++++++++++++-----
1 file changed, 70 insertions(+), 8 deletions(-)
diff --git a/kernel/bpf/crypto.c b/kernel/bpf/crypto.c
index 1ab79a6dec84..f593e7910d3d 100644
--- a/kernel/bpf/crypto.c
+++ b/kernel/bpf/crypto.c
@@ -171,7 +171,12 @@ bpf_crypto_ctx_create(const struct bpf_crypto_params *params, u32 params__sz,
goto err_module_put;
}
- if (!params->key_len || params->key_len > sizeof(params->key)) {
+ /* Hash operations don't require a key, but cipher operations do */
+ if (params->key_len > sizeof(params->key)) {
+ *err = -EINVAL;
+ goto err_module_put;
+ }
+ if (!params->key_len && type->setkey) {
*err = -EINVAL;
goto err_module_put;
}
@@ -195,16 +200,19 @@ bpf_crypto_ctx_create(const struct bpf_crypto_params *params, u32 params__sz,
goto err_free_tfm;
}
- *err = type->setkey(ctx->tfm, params->key, params->key_len);
- if (*err)
- goto err_free_tfm;
+ if (params->key_len) {
+ *err = type->setkey(ctx->tfm, params->key, params->key_len);
+ if (*err)
+ goto err_free_tfm;
- if (type->get_flags(ctx->tfm) & CRYPTO_TFM_NEED_KEY) {
- *err = -EINVAL;
- goto err_free_tfm;
+ if (type->get_flags(ctx->tfm) & CRYPTO_TFM_NEED_KEY) {
+ *err = -EINVAL;
+ goto err_free_tfm;
+ }
}
- ctx->siv_len = type->ivsize(ctx->tfm) + type->statesize(ctx->tfm);
+ if (type->ivsize && type->statesize)
+ ctx->siv_len = type->ivsize(ctx->tfm) + type->statesize(ctx->tfm);
refcount_set(&ctx->usage, 1);
@@ -343,6 +351,55 @@ __bpf_kfunc int bpf_crypto_encrypt(struct bpf_crypto_ctx *ctx,
return bpf_crypto_crypt(ctx, src_kern, dst_kern, siv_kern, false);
}
+#if IS_ENABLED(CONFIG_CRYPTO_HASH2)
+/**
+ * bpf_crypto_hash() - Compute hash using configured context
+ * @ctx: The crypto context being used. The ctx must be a trusted pointer.
+ * @data: bpf_dynptr to the input data to hash. Must be a trusted pointer.
+ * @out: bpf_dynptr to the output buffer. Must be a trusted pointer.
+ *
+ * Computes hash of the input data using the crypto context. The output buffer
+ * must be at least as large as the digest size of the hash algorithm.
+ */
+__bpf_kfunc int bpf_crypto_hash(struct bpf_crypto_ctx *ctx,
+ const struct bpf_dynptr *data,
+ const struct bpf_dynptr *out)
+{
+ const struct bpf_dynptr_kern *data_kern = (struct bpf_dynptr_kern *)data;
+ const struct bpf_dynptr_kern *out_kern = (struct bpf_dynptr_kern *)out;
+ unsigned int digestsize;
+ u64 data_len, out_len;
+ const u8 *data_ptr;
+ u8 *out_ptr;
+
+ if (!ctx->type->hash)
+ return -EOPNOTSUPP;
+
+ data_len = __bpf_dynptr_size(data_kern);
+ out_len = __bpf_dynptr_size(out_kern);
+
+ if (data_len == 0 || data_len > UINT_MAX)
+ return -EINVAL;
+
+ if (!ctx->type->digestsize)
+ return -EOPNOTSUPP;
+
+ digestsize = ctx->type->digestsize(ctx->tfm);
+ if (out_len < digestsize)
+ return -EINVAL;
+
+ data_ptr = __bpf_dynptr_data(data_kern, data_len);
+ if (!data_ptr)
+ return -EINVAL;
+
+ out_ptr = __bpf_dynptr_data_rw(out_kern, out_len);
+ if (!out_ptr)
+ return -EINVAL;
+
+ return ctx->type->hash(ctx->tfm, data_ptr, out_ptr, data_len);
+}
+#endif /* CONFIG_CRYPTO_HASH2 */
+
__bpf_kfunc_end_defs();
BTF_KFUNCS_START(crypt_init_kfunc_btf_ids)
@@ -359,6 +416,9 @@ static const struct btf_kfunc_id_set crypt_init_kfunc_set = {
BTF_KFUNCS_START(crypt_kfunc_btf_ids)
BTF_ID_FLAGS(func, bpf_crypto_decrypt, KF_RCU)
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
BTF_KFUNCS_END(crypt_kfunc_btf_ids)
static const struct btf_kfunc_id_set crypt_kfunc_set = {
@@ -383,6 +443,8 @@ static int __init crypto_kfunc_init(void)
ret = register_btf_kfunc_id_set(BPF_PROG_TYPE_SCHED_CLS, &crypt_kfunc_set);
ret = ret ?: register_btf_kfunc_id_set(BPF_PROG_TYPE_SCHED_ACT, &crypt_kfunc_set);
ret = ret ?: register_btf_kfunc_id_set(BPF_PROG_TYPE_XDP, &crypt_kfunc_set);
+ /* Register for SYSCALL programs to enable testing and debugging */
+ 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);
return ret ?: register_btf_id_dtor_kfuncs(bpf_crypto_dtors,
--
2.51.0
^ permalink raw reply related [flat|nested] 12+ messages in thread
* [PATCH bpf-next v4 4/6] selftests/bpf: Add tests for bpf_crypto_hash kfunc
2026-01-05 17:37 [PATCH bpf-next v4 0/6] Add cryptographic hash and signature verification kfuncs to BPF Daniel Hodges
` (2 preceding siblings ...)
2026-01-05 17:37 ` [PATCH bpf-next v4 3/6] bpf: Add hash kfunc for cryptographic hashing Daniel Hodges
@ 2026-01-05 17:37 ` Daniel Hodges
2026-01-05 17:37 ` [PATCH bpf-next v4 5/6] bpf: Add ECDSA signature verification kfuncs Daniel Hodges
2026-01-05 17:37 ` [PATCH bpf-next v4 6/6] selftests/bpf: Add tests for " Daniel Hodges
5 siblings, 0 replies; 12+ messages in thread
From: Daniel Hodges @ 2026-01-05 17:37 UTC (permalink / raw)
To: bpf
Cc: Alexei Starovoitov, Andrii Nakryiko, Daniel Borkmann,
Vadim Fedorenko, Song Liu, Mykyta Yatsenko, Martin KaFai Lau,
Eduard Zingerman, Hao Luo, Jiri Olsa, John Fastabend, KP Singh,
Stanislav Fomichev, Yonghong Song, Herbert Xu, David S . Miller,
linux-crypto, linux-kernel, linux-kselftest, Daniel Hodges
Add selftests to validate the bpf_crypto_hash works properly. The tests
verify both correct functionality and proper error handling.
Test Data:
All tests use the well-known NIST test vector input "abc" and validate
against the standardized expected outputs for each algorithm. This ensures
the BPF kfunc wrappers correctly delegate to the kernel crypto library.
Signed-off-by: Daniel Hodges <git@danielhodges.dev>
---
MAINTAINERS | 2 +
tools/testing/selftests/bpf/config | 2 +
.../selftests/bpf/prog_tests/crypto_hash.c | 147 ++++++++++++++++++
.../selftests/bpf/progs/crypto_common.h | 7 +
.../testing/selftests/bpf/progs/crypto_hash.c | 136 ++++++++++++++++
5 files changed, 294 insertions(+)
create mode 100644 tools/testing/selftests/bpf/prog_tests/crypto_hash.c
create mode 100644 tools/testing/selftests/bpf/progs/crypto_hash.c
diff --git a/MAINTAINERS b/MAINTAINERS
index fdf451bad869..a413cb1b973c 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -4717,6 +4717,8 @@ F: crypto/bpf_crypto_sig.c
F: crypto/bpf_crypto_skcipher.c
F: include/linux/bpf_crypto.h
F: kernel/bpf/crypto.c
+F: tools/testing/selftests/bpf/prog_tests/crypto_hash.c
+F: tools/testing/selftests/bpf/progs/crypto_hash.c
BPF [DOCUMENTATION] (Related to Standardization)
R: David Vernet <void@manifault.com>
diff --git a/tools/testing/selftests/bpf/config b/tools/testing/selftests/bpf/config
index 558839e3c185..d168b3073cba 100644
--- a/tools/testing/selftests/bpf/config
+++ b/tools/testing/selftests/bpf/config
@@ -12,7 +12,9 @@ CONFIG_BPF_SYSCALL=y
# CONFIG_BPF_UNPRIV_DEFAULT_OFF is not set
CONFIG_CGROUP_BPF=y
CONFIG_CRYPTO_HMAC=y
+CONFIG_CRYPTO_HASH2=y
CONFIG_CRYPTO_SHA256=y
+CONFIG_CRYPTO_SHA512=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/crypto_hash.c b/tools/testing/selftests/bpf/prog_tests/crypto_hash.c
new file mode 100644
index 000000000000..1d8acbd56e32
--- /dev/null
+++ b/tools/testing/selftests/bpf/prog_tests/crypto_hash.c
@@ -0,0 +1,147 @@
+// SPDX-License-Identifier: GPL-2.0
+/* Copyright (c) 2025 Meta Platforms, Inc. and affiliates. */
+
+#include <test_progs.h>
+#include <errno.h>
+#include "crypto_hash.skel.h"
+
+/* NIST test vectors for SHA-256("abc") */
+static const unsigned char expected_sha256[32] = {
+ 0xba, 0x78, 0x16, 0xbf, 0x8f, 0x01, 0xcf, 0xea,
+ 0x41, 0x41, 0x40, 0xde, 0x5d, 0xae, 0x22, 0x23,
+ 0xb0, 0x03, 0x61, 0xa3, 0x96, 0x17, 0x7a, 0x9c,
+ 0xb4, 0x10, 0xff, 0x61, 0xf2, 0x00, 0x15, 0xad
+};
+
+/* NIST test vectors for SHA-384("abc") */
+static const unsigned char expected_sha384[48] = {
+ 0xcb, 0x00, 0x75, 0x3f, 0x45, 0xa3, 0x5e, 0x8b,
+ 0xb5, 0xa0, 0x3d, 0x69, 0x9a, 0xc6, 0x50, 0x07,
+ 0x27, 0x2c, 0x32, 0xab, 0x0e, 0xde, 0xd1, 0x63,
+ 0x1a, 0x8b, 0x60, 0x5a, 0x43, 0xff, 0x5b, 0xed,
+ 0x80, 0x86, 0x07, 0x2b, 0xa1, 0xe7, 0xcc, 0x23,
+ 0x58, 0xba, 0xec, 0xa1, 0x34, 0xc8, 0x25, 0xa7
+};
+
+/* NIST test vectors for SHA-512("abc") */
+static const unsigned char expected_sha512[64] = {
+ 0xdd, 0xaf, 0x35, 0xa1, 0x93, 0x61, 0x7a, 0xba,
+ 0xcc, 0x41, 0x73, 0x49, 0xae, 0x20, 0x41, 0x31,
+ 0x12, 0xe6, 0xfa, 0x4e, 0x89, 0xa9, 0x7e, 0xa2,
+ 0x0a, 0x9e, 0xee, 0xe6, 0x4b, 0x55, 0xd3, 0x9a,
+ 0x21, 0x92, 0x99, 0x2a, 0x27, 0x4f, 0xc1, 0xa8,
+ 0x36, 0xba, 0x3c, 0x23, 0xa3, 0xfe, 0xeb, 0xbd,
+ 0x45, 0x4d, 0x44, 0x23, 0x64, 0x3c, 0xe8, 0x0e,
+ 0x2a, 0x9a, 0xc9, 0x4f, 0xa5, 0x4c, 0xa4, 0x9f
+};
+
+static struct crypto_hash *setup_skel(void)
+{
+ struct crypto_hash *skel;
+
+ skel = crypto_hash__open_and_load();
+ if (!skel) {
+ /* Skip if kfuncs not available (CONFIG_CRYPTO_HASH2 not set) */
+ if (errno == ENOENT || errno == EINVAL) {
+ test__skip();
+ return NULL;
+ }
+ ASSERT_OK_PTR(skel, "crypto_hash__open_and_load");
+ return NULL;
+ }
+
+ return skel;
+}
+
+static void test_sha256_basic(void)
+{
+ struct crypto_hash *skel;
+ int err, prog_fd;
+
+ LIBBPF_OPTS(bpf_test_run_opts, topts);
+
+ skel = setup_skel();
+ if (!skel)
+ return;
+
+ prog_fd = bpf_program__fd(skel->progs.test_sha256);
+ err = bpf_prog_test_run_opts(prog_fd, &topts);
+ ASSERT_OK(err, "test_sha256");
+ ASSERT_EQ(skel->data->sha256_status, 0, "sha256_status");
+ ASSERT_EQ(memcmp(skel->bss->sha256_output, expected_sha256, 32), 0,
+ "sha256_output_match");
+
+ crypto_hash__destroy(skel);
+}
+
+static void test_sha384_basic(void)
+{
+ struct crypto_hash *skel;
+ int err, prog_fd;
+
+ LIBBPF_OPTS(bpf_test_run_opts, topts);
+
+ skel = setup_skel();
+ if (!skel)
+ return;
+ prog_fd = bpf_program__fd(skel->progs.test_sha384);
+ err = bpf_prog_test_run_opts(prog_fd, &topts);
+ ASSERT_OK(err, "test_sha384");
+ ASSERT_EQ(skel->data->sha384_status, 0, "sha384_status");
+ ASSERT_EQ(memcmp(skel->bss->sha384_output, expected_sha384, 48), 0,
+ "sha384_output_match");
+
+ crypto_hash__destroy(skel);
+}
+
+static void test_sha512_basic(void)
+{
+ struct crypto_hash *skel;
+ int err, prog_fd;
+
+ LIBBPF_OPTS(bpf_test_run_opts, topts);
+
+ skel = setup_skel();
+ if (!skel)
+ return;
+
+ prog_fd = bpf_program__fd(skel->progs.test_sha512);
+ err = bpf_prog_test_run_opts(prog_fd, &topts);
+ ASSERT_OK(err, "test_sha512");
+ ASSERT_EQ(skel->data->sha512_status, 0, "sha512_status");
+ ASSERT_EQ(memcmp(skel->bss->sha512_output, expected_sha512, 64), 0,
+ "sha512_output_match");
+
+ crypto_hash__destroy(skel);
+}
+
+static void test_sha256_invalid_params(void)
+{
+ struct crypto_hash *skel;
+ int err, prog_fd;
+
+ LIBBPF_OPTS(bpf_test_run_opts, topts);
+
+ skel = setup_skel();
+ if (!skel)
+ return;
+
+ prog_fd = bpf_program__fd(skel->progs.test_sha256_zero_len);
+ err = bpf_prog_test_run_opts(prog_fd, &topts);
+ ASSERT_OK(err, "test_zero_len");
+ ASSERT_EQ(skel->data->sha256_status, 0, "zero_len_rejected");
+
+ crypto_hash__destroy(skel);
+}
+
+void test_crypto_hash(void)
+{
+ if (test__start_subtest("sha256_basic"))
+ test_sha256_basic();
+ if (test__start_subtest("sha384_basic"))
+ test_sha384_basic();
+ if (test__start_subtest("sha512_basic"))
+ test_sha512_basic();
+ if (test__start_subtest("sha256_invalid_params"))
+ test_sha256_invalid_params();
+}
diff --git a/tools/testing/selftests/bpf/progs/crypto_common.h b/tools/testing/selftests/bpf/progs/crypto_common.h
index 57dd7a68a8c3..c357850b17a6 100644
--- a/tools/testing/selftests/bpf/progs/crypto_common.h
+++ b/tools/testing/selftests/bpf/progs/crypto_common.h
@@ -15,6 +15,13 @@ int bpf_crypto_encrypt(struct bpf_crypto_ctx *ctx, const struct bpf_dynptr *src,
const struct bpf_dynptr *dst, const struct bpf_dynptr *iv) __ksym;
int bpf_crypto_decrypt(struct bpf_crypto_ctx *ctx, const struct bpf_dynptr *src,
const struct bpf_dynptr *dst, const struct bpf_dynptr *iv) __ksym;
+int bpf_crypto_hash(struct bpf_crypto_ctx *ctx, const struct bpf_dynptr *data,
+ const struct bpf_dynptr *out) __ksym;
+int bpf_ecdsa_verify(struct bpf_crypto_ctx *ctx, const struct bpf_dynptr *message,
+ const struct bpf_dynptr *signature) __ksym;
+int bpf_ecdsa_keysize(struct bpf_crypto_ctx *ctx) __ksym;
+int bpf_ecdsa_digestsize(struct bpf_crypto_ctx *ctx) __ksym;
+int bpf_ecdsa_maxsize(struct bpf_crypto_ctx *ctx) __ksym;
struct __crypto_ctx_value {
struct bpf_crypto_ctx __kptr * ctx;
diff --git a/tools/testing/selftests/bpf/progs/crypto_hash.c b/tools/testing/selftests/bpf/progs/crypto_hash.c
new file mode 100644
index 000000000000..7eafbdd394af
--- /dev/null
+++ b/tools/testing/selftests/bpf/progs/crypto_hash.c
@@ -0,0 +1,136 @@
+// 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"
+#include "bpf_kfuncs.h"
+#include "crypto_common.h"
+
+unsigned char test_input[3] = "abc";
+
+/* Expected SHA-256 hash of "abc" */
+/* ba7816bf 8f01cfea 414140de 5dae2223 b00361a3 96177a9c b410ff61 f20015ad */
+unsigned char expected_sha256[32] = {
+ 0xba, 0x78, 0x16, 0xbf, 0x8f, 0x01, 0xcf, 0xea,
+ 0x41, 0x41, 0x40, 0xde, 0x5d, 0xae, 0x22, 0x23,
+ 0xb0, 0x03, 0x61, 0xa3, 0x96, 0x17, 0x7a, 0x9c,
+ 0xb4, 0x10, 0xff, 0x61, 0xf2, 0x00, 0x15, 0xad
+};
+
+/* Output buffers for test results */
+unsigned char sha256_output[32] = {};
+unsigned char sha384_output[48] = {};
+unsigned char sha512_output[64] = {};
+
+int sha256_status = -1;
+int sha384_status = -1;
+int sha512_status = -1;
+
+SEC("syscall")
+int test_sha256(void *ctx)
+{
+ struct bpf_dynptr input_ptr, output_ptr;
+ struct bpf_crypto_ctx *hash_ctx;
+ struct bpf_crypto_params params = {
+ .type = "hash",
+ .algo = "sha256",
+ .key_len = 0,
+ };
+ int err = 0;
+
+ hash_ctx = bpf_crypto_ctx_create(¶ms, sizeof(params), &err);
+ if (!hash_ctx) {
+ sha256_status = err;
+ return 0;
+ }
+
+ bpf_dynptr_from_mem(test_input, sizeof(test_input), 0, &input_ptr);
+ bpf_dynptr_from_mem(sha256_output, sizeof(sha256_output), 0, &output_ptr);
+
+ sha256_status = bpf_crypto_hash(hash_ctx, &input_ptr, &output_ptr);
+ bpf_crypto_ctx_release(hash_ctx);
+ return 0;
+}
+
+SEC("syscall")
+int test_sha384(void *ctx)
+{
+ struct bpf_dynptr input_ptr, output_ptr;
+ struct bpf_crypto_ctx *hash_ctx;
+ struct bpf_crypto_params params = {
+ .type = "hash",
+ .algo = "sha384",
+ .key_len = 0,
+ };
+ int err = 0;
+
+ hash_ctx = bpf_crypto_ctx_create(¶ms, sizeof(params), &err);
+ if (!hash_ctx) {
+ sha384_status = err;
+ return 0;
+ }
+
+ bpf_dynptr_from_mem(test_input, sizeof(test_input), 0, &input_ptr);
+ bpf_dynptr_from_mem(sha384_output, sizeof(sha384_output), 0, &output_ptr);
+
+ sha384_status = bpf_crypto_hash(hash_ctx, &input_ptr, &output_ptr);
+ bpf_crypto_ctx_release(hash_ctx);
+ return 0;
+}
+
+SEC("syscall")
+int test_sha512(void *ctx)
+{
+ struct bpf_dynptr input_ptr, output_ptr;
+ struct bpf_crypto_ctx *hash_ctx;
+ struct bpf_crypto_params params = {
+ .type = "hash",
+ .algo = "sha512",
+ .key_len = 0,
+ };
+ int err = 0;
+
+ hash_ctx = bpf_crypto_ctx_create(¶ms, sizeof(params), &err);
+ if (!hash_ctx) {
+ sha512_status = err;
+ return 0;
+ }
+
+ bpf_dynptr_from_mem(test_input, sizeof(test_input), 0, &input_ptr);
+ bpf_dynptr_from_mem(sha512_output, sizeof(sha512_output), 0, &output_ptr);
+
+ sha512_status = bpf_crypto_hash(hash_ctx, &input_ptr, &output_ptr);
+ bpf_crypto_ctx_release(hash_ctx);
+ return 0;
+}
+
+SEC("syscall")
+int test_sha256_zero_len(void *ctx)
+{
+ struct bpf_dynptr input_ptr, output_ptr;
+ struct bpf_crypto_ctx *hash_ctx;
+ struct bpf_crypto_params params = {
+ .type = "hash",
+ .algo = "sha256",
+ .key_len = 0,
+ };
+ int err = 0;
+ int ret;
+
+ hash_ctx = bpf_crypto_ctx_create(¶ms, sizeof(params), &err);
+ if (!hash_ctx) {
+ sha256_status = err;
+ return 0;
+ }
+
+ bpf_dynptr_from_mem(test_input, 0, 0, &input_ptr);
+ bpf_dynptr_from_mem(sha256_output, sizeof(sha256_output), 0, &output_ptr);
+
+ ret = bpf_crypto_hash(hash_ctx, &input_ptr, &output_ptr);
+ sha256_status = (ret == -22) ? 0 : ret;
+ bpf_crypto_ctx_release(hash_ctx);
+ return 0;
+}
+
+char __license[] SEC("license") = "GPL";
--
2.51.0
^ permalink raw reply related [flat|nested] 12+ messages in thread
* [PATCH bpf-next v4 5/6] bpf: Add ECDSA signature verification kfuncs
2026-01-05 17:37 [PATCH bpf-next v4 0/6] Add cryptographic hash and signature verification kfuncs to BPF Daniel Hodges
` (3 preceding siblings ...)
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
2026-01-06 22:17 ` 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
5 siblings, 2 replies; 12+ messages in thread
From: Daniel Hodges @ 2026-01-05 17:37 UTC (permalink / raw)
To: bpf
Cc: Alexei Starovoitov, Andrii Nakryiko, Daniel Borkmann,
Vadim Fedorenko, Song Liu, Mykyta Yatsenko, Martin KaFai Lau,
Eduard Zingerman, Hao Luo, Jiri Olsa, John Fastabend, KP Singh,
Stanislav Fomichev, Yonghong Song, Herbert Xu, David S . Miller,
linux-crypto, linux-kernel, linux-kselftest, Daniel Hodges
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
^ permalink raw reply related [flat|nested] 12+ messages in thread
* [PATCH bpf-next v4 6/6] selftests/bpf: Add tests for ECDSA signature verification kfuncs
2026-01-05 17:37 [PATCH bpf-next v4 0/6] Add cryptographic hash and signature verification kfuncs to BPF Daniel Hodges
` (4 preceding siblings ...)
2026-01-05 17:37 ` [PATCH bpf-next v4 5/6] bpf: Add ECDSA signature verification kfuncs Daniel Hodges
@ 2026-01-05 17:37 ` Daniel Hodges
5 siblings, 0 replies; 12+ messages in thread
From: Daniel Hodges @ 2026-01-05 17:37 UTC (permalink / raw)
To: bpf
Cc: Alexei Starovoitov, Andrii Nakryiko, Daniel Borkmann,
Vadim Fedorenko, Song Liu, Mykyta Yatsenko, Martin KaFai Lau,
Eduard Zingerman, Hao Luo, Jiri Olsa, John Fastabend, KP Singh,
Stanislav Fomichev, Yonghong Song, Herbert Xu, David S . Miller,
linux-crypto, linux-kernel, linux-kselftest, Daniel Hodges
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>
---
MAINTAINERS | 2 +
tools/testing/selftests/bpf/config | 1 +
.../selftests/bpf/prog_tests/ecdsa_verify.c | 75 +++++++++
.../selftests/bpf/progs/ecdsa_verify.c | 157 ++++++++++++++++++
4 files changed, 235 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/MAINTAINERS b/MAINTAINERS
index a413cb1b973c..7d65deb4dd03 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -4718,7 +4718,9 @@ F: crypto/bpf_crypto_skcipher.c
F: include/linux/bpf_crypto.h
F: kernel/bpf/crypto.c
F: tools/testing/selftests/bpf/prog_tests/crypto_hash.c
+F: tools/testing/selftests/bpf/prog_tests/ecdsa_verify.c
F: tools/testing/selftests/bpf/progs/crypto_hash.c
+F: tools/testing/selftests/bpf/progs/ecdsa_verify.c
BPF [DOCUMENTATION] (Related to Standardization)
R: David Vernet <void@manifault.com>
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..2dd74995bd3a
--- /dev/null
+++ b/tools/testing/selftests/bpf/progs/ecdsa_verify.c
@@ -0,0 +1,157 @@
+// 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"
+#include "crypto_common.h"
+
+/* NIST P-256 test vector
+ * This is a known valid ECDSA signature for testing purposes
+ */
+
+/* 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_crypto_ctx *ecdsa_ctx;
+ struct bpf_crypto_params params = {
+ .type = "sig",
+ .algo = "p1363(ecdsa-nist-p256)",
+ .key_len = sizeof(pubkey_p256),
+ };
+ struct bpf_dynptr msg_ptr, sig_ptr;
+ int err = 0;
+
+ __builtin_memcpy(params.key, pubkey_p256, sizeof(pubkey_p256));
+
+ ecdsa_ctx = bpf_crypto_ctx_create(¶ms, sizeof(params), &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_crypto_ctx_release(ecdsa_ctx);
+
+ return 0;
+}
+
+SEC("syscall")
+int test_ecdsa_verify_invalid(void *ctx)
+{
+ struct bpf_crypto_ctx *ecdsa_ctx;
+ struct bpf_crypto_params params = {
+ .type = "sig",
+ .algo = "p1363(ecdsa-nist-p256)",
+ .key_len = sizeof(pubkey_p256),
+ };
+ struct bpf_dynptr msg_ptr, sig_ptr;
+ int err = 0;
+
+ __builtin_memcpy(params.key, pubkey_p256, sizeof(pubkey_p256));
+
+ ecdsa_ctx = bpf_crypto_ctx_create(¶ms, sizeof(params), &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_crypto_ctx_release(ecdsa_ctx);
+
+ return 0;
+}
+
+SEC("syscall")
+int test_ecdsa_size_queries(void *ctx)
+{
+ struct bpf_crypto_ctx *ecdsa_ctx;
+ struct bpf_crypto_params params = {
+ .type = "sig",
+ .algo = "p1363(ecdsa-nist-p256)",
+ .key_len = sizeof(pubkey_p256),
+ };
+ int err = 0;
+
+ __builtin_memcpy(params.key, pubkey_p256, sizeof(pubkey_p256));
+
+ ecdsa_ctx = bpf_crypto_ctx_create(¶ms, sizeof(params), &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_crypto_ctx_release(ecdsa_ctx);
+
+ return 0;
+}
+
+char __license[] SEC("license") = "GPL";
--
2.51.0
^ permalink raw reply related [flat|nested] 12+ messages in thread
* Re: [PATCH bpf-next v4 1/6] crypto: Add BPF hash algorithm type registration module
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
0 siblings, 0 replies; 12+ messages in thread
From: Vadim Fedorenko @ 2026-01-06 21:57 UTC (permalink / raw)
To: Daniel Hodges, bpf
Cc: Alexei Starovoitov, Andrii Nakryiko, Daniel Borkmann, Song Liu,
Mykyta Yatsenko, Martin KaFai Lau, Eduard Zingerman, Hao Luo,
Jiri Olsa, John Fastabend, KP Singh, Stanislav Fomichev,
Yonghong Song, Herbert Xu, David S . Miller, linux-crypto,
linux-kernel, linux-kselftest
On 05/01/2026 17:37, Daniel Hodges wrote:
> Add bpf_crypto_shash module that registers a hash type with the BPF
> crypto infrastructure, enabling BPF programs to access kernel hash
> algorithms through a unified interface.
>
> Update the bpf_crypto_type interface with hash-specific callbacks:
> - alloc_tfm: Allocates crypto_shash context with proper descriptor size
> - free_tfm: Releases hash transform and context memory
> - has_algo: Checks algorithm availability via crypto_has_shash()
> - hash: Performs single-shot hashing via crypto_shash_digest()
> - digestsize: Returns the output size for the hash algorithm
> - get_flags: Exposes transform flags to BPF programs
>
> Update bpf_shash_ctx to contain crypto_shash transform and shash_desc
> descriptor to accommodate algorithm-specific descriptor requirements.
>
> Signed-off-by: Daniel Hodges <git@danielhodges.dev>
> ---
> MAINTAINERS | 1 +
> crypto/Makefile | 3 ++
> crypto/bpf_crypto_shash.c | 95 +++++++++++++++++++++++++++++++++++++++
> 3 files changed, 99 insertions(+)
> create mode 100644 crypto/bpf_crypto_shash.c
[...]
> +static const struct bpf_crypto_type bpf_crypto_shash_type = {
> + .alloc_tfm = bpf_crypto_shash_alloc_tfm,
> + .free_tfm = bpf_crypto_shash_free_tfm,
> + .has_algo = bpf_crypto_shash_has_algo,
> + .hash = bpf_crypto_shash_hash,
I don't see a definition of hash() callback in struct bpf_crypto_type
> + .digestsize = bpf_crypto_shash_digestsize,
> + .get_flags = bpf_crypto_shash_get_flags,
> + .owner = THIS_MODULE,
> + .name = "hash",
> +};
^ permalink raw reply [flat|nested] 12+ messages in thread
* Re: [PATCH bpf-next v4 2/6] crypto: Add BPF signature algorithm type registration module
2026-01-05 17:37 ` [PATCH bpf-next v4 2/6] crypto: Add BPF signature " Daniel Hodges
@ 2026-01-06 22:08 ` Vadim Fedorenko
0 siblings, 0 replies; 12+ messages in thread
From: Vadim Fedorenko @ 2026-01-06 22:08 UTC (permalink / raw)
To: Daniel Hodges, bpf
Cc: Alexei Starovoitov, Andrii Nakryiko, Daniel Borkmann, Song Liu,
Mykyta Yatsenko, Martin KaFai Lau, Eduard Zingerman, Hao Luo,
Jiri Olsa, John Fastabend, KP Singh, Stanislav Fomichev,
Yonghong Song, Herbert Xu, David S . Miller, linux-crypto,
linux-kernel, linux-kselftest
On 05/01/2026 17:37, Daniel Hodges wrote:
> Add a new bpf_crypto_sig module that registers signature verification
> algorithms with the BPF crypto type system. This enables signature
> operations (like ECDSA) to use the unified bpf_crypto_ctx structure
> instead of requiring separate context types.
>
> The module provides:
> - alloc_tfm/free_tfm for crypto_sig transform lifecycle
> - has_algo to check algorithm availability
> - get_flags for crypto API flags
>
> This allows ECDSA and other signature verification operations to
> integrate with the existing BPF crypto infrastructure.
>
> Signed-off-by: Daniel Hodges <git@danielhodges.dev>
[...]
> +static int bpf_crypto_sig_setkey(void *tfm, const u8 *key, unsigned int keylen)
> +{
> + return crypto_sig_set_pubkey(tfm, key, keylen);
> +}
That effectively means that signature verification only is provided for
BPF programs? Do we plan to extend API to sign a buffer?
> +
> +static const struct bpf_crypto_type bpf_crypto_sig_type = {
> + .alloc_tfm = bpf_crypto_sig_alloc_tfm,
> + .free_tfm = bpf_crypto_sig_free_tfm,
> + .has_algo = bpf_crypto_sig_has_algo,
> + .get_flags = bpf_crypto_sig_get_flags,
> + .setkey = bpf_crypto_sig_setkey,
> + .owner = THIS_MODULE,
> + .name = "sig",
> +};
I think we have to introduce verify() callback here.
^ permalink raw reply [flat|nested] 12+ messages in thread
* Re: [PATCH bpf-next v4 3/6] bpf: Add hash kfunc for cryptographic hashing
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
0 siblings, 0 replies; 12+ messages in thread
From: Vadim Fedorenko @ 2026-01-06 22:12 UTC (permalink / raw)
To: Daniel Hodges, bpf
Cc: Alexei Starovoitov, Andrii Nakryiko, Daniel Borkmann, Song Liu,
Mykyta Yatsenko, Martin KaFai Lau, Eduard Zingerman, Hao Luo,
Jiri Olsa, John Fastabend, KP Singh, Stanislav Fomichev,
Yonghong Song, Herbert Xu, David S . Miller, linux-crypto,
linux-kernel, linux-kselftest
On 05/01/2026 17:37, Daniel Hodges wrote:
> Extend bpf_crypto_type structure with hash operations:
> - hash(): Performs hashing operation
> - digestsize(): Returns hash output size
well, as I've already mentioned, none of them are actually introduced in
the patchset.
>
> Update bpf_crypto_ctx_create() to support keyless operations:
> - Hash algorithms don't require keys, unlike ciphers
> - Only validates key presence if type->setkey is defined
> - Conditionally sets IV/state length for cipher operations only
>
> Add bpf_crypto_hash() kfunc that works with any hash algorithm
> registered in the kernel's crypto API through the BPF crypto type
> system. This enables BPF programs to compute cryptographic hashes for
> use cases such as content verification, integrity checking, and data
> authentication.
>
> Signed-off-by: Daniel Hodges <git@danielhodges.dev>
> ---
> kernel/bpf/crypto.c | 78 ++++++++++++++++++++++++++++++++++++++++-----
> 1 file changed, 70 insertions(+), 8 deletions(-)
>
^ permalink raw reply [flat|nested] 12+ messages in thread
* Re: [PATCH bpf-next v4 5/6] bpf: Add ECDSA signature verification kfuncs
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
2026-01-06 23:11 ` Vadim Fedorenko
1 sibling, 0 replies; 12+ messages in thread
From: Vadim Fedorenko @ 2026-01-06 22:17 UTC (permalink / raw)
To: Daniel Hodges, bpf
Cc: Alexei Starovoitov, Andrii Nakryiko, Daniel Borkmann, Song Liu,
Mykyta Yatsenko, Martin KaFai Lau, Eduard Zingerman, Hao Luo,
Jiri Olsa, John Fastabend, KP Singh, Stanislav Fomichev,
Yonghong Song, Herbert Xu, David S . Miller, linux-crypto,
linux-kernel, linux-kselftest
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);
^ permalink raw reply [flat|nested] 12+ messages in thread
* Re: [PATCH bpf-next v4 5/6] bpf: Add ECDSA signature verification kfuncs
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
@ 2026-01-06 23:11 ` Vadim Fedorenko
1 sibling, 0 replies; 12+ messages in thread
From: Vadim Fedorenko @ 2026-01-06 23:11 UTC (permalink / raw)
To: Daniel Hodges, bpf
Cc: Alexei Starovoitov, Andrii Nakryiko, Daniel Borkmann, Song Liu,
Mykyta Yatsenko, Martin KaFai Lau, Eduard Zingerman, Hao Luo,
Jiri Olsa, John Fastabend, KP Singh, Stanislav Fomichev,
Yonghong Song, Herbert Xu, David S . Miller, linux-crypto,
linux-kernel, linux-kselftest
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>
> @@ -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;
This chunk is extra empty line - no need for it
^ permalink raw reply [flat|nested] 12+ messages in thread
end of thread, other threads:[~2026-01-06 23:12 UTC | newest]
Thread overview: 12+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
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
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
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).