From f8b76e06f102a0ab21267a726922505b125e28c4 Mon Sep 17 00:00:00 2001 From: Holger Dengler Date: Mon, 9 Mar 2026 12:39:32 -0400 Subject: [PATCH 01/36] libzpc: Harmonize length types in ecc API In some of the ecc API functions, the buffer length parameters are of type `unsigned int`. All other API components use `size_t` for such length parameters. To harmonize with these other APIs, change all length parameter in ecc functions to type `size_t`. Signed-off-by: Holger Dengler --- include/zpc/ecc_key.h | 10 +++---- include/zpc/ecdsa_ctx.h | 8 +++--- src/ecc_key.c | 38 +++++++++++++------------- src/ecc_key_local.h | 6 ++--- src/ecdsa_ctx.c | 36 ++++++++++++------------- test/t_ecc_key.cc | 17 ++++++------ test/t_ecdsa_ctx.cc | 60 +++++++++++++++++++++-------------------- 7 files changed, 89 insertions(+), 86 deletions(-) diff --git a/include/zpc/ecc_key.h b/include/zpc/ecc_key.h index ec0e529..301ff72 100644 --- a/include/zpc/ecc_key.h +++ b/include/zpc/ecc_key.h @@ -125,7 +125,7 @@ int zpc_ec_key_set_apqns(struct zpc_ec_key *key, const char *apqns[]); */ __attribute__((visibility("default"))) int zpc_ec_key_import(struct zpc_ec_key *key, const unsigned char *seckey, - unsigned int seckeylen); + size_t seckeylen); /** * Import an EC clear-key pair. At least one of the key parts must be non-NULL. @@ -150,8 +150,8 @@ int zpc_ec_key_import(struct zpc_ec_key *key, const unsigned char *seckey, */ __attribute__((visibility("default"))) int zpc_ec_key_import_clear(struct zpc_ec_key *key, - const unsigned char *pubkey, unsigned int publen, - const unsigned char *privkey, unsigned int privlen); + const unsigned char *pubkey, size_t publen, + const unsigned char *privkey, size_t privlen); /** * Export an EC secure-key. Depending on the key type (CCA or EP11), the secure @@ -166,7 +166,7 @@ int zpc_ec_key_import_clear(struct zpc_ec_key *key, */ __attribute__((visibility("default"))) int zpc_ec_key_export(struct zpc_ec_key *key, unsigned char *seckey, - unsigned int *seckeylen); + size_t *seckeylen); /** * Export an EC public-key. @@ -180,7 +180,7 @@ int zpc_ec_key_export(struct zpc_ec_key *key, unsigned char *seckey, */ __attribute__((visibility("default"))) int zpc_ec_key_export_public(struct zpc_ec_key *key, unsigned char *pubkey, - unsigned int *pubkeylen); + size_t *pubkeylen); /** * Generate an EC secure-key. diff --git a/include/zpc/ecdsa_ctx.h b/include/zpc/ecdsa_ctx.h index 7607b46..e72d85c 100644 --- a/include/zpc/ecdsa_ctx.h +++ b/include/zpc/ecdsa_ctx.h @@ -58,8 +58,8 @@ int zpc_ecdsa_ctx_set_key(struct zpc_ecdsa_ctx *ctx, struct zpc_ec_key *key); */ __attribute__((visibility("default"))) int zpc_ecdsa_sign(struct zpc_ecdsa_ctx *ctx, - const unsigned char *hash, unsigned int hash_len, - unsigned char *signature, unsigned int *sig_len); + const unsigned char *hash, size_t hash_len, + unsigned char *signature, size_t *sig_len); /** * Do an ECDSA verify operation. @@ -72,8 +72,8 @@ int zpc_ecdsa_sign(struct zpc_ecdsa_ctx *ctx, */ __attribute__((visibility("default"))) int zpc_ecdsa_verify(struct zpc_ecdsa_ctx *ctx, - const unsigned char *hash, unsigned int hash_len, - const unsigned char *signature, unsigned int sig_len); + const unsigned char *hash, size_t hash_len, + const unsigned char *signature, size_t sig_len); /** * Free an ECDSA context. diff --git a/src/ecc_key.c b/src/ecc_key.c index 8cbe6f5..a6fad19 100644 --- a/src/ecc_key.c +++ b/src/ecc_key.c @@ -43,13 +43,13 @@ const u16 curve2pvsecret_type[] = { static void __ec_key_reset(struct zpc_ec_key *); static int ec_key_check_ep11_spki(const struct zpc_ec_key *ec_key, - const unsigned char *spki, unsigned int spki_len); + const unsigned char *spki, size_t spki_len); static void ec_key_use_maced_spki_from_buf(struct zpc_ec_key *ec_key, - const unsigned char *spki, unsigned int spki_len); + const unsigned char *spki, size_t spki_len); static int ec_key_use_raw_spki_from_buf(struct zpc_ec_key *ec_key, - const unsigned char *spki, unsigned int spki_len); + const unsigned char *spki, size_t spki_len); static int ec_key_spki_has_valid_mkvp(const struct zpc_ec_key *ec_key, - const unsigned char *spki, unsigned int spki_len); + const unsigned char *spki, size_t spki_len); static int ec_key_blob_has_valid_mkvp(struct zpc_ec_key *ec_key, const unsigned char *buf); static int ec_key_blob_is_pkey_extractable(struct zpc_ec_key *ec_key, @@ -492,7 +492,7 @@ int zpc_ec_key_set_apqns(struct zpc_ec_key *ec_key, const char *apqns[]) int zpc_ec_key_export(struct zpc_ec_key *ec_key, unsigned char *buf, - unsigned int *buflen) + size_t *buflen) { int rc, rv; @@ -558,7 +558,7 @@ zpc_ec_key_export(struct zpc_ec_key *ec_key, unsigned char *buf, } int zpc_ec_key_export_public(struct zpc_ec_key *ec_key, - unsigned char *buf, unsigned int *buflen) + unsigned char *buf, size_t *buflen) { int rc, rv; @@ -613,7 +613,7 @@ int zpc_ec_key_export_public(struct zpc_ec_key *ec_key, } int zpc_ec_key_import(struct zpc_ec_key *ec_key, const unsigned char *buf, - unsigned int buflen) + size_t buflen) { target_t target; int rc, rv, seclen; @@ -789,8 +789,8 @@ int zpc_ec_key_import(struct zpc_ec_key *ec_key, const unsigned char *buf, } int zpc_ec_key_import_clear(struct zpc_ec_key *ec_key, const unsigned char *pubkey, - unsigned int publen, const unsigned char *privkey, - unsigned int privlen) + size_t publen, const unsigned char *privkey, + size_t privlen) { unsigned int flags; int rc, rv; @@ -1057,7 +1057,7 @@ int zpc_ec_key_generate(struct zpc_ec_key *ec_key) int zpc_ec_key_reencipher(struct zpc_ec_key *ec_key, unsigned int method) { struct ec_key reenc; - unsigned int seckeylen; + size_t seckeylen; target_t target; int rv, rc = ZPC_ERROR_APQNSNOTSET; size_t i; @@ -1343,8 +1343,8 @@ int ec_key_pvsec2prot(struct zpc_ec_key *ec_key) } int ec_key_clr2sec(struct zpc_ec_key *ec_key, unsigned int flags, - const unsigned char *pubkey, unsigned int publen, - const unsigned char *privkey, unsigned int privlen) + const unsigned char *pubkey, size_t publen, + const unsigned char *privkey, size_t privlen) { target_t target; int rv, rc = ZPC_ERROR_APQNSNOTSET; @@ -1400,7 +1400,7 @@ int ec_key_sec2prot(struct zpc_ec_key *ec_key, enum ec_key_sec sec) { struct pkey_kblob2pkey3 io; struct ec_key *key = NULL; - unsigned int keybuf_len; + size_t keybuf_len; int rc, i; assert(sec == EC_KEY_SEC_OLD || sec == EC_KEY_SEC_CUR); @@ -1442,7 +1442,7 @@ int ec_key_sec2prot(struct zpc_ec_key *ec_key, enum ec_key_sec sec) } int ec_key_clr2prot(struct zpc_ec_key *ec_key, const unsigned char *privkey, - unsigned int privlen) + size_t privlen) { struct pkey_kblob2pkey3 io; unsigned char buf[sizeof(struct clearkeytoken) + 80]; @@ -1529,7 +1529,7 @@ int ec_key_spki_valid_for_pubkey(const struct zpc_ec_key *ec_key, } static int ec_key_check_ep11_spki(const struct zpc_ec_key *ec_key, - const unsigned char *spki, unsigned int spki_len) + const unsigned char *spki, size_t spki_len) { if (spki_len > curve2macedspkilen[ec_key->curve] && spki_len < curve2rawspkilen[ec_key->curve]) @@ -1550,7 +1550,7 @@ static int ec_key_check_ep11_spki(const struct zpc_ec_key *ec_key, } static void ec_key_use_maced_spki_from_buf(struct zpc_ec_key *ec_key, - const unsigned char *spki, unsigned int spki_len) + const unsigned char *spki, size_t spki_len) { memcpy(ec_key->pub.spki, spki, spki_len); ec_key->pub.spkilen = spki_len; @@ -1563,7 +1563,7 @@ static void ec_key_use_maced_spki_from_buf(struct zpc_ec_key *ec_key, } static int ec_key_use_raw_spki_from_buf(struct zpc_ec_key *ec_key, - const unsigned char *spki, unsigned int spki_len) + const unsigned char *spki, size_t spki_len) { target_t target; int rc = -EIO, rv; @@ -1600,7 +1600,7 @@ static int ec_key_use_raw_spki_from_buf(struct zpc_ec_key *ec_key, } static int ec_key_spki_has_valid_mkvp(const struct zpc_ec_key *ec_key, - const unsigned char *spki, unsigned int spki_len) + const unsigned char *spki, size_t spki_len) { (void)spki_len; /* suppress unused parm compiler warning */ @@ -1618,7 +1618,7 @@ static int ec_key_spki_has_valid_mkvp(const struct zpc_ec_key *ec_key, static int ec_key_blob_has_valid_mkvp(struct zpc_ec_key *ec_key, const unsigned char *buf) { const unsigned char *mkvp; - unsigned int mkvp_len; + size_t mkvp_len; if (ec_key->mkvp_set == 0) return 1; /* cannot judge */ diff --git a/src/ecc_key_local.h b/src/ecc_key_local.h index e5ca013..22a0369 100644 --- a/src/ecc_key_local.h +++ b/src/ecc_key_local.h @@ -59,10 +59,10 @@ struct zpc_ec_key { }; int ec_key_clr2sec(struct zpc_ec_key *ec_key, unsigned int flags, - const unsigned char *pubkey, unsigned int publen, - const unsigned char *privkey, unsigned int privlen); + const unsigned char *pubkey, size_t publen, + const unsigned char *privkey, size_t privlen); int ec_key_sec2prot(struct zpc_ec_key *, enum ec_key_sec sec); int ec_key_check(const struct zpc_ec_key *); int ec_key_clr2prot(struct zpc_ec_key *ec_key, const unsigned char *privkey, - unsigned int privlen); + size_t privlen); #endif diff --git a/src/ecdsa_ctx.c b/src/ecdsa_ctx.c index d5aa853..3bf9eb5 100644 --- a/src/ecdsa_ctx.c +++ b/src/ecdsa_ctx.c @@ -27,19 +27,19 @@ extern const size_t curve2siglen[]; static int __ec_sign(struct zpc_ecdsa_ctx *, const unsigned char *hash, - unsigned int hash_len, unsigned char *signature, unsigned int *sig_len); + size_t hash_len, unsigned char *signature, size_t *sig_len); static int __ec_verify(struct zpc_ecdsa_ctx *, const unsigned char *hash, - unsigned int hash_len, const unsigned char *signature, unsigned int sig_len); + size_t hash_len, const unsigned char *signature, size_t sig_len); static void __ec_ctx_reset(struct zpc_ecdsa_ctx *); static void __copy_hash_to_sign_param(struct zpc_ecdsa_ctx *ctx, - const unsigned char *hash, unsigned int hash_len); + const unsigned char *hash, size_t hash_len); static void __get_signature_from_sign_param(struct zpc_ecdsa_ctx *ctx, - unsigned char *signature, unsigned int sig_len); + unsigned char *signature, size_t sig_len); static void __copy_pubkey_to_verify_param(struct zpc_ecdsa_ctx *ctx); static void __copy_protkey_to_sign_param(struct zpc_ecdsa_ctx *ctx); static void __copy_args_to_verify_param(struct zpc_ecdsa_ctx *ctx, - const unsigned char *hash, unsigned int hash_len, - const unsigned char *signature, unsigned int sig_len); + const unsigned char *hash, size_t hash_len, + const unsigned char *signature, size_t sig_len); static void __cleanup_verify_param(struct zpc_ecdsa_ctx *ctx); static void __cleanup_sign_param(struct zpc_ecdsa_ctx *ctx); @@ -182,8 +182,8 @@ int zpc_ecdsa_ctx_set_key(struct zpc_ecdsa_ctx *ec_ctx, struct zpc_ec_key *ec_ke } int zpc_ecdsa_sign(struct zpc_ecdsa_ctx *ctx, - const unsigned char *hash, unsigned int hash_len, - unsigned char *signature, unsigned int *sig_len) + const unsigned char *hash, size_t hash_len, + unsigned char *signature, size_t *sig_len) { int rc, rv, i; @@ -274,8 +274,8 @@ int zpc_ecdsa_sign(struct zpc_ecdsa_ctx *ctx, } int zpc_ecdsa_verify(struct zpc_ecdsa_ctx *ctx, - const unsigned char *hash, unsigned int hash_len, - const unsigned char *signature, unsigned int sig_len) + const unsigned char *hash, size_t hash_len, + const unsigned char *signature, size_t sig_len) { int rc, rv; @@ -358,8 +358,8 @@ void zpc_ecdsa_ctx_free(struct zpc_ecdsa_ctx **ctx) } static int __ec_sign(struct zpc_ecdsa_ctx *ctx, - const unsigned char *hash, unsigned int hash_len, - unsigned char *signature, unsigned int *sig_len) + const unsigned char *hash, size_t hash_len, + unsigned char *signature, size_t *sig_len) { void *param; int rc, cc; @@ -391,8 +391,8 @@ static int __ec_sign(struct zpc_ecdsa_ctx *ctx, } static int __ec_verify(struct zpc_ecdsa_ctx *ctx, - const unsigned char *hash, unsigned int hash_len, - const unsigned char *signature, unsigned int sig_len) + const unsigned char *hash, size_t hash_len, + const unsigned char *signature, size_t sig_len) { void *param; int rc = ZPC_ERROR_EC_SIGNATURE_INVALID, cc; @@ -431,7 +431,7 @@ static void __ec_ctx_reset(struct zpc_ecdsa_ctx *ctx) } static void __copy_hash_to_sign_param(struct zpc_ecdsa_ctx *ctx, - const unsigned char *hash, unsigned int hash_len) + const unsigned char *hash, size_t hash_len) { switch (ctx->ec_key->curve) { case ZPC_EC_CURVE_P256: @@ -455,7 +455,7 @@ static void __copy_hash_to_sign_param(struct zpc_ecdsa_ctx *ctx, } static void __get_signature_from_sign_param(struct zpc_ecdsa_ctx *ctx, - unsigned char *signature, unsigned int sig_len) + unsigned char *signature, size_t sig_len) { switch (ctx->ec_key->curve) { case ZPC_EC_CURVE_P256: @@ -538,8 +538,8 @@ static void __copy_protkey_to_sign_param(struct zpc_ecdsa_ctx *ctx) } static void __copy_args_to_verify_param(struct zpc_ecdsa_ctx *ctx, - const unsigned char *hash, unsigned int hash_len, - const unsigned char *signature, unsigned int sig_len) + const unsigned char *hash, size_t hash_len, + const unsigned char *signature, size_t sig_len) { switch (ctx->ec_key->curve) { case ZPC_EC_CURVE_P256: diff --git a/test/t_ecc_key.cc b/test/t_ecc_key.cc index 7e2b567..a9f3baa 100644 --- a/test/t_ecc_key.cc +++ b/test/t_ecc_key.cc @@ -489,7 +489,7 @@ TEST(ec_key, export) { struct zpc_ec_key *ec_key, *ec_key2; u8 buf[2000], buf2[2000]; - unsigned int buflen, buflen2, flags; + size_t buflen, buflen2, flags; const char *apqns[257]; int rc, type; zpc_ec_curve_t curve; @@ -583,7 +583,8 @@ TEST(ec_key, export_public) { struct zpc_ec_key *ec_key; u8 buf[132]; - unsigned int buflen, flags; + unsigned int flags; + size_t buflen; const char *apqns[257]; int rc, type; zpc_ec_curve_t curve; @@ -656,8 +657,8 @@ TEST(ec_key, import) { struct zpc_ec_key *ec_key, *ec_key2; u8 buf[10000], buf2[10000]; - unsigned int buflen = sizeof(buf); - unsigned int buf2len = sizeof(buf2); + size_t buflen = sizeof(buf); + size_t buf2len = sizeof(buf2); unsigned int flags; const char *apqns[257]; const char *mkvp; @@ -757,10 +758,10 @@ TEST(ec_key, spki_test) struct zpc_ec_key *ec_key, *ec_key2; unsigned int pubkeylen, privkeylen, blob_len, pubkey_offset; u8 buf[3000] = {0}, buf2[3000] = {0}, buf3[132] = {0}, buf4[3000] = {0}; - unsigned int buflen = sizeof(buf); - unsigned int buf2len = sizeof(buf2); - unsigned int buf3len = sizeof(buf3); - unsigned int buf4len = sizeof(buf4); + size_t buflen = sizeof(buf); + size_t buf2len = sizeof(buf2); + size_t buf3len = sizeof(buf3); + size_t buf4len = sizeof(buf4); unsigned int flags; const char *apqns[257]; const char *mkvp; diff --git a/test/t_ecdsa_ctx.cc b/test/t_ecdsa_ctx.cc index e6110e1..cb2d7e6 100644 --- a/test/t_ecdsa_ctx.cc +++ b/test/t_ecdsa_ctx.cc @@ -105,7 +105,8 @@ TEST(ecdsa_ctx, set_key) { struct zpc_ec_key *ec_key; struct zpc_ecdsa_ctx *ec_ctx; - unsigned int pubkeylen, privkeylen, flags = 0; + size_t pubkeylen, privkeylen; + unsigned int flags = 0; const char *mkvp, *apqns[257]; int rc, type; zpc_ec_curve_t curve; @@ -183,7 +184,8 @@ TEST(ecdsa_ctx, sign) struct zpc_ecdsa_ctx *ec_ctx; const char *mkvp, *apqns[257]; u8 msg[1000], signature[200]; - unsigned int msg_len, sig_len, flags; + size_t msg_len, sig_len; + unsigned int flags; int rc, type; zpc_ec_curve_t curve; const unsigned int test_msglen_from_curve[] = { 32, 48, 64, 500, 1000 }; @@ -260,8 +262,8 @@ TEST(ecdsa_ctx, verify) const char *mkvp, *apqns[257]; u8 signature[200]; u8 buf[200]; - unsigned int signature_len, hash_len, sig_len, buflen; - unsigned int pubkeylen, flags; + size_t signature_len, hash_len, sig_len, buflen, pubkeylen; + unsigned int flags; int rc, type; zpc_ec_curve_t curve; @@ -397,7 +399,7 @@ TEST(ecdsa_ctx, sv) struct zpc_ec_key *ec_key1, *ec_key2; struct zpc_ecdsa_ctx *ec_ctx1, *ec_ctx2; u8 sigbuf[200]; - unsigned int hash_len, sig_len, pubkeylen, privkeylen; + size_t hash_len, sig_len, pubkeylen, privkeylen; const char *mkvp, *apqns[257]; unsigned int flags; int rc, type; @@ -607,8 +609,8 @@ static zpc_ec_curve_t __str2curve(const char *str) } static void __get_ec_params_from_json(json_object *jtmp, zpc_ec_curve_t curve, - u8 *priv, unsigned int *privlen, u8 *pub, unsigned int *publen, - u8 *msg, unsigned int *msglen, u8 *sig, unsigned int *siglen) + u8 *priv, size_t *privlen, u8 *pub, size_t *publen, + u8 *msg, size_t *msglen, u8 *sig, size_t *siglen) { json_object *jd, *jx, *jy, *jmsg, *jsig_r, *jsig_s; json_bool b; @@ -683,8 +685,8 @@ static void __get_ec_params_from_json(json_object *jtmp, zpc_ec_curve_t curve, } static void __get_ed_params_from_json(json_object *jtmp, - u8 *priv, unsigned int *privlen, u8 *pub, unsigned int *publen, - u8 *msg, unsigned int *msglen, u8 *sig, unsigned int *siglen) + u8 *priv, size_t *privlen, u8 *pub, size_t *publen, + u8 *msg, size_t *msglen, u8 *sig, size_t *siglen) { json_object *jd, *jq, *jm, *js; json_bool b; @@ -763,8 +765,8 @@ static void __get_result_from_json(json_object *jresult, int *valid) * Get key material from json 'key' entry */ static void __get_key_from_json(json_object *jkey, zpc_ec_curve_t curve, - unsigned char *pubbuf, unsigned int *publen, - unsigned char *privbuf, unsigned int *privlen) + unsigned char *pubbuf, size_t *publen, + unsigned char *privbuf, size_t *privlen) { json_object *jwx, *jwy, *jsk, *jpk; json_bool b; @@ -827,7 +829,7 @@ static void __get_key_from_json(json_object *jkey, zpc_ec_curve_t curve, } static void __get_bytes_from_json(json_object *jobj, unsigned char *buf, - unsigned int *len) + size_t *len) { const char *str; u8 *bytes = NULL; @@ -849,9 +851,9 @@ static void __get_bytes_from_json(json_object *jobj, unsigned char *buf, } static void __run_sign_verify_test(zpc_ecdsa_ctx *ec_ctx, - unsigned char *msgbuf, unsigned int msglen, - unsigned char *sigbuf1, unsigned int *siglen1, - unsigned int privlen) + unsigned char *msgbuf, size_t msglen, + unsigned char *sigbuf1, size_t *siglen1, + size_t privlen) { int rc; @@ -865,8 +867,8 @@ static void __run_sign_verify_test(zpc_ecdsa_ctx *ec_ctx, } static void __run_verify_kat_test(zpc_ecdsa_ctx *ec_ctx, zpc_ec_curve_t curve, - unsigned char *msgbuf, unsigned int msglen, - unsigned char *sigbuf2, unsigned int siglen2, + unsigned char *msgbuf, size_t msglen, + unsigned char *sigbuf2, size_t siglen2, int expected_valid) { int rc; @@ -933,8 +935,8 @@ static void __run_nist_tests(json_object *jtestgroups, struct zpc_ec_key *ec_key u8 pubbuf[200] = { 0 }, privbuf[100] = { 0 }; u8 sigbuf1[200] = { 0 }, sigbuf2[200] = { 0 }, msgbuf[4096] = { 0 }; - unsigned int siglen1 = sizeof(sigbuf1), siglen2 = sizeof(sigbuf2); - unsigned int privlen, publen, msglen; + size_t siglen1 = sizeof(sigbuf1), siglen2 = sizeof(sigbuf2); + size_t privlen, publen, msglen; jtmp = json_object_array_get_idx(jtests, j); ASSERT_NE(jtmp, nullptr); @@ -1002,8 +1004,8 @@ static void __run_wycheproof_tests(json_object *jtestgroups, struct zpc_ec_key * u8 sigbuf1[200] = { 0 }, sigbuf2[200] = { 0 }, msgbuf[4096] = { 0 }; u8 pubbuf[200] = { 0 }, privbuf[100] = { 0 }; - unsigned int siglen1 = sizeof(sigbuf1), siglen2 = sizeof(sigbuf2); - unsigned int privlen, publen, msglen; + size_t siglen1 = sizeof(sigbuf1), siglen2 = sizeof(sigbuf2); + size_t privlen, publen, msglen; jtmp = json_object_array_get_idx(jtestgroups, i); ASSERT_NE(jtmp, nullptr); @@ -1115,7 +1117,7 @@ static void __run_json(const char *json) TEST(ecdsa_ctx, rederive_protected_key) { - unsigned int pubkeylen, privkeylen, msg_len, sig_len; + size_t pubkeylen, privkeylen, msg_len, sig_len; zpc_ec_curve_t curve; unsigned char buf[4096]; const char *mkvp, *apqns[257]; @@ -1206,7 +1208,7 @@ TEST(ecdsa_ctx, rederive_protected_key) TEST(ecdsa_ctx, reencipher) { - unsigned int pubkeylen, privkeylen, msg_len, sig_len; + size_t pubkeylen, privkeylen, msg_len, sig_len; unsigned char buf[4096]; const char *mkvp, *apqns[257]; struct zpc_ec_key *ec_key; @@ -1298,9 +1300,9 @@ TEST(ecdsa_ctx, reencipher) TEST(ecdsa_ctx, use_existing) { - unsigned int pubkeylen, privkeylen, msg_len, sig_len, signature_len; + size_t pubkeylen, privkeylen, msg_len, sig_len, signature_len; unsigned char buf[4096], signature[132]; - unsigned int buflen; + size_t buflen; const char *mkvp, *apqns[257]; struct zpc_ec_key *ec_key, *ec_key2; struct zpc_ecdsa_ctx *ec_ctx; @@ -1435,8 +1437,8 @@ TEST(ecdsa_ctx, use_existing) TEST(ecdsa_ctx, pvsecret_kat) { unsigned char sig1[132], sig2[132], pubkey[200], msg[32]; - unsigned int sig1_len = sizeof(sig1), sig2_len = sizeof(sig2); - unsigned int msg_len = sizeof(msg), publen = sizeof(pubkey); + size_t sig1_len = sizeof(sig1), sig2_len = sizeof(sig2); + size_t msg_len = sizeof(msg), publen = sizeof(pubkey); const char *mkvp, *apqns[257]; struct zpc_ec_key *ec_key1, *ec_key2; struct zpc_ecdsa_ctx *ec_ctx1, *ec_ctx2; @@ -1579,7 +1581,7 @@ static void __task(struct zpc_ec_key *ec_key) { struct zpc_ecdsa_ctx *ec_ctx; unsigned char sigbuf[200]; - unsigned int msglen, siglen; + size_t msglen, siglen; int rc, i; const u8 *msg = ec_tv[ec_key->curve].msg; @@ -1624,7 +1626,7 @@ static void __task(struct zpc_ec_key *ec_key) TEST(ecdsa_ctx, threads) { - unsigned int pubkeylen, privkeylen; + size_t pubkeylen, privkeylen; const char *mkvp, *apqns[257]; struct zpc_ec_key *ec_key; unsigned int flags; From d278e0c14694b72b2451215c1bd837dea6de7d7a Mon Sep 17 00:00:00 2001 From: Holger Dengler Date: Wed, 11 Mar 2026 12:30:28 +0100 Subject: [PATCH 02/36] cmake: Add cross-build architecture information The target architecture is different from the host architecture in cross-builds. Add the correct information to the s390x toolchain file. Signed-off-by: Holger Dengler --- s390x-tc-debian.cmake | 1 + 1 file changed, 1 insertion(+) diff --git a/s390x-tc-debian.cmake b/s390x-tc-debian.cmake index a4120c6..e5aabc6 100644 --- a/s390x-tc-debian.cmake +++ b/s390x-tc-debian.cmake @@ -1,4 +1,5 @@ set(CMAKE_SYSTEM_NAME Linux) +set(CMAKE_SYSTEM_PROCESSOR s390x) set(CMAKE_C_COMPILER s390x-linux-gnu-gcc) set(CMAKE_CXX_COMPILER s390x-linux-gnu-g++) From 7c9a4d8cc7497aac5294c311b0b9bab93872e1fd Mon Sep 17 00:00:00 2001 From: Holger Dengler Date: Wed, 1 Oct 2025 20:10:33 +0200 Subject: [PATCH 03/36] cmake: Add test header comment To follow the structure for other sections in the cmake definition, a comment header is added for the test section. Signed-off-by: Holger Dengler --- CMakeLists.txt | 3 +++ 1 file changed, 3 insertions(+) diff --git a/CMakeLists.txt b/CMakeLists.txt index 5223abb..f9ffb97 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -137,6 +137,9 @@ install( DESTINATION ${CMAKE_INSTALL_LIBDIR}/pkgconfig ) +########################################################### +# Test + option(BUILD_TEST OFF) if (BUILD_TEST) From 2ca0af9281e6ffd520809e5c9153f16e42b2d572 Mon Sep 17 00:00:00 2001 From: Holger Dengler Date: Fri, 10 Apr 2026 16:15:32 +0200 Subject: [PATCH 04/36] CONTRIBUTING: re-format Add line-breaks to the contribution rules to increase the readability without a markdown-reader. Signed-off-by: Holger Dengler --- CONTRIBUTING.md | 25 ++++++++++++++++++------- 1 file changed, 18 insertions(+), 7 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 662d462..097b967 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -1,7 +1,8 @@ Contributing {#contrib} === -You can contribute to `libzpc` by submitting issues (feature requests, bug reports) or pull requests (code contributions) to the GitHub repository. +You can contribute to `libzpc` by submitting issues (feature requests, bug +reports) or pull requests (code contributions) to the GitHub repository. Bug reports @@ -9,9 +10,11 @@ Bug reports When filing a bug report, please include all relevant information. -In all cases include the `libzpc` version, operating system and kernel version used. +In all cases include the `libzpc` version, operating system and kernel version +used. -Additionally, if it is a build error, include the toolchain version used. If it is a runtime error, include the crypto adapter config and processor model used. +Additionally, if it is a build error, include the toolchain version used. If it +is a runtime error, include the crypto adapter config and processor model used. Ideally, detailed steps on how to reproduce the issue would be included. @@ -19,12 +22,20 @@ Ideally, detailed steps on how to reproduce the issue would be included. Code contributions --- -All code contributions are reviewed by the `libzpc` maintainers who reverve the right to accept or reject a pull request. +All code contributions are reviewed by the `libzpc` maintainers who reverve the +right to accept or reject a pull request. -Please state clearly if your pull request changes the `libzpc` API or ABI, and if so, whether the changes are backward compatible. +Please state clearly if your pull request changes the `libzpc` API or ABI, and +if so, whether the changes are backward compatible. -If your pull request resolves an issue, please put a `"Fixes #"` line in the commit message. Ideally, the pull request would add a corresponding regression test. +If your pull request resolves an issue, please put a `"Fixes #"` +line in the commit message. Ideally, the pull request would add a corresponding +regression test. If your pull request adds a new feature, please add a corresponding unit test. -The code base is formatted using the `indent` tool with the options specified in the enclosed `.indent.pro` file. All code contributions must not violate this coding style. When formatting `libzpc` code, you can use `indent` with the prescribed options by copying the file to your home directory or by setting the `INDENT_PROFILE` environment variable's value to name the file. +The code base is formatted using the `indent` tool with the options specified in +the enclosed `.indent.pro` file. All code contributions must not violate this +coding style. When formatting `libzpc` code, you can use `indent` with the +prescribed options by copying the file to your home directory or by setting the +`INDENT_PROFILE` environment variable's value to name the file. From 911117c913ab559ea822f3abeab09a6047753ddb Mon Sep 17 00:00:00 2001 From: Holger Dengler Date: Wed, 1 Oct 2025 20:11:16 +0200 Subject: [PATCH 05/36] cmake: Add OpenSSL package The zpc functionality will be exposed via the OpenSSL API. Query the required OpenSSL package during build. Signed-off-by: Holger Dengler --- CMakeLists.txt | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/CMakeLists.txt b/CMakeLists.txt index f9ffb97..8e78d7c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -95,6 +95,11 @@ find_package(json-c REQUIRED ) +find_package(OpenSSL + 3.5.0 + REQUIRED +) + add_definitions( -D_GNU_SOURCE ) From f0d28952d1f23c926f9f31e67fd34f18d0aa70fa Mon Sep 17 00:00:00 2001 From: Holger Dengler Date: Wed, 1 Oct 2025 16:42:12 +0200 Subject: [PATCH 06/36] provider: Add base provider The provider is the base to plug-in further implementation like key-management, ciphers and so on. It has no functionality itself. Signed-off-by: Holger Dengler --- src/ossl.h | 22 ++++ src/provider.c | 351 +++++++++++++++++++++++++++++++++++++++++++++++++ src/provider.h | 62 +++++++++ 3 files changed, 435 insertions(+) create mode 100644 src/ossl.h create mode 100644 src/provider.c create mode 100644 src/provider.h diff --git a/src/ossl.h b/src/ossl.h new file mode 100644 index 0000000..c671af1 --- /dev/null +++ b/src/ossl.h @@ -0,0 +1,22 @@ +// SPDX-License-Identifier: MIT +// Copyright contributors to the libzpc project +#ifndef _OSSL_H +#define _OSSL_H + +#include + +#define OSSL_RV_TRUE (1) +#define OSSL_RV_FALSE (0) +#define OSSL_RV_OK (1) +#define OSSL_RV_ERR (0) + +#define ALGORITHM_DEFN(name, prop, fn, desc) { name, prop, fn, desc } +#define ALGORITHM_END { NULL, NULL, NULL, NULL } + +#define DISPATCH_DEFN(MODULE, NAME, name) { OSSL_FUNC_##MODULE##_##NAME, (void (*)(void))name } +#define DISPATCH_END { 0, NULL } + +#define DECL_DISPATCH_FUNC(MODULE, NAME, name) \ + static OSSL_FUNC_##MODULE##_##NAME##_fn name + +#endif /* _OSSL_H */ diff --git a/src/provider.c b/src/provider.c new file mode 100644 index 0000000..4558474 --- /dev/null +++ b/src/provider.c @@ -0,0 +1,351 @@ +// SPDX-License-Identifier: MIT +// Copyright contributors to the libzpc project +#include +#include +#include +#include +#include + +#include + +#include "ossl.h" +#include "provider.h" + +#define C(str) (void *)(str) +static const OSSL_ITEM reason_strings[] = { + { ZPC_ERROR_ARG1NULL, + C("argument 1 NULL") }, + { ZPC_ERROR_ARG2NULL, + C("argument 2 NULL") }, + { ZPC_ERROR_ARG3NULL, + C("argument 3 NULL") }, + { ZPC_ERROR_ARG4NULL, + C("argument 4 NULL") }, + { ZPC_ERROR_ARG5NULL, + C("argument 5 NULL") }, + { ZPC_ERROR_ARG6NULL, + C("argument 6 NULL") }, + { ZPC_ERROR_ARG7NULL, + C("argument 7 NULL") }, + { ZPC_ERROR_ARG8NULL, + C("argument 8 NULL") }, + { ZPC_ERROR_ARG1RANGE, + C("argument 1 out of range") }, + { ZPC_ERROR_ARG2RANGE, + C("argument 2 out of range") }, + { ZPC_ERROR_ARG3RANGE, + C("argument 3 out of range") }, + { ZPC_ERROR_ARG4RANGE, + C("argument 4 out of range") }, + { ZPC_ERROR_ARG5RANGE, + C("argument 5 out of range") }, + { ZPC_ERROR_ARG6RANGE, + C("argument 6 out of range") }, + { ZPC_ERROR_ARG7RANGE, + C("argument 7 out of range") }, + { ZPC_ERROR_ARG8RANGE, + C("argument 8 out of range") }, + { ZPC_ERROR_MALLOC, + C("malloc failed") }, + { ZPC_ERROR_KEYNOTSET, + C("no key is set") }, + { ZPC_ERROR_KEYSIZE, + C("invalid key size") }, + { ZPC_ERROR_IVNOTSET, + C("IV not set") }, + { ZPC_ERROR_IVSIZE, + C("invalid IV size") }, + { ZPC_ERROR_TAGSIZE, + C("invalid tag size") }, + { ZPC_ERROR_TAGMISMATCH, + C("tag mismatch") }, + { ZPC_ERROR_HWCAPS, + C("function not supported") }, + { ZPC_ERROR_SMALLOUTBUF, + C("output buffer too small") }, + { ZPC_ERROR_APQNSNOTSET, + C("APQNs not set") }, + { ZPC_ERROR_KEYTYPE, + C("invalid key type") }, + { ZPC_ERROR_KEYTYPENOTSET, + C("key type not set") }, + { ZPC_ERROR_IOCTLGENSECK2, + C("PKEY_GENSECK2 ioctl failed") }, + { ZPC_ERROR_IOCTLCLR2SECK2, + C("PKEY_CLR2SECK2 ioctl failed") }, + { ZPC_ERROR_IOCTLBLOB2PROTK2, + C("PKEY_BLOB2PROTK2 ioctl failed") }, + { ZPC_ERROR_WKVPMISMATCH, + C("wrapping key verification pattern mismatch") }, + { ZPC_ERROR_DEVPKEY, + C("opening /dev/pkey failed") }, + { ZPC_ERROR_CLEN, + C("ciphertext too long") }, + { ZPC_ERROR_MLEN, + C("message too long") }, + { ZPC_ERROR_AADLEN, + C("additional authenticated data too long") }, + { ZPC_ERROR_PARSE, + C("parse error") }, + { ZPC_ERROR_APQNNOTFOUND, + C("APQN not found in APQN list") }, + { ZPC_ERROR_MKVPLEN, + C("MKVP too long") }, + { ZPC_ERROR_INITLOCK, + C("initializing a lock failed") }, + { ZPC_ERROR_OBJINUSE, + C("object is in use") }, + { ZPC_ERROR_IOCTLAPQNS4KT, + C("PKEY_APQNS4KT ioctl failed") }, + { ZPC_ERROR_KEYSIZENOTSET, + C("key-size not set") }, + { ZPC_ERROR_IOCTLGENPROTK, + C("PKEY_GENPROTK ioctl failed") }, + { ZPC_ERROR_PROTKEYONLY, + C("protected-key only") }, + { ZPC_ERROR_KEYSEQUAL, + C("keys are equal") }, + { ZPC_ERROR_NOTSUP, + C("not supported") }, + { ZPC_ERROR_EC_INVALID_CURVE, + C("Invalid EC curve") }, + { ZPC_ERROR_EC_CURVE_NOTSET, + C("EC curve not set") }, + { ZPC_ERROR_EC_PRIVKEY_NOTSET, + C("EC private key not set") }, + { ZPC_ERROR_EC_PUBKEY_NOTSET, + C("EC public key not set") }, + { ZPC_ERROR_EC_NO_KEY_PARTS, + C("No EC key parts given") }, + { ZPC_ERROR_EC_SIGNATURE_INVALID, + C("signature invalid") }, + { ZPC_ERROR_IOCTLBLOB2PROTK3, + C("PKEY_BLOB2PROTK3 ioctl failed") }, + { ZPC_ERROR_IOCTLCLR2SECK3, + C("PKEY_CLR2SECK3 ioctl failed") }, + { ZPC_ERROR_APQNS_NOTSET, + C("No APQNs set for this key,but required for this operation") }, + { ZPC_ERROR_EC_SIGNATURE_LENGTH, + C("Signature length is invalid for this EC key") }, + { ZPC_ERROR_EC_KEY_PARTS_INCONSISTENT, + C("Given public/private key parts are inconsistent") }, + { ZPC_ERROR_CCA_HOST_LIB_NOT_AVAILABLE, + C("CCA host library not available,but required for this operation") }, + { ZPC_ERROR_EP11_HOST_LIB_NOT_AVAILABLE, + C("EP11 host library not available,but required for this operation") }, + { ZPC_ERROR_EC_PUBKEY_LENGTH, + C("The given EC public key length is invalid") }, + { ZPC_ERROR_EC_PRIVKEY_LENGTH, + C("The given EC private key length is invalid") }, + { ZPC_ERROR_EC_NO_CCA_SECUREKEY_TOKEN, + C("The given buffer does not contain a valid CCA secure key token") }, + { ZPC_ERROR_EC_NO_EP11_SECUREKEY_TOKEN, + C("The given buffer does not contain a valid EP11 secure key token") }, + { ZPC_ERROR_EC_EP11_SPKI_INVALID_LENGTH, + C("The imported buffer contains an EP11 SPKI with an invalid length") }, + { ZPC_ERROR_EC_EP11_SPKI_INVALID_CURVE, + C("The imported buffer contains an EP11 SPKI with an invalid EC curve") }, + { ZPC_ERROR_EC_EP11_SPKI_INVALID_PUBKEY, + C("The imported buffer contains an EP11 SPKI with an invalid public key") }, + { ZPC_ERROR_EC_EP11_SPKI_INVALID_MKVP, + C("The imported buffer contains an EP11 MACed SPKI with an invalid MKVP") }, + { ZPC_ERROR_BLOB_NOT_PKEY_EXTRACTABLE, + C("The imported buffer contains a key blob that cannot be transformed into a protected key.") }, + { ZPC_ERROR_APQNS_INVALID_VERSION, + C("At least one APQN version is invalid for this function.") }, + { ZPC_ERROR_AES_NO_EP11_SECUREKEY_TOKEN, + C("The given buffer does not contain a valid EP11 AES secure key token.") }, + { ZPC_ERROR_AES_NO_CCA_DATAKEY_TOKEN, + C("The given buffer does not contain a valid CCA datakey token") }, + { ZPC_ERROR_AES_NO_CCA_CIPHERKEY_TOKEN, + C("The given buffer does not contain a valid CCA cipherkey token") }, + { ZPC_ERROR_RNDGEN, + C("Error creating random bytes") }, + { ZPC_ERROR_GCM_IV_CREATED_INTERNALLY, + C("Invalid usage of a gcm context with an internally created iv") }, + { ZPC_ERROR_UV_PVSECRETS_NOT_AVAILABLE, + C("Support for UV retrievable secrets is not available,but required for this function.") }, + { ZPC_ERROR_PVSECRET_TYPE_NOT_SUPPORTED, + C("The given pvsecret type is not supported by libzpc.") }, + { ZPC_ERROR_PVSECRET_ID_NOT_FOUND_IN_UV_OR_INVALID_TYPE, + C("The given pvsecret ID does either not exist or belongs to a different secret type.") }, + { ZPC_ERROR_IOCTLVERIFYKEY2, + C("PKEY_VERIFYKEY2 ioctl failed.") }, + { ZPC_ERROR_HMAC_HASH_FUNCTION_NOTSET, + C("HMAC hash function not set.") }, + { ZPC_ERROR_HMAC_HASH_FUNCTION_INVALID, + C("HMAC hash function invalid.") }, + { ZPC_ERROR_HMAC_KEYGEN_VIA_SYSFS, + C("HMAC key generation via sysfs attributes failed.") }, + { ZPC_ERROR_CREATE_BLOCKSIZED_KEY, + C("Creating a block-sized HMAC key failed.") }, + { ZPC_ERROR_XTS_KEYGEN_VIA_SYSFS, + C("Creating a full-xts key via sysfs attributes failed") }, + { 0, NULL }, +}; +#undef C + +static const OSSL_PARAM prov_param_types[] = { + OSSL_PARAM_DEFN(OSSL_PROV_PARAM_NAME, OSSL_PARAM_UTF8_PTR, NULL, 0), + OSSL_PARAM_DEFN(OSSL_PROV_PARAM_VERSION, OSSL_PARAM_UTF8_PTR, NULL, 0), + OSSL_PARAM_DEFN(OSSL_PROV_PARAM_BUILDINFO, OSSL_PARAM_UTF8_PTR, NULL, 0), + OSSL_PARAM_DEFN(OSSL_PROV_PARAM_STATUS, OSSL_PARAM_INTEGER, NULL, 0), + OSSL_PARAM_END, +}; + +static int prov_ctx_init(struct provider_ctx *pctx, const OSSL_CORE_HANDLE *handle, + const OSSL_DISPATCH *in) +{ + const OSSL_DISPATCH *iter_in; + OSSL_LIB_CTX *libctx; + + if (!pctx) + return OSSL_RV_ERR; + + libctx = OSSL_LIB_CTX_new_from_dispatch(handle, in); + if (!libctx) + return OSSL_RV_ERR; + + pctx->libctx = libctx; + pctx->handle = handle; + pctx->state = PROVIDER_INITIALIZED; + + for (iter_in = in; iter_in->function_id != 0; iter_in++) { + switch (iter_in->function_id) { + case OSSL_FUNC_CORE_NEW_ERROR: + pctx->core_new_error = OSSL_FUNC_core_new_error(iter_in); + break; + case OSSL_FUNC_CORE_SET_ERROR_DEBUG: + pctx->core_set_error_debug = OSSL_FUNC_core_set_error_debug(iter_in); + break; + case OSSL_FUNC_CORE_VSET_ERROR: + pctx->core_vset_error = OSSL_FUNC_core_vset_error(iter_in); + break; + default: + continue; + } + } + return OSSL_RV_OK; +} + +static void prov_teardown(void *vpctx) +{ + OPENSSL_free(vpctx); +} + +static const OSSL_PARAM *prov_gettable_params(void *vpctx __unused) +{ + return prov_param_types; +} + +static int prov_get_params(void *vpctx, OSSL_PARAM params[]) +{ + struct provider_ctx *pctx = vpctx; + OSSL_PARAM *p; + + if (!pctx) + return OSSL_RV_ERR; + + p = OSSL_PARAM_locate(params, OSSL_PROV_PARAM_NAME); + if (p && (OSSL_PARAM_set_utf8_ptr(p, PROV_NAME) != OSSL_RV_OK)) + return OSSL_RV_ERR; + + p = OSSL_PARAM_locate(params, OSSL_PROV_PARAM_VERSION); + if (p && (OSSL_PARAM_set_utf8_ptr(p, PROV_VERSION) != OSSL_RV_OK)) + return OSSL_RV_ERR; + + p = OSSL_PARAM_locate(params, OSSL_PROV_PARAM_BUILDINFO); + if (p && (OSSL_PARAM_set_utf8_ptr(p, PROV_VERSION) != OSSL_RV_OK)) + return OSSL_RV_ERR; + + p = OSSL_PARAM_locate(params, OSSL_PROV_PARAM_STATUS); + if (p && (OSSL_PARAM_set_int(p, pctx->state) != OSSL_RV_OK)) + return OSSL_RV_ERR; + + return OSSL_RV_OK; +} + +static const OSSL_ALGORITHM *prov_query_operation(void *vpctx, int operation_id, int *no_cache) +{ + struct provider_ctx *pctx = vpctx; + const OSSL_ALGORITHM *ops; + + if (!pctx || pctx->state == PROVIDER_UNINITIALIZED) + return NULL; + + switch (operation_id) { + default: + ops = NULL; + break; + } + + *no_cache = 1; + return ops; +} + +static const OSSL_ITEM *prov_get_reason_strings(void *vpctx __unused) +{ + return reason_strings; +} + +static const OSSL_DISPATCH provider_dispatch_table[] = { +#define FUNC(func) (void (*)(void))(func) + { OSSL_FUNC_PROVIDER_TEARDOWN, FUNC(prov_teardown) }, + { OSSL_FUNC_PROVIDER_GETTABLE_PARAMS, FUNC(prov_gettable_params) }, + { OSSL_FUNC_PROVIDER_GET_PARAMS, FUNC(prov_get_params) }, + { OSSL_FUNC_PROVIDER_QUERY_OPERATION, FUNC(prov_query_operation) }, + { OSSL_FUNC_PROVIDER_GET_REASON_STRINGS, FUNC(prov_get_reason_strings) }, + { 0, NULL } +#undef FUNC +}; + +static int prov_init(const OSSL_CORE_HANDLE *handle, + const OSSL_DISPATCH *in, + const OSSL_DISPATCH **out, + void **vpctx) +{ + struct provider_ctx *pctx; + int rv = OSSL_RV_ERR; + + if (!handle || !in || !out || !vpctx) + return OSSL_RV_ERR; + + pctx = OPENSSL_zalloc(sizeof(*pctx)); + if (!pctx) + return OSSL_RV_ERR; + + if (!prov_ctx_init(pctx, handle, in)) + goto err; + + *vpctx = pctx; + *out = provider_dispatch_table; + return OSSL_RV_OK; + +err: + OPENSSL_free(pctx); + return rv; +} + +void prov_err_raise(struct provider_ctx *pctx, const char *file, int line, + const char *func, int reason, const char *fmt, ...) +{ + va_list args; + + if (!pctx || !pctx->core_new_error || + !pctx->core_set_error_debug || !pctx->core_vset_error) + return ERR_raise(ERR_LIB_PROV, reason); + + va_start(args, fmt); + pctx->core_new_error(pctx->handle); + pctx->core_set_error_debug(pctx->handle, file, line, func); + pctx->core_vset_error(pctx->handle, reason, fmt, args); + va_end(args); +} + +int OSSL_provider_init(const OSSL_CORE_HANDLE *handle, + const OSSL_DISPATCH *in, + const OSSL_DISPATCH **out, + void **provctx) +{ + return prov_init(handle, in, out, provctx); +} diff --git a/src/provider.h b/src/provider.h new file mode 100644 index 0000000..701e745 --- /dev/null +++ b/src/provider.h @@ -0,0 +1,62 @@ +// SPDX-License-Identifier: MIT +// Copyright contributors to the libzpc project +#ifndef _PROVIDER_H +#define _PROVIDER_H + +#include +#include +#include + +#define PROV_NAME "hbkzpc" +#define PROV_VERSION "2.0.0" +#define PROV_PROP "provider="PROV_NAME +#define PROV_PROP_FWD "provider!="PROV_NAME + +#define PROV_NAME_EC "EC" +#define PROV_NAMES_EC "EC:id-ecPublicKey:1.2.840.10045.2.1" +#define PROV_DESC_EC "hbkzpc EC implementation" + +#define PROV_NAME_ED25519 "ED25519" +#define PROV_NAMES_ED25519 "ED25519:1.3.101.112" +#define PROV_DESCS_ED25519 "hkkzpc ED25519 Implementation" + +#define PROV_NAME_ED448 "ED448" +#define PROV_NAMES_ED448 "ED448:1.3.101.113" +#define PROV_DESCS_ED448 "hbkzpc ED448 Implementation" + +#define __unused __attribute__((unused)) + +#ifndef ARRAY_SIZE +#define ARRAY_SIZE(x) (sizeof(x) / sizeof(*(x))) +#endif + +#ifndef MIN +#define MIN(a, b) ((a) < (b) ? (a) : (b)) +#endif + +#ifndef MAX +#define MAX(a, b) ((a) > (b) ? (a) : (b)) +#endif + +enum provider_state { + PROVIDER_UNINITIALIZED = 0, + PROVIDER_INITIALIZED, +}; + +struct provider_ctx { + const OSSL_CORE_HANDLE *handle; + OSSL_LIB_CTX *libctx; + + enum provider_state state; + + OSSL_FUNC_core_new_error_fn *core_new_error; + OSSL_FUNC_core_set_error_debug_fn *core_set_error_debug; + OSSL_FUNC_core_vset_error_fn *core_vset_error; +}; + +void prov_err_raise(struct provider_ctx *pctx, const char *file, int line, + const char *func, int reason, const char *fmt, ...); +#define PROV_ERR_raise(pctx, reason) \ + prov_err_raise(pctx, OPENSSL_FILE, OPENSSL_LINE, OPENSSL_FUNC, reason, NULL) + +#endif /* _PROVIDER_H */ From ccce480e34cbb2a52df79fa4b36c9b40e4d6bf9e Mon Sep 17 00:00:00 2001 From: Holger Dengler Date: Wed, 1 Oct 2025 20:11:48 +0200 Subject: [PATCH 07/36] cmake: Integrate base provider Signed-off-by: Holger Dengler --- CMakeLists.txt | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/CMakeLists.txt b/CMakeLists.txt index 8e78d7c..4ab7f61 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -142,6 +142,34 @@ install( DESTINATION ${CMAKE_INSTALL_LIBDIR}/pkgconfig ) +########################################################### +# zpcprovider + +set(ZPCPROVIDER_SOURCES + src/provider.c +) + +add_library(zpcprovider MODULE ${ZPCPROVIDER_SOURCES}) +set_target_properties(zpcprovider PROPERTIES PREFIX "") + +target_include_directories(zpcprovider PRIVATE src include ${OPENSSL_INCLUDE_DIR}) +target_link_libraries(zpcprovider PRIVATE OpenSSL::Crypto) + +install( + TARGETS zpcprovider + LIBRARY DESTINATION ${CMAKE_INSTALL_LIBEXECDIR} +) + +# install( +# FILES ${CMAKE_SOURCE_DIR}/man/zpcprovider.cnf.5 +# DESTINATION ${CMAKE_INSTALL_MANDIR}/man5 +# ) +# +# install( +# FILES ${CMAKE_SOURCE_DIR}/man/zpcprovider.7 +# DESTINATION ${CMAKE_INSTALL_MANDIR}/man7 +# ) + ########################################################### # Test From 66ad25d358f8de03514cd159218b6a379a373973 Mon Sep 17 00:00:00 2001 From: Holger Dengler Date: Tue, 19 Aug 2025 17:55:05 +0200 Subject: [PATCH 08/36] test: Add OpenSSL configuration template To use the zpc functionality via the OpenSSL API, the zpc provider has to be defined in the OpenSSL configuration. The build configures the template and creates a `openssl.cnf` file, which can be used for test purposes. The configuration file will be created in the build output folder. Signed-off-by: Holger Dengler --- CMakeLists.txt | 11 +++++++++++ openssl.cnf.in | 28 ++++++++++++++++++++++++++++ 2 files changed, 39 insertions(+) create mode 100644 openssl.cnf.in diff --git a/CMakeLists.txt b/CMakeLists.txt index 4ab7f61..9e71947 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -160,6 +160,17 @@ install( LIBRARY DESTINATION ${CMAKE_INSTALL_LIBEXECDIR} ) +set(OPENSSL_CONF + ${CMAKE_BINARY_DIR}/openssl.cnf +) +set(OPENSSL_CONF_IN + ${CMAKE_SOURCE_DIR}/openssl.cnf.in +) +set(ZPCPROVIDER_MODULE + ${CMAKE_BINARY_DIR}/zpcprovider.so +) +configure_file(${OPENSSL_CONF_IN} ${OPENSSL_CONF} @ONLY) + # install( # FILES ${CMAKE_SOURCE_DIR}/man/zpcprovider.cnf.5 # DESTINATION ${CMAKE_INSTALL_MANDIR}/man5 diff --git a/openssl.cnf.in b/openssl.cnf.in new file mode 100644 index 0000000..8d3edc0 --- /dev/null +++ b/openssl.cnf.in @@ -0,0 +1,28 @@ +HOME = . + +# Use this in order to automatically load providers. +openssl_conf = openssl_init + +config_diagnostics = 1 + +[openssl_init] +providers = provider_sect +alg_section = evp_properties + +[provider_sect] +default = default_sect +base = base_sect +hbkzpc = hbkzpc_sect + +[evp_properties] + +[base_sect] +activate = 1 + +[default_sect] +activate = 1 + +[hbkzpc_sect] +module = @ZPCPROVIDER_MODULE@ +identity = hbkzpc +activate = 1 From 141e6fb4ee9d55ccb74126ab326fc7cd65931ebe Mon Sep 17 00:00:00 2001 From: Holger Dengler Date: Fri, 3 Oct 2025 14:28:13 -0400 Subject: [PATCH 09/36] test: Add provider tests Add provider test framework with a base retrieval of the hbkzpc provider. Signed-off-by: Holger Dengler --- test/tprovider.c | 55 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 55 insertions(+) create mode 100644 test/tprovider.c diff --git a/test/tprovider.c b/test/tprovider.c new file mode 100644 index 0000000..319d148 --- /dev/null +++ b/test/tprovider.c @@ -0,0 +1,55 @@ +// SPDX-License-Identifier: MIT +// Copyright contributors to the libzpc project +#include +#include +#include +#include + +#include "ossl.h" + +#define PROVIDER "hbkzpc" +#define PROP_PROVIDER "provider=" PROVIDER + +enum rv { + PASS = 0, + SKIP = 77, + FAIL = 99, +}; + +static const char *stringify(int rv) +{ + switch(rv) { + case PASS: + return "PASS"; + case FAIL: + return "FAIL"; + case SKIP: + return "SKIP"; + }; + return "n/a"; +} + +static int test_provider(void) +{ + OSSL_LIB_CTX *libctx = NULL; + OSSL_PROVIDER *provider = NULL; + int rv = FAIL; + + provider = OSSL_PROVIDER_load(libctx, PROVIDER); + if (!provider) { + fprintf(stderr, "no provider %s\n", PROVIDER); + ERR_print_errors_fp(stderr); + goto out; + } + + rv = PASS; +out: + return rv; +} + +#define RUNTEST(t) do { fprintf(stdout, "%s - %s\n", #t, stringify(t())); } while (0) + +int main(void) +{ + RUNTEST(test_provider); +} From f6624441d6591f965d3f3e81f6ae2274bbd45d46 Mon Sep 17 00:00:00 2001 From: Holger Dengler Date: Fri, 3 Oct 2025 14:28:47 -0400 Subject: [PATCH 10/36] cmake: Integrate provider test Signed-off-by: Holger Dengler --- CMakeLists.txt | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/CMakeLists.txt b/CMakeLists.txt index 9e71947..25d4b58 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -467,6 +467,14 @@ target_include_directories(runtest PRIVATE include src ${GTEST_INCLUDE_DIR}) include(GoogleTest) gtest_discover_tests(runtest) +set (ZPCPROVIDER_TEST_SOURCES + test/tprovider.c +) +add_executable(runprovidertest ${ZPCPROVIDER_TEST_SOURCES}) +add_dependencies(runprovidertest zpcprovider) +target_include_directories(runprovidertest PRIVATE src ${OPENSSL_INCLUDE_DIR}) +target_link_libraries(runprovidertest PRIVATE OpenSSL::Crypto) + endif () ########################################################### From 3d504653a9362716d6ebb6a84af9cee251255e8f Mon Sep 17 00:00:00 2001 From: Holger Dengler Date: Wed, 25 Feb 2026 14:07:00 +0100 Subject: [PATCH 11/36] provider: Add provider-specific key object The provider-specific key object structure is shared between the provider components and references to the internal zpc-key structure(s). Signed-off-by: Holger Dengler --- src/object.c | 44 ++++++++++++++++++++++++++++++++++++++++++++ src/object.h | 41 +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 85 insertions(+) create mode 100644 src/object.c create mode 100644 src/object.h diff --git a/src/object.c b/src/object.c new file mode 100644 index 0000000..dc59ba7 --- /dev/null +++ b/src/object.c @@ -0,0 +1,44 @@ +// SPDX-License-Identifier: MIT +// Copyright contributors to the libzpc project +#include + +#include "object.h" + +static void _obj_free(struct obj *obj) +{ + OPENSSL_free(obj->id); + OPENSSL_free(obj); +} + +void obj_free(struct obj *obj) +{ + if (!obj) + return; + + if (__atomic_sub_fetch(&obj->refcnt, 1, __ATOMIC_SEQ_CST)) + return; + + _obj_free(obj); +} + +struct obj *obj_get(struct obj *obj) +{ + if (!obj) + return NULL; + + __atomic_fetch_add(&obj->refcnt, 1, __ATOMIC_SEQ_CST); + return obj; +} + +struct obj *obj_new(struct provider_ctx *pctx) +{ + struct obj *obj; + + obj = OPENSSL_zalloc(sizeof(struct obj)); + if (!obj) + return NULL; + + obj->pctx = pctx; + + return obj_get(obj); +} diff --git a/src/object.h b/src/object.h new file mode 100644 index 0000000..3d2ad42 --- /dev/null +++ b/src/object.h @@ -0,0 +1,41 @@ +// SPDX-License-Identifier: MIT +// Copyright contributors to the libzpc project +#ifndef _OBJECT_H +#define _OBJECT_H + +#include "provider.h" + +#define OBJ_PARAMS_MAX (8 + 1) + +struct data { + size_t plen; + unsigned char *p; +}; + +struct obj { + /* common */ + unsigned int refcnt; + struct provider_ctx *pctx; + + /* prototype - will be replaced by origin_blob */ + char *id; + + /* zpc keys */ + + /* origin path attrs */ + char *origin_type; + char *origin_alg; + struct data origin_blob; + struct data origin_flags; + struct data origin_pubkey; + + /* origin qeuery attrs */ + char *apqns; + char *mkvp; +}; + +struct obj *obj_new(struct provider_ctx *pctx); +struct obj *obj_get(struct obj *obj); +void obj_free(struct obj *obj); + +#endif /* _OBJECT_H */ From 1c3919f2fda8b6114f529a7b4acc4e87c22d88ca Mon Sep 17 00:00:00 2001 From: Holger Dengler Date: Wed, 25 Feb 2026 14:36:47 +0100 Subject: [PATCH 12/36] cmake: Integrate provider-specific key object Signed-off-by: Holger Dengler --- CMakeLists.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/CMakeLists.txt b/CMakeLists.txt index 25d4b58..5a058b2 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -147,6 +147,7 @@ install( set(ZPCPROVIDER_SOURCES src/provider.c + src/object.c ) add_library(zpcprovider MODULE ${ZPCPROVIDER_SOURCES}) From e6af4b06238ab63271dcfe8f15e7dc86e3a34320 Mon Sep 17 00:00:00 2001 From: Holger Dengler Date: Wed, 21 Jan 2026 16:53:09 +0100 Subject: [PATCH 13/36] provider: Add hbkzpc-URI parser A hbkzpc-URI references a hardware-backed key origin. The parser destructs the URI into key-value pairs. Signed-off-by: Holger Dengler --- src/uri.c | 225 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ src/uri.h | 37 +++++++++ 2 files changed, 262 insertions(+) create mode 100644 src/uri.c create mode 100644 src/uri.h diff --git a/src/uri.c b/src/uri.c new file mode 100644 index 0000000..a7269c7 --- /dev/null +++ b/src/uri.c @@ -0,0 +1,225 @@ +// SPDX-License-Identifier: MIT +// Copyright contributors to the libzpc project +#include +#include + +#include "uri.h" + +#define SEP_PROTOCOL ":" +#define SEP_PATHQUERY "?" +#define SEP_KEYVALUE "=" +#define SEP_PATHATTRS ";" +#define SEP_QUERYATTRS "&" + +#define URI_PROTOCOL URI_PROTOCOL_PREFIX SEP_PROTOCOL + +#define URI_P_ORIGIN_TYPE "origin-type" SEP_KEYVALUE +#define URI_P_ORIGIN_ALG "origin-alg" SEP_KEYVALUE +#define URI_P_ORIGIN_BLOB "origin-blob" SEP_KEYVALUE +#define URI_P_ORIGIN_FLAGS "origin-flags" SEP_KEYVALUE +#define URI_P_ORIGIN_PUBKEY "origin-spki" SEP_KEYVALUE +#define URI_P_COMMENT "comment" SEP_KEYVALUE + +#define URI_Q_MKVP "mkvp" SEP_KEYVALUE +#define URI_Q_APQNS "apqns" SEP_KEYVALUE + +static void decode_pct(char *s) +{ + char *rp, *wp, *endptr; + unsigned long tmp; + char hex[3] = {0}; + size_t wp_len = 0; + + if (!s) + return; + + if (!strchr(s, '%')) + return; + + rp = wp = s; + while(*rp) { + switch(*rp) { + case '%': + if (strlen(rp) < 3) + goto out; /* invalid format */ + + rp++; /* skip % */ + memcpy(hex, rp, 2); /* 2 chars only */ + + tmp = strtoul(hex, &endptr, 16);/* convert */ + if (*endptr != '\0') + goto out; /* non-hex chars */ + *wp = (char)(tmp & 0xff); + + rp++; + break; + default: + *wp = *rp; + } + + rp++; + wp++; + wp_len++; + } +out: + *wp = '\0'; +} + +static int parse_attr(char *str, struct attr *attr) +{ + char *key, **p; + int rc = 1; + + if (!str || !attr) + goto out; + + /* skip already parsed attribute */ + if (attr->value) + goto out; + + p = &str; + key = strsep(p, SEP_KEYVALUE); + if (!p) + goto out; + + decode_pct(*p); + attr->key = key; + attr->value = *p; + + rc = 0; +out: + return rc; +} + +static inline int match_elem_attrkey(const char *elem, const char *attrkey) +{ + return (strncmp(elem, attrkey, strlen(attrkey)) == 0); +} + +static int parse_query(char *qattr, struct parsed_uri *puri) +{ + char **next; + + /* query attributes are optional */ + if (!qattr || !strlen(qattr)) + return 0; + + next = &qattr; + do { + char *e = strsep(next, SEP_QUERYATTRS); + int rc = 0; + + if (match_elem_attrkey(e, URI_Q_MKVP)) + rc = parse_attr(e, &puri->mkvp); + else if (match_elem_attrkey(e, URI_Q_APQNS)) + rc = parse_attr(e, &puri->apqns); + else + rc = 1; /* unknown attribute */ + if (rc) + return rc; + } while (*next); + + return 0; +} + +static int parse_path(char *pattr, struct parsed_uri *puri) +{ + char **next; + + /* path attributes are mandatory */ + if (!pattr || !strlen(pattr)) + return 1; + + next = &pattr; + do { + char *e = strsep(next, SEP_PATHATTRS); + int rc = 0; + + if (match_elem_attrkey(e, URI_P_ORIGIN_TYPE)) + rc = parse_attr(e, &puri->origin_type); + else if (match_elem_attrkey(e, URI_P_ORIGIN_ALG)) + rc = parse_attr(e, &puri->origin_alg); + else if (match_elem_attrkey(e, URI_P_ORIGIN_BLOB)) + rc = parse_attr(e, &puri->origin_blob); + else if (match_elem_attrkey(e, URI_P_ORIGIN_FLAGS)) + rc = parse_attr(e, &puri->origin_flags); + else if (match_elem_attrkey(e, URI_P_ORIGIN_PUBKEY)) + rc = parse_attr(e, &puri->origin_spki); + else if (match_elem_attrkey(e, URI_P_COMMENT)) + rc = parse_attr(e, &puri->comment); + else + rc = 1; /* unknown attribute */ + if (rc) + return rc; + } while (*next); + + return 0; +} + +static int parse(char *uri, struct parsed_uri *puri) +{ + char *pattr, *qattr; + char **next; + int rc; + + if (!uri || !puri) + return 1; + + if (strncmp(uri, URI_PROTOCOL, strlen(URI_PROTOCOL)) != 0) + return 1; + + next = &uri; + + /* drop protocol */ + strsep(next, SEP_PROTOCOL); + + pattr = strsep(next, SEP_PATHQUERY); + qattr = *next; + + rc = parse_path(pattr, puri); + if (rc) { + return rc; + } + + rc = parse_query(qattr, puri); + if (rc) { + return rc; + } + + return 0; +} + +void parsed_uri_free(struct parsed_uri *puri) +{ + if (!puri) + return; + + if (puri->priv) + OPENSSL_clear_free(puri->priv, + puri->privlen); + + OPENSSL_free(puri); +} + +struct parsed_uri *parsed_uri_new(const char *uri) +{ + struct parsed_uri *puri; + + puri = OPENSSL_zalloc(sizeof(struct parsed_uri)); + if (!puri) + return NULL; + + puri->priv = OPENSSL_strdup(uri); + if (!puri->priv) + goto err; + puri->privlen = strlen(uri); + + if(parse(puri->priv, puri)) + goto err; + + return puri; + +err: + parsed_uri_free(puri); + return NULL; +} diff --git a/src/uri.h b/src/uri.h new file mode 100644 index 0000000..cf2115e --- /dev/null +++ b/src/uri.h @@ -0,0 +1,37 @@ +// SPDX-License-Identifier: MIT +// Copyright contributors to the libzpc project +#ifndef _URI_H +#define _URI_H + +#include + +#define URI_PROTOCOL_PREFIX "hbkzpc" + +struct attr { + const char *key; + const char *value; + //unsigned char *data; + //size_t datalen; +}; + +struct parsed_uri { + char *priv; + size_t privlen; + + /* path attributes */ + struct attr origin_type; + struct attr origin_alg; + struct attr origin_blob; + struct attr origin_flags; + struct attr origin_spki; + struct attr comment; + + /* query attributes */ + struct attr mkvp; + struct attr apqns; +}; + +struct parsed_uri *parsed_uri_new(const char *uri); +void parsed_uri_free(struct parsed_uri *puri); + +#endif /* _URI_H */ From 4ed730ed387ba80fddd6d405303c41f2c3d0076a Mon Sep 17 00:00:00 2001 From: Holger Dengler Date: Wed, 21 Jan 2026 16:54:30 +0100 Subject: [PATCH 14/36] cmake: Integrate uri Signed-off-by: Holger Dengler --- CMakeLists.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/CMakeLists.txt b/CMakeLists.txt index 5a058b2..4104513 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -148,6 +148,7 @@ install( set(ZPCPROVIDER_SOURCES src/provider.c src/object.c + src/uri.c ) add_library(zpcprovider MODULE ${ZPCPROVIDER_SOURCES}) From ef6599c8e3ce3d9fabd4cb5c3d8ce9971b4b08e3 Mon Sep 17 00:00:00 2001 From: Holger Dengler Date: Wed, 25 Feb 2026 03:21:27 -0500 Subject: [PATCH 15/36] provider: Add mapping helpers The mapping helpers provide mappings between e.g. algorithm strings and algorithm-related values. Signed-off-by: Holger Dengler --- src/map.c | 167 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ src/map.h | 20 +++++++ 2 files changed, 187 insertions(+) create mode 100644 src/map.c create mode 100644 src/map.h diff --git a/src/map.c b/src/map.c new file mode 100644 index 0000000..049790f --- /dev/null +++ b/src/map.c @@ -0,0 +1,167 @@ +// SPDX-License-Identifier: MIT +// Copyright contributors to the libzpc project +#include +#include +#include +#include + +#include "provider.h" +#include "map.h" + +static struct { + const char *alg; + union { + int key_size; + zpc_ec_curve_t key_curve; + }; + int object_type; + char *data_type; +} alg_map[] = { + { + .alg = SN_X9_62_prime256v1, + .key_curve = ZPC_EC_CURVE_P256, + .object_type = OSSL_OBJECT_PKEY, + .data_type = PROV_NAME_EC, + }, { + .alg = "1.2.840.10045.3.1.7", + .key_curve = ZPC_EC_CURVE_P256, + .object_type = OSSL_OBJECT_PKEY, + .data_type = PROV_NAME_EC, + }, { + .alg = SN_secp384r1, + .key_curve = ZPC_EC_CURVE_P384, + .object_type = OSSL_OBJECT_PKEY, + .data_type = PROV_NAME_EC, + }, { + .alg = "1.3.132.0.34", + .key_curve = ZPC_EC_CURVE_P384, + .object_type = OSSL_OBJECT_PKEY, + .data_type = PROV_NAME_EC, + }, { + .alg = SN_secp521r1, + .key_curve = ZPC_EC_CURVE_P521, + .object_type = OSSL_OBJECT_PKEY, + .data_type = PROV_NAME_EC, + }, { + .alg = "1.3.132.0.35", + .key_curve = ZPC_EC_CURVE_P521, + .object_type = OSSL_OBJECT_PKEY, + .data_type = PROV_NAME_EC, + }, { + .alg = SN_ED25519, + .key_curve = ZPC_EC_CURVE_ED25519, + .object_type = OSSL_OBJECT_PKEY, + .data_type = PROV_NAME_ED25519, + }, { + .alg = "1.3.101.112", + .key_curve = ZPC_EC_CURVE_ED25519, + .object_type = OSSL_OBJECT_PKEY, + .data_type = PROV_NAME_ED25519, + }, { + .alg = SN_ED448, + .key_curve = ZPC_EC_CURVE_ED448, + .object_type = OSSL_OBJECT_PKEY, + .data_type = PROV_NAME_ED448, + }, { + .alg = "1.3.101.113", + .key_curve = ZPC_EC_CURVE_ED448, + .object_type = OSSL_OBJECT_PKEY, + .data_type = PROV_NAME_ED448, + }, { 0 }, +}; + +char *alg2data_type(const char *alg) +{ + char *rv = NULL; + size_t i; + + if (!alg) + return rv; + + for (i = 0; alg_map[i].alg; i++) { + if (OPENSSL_strcasecmp(alg_map[i].alg, alg) == 0) { + rv = alg_map[i].data_type; + break; + } + } + + return rv; +} + +int alg2object_type(const char *alg) +{ + int rv = OSSL_OBJECT_UNKNOWN; + size_t i; + + if (!alg) + return rv; + + for (i = 0; alg_map[i].alg; i++) { + if (OPENSSL_strcasecmp(alg_map[i].alg, alg) == 0) { + rv = alg_map[i].object_type; + break; + } + } + + return rv; +} + +zpc_ec_curve_t alg2key_curve(const char *alg) +{ + zpc_ec_curve_t rv = ZPC_EC_CURVE_INVALID; + size_t i; + + if (!alg) + return rv; + + for (i = 0; alg_map[i].alg; i++) { + if (OPENSSL_strcasecmp(alg_map[i].alg, alg) == 0) { + rv = alg_map[i].key_curve; + break; + } + } + + return rv; +} + +int alg2key_size(const char *alg) +{ + int rv = 0; + size_t i; + + if (!alg) + return rv; + + for (i = 0; alg_map[i].alg; i++) { + if (OPENSSL_strcasecmp(alg_map[i].alg, alg) == 0) { + rv = alg_map[i].key_size; + break; + } + } + + return rv; +} + +char *obj_data_type(const struct obj *obj) +{ + const char *alg = obj ? obj->origin_alg : NULL; + return alg2data_type(alg); +} + +int obj_object_type(const struct obj *obj) +{ + const char *alg = obj ? obj->origin_alg : NULL; + return alg2object_type(alg); +} + +zpc_ec_curve_t obj_key_curve(const struct obj *obj) +{ + const char *alg = obj ? obj->origin_alg : NULL; + return alg2key_curve(alg); +} + +int obj_key_size(const struct obj *obj) +{ + const char *alg = obj ? obj->origin_alg : NULL; + return alg2key_size(alg); +} diff --git a/src/map.h b/src/map.h new file mode 100644 index 0000000..1993b4e --- /dev/null +++ b/src/map.h @@ -0,0 +1,20 @@ +// SPDX-License-Identifier: MIT +// Copyright contributors to the libzpc project +#ifndef _MAP_H +#define _MAP_H + +#include + +#include "object.h" + +char *alg2data_type(const char *alg); +int alg2object_type(const char *alg); +zpc_ec_curve_t alg2key_curve(const char *alg); +int alg2key_size(const char *alg); + +char *obj_data_type(const struct obj *alg); +int obj_object_type(const struct obj *alg); +zpc_ec_curve_t obj_key_curve(const struct obj *alg); +int obj_key_size(const struct obj *alg); + +#endif /* _MAP_H */ From 5871096d0df7888908bb85ce717c1b5029e281e6 Mon Sep 17 00:00:00 2001 From: Holger Dengler Date: Wed, 25 Feb 2026 03:22:34 -0500 Subject: [PATCH 16/36] cmake: Integrate mapping helpers Signed-off-by: Holger Dengler --- CMakeLists.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/CMakeLists.txt b/CMakeLists.txt index 4104513..b8ddfce 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -149,6 +149,7 @@ set(ZPCPROVIDER_SOURCES src/provider.c src/object.c src/uri.c + src/map.c ) add_library(zpcprovider MODULE ${ZPCPROVIDER_SOURCES}) From 8e247be99c9c2278fff84f63ce04b941bc6e63f0 Mon Sep 17 00:00:00 2001 From: Holger Dengler Date: Wed, 21 Jan 2026 16:59:02 +0100 Subject: [PATCH 17/36] provider: Add store-loader Introduce a store-loader for hbkzpc-URI based keys. The store-loader creates a provider-specific key object and adds relevant information from the URI. Signed-off-by: Holger Dengler --- src/object.c | 8 ++ src/object.h | 2 +- src/store.c | 327 ++++++++++++++++++++++++++++++++++++++++++++++ src/store.h | 10 ++ src/store_local.h | 15 +++ 5 files changed, 361 insertions(+), 1 deletion(-) create mode 100644 src/store.c create mode 100644 src/store.h create mode 100644 src/store_local.h diff --git a/src/object.c b/src/object.c index dc59ba7..7ff6d4b 100644 --- a/src/object.c +++ b/src/object.c @@ -6,6 +6,14 @@ static void _obj_free(struct obj *obj) { + OPENSSL_free(obj->origin_type); + OPENSSL_free(obj->origin_alg); + OPENSSL_free(obj->origin_blob.p); + OPENSSL_free(obj->origin_flags.p); + OPENSSL_free(obj->origin_spki.p); + OPENSSL_free(obj->apqns); + OPENSSL_free(obj->mkvp); + OPENSSL_free(obj->id); OPENSSL_free(obj); } diff --git a/src/object.h b/src/object.h index 3d2ad42..d289047 100644 --- a/src/object.h +++ b/src/object.h @@ -27,7 +27,7 @@ struct obj { char *origin_alg; struct data origin_blob; struct data origin_flags; - struct data origin_pubkey; + struct data origin_spki; /* origin qeuery attrs */ char *apqns; diff --git a/src/store.c b/src/store.c new file mode 100644 index 0000000..76fe83b --- /dev/null +++ b/src/store.c @@ -0,0 +1,327 @@ +// SPDX-License-Identifier: MIT +// Copyright contributors to the libzpc project +#include +#include +#include +#include +#include + +#include "provider.h" +#include "object.h" +#include "ossl.h" +#include "uri.h" +#include "map.h" +#include "store_local.h" + +struct store_ctx { + struct provider_ctx *pctx; + struct parsed_uri *puri; + + int type_exp; + bool eof; +}; + +#define DISP_STORE_FN(tname, name) DECL_DISPATCH_FUNC(store, tname, name) +DISP_STORE_FN(open, store_open); +#ifdef OSSL_FUNC_STORE_OPEN_EX +DISP_STORE_FN(open_ex, store_open_ex); +#endif +DISP_STORE_FN(load, store_load); +DISP_STORE_FN(eof, store_eof); +DISP_STORE_FN(close, store_close); +DISP_STORE_FN(set_ctx_params, store_set_ctx_params); +DISP_STORE_FN(settable_ctx_params, store_settable_ctx_params); +#undef DISP_STORE_FN + +static struct store_ctx *store_ctx_init(struct provider_ctx *pctx) +{ + struct store_ctx *sctx; + + sctx = OPENSSL_zalloc(sizeof(struct store_ctx)); + if (!sctx) + return NULL; + + sctx->pctx = pctx; + sctx->eof = false; + + return sctx; +} + +static void store_ctx_free(struct store_ctx *sctx) +{ + if (!sctx) + return; + + parsed_uri_free(sctx->puri); + OPENSSL_free(sctx); + + return; +} + +static int store_ctx_expect(struct store_ctx *sctx, int type_exp) +{ + int rv = OSSL_RV_OK; + + switch (type_exp) { + case OSSL_STORE_INFO_PUBKEY: + case OSSL_STORE_INFO_PKEY: + sctx->type_exp = type_exp; + break; + default: + rv = OSSL_RV_ERR; + break; + } + + return rv; +} + +static void *store_open(void *vpctx, const char *uri) +{ + struct store_ctx *sctx; + + sctx = store_ctx_init(vpctx); + if (!sctx) + return NULL; + + sctx->puri = parsed_uri_new(uri); + if (!sctx->puri) + goto err; + + return sctx; +err: + store_ctx_free(sctx); + return NULL; +} + +static void *store_open_ex(void *vpctx, const char *uri, + const OSSL_PARAM params[], + OSSL_PASSPHRASE_CALLBACK *pw_cb __unused, + void *pw_cbarg __unused) +{ + struct store_ctx *sctx; + + sctx = store_open(vpctx, uri); + if (!sctx) + return NULL; + + if (store_set_ctx_params(sctx, params) != OSSL_RV_OK) + goto err; + + return sctx; +err: + store_ctx_free(sctx); + return NULL; + +} + +static int attr2str(const struct attr *attr, char **str) +{ + if (!attr->value) + return OSSL_RV_OK; + + if (*str) + return OSSL_RV_ERR; + + *str = OPENSSL_strdup(attr->value); + return (*str) ? OSSL_RV_OK : OSSL_RV_ERR; +} + +static int attr2data(const struct attr *attr, struct data *data) +{ + size_t plen; + + if (!attr || !data) + return OSSL_RV_ERR; + + /* data already set */ + if (data->p || data->plen) + return OSSL_RV_ERR; + + if (!attr->value) + return OSSL_RV_OK; + plen = strlen(attr->value); + + if (OPENSSL_hexstr2buf_ex(NULL, 0, &plen, + attr->value, '\0') != 1) + return OSSL_RV_ERR; + + data->p = OPENSSL_zalloc(plen); + if (!data->p) + return OSSL_RV_ERR; + data->plen = plen; + + if (OPENSSL_hexstr2buf_ex(data->p, data->plen, &data->plen, + attr->value, '\0') != 1) { + OPENSSL_free(data->p); + return OSSL_RV_ERR; + } + + return OSSL_RV_OK; +} + +static struct obj *uri2obj(struct provider_ctx *pctx, const struct parsed_uri *puri) +{ + struct obj *obj; + + obj = obj_new(pctx); + if (!obj) + return NULL; + + if (attr2str(&puri->origin_type, &obj->origin_type) != OSSL_RV_OK) + goto err; + if (attr2str(&puri->origin_alg, &obj->origin_alg) != OSSL_RV_OK) + goto err; + if (attr2data(&puri->origin_blob, &obj->origin_blob) != OSSL_RV_OK) + goto err; + if (attr2data(&puri->origin_flags, &obj->origin_flags) != OSSL_RV_OK) + goto err; + if (attr2data(&puri->origin_spki, &obj->origin_spki) != OSSL_RV_OK) + goto err; + if (attr2str(&puri->mkvp, &obj->mkvp) != OSSL_RV_OK) + goto err; + if (attr2str(&puri->apqns, &obj->apqns) != OSSL_RV_OK) + goto err; + + return obj; +err: + obj_free(obj); + return NULL; +} + +static int store_load(void *vsctx, + OSSL_CALLBACK *object_cb, void *object_cbarg, + OSSL_PASSPHRASE_CALLBACK *pw_cb, void *pw_cbarg) +{ + struct store_ctx *sctx = (struct store_ctx *)vsctx; + struct parsed_uri *puri; + int object_type; + + if (!sctx) + return OSSL_RV_ERR; + puri = sctx->puri; + + object_type = alg2object_type(puri->origin_alg.value); + if (object_type == OSSL_OBJECT_UNKNOWN) + return OSSL_RV_ERR; + + /* early checks */ + switch (sctx->type_exp) { + case OSSL_STORE_INFO_PKEY: + if (object_type != OSSL_OBJECT_PKEY) + return OSSL_RV_ERR; + break; + case 0: + /* no expected type */ + break; + default: + return OSSL_RV_ERR; + } + + sctx->eof = true; + return store_load_uri(sctx->pctx, puri, object_cb, object_cbarg, + pw_cb, pw_cbarg); +} + +static int store_eof(void *vsctx) +{ + struct store_ctx *sctx = (struct store_ctx *)vsctx; + + if (!sctx) + return OSSL_RV_TRUE; + + return sctx->eof ? OSSL_RV_TRUE : OSSL_RV_FALSE; +} + +static int store_close(void *vsctx) +{ + store_ctx_free((struct store_ctx *)vsctx); + return OSSL_RV_OK; +} + +static int store_set_ctx_params(void *vsctx, const OSSL_PARAM params[]) +{ + struct store_ctx *sctx = (struct store_ctx *)vsctx; + const OSSL_PARAM *p; + int type_exp; + + if (!sctx) + return OSSL_RV_ERR; + + if (!params) + return OSSL_RV_OK; + + p = OSSL_PARAM_locate_const(params, OSSL_STORE_PARAM_EXPECT); + if (p) { + if ((OSSL_PARAM_get_int(p, &type_exp) != OSSL_RV_OK) || + (store_ctx_expect(sctx, type_exp) != OSSL_RV_OK)) + return OSSL_RV_ERR; + } + + return OSSL_RV_OK; +} + +static const OSSL_PARAM *store_settable_ctx_params(void *pctx __unused) +{ + static const OSSL_PARAM known_settable_ctx_params[] = { + OSSL_PARAM_int(OSSL_STORE_PARAM_EXPECT, NULL), + OSSL_PARAM_END, + }; + return known_settable_ctx_params; +} + +int store_load_uri(struct provider_ctx *pctx, struct parsed_uri *puri, + OSSL_CALLBACK *object_cb, void *object_cbarg, + OSSL_PASSPHRASE_CALLBACK *pw_cb __unused, + void *pw_cbarg __unused) +{ + OSSL_PARAM params[4]; + struct obj *obj; + char *data_type; + int object_type; + int rv; + + if (!pctx || !puri) + return OSSL_RV_ERR; + + object_type = alg2object_type(puri->origin_alg.value); + if (object_type == OSSL_OBJECT_UNKNOWN) + return OSSL_RV_ERR; + + data_type = alg2data_type(puri->origin_alg.value); + if (!data_type) + return OSSL_RV_ERR; + + obj = uri2obj(pctx, puri); + if (!obj) + return OSSL_RV_ERR; + + params[0] = OSSL_PARAM_construct_int(OSSL_OBJECT_PARAM_TYPE, + &object_type); + params[1] = OSSL_PARAM_construct_utf8_string(OSSL_OBJECT_PARAM_DATA_TYPE, + data_type, 0); + params[2] = OSSL_PARAM_construct_octet_string(OSSL_OBJECT_PARAM_REFERENCE, + obj, sizeof(struct obj)); + params[3] = OSSL_PARAM_construct_end(); + + rv = object_cb(params, object_cbarg); + obj_free(obj); + return rv; +} + +static const OSSL_DISPATCH store_functions[] = { + DISPATCH_DEFN(STORE, OPEN, store_open), +#ifdef OSSL_FUNC_STORE_OPEN_EX + DISPATCH_DEFN(STORE, OPEN_EX, store_open_ex), +#endif + DISPATCH_DEFN(STORE, LOAD, store_load), + DISPATCH_DEFN(STORE, EOF, store_eof), + DISPATCH_DEFN(STORE, CLOSE, store_close), + DISPATCH_DEFN(STORE, SET_CTX_PARAMS, store_set_ctx_params), + DISPATCH_DEFN(STORE, SETTABLE_CTX_PARAMS, store_settable_ctx_params), + DISPATCH_END +}; + +const OSSL_ALGORITHM store_ops[] = { + { URI_PROTOCOL_PREFIX, "provider=" PROV_NAME, store_functions, "HBKZPC URI Store" }, + { NULL, NULL, NULL, NULL }, +}; diff --git a/src/store.h b/src/store.h new file mode 100644 index 0000000..a03c60f --- /dev/null +++ b/src/store.h @@ -0,0 +1,10 @@ +// SPDX-License-Identifier: MIT +// Copyright contributors to the libzpc project +#ifndef _STORE_H +#define _STORE_H + +#include + +extern const OSSL_ALGORITHM store_ops[]; + +#endif /* _STORE_H */ diff --git a/src/store_local.h b/src/store_local.h new file mode 100644 index 0000000..55a3c62 --- /dev/null +++ b/src/store_local.h @@ -0,0 +1,15 @@ +// SPDX-License-Identifier: MIT +// Copyright contributors to the libzpc project +#ifndef _STORE_LOCAL_H +#define _STORE_LOCAL_H + +#include + +#include "provider.h" +#include "uri.h" + +int store_load_uri(struct provider_ctx *pctx, struct parsed_uri *puri, + OSSL_CALLBACK *object_cb, void *object_cbarg, + OSSL_PASSPHRASE_CALLBACK *pw_cb , void *pw_cbarg); + +#endif /* _STORE_LOCAL_H */ From 6f49dea0db79db75c491d9c5a625d4288d82f9b1 Mon Sep 17 00:00:00 2001 From: Holger Dengler Date: Wed, 21 Jan 2026 16:59:57 +0100 Subject: [PATCH 18/36] cmake: Integrate store-loader Signed-off-by: Holger Dengler --- CMakeLists.txt | 1 + src/provider.c | 4 ++++ 2 files changed, 5 insertions(+) diff --git a/CMakeLists.txt b/CMakeLists.txt index b8ddfce..3a976d8 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -150,6 +150,7 @@ set(ZPCPROVIDER_SOURCES src/object.c src/uri.c src/map.c + src/store.c ) add_library(zpcprovider MODULE ${ZPCPROVIDER_SOURCES}) diff --git a/src/provider.c b/src/provider.c index 4558474..7ae2853 100644 --- a/src/provider.c +++ b/src/provider.c @@ -10,6 +10,7 @@ #include "ossl.h" #include "provider.h" +#include "store.h" #define C(str) (void *)(str) static const OSSL_ITEM reason_strings[] = { @@ -274,6 +275,9 @@ static const OSSL_ALGORITHM *prov_query_operation(void *vpctx, int operation_id, return NULL; switch (operation_id) { + case OSSL_OP_STORE: + ops = store_ops; + break; default: ops = NULL; break; From 6b205d906a42d07f1d833b60bb3962002c1766ac Mon Sep 17 00:00:00 2001 From: Holger Dengler Date: Wed, 18 Feb 2026 04:37:32 -0500 Subject: [PATCH 19/36] provider: Add asymmetric key management Introduce a asymmetric key management to map the provider-specific key object to a intern zpc-key. Not supported: - key generation - key import/export Signed-off-by: Holger Dengler --- src/keymgmt.c | 168 ++++++++++++++++++++++++++++++++++++++++++++++++++ src/keymgmt.h | 10 +++ src/object.c | 4 ++ src/object.h | 3 + 4 files changed, 185 insertions(+) create mode 100644 src/keymgmt.c create mode 100644 src/keymgmt.h diff --git a/src/keymgmt.c b/src/keymgmt.c new file mode 100644 index 0000000..411e351 --- /dev/null +++ b/src/keymgmt.c @@ -0,0 +1,168 @@ +// SPDX-License-Identifier: MIT +// Copyright contributors to the libzpc project +#include +#include +#include +#include + +#include +#include +#include + +#include "provider.h" +#include "object.h" +#include "ossl.h" +#include "map.h" + +static struct { + const char *str; + int type; +} type_map[] = { + { .str = "uv", .type = ZPC_EC_KEY_TYPE_PVSECRET, }, + { .str = "cca", .type = ZPC_EC_KEY_TYPE_CCA, }, + { .str = "ep11", .type = ZPC_EC_KEY_TYPE_EP11, }, + { 0 }, +}; + +static int str2type(const char *str) +{ + for (int i = 0; type_map[i].str; i++) { + if (OPENSSL_strcasecmp(type_map[i].str, str) == 0) + return type_map[i].type; + } + return 0; +} + +#define SPKI_HDR_SIZE (4) +static int zpc_key_update_pubkey(struct zpc_ec_key *key, unsigned char *hex, + size_t hexlen) +{ + const unsigned char *spki; + size_t spkilen; + + if (hexlen < SPKI_HDR_SIZE || + hex[0] != 0x03 || + hex[3] != 0x04) + return ZPC_ERROR_NOTSUP; + + spki = hex + SPKI_HDR_SIZE; + spkilen = hexlen - SPKI_HDR_SIZE; + + return zpc_ec_key_import_clear(key, spki, spkilen, NULL, 0); +} + +static int zpc_key_update(struct obj *obj) +{ + struct zpc_ec_key *key = NULL; + int rc; + + if ((rc = zpc_ec_key_alloc(&key))) + goto err; + + if ((rc = zpc_ec_key_set_type(key, str2type(obj->origin_type)))) + goto err; + + if ((rc = zpc_ec_key_set_curve(key, obj_key_curve(obj)))) + goto err; + + if ((rc = zpc_ec_key_import(key, obj->origin_blob.p, obj->origin_blob.plen))) + goto err; + + if (strcmp(obj->origin_type, "uv") == 0) { + /* uv only: import spki */ + if ((rc = zpc_key_update_pubkey(key, obj->origin_spki.p, + obj->origin_spki.plen))) + goto err; + } else { + if (obj->mkvp && (rc = zpc_ec_key_set_mkvp(key, obj->mkvp))) + goto err; + /* TODO: apqns */ + } + + obj->ec_key = key; + return OSSL_RV_OK; +err: + PROV_ERR_raise(obj->pctx, rc); + zpc_ec_key_free(&key); + return OSSL_RV_ERR; +} + +#define DECL_KMGMT_FN(tname, name) DECL_DISPATCH_FUNC(keymgmt, tname, name) +DECL_KMGMT_FN(new, ec_new); +DECL_KMGMT_FN(free, ec_free); +DECL_KMGMT_FN(load, ec_load); +DECL_KMGMT_FN(has, ec_has); +#undef DECL_SKMGMT_FN + +static void *ec_new(void *provctx) +{ + return obj_new((struct provider_ctx *)provctx); +} + +static void ec_free(void *keydata) +{ + struct obj *obj = (struct obj *)keydata; + + zpc_ec_key_free(&obj->ec_key); + obj_free(obj); +} + +static void *ec_load(const void *reference, size_t reference_sz) +{ + struct obj *obj; + + if (!reference || reference_sz != sizeof(struct obj)) + return NULL; + obj = (struct obj *)reference; + + if (zpc_key_update(obj) == OSSL_RV_ERR) + return NULL; + + return obj_get(obj); +} + +static int ec_has(const void *keydata, int selection) +{ + struct obj *obj = (struct obj *)keydata; + int rv = OSSL_RV_FALSE; + + if (!obj) + return OSSL_RV_ERR; + + if (selection & OSSL_KEYMGMT_SELECT_PRIVATE_KEY) { + if (obj->origin_blob.p && obj->ec_key) + rv = OSSL_RV_TRUE; + } else if (selection & OSSL_KEYMGMT_SELECT_PUBLIC_KEY) { + if (obj->origin_spki.p) + rv = OSSL_RV_TRUE; + } + + return rv; +} + +static const char *ec_query_operation_name(int operation_id) +{ + switch (operation_id) { + case OSSL_OP_SIGNATURE: + return "ECDSA"; + default: + break; + } + + return NULL; +} + +static const OSSL_DISPATCH keymgmt_ec_functions[] = { + DISPATCH_DEFN(KEYMGMT, NEW, ec_new), + DISPATCH_DEFN(KEYMGMT, FREE, ec_free), + DISPATCH_DEFN(KEYMGMT, LOAD, ec_load), + DISPATCH_DEFN(KEYMGMT, HAS, ec_has), + DISPATCH_DEFN(KEYMGMT, QUERY_OPERATION_NAME, ec_query_operation_name), + DISPATCH_END, +}; + +const OSSL_ALGORITHM keymgmt_ops[] = { + ALGORITHM_DEFN(PROV_NAME_EC, PROV_PROP, keymgmt_ec_functions, + PROV_DESC_EC), + ALGORITHM_END, +}; diff --git a/src/keymgmt.h b/src/keymgmt.h new file mode 100644 index 0000000..359ec42 --- /dev/null +++ b/src/keymgmt.h @@ -0,0 +1,10 @@ +// SPDX-License-Identifier: MIT +// Copyright contributors to the libzpc project +#ifndef _KEYMGMT_H +#define _KEYMGMT_H + +#include + +extern const OSSL_ALGORITHM keymgmt_ops[]; + +#endif /* _KEYMGMT_H */ diff --git a/src/object.c b/src/object.c index 7ff6d4b..241d86b 100644 --- a/src/object.c +++ b/src/object.c @@ -2,10 +2,14 @@ // Copyright contributors to the libzpc project #include +#include + #include "object.h" static void _obj_free(struct obj *obj) { + zpc_ec_key_free(&obj->ec_key); + OPENSSL_free(obj->origin_type); OPENSSL_free(obj->origin_alg); OPENSSL_free(obj->origin_blob.p); diff --git a/src/object.h b/src/object.h index d289047..ddc3536 100644 --- a/src/object.h +++ b/src/object.h @@ -3,6 +3,8 @@ #ifndef _OBJECT_H #define _OBJECT_H +#include + #include "provider.h" #define OBJ_PARAMS_MAX (8 + 1) @@ -21,6 +23,7 @@ struct obj { char *id; /* zpc keys */ + struct zpc_ec_key *ec_key; /* origin path attrs */ char *origin_type; From 33f3dcbf6dbc68d73521fc32c512e78167485860 Mon Sep 17 00:00:00 2001 From: Holger Dengler Date: Wed, 1 Oct 2025 20:36:51 +0200 Subject: [PATCH 20/36] cmake: Add zpc dependency for provider The symmetric key-management has a dependency to zpc library code. Make the build aware of it. Signed-off-by: Holger Dengler --- CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 3a976d8..e989802 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -157,7 +157,7 @@ add_library(zpcprovider MODULE ${ZPCPROVIDER_SOURCES}) set_target_properties(zpcprovider PROPERTIES PREFIX "") target_include_directories(zpcprovider PRIVATE src include ${OPENSSL_INCLUDE_DIR}) -target_link_libraries(zpcprovider PRIVATE OpenSSL::Crypto) +target_link_libraries(zpcprovider PRIVATE zpc OpenSSL::Crypto) install( TARGETS zpcprovider From 1aa12cf7ded8ddbc089af7329b7c9bf21ea6faa6 Mon Sep 17 00:00:00 2001 From: Holger Dengler Date: Wed, 18 Feb 2026 04:38:01 -0500 Subject: [PATCH 21/36] cmake: Integrate asymmetric key management Signed-off-by: Holger Dengler --- CMakeLists.txt | 1 + src/provider.c | 4 ++++ 2 files changed, 5 insertions(+) diff --git a/CMakeLists.txt b/CMakeLists.txt index e989802..0ea2970 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -151,6 +151,7 @@ set(ZPCPROVIDER_SOURCES src/uri.c src/map.c src/store.c + src/keymgmt.c ) add_library(zpcprovider MODULE ${ZPCPROVIDER_SOURCES}) diff --git a/src/provider.c b/src/provider.c index 7ae2853..8403e53 100644 --- a/src/provider.c +++ b/src/provider.c @@ -11,6 +11,7 @@ #include "ossl.h" #include "provider.h" #include "store.h" +#include "keymgmt.h" #define C(str) (void *)(str) static const OSSL_ITEM reason_strings[] = { @@ -278,6 +279,9 @@ static const OSSL_ALGORITHM *prov_query_operation(void *vpctx, int operation_id, case OSSL_OP_STORE: ops = store_ops; break; + case OSSL_OP_KEYMGMT: + ops = keymgmt_ops; + break; default: ops = NULL; break; From 97b2a0ceb8fa2691ccf9120a1d6c6485f57a1d2d Mon Sep 17 00:00:00 2001 From: Holger Dengler Date: Thu, 12 Feb 2026 16:18:56 +0100 Subject: [PATCH 22/36] test: Add provider test for store-loader Add tests for the sore-loader. It covers mainly the open()/load()/eof() sequence. Signed-off-by: Holger Dengler --- test/tprovider.c | 52 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 52 insertions(+) diff --git a/test/tprovider.c b/test/tprovider.c index 319d148..edc88c4 100644 --- a/test/tprovider.c +++ b/test/tprovider.c @@ -4,12 +4,23 @@ #include #include #include +#include #include "ossl.h" #define PROVIDER "hbkzpc" #define PROP_PROVIDER "provider=" PROVIDER +#define HBKZPC_URI_ECDSA_UV "hbkzpc:comment=uv-secret-name=ecdsa" \ + ";origin-alg=prime256v1" \ + ";origin-type=uv" \ + ";origin-blob=318f9f812b9e89ec3bd948c00afc751749a5a275b3a709436288da62f4cb36fb" \ + ";origin-spki=0342000424873fcb06306adc8f65c8ec" \ + "d5aaf7bc6b62db8db50d8ce01677e49d" \ + "48e3be50af733b6e30a4c24fb52209cf" \ + "6254b2b87c6ffb65a50583cea136a048" \ + "8d431923" + enum rv { PASS = 0, SKIP = 77, @@ -47,9 +58,50 @@ static int test_provider(void) return rv; } +static int test_store_load_eof(void) +{ + const char *uri = HBKZPC_URI_ECDSA_UV; + OSSL_STORE_INFO *info; + OSSL_STORE_CTX *sctx; + int rv = FAIL; + + sctx = OSSL_STORE_open(uri, NULL, NULL, NULL, NULL); + if (!sctx) { + fprintf(stderr, "fail: OSSL_STORE_open() [uri=%s]\n", uri); + ERR_print_errors_fp(stderr); + goto out; + } + + if (OSSL_STORE_eof(sctx) != 0) { + fprintf(stderr, "fail: OSSL_STORE_eof() != 0 [uri=%s]\n", uri); + ERR_print_errors_fp(stderr); + goto out_close; + } + + info = OSSL_STORE_load(sctx); + if (!info) { + fprintf(stderr, "fail: OSSL_STORE_load() [uri=%s]\n", uri); + ERR_print_errors_fp(stderr); + goto out_close; + } + + if (OSSL_STORE_eof(sctx) != 1) { + fprintf(stderr, "fail: OSSL_STORE_eof() != 1 [uri=%s]\n", uri); + ERR_print_errors_fp(stderr); + goto out_close; + } + + rv = PASS; +out_close: + OSSL_STORE_close(sctx); +out: + return rv; +} + #define RUNTEST(t) do { fprintf(stdout, "%s - %s\n", #t, stringify(t())); } while (0) int main(void) { RUNTEST(test_provider); + RUNTEST(test_store_load_eof); } From 01c4e9f6617dc5091635be901ae16bb43254a900 Mon Sep 17 00:00:00 2001 From: Holger Dengler Date: Tue, 17 Feb 2026 09:45:28 -0500 Subject: [PATCH 23/36] test: Add provider test for PKEY (store/keymgmt) Add test for loading a EVP PKEY object from a hbkzpc-URI via store and keymgmt. Signed-off-by: Holger Dengler --- test/tprovider.c | 53 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 53 insertions(+) diff --git a/test/tprovider.c b/test/tprovider.c index edc88c4..0c80605 100644 --- a/test/tprovider.c +++ b/test/tprovider.c @@ -98,10 +98,63 @@ static int test_store_load_eof(void) return rv; } +static int test_store_get_pkey(void) +{ + const char *uri = HBKZPC_URI_ECDSA_UV; + OSSL_STORE_CTX *sctx; + void *key = NULL; + int rv = FAIL; + + sctx = OSSL_STORE_open(uri, NULL, NULL, NULL, NULL); + if (!sctx) { + fprintf(stderr, "fail: OSSL_STORE_open() [uri=%s]\n", uri); + ERR_print_errors_fp(stderr); + goto out; + } + + while (!OSSL_STORE_eof(sctx)) { + OSSL_STORE_INFO *info = OSSL_STORE_load(sctx); + if (!info) { + fprintf(stderr, "fail: OSSL_STORE_load() [uri=%s]\n", uri); + ERR_print_errors_fp(stderr); + goto out_close; + } + + switch (OSSL_STORE_INFO_get_type(info)) { + case OSSL_STORE_INFO_PUBKEY: + key = OSSL_STORE_INFO_get1_PUBKEY(info); + break; + case OSSL_STORE_INFO_PKEY: + key = OSSL_STORE_INFO_get1_PKEY(info); + break; + default: + OSSL_STORE_INFO_free(info); + continue; + } + + OSSL_STORE_INFO_free(info); + break; + } + + if (!key) { + fprintf(stderr, "fail: OSSL_STORE_INFO_[PUBKEY|PKEY] lookup [uri=%s]\n", uri); + ERR_print_errors_fp(stderr); + goto out_close; + } + + EVP_PKEY_free(key); + rv = PASS; +out_close: + OSSL_STORE_close(sctx); +out: + return rv; +} + #define RUNTEST(t) do { fprintf(stdout, "%s - %s\n", #t, stringify(t())); } while (0) int main(void) { RUNTEST(test_provider); RUNTEST(test_store_load_eof); + RUNTEST(test_store_get_pkey); } From cbf1358b52b0225242ae0d9fa8b54968f8515a12 Mon Sep 17 00:00:00 2001 From: Holger Dengler Date: Mon, 9 Mar 2026 12:37:49 -0400 Subject: [PATCH 24/36] provider: Add signature algorithms Add signature algorithms for sign/verify with ECDSA and EDDSA keys. Signed-off-by: Holger Dengler --- src/signature.c | 482 ++++++++++++++++++++++++++++++++++++++++++++++++ src/signature.h | 10 + 2 files changed, 492 insertions(+) create mode 100644 src/signature.c create mode 100644 src/signature.h diff --git a/src/signature.c b/src/signature.c new file mode 100644 index 0000000..6fde63f --- /dev/null +++ b/src/signature.c @@ -0,0 +1,482 @@ +// SPDX-License-Identifier: MIT +// Copyright contributors to the libzpc project +#include +#include +#include +#include +#include +#include + +#include + +#include "provider.h" +#include "signature.h" +#include "object.h" +#include "ossl.h" +#include "map.h" + +/* TODO: OSSL_SIGNATURE_PARAM_NONCE_TYPE support */ + +#define ASN1_SIG_HDR 8 + +enum sig_op { + SIG_OP_UNDEF = 0, + SIG_OP_SIGN, + SIG_OP_VERIFY, +}; + +static int ecdsa_curves[] = { + ZPC_EC_CURVE_P256, + ZPC_EC_CURVE_P384, + ZPC_EC_CURVE_P521, +}; + +static int eddsa_curves[] = { + ZPC_EC_CURVE_ED25519, + ZPC_EC_CURVE_ED448, +}; + +struct sig_ctx { + struct provider_ctx *pctx; + char *propq; + + unsigned int nid; + enum sig_op op; + struct zpc_ecdsa_ctx *zpc_ctx; + + int *curves; + size_t curves_len; + + EVP_MD_CTX *fwd_md_ctx; + bool raw_sig; +}; + +static bool valid_curve(int curve, int *curves, size_t curves_len) +{ + for (size_t i = 0; i < curves_len; i++) + if (curve == curves[i]) + return true; + + return false; +} + +static int raw2der(const unsigned char *raw, size_t rawlen, + unsigned char *der, size_t *derlen) +{ + ECDSA_SIG *ec_sig = NULL; + int rv = OSSL_RV_ERR; + size_t _derlen; + + if (!raw || !rawlen || !derlen || + (*derlen < (rawlen + ASN1_SIG_HDR))) + goto out; + + ec_sig = ECDSA_SIG_new(); + if (!ec_sig) + goto out; + + rv = ECDSA_SIG_set0(ec_sig, + BN_bin2bn(raw, rawlen / 2, NULL), + BN_bin2bn(raw + rawlen / 2, rawlen / 2, NULL)); + if (rv != OSSL_RV_OK) + goto out; + + _derlen = i2d_ECDSA_SIG(ec_sig, &der); + if (_derlen <= 0) + goto out; + + *derlen = _derlen; + rv = OSSL_RV_OK; +out: + ECDSA_SIG_free(ec_sig); + return rv; +} + +static int der2raw(const unsigned char *der, size_t derlen, + unsigned char *raw, size_t *rawlen) +{ + ECDSA_SIG *ec_sig = NULL; + int rv = OSSL_RV_ERR; + const BIGNUM *r, *s; + size_t _rawlen; + + if (!der || !derlen || !rawlen) + goto out; + _rawlen = *rawlen; + + ec_sig = d2i_ECDSA_SIG(NULL, &der, derlen); + if (!ec_sig) + goto out; + + r = ECDSA_SIG_get0_r(ec_sig); + s = ECDSA_SIG_get0_s(ec_sig); + if (!r || !s) + goto out; + + if ((BN_bn2binpad(r, raw, _rawlen / 2) == -1) || + (BN_bn2binpad(s, raw + _rawlen / 2, _rawlen / 2) == -1)) + goto out; + + rv = OSSL_RV_OK; +out: + ECDSA_SIG_free(ec_sig); + return rv; +} + +static struct sig_ctx *sig_newctx(struct provider_ctx *pctx, const char *propq, + int *curves, size_t curves_len, bool raw_sig) +{ + struct zpc_ecdsa_ctx *zpc_ctx = NULL; + struct sig_ctx *sctx = NULL; + char *pq; + int rc; + + rc = zpc_ecdsa_ctx_alloc(&zpc_ctx); + if (rc) { + PROV_ERR_raise(pctx, rc); + return NULL; + } + + sctx = OPENSSL_zalloc(sizeof(struct sig_ctx)); + if (!sctx) + goto err; + + pq = OPENSSL_strdup(propq); + if (pq) + goto err; + + sctx->pctx = pctx; + sctx->zpc_ctx = zpc_ctx; + sctx->propq = pq; + sctx->curves = curves; + sctx->curves_len = curves_len; + sctx->raw_sig = raw_sig; + + return sctx; +err: + OPENSSL_free(sctx); + zpc_ecdsa_ctx_free(&zpc_ctx); + return NULL; +} + +static int sig_init(struct sig_ctx *sctx, struct obj *obj, + const OSSL_PARAM params[] __unused, + enum sig_op op) +{ + int rc; + + if (!sctx) + return OSSL_RV_ERR; + + if (obj) { + if (!valid_curve(obj_key_curve(obj), + sctx->curves, sctx->curves_len)) + return OSSL_RV_ERR; + rc = zpc_ecdsa_ctx_set_key(sctx->zpc_ctx, obj->ec_key); + if (rc) { + PROV_ERR_raise(sctx->pctx, rc); + return OSSL_RV_ERR; + } + } + + /* TODO: params */ + + sctx->op = op; + return OSSL_RV_OK; +} + +static int sig_digest_init(struct sig_ctx *sctx, const char *mdname, + struct obj *obj, const OSSL_PARAM params[], + enum sig_op op) +{ + const EVP_MD *md; + EVP_MD_CTX *md_ctx; + + if (!sctx) + return OSSL_RV_ERR; + + md = EVP_MD_fetch(sctx->pctx->libctx, mdname, PROV_PROP_FWD); + if (!md) + return OSSL_RV_ERR; + + if (!sctx->fwd_md_ctx) { + md_ctx = EVP_MD_CTX_new(); + if (!md_ctx) + return OSSL_RV_ERR; + sctx->fwd_md_ctx = md_ctx; + + if (EVP_DigestInit_ex2(sctx->fwd_md_ctx, md, params) != OSSL_RV_OK) + return OSSL_RV_ERR; + } else { + if (EVP_MD_CTX_reset(sctx->fwd_md_ctx)) + return OSSL_RV_ERR; + } + + return sig_init(sctx, obj, params, op); +} + +static int sig_sign_raw(struct sig_ctx *sctx, + unsigned char *sig, size_t *siglen, size_t sigsize, + const unsigned char *tbs, size_t tbslen) +{ + *siglen = sigsize; + return zpc_ecdsa_sign(sctx->zpc_ctx, tbs, tbslen, sig, siglen) + ? OSSL_RV_ERR + : OSSL_RV_OK; +} + +static int sig_sign_der(struct sig_ctx *sctx, + unsigned char *sig, size_t *siglen, size_t sigsize, + const unsigned char *tbs, size_t tbslen) +{ + unsigned char raw[EVP_MAX_MD_SIZE]; + unsigned char *_sig; + size_t rawlen; + int rv; + + rawlen = MIN(sigsize, EVP_MAX_MD_SIZE); + _sig = sig ? raw : NULL; + + rv = sig_sign_raw(sctx, _sig, &rawlen, rawlen, tbs, tbslen); + if (rv != OSSL_RV_OK) + return rv; + + if (!sig) + *siglen = rawlen + ASN1_SIG_HDR; + else + rv = raw2der(raw, rawlen, sig, siglen); + + return rv; +} + +static int sig_verify_raw(struct sig_ctx *sctx, + const unsigned char *sig, size_t siglen, + const unsigned char *tbs, size_t tbslen) +{ + if (!sctx || + !sctx->zpc_ctx || + sctx->op != SIG_OP_VERIFY) + return OSSL_RV_ERR; + + return zpc_ecdsa_verify(sctx->zpc_ctx, tbs, tbslen, sig, siglen) + ? OSSL_RV_ERR + : OSSL_RV_OK; +} + +static int sig_verify_der(struct sig_ctx *sctx, + const unsigned char *sig, size_t siglen, + const unsigned char *tbs, size_t tbslen) +{ + unsigned char raw[EVP_MAX_MD_SIZE]; + size_t rawlen; + int rv; + + /* calculate raw signature size */ + if (zpc_ecdsa_sign(sctx->zpc_ctx, tbs, tbslen, NULL, &rawlen)) + return OSSL_RV_ERR; + + rv = der2raw(sig, siglen, raw, &rawlen); + if (rv != OSSL_RV_OK) + return rv; + + return sig_verify_raw(sctx, raw, rawlen, tbs, tbslen); +} + +#define DISP_SIG(tname, name) DECL_DISPATCH_FUNC(signature, tname, name) +DISP_SIG(newctx, ecdsa_newctx); +DISP_SIG(newctx, eddsa_newctx); +DISP_SIG(freectx, sig_freectx); + +DISP_SIG(sign_init, sig_sign_init); +DISP_SIG(sign, sig_sign); +DISP_SIG(verify_init, sig_verify_init); +DISP_SIG(verify, sig_verify); + +DISP_SIG(digest_sign_init, sig_digest_sign_init); +DISP_SIG(digest_sign_update, sig_digest_update); +DISP_SIG(digest_sign_final, sig_digest_sign_final); +DISP_SIG(digest_verify_init, sig_digest_verify_init); +DISP_SIG(digest_verify_update, sig_digest_update); +DISP_SIG(digest_verify_final, sig_digest_verify_final); +#undef DISP_SIG + +static void *ecdsa_newctx(void *vpctx, const char *propq) +{ + return sig_newctx(vpctx, propq, ecdsa_curves, ARRAY_SIZE(ecdsa_curves), + false); +} + +static void *eddsa_newctx(void *vpctx, const char *propq) +{ + return sig_newctx(vpctx, propq, eddsa_curves, ARRAY_SIZE(eddsa_curves), + true); +} + +static void sig_freectx(void *vsctx) +{ + struct sig_ctx *sctx = (struct sig_ctx *)vsctx; + + if (!sctx) + return; + + zpc_ecdsa_ctx_free(&sctx->zpc_ctx); + OPENSSL_free(sctx->propq); + OPENSSL_free(sctx); +} + +/* pre-hashed sign/verify */ +static int sig_sign_init(void *vsctx, void *provkey, + const OSSL_PARAM params[]) +{ + return sig_init(vsctx, provkey, params, SIG_OP_SIGN); +} + +static int sig_verify_init(void *vsctx, void *provkey, + const OSSL_PARAM params[]) +{ + return sig_init(vsctx, provkey, params, SIG_OP_VERIFY); +} + +static int sig_sign(void *vsctx, unsigned char *sig, size_t *siglen, + size_t sigsize, const unsigned char *tbs, size_t tbslen) +{ + struct sig_ctx *sctx = (struct sig_ctx *)vsctx; + size_t _siglen; + int rv; + + if (!sctx || !tbs || + !sctx->zpc_ctx || + sctx->op != SIG_OP_SIGN) + return OSSL_RV_ERR; + + _siglen = siglen ? *siglen : sigsize; + + rv = sctx->raw_sig ? + sig_sign_raw(sctx, sig, &_siglen, sigsize, tbs, tbslen) : + sig_sign_der(sctx, sig, &_siglen, sigsize, tbs, tbslen); + + if (siglen) + *siglen = _siglen; + + return rv; +} + +static int sig_verify(void *vsctx, const unsigned char *sig, size_t siglen, + const unsigned char *tbs, size_t tbslen) +{ + struct sig_ctx *sctx = (struct sig_ctx *)vsctx; + + if (!sctx || !sig || !tbs || + !sctx->zpc_ctx || + sctx->op != SIG_OP_VERIFY) + return OSSL_RV_ERR; + + return sctx->raw_sig ? + sig_verify_raw(sctx, sig, siglen, tbs, tbslen) : + sig_verify_der(sctx, sig, siglen, tbs, tbslen); +} + +/* digest sign/verify */ +static int sig_digest_sign_init(void *vsctx, const char *mdname, + void *provkey, const OSSL_PARAM params[]) +{ + return sig_digest_init(vsctx, mdname, provkey, params, SIG_OP_SIGN); +} + +static int sig_digest_verify_init(void *vsctx, const char *mdname, + void *provkey, const OSSL_PARAM params[]) +{ + return sig_digest_init(vsctx, mdname, provkey, params, SIG_OP_VERIFY); +} + +static int sig_digest_update(void *vsctx, const unsigned char *data, + size_t datalen) +{ + struct sig_ctx *sctx = (struct sig_ctx *)vsctx; + + if (!sctx) + return OSSL_RV_ERR; + + return EVP_DigestUpdate(sctx->fwd_md_ctx, data, datalen); +} + +static int sig_digest_sign_final(void *vsctx, unsigned char *sig, + size_t *siglen, size_t sigsize) +{ + struct sig_ctx *sctx = (struct sig_ctx *)vsctx; + unsigned char tbs[EVP_MAX_MD_SIZE]; + unsigned int tbslen = EVP_MAX_MD_SIZE; + + if (!sctx) + return OSSL_RV_ERR; + + if (sig && + EVP_DigestFinal_ex(sctx->fwd_md_ctx, tbs, &tbslen) != OSSL_RV_OK) + return OSSL_RV_ERR; + + return sig_sign(sctx, sig, siglen, sigsize, tbs, tbslen); +} + +static int sig_digest_verify_final(void *vsctx, const unsigned char *sig, + size_t siglen) +{ + struct sig_ctx *sctx = (struct sig_ctx *)vsctx; + unsigned char tbs[EVP_MAX_MD_SIZE]; + unsigned int tbslen = EVP_MAX_MD_SIZE; + + if (!sctx) + return OSSL_RV_ERR; + + if (EVP_DigestFinal_ex(sctx->fwd_md_ctx, tbs, &tbslen) != OSSL_RV_OK) + return OSSL_RV_ERR; + + return sig_verify(sctx, sig, siglen, tbs, tbslen); +} + +static const OSSL_DISPATCH ecdsa_functions[] = { + DISPATCH_DEFN(SIGNATURE, NEWCTX, ecdsa_newctx), + DISPATCH_DEFN(SIGNATURE, FREECTX, sig_freectx), + + DISPATCH_DEFN(SIGNATURE, SIGN_INIT, sig_sign_init), + DISPATCH_DEFN(SIGNATURE, SIGN, sig_sign), + + DISPATCH_DEFN(SIGNATURE, VERIFY_INIT, sig_verify_init), + DISPATCH_DEFN(SIGNATURE, VERIFY, sig_verify), + + DISPATCH_DEFN(SIGNATURE, DIGEST_SIGN_INIT, sig_digest_sign_init), + DISPATCH_DEFN(SIGNATURE, DIGEST_SIGN_UPDATE, sig_digest_update), + DISPATCH_DEFN(SIGNATURE, DIGEST_SIGN_FINAL, sig_digest_sign_final), + + DISPATCH_DEFN(SIGNATURE, DIGEST_VERIFY_INIT, sig_digest_verify_init), + DISPATCH_DEFN(SIGNATURE, DIGEST_VERIFY_UPDATE, sig_digest_update), + DISPATCH_DEFN(SIGNATURE, DIGEST_VERIFY_FINAL, sig_digest_verify_final), + + DISPATCH_END, +}; + +static const OSSL_DISPATCH eddsa_functions[] = { + DISPATCH_DEFN(SIGNATURE, NEWCTX, eddsa_newctx), + DISPATCH_DEFN(SIGNATURE, FREECTX, sig_freectx), + + DISPATCH_DEFN(SIGNATURE, SIGN_INIT, sig_sign_init), + DISPATCH_DEFN(SIGNATURE, SIGN, sig_sign), + + DISPATCH_DEFN(SIGNATURE, VERIFY_INIT, sig_verify_init), + DISPATCH_DEFN(SIGNATURE, VERIFY, sig_verify), + + DISPATCH_DEFN(SIGNATURE, DIGEST_SIGN_INIT, sig_digest_sign_init), + DISPATCH_DEFN(SIGNATURE, DIGEST_SIGN_UPDATE, sig_digest_update), + DISPATCH_DEFN(SIGNATURE, DIGEST_SIGN_FINAL, sig_digest_sign_final), + + DISPATCH_DEFN(SIGNATURE, DIGEST_VERIFY_INIT, sig_digest_verify_init), + DISPATCH_DEFN(SIGNATURE, DIGEST_VERIFY_UPDATE, sig_digest_update), + DISPATCH_DEFN(SIGNATURE, DIGEST_VERIFY_FINAL, sig_digest_verify_final), + + DISPATCH_END, +}; + +const OSSL_ALGORITHM signature_ops[] = { + ALGORITHM_DEFN("ECDSA", PROV_PROP, ecdsa_functions, NULL), + ALGORITHM_DEFN("EDDSA", PROV_PROP, eddsa_functions, NULL), + ALGORITHM_END, +}; diff --git a/src/signature.h b/src/signature.h new file mode 100644 index 0000000..fbeed32 --- /dev/null +++ b/src/signature.h @@ -0,0 +1,10 @@ +// SPDX-License-Identifier: MIT +// Copyright contributors to the libzpc project +#ifndef _SIGNATURE_H +#define _SIGNATURE_H + +#include + +extern const OSSL_ALGORITHM signature_ops[]; + +#endif /* _SIGNATURE_H */ From 767db6268bdd66c3c06a537224c7ab501c161e95 Mon Sep 17 00:00:00 2001 From: Holger Dengler Date: Mon, 9 Mar 2026 12:40:43 -0400 Subject: [PATCH 25/36] cmake: Integrate signature algorithms Signed-off-by: Holger Dengler --- CMakeLists.txt | 1 + src/provider.c | 4 ++++ 2 files changed, 5 insertions(+) diff --git a/CMakeLists.txt b/CMakeLists.txt index 0ea2970..91ae326 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -152,6 +152,7 @@ set(ZPCPROVIDER_SOURCES src/map.c src/store.c src/keymgmt.c + src/signature.c ) add_library(zpcprovider MODULE ${ZPCPROVIDER_SOURCES}) diff --git a/src/provider.c b/src/provider.c index 8403e53..970eb87 100644 --- a/src/provider.c +++ b/src/provider.c @@ -12,6 +12,7 @@ #include "provider.h" #include "store.h" #include "keymgmt.h" +#include "signature.h" #define C(str) (void *)(str) static const OSSL_ITEM reason_strings[] = { @@ -282,6 +283,9 @@ static const OSSL_ALGORITHM *prov_query_operation(void *vpctx, int operation_id, case OSSL_OP_KEYMGMT: ops = keymgmt_ops; break; + case OSSL_OP_SIGNATURE: + ops = signature_ops; + break; default: ops = NULL; break; From 2a6c319a770df3898debbd328277dcae55b8559c Mon Sep 17 00:00:00 2001 From: Holger Dengler Date: Tue, 17 Mar 2026 21:37:28 +0100 Subject: [PATCH 26/36] test: Add provider test for signature algorithms Add sign/verify tests for full and pre-hashed messages. The verification is checked across both variants. Note: The test covers only ECDSA and uses a hard-coded key origin. Signed-off-by: Holger Dengler --- test/tprovider.c | 331 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 331 insertions(+) diff --git a/test/tprovider.c b/test/tprovider.c index 0c80605..82cf1ba 100644 --- a/test/tprovider.c +++ b/test/tprovider.c @@ -4,6 +4,7 @@ #include #include #include +#include #include #include "ossl.h" @@ -27,6 +28,18 @@ enum rv { FAIL = 99, }; +static unsigned char text[32]; + +static unsigned char sha256[32]; + +static unsigned char *sig = NULL; +static size_t siglen = 0; + +static unsigned char *dgst_sig = NULL; +static size_t dgst_siglen = 0; + +/* helpers */ + static const char *stringify(int rv) { switch(rv) { @@ -40,6 +53,55 @@ static const char *stringify(int rv) return "n/a"; } +static EVP_PKEY *uri_pkey_get1(const char *uri) +{ + OSSL_STORE_CTX *sctx; + void *key = NULL; + + sctx = OSSL_STORE_open(uri, NULL, NULL, NULL, NULL); + if (!sctx) { + fprintf(stderr, "fail: OSSL_STORE_open() [uri=%s]\n", uri); + ERR_print_errors_fp(stderr); + goto out; + } + + while (!OSSL_STORE_eof(sctx)) { + OSSL_STORE_INFO *info = OSSL_STORE_load(sctx); + if (!info) { + fprintf(stderr, "fail: OSSL_STORE_load() [uri=%s]\n", uri); + ERR_print_errors_fp(stderr); + goto out_close; + } + + switch (OSSL_STORE_INFO_get_type(info)) { + case OSSL_STORE_INFO_PKEY: + key = OSSL_STORE_INFO_get1_PKEY(info); + break; + default: + OSSL_STORE_INFO_free(info); + continue; + } + + OSSL_STORE_INFO_free(info); + break; + } +out_close: + OSSL_STORE_close(sctx); +out: + return key; +} + +static int sha2_256(unsigned char *in, size_t inlen) +{ + size_t len = sizeof(sha256); + + return EVP_Q_digest(NULL, "SHA2-256", NULL, + in, inlen, + sha256, &len); +} + +/* tests */ + static int test_provider(void) { OSSL_LIB_CTX *libctx = NULL; @@ -150,11 +212,280 @@ static int test_store_get_pkey(void) return rv; } +static int test_signature_sign(void) +{ + const char *uri = HBKZPC_URI_ECDSA_UV; + EVP_PKEY *signing_key; + EVP_PKEY_CTX *ctx; + int rv = FAIL; + + signing_key = uri_pkey_get1(uri); + if (!signing_key) { + fprintf(stderr, "fail: EVP_PKEY_get1 [uri=%s]\n", uri); + ERR_print_errors_fp(stderr); + rv = SKIP; + goto out; + } + + ctx = EVP_PKEY_CTX_new(signing_key, NULL); + if (ctx == NULL) { + fprintf(stderr, "fail: EVP_PKEY_CTX_new [uri=%s]\n", uri); + ERR_print_errors_fp(stderr); + goto pkey_out; + } + + if (EVP_PKEY_sign_init(ctx) != OSSL_RV_OK) { + fprintf(stderr, "fail: EVP_PKEY_sign_init [uri=%s]\n", uri); + ERR_print_errors_fp(stderr); + goto ctx_out; + } + + /* Determine buffer length */ + if (EVP_PKEY_sign(ctx, NULL, &siglen, sha256, sizeof(sha256)) != OSSL_RV_OK) { + fprintf(stderr, "fail: EVP_PKEY_sign [uri=%s]\n", uri); + ERR_print_errors_fp(stderr); + goto ctx_out; + } + + sig = OPENSSL_malloc(siglen); + if (sig == NULL) { + fprintf(stderr, "fail: malloc [uri=%s]\n", uri); + ERR_print_errors_fp(stderr); + goto ctx_out; + } + + if (EVP_PKEY_sign(ctx, sig, &siglen, sha256, sizeof(sha256)) != OSSL_RV_OK) { + fprintf(stderr, "fail: EVP_PKEY_sign [uri=%s]\n", uri); + ERR_print_errors_fp(stderr); + OPENSSL_free(sig); + sig = NULL; + goto ctx_out; + } + + rv = PASS; +ctx_out: + EVP_PKEY_CTX_free(ctx); +pkey_out: + EVP_PKEY_free(signing_key); +out: + return rv; +} + +static int _test_signature_verify(unsigned char *s, size_t slen) +{ + const char *uri = HBKZPC_URI_ECDSA_UV; + EVP_PKEY *verify_key; + EVP_PKEY_CTX *ctx; + int rv = FAIL; + + if (!sig || !siglen) + return SKIP; + + verify_key = uri_pkey_get1(uri); + if (!verify_key) { + fprintf(stderr, "fail: EVP_PKEY_get1 [uri=%s]\n", uri); + ERR_print_errors_fp(stderr); + rv = SKIP; + goto out; + } + + ctx = EVP_PKEY_CTX_new(verify_key, NULL); + if (ctx == NULL) { + fprintf(stderr, "fail: EVP_PKEY_CTX_new [uri=%s]\n", uri); + ERR_print_errors_fp(stderr); + goto pkey_out; + } + + if (EVP_PKEY_verify_init(ctx) != OSSL_RV_OK) { + fprintf(stderr, "fail: EVP_PKEY_verify_init [uri=%s]\n", uri); + ERR_print_errors_fp(stderr); + goto ctx_out; + } + + if (EVP_PKEY_verify(ctx, s, slen, sha256, sizeof(sha256)) != OSSL_RV_OK) { + fprintf(stderr, "fail: EVP_PKEY_verify [uri=%s]\n", uri); + ERR_print_errors_fp(stderr); + OPENSSL_free(s); + s = NULL; + goto ctx_out; + } + + rv = PASS; +ctx_out: + EVP_PKEY_CTX_free(ctx); +pkey_out: + EVP_PKEY_free(verify_key); +out: + return rv; +} + +static int test_signature_verify(void) +{ + return _test_signature_verify(sig, siglen); +} + +static int test_signature_cross_verify(void) +{ + return _test_signature_verify(dgst_sig, dgst_siglen); +} + +static int _test_signature_digest_sign(EVP_PKEY *signing_key, + const char *msg) +{ + EVP_MD_CTX *md_ctx = NULL; + EVP_PKEY_CTX *ctx = NULL; + int rv = FAIL; + + /* just to make sure... */ + if (!signing_key) + return SKIP; + + md_ctx = EVP_MD_CTX_new(); + if (!md_ctx) { + fprintf(stderr, "fail: EVP_MD_CTX_new [%s]\n", msg); + ERR_print_errors_fp(stderr); + goto out; + } + + if (EVP_DigestSignInit_ex(md_ctx, &ctx, "SHA256", NULL, NULL, signing_key, NULL) != OSSL_RV_OK) { + fprintf(stderr, "fail: EVP_DigestSignInit_ex [%s]\n", msg); + ERR_print_errors_fp(stderr); + goto out; + } + + if (EVP_DigestSignUpdate(md_ctx, text, sizeof(text)) != OSSL_RV_OK) { + fprintf(stderr, "fail: EVP_DigestSignUpdate [%s]\n", msg); + ERR_print_errors_fp(stderr); + goto out; + } + + /* Determine buffer length */ + if (EVP_DigestSignFinal(md_ctx, NULL, &dgst_siglen) != OSSL_RV_OK) { + fprintf(stderr, "fail: EVP_DigestSignFinal [%s]\n", msg); + ERR_print_errors_fp(stderr); + goto out; + } + + dgst_sig = OPENSSL_malloc(dgst_siglen); + if (dgst_sig == NULL) { + fprintf(stderr, "fail: malloc [%s]\n", msg); + ERR_print_errors_fp(stderr); + goto out; + } + + if (EVP_DigestSignFinal(md_ctx, dgst_sig, &dgst_siglen) != OSSL_RV_OK) { + fprintf(stderr, "fail: DigestSignFinal [%s]\n", msg); + ERR_print_errors_fp(stderr); + OPENSSL_free(dgst_sig); + dgst_sig = NULL; + goto out; + } + + rv = PASS; +out: + EVP_MD_CTX_free(md_ctx); + return rv; +} + +static int test_signature_digest_sign_uri(void) +{ + const char *uri = HBKZPC_URI_ECDSA_UV; + EVP_PKEY *signing_key = NULL; + int rv = SKIP; + + signing_key = uri_pkey_get1(uri); + if (!signing_key) { + fprintf(stderr, "fail: EVP_PKEY_get1 [uri=%s]\n", uri); + ERR_print_errors_fp(stderr); + goto out; + } + + rv = _test_signature_digest_sign(signing_key, "uri=" HBKZPC_URI_ECDSA_UV); +out: + EVP_PKEY_free(signing_key); + return rv; +} + +static int _test_signature_digest_verify(unsigned char *t, size_t tlen, + unsigned char *s, size_t slen) +{ + const char *uri = HBKZPC_URI_ECDSA_UV; + EVP_PKEY *verify_key; + EVP_MD_CTX *md_ctx; + EVP_PKEY_CTX *ctx; + int rv = FAIL; + + if (!s || !slen) + return SKIP; + + verify_key = uri_pkey_get1(uri); + if (!verify_key) { + fprintf(stderr, "fail: EVP_PKEY_get1 [uri=%s]\n", uri); + ERR_print_errors_fp(stderr); + rv = SKIP; + goto out; + } + + md_ctx = EVP_MD_CTX_new(); + if (!md_ctx) { + fprintf(stderr, "fail: EVP_MD_CTX_new [uri=%s]\n", uri); + ERR_print_errors_fp(stderr); + goto pkey_out; + } + + if (EVP_DigestVerifyInit_ex(md_ctx, &ctx, "SHA256", NULL, NULL, verify_key, NULL) != OSSL_RV_OK) { + fprintf(stderr, "fail: EVP_DigestVerifyInit_ex [uri=%s]\n", uri); + ERR_print_errors_fp(stderr); + goto md_out; + } + + if (EVP_DigestVerifyUpdate(md_ctx, t, tlen) != OSSL_RV_OK) { + fprintf(stderr, "fail: EVP_DigestVerifyUpdate [uri=%s]\n", uri); + ERR_print_errors_fp(stderr); + goto md_out; + } + + if (EVP_DigestVerifyFinal(md_ctx, s, slen) != OSSL_RV_OK) { + fprintf(stderr, "fail: EVP_DigestVerifyFinal [uri=%s]\n", uri); + ERR_print_errors_fp(stderr); + s = NULL; + goto md_out; + } + + rv = PASS; +md_out: + EVP_MD_CTX_free(md_ctx); +pkey_out: + EVP_PKEY_free(verify_key); +out: + return rv; +} + +static int test_signature_digest_verify(void) +{ + return _test_signature_digest_verify(text, sizeof(text), dgst_sig, dgst_siglen); +} + +static int test_signature_cross_digest_verify(void) +{ + return _test_signature_digest_verify(text, sizeof(text), sig, siglen); +} + + #define RUNTEST(t) do { fprintf(stdout, "%s - %s\n", #t, stringify(t())); } while (0) int main(void) { + RAND_bytes(text, sizeof(text)); + sha2_256(text, sizeof(text)); + RUNTEST(test_provider); RUNTEST(test_store_load_eof); RUNTEST(test_store_get_pkey); + RUNTEST(test_signature_sign); + RUNTEST(test_signature_verify); + RUNTEST(test_signature_digest_sign_uri); + RUNTEST(test_signature_digest_verify); + RUNTEST(test_signature_cross_verify); + RUNTEST(test_signature_cross_digest_verify); } From 7fd337b112059f0df6e2f030f4889f5d5e32c658 Mon Sep 17 00:00:00 2001 From: Holger Dengler Date: Tue, 10 Mar 2026 11:50:29 +0100 Subject: [PATCH 27/36] provider: Add tls-property helpers Add the supported TLS properties of the hbkzpc provider. Signed-off-by: Holger Dengler --- src/tls.c | 85 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ src/tls.h | 10 +++++++ 2 files changed, 95 insertions(+) create mode 100644 src/tls.c create mode 100644 src/tls.h diff --git a/src/tls.c b/src/tls.c new file mode 100644 index 0000000..28f7a9f --- /dev/null +++ b/src/tls.c @@ -0,0 +1,85 @@ +// SPDX-License-Identifier: MIT +// Copyright contributors to the libzpc project +// Derived from OpenSSL source +#include +#include +#include + +#include "provider.h" +#include "ossl.h" +#include "tls.h" + +/* taken from include/internal/tlsgroups.h */ +#define OSSL_TLS_GROUP_ID_secp256r1 0x0017 +#define OSSL_TLS_GROUP_ID_secp384r1 0x0018 +#define OSSL_TLS_GROUP_ID_secp521r1 0x0019 +#define OSSL_TLS_GROUP_ID_x25519 0x001D +#define OSSL_TLS_GROUP_ID_x448 0x001E + +/* taken from providers/common/capabilities.c */ +#define TLS_GROUP_ENTRY(tlsname, realname, algorithm, idx) \ +{ \ + OSSL_PARAM_utf8_string(OSSL_CAPABILITY_TLS_GROUP_NAME, \ + tlsname, sizeof(tlsname)), \ + OSSL_PARAM_utf8_string(OSSL_CAPABILITY_TLS_GROUP_NAME_INTERNAL, \ + realname, sizeof(realname)), \ + OSSL_PARAM_utf8_string(OSSL_CAPABILITY_TLS_GROUP_ALG, \ + algorithm, sizeof(algorithm)), \ + OSSL_PARAM_uint(OSSL_CAPABILITY_TLS_GROUP_ID, \ + (unsigned int *)&group_list[idx].group_id), \ + OSSL_PARAM_uint(OSSL_CAPABILITY_TLS_GROUP_SECURITY_BITS, \ + (unsigned int *)&group_list[idx].secbits), \ + OSSL_PARAM_int(OSSL_CAPABILITY_TLS_GROUP_MIN_TLS, \ + (unsigned int *)&group_list[idx].mintls), \ + OSSL_PARAM_int(OSSL_CAPABILITY_TLS_GROUP_MAX_TLS, \ + (unsigned int *)&group_list[idx].maxtls), \ + OSSL_PARAM_int(OSSL_CAPABILITY_TLS_GROUP_MIN_DTLS, \ + (unsigned int *)&group_list[idx].mindtls), \ + OSSL_PARAM_int(OSSL_CAPABILITY_TLS_GROUP_MAX_DTLS, \ + (unsigned int *)&group_list[idx].maxdtls), \ + OSSL_PARAM_int(OSSL_CAPABILITY_TLS_GROUP_IS_KEM, \ + (unsigned int *)&group_list[idx].is_kem), \ + OSSL_PARAM_END \ +} + +typedef struct tls_group_constants_st { + unsigned int group_id; /* Group ID */ + unsigned int secbits; /* Bits of security */ + int mintls; /* Minimum TLS version, -1 unsupported */ + int maxtls; /* Maximum TLS version (or 0 for undefined) */ + int mindtls; /* Minimum DTLS version, -1 unsupported */ + int maxdtls; /* Maximum DTLS version (or 0 for undefined) */ + int is_kem; /* Indicates utility as KEM */ +} TLS_GROUP_CONSTANTS; + +static const TLS_GROUP_CONSTANTS group_list[] = { + [0] = { OSSL_TLS_GROUP_ID_secp256r1, 128, TLS1_VERSION, 0, DTLS1_VERSION, 0, 0 }, + [1] = { OSSL_TLS_GROUP_ID_secp384r1, 192, TLS1_VERSION, 0, DTLS1_VERSION, 0, 0 }, + [2] = { OSSL_TLS_GROUP_ID_secp521r1, 256, TLS1_VERSION, 0, DTLS1_VERSION, 0, 0 }, + [3] = { OSSL_TLS_GROUP_ID_x25519, 128, TLS1_VERSION, 0, DTLS1_VERSION, 0, 0 }, + [4] = { OSSL_TLS_GROUP_ID_x448, 224, TLS1_VERSION, 0, DTLS1_VERSION, 0, 0 }, +}; + +static const OSSL_PARAM tls_group_list[][11] = { + TLS_GROUP_ENTRY("secp256r1", "prime256v1", "EC", 0), + TLS_GROUP_ENTRY("P-256", "prime256v1", "EC", 0), + TLS_GROUP_ENTRY("secp384r1", "secp384r1", "EC", 1), + TLS_GROUP_ENTRY("P-384", "secp384r1", "EC", 1), + TLS_GROUP_ENTRY("secp521r1", "secp521r1", "EC", 2), + TLS_GROUP_ENTRY("P-521", "secp521r1", "EC", 2), + TLS_GROUP_ENTRY("x25519", "X25519", "X25519", 3), + TLS_GROUP_ENTRY("x448", "X448", "X448", 4), +}; + +int tls_group_capabilities(OSSL_CALLBACK *cb, void *arg) +{ + int rv = OSSL_RV_ERR; + size_t i; + + for (i = 0; i < ARRAY_SIZE(tls_group_list); i++) { + if (cb(tls_group_list[i], arg) != OSSL_RV_OK) + return OSSL_RV_ERR; + } + + return rv; +} diff --git a/src/tls.h b/src/tls.h new file mode 100644 index 0000000..3dd4c6d --- /dev/null +++ b/src/tls.h @@ -0,0 +1,10 @@ +// SPDX-License-Identifier: MIT +// Copyright contributors to the libzpc project +#ifndef _TLS_H +#define _TLS_H + +#include + +int tls_group_capabilities(OSSL_CALLBACK *cb, void *arg); + +#endif /* _TLS_H */ From 4c8295cddb761123847afd0e8066557d142f2bfa Mon Sep 17 00:00:00 2001 From: Holger Dengler Date: Tue, 10 Mar 2026 11:51:08 +0100 Subject: [PATCH 28/36] cmake: Integrate tls-property helpers Signed-off-by: Holger Dengler --- CMakeLists.txt | 1 + src/provider.c | 13 +++++++++++++ 2 files changed, 14 insertions(+) diff --git a/CMakeLists.txt b/CMakeLists.txt index 91ae326..057cedd 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -153,6 +153,7 @@ set(ZPCPROVIDER_SOURCES src/store.c src/keymgmt.c src/signature.c + src/tls.c ) add_library(zpcprovider MODULE ${ZPCPROVIDER_SOURCES}) diff --git a/src/provider.c b/src/provider.c index 970eb87..69253fa 100644 --- a/src/provider.c +++ b/src/provider.c @@ -13,6 +13,7 @@ #include "store.h" #include "keymgmt.h" #include "signature.h" +#include "tls.h" #define C(str) (void *)(str) static const OSSL_ITEM reason_strings[] = { @@ -295,6 +296,17 @@ static const OSSL_ALGORITHM *prov_query_operation(void *vpctx, int operation_id, return ops; } +static int prov_get_capabilities(void *vpctx __unused, const char *capability, + OSSL_CALLBACK *cb, void *arg) +{ + int rv = OSSL_RV_OK; + + if (OPENSSL_strcasecmp(capability, "TLS-GROUP") == 0) + rv = tls_group_capabilities(cb, arg); + + return rv; +} + static const OSSL_ITEM *prov_get_reason_strings(void *vpctx __unused) { return reason_strings; @@ -306,6 +318,7 @@ static const OSSL_DISPATCH provider_dispatch_table[] = { { OSSL_FUNC_PROVIDER_GETTABLE_PARAMS, FUNC(prov_gettable_params) }, { OSSL_FUNC_PROVIDER_GET_PARAMS, FUNC(prov_get_params) }, { OSSL_FUNC_PROVIDER_QUERY_OPERATION, FUNC(prov_query_operation) }, + { OSSL_FUNC_PROVIDER_GET_CAPABILITIES, FUNC(prov_get_capabilities) }, { OSSL_FUNC_PROVIDER_GET_REASON_STRINGS, FUNC(prov_get_reason_strings) }, { 0, NULL } #undef FUNC From 015a0a6faadda8fb5bdcd069298ab5a3f39e2ebc Mon Sep 17 00:00:00 2001 From: Holger Dengler Date: Fri, 13 Mar 2026 17:01:36 +0100 Subject: [PATCH 29/36] asn1: Add ASN.1 module (definition and functions) The ASN.1 module provides DER en-/decoding for hbkzpc-URIs. These functions are required for the decoder/encoder support. Signed-off-by: Holger Dengler --- src/asn1.c | 21 +++++++++++++++++++++ src/asn1.h | 24 ++++++++++++++++++++++++ src/asn1_gen.c.in | 10 ++++++++++ 3 files changed, 55 insertions(+) create mode 100644 src/asn1.c create mode 100644 src/asn1.h create mode 100644 src/asn1_gen.c.in diff --git a/src/asn1.c b/src/asn1.c new file mode 100644 index 0000000..ca0749f --- /dev/null +++ b/src/asn1.c @@ -0,0 +1,21 @@ +// SPDX-License-Identifier: MIT +// Copyright contributors to the libzpc project +#include "asn1.h" + +ASN1_SEQUENCE(ZPCHBK) = { + ASN1_EXP(ZPCHBK, desc, ASN1_VISIBLESTRING, 0), + ASN1_EXP(ZPCHBK, uri, ASN1_UTF8STRING, 1), +} ASN1_SEQUENCE_END(ZPCHBK); + +#include "asn1_gen.c" + +int i2d_ZPCHBK_bio(BIO *bp, const ZPCHBK *hbkp) +{ + return ASN1_i2d_bio_of(ZPCHBK, i2d_ZPCHBK, bp, hbkp); +} + +ZPCHBK *d2i_ZPCHBK_bio(BIO *bp, ZPCHBK **hbkpp) +{ + return ASN1_d2i_bio_of(ZPCHBK, ZPCHBK_new, d2i_ZPCHBK, + bp, hbkpp); +} diff --git a/src/asn1.h b/src/asn1.h new file mode 100644 index 0000000..21e91b4 --- /dev/null +++ b/src/asn1.h @@ -0,0 +1,24 @@ +// SPDX-License-Identifier: MIT +// Copyright contributors to the libzpc project +#ifndef _ASN1_H +#define _ASN1_H + +#include +#include + +#define HBKZPC_PEM_STRING "ZPC HARDWARE BACKED KEY" +#define HBKZPC_DER_DESC "HBKZPC Provider URI v1.0" + +struct zpc_hardware_backed_key_sequence_st { + ASN1_VISIBLESTRING *desc; + ASN1_UTF8STRING *uri; +}; +typedef struct zpc_hardware_backed_key_sequence_st ZPCHBK; +DECLARE_ASN1_FUNCTIONS(ZPCHBK) + +int i2d_ZPCHBK_bio(BIO *bp, const ZPCHBK *hbkp); +ZPCHBK *d2i_ZPCHBK_bio(BIO *bp, ZPCHBK **hbkpp); + +DECLARE_PEM_write_bio(ZPCHBK, ZPCHBK) +DECLARE_PEM_read_bio(ZPCHBK, ZPCHBK) +#endif /* _ASN1_H */ diff --git a/src/asn1_gen.c.in b/src/asn1_gen.c.in new file mode 100644 index 0000000..1f719c0 --- /dev/null +++ b/src/asn1_gen.c.in @@ -0,0 +1,10 @@ +// SPDX-License-Identifier: MIT +// Copyright contributors to the libzpc project +#include +#include +#include + +BEGIN: +IMPLEMENT_ASN1_FUNCTIONS(ZPCHBK) +IMPLEMENT_PEM_write_bio(ZPCHBK, ZPCHBK, HBKZPC_PEM_STRING, ZPCHBK) +IMPLEMENT_PEM_read_bio(ZPCHBK, ZPCHBK, HBKZPC_PEM_STRING, ZPCHBK) From bd4d77292b7806ecdb8267a3632b0fe5b4e5db3d Mon Sep 17 00:00:00 2001 From: Holger Dengler Date: Fri, 13 Mar 2026 17:05:25 +0100 Subject: [PATCH 30/36] cmake: ASN.1 module integration Signed-off-by: Holger Dengler --- CMakeLists.txt | 28 ++++++++++++++++++++++++++-- 1 file changed, 26 insertions(+), 2 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 057cedd..8606d03 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -142,6 +142,30 @@ install( DESTINATION ${CMAKE_INSTALL_LIBDIR}/pkgconfig ) +########################################################### +# ASN.1 + +set (ASN1_SOURCES + src/asn1.c +) + +add_custom_command( + OUTPUT asn1_gen.c + COMMAND ${CMAKE_C_COMPILER} -I${OPENSSL_INCLUDE_DIR} -x c -E ${CMAKE_SOURCE_DIR}/src/asn1_gen.c.in + | grep -v "^#" + | sed -n -e "1,/^BEGIN:$$/!p" + | clang-format --assume-filename=.c + > asn1_gen.c + MAIN_DEPENDENCY ${CMAKE_SOURCE_DIR}/src/asn1_gen.c.in + WORKING_DIRECTORY ${CMAKE_BINARY_DIR} +) +add_custom_target(asn1_gen ALL DEPENDS asn1_gen.c) + +add_library(asn1 OBJECT ${ASN1_SOURCES}) +set_property(TARGET asn1 PROPERTY POSITION_INDEPENDENT_CODE ON) +target_include_directories(asn1 PRIVATE ${OPENSSL_INCLUDE_DIR} ${CMAKE_BINARY_DIR}) +add_dependencies(asn1 asn1_gen) + ########################################################### # zpcprovider @@ -160,7 +184,7 @@ add_library(zpcprovider MODULE ${ZPCPROVIDER_SOURCES}) set_target_properties(zpcprovider PROPERTIES PREFIX "") target_include_directories(zpcprovider PRIVATE src include ${OPENSSL_INCLUDE_DIR}) -target_link_libraries(zpcprovider PRIVATE zpc OpenSSL::Crypto) +target_link_libraries(zpcprovider PRIVATE zpc OpenSSL::Crypto $) install( TARGETS zpcprovider @@ -480,7 +504,7 @@ set (ZPCPROVIDER_TEST_SOURCES add_executable(runprovidertest ${ZPCPROVIDER_TEST_SOURCES}) add_dependencies(runprovidertest zpcprovider) target_include_directories(runprovidertest PRIVATE src ${OPENSSL_INCLUDE_DIR}) -target_link_libraries(runprovidertest PRIVATE OpenSSL::Crypto) +target_link_libraries(runprovidertest PRIVATE OpenSSL::Crypto $) endif () From 6ccf5ee8c5ce37483780de535074936a25aa0191 Mon Sep 17 00:00:00 2001 From: Holger Dengler Date: Wed, 18 Mar 2026 13:54:23 +0100 Subject: [PATCH 31/36] test: Add asn.1 tests Add tests for the DER encoding. It takes the hard-coded ECDSA key and stores it as a file. Signed-off-by: Holger Dengler --- test/tprovider.c | 82 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 82 insertions(+) diff --git a/test/tprovider.c b/test/tprovider.c index 82cf1ba..c8b6bc0 100644 --- a/test/tprovider.c +++ b/test/tprovider.c @@ -1,13 +1,16 @@ // SPDX-License-Identifier: MIT // Copyright contributors to the libzpc project +#include #include #include +#include #include #include #include #include #include "ossl.h" +#include "asn1.h" #define PROVIDER "hbkzpc" #define PROP_PROVIDER "provider=" PROVIDER @@ -22,6 +25,12 @@ "6254b2b87c6ffb65a50583cea136a048" \ "8d431923" +#define HBKZPC_FILE_ECDSA_DER "ecdsa.der" +#define HBKZPC_FILE_ECDSA_PEM "ecdsa.pem" + +static const char *default_file_der = HBKZPC_FILE_ECDSA_DER; +static const char *default_file_pem = HBKZPC_FILE_ECDSA_PEM; + enum rv { PASS = 0, SKIP = 77, @@ -38,6 +47,9 @@ static size_t siglen = 0; static unsigned char *dgst_sig = NULL; static size_t dgst_siglen = 0; +static const char *file_der = NULL; +static const char *file_pem = NULL; + /* helpers */ static const char *stringify(int rv) @@ -100,6 +112,49 @@ static int sha2_256(unsigned char *in, size_t inlen) sha256, &len); } +static int uri2file(const char *uri, const char *path, bool der) +{ + int rv = OSSL_RV_ERR; + ZPCHBK *zpchbk = NULL; + BIO *bo = NULL; + + if (!uri || !path) + goto out; + + zpchbk = ZPCHBK_new(); + if (!zpchbk) { + fprintf(stderr, "Unable to create hbk\n"); + goto out; + } + + ASN1_STRING_set(zpchbk->desc, HBKZPC_DER_DESC, -1); + ASN1_STRING_set(zpchbk->uri, uri, -1); + + bo = BIO_new_file(path, "w"); + if (!bo) { + fprintf(stderr, "Unable to open file: %s\n", path); + goto out; + } + + if (der) { + if (!i2d_ZPCHBK_bio(bo, zpchbk)) { + fprintf(stderr, "Unable to write DER file %s\n", path); + goto out; + } + } else { + if (!PEM_write_bio_ZPCHBK(bo, zpchbk)) { + fprintf(stderr, "Unable to write PEM file %s\n", path); + goto out; + } + } + + rv = OSSL_RV_OK; +out: + ZPCHBK_free(zpchbk); + BIO_free(bo); + return rv; +} + /* tests */ static int test_provider(void) @@ -471,6 +526,31 @@ static int test_signature_cross_digest_verify(void) return _test_signature_digest_verify(text, sizeof(text), sig, siglen); } +static int test_uri_der_file(void) +{ + const char *uri = HBKZPC_URI_ECDSA_UV; + const char *file = default_file_der; + int rv = FAIL; + + rv = uri2file(uri, file, true) == OSSL_RV_OK ? PASS : FAIL; + if (rv == PASS) + file_der = file; + + return rv; +} + +static int test_uri_pem_file(void) +{ + const char *uri = HBKZPC_URI_ECDSA_UV; + const char *file = default_file_pem; + int rv = OSSL_RV_ERR; + + rv = uri2file(uri, file, false) == OSSL_RV_OK ? PASS : FAIL; + if (rv == PASS) + file_pem = file; + + return rv; +} #define RUNTEST(t) do { fprintf(stdout, "%s - %s\n", #t, stringify(t())); } while (0) @@ -488,4 +568,6 @@ int main(void) RUNTEST(test_signature_digest_verify); RUNTEST(test_signature_cross_verify); RUNTEST(test_signature_cross_digest_verify); + RUNTEST(test_uri_der_file); + RUNTEST(test_uri_pem_file); } From 1d2edc6451209440fcf64461d0e3aa196cbd92ee Mon Sep 17 00:00:00 2001 From: Holger Dengler Date: Sat, 14 Mar 2026 09:18:59 +0100 Subject: [PATCH 32/36] provider: Add decoders for hbkzpc-URI Add decoders for PEM and DER to support hbkzpc-URI files. Signed-off-by: Holger Dengler --- src/decoder.c | 182 ++++++++++++++++++++++++++++++++++++++++++++++++++ src/decoder.h | 10 +++ 2 files changed, 192 insertions(+) create mode 100644 src/decoder.c create mode 100644 src/decoder.h diff --git a/src/decoder.c b/src/decoder.c new file mode 100644 index 0000000..7f0696b --- /dev/null +++ b/src/decoder.c @@ -0,0 +1,182 @@ +// SPDX-License-Identifier: MIT +// Copyright contributors to the libzpc project +#include +#include +#include + +#include "store_local.h" + +#include "provider.h" +#include "decoder.h" +#include "ossl.h" +#include "asn1.h" +#include "uri.h" +#include "map.h" + +#define DECODER_DER_STRUCTURE "zpchbk" +#define DECODER_PROP_PEM PROV_PROP",input=pem" +#define DECODER_PROP_DER PROV_PROP",input=der,structure="DECODER_DER_STRUCTURE + +#define DECODER_CARRYON OSSL_RV_TRUE +#define DECODER_STOP OSSL_RV_FALSE + +struct decoder_ctx { + struct provider_ctx *pctx; +}; + +static void *dec_newctx(void *vpctx) +{ + struct provider_ctx *pctx = (struct provider_ctx *)vpctx; + struct decoder_ctx *dctx; + + if (!pctx) + return NULL; + + dctx = OPENSSL_zalloc(sizeof(struct decoder_ctx)); + if (!dctx) + return NULL; + + dctx->pctx = pctx; + return dctx; +} + +static void dec_freectx(void *vdctx) +{ + OPENSSL_free(vdctx); +} + +static int dec_pem_der_decode(void *vdctx, OSSL_CORE_BIO *in, + int selection __unused, + OSSL_CALLBACK *data_cb, void *data_cbarg, + OSSL_PASSPHRASE_CALLBACK *cb __unused, + void *cbarg __unused) +{ + char *label = NULL, *header = NULL; + struct decoder_ctx *dctx = vdctx; + unsigned char *data = NULL; + int rc = DECODER_CARRYON; + OSSL_PARAM params[3]; + long datalen; + BIO *bin; + + bin = BIO_new_from_core_bio(dctx->pctx->libctx, in); + if (!bin) + goto out; + + if (PEM_read_bio(bin, &label, &header, &data, &datalen) != OSSL_RV_OK || + strcmp (label, HBKZPC_PEM_STRING) != 0) + goto out; + + params[0] = OSSL_PARAM_construct_octet_string(OSSL_OBJECT_PARAM_DATA, + data, datalen); + params[1] = OSSL_PARAM_construct_utf8_string(OSSL_OBJECT_PARAM_DATA_STRUCTURE, + DECODER_DER_STRUCTURE, 0); + params[2] = OSSL_PARAM_construct_end(); + rc = data_cb(params, data_cbarg); +out: + OPENSSL_free(header); + OPENSSL_free(label); + OPENSSL_free(data); + BIO_free(bin); + + return rc; +} + +static int dec_der_decode(struct decoder_ctx *dctx, OSSL_CORE_BIO *in, + int selection __unused, const char *data_type, + OSSL_CALLBACK *data_cb, void *data_cbarg, + OSSL_PASSPHRASE_CALLBACK *cb, void *cbarg) +{ + const char *uri_data_type; + struct parsed_uri *puri = NULL; + int rv = DECODER_STOP; + ZPCHBK *hbk = NULL; + BIO *bin; + + bin = BIO_new_from_core_bio(dctx->pctx->libctx, in); + if (!bin) + goto out; + + if (!d2i_ZPCHBK_bio(bin, &hbk)) + goto out; + + puri = parsed_uri_new((const char *)ASN1_STRING_get0_data(hbk->uri)); + if (!puri) + goto out; + + rv = DECODER_CARRYON; + uri_data_type = alg2data_type(puri->origin_alg.value); + + if (OPENSSL_strcasecmp(data_type, uri_data_type) != 0) + goto out; + + rv = store_load_uri(dctx->pctx, puri, data_cb, data_cbarg, cb, cbarg); +out: + parsed_uri_free(puri); + OPENSSL_free(hbk); + BIO_free(bin); + return rv; +} + +static int dec_der_ec_decode(void *vdctx, OSSL_CORE_BIO *in, + int selection, + OSSL_CALLBACK *data_cb, void *data_cbarg, + OSSL_PASSPHRASE_CALLBACK *cb, void *cbarg) +{ + return dec_der_decode(vdctx, in, selection, PROV_NAME_EC, + data_cb, data_cbarg, cb, cbarg); +} + +static int dec_der_ed25519_decode(void *vdctx, OSSL_CORE_BIO *in, + int selection, + OSSL_CALLBACK *data_cb, void *data_cbarg, + OSSL_PASSPHRASE_CALLBACK *cb, void *cbarg) +{ + return dec_der_decode(vdctx, in, selection, PROV_NAME_ED25519, + data_cb, data_cbarg, cb, cbarg); +} + +static int dec_der_ed448_decode(void *vdctx, OSSL_CORE_BIO *in, + int selection, + OSSL_CALLBACK *data_cb, void *data_cbarg, + OSSL_PASSPHRASE_CALLBACK *cb, void *cbarg) +{ + return dec_der_decode(vdctx, in, selection, PROV_NAME_ED448, + data_cb, data_cbarg, cb, cbarg); +} + +static const OSSL_DISPATCH decoder_der_ec_functions[] = { + DISPATCH_DEFN(DECODER, NEWCTX, dec_newctx), + DISPATCH_DEFN(DECODER, FREECTX, dec_freectx), + DISPATCH_DEFN(DECODER, DECODE, dec_der_ec_decode), + DISPATCH_END, +}; + +static const OSSL_DISPATCH decoder_der_ed25519_functions[] = { + DISPATCH_DEFN(DECODER, NEWCTX, dec_newctx), + DISPATCH_DEFN(DECODER, FREECTX, dec_freectx), + DISPATCH_DEFN(DECODER, DECODE, dec_der_ed25519_decode), + DISPATCH_END, +}; + +static const OSSL_DISPATCH decoder_der_ed448_functions[] = { + DISPATCH_DEFN(DECODER, NEWCTX, dec_newctx), + DISPATCH_DEFN(DECODER, FREECTX, dec_freectx), + DISPATCH_DEFN(DECODER, DECODE, dec_der_ed448_decode), + DISPATCH_END, +}; + +static const OSSL_DISPATCH decoder_pem_der_functions[] = { + DISPATCH_DEFN(DECODER, NEWCTX, dec_newctx), + DISPATCH_DEFN(DECODER, FREECTX, dec_freectx), + DISPATCH_DEFN(DECODER, DECODE, dec_pem_der_decode), + DISPATCH_END, +}; + +const OSSL_ALGORITHM decoder_ops[] = { + ALGORITHM_DEFN("DER", DECODER_PROP_PEM, decoder_pem_der_functions, NULL), + ALGORITHM_DEFN(PROV_NAME_EC, DECODER_PROP_DER, decoder_der_ec_functions, NULL), + ALGORITHM_DEFN(PROV_NAME_ED25519, DECODER_PROP_DER, decoder_der_ed25519_functions, NULL), + ALGORITHM_DEFN(PROV_NAME_ED448, DECODER_PROP_DER, decoder_der_ed448_functions, NULL), + ALGORITHM_END, +}; diff --git a/src/decoder.h b/src/decoder.h new file mode 100644 index 0000000..3c40016 --- /dev/null +++ b/src/decoder.h @@ -0,0 +1,10 @@ +// SPDX-License-Identifier: MIT +// Copyright contributors to the libzpc project +#ifndef _DECODER_H +#define _DECODER_H + +#include + +extern const OSSL_ALGORITHM decoder_ops[]; + +#endif /* _DECODER_H */ From f70038acf302ac92a549f5a4a276cf1732dc99f5 Mon Sep 17 00:00:00 2001 From: Holger Dengler Date: Sat, 14 Mar 2026 09:20:46 +0100 Subject: [PATCH 33/36] cmake: Integrate decoder implementation Signed-off-by: Holger Dengler --- CMakeLists.txt | 1 + src/provider.c | 4 ++++ 2 files changed, 5 insertions(+) diff --git a/CMakeLists.txt b/CMakeLists.txt index 8606d03..b2a0571 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -178,6 +178,7 @@ set(ZPCPROVIDER_SOURCES src/keymgmt.c src/signature.c src/tls.c + src/decoder.c ) add_library(zpcprovider MODULE ${ZPCPROVIDER_SOURCES}) diff --git a/src/provider.c b/src/provider.c index 69253fa..bb92fa3 100644 --- a/src/provider.c +++ b/src/provider.c @@ -14,6 +14,7 @@ #include "keymgmt.h" #include "signature.h" #include "tls.h" +#include "decoder.h" #define C(str) (void *)(str) static const OSSL_ITEM reason_strings[] = { @@ -287,6 +288,9 @@ static const OSSL_ALGORITHM *prov_query_operation(void *vpctx, int operation_id, case OSSL_OP_SIGNATURE: ops = signature_ops; break; + case OSSL_OP_DECODER: + ops = decoder_ops; + break; default: ops = NULL; break; From 37affd176a11b4b544adce0aafc62f1fc3416188 Mon Sep 17 00:00:00 2001 From: Holger Dengler Date: Tue, 24 Mar 2026 15:38:27 +0100 Subject: [PATCH 34/36] test: Add decoder tests Add simple decoder fetch test. Signed-off-by: Holger Dengler --- test/tprovider.c | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/test/tprovider.c b/test/tprovider.c index c8b6bc0..2d943be 100644 --- a/test/tprovider.c +++ b/test/tprovider.c @@ -552,6 +552,34 @@ static int test_uri_pem_file(void) return rv; } +static int test_pem_pkey(void) +{ + EVP_PKEY *signing_key = NULL; + BIO *bin = NULL; + int rv = FAIL; + + bin = BIO_new_file(default_file_pem, "r"); + if (!bin) { + fprintf(stderr, "fail: BIO_new_file [path=%s]\n", default_file_pem); + ERR_print_errors_fp(stderr); + rv = SKIP; + goto out; + } + + signing_key = PEM_read_bio_PrivateKey(bin, &signing_key, NULL, ""); + if (!signing_key) { + fprintf(stderr, "fail: PEM_read_bio_PrivateKey [path=%s]\n", default_file_pem); + ERR_print_errors_fp(stderr); + goto out; + } + + rv = PASS; + EVP_PKEY_free(signing_key); +out: + BIO_free(bin); + return rv; +} + #define RUNTEST(t) do { fprintf(stdout, "%s - %s\n", #t, stringify(t())); } while (0) int main(void) @@ -570,4 +598,5 @@ int main(void) RUNTEST(test_signature_cross_digest_verify); RUNTEST(test_uri_der_file); RUNTEST(test_uri_pem_file); + RUNTEST(test_pem_pkey); } From d84e0c23818c3f252b5658ab2ea3447cb9c07a9a Mon Sep 17 00:00:00 2001 From: Holger Dengler Date: Wed, 8 Apr 2026 13:55:34 +0200 Subject: [PATCH 35/36] test: Add signature test (PEM) Add tests to use hbkzpc-URI file for sign/verify (instead of loading the URI via store). Signed-off-by: Holger Dengler --- test/tprovider.c | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/test/tprovider.c b/test/tprovider.c index 2d943be..c36734d 100644 --- a/test/tprovider.c +++ b/test/tprovider.c @@ -461,6 +461,33 @@ static int test_signature_digest_sign_uri(void) return rv; } +static int test_signature_digest_sign_pem(void) +{ + EVP_PKEY *signing_key = NULL; + BIO *bin = NULL; + int rv = SKIP; + + bin = BIO_new_file(default_file_pem, "r"); + if (!bin) { + fprintf(stderr, "fail: BIO_new_file [path=%s]\n", default_file_pem); + ERR_print_errors_fp(stderr); + goto out; + } + + signing_key = PEM_read_bio_PrivateKey(bin, &signing_key, NULL, ""); + if (!signing_key) { + fprintf(stderr, "fail: PEM_read_bio_PrivateKey [path=%s]\n", default_file_pem); + ERR_print_errors_fp(stderr); + goto out; + } + + rv = _test_signature_digest_sign(signing_key, "path=" HBKZPC_FILE_ECDSA_PEM); +out: + EVP_PKEY_free(signing_key); + BIO_free(bin); + return rv; +} + static int _test_signature_digest_verify(unsigned char *t, size_t tlen, unsigned char *s, size_t slen) { @@ -599,4 +626,6 @@ int main(void) RUNTEST(test_uri_der_file); RUNTEST(test_uri_pem_file); RUNTEST(test_pem_pkey); + RUNTEST(test_signature_digest_sign_pem); + RUNTEST(test_signature_digest_verify); } From ab5204ef46c4c793d7cc732e7f6435084e91ce98 Mon Sep 17 00:00:00 2001 From: Holger Dengler Date: Wed, 25 Feb 2026 07:49:18 -0500 Subject: [PATCH 36/36] WIP dbg: Add provider gdb-scripts Signed-off-by: Holger Dengler --- misc/dbg/decoder.gdb | 5 +++++ misc/dbg/kmgmt.gdb | 6 ++++++ misc/dbg/store.gdb | 12 ++++++++++++ 3 files changed, 23 insertions(+) create mode 100644 misc/dbg/decoder.gdb create mode 100644 misc/dbg/kmgmt.gdb create mode 100644 misc/dbg/store.gdb diff --git a/misc/dbg/decoder.gdb b/misc/dbg/decoder.gdb new file mode 100644 index 0000000..3d9d7d1 --- /dev/null +++ b/misc/dbg/decoder.gdb @@ -0,0 +1,5 @@ +set breakpoint pending on +break decoder_newctx +break decoder_freectx +break decoder_pem_hbkzpc_der_decode +break decoder_der_hbkzpc_ec_decode diff --git a/misc/dbg/kmgmt.gdb b/misc/dbg/kmgmt.gdb new file mode 100644 index 0000000..c08fb02 --- /dev/null +++ b/misc/dbg/kmgmt.gdb @@ -0,0 +1,6 @@ +set breakpoint pending on +break ec_new +break ec_free +break ec_load +break ec_has +# disable diff --git a/misc/dbg/store.gdb b/misc/dbg/store.gdb new file mode 100644 index 0000000..6bee834 --- /dev/null +++ b/misc/dbg/store.gdb @@ -0,0 +1,12 @@ +set breakpoint pending on +break store_ctx_init +break store_ctx_free +break store_ctx_expect +break store_open +break store_open_ex +break store_load +break store_eof +break store_close +break store_set_ctx_params +break store_settable_ctx_params +disable