[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-ID: <20260120184701.23082-7-git@danielhodges.dev>
Date: Tue, 20 Jan 2026 13:47:00 -0500
From: Daniel Hodges <git@...ielhodges.dev>
To: bpf@...r.kernel.org
Cc: Alexei Starovoitov <ast@...nel.org>,
Andrii Nakryiko <andrii@...nel.org>,
Daniel Borkmann <daniel@...earbox.net>,
Vadim Fedorenko <vadim.fedorenko@...ux.dev>,
Song Liu <song@...nel.org>,
Mykyta Yatsenko <yatsenko@...a.com>,
Martin KaFai Lau <martin.lau@...ux.dev>,
Eduard Zingerman <eddyz87@...il.com>,
Hao Luo <haoluo@...gle.com>,
Jiri Olsa <jolsa@...nel.org>,
John Fastabend <john.fastabend@...il.com>,
KP Singh <kpsingh@...nel.org>,
Stanislav Fomichev <sdf@...ichev.me>,
Yonghong Song <yonghong.song@...ux.dev>,
Herbert Xu <herbert@...dor.apana.org.au>,
"David S . Miller" <davem@...emloft.net>,
linux-crypto@...r.kernel.org,
linux-kernel@...r.kernel.org,
linux-kselftest@...r.kernel.org,
Daniel Hodges <git@...ielhodges.dev>
Subject: [PATCH bpf-next v5 6/7] bpf: Add signature verification kfuncs
Introduce bpf_sig_verify, bpf_sig_keysize, bpf_sig_digestsize,
and bpf_sig_maxsize kfuncs enabling BPF programs to verify digital
signatures using the kernel's crypto infrastructure.
This adds enum bpf_crypto_type_id for runtime type checking to ensure
operations are performed on the correct crypto context type. The enum
values are assigned to all crypto type modules (skcipher, hash, sig).
The verify kfunc takes a crypto context (initialized with the "sig"
type and appropriate algorithm like "ecdsa-nist-p256"), a message
digest, and a signature. It uses dynptr for memory access.
These kfuncs support any signature algorithm registered with the
crypto subsystem (e.g., ECDSA, RSA).
Signed-off-by: Daniel Hodges <git@...ielhodges.dev>
---
crypto/bpf_crypto_sig.c | 22 +++++++
crypto/bpf_crypto_skcipher.c | 1 +
include/linux/bpf_crypto.h | 2 +
kernel/bpf/crypto.c | 117 +++++++++++++++++++++++++++++++++++
4 files changed, 142 insertions(+)
diff --git a/crypto/bpf_crypto_sig.c b/crypto/bpf_crypto_sig.c
index 1d6521a066be..2dc82c5f9abb 100644
--- a/crypto/bpf_crypto_sig.c
+++ b/crypto/bpf_crypto_sig.c
@@ -37,6 +37,25 @@ static int bpf_crypto_sig_verify(void *tfm, const u8 *sig, unsigned int sig_len,
return crypto_sig_verify(tfm, sig, sig_len, msg, msg_len);
}
+static unsigned int bpf_crypto_sig_keysize(void *tfm)
+{
+ return crypto_sig_keysize(tfm);
+}
+
+static unsigned int bpf_crypto_sig_digestsize(void *tfm)
+{
+ struct sig_alg *alg = crypto_sig_alg(tfm);
+
+ return alg->digest_size ? alg->digest_size(tfm) : 0;
+}
+
+static unsigned int bpf_crypto_sig_maxsize(void *tfm)
+{
+ struct sig_alg *alg = crypto_sig_alg(tfm);
+
+ return alg->max_size ? alg->max_size(tfm) : 0;
+}
+
static const struct bpf_crypto_type bpf_crypto_sig_type = {
.alloc_tfm = bpf_crypto_sig_alloc_tfm,
.free_tfm = bpf_crypto_sig_free_tfm,
@@ -44,6 +63,9 @@ static const struct bpf_crypto_type bpf_crypto_sig_type = {
.get_flags = bpf_crypto_sig_get_flags,
.setkey = bpf_crypto_sig_setkey,
.verify = bpf_crypto_sig_verify,
+ .keysize = bpf_crypto_sig_keysize,
+ .digestsize = bpf_crypto_sig_digestsize,
+ .maxsize = bpf_crypto_sig_maxsize,
.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 363ed72561f4..e0f946926f69 100644
--- a/include/linux/bpf_crypto.h
+++ b/include/linux/bpf_crypto.h
@@ -23,6 +23,8 @@ struct bpf_crypto_type {
unsigned int (*ivsize)(void *tfm);
unsigned int (*statesize)(void *tfm);
unsigned int (*digestsize)(void *tfm);
+ unsigned int (*keysize)(void *tfm);
+ unsigned int (*maxsize)(void *tfm);
u32 (*get_flags)(void *tfm);
struct module *owner;
enum bpf_crypto_type_id type_id;
diff --git a/kernel/bpf/crypto.c b/kernel/bpf/crypto.c
index c8f354b1a2cb..6bc534cd4076 100644
--- a/kernel/bpf/crypto.c
+++ b/kernel/bpf/crypto.c
@@ -413,6 +413,117 @@ __bpf_kfunc int bpf_crypto_hash(struct bpf_crypto_ctx *ctx,
}
#endif /* CONFIG_CRYPTO_HASH2 */
+#if IS_ENABLED(CONFIG_CRYPTO_SIG2)
+/**
+ * bpf_sig_verify() - Verify digital signature using configured context
+ * @ctx: The crypto context being used. The ctx must be a trusted pointer.
+ * @message: bpf_dynptr to the message hash to verify. Must be a trusted pointer.
+ * @signature: bpf_dynptr to the signature. Must be a trusted pointer.
+ *
+ * Verifies a digital signature over a message hash using the public key
+ * configured in the crypto context. Supports any signature algorithm
+ * registered with the crypto subsystem (e.g., ECDSA, RSA).
+ *
+ * Return: 0 on success (valid signature), negative error code on failure.
+ */
+__bpf_kfunc int bpf_sig_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;
+ u64 msg_len, sig_len;
+ const u8 *msg_ptr, *sig_ptr;
+
+ if (ctx->type->type_id != BPF_CRYPTO_TYPE_SIG)
+ return -EINVAL;
+
+ if (!ctx->type->verify)
+ return -EOPNOTSUPP;
+
+ msg_len = __bpf_dynptr_size(msg_kern);
+ sig_len = __bpf_dynptr_size(sig_kern);
+
+ if (msg_len == 0 || msg_len > UINT_MAX)
+ return -EINVAL;
+ if (sig_len == 0 || sig_len > UINT_MAX)
+ 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;
+
+ return ctx->type->verify(ctx->tfm, sig_ptr, sig_len, msg_ptr, msg_len);
+}
+
+/**
+ * bpf_sig_keysize() - Get the key size for signature context
+ * @ctx: The crypto context being used. The ctx must be a trusted pointer.
+ *
+ * Return: The key size in bytes, or negative error code on failure.
+ */
+__bpf_kfunc int bpf_sig_keysize(struct bpf_crypto_ctx *ctx)
+{
+ if (ctx->type->type_id != BPF_CRYPTO_TYPE_SIG)
+ return -EINVAL;
+
+ if (!ctx->type->keysize)
+ return -EOPNOTSUPP;
+
+ return ctx->type->keysize(ctx->tfm);
+}
+
+/**
+ * bpf_sig_digestsize() - Get the digest size for signature context
+ * @ctx: The crypto context being used. The ctx must be a trusted pointer.
+ *
+ * Return: The digest size in bytes, or negative error code on failure.
+ */
+__bpf_kfunc int bpf_sig_digestsize(struct bpf_crypto_ctx *ctx)
+{
+ unsigned int size;
+
+ if (ctx->type->type_id != BPF_CRYPTO_TYPE_SIG)
+ return -EINVAL;
+
+ if (!ctx->type->digestsize)
+ return -EOPNOTSUPP;
+
+ size = ctx->type->digestsize(ctx->tfm);
+ if (!size)
+ return -EOPNOTSUPP;
+
+ return size;
+}
+
+/**
+ * bpf_sig_maxsize() - Get the maximum signature size for signature context
+ * @ctx: The crypto context being used. The ctx must be a trusted pointer.
+ *
+ * Return: The maximum signature size in bytes, or negative error code on failure.
+ */
+__bpf_kfunc int bpf_sig_maxsize(struct bpf_crypto_ctx *ctx)
+{
+ unsigned int size;
+
+ if (ctx->type->type_id != BPF_CRYPTO_TYPE_SIG)
+ return -EINVAL;
+
+ if (!ctx->type->maxsize)
+ return -EOPNOTSUPP;
+
+ size = ctx->type->maxsize(ctx->tfm);
+ if (!size)
+ return -EOPNOTSUPP;
+
+ return size;
+}
+#endif /* CONFIG_CRYPTO_SIG2 */
+
__bpf_kfunc_end_defs();
BTF_KFUNCS_START(crypt_init_kfunc_btf_ids)
@@ -432,6 +543,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_SIG2)
+BTF_ID_FLAGS(func, bpf_sig_verify, KF_RCU)
+BTF_ID_FLAGS(func, bpf_sig_keysize)
+BTF_ID_FLAGS(func, bpf_sig_digestsize)
+BTF_ID_FLAGS(func, bpf_sig_maxsize)
+#endif
BTF_KFUNCS_END(crypt_kfunc_btf_ids)
static const struct btf_kfunc_id_set crypt_kfunc_set = {
--
2.52.0
Powered by blists - more mailing lists