Skip to content

Commit 3b29669

Browse files
hodgesdsKernel Patches Daemon
authored andcommitted
bpf: Add ECDSA signature verification kfuncs
Add context-based ECDSA signature verification kfuncs: - bpf_ecdsa_ctx_create(): Creates reusable ECDSA context with public key - bpf_ecdsa_verify(): Verifies signatures using the context - bpf_ecdsa_ctx_acquire(): Increments context reference count - bpf_ecdsa_ctx_release(): Releases context with RCU safety The ECDSA implementation supports NIST curves (P-256, P-384, P-521) and uses the kernel's crypto_sig API. Public keys must be in uncompressed format (0x04 || x || y), and signatures are in r || s format. Signed-off-by: Daniel Hodges <[email protected]>
1 parent d2c69e6 commit 3b29669

File tree

1 file changed

+230
-0
lines changed

1 file changed

+230
-0
lines changed

kernel/bpf/crypto.c

Lines changed: 230 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
#include <linux/scatterlist.h>
1010
#include <linux/skbuff.h>
1111
#include <crypto/skcipher.h>
12+
#include <crypto/sig.h>
1213

1314
struct bpf_crypto_type_list {
1415
const struct bpf_crypto_type *type;
@@ -57,6 +58,21 @@ struct bpf_crypto_ctx {
5758
refcount_t usage;
5859
};
5960

61+
#if IS_ENABLED(CONFIG_CRYPTO_ECDSA)
62+
/**
63+
* struct bpf_ecdsa_ctx - refcounted BPF ECDSA context structure
64+
* @tfm: The crypto_sig transform for ECDSA operations
65+
* @rcu: The RCU head used to free the context with RCU safety
66+
* @usage: Object reference counter. When the refcount goes to 0, the
67+
* memory is released with RCU safety.
68+
*/
69+
struct bpf_ecdsa_ctx {
70+
struct crypto_sig *tfm;
71+
struct rcu_head rcu;
72+
refcount_t usage;
73+
};
74+
#endif
75+
6076
int bpf_crypto_register_type(const struct bpf_crypto_type *type)
6177
{
6278
struct bpf_crypto_type_list *node;
@@ -399,12 +415,206 @@ __bpf_kfunc int bpf_crypto_hash(struct bpf_crypto_ctx *ctx,
399415
}
400416
#endif /* CONFIG_CRYPTO_HASH2 */
401417

418+
#if IS_ENABLED(CONFIG_CRYPTO_ECDSA)
419+
/**
420+
* bpf_ecdsa_ctx_create() - Create a BPF ECDSA verification context
421+
* @algo_name: bpf_dynptr to the algorithm name (e.g., "p1363(ecdsa-nist-p256)")
422+
* @public_key: bpf_dynptr to the public key in uncompressed format (0x04 || x || y)
423+
* Must be 65 bytes for P-256, 97 for P-384, 133 for P-521
424+
* @err: Pointer to store error code on failure
425+
*
426+
* Creates an ECDSA verification context that can be reused for multiple
427+
* signature verifications. This function uses GFP_KERNEL allocation and
428+
* can only be called from sleepable BPF programs. Uses bpf_dynptr to ensure
429+
* safe memory access without risk of page faults.
430+
*/
431+
__bpf_kfunc struct bpf_ecdsa_ctx *
432+
bpf_ecdsa_ctx_create(const struct bpf_dynptr *algo_name,
433+
const struct bpf_dynptr *public_key, int *err)
434+
{
435+
const struct bpf_dynptr_kern *algo_kern = (struct bpf_dynptr_kern *)algo_name;
436+
const struct bpf_dynptr_kern *key_kern = (struct bpf_dynptr_kern *)public_key;
437+
struct bpf_ecdsa_ctx *ctx;
438+
const char *algo_ptr;
439+
const u8 *key_ptr;
440+
u32 algo_len, key_len;
441+
char algo[64];
442+
int ret;
443+
444+
if (!err)
445+
return NULL;
446+
447+
algo_len = __bpf_dynptr_size(algo_kern);
448+
key_len = __bpf_dynptr_size(key_kern);
449+
450+
if (algo_len == 0 || algo_len >= sizeof(algo)) {
451+
*err = -EINVAL;
452+
return NULL;
453+
}
454+
455+
if (key_len < 65) {
456+
*err = -EINVAL;
457+
return NULL;
458+
}
459+
460+
algo_ptr = __bpf_dynptr_data(algo_kern, algo_len);
461+
if (!algo_ptr) {
462+
*err = -EINVAL;
463+
return NULL;
464+
}
465+
466+
key_ptr = __bpf_dynptr_data(key_kern, key_len);
467+
if (!key_ptr) {
468+
*err = -EINVAL;
469+
return NULL;
470+
}
471+
472+
if (key_ptr[0] != 0x04) {
473+
*err = -EINVAL;
474+
return NULL;
475+
}
476+
477+
memcpy(algo, algo_ptr, algo_len);
478+
algo[algo_len] = '\0';
479+
480+
ctx = kzalloc(sizeof(*ctx), GFP_KERNEL);
481+
if (!ctx) {
482+
*err = -ENOMEM;
483+
return NULL;
484+
}
485+
486+
ctx->tfm = crypto_alloc_sig(algo, 0, 0);
487+
if (IS_ERR(ctx->tfm)) {
488+
*err = PTR_ERR(ctx->tfm);
489+
kfree(ctx);
490+
return NULL;
491+
}
492+
493+
ret = crypto_sig_set_pubkey(ctx->tfm, key_ptr, key_len);
494+
if (ret) {
495+
*err = ret;
496+
crypto_free_sig(ctx->tfm);
497+
kfree(ctx);
498+
return NULL;
499+
}
500+
501+
refcount_set(&ctx->usage, 1);
502+
*err = 0;
503+
return ctx;
504+
}
505+
506+
/**
507+
* bpf_ecdsa_verify() - Verify ECDSA signature using pre-allocated context
508+
* @ctx: ECDSA context created by bpf_ecdsa_ctx_create()
509+
* @message: bpf_dynptr to the message hash to verify. Must be a trusted pointer.
510+
* @signature: bpf_dynptr to the ECDSA signature in r || s format. Must be a trusted pointer.
511+
* Must be 64 bytes for P-256, 96 for P-384, 132 for P-521
512+
*
513+
* Verifies an ECDSA signature using a pre-allocated context. This function
514+
* does not allocate memory and can be used in non-sleepable BPF programs.
515+
* Uses bpf_dynptr to ensure safe memory access without risk of page faults.
516+
*/
517+
__bpf_kfunc int bpf_ecdsa_verify(struct bpf_ecdsa_ctx *ctx,
518+
const struct bpf_dynptr *message,
519+
const struct bpf_dynptr *signature)
520+
{
521+
const struct bpf_dynptr_kern *msg_kern = (struct bpf_dynptr_kern *)message;
522+
const struct bpf_dynptr_kern *sig_kern = (struct bpf_dynptr_kern *)signature;
523+
const u8 *msg_ptr, *sig_ptr;
524+
u32 msg_len, sig_len;
525+
526+
if (!ctx)
527+
return -EINVAL;
528+
529+
msg_len = __bpf_dynptr_size(msg_kern);
530+
sig_len = __bpf_dynptr_size(sig_kern);
531+
532+
if (msg_len == 0 || sig_len == 0)
533+
return -EINVAL;
534+
535+
msg_ptr = __bpf_dynptr_data(msg_kern, msg_len);
536+
if (!msg_ptr)
537+
return -EINVAL;
538+
539+
sig_ptr = __bpf_dynptr_data(sig_kern, sig_len);
540+
if (!sig_ptr)
541+
return -EINVAL;
542+
543+
return crypto_sig_verify(ctx->tfm, sig_ptr, sig_len, msg_ptr, msg_len);
544+
}
545+
546+
__bpf_kfunc struct bpf_ecdsa_ctx *
547+
bpf_ecdsa_ctx_acquire(struct bpf_ecdsa_ctx *ctx)
548+
{
549+
if (!refcount_inc_not_zero(&ctx->usage))
550+
return NULL;
551+
return ctx;
552+
}
553+
554+
static void ecdsa_free_cb(struct rcu_head *head)
555+
{
556+
struct bpf_ecdsa_ctx *ctx = container_of(head, struct bpf_ecdsa_ctx, rcu);
557+
558+
crypto_free_sig(ctx->tfm);
559+
kfree(ctx);
560+
}
561+
562+
__bpf_kfunc void bpf_ecdsa_ctx_release(struct bpf_ecdsa_ctx *ctx)
563+
{
564+
if (refcount_dec_and_test(&ctx->usage))
565+
call_rcu(&ctx->rcu, ecdsa_free_cb);
566+
}
567+
568+
/**
569+
* bpf_ecdsa_keysize() - Get the key size for ECDSA context
570+
* @ctx: ECDSA context
571+
*
572+
* Returns: Key size in bits, or negative error code on failure
573+
*/
574+
__bpf_kfunc int bpf_ecdsa_keysize(struct bpf_ecdsa_ctx *ctx)
575+
{
576+
if (!ctx)
577+
return -EINVAL;
578+
579+
return crypto_sig_keysize(ctx->tfm);
580+
}
581+
582+
/**
583+
* bpf_ecdsa_digestsize() - Get the maximum digest size for ECDSA context
584+
* @ctx: ECDSA context
585+
*/
586+
__bpf_kfunc int bpf_ecdsa_digestsize(struct bpf_ecdsa_ctx *ctx)
587+
{
588+
if (!ctx)
589+
return -EINVAL;
590+
591+
return crypto_sig_digestsize(ctx->tfm);
592+
}
593+
594+
/**
595+
* bpf_ecdsa_maxsize() - Get the maximum signature size for ECDSA context
596+
* @ctx: ECDSA context
597+
*/
598+
__bpf_kfunc int bpf_ecdsa_maxsize(struct bpf_ecdsa_ctx *ctx)
599+
{
600+
if (!ctx)
601+
return -EINVAL;
602+
603+
return crypto_sig_maxsize(ctx->tfm);
604+
}
605+
#endif /* CONFIG_CRYPTO_ECDSA */
606+
402607
__bpf_kfunc_end_defs();
403608

404609
BTF_KFUNCS_START(crypt_init_kfunc_btf_ids)
405610
BTF_ID_FLAGS(func, bpf_crypto_ctx_create, KF_ACQUIRE | KF_RET_NULL | KF_SLEEPABLE)
406611
BTF_ID_FLAGS(func, bpf_crypto_ctx_release, KF_RELEASE)
407612
BTF_ID_FLAGS(func, bpf_crypto_ctx_acquire, KF_ACQUIRE | KF_RCU | KF_RET_NULL)
613+
#if IS_ENABLED(CONFIG_CRYPTO_ECDSA)
614+
BTF_ID_FLAGS(func, bpf_ecdsa_ctx_create, KF_ACQUIRE | KF_RET_NULL | KF_SLEEPABLE)
615+
BTF_ID_FLAGS(func, bpf_ecdsa_ctx_release, KF_RELEASE)
616+
BTF_ID_FLAGS(func, bpf_ecdsa_ctx_acquire, KF_ACQUIRE | KF_RCU | KF_RET_NULL)
617+
#endif
408618
BTF_KFUNCS_END(crypt_init_kfunc_btf_ids)
409619

410620
static const struct btf_kfunc_id_set crypt_init_kfunc_set = {
@@ -418,6 +628,12 @@ BTF_ID_FLAGS(func, bpf_crypto_encrypt, KF_RCU)
418628
#if IS_ENABLED(CONFIG_CRYPTO_HASH2)
419629
BTF_ID_FLAGS(func, bpf_crypto_hash, KF_RCU)
420630
#endif
631+
#if IS_ENABLED(CONFIG_CRYPTO_ECDSA)
632+
BTF_ID_FLAGS(func, bpf_ecdsa_verify, 0)
633+
BTF_ID_FLAGS(func, bpf_ecdsa_keysize, 0)
634+
BTF_ID_FLAGS(func, bpf_ecdsa_digestsize, 0)
635+
BTF_ID_FLAGS(func, bpf_ecdsa_maxsize, 0)
636+
#endif
421637
BTF_KFUNCS_END(crypt_kfunc_btf_ids)
422638

423639
static const struct btf_kfunc_id_set crypt_kfunc_set = {
@@ -428,6 +644,10 @@ static const struct btf_kfunc_id_set crypt_kfunc_set = {
428644
BTF_ID_LIST(bpf_crypto_dtor_ids)
429645
BTF_ID(struct, bpf_crypto_ctx)
430646
BTF_ID(func, bpf_crypto_ctx_release)
647+
#if IS_ENABLED(CONFIG_CRYPTO_ECDSA)
648+
BTF_ID(struct, bpf_ecdsa_ctx)
649+
BTF_ID(func, bpf_ecdsa_ctx_release)
650+
#endif
431651

432652
static int __init crypto_kfunc_init(void)
433653
{
@@ -437,6 +657,12 @@ static int __init crypto_kfunc_init(void)
437657
.btf_id = bpf_crypto_dtor_ids[0],
438658
.kfunc_btf_id = bpf_crypto_dtor_ids[1]
439659
},
660+
#if IS_ENABLED(CONFIG_CRYPTO_ECDSA)
661+
{
662+
.btf_id = bpf_crypto_dtor_ids[2],
663+
.kfunc_btf_id = bpf_crypto_dtor_ids[3]
664+
},
665+
#endif
440666
};
441667

442668
ret = register_btf_kfunc_id_set(BPF_PROG_TYPE_SCHED_CLS, &crypt_kfunc_set);
@@ -445,6 +671,10 @@ static int __init crypto_kfunc_init(void)
445671
ret = ret ?: register_btf_kfunc_id_set(BPF_PROG_TYPE_SYSCALL, &crypt_kfunc_set);
446672
ret = ret ?: register_btf_kfunc_id_set(BPF_PROG_TYPE_SYSCALL,
447673
&crypt_init_kfunc_set);
674+
ret = ret ?: register_btf_kfunc_id_set(BPF_PROG_TYPE_SCHED_CLS,
675+
&crypt_init_kfunc_set);
676+
ret = ret ?: register_btf_kfunc_id_set(BPF_PROG_TYPE_XDP,
677+
&crypt_init_kfunc_set);
448678
return ret ?: register_btf_id_dtor_kfuncs(bpf_crypto_dtors,
449679
ARRAY_SIZE(bpf_crypto_dtors),
450680
THIS_MODULE);

0 commit comments

Comments
 (0)