Add three new kfuncs for computing cryptographic hashes in BPF programs: - bpf_sha256_hash(): Computes SHA-256 hash (32-byte output) - bpf_sha384_hash(): Computes SHA-384 hash (48-byte output) - bpf_sha512_hash(): Computes SHA-512 hash (64-byte output) These kfuncs leverage the kernel's existing crypto library (sha256/sha384/ sha512 functions) and use bpf_dynptr for safe memory access without risk of page faults. The functions validate input parameters including checking for read-only output buffers and ensuring sufficient buffer sizes. 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 --- kernel/bpf/crypto.c | 125 +++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 124 insertions(+), 1 deletion(-) diff --git a/kernel/bpf/crypto.c b/kernel/bpf/crypto.c index 83c4d9943084..485972b0f858 100644 --- a/kernel/bpf/crypto.c +++ b/kernel/bpf/crypto.c @@ -8,7 +8,8 @@ #include #include #include -#include +#include +#include struct bpf_crypto_type_list { const struct bpf_crypto_type *type; @@ -343,6 +344,122 @@ __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_LIB_SHA256) +/** + * bpf_sha256_hash() - Compute SHA-256 hash using kernel crypto library + * @data: bpf_dynptr to the input data to hash. Must be a trusted pointer. + * @out: bpf_dynptr to the output buffer (must be at least 32 bytes). Must be a trusted pointer. + * + * Computes SHA-256 hash of the input data. Uses bpf_dynptr to ensure safe memory access + * without risk of page faults. + */ +__bpf_kfunc int bpf_sha256_hash(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; + u32 data_len, out_len; + const u8 *data_ptr; + u8 *out_ptr; + + if (__bpf_dynptr_is_rdonly(out_kern)) + return -EINVAL; + + data_len = __bpf_dynptr_size(data_kern); + out_len = __bpf_dynptr_size(out_kern); + + if (data_len == 0 || out_len < 32) + 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; + + sha256(data_ptr, data_len, out_ptr); + + return 0; +} + +/** + * bpf_sha384_hash() - Compute SHA-384 hash using kernel crypto library + * @data: bpf_dynptr to the input data to hash. Must be a trusted pointer. + * @out: bpf_dynptr to the output buffer (must be at least 48 bytes). Must be a trusted pointer. + * + * Computes SHA-384 hash of the input data. Uses bpf_dynptr to ensure safe memory access + * without risk of page faults. + */ +__bpf_kfunc int bpf_sha384_hash(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; + u32 data_len, out_len; + const u8 *data_ptr; + u8 *out_ptr; + + if (__bpf_dynptr_is_rdonly(out_kern)) + return -EINVAL; + + data_len = __bpf_dynptr_size(data_kern); + out_len = __bpf_dynptr_size(out_kern); + + if (data_len == 0 || out_len < 48) + 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; + + sha384(data_ptr, data_len, out_ptr); + + return 0; +} + +/** + * bpf_sha512_hash() - Compute SHA-512 hash using kernel crypto library + * @data: bpf_dynptr to the input data to hash. Must be a trusted pointer. + * @out: bpf_dynptr to the output buffer (must be at least 64 bytes). Must be a trusted pointer. + * + * Computes SHA-512 hash of the input data. Uses bpf_dynptr to ensure safe memory access + * without risk of page faults. + */ +__bpf_kfunc int bpf_sha512_hash(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; + u32 data_len, out_len; + const u8 *data_ptr; + u8 *out_ptr; + + if (__bpf_dynptr_is_rdonly(out_kern)) + return -EINVAL; + + data_len = __bpf_dynptr_size(data_kern); + out_len = __bpf_dynptr_size(out_kern); + + if (data_len == 0 || out_len < 64) + 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; + + sha512(data_ptr, data_len, out_ptr); + + return 0; +} +#endif /* CONFIG_CRYPTO_LIB_SHA256 */ + __bpf_kfunc_end_defs(); BTF_KFUNCS_START(crypt_init_kfunc_btf_ids) @@ -359,6 +476,11 @@ 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_LIB_SHA256) +BTF_ID_FLAGS(func, bpf_sha256_hash, 0) +BTF_ID_FLAGS(func, bpf_sha384_hash, 0) +BTF_ID_FLAGS(func, bpf_sha512_hash, 0) +#endif BTF_KFUNCS_END(crypt_kfunc_btf_ids) static const struct btf_kfunc_id_set crypt_kfunc_set = { @@ -383,6 +505,7 @@ 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); + 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 Add selftests to validate the SHA-256, SHA-384, and SHA-512 hash kfuncs introduced in the BPF crypto subsystem. 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 --- .../selftests/bpf/prog_tests/crypto_hash.c | 129 ++++++++++++++++++ .../testing/selftests/bpf/progs/crypto_hash.c | 83 +++++++++++ 2 files changed, 212 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/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..4600dad693d4 --- /dev/null +++ b/tools/testing/selftests/bpf/prog_tests/crypto_hash.c @@ -0,0 +1,129 @@ +// SPDX-License-Identifier: GPL-2.0 + +#include +#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 void test_sha256_basic(void) +{ + struct crypto_hash *skel; + int err, prog_fd; + + LIBBPF_OPTS(bpf_test_run_opts, topts); + + skel = crypto_hash__open_and_load(); + if (!ASSERT_OK_PTR(skel, "crypto_hash__open_and_load")) + 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 = crypto_hash__open_and_load(); + if (!ASSERT_OK_PTR(skel, "crypto_hash__open_and_load")) + return; + + /* Run SHA-384 test */ + 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 = crypto_hash__open_and_load(); + if (!ASSERT_OK_PTR(skel, "crypto_hash__open_and_load")) + 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 = crypto_hash__open_and_load(); + if (!ASSERT_OK_PTR(skel, "crypto_hash__open_and_load")) + 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_hash.c b/tools/testing/selftests/bpf/progs/crypto_hash.c new file mode 100644 index 000000000000..d01f23557411 --- /dev/null +++ b/tools/testing/selftests/bpf/progs/crypto_hash.c @@ -0,0 +1,83 @@ +// SPDX-License-Identifier: GPL-2.0 + +#include "vmlinux.h" +#include +#include "bpf_misc.h" +#include "bpf_kfuncs.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; + +/* Declare the SHA hash kfuncs */ +extern int bpf_sha256_hash(const struct bpf_dynptr *data, const struct bpf_dynptr *out) __ksym; +extern int bpf_sha384_hash(const struct bpf_dynptr *data, const struct bpf_dynptr *out) __ksym; +extern int bpf_sha512_hash(const struct bpf_dynptr *data, const struct bpf_dynptr *out) __ksym; + +SEC("syscall") +int test_sha256(void *ctx) +{ + struct bpf_dynptr input_ptr, output_ptr; + + 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_sha256_hash(&input_ptr, &output_ptr); + return 0; +} + +SEC("syscall") +int test_sha384(void *ctx) +{ + struct bpf_dynptr input_ptr, output_ptr; + + 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_sha384_hash(&input_ptr, &output_ptr); + return 0; +} + +SEC("syscall") +int test_sha512(void *ctx) +{ + struct bpf_dynptr input_ptr, output_ptr; + + 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_sha512_hash(&input_ptr, &output_ptr); + return 0; +} + +SEC("syscall") +int test_sha256_zero_len(void *ctx) +{ + struct bpf_dynptr input_ptr, output_ptr; + int ret; + + bpf_dynptr_from_mem(test_input, 0, 0, &input_ptr); + bpf_dynptr_from_mem(sha256_output, sizeof(sha256_output), 0, &output_ptr); + + ret = bpf_sha256_hash(&input_ptr, &output_ptr); + sha256_status = (ret == -22) ? 0 : ret; + return 0; +} + +char __license[] SEC("license") = "GPL"; -- 2.51.0 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 --- kernel/bpf/crypto.c | 358 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 358 insertions(+) diff --git a/kernel/bpf/crypto.c b/kernel/bpf/crypto.c index 485972b0f858..e9a282ade788 100644 --- a/kernel/bpf/crypto.c +++ b/kernel/bpf/crypto.c @@ -8,6 +8,7 @@ #include #include #include +#include #include #include @@ -58,6 +59,21 @@ struct bpf_crypto_ctx { refcount_t usage; }; +#if IS_ENABLED(CONFIG_CRYPTO_ECDSA) +/** + * struct bpf_ecdsa_ctx - refcounted BPF ECDSA context structure + * @tfm: The crypto_sig transform for ECDSA operations + * @rcu: The RCU head used to free the context with RCU safety + * @usage: Object reference counter. When the refcount goes to 0, the + * memory is released with RCU safety. + */ +struct bpf_ecdsa_ctx { + struct crypto_sig *tfm; + struct rcu_head rcu; + refcount_t usage; +}; +#endif + int bpf_crypto_register_type(const struct bpf_crypto_type *type) { struct bpf_crypto_type_list *node; @@ -460,12 +476,332 @@ __bpf_kfunc int bpf_sha512_hash(const struct bpf_dynptr *data, const struct bpf_ } #endif /* CONFIG_CRYPTO_LIB_SHA256 */ +#if IS_ENABLED(CONFIG_CRYPTO_ECDSA) +/** + * bpf_ecdsa_ctx_create() - Create a BPF ECDSA verification context + * @algo_name: bpf_dynptr to the algorithm name (e.g., "p1363(ecdsa-nist-p256)") + * @public_key: bpf_dynptr to the public key in uncompressed format (0x04 || x || y) + * Must be 65 bytes for P-256, 97 for P-384, 133 for P-521 + * @err: Pointer to store error code on failure + * + * Creates an ECDSA verification context that can be reused for multiple + * signature verifications. This function uses GFP_KERNEL allocation and + * can only be called from sleepable BPF programs. Uses bpf_dynptr to ensure + * safe memory access without risk of page faults. + */ +__bpf_kfunc struct bpf_ecdsa_ctx * +bpf_ecdsa_ctx_create(const struct bpf_dynptr *algo_name, + const struct bpf_dynptr *public_key, int *err) +{ + const struct bpf_dynptr_kern *algo_kern = (struct bpf_dynptr_kern *)algo_name; + const struct bpf_dynptr_kern *key_kern = (struct bpf_dynptr_kern *)public_key; + struct bpf_ecdsa_ctx *ctx; + const char *algo_ptr; + const u8 *key_ptr; + u32 algo_len, key_len; + char algo[64]; + int ret; + + if (!err) + return NULL; + + algo_len = __bpf_dynptr_size(algo_kern); + key_len = __bpf_dynptr_size(key_kern); + + if (algo_len == 0 || algo_len >= sizeof(algo)) { + *err = -EINVAL; + return NULL; + } + + if (key_len < 65) { + *err = -EINVAL; + return NULL; + } + + algo_ptr = __bpf_dynptr_data(algo_kern, algo_len); + if (!algo_ptr) { + *err = -EINVAL; + return NULL; + } + + key_ptr = __bpf_dynptr_data(key_kern, key_len); + if (!key_ptr) { + *err = -EINVAL; + return NULL; + } + + if (key_ptr[0] != 0x04) { + *err = -EINVAL; + return NULL; + } + + memcpy(algo, algo_ptr, algo_len); + algo[algo_len] = '\0'; + + ctx = kzalloc(sizeof(*ctx), GFP_KERNEL); + if (!ctx) { + *err = -ENOMEM; + return NULL; + } + + ctx->tfm = crypto_alloc_sig(algo, 0, 0); + if (IS_ERR(ctx->tfm)) { + *err = PTR_ERR(ctx->tfm); + kfree(ctx); + return NULL; + } + + ret = crypto_sig_set_pubkey(ctx->tfm, key_ptr, key_len); + if (ret) { + *err = ret; + crypto_free_sig(ctx->tfm); + kfree(ctx); + return NULL; + } + + refcount_set(&ctx->usage, 1); + *err = 0; + return ctx; +} + +/** + * bpf_ecdsa_verify() - Verify ECDSA signature using pre-allocated context + * @ctx: ECDSA context created by bpf_ecdsa_ctx_create() + * @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_ecdsa_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; + const u8 *msg_ptr, *sig_ptr; + u32 msg_len, sig_len; + + if (!ctx) + 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; + + return crypto_sig_verify(ctx->tfm, sig_ptr, sig_len, msg_ptr, msg_len); +} + +__bpf_kfunc struct bpf_ecdsa_ctx * +bpf_ecdsa_ctx_acquire(struct bpf_ecdsa_ctx *ctx) +{ + if (!refcount_inc_not_zero(&ctx->usage)) + return NULL; + return ctx; +} + +static void ecdsa_free_cb(struct rcu_head *head) +{ + struct bpf_ecdsa_ctx *ctx = container_of(head, struct bpf_ecdsa_ctx, rcu); + + crypto_free_sig(ctx->tfm); + kfree(ctx); +} + +__bpf_kfunc void bpf_ecdsa_ctx_release(struct bpf_ecdsa_ctx *ctx) +{ + if (refcount_dec_and_test(&ctx->usage)) + call_rcu(&ctx->rcu, ecdsa_free_cb); +} + +/** + * bpf_ecdsa_ctx_create_with_privkey() - Create a BPF ECDSA signing context + * @algo_name: bpf_dynptr to the algorithm name (e.g., "p1363(ecdsa-nist-p256)") + * @private_key: bpf_dynptr to the private key in raw format + * @err: Pointer to store error code on failure + * + * Creates an ECDSA signing context that can be used for signing messages. + * This function uses GFP_KERNEL allocation and can only be called from + * sleepable BPF programs. Uses bpf_dynptr to ensure safe memory access + * without risk of page faults. + */ +__bpf_kfunc struct bpf_ecdsa_ctx * +bpf_ecdsa_ctx_create_with_privkey(const struct bpf_dynptr *algo_name, + const struct bpf_dynptr *private_key, int *err) +{ + const struct bpf_dynptr_kern *algo_kern = (struct bpf_dynptr_kern *)algo_name; + const struct bpf_dynptr_kern *key_kern = (struct bpf_dynptr_kern *)private_key; + struct bpf_ecdsa_ctx *ctx; + const char *algo_ptr; + const u8 *key_ptr; + u32 algo_len, key_len; + char algo[64]; + int ret; + + if (!err) + return NULL; + + algo_len = __bpf_dynptr_size(algo_kern); + key_len = __bpf_dynptr_size(key_kern); + + if (algo_len == 0 || algo_len >= sizeof(algo)) { + *err = -EINVAL; + return NULL; + } + + if (key_len < 32) { + *err = -EINVAL; + return NULL; + } + + algo_ptr = __bpf_dynptr_data(algo_kern, algo_len); + if (!algo_ptr) { + *err = -EINVAL; + return NULL; + } + + key_ptr = __bpf_dynptr_data(key_kern, key_len); + if (!key_ptr) { + *err = -EINVAL; + return NULL; + } + + memcpy(algo, algo_ptr, algo_len); + algo[algo_len] = '\0'; + + ctx = kzalloc(sizeof(*ctx), GFP_KERNEL); + if (!ctx) { + *err = -ENOMEM; + return NULL; + } + + ctx->tfm = crypto_alloc_sig(algo, 0, 0); + if (IS_ERR(ctx->tfm)) { + *err = PTR_ERR(ctx->tfm); + kfree(ctx); + return NULL; + } + + ret = crypto_sig_set_privkey(ctx->tfm, key_ptr, key_len); + if (ret) { + *err = ret; + crypto_free_sig(ctx->tfm); + kfree(ctx); + return NULL; + } + + refcount_set(&ctx->usage, 1); + *err = 0; + return ctx; +} + +/** + * bpf_ecdsa_sign() - Sign a message using ECDSA + * @ctx: ECDSA context created with bpf_ecdsa_ctx_create_with_privkey() + * @message: bpf_dynptr to the message hash to sign. Must be a trusted pointer. + * @signature: bpf_dynptr to the output buffer for signature. Must be a trusted pointer. + * Must be at least 64 bytes for P-256, 96 for P-384, 132 for P-521 + * + * Signs a message hash using ECDSA with a pre-configured private key. + * The signature is returned in r || s format. Uses bpf_dynptr to ensure + * safe memory access without risk of page faults. + */ +__bpf_kfunc int bpf_ecdsa_sign(struct bpf_ecdsa_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; + const u8 *msg_ptr; + u8 *sig_ptr; + u32 msg_len, sig_len; + + if (!ctx) + return -EINVAL; + + if (__bpf_dynptr_is_rdonly(sig_kern)) + 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_rw(sig_kern, sig_len); + if (!sig_ptr) + return -EINVAL; + + return crypto_sig_sign(ctx->tfm, msg_ptr, msg_len, sig_ptr, sig_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_ecdsa_ctx *ctx) +{ + if (!ctx) + return -EINVAL; + + return crypto_sig_keysize(ctx->tfm); +} + +/** + * bpf_ecdsa_digestsize() - Get the maximum digest size for ECDSA context + * @ctx: ECDSA context + */ +__bpf_kfunc int bpf_ecdsa_digestsize(struct bpf_ecdsa_ctx *ctx) +{ + if (!ctx) + return -EINVAL; + + return crypto_sig_digestsize(ctx->tfm); +} + +/** + * bpf_ecdsa_maxsize() - Get the maximum signature size for ECDSA context + * @ctx: ECDSA context + */ +__bpf_kfunc int bpf_ecdsa_maxsize(struct bpf_ecdsa_ctx *ctx) +{ + if (!ctx) + return -EINVAL; + + return crypto_sig_maxsize(ctx->tfm); +} +#endif /* CONFIG_CRYPTO_ECDSA */ + __bpf_kfunc_end_defs(); BTF_KFUNCS_START(crypt_init_kfunc_btf_ids) BTF_ID_FLAGS(func, bpf_crypto_ctx_create, KF_ACQUIRE | KF_RET_NULL | KF_SLEEPABLE) BTF_ID_FLAGS(func, bpf_crypto_ctx_release, KF_RELEASE) BTF_ID_FLAGS(func, bpf_crypto_ctx_acquire, KF_ACQUIRE | KF_RCU | KF_RET_NULL) +#if IS_ENABLED(CONFIG_CRYPTO_ECDSA) +BTF_ID_FLAGS(func, bpf_ecdsa_ctx_create, KF_ACQUIRE | KF_RET_NULL | KF_SLEEPABLE) +BTF_ID_FLAGS(func, bpf_ecdsa_ctx_create_with_privkey, KF_ACQUIRE | KF_RET_NULL | KF_SLEEPABLE) +BTF_ID_FLAGS(func, bpf_ecdsa_ctx_release, KF_RELEASE) +BTF_ID_FLAGS(func, bpf_ecdsa_ctx_acquire, KF_ACQUIRE | KF_RCU | KF_RET_NULL) +#endif BTF_KFUNCS_END(crypt_init_kfunc_btf_ids) static const struct btf_kfunc_id_set crypt_init_kfunc_set = { @@ -481,6 +817,13 @@ BTF_ID_FLAGS(func, bpf_sha256_hash, 0) BTF_ID_FLAGS(func, bpf_sha384_hash, 0) BTF_ID_FLAGS(func, bpf_sha512_hash, 0) #endif +#if IS_ENABLED(CONFIG_CRYPTO_ECDSA) +BTF_ID_FLAGS(func, bpf_ecdsa_verify, 0) +BTF_ID_FLAGS(func, bpf_ecdsa_sign, 0) +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 = { @@ -491,6 +834,10 @@ static const struct btf_kfunc_id_set crypt_kfunc_set = { BTF_ID_LIST(bpf_crypto_dtor_ids) BTF_ID(struct, bpf_crypto_ctx) BTF_ID(func, bpf_crypto_ctx_release) +#if IS_ENABLED(CONFIG_CRYPTO_ECDSA) +BTF_ID(struct, bpf_ecdsa_ctx) +BTF_ID(func, bpf_ecdsa_ctx_release) +#endif static int __init crypto_kfunc_init(void) { @@ -500,6 +847,12 @@ static int __init crypto_kfunc_init(void) .btf_id = bpf_crypto_dtor_ids[0], .kfunc_btf_id = bpf_crypto_dtor_ids[1] }, +#if IS_ENABLED(CONFIG_CRYPTO_ECDSA) + { + .btf_id = bpf_crypto_dtor_ids[2], + .kfunc_btf_id = bpf_crypto_dtor_ids[3] + }, +#endif }; ret = register_btf_kfunc_id_set(BPF_PROG_TYPE_SCHED_CLS, &crypt_kfunc_set); @@ -508,6 +861,11 @@ 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); + /* Enable kptr pattern for TC and XDP programs */ + 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 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 --- .../selftests/bpf/prog_tests/ecdsa_verify.c | 96 ++++++++ .../selftests/bpf/progs/ecdsa_verify.c | 228 ++++++++++++++++++ 2 files changed, 324 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/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..d1f83ce08ad6 --- /dev/null +++ b/tools/testing/selftests/bpf/prog_tests/ecdsa_verify.c @@ -0,0 +1,96 @@ +// SPDX-License-Identifier: GPL-2.0 + +#include +#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_sign_and_verify(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_sign_verify); + err = bpf_prog_test_run_opts(prog_fd, &topts); + ASSERT_OK(err, "test_ecdsa_sign_verify"); + ASSERT_GT(skel->data->sign_result, 0, "sign_returns_signature_size"); + ASSERT_EQ(skel->data->sign_verify_result, 0, "verify_generated_signature"); + + 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("sign_and_verify")) + test_ecdsa_sign_and_verify(); + 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..fb24baf6c437 --- /dev/null +++ b/tools/testing/selftests/bpf/progs/ecdsa_verify.c @@ -0,0 +1,228 @@ +// SPDX-License-Identifier: GPL-2.0 + +#include "vmlinux.h" +#include +#include "bpf_misc.h" + +struct bpf_ecdsa_ctx; +extern struct bpf_ecdsa_ctx * +bpf_ecdsa_ctx_create(const struct bpf_dynptr *algo_name, + const struct bpf_dynptr *public_key, int *err) __ksym; +extern struct bpf_ecdsa_ctx * +bpf_ecdsa_ctx_create_with_privkey(const struct bpf_dynptr *algo_name, + const struct bpf_dynptr *private_key, int *err) __ksym; +extern int bpf_ecdsa_verify(struct bpf_ecdsa_ctx *ctx, + const struct bpf_dynptr *message, + const struct bpf_dynptr *signature) __ksym; +extern int bpf_ecdsa_sign(struct bpf_ecdsa_ctx *ctx, + const struct bpf_dynptr *message, + const struct bpf_dynptr *signature) __ksym; +extern int bpf_ecdsa_keysize(struct bpf_ecdsa_ctx *ctx) __ksym; +extern int bpf_ecdsa_digestsize(struct bpf_ecdsa_ctx *ctx) __ksym; +extern int bpf_ecdsa_maxsize(struct bpf_ecdsa_ctx *ctx) __ksym; +extern void bpf_ecdsa_ctx_release(struct bpf_ecdsa_ctx *ctx) __ksym; + +/* NIST P-256 test vector + * This is a known valid ECDSA signature for testing purposes + */ + +/* Algorithm name for P-256 with p1363 format (standard r||s signature) */ +char algo_p256[] = "p1363(ecdsa-nist-p256)"; + +/* 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 +}; + +/* Private key for signing (32 bytes) - matches the public key above */ +unsigned char privkey_p256[32] = { + 0xc9, 0xaf, 0xa9, 0xd8, 0x45, 0xba, 0x75, 0x16, + 0x6b, 0x5c, 0x21, 0x57, 0x67, 0xb1, 0xd6, 0x93, + 0x4e, 0x50, 0xc3, 0xdb, 0x36, 0xe8, 0x9b, 0x12, + 0x7b, 0x8a, 0x62, 0x2b, 0x12, 0x0f, 0x67, 0x21 +}; + +/* Test results */ +int verify_result = -1; +int verify_invalid_result = -1; +int ctx_create_status = -1; +int sign_result = -1; +int sign_verify_result = -1; +int keysize_result = -1; +int digestsize_result = -1; +int maxsize_result = -1; +unsigned char generated_signature[64] = {0}; + +SEC("syscall") +int test_ecdsa_verify_valid(void *ctx) +{ + struct bpf_ecdsa_ctx *ecdsa_ctx; + struct bpf_dynptr algo_ptr, key_ptr, msg_ptr, sig_ptr; + int err = 0; + + bpf_dynptr_from_mem(algo_p256, sizeof(algo_p256) - 1, 0, &algo_ptr); + bpf_dynptr_from_mem(pubkey_p256, sizeof(pubkey_p256), 0, &key_ptr); + + ecdsa_ctx = bpf_ecdsa_ctx_create(&algo_ptr, &key_ptr, &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_ecdsa_ctx_release(ecdsa_ctx); + + return 0; +} + +SEC("syscall") +int test_ecdsa_verify_invalid(void *ctx) +{ + struct bpf_ecdsa_ctx *ecdsa_ctx; + struct bpf_dynptr algo_ptr, key_ptr, msg_ptr, sig_ptr; + int err = 0; + + bpf_dynptr_from_mem(algo_p256, sizeof(algo_p256) - 1, 0, &algo_ptr); + bpf_dynptr_from_mem(pubkey_p256, sizeof(pubkey_p256), 0, &key_ptr); + + ecdsa_ctx = bpf_ecdsa_ctx_create(&algo_ptr, &key_ptr, &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_ecdsa_ctx_release(ecdsa_ctx); + + return 0; +} + +SEC("syscall") +int test_ecdsa_sign_verify(void *ctx) +{ + struct bpf_ecdsa_ctx *sign_ctx, *verify_ctx; + struct bpf_dynptr algo_ptr, privkey_ptr, pubkey_ptr, msg_ptr, sig_ptr; + int err = 0; + + /* Create signing context with private key */ + bpf_dynptr_from_mem(algo_p256, sizeof(algo_p256) - 1, 0, &algo_ptr); + bpf_dynptr_from_mem(privkey_p256, sizeof(privkey_p256), 0, &privkey_ptr); + + sign_ctx = bpf_ecdsa_ctx_create_with_privkey(&algo_ptr, &privkey_ptr, &err); + if (!sign_ctx) { + sign_result = err; + return 0; + } + + /* Sign the message */ + bpf_dynptr_from_mem(message_hash, sizeof(message_hash), 0, &msg_ptr); + bpf_dynptr_from_mem(generated_signature, sizeof(generated_signature), 0, &sig_ptr); + + sign_result = bpf_ecdsa_sign(sign_ctx, &msg_ptr, &sig_ptr); + + bpf_ecdsa_ctx_release(sign_ctx); + + /* If signing succeeded, verify the generated signature */ + if (sign_result > 0 && sign_result <= (int)sizeof(generated_signature)) { + unsigned int sig_size; + + /* Explicitly bound the value for the verifier */ + sig_size = sign_result & 0x3F; /* Max 64 bytes */ + + bpf_dynptr_from_mem(algo_p256, sizeof(algo_p256) - 1, 0, &algo_ptr); + bpf_dynptr_from_mem(pubkey_p256, sizeof(pubkey_p256), 0, &pubkey_ptr); + + verify_ctx = bpf_ecdsa_ctx_create(&algo_ptr, &pubkey_ptr, &err); + if (!verify_ctx) { + sign_verify_result = err; + return 0; + } + + bpf_dynptr_from_mem(message_hash, sizeof(message_hash), 0, &msg_ptr); + bpf_dynptr_from_mem(generated_signature, sig_size, 0, &sig_ptr); + + sign_verify_result = bpf_ecdsa_verify(verify_ctx, &msg_ptr, &sig_ptr); + + bpf_ecdsa_ctx_release(verify_ctx); + } + + return 0; +} + +SEC("syscall") +int test_ecdsa_size_queries(void *ctx) +{ + struct bpf_ecdsa_ctx *ecdsa_ctx; + struct bpf_dynptr algo_ptr, key_ptr; + int err = 0; + + bpf_dynptr_from_mem(algo_p256, sizeof(algo_p256) - 1, 0, &algo_ptr); + bpf_dynptr_from_mem(pubkey_p256, sizeof(pubkey_p256), 0, &key_ptr); + + ecdsa_ctx = bpf_ecdsa_ctx_create(&algo_ptr, &key_ptr, &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_ecdsa_ctx_release(ecdsa_ctx); + + return 0; +} + +char __license[] SEC("license") = "GPL"; -- 2.51.0