diff --git a/.gitignore b/.gitignore index 28b7d6b5..9e25d028 100644 --- a/.gitignore +++ b/.gitignore @@ -92,6 +92,7 @@ tests/fork-change-slot-prov tests/rsa-oaep-prov tests/rsa-pss-sign-prov tests/rsa-keygen +tests/ec-duplicate-key tests/ec-keygen tests/ec-derive tests/ec-derive-prov diff --git a/NEWS b/NEWS index f9df1b20..2076e1fa 100644 --- a/NEWS +++ b/NEWS @@ -5,6 +5,7 @@ New in 0.4.21; unreleased As a compatibility regression, registering PKCS11_pkey_meths() directly as an ENGINE callback now leaks methods; use the bundled engine, which caches methods per ENGINE. +* Added PKCS#11 provider support for `openssl genpkey` (Małgorzata Olszówka) New in 0.4.20; 2026-08-08; Michał Trojnara * Added PKCS#11 3.2 interface discovery and updated the bundled header diff --git a/src/libp11-int.h b/src/libp11-int.h index ecde9359..aee4cbb4 100644 --- a/src/libp11-int.h +++ b/src/libp11-int.h @@ -120,6 +120,7 @@ struct pkcs11_object_private { PKCS11_SLOT_private *slot; CK_OBJECT_CLASS object_class; CK_OBJECT_HANDLE object; + CK_OBJECT_HANDLE public_object; CK_BBOOL always_authenticate; unsigned char id[255]; size_t id_len; @@ -416,48 +417,48 @@ extern int pkcs11_generate_random(PKCS11_SLOT_private *, unsigned char *r, unsig /* Generate and store a private key on the token */ extern int pkcs11_rsa_keygen(PKCS11_SLOT_private *tpriv, unsigned int bits, const char *label, const unsigned char *id, - size_t id_len, const PKCS11_params *params); + size_t id_len, const PKCS11_params *params, PKCS11_KEY **ret_key); #ifndef OPENSSL_NO_EC extern int pkcs11_ec_keygen(PKCS11_SLOT_private *tpriv, const char *curve , const char *label, const unsigned char *id, - size_t id_len, const PKCS11_params *params); + size_t id_len, const PKCS11_params *params, PKCS11_KEY **ret_key); #endif /* OPENSSL_NO_EC */ #if !defined(OPENSSL_NO_ECX) && OPENSSL_VERSION_NUMBER >= 0x30000000L extern int pkcs11_eddsa_keygen(PKCS11_SLOT_private *tpriv, int nid, const char *label, const unsigned char *id, - size_t id_len, const PKCS11_params *params); + size_t id_len, const PKCS11_params *params, PKCS11_KEY **ret_key); extern int pkcs11_xdh_keygen(PKCS11_SLOT_private *tpriv, int nid, const char *label, const unsigned char *id, - size_t id_len, const PKCS11_params *params); + size_t id_len, const PKCS11_params *params, PKCS11_KEY **ret_key); #endif /* !defined(OPENSSL_NO_ECX) && OPENSSL_VERSION_NUMBER >= 0x30000000L */ #if OPENSSL_VERSION_NUMBER >= 0x30500000L #ifndef OPENSSL_NO_ML_DSA extern int pkcs11_mldsa_keygen(PKCS11_SLOT_private *tpriv, int nid, const char *label, const unsigned char *id, - size_t id_len, const PKCS11_params *params); + size_t id_len, const PKCS11_params *params, PKCS11_KEY **ret_key); #endif /* OPENSSL_NO_ML_DSA */ #ifndef OPENSSL_NO_ML_KEM extern int pkcs11_mlkem_keygen(PKCS11_SLOT_private *tpriv, int nid, const char *label, const unsigned char *id, - size_t id_len, const PKCS11_params *params); + size_t id_len, const PKCS11_params *params, PKCS11_KEY **ret_key); #endif /* OPENSSL_NO_ML_KEM */ #ifndef OPENSSL_NO_SLH_DSA extern int pkcs11_slhdsa_keygen(PKCS11_SLOT_private *tpriv, int nid, const char *label, const unsigned char *id, - size_t id_len, const PKCS11_params *params); + size_t id_len, const PKCS11_params *params, PKCS11_KEY **ret_key); #endif /* OPENSSL_NO_SLH_DSA */ #endif /* OPENSSL_VERSION_NUMBER >= 0x30500000L */ #if OPENSSL_VERSION_NUMBER >= 0x30000000L extern int pkcs11_falcon_keygen(PKCS11_SLOT_private *tpriv, int nid, const char *label, const unsigned char *id, - size_t id_len, const PKCS11_params *params); + size_t id_len, const PKCS11_params *params, PKCS11_KEY **ret_key); #endif /* OPENSSL_VERSION_NUMBER >= 0x30000000L */ /* Get the RSA key modulus size (in bytes) */ diff --git a/src/libp11.exports b/src/libp11.exports index b87643f5..7270f532 100644 --- a/src/libp11.exports +++ b/src/libp11.exports @@ -35,6 +35,7 @@ PKCS11_init_token PKCS11_init_pin PKCS11_change_pin PKCS11_generate_key +PKCS11_generate_key_ext PKCS11_store_private_key PKCS11_store_public_key PKCS11_store_certificate diff --git a/src/libp11.h b/src/libp11.h index a7089900..c0ccaeba 100644 --- a/src/libp11.h +++ b/src/libp11.h @@ -572,6 +572,11 @@ extern int PKCS11_generate_key(PKCS11_TOKEN *token, int algorithm, unsigned int bits_or_nid, char *label, unsigned char *id, size_t id_len); +extern int PKCS11_generate_key_ext(PKCS11_TOKEN *token, + int algorithm, unsigned int bits_or_nid, + char *label, unsigned char *id, size_t id_len, + PKCS11_KEY **ret_key); + /* Get the RSA key modulus size (in bytes) */ extern int PKCS11_get_key_size(PKCS11_KEY *); diff --git a/src/p11_front.c b/src/p11_front.c index 084d69a0..9b4d3091 100644 --- a/src/p11_front.c +++ b/src/p11_front.c @@ -440,7 +440,8 @@ int PKCS11_set_ui_method(PKCS11_CTX *pctx, UI_METHOD *ui_method, void *ui_user_d /* External interface to the deprecated features */ -int PKCS11_keygen(PKCS11_TOKEN *token, PKCS11_KGEN_ATTRS *kg) +static int pkcs11_keygen_internal(PKCS11_TOKEN *token, PKCS11_KGEN_ATTRS *kg, + PKCS11_KEY **ret_key) { PKCS11_SLOT_private *slot; @@ -454,21 +455,25 @@ int PKCS11_keygen(PKCS11_TOKEN *token, PKCS11_KGEN_ATTRS *kg) switch(kg->type) { case EVP_PKEY_RSA: return pkcs11_rsa_keygen(slot, kg->kgen.rsa->bits, - kg->key_label, kg->key_id, kg->id_len, kg->key_params); + kg->key_label, kg->key_id, kg->id_len, + kg->key_params, ret_key); #ifndef OPENSSL_NO_EC case EVP_PKEY_EC: return pkcs11_ec_keygen(slot, kg->kgen.ec->curve, - kg->key_label, kg->key_id, kg->id_len, kg->key_params); + kg->key_label, kg->key_id, kg->id_len, + kg->key_params, ret_key); #endif /* OPENSSL_NO_EC */ #if !defined(OPENSSL_NO_ECX) && OPENSSL_VERSION_NUMBER >= 0x30000000L case EVP_PKEY_ED25519: case EVP_PKEY_ED448: return pkcs11_eddsa_keygen(slot, kg->kgen.nid->nid, - kg->key_label, kg->key_id, kg->id_len, kg->key_params); + kg->key_label, kg->key_id, kg->id_len, + kg->key_params, ret_key); case EVP_PKEY_X25519: case EVP_PKEY_X448: return pkcs11_xdh_keygen(slot, kg->kgen.eddsa->nid, - kg->key_label, kg->key_id, kg->id_len, kg->key_params); + kg->key_label, kg->key_id, kg->id_len, + kg->key_params, ret_key); #endif /* !defined(OPENSSL_NO_ECX) && OPENSSL_VERSION_NUMBER >= 0x30000000L */ #if OPENSSL_VERSION_NUMBER >= 0x30500000L @@ -477,7 +482,8 @@ int PKCS11_keygen(PKCS11_TOKEN *token, PKCS11_KGEN_ATTRS *kg) case EVP_PKEY_ML_DSA_65: case EVP_PKEY_ML_DSA_87: return pkcs11_mldsa_keygen(slot, kg->kgen.nid->nid, - kg->key_label, kg->key_id, kg->id_len, kg->key_params); + kg->key_label, kg->key_id, kg->id_len, + kg->key_params, ret_key); #endif /* OPENSSL_NO_ML_DSA */ #ifndef OPENSSL_NO_ML_KEM @@ -485,7 +491,8 @@ int PKCS11_keygen(PKCS11_TOKEN *token, PKCS11_KGEN_ATTRS *kg) case EVP_PKEY_ML_KEM_768: case EVP_PKEY_ML_KEM_1024: return pkcs11_mlkem_keygen(slot, kg->kgen.nid->nid, - kg->key_label, kg->key_id, kg->id_len, kg->key_params); + kg->key_label, kg->key_id, kg->id_len, + kg->key_params, ret_key); #endif /* OPENSSL_NO_ML_KEM */ #ifndef OPENSSL_NO_SLH_DSA @@ -502,7 +509,8 @@ int PKCS11_keygen(PKCS11_TOKEN *token, PKCS11_KGEN_ATTRS *kg) case EVP_PKEY_SLH_DSA_SHAKE_256S: case EVP_PKEY_SLH_DSA_SHAKE_256F: return pkcs11_slhdsa_keygen(slot, kg->kgen.nid->nid, - kg->key_label, kg->key_id, kg->id_len, kg->key_params); + kg->key_label, kg->key_id, kg->id_len, + kg->key_params, ret_key); #endif /* OPENSSL_NO_SLH_DSA */ #endif /* OPENSSL_VERSION_NUMBER >= 0x30500000L */ @@ -510,7 +518,8 @@ int PKCS11_keygen(PKCS11_TOKEN *token, PKCS11_KGEN_ATTRS *kg) case EVP_PKEY_FALCON512: case EVP_PKEY_FALCON1024: return pkcs11_falcon_keygen(slot, kg->kgen.nid->nid, - kg->key_label, kg->key_id, kg->id_len, kg->key_params); + kg->key_label, kg->key_id, kg->id_len, + kg->key_params, ret_key); #endif /* OPENSSL_VERSION_NUMBER >= 0x30000000L */ default: @@ -518,9 +527,10 @@ int PKCS11_keygen(PKCS11_TOKEN *token, PKCS11_KGEN_ATTRS *kg) } } -int PKCS11_generate_key(PKCS11_TOKEN *token, int algorithm, +int PKCS11_generate_key_ext(PKCS11_TOKEN *token, int algorithm, unsigned int param, /* bits for RSA, nid for EC, unused for EdDSA */ - char *label, unsigned char *id, size_t id_len) + char *label, unsigned char *id, size_t id_len, + PKCS11_KEY **ret_key) { PKCS11_params key_params = { .extractable = 0, .sensitive = 1 }; #ifndef OPENSSL_NO_EC @@ -532,6 +542,9 @@ int PKCS11_generate_key(PKCS11_TOKEN *token, int algorithm, PKCS11_RSA_KGEN rsa_kgen; PKCS11_KGEN_ATTRS kgen_attrs = { 0 }; + if (ret_key != NULL) + *ret_key = NULL; + switch (algorithm) { #ifndef OPENSSL_NO_EC case EVP_PKEY_EC: @@ -872,7 +885,20 @@ int PKCS11_generate_key(PKCS11_TOKEN *token, int algorithm, }; } - return PKCS11_keygen(token, &kgen_attrs); + return pkcs11_keygen_internal(token, &kgen_attrs, ret_key); +} + +int PKCS11_generate_key(PKCS11_TOKEN *token, int algorithm, + unsigned int param, char *label, + unsigned char *id, size_t id_len) +{ + return PKCS11_generate_key_ext(token, algorithm, param, + label, id, id_len, NULL); +} + +int PKCS11_keygen(PKCS11_TOKEN *token, PKCS11_KGEN_ATTRS *kg) +{ + return pkcs11_keygen_internal(token, kg, NULL); } int PKCS11_get_key_size(PKCS11_KEY *pkey) diff --git a/src/p11_key.c b/src/p11_key.c index 3c5c9263..3a27b0b2 100644 --- a/src/p11_key.c +++ b/src/p11_key.c @@ -67,6 +67,9 @@ static const unsigned char STR_X448[] = { static int pkcs11_find_keys(PKCS11_SLOT_private *, CK_SESSION_HANDLE, unsigned int, PKCS11_TEMPLATE *); +static int pkcs11_init_generated_key(PKCS11_SLOT_private *slot, + CK_SESSION_HANDLE session, CK_OBJECT_HANDLE pub_object, + CK_OBJECT_HANDLE priv_object, PKCS11_KEY **ret); static int pkcs11_init_key(PKCS11_SLOT_private *, CK_SESSION_HANDLE session, CK_OBJECT_HANDLE o, CK_OBJECT_CLASS type, PKCS11_KEY **); static int pkcs11_next_key(PKCS11_CTX_private *ctx, PKCS11_SLOT_private *, @@ -426,7 +429,27 @@ PKCS11_OBJECT_private *pkcs11_object_from_object(PKCS11_OBJECT_private *obj, CK_SESSION_HANDLE session, CK_OBJECT_CLASS object_class) { PKCS11_TEMPLATE tmpl = {0}; - PKCS11_OBJECT_private *ret; + PKCS11_OBJECT_private *ret = NULL; + int release = 0; + + if (obj->object_class == CKO_PRIVATE_KEY && + object_class == CKO_PUBLIC_KEY && + obj->public_object != CK_INVALID_HANDLE) { + if (session == CK_INVALID_HANDLE) { + if (!pkcs11_session_pool_acquire(obj->slot, 0, &session)) + release = 1; + } + + if (session != CK_INVALID_HANDLE) + ret = pkcs11_object_from_handle(obj->slot, session, + obj->public_object); + + if (release) + pkcs11_session_pool_release(obj->slot, session); + + if (ret != NULL) + return ret; + } pkcs11_addattr_var(&tmpl, CKA_CLASS, object_class); pkcs11_addattr(&tmpl, CKA_ID, obj->id, obj->id_len); @@ -502,6 +525,7 @@ int pkcs11_reload_object(PKCS11_OBJECT_private *obj) pkcs11_addattr_s(&tmpl, CKA_LABEL, obj->label); obj->object = pkcs11_handle_from_template(slot, session, &tmpl); + obj->public_object = CK_INVALID_HANDLE; pkcs11_zap_attrs(&tmpl); pkcs11_session_pool_release(slot, session); @@ -522,7 +546,7 @@ int pkcs11_reload_object(PKCS11_OBJECT_private *obj) */ int pkcs11_rsa_keygen(PKCS11_SLOT_private *slot, unsigned int bits, const char *label, const unsigned char *id, size_t id_len, - const PKCS11_params *params) + const PKCS11_params *params, PKCS11_KEY **ret_key) { PKCS11_CTX_private *ctx = slot->ctx; CK_SESSION_HANDLE session; @@ -533,7 +557,8 @@ int pkcs11_rsa_keygen(PKCS11_SLOT_private *slot, unsigned int bits, CK_ULONG num_bits = bits; CK_BYTE public_exponent[] = { 0x01, 0x00, 0x01 }; /* 65537 (0x10001) */ CK_OBJECT_HANDLE pub_key_obj, priv_key_obj; - int rv; + CK_RV rv; + int ret = 0; if (pkcs11_session_pool_acquire_keygen(slot, &session)) return -1; @@ -559,6 +584,11 @@ int pkcs11_rsa_keygen(PKCS11_SLOT_private *slot, unsigned int bits, privtmpl.attrs, privtmpl.nattr, &pub_key_obj, &priv_key_obj)); + if (rv == CKR_OK && ret_key != NULL && + pkcs11_init_generated_key(slot, session, + pub_key_obj, priv_key_obj, ret_key)) + ret = -1; + pkcs11_session_pool_release(slot, session); /* zap all memory allocated when building the template */ @@ -567,7 +597,7 @@ int pkcs11_rsa_keygen(PKCS11_SLOT_private *slot, unsigned int bits, CRYPTOKI_checkerr(CKR_F_PKCS11_GENERATE_KEY, rv); - return 0; + return ret; } #ifndef OPENSSL_NO_EC @@ -577,7 +607,7 @@ int pkcs11_rsa_keygen(PKCS11_SLOT_private *slot, unsigned int bits, */ int pkcs11_ec_keygen(PKCS11_SLOT_private *slot, const char *curve, const char *label, const unsigned char *id, size_t id_len, - const PKCS11_params *params) + const PKCS11_params *params, PKCS11_KEY **ret_key) { PKCS11_CTX_private *ctx = slot->ctx; CK_SESSION_HANDLE session; @@ -586,13 +616,17 @@ int pkcs11_ec_keygen(PKCS11_SLOT_private *slot, const char *curve, CKM_EC_KEY_PAIR_GEN, NULL_PTR, 0 }; CK_OBJECT_HANDLE pub_key_obj, priv_key_obj; - int rv; + CK_RV rv; + int ret = 0; unsigned char *ec_params = NULL; int ec_params_len = 0; unsigned char *tmp = NULL; ASN1_OBJECT *curve_obj = NULL; int curve_nid = NID_undef; + if (ret_key != NULL) + *ret_key = NULL; + if (pkcs11_session_pool_acquire_keygen(slot, &session)) return -1; @@ -603,13 +637,16 @@ int pkcs11_ec_keygen(PKCS11_SLOT_private *slot, const char *curve, curve_nid = OBJ_ln2nid(curve); if (curve_nid == NID_undef) goto error; + curve_obj = OBJ_nid2obj(curve_nid); if (!curve_obj) goto error; + /* convert to DER format and take just the length */ ec_params_len = i2d_ASN1_OBJECT(curve_obj, NULL); if (ec_params_len < 0) goto error; + ec_params = OPENSSL_malloc(ec_params_len); if (!ec_params) goto error; @@ -637,10 +674,15 @@ int pkcs11_ec_keygen(PKCS11_SLOT_private *slot, const char *curve, /* call the pkcs11 module to create the key pair */ rv = CRYPTOKI_call(ctx, C_GenerateKeyPair( - session, &mechanism, - pubtmpl.attrs, pubtmpl.nattr, - privtmpl.attrs, privtmpl.nattr, - &pub_key_obj, &priv_key_obj)); + session, &mechanism, + pubtmpl.attrs, pubtmpl.nattr, + privtmpl.attrs, privtmpl.nattr, + &pub_key_obj, &priv_key_obj)); + + if (rv == CKR_OK && ret_key != NULL && + pkcs11_init_generated_key(slot, session, + pub_key_obj, priv_key_obj, ret_key)) + ret = -1; pkcs11_session_pool_release(slot, session); @@ -651,7 +693,7 @@ int pkcs11_ec_keygen(PKCS11_SLOT_private *slot, const char *curve, OPENSSL_free(ec_params); CRYPTOKI_checkerr(CKR_F_PKCS11_GENERATE_KEY, rv); - return 0; + return ret; error: pkcs11_session_pool_release(slot, session); @@ -666,7 +708,7 @@ int pkcs11_ec_keygen(PKCS11_SLOT_private *slot, const char *curve, */ int pkcs11_eddsa_keygen(PKCS11_SLOT_private *slot, int nid, const char *label, const unsigned char *id, - size_t id_len, const PKCS11_params *params) + size_t id_len, const PKCS11_params *params, PKCS11_KEY **ret_key) { PKCS11_CTX_private *ctx = slot->ctx; CK_SESSION_HANDLE session; @@ -675,7 +717,8 @@ int pkcs11_eddsa_keygen(PKCS11_SLOT_private *slot, CKM_EC_EDWARDS_KEY_PAIR_GEN, NULL_PTR, 0 }; CK_OBJECT_HANDLE pub_key_obj, priv_key_obj; - int rv; + CK_RV rv; + int ret = 0; unsigned char *eddsa_params = NULL; size_t eddsa_params_len = 0; @@ -709,13 +752,18 @@ int pkcs11_eddsa_keygen(PKCS11_SLOT_private *slot, privtmpl.attrs, privtmpl.nattr, &pub_key_obj, &priv_key_obj)); + if (rv == CKR_OK && ret_key != NULL && + pkcs11_init_generated_key(slot, session, + pub_key_obj, priv_key_obj, ret_key)) + ret = -1; + /* cleanup */ pkcs11_session_pool_release(slot, session); pkcs11_zap_attrs(&privtmpl); pkcs11_zap_attrs(&pubtmpl); CRYPTOKI_checkerr(CKR_F_PKCS11_GENERATE_KEY, rv); - return 0; + return ret; } /** @@ -723,7 +771,7 @@ int pkcs11_eddsa_keygen(PKCS11_SLOT_private *slot, */ int pkcs11_xdh_keygen(PKCS11_SLOT_private *slot, int nid, const char *label, const unsigned char *id, - size_t id_len, const PKCS11_params *params) + size_t id_len, const PKCS11_params *params, PKCS11_KEY **ret_key) { PKCS11_CTX_private *ctx = slot->ctx; CK_SESSION_HANDLE session; @@ -732,7 +780,8 @@ int pkcs11_xdh_keygen(PKCS11_SLOT_private *slot, CKM_EC_MONTGOMERY_KEY_PAIR_GEN, NULL_PTR, 0 }; CK_OBJECT_HANDLE pub_key_obj, priv_key_obj; - int rv; + CK_RV rv; + int ret = 0; unsigned char *xdh_params = NULL; size_t xdh_params_len = 0; @@ -766,13 +815,18 @@ int pkcs11_xdh_keygen(PKCS11_SLOT_private *slot, privtmpl.attrs, privtmpl.nattr, &pub_key_obj, &priv_key_obj)); + if (rv == CKR_OK && ret_key != NULL && + pkcs11_init_generated_key(slot, session, + pub_key_obj, priv_key_obj, ret_key)) + ret = -1; + /* cleanup */ pkcs11_session_pool_release(slot, session); pkcs11_zap_attrs(&privtmpl); pkcs11_zap_attrs(&pubtmpl); CRYPTOKI_checkerr(CKR_F_PKCS11_GENERATE_KEY, rv); - return 0; + return ret; } #endif /* !defined(OPENSSL_NO_ECX) && OPENSSL_VERSION_NUMBER >= 0x30000000L */ @@ -783,7 +837,7 @@ int pkcs11_xdh_keygen(PKCS11_SLOT_private *slot, */ int pkcs11_mldsa_keygen(PKCS11_SLOT_private *slot, int nid, const char *label, const unsigned char *id, - size_t id_len, const PKCS11_params *params) + size_t id_len, const PKCS11_params *params, PKCS11_KEY **ret_key) { PKCS11_CTX_private *ctx = slot->ctx; CK_SESSION_HANDLE session; @@ -794,6 +848,7 @@ int pkcs11_mldsa_keygen(PKCS11_SLOT_private *slot, CK_ULONG signParamSet = 0; CK_OBJECT_HANDLE pub_key_obj, priv_key_obj; CK_RV rv; + int ret = 0; if (pkcs11_session_pool_acquire_keygen(slot, &session)) return -1; @@ -857,13 +912,18 @@ int pkcs11_mldsa_keygen(PKCS11_SLOT_private *slot, &pub_key_obj, &priv_key_obj)); } + if (rv == CKR_OK && ret_key != NULL && + pkcs11_init_generated_key(slot, session, + pub_key_obj, priv_key_obj, ret_key)) + ret = -1; + /* cleanup */ pkcs11_session_pool_release(slot, session); pkcs11_zap_attrs(&privtmpl); pkcs11_zap_attrs(&pubtmpl); CRYPTOKI_checkerr(CKR_F_PKCS11_GENERATE_KEY, rv); - return 0; + return ret; } #endif /* OPENSSL_NO_ML_DSA */ @@ -874,7 +934,7 @@ int pkcs11_mldsa_keygen(PKCS11_SLOT_private *slot, */ int pkcs11_mlkem_keygen(PKCS11_SLOT_private *slot, int nid, const char *label, const unsigned char *id, size_t id_len, - const PKCS11_params *params) + const PKCS11_params *params, PKCS11_KEY **ret_key) { PKCS11_CTX_private *ctx = slot->ctx; CK_SESSION_HANDLE session; @@ -885,6 +945,7 @@ int pkcs11_mlkem_keygen(PKCS11_SLOT_private *slot, int nid, CK_ML_KEM_PARAMETER_SET_TYPE kemParamSet = 0; CK_OBJECT_HANDLE pub_key_obj, priv_key_obj; CK_RV rv; + int ret = 0; if (pkcs11_session_pool_acquire_keygen(slot, &session)) return -1; @@ -948,13 +1009,18 @@ int pkcs11_mlkem_keygen(PKCS11_SLOT_private *slot, int nid, &pub_key_obj, &priv_key_obj)); } + if (rv == CKR_OK && ret_key != NULL && + pkcs11_init_generated_key(slot, session, + pub_key_obj, priv_key_obj, ret_key)) + ret = -1; + /* cleanup */ pkcs11_session_pool_release(slot, session); pkcs11_zap_attrs(&privtmpl); pkcs11_zap_attrs(&pubtmpl); CRYPTOKI_checkerr(CKR_F_PKCS11_GENERATE_KEY, rv); - return 0; + return ret; } #endif /* OPENSSL_NO_ML_KEM */ @@ -964,7 +1030,7 @@ int pkcs11_mlkem_keygen(PKCS11_SLOT_private *slot, int nid, */ int pkcs11_slhdsa_keygen(PKCS11_SLOT_private *slot, int nid, const char *label, const unsigned char *id, - size_t id_len, const PKCS11_params *params) + size_t id_len, const PKCS11_params *params, PKCS11_KEY **ret_key) { PKCS11_CTX_private *ctx = slot->ctx; CK_SESSION_HANDLE session; @@ -975,6 +1041,7 @@ int pkcs11_slhdsa_keygen(PKCS11_SLOT_private *slot, CK_ULONG signParamSet = 0; CK_OBJECT_HANDLE pub_key_obj, priv_key_obj; CK_RV rv; + int ret = 0; if (pkcs11_session_pool_acquire_keygen(slot, &session)) return -1; @@ -1038,13 +1105,18 @@ int pkcs11_slhdsa_keygen(PKCS11_SLOT_private *slot, privtmpl.attrs, privtmpl.nattr, &pub_key_obj, &priv_key_obj)); + if (rv == CKR_OK && ret_key != NULL && + pkcs11_init_generated_key(slot, session, + pub_key_obj, priv_key_obj, ret_key)) + ret = -1; + /* cleanup */ pkcs11_session_pool_release(slot, session); pkcs11_zap_attrs(&privtmpl); pkcs11_zap_attrs(&pubtmpl); CRYPTOKI_checkerr(CKR_F_PKCS11_GENERATE_KEY, rv); - return 0; + return ret; } #endif /* OPENSSL_NO_SLH_DSA */ #endif /* OPENSSL_VERSION_NUMBER >= 0x30500000L */ @@ -1055,7 +1127,7 @@ int pkcs11_slhdsa_keygen(PKCS11_SLOT_private *slot, */ int pkcs11_falcon_keygen(PKCS11_SLOT_private *slot, int nid, const char *label, const unsigned char *id, - size_t id_len, const PKCS11_params *params) + size_t id_len, const PKCS11_params *params, PKCS11_KEY **ret_key) { PKCS11_CTX_private *ctx = slot->ctx; CK_SESSION_HANDLE session; @@ -1068,6 +1140,7 @@ int pkcs11_falcon_keygen(PKCS11_SLOT_private *slot, CK_ULONG signParamSet = 0; CK_OBJECT_HANDLE pub_key_obj, priv_key_obj; CK_RV rv; + int ret = 0; if (pkcs11_session_pool_acquire_keygen(slot, &session)) return -1; @@ -1098,13 +1171,18 @@ int pkcs11_falcon_keygen(PKCS11_SLOT_private *slot, privtmpl.attrs, privtmpl.nattr, &pub_key_obj, &priv_key_obj)); + if (rv == CKR_OK && ret_key != NULL && + pkcs11_init_generated_key(slot, session, + pub_key_obj, priv_key_obj, ret_key)) + ret = -1; + /* cleanup */ pkcs11_session_pool_release(slot, session); pkcs11_zap_attrs(&privtmpl); pkcs11_zap_attrs(&pubtmpl); CRYPTOKI_checkerr(CKR_F_PKCS11_GENERATE_KEY, rv); - return 0; + return ret; } #endif /* OPENSSL_VERSION_NUMBER >= 0x30000000L */ @@ -1502,6 +1580,25 @@ PKCS11_OBJECT_private *pkcs11_object_ref(PKCS11_OBJECT_private *obj) return obj; } +static int pkcs11_init_generated_key(PKCS11_SLOT_private *slot, + CK_SESSION_HANDLE session, CK_OBJECT_HANDLE pub_object, + CK_OBJECT_HANDLE priv_object, PKCS11_KEY **ret) +{ + PKCS11_KEY *priv = NULL; + + if (ret == NULL) + return 0; + + if (pkcs11_init_key(slot, session, priv_object, + CKO_PRIVATE_KEY, &priv)) + return -1; + + priv->_private->public_object = pub_object; + + *ret = priv; + return 0; +} + static int pkcs11_init_key(PKCS11_SLOT_private *slot, CK_SESSION_HANDLE session, CK_OBJECT_HANDLE object, CK_OBJECT_CLASS type, PKCS11_KEY **ret) { diff --git a/src/provider.c b/src/provider.c index 872b8769..9330907b 100644 --- a/src/provider.c +++ b/src/provider.c @@ -73,6 +73,9 @@ PROVIDER_FN(keymgmt_export_types); PROVIDER_FN(keymgmt_get_params); PROVIDER_FN(keymgmt_gettable_params); PROVIDER_FN(keymgmt_dup); +PROVIDER_FN(keymgmt_gen_set_params); +PROVIDER_FN(keymgmt_gen); +PROVIDER_FN(keymgmt_gen_cleanup); PROVIDER_FN(signature_newctx); PROVIDER_FN(signature_freectx); @@ -152,23 +155,6 @@ static const OSSL_DISPATCH provider_functions[] = { OSSL_DISPATCH_END }; -static const OSSL_DISPATCH keymgmt_functions[] = { - {OSSL_FUNC_KEYMGMT_NEW, (void (*)(void))keymgmt_new}, - {OSSL_FUNC_KEYMGMT_LOAD, (void (*)(void))keymgmt_load}, - {OSSL_FUNC_KEYMGMT_FREE, (void (*)(void))keymgmt_free}, - {OSSL_FUNC_KEYMGMT_HAS, (void (*)(void))keymgmt_has}, - {OSSL_FUNC_KEYMGMT_MATCH, (void (*)(void))keymgmt_match}, - {OSSL_FUNC_KEYMGMT_QUERY_OPERATION_NAME, (void (*)(void))keymgmt_query_operation_name}, - {OSSL_FUNC_KEYMGMT_IMPORT, (void (*)(void))keymgmt_import}, - {OSSL_FUNC_KEYMGMT_IMPORT_TYPES, (void (*)(void))keymgmt_import_types}, - {OSSL_FUNC_KEYMGMT_EXPORT, (void (*)(void))keymgmt_export}, - {OSSL_FUNC_KEYMGMT_EXPORT_TYPES, (void (*)(void))keymgmt_export_types}, - {OSSL_FUNC_KEYMGMT_GET_PARAMS, (void (*)(void))keymgmt_get_params}, - {OSSL_FUNC_KEYMGMT_GETTABLE_PARAMS, (void (*)(void))keymgmt_gettable_params}, - {OSSL_FUNC_KEYMGMT_DUP, (void (*)(void))keymgmt_dup}, - OSSL_DISPATCH_END -}; - static const OSSL_DISPATCH signature_functions[] = { {OSSL_FUNC_SIGNATURE_NEWCTX, (void (*)(void))signature_newctx}, {OSSL_FUNC_SIGNATURE_FREECTX, (void (*)(void))signature_freectx}, @@ -248,60 +234,213 @@ static const OSSL_DISPATCH store_functions[] = { OSSL_DISPATCH_END }; -/* Keymgmt algorithms: must be real key types (e.g. RSA, EC), not provider names */ +#define KEYMGMT_COMMON_DISPATCH \ + {OSSL_FUNC_KEYMGMT_NEW, (void (*)(void))keymgmt_new}, \ + {OSSL_FUNC_KEYMGMT_LOAD, (void (*)(void))keymgmt_load}, \ + {OSSL_FUNC_KEYMGMT_FREE, (void (*)(void))keymgmt_free}, \ + {OSSL_FUNC_KEYMGMT_HAS, (void (*)(void))keymgmt_has}, \ + {OSSL_FUNC_KEYMGMT_MATCH, (void (*)(void))keymgmt_match}, \ + {OSSL_FUNC_KEYMGMT_QUERY_OPERATION_NAME, \ + (void (*)(void))keymgmt_query_operation_name}, \ + {OSSL_FUNC_KEYMGMT_IMPORT, (void (*)(void))keymgmt_import}, \ + {OSSL_FUNC_KEYMGMT_IMPORT_TYPES, \ + (void (*)(void))keymgmt_import_types}, \ + {OSSL_FUNC_KEYMGMT_EXPORT, (void (*)(void))keymgmt_export}, \ + {OSSL_FUNC_KEYMGMT_EXPORT_TYPES, \ + (void (*)(void))keymgmt_export_types}, \ + {OSSL_FUNC_KEYMGMT_GET_PARAMS, \ + (void (*)(void))keymgmt_get_params}, \ + {OSSL_FUNC_KEYMGMT_GETTABLE_PARAMS, \ + (void (*)(void))keymgmt_gettable_params}, \ + {OSSL_FUNC_KEYMGMT_DUP, (void (*)(void))keymgmt_dup} + +#define KEYMGMT_GEN_DISPATCH(gen_init, gen_settable) \ + {OSSL_FUNC_KEYMGMT_GEN_INIT, (void (*)(void))(gen_init)}, \ + {OSSL_FUNC_KEYMGMT_GEN_SET_PARAMS, \ + (void (*)(void))keymgmt_gen_set_params}, \ + {OSSL_FUNC_KEYMGMT_GEN_SETTABLE_PARAMS, \ + (void (*)(void))(gen_settable)}, \ + {OSSL_FUNC_KEYMGMT_GEN, (void (*)(void))keymgmt_gen}, \ + {OSSL_FUNC_KEYMGMT_GEN_CLEANUP, \ + (void (*)(void))keymgmt_gen_cleanup} + +static OSSL_FUNC_keymgmt_gen_settable_params_fn rsa_keymgmt_gen_settable_params; + +#ifndef OPENSSL_NO_EC +static OSSL_FUNC_keymgmt_gen_settable_params_fn ec_keymgmt_gen_settable_params; +#endif /* OPENSSL_NO_EC */ + +static OSSL_FUNC_keymgmt_gen_settable_params_fn common_keymgmt_gen_settable_params; + +static void *keymgmt_gen_init_common(void *provctx, int type, + int selection, const OSSL_PARAM params[]); + +#define DEFINE_KEYMGMT_FUNCTIONS(name, type, gen_settable) \ + static void *name##_keymgmt_gen_init(void *provctx, int selection, \ + const OSSL_PARAM params[]) \ + { \ + return keymgmt_gen_init_common(provctx, type, selection, params); \ + } \ + static const OSSL_DISPATCH name##_keymgmt_functions[] = { \ + KEYMGMT_COMMON_DISPATCH, \ + KEYMGMT_GEN_DISPATCH(name##_keymgmt_gen_init, gen_settable), \ + OSSL_DISPATCH_END \ + }; + +DEFINE_KEYMGMT_FUNCTIONS(rsa, EVP_PKEY_RSA, rsa_keymgmt_gen_settable_params) + +#ifndef OPENSSL_NO_EC +DEFINE_KEYMGMT_FUNCTIONS(ec, EVP_PKEY_EC, ec_keymgmt_gen_settable_params) +#endif /* OPENSSL_NO_EC */ + +#ifndef OPENSSL_NO_ECX +DEFINE_KEYMGMT_FUNCTIONS(ed25519, EVP_PKEY_ED25519, + common_keymgmt_gen_settable_params) +DEFINE_KEYMGMT_FUNCTIONS(ed448, EVP_PKEY_ED448, + common_keymgmt_gen_settable_params) +DEFINE_KEYMGMT_FUNCTIONS(x25519, EVP_PKEY_X25519, + common_keymgmt_gen_settable_params) +DEFINE_KEYMGMT_FUNCTIONS(x448, EVP_PKEY_X448, + common_keymgmt_gen_settable_params) +#endif /* OPENSSL_NO_ECX */ + +#if OPENSSL_VERSION_NUMBER >= 0x30500000L +#ifndef OPENSSL_NO_ML_DSA +DEFINE_KEYMGMT_FUNCTIONS(mldsa44, EVP_PKEY_ML_DSA_44, + common_keymgmt_gen_settable_params) +DEFINE_KEYMGMT_FUNCTIONS(mldsa65, EVP_PKEY_ML_DSA_65, + common_keymgmt_gen_settable_params) +DEFINE_KEYMGMT_FUNCTIONS(mldsa87, EVP_PKEY_ML_DSA_87, + common_keymgmt_gen_settable_params) +#endif /* OPENSSL_NO_ML_DSA */ + +#ifndef OPENSSL_NO_ML_KEM +DEFINE_KEYMGMT_FUNCTIONS(mlkem512, EVP_PKEY_ML_KEM_512, + common_keymgmt_gen_settable_params) +DEFINE_KEYMGMT_FUNCTIONS(mlkem768, EVP_PKEY_ML_KEM_768, + common_keymgmt_gen_settable_params) +DEFINE_KEYMGMT_FUNCTIONS(mlkem1024, EVP_PKEY_ML_KEM_1024, + common_keymgmt_gen_settable_params) +#endif /* OPENSSL_NO_ML_KEM */ + +#ifndef OPENSSL_NO_SLH_DSA +DEFINE_KEYMGMT_FUNCTIONS(slhdsa_sha2_128s, EVP_PKEY_SLH_DSA_SHA2_128S, + common_keymgmt_gen_settable_params) +DEFINE_KEYMGMT_FUNCTIONS(slhdsa_sha2_128f, EVP_PKEY_SLH_DSA_SHA2_128F, + common_keymgmt_gen_settable_params) +DEFINE_KEYMGMT_FUNCTIONS(slhdsa_sha2_192s, EVP_PKEY_SLH_DSA_SHA2_192S, + common_keymgmt_gen_settable_params) +DEFINE_KEYMGMT_FUNCTIONS(slhdsa_sha2_192f, EVP_PKEY_SLH_DSA_SHA2_192F, + common_keymgmt_gen_settable_params) +DEFINE_KEYMGMT_FUNCTIONS(slhdsa_sha2_256s, EVP_PKEY_SLH_DSA_SHA2_256S, + common_keymgmt_gen_settable_params) +DEFINE_KEYMGMT_FUNCTIONS(slhdsa_sha2_256f, EVP_PKEY_SLH_DSA_SHA2_256F, + common_keymgmt_gen_settable_params) + +DEFINE_KEYMGMT_FUNCTIONS(slhdsa_shake_128s, EVP_PKEY_SLH_DSA_SHAKE_128S, + common_keymgmt_gen_settable_params) +DEFINE_KEYMGMT_FUNCTIONS(slhdsa_shake_128f, EVP_PKEY_SLH_DSA_SHAKE_128F, + common_keymgmt_gen_settable_params) +DEFINE_KEYMGMT_FUNCTIONS(slhdsa_shake_192s, EVP_PKEY_SLH_DSA_SHAKE_192S, + common_keymgmt_gen_settable_params) +DEFINE_KEYMGMT_FUNCTIONS(slhdsa_shake_192f, EVP_PKEY_SLH_DSA_SHAKE_192F, + common_keymgmt_gen_settable_params) +DEFINE_KEYMGMT_FUNCTIONS(slhdsa_shake_256s, EVP_PKEY_SLH_DSA_SHAKE_256S, + common_keymgmt_gen_settable_params) +DEFINE_KEYMGMT_FUNCTIONS(slhdsa_shake_256f, EVP_PKEY_SLH_DSA_SHAKE_256F, + common_keymgmt_gen_settable_params) +#endif /* OPENSSL_NO_SLH_DSA */ +#endif /* OPENSSL_VERSION_NUMBER >= 0x30500000L */ + +DEFINE_KEYMGMT_FUNCTIONS(falcon512, EVP_PKEY_FALCON512, + common_keymgmt_gen_settable_params) +DEFINE_KEYMGMT_FUNCTIONS(falcon1024, EVP_PKEY_FALCON1024, + common_keymgmt_gen_settable_params) + + +/* + * Keymgmt algorithms: must be real key types (e.g. RSA, EC), not provider names. + */ static const OSSL_ALGORITHM p11_keymgmts[] = { - {"RSA:rsaEncryption", FIPS_PROPQ, keymgmt_functions, "PKCS#11 RSA keymgm functions"}, + {"RSA:rsaEncryption", FIPS_PROPQ, rsa_keymgmt_functions, + "PKCS#11 RSA keymgm functions"}, #ifndef OPENSSL_NO_EC - {"EC:id-ecPublicKey", FIPS_PROPQ, keymgmt_functions, "PKCS#11 EC keymgm functions"}, - {"ECDH", FIPS_PROPQ, keymgmt_functions, "PKCS#11 key exchange functions"}, + {"EC:id-ecPublicKey", FIPS_PROPQ, ec_keymgmt_functions, + "PKCS#11 EC keymgm functions"}, + {"ECDH", FIPS_PROPQ, ec_keymgmt_functions, + "PKCS#11 key exchange functions"}, #endif /* OPENSSL_NO_EC */ #ifndef OPENSSL_NO_ECX - {"ED25519", FIPS_PROPQ, keymgmt_functions, "PKCS#11 Ed25519 keymgm functions"}, - {"ED448", FIPS_PROPQ, keymgmt_functions, "PKCS#11 Ed448 keymgm functions"}, - {"X25519", FIPS_PROPQ, keymgmt_functions, "PKCS#11 X25519 keymgm functions"}, - {"X448", FIPS_PROPQ, keymgmt_functions, "PKCS#11 X448 keymgm functions"}, + {"ED25519", FIPS_PROPQ, ed25519_keymgmt_functions, + "PKCS#11 Ed25519 keymgm functions"}, + {"ED448", FIPS_PROPQ, ed448_keymgmt_functions, + "PKCS#11 Ed448 keymgm functions"}, + {"X25519", FIPS_PROPQ, x25519_keymgmt_functions, + "PKCS#11 X25519 keymgm functions"}, + {"X448", FIPS_PROPQ, x448_keymgmt_functions, + "PKCS#11 X448 keymgm functions"}, #endif /* OPENSSL_NO_ECX */ #if OPENSSL_VERSION_NUMBER >= 0x30500000L #ifndef OPENSSL_NO_ML_DSA - {"ML-DSA-44", FIPS_PROPQ, keymgmt_functions, "PKCS#11 ML-DSA-44 keymgmt functions"}, - {"ML-DSA-65", FIPS_PROPQ, keymgmt_functions, "PKCS#11 ML-DSA-65 keymgmt functions"}, - {"ML-DSA-87", FIPS_PROPQ, keymgmt_functions, "PKCS#11 ML-DSA-87 keymgmt functions"}, + {"ML-DSA-44", FIPS_PROPQ, mldsa44_keymgmt_functions, + "PKCS#11 ML-DSA-44 keymgmt functions"}, + {"ML-DSA-65", FIPS_PROPQ, mldsa65_keymgmt_functions, + "PKCS#11 ML-DSA-65 keymgmt functions"}, + {"ML-DSA-87", FIPS_PROPQ, mldsa87_keymgmt_functions, + "PKCS#11 ML-DSA-87 keymgmt functions"}, #endif /* OPENSSL_NO_ML_DSA */ #ifndef OPENSSL_NO_ML_KEM - {"ML-KEM-512", FIPS_PROPQ, keymgmt_functions, "PKCS#11 ML-KEM-512 keymgmt functions"}, - {"ML-KEM-768", FIPS_PROPQ, keymgmt_functions, "PKCS#11 ML-KEM-768 keymgmt functions"}, - {"ML-KEM-1024", FIPS_PROPQ, keymgmt_functions, "PKCS#11 ML-KEM-1024 keymgmt functions"}, + {"ML-KEM-512", FIPS_PROPQ, mlkem512_keymgmt_functions, + "PKCS#11 ML-KEM-512 keymgmt functions"}, + {"ML-KEM-768", FIPS_PROPQ, mlkem768_keymgmt_functions, + "PKCS#11 ML-KEM-768 keymgmt functions"}, + {"ML-KEM-1024", FIPS_PROPQ, mlkem1024_keymgmt_functions, + "PKCS#11 ML-KEM-1024 keymgmt functions"}, #endif /* OPENSSL_NO_ML_KEM */ #ifndef OPENSSL_NO_SLH_DSA - {"SLH-DSA-SHA2-128s", FIPS_PROPQ, keymgmt_functions, + {"SLH-DSA-SHA2-128s", FIPS_PROPQ, + slhdsa_sha2_128s_keymgmt_functions, "PKCS#11 SLH-DSA-SHA2-128s keymgmt functions"}, - {"SLH-DSA-SHA2-128f", FIPS_PROPQ, keymgmt_functions, + {"SLH-DSA-SHA2-128f", FIPS_PROPQ, + slhdsa_sha2_128f_keymgmt_functions, "PKCS#11 SLH-DSA-SHA2-128f keymgmt functions"}, - {"SLH-DSA-SHA2-192s", FIPS_PROPQ, keymgmt_functions, + {"SLH-DSA-SHA2-192s", FIPS_PROPQ, + slhdsa_sha2_192s_keymgmt_functions, "PKCS#11 SLH-DSA-SHA2-192s keymgmt functions"}, - {"SLH-DSA-SHA2-192f", FIPS_PROPQ, keymgmt_functions, + {"SLH-DSA-SHA2-192f", FIPS_PROPQ, + slhdsa_sha2_192f_keymgmt_functions, "PKCS#11 SLH-DSA-SHA2-192f keymgmt functions"}, - {"SLH-DSA-SHA2-256s", FIPS_PROPQ, keymgmt_functions, + {"SLH-DSA-SHA2-256s", FIPS_PROPQ, + slhdsa_sha2_256s_keymgmt_functions, "PKCS#11 SLH-DSA-SHA2-256s keymgmt functions"}, - {"SLH-DSA-SHA2-256f", FIPS_PROPQ, keymgmt_functions, + {"SLH-DSA-SHA2-256f", FIPS_PROPQ, + slhdsa_sha2_256f_keymgmt_functions, "PKCS#11 SLH-DSA-SHA2-256f keymgmt functions"}, - {"SLH-DSA-SHAKE-128s", FIPS_PROPQ, keymgmt_functions, + {"SLH-DSA-SHAKE-128s", FIPS_PROPQ, + slhdsa_shake_128s_keymgmt_functions, "PKCS#11 SLH-DSA-SHAKE-128s keymgmt functions"}, - {"SLH-DSA-SHAKE-128f", FIPS_PROPQ, keymgmt_functions, + {"SLH-DSA-SHAKE-128f", FIPS_PROPQ, + slhdsa_shake_128f_keymgmt_functions, "PKCS#11 SLH-DSA-SHAKE-128f keymgmt functions"}, - {"SLH-DSA-SHAKE-192s", FIPS_PROPQ, keymgmt_functions, + {"SLH-DSA-SHAKE-192s", FIPS_PROPQ, + slhdsa_shake_192s_keymgmt_functions, "PKCS#11 SLH-DSA-SHAKE-192s keymgmt functions"}, - {"SLH-DSA-SHAKE-192f", FIPS_PROPQ, keymgmt_functions, + {"SLH-DSA-SHAKE-192f", FIPS_PROPQ, + slhdsa_shake_192f_keymgmt_functions, "PKCS#11 SLH-DSA-SHAKE-192f keymgmt functions"}, - {"SLH-DSA-SHAKE-256s", FIPS_PROPQ, keymgmt_functions, + {"SLH-DSA-SHAKE-256s", FIPS_PROPQ, + slhdsa_shake_256s_keymgmt_functions, "PKCS#11 SLH-DSA-SHAKE-256s keymgmt functions"}, - {"SLH-DSA-SHAKE-256f", FIPS_PROPQ, keymgmt_functions, + {"SLH-DSA-SHAKE-256f", FIPS_PROPQ, + slhdsa_shake_256f_keymgmt_functions, "PKCS#11 SLH-DSA-SHAKE-256f keymgmt functions"}, #endif /* OPENSSL_NO_SLH_DSA */ #endif /* OPENSSL_VERSION_NUMBER >= 0x30500000L */ - {"FALCON-512:FN-DSA-512:falcon512", FIPS_PROPQ, keymgmt_functions, + {"FALCON-512:FN-DSA-512:falcon512", FIPS_PROPQ, + falcon512_keymgmt_functions, "PKCS#11 Falcon-512 keymgmt"}, - {"FALCON-1024:FN-DSA-1024:falcon1024", FIPS_PROPQ, keymgmt_functions, + {"FALCON-1024:FN-DSA-1024:falcon1024", FIPS_PROPQ, + falcon1024_keymgmt_functions, "PKCS#11 Falcon-1024 keymgmt"}, {NULL, NULL, NULL, NULL} }; @@ -808,6 +947,83 @@ static void *keymgmt_dup(const void *provkey, int selection) return keydata; } +/* + * KEYMGMT generation initialization needs to know the concrete key type. + * The remaining KEYMGMT callbacks are shared by all supported algorithms. + */ +static void *keymgmt_gen_init_common(void *provctx, int type, + int selection, const OSSL_PARAM params[]) +{ + if ((selection & OSSL_KEYMGMT_SELECT_KEYPAIR) == 0) + return NULL; + + return p11_keygen_ctx_new(provctx, type, params); +} + +/* Set additional parameters from params in the key object generation context genctx. */ +int keymgmt_gen_set_params(void *genctx, const OSSL_PARAM params[]) +{ + return p11_keygen_ctx_set_params(genctx, params); +} + +static const OSSL_PARAM *rsa_keymgmt_gen_settable_params( + void *genctx, void *provctx) +{ + static const OSSL_PARAM keymgmt_gen_settable_rsa[] = { + OSSL_PARAM_utf8_string("pkcs11_uri", NULL, 0), + OSSL_PARAM_uint(OSSL_PKEY_PARAM_RSA_BITS, NULL), + OSSL_PARAM_END + }; + (void)genctx; + (void)provctx; + + return keymgmt_gen_settable_rsa; +} + +#ifndef OPENSSL_NO_EC +static const OSSL_PARAM *ec_keymgmt_gen_settable_params( + void *genctx, void *provctx) +{ + static const OSSL_PARAM keymgmt_gen_settable_ec[] = { + OSSL_PARAM_utf8_string("pkcs11_uri", NULL, 0), + OSSL_PARAM_utf8_string(OSSL_PKEY_PARAM_GROUP_NAME, NULL, 0), + OSSL_PARAM_END + }; + + (void)genctx; + (void)provctx; + + return keymgmt_gen_settable_ec; +} +#endif /* OPENSSL_NO_EC */ + +static const OSSL_PARAM *common_keymgmt_gen_settable_params( + void *genctx, void *provctx) +{ + static const OSSL_PARAM keymgmt_gen_settable_common[] = { + OSSL_PARAM_utf8_string("pkcs11_uri", NULL, 0), + OSSL_PARAM_END + }; + (void)genctx; + (void)provctx; + + return keymgmt_gen_settable_common; +} + +/* Perform the key object generation itself, and return the result. */ +void *keymgmt_gen(void *genctx, OSSL_CALLBACK *cb, void *cbarg) +{ + (void)cb; + (void)cbarg; + return p11_keygen_ctx_generate(genctx); +} + +/* Clean up and free the key object generation context. */ +void keymgmt_gen_cleanup(void *genctx) +{ + p11_keygen_ctx_free(genctx); +} + /******************************************************************************/ /* Signature functions */ /******************************************************************************/ diff --git a/src/provider_helpers.c b/src/provider_helpers.c index 888043b7..7d14228f 100644 --- a/src/provider_helpers.c +++ b/src/provider_helpers.c @@ -182,6 +182,13 @@ struct p11_keydata_st { P11_PUBDATA pubdata; }; +struct p11_keygen_ctx { + PROVIDER_CTX *prov_ctx; + int type; + char *uri; + unsigned int param; /* bits for RSA, nid for EC, unused for others */ +}; + struct p11_store_ctx_st { PROVIDER_CTX *prov_ctx; char *uri; @@ -969,6 +976,125 @@ int keydata_export_pub(P11_KEYDATA *keydata, OSSL_CALLBACK *param_cb, void *cbar return export_raw_pub(keydata, param_cb, cbarg); } +/******************************************************************************/ +/* KEY GENERATION helper functions */ +/******************************************************************************/ + +P11_KEYGEN_CTX *p11_keygen_ctx_new(PROVIDER_CTX *prov_ctx, int type, + const OSSL_PARAM params[]) +{ + P11_KEYGEN_CTX *gen_ctx; + + if (prov_ctx == NULL) + return NULL; + + if (!PROVIDER_CTX_is_initialized(prov_ctx)) { + if (!PROVIDER_CTX_set_parameters(prov_ctx)) + return NULL; + PROVIDER_CTX_initialize(prov_ctx); + } + + gen_ctx = OPENSSL_zalloc(sizeof(P11_KEYGEN_CTX)); + if (gen_ctx == NULL) + return NULL; + + gen_ctx->prov_ctx = prov_ctx; + gen_ctx->type = type; + if (type == EVP_PKEY_RSA) + gen_ctx->param = 2048; + + if (!p11_keygen_ctx_set_params(gen_ctx, params)) { + p11_keygen_ctx_free(gen_ctx); + return NULL; + } + return gen_ctx; +} + +void p11_keygen_ctx_free(P11_KEYGEN_CTX *gen_ctx) +{ + if (gen_ctx == NULL) + return; + + OPENSSL_free(gen_ctx->uri); + OPENSSL_free(gen_ctx); +} + +int p11_keygen_ctx_set_params(P11_KEYGEN_CTX *gen_ctx, const OSSL_PARAM params[]) +{ + const OSSL_PARAM *p; + + if (gen_ctx == NULL) + return 0; + + if (params == NULL) + return 1; + + p = OSSL_PARAM_locate_const(params, "pkcs11_uri"); + if (p != NULL) { + char *uri = NULL; + + if (!OSSL_PARAM_get_utf8_string(p, &uri, 0)) + return 0; + + OPENSSL_free(gen_ctx->uri); + gen_ctx->uri = uri; + } + + switch (gen_ctx->type) { + case EVP_PKEY_RSA: + p = OSSL_PARAM_locate_const(params, OSSL_PKEY_PARAM_BITS); + if (p != NULL && !OSSL_PARAM_get_uint(p, &gen_ctx->param)) + return 0; + break; + +#ifndef OPENSSL_NO_EC + case EVP_PKEY_EC: + p = OSSL_PARAM_locate_const(params, OSSL_PKEY_PARAM_GROUP_NAME); + if (p != NULL) { + const char *group; + int nid; + + if (!OSSL_PARAM_get_utf8_string_ptr(p, &group)) + return 0; + + nid = OBJ_txt2nid(group); + if (nid == NID_undef) + nid = EC_curve_nist2nid(group); + if (nid == NID_undef) + return 0; + + gen_ctx->param = (unsigned int)nid; + } + break; +#endif /* OPENSSL_NO_EC */ + + default: + break; + } + + return 1; +} + +P11_KEYDATA *p11_keygen_ctx_generate(P11_KEYGEN_CTX *gen_ctx) +{ + EVP_PKEY *key; + P11_KEYDATA *keydata; + + if (gen_ctx == NULL || gen_ctx->prov_ctx == NULL || + gen_ctx->uri == NULL) + return NULL; + + key = UTIL_CTX_generate_key(gen_ctx->prov_ctx->util_ctx, + gen_ctx->uri, gen_ctx->type, gen_ctx->param); + if (key == NULL) + return NULL; + + keydata = p11_keydata_from_evp_pkey(gen_ctx->prov_ctx, key, 1); + + EVP_PKEY_free(key); + return keydata; +} + /******************************************************************************/ /* SIGNATURE helper functions */ /******************************************************************************/ diff --git a/src/provider_helpers.h b/src/provider_helpers.h index 93381451..2ba01c1f 100644 --- a/src/provider_helpers.h +++ b/src/provider_helpers.h @@ -49,6 +49,7 @@ /* opaque, defined in provider_helpers.c */ typedef struct provider_ctx PROVIDER_CTX; typedef struct p11_keydata_st P11_KEYDATA; +typedef struct p11_keygen_ctx P11_KEYGEN_CTX; typedef struct p11_signature_ctx P11_SIGNATURE_CTX; typedef struct p11_asym_cipher_ctx P11_ASYM_CIPHER_CTX; typedef struct p11_keyexch_ctx P11_KEYEXCH_CTX; @@ -98,6 +99,15 @@ int p11_public_equal(const P11_KEYDATA *k1, const P11_KEYDATA *k2); int pad_mode_from_param(const OSSL_PARAM *p, int *pad_mode); int keydata_export_pub(P11_KEYDATA *keydata, OSSL_CALLBACK *param_cb, void *cbarg); +/******************************************************************************/ +/* KEY GENERATION helper functions */ +/******************************************************************************/ +P11_KEYGEN_CTX *p11_keygen_ctx_new(PROVIDER_CTX *prov_ctx, int type, + const OSSL_PARAM params[]); +void p11_keygen_ctx_free(P11_KEYGEN_CTX *genctx); +int p11_keygen_ctx_set_params(P11_KEYGEN_CTX *genctx, const OSSL_PARAM params[]); +P11_KEYDATA *p11_keygen_ctx_generate(P11_KEYGEN_CTX *genctx); + /******************************************************************************/ /* SIGNATURE helper functions */ /******************************************************************************/ diff --git a/src/util.h b/src/util.h index e873409d..d14fd2cf 100644 --- a/src/util.h +++ b/src/util.h @@ -82,6 +82,8 @@ EVP_PKEY *UTIL_CTX_get_privkey_from_uri(UTIL_CTX *ctx, const char *uri, UI_METHOD *ui_method, void *ui_data); int UTIL_CTX_keygen(UTIL_CTX *ctx, PKCS11_KGEN_ATTRS *kg_attrs); +EVP_PKEY *UTIL_CTX_generate_key(UTIL_CTX *ctx, const char *uri, int algorithm, + unsigned int param); #endif /* _UTIL_LIBP11_H */ diff --git a/src/util_uri.c b/src/util_uri.c index 7390a540..1d4083d4 100644 --- a/src/util_uri.c +++ b/src/util_uri.c @@ -1616,4 +1616,78 @@ int UTIL_CTX_keygen(UTIL_CTX *ctx, PKCS11_KGEN_ATTRS *kg_attrs) return 1; } +/* + * Generate a key pair on the token uniquely selected by the PKCS#11 URI. + * The URI also specifies the generated key label and ID. + * Returns an EVP_PKEY for the generated private key, or NULL on error. + */ +EVP_PKEY *UTIL_CTX_generate_key(UTIL_CTX *ctx, const char *uri, int algorithm, + unsigned int param) +{ + PARSED parsed = {0}; + PKCS11_SLOT *slot = NULL; + PKCS11_KEY *pkey = NULL; + EVP_PKEY *key = NULL; + size_t i; + unsigned int count = 0; + int rv; + + if (ctx == NULL || uri == NULL || strncasecmp(uri, "pkcs11:", 7) != 0) + return NULL; + + pthread_mutex_lock(&ctx->lock); + + if (util_ctx_init_libp11(ctx)) + goto end; + + if (!util_ctx_parse_uri(ctx, &parsed, "key", uri)) + goto end; + + /* + * Key generation requires exactly one initialized token. + * This avoids generating a key on an arbitrary matching token. + */ + for (i = 0; i < parsed.matched_count; i++) { + PKCS11_SLOT *candidate = parsed.matched_slots[i]; + + if (candidate == NULL || candidate->token == NULL || + !candidate->token->initialized) + continue; + + slot = candidate; + count++; + } + + if (count != 1 || slot == NULL) { + UTIL_CTX_log(ctx, LOG_ERR, + "PKCS#11 URI must match exactly one initialized token\n"); + goto end; + } + + if (!util_ctx_login(ctx, slot, slot->token, ctx->ui_method, ctx->ui_data)) + goto end; + + rv = PKCS11_generate_key_ext(slot->token, algorithm, param, + parsed.obj_label, (unsigned char *)parsed.obj_id, + parsed.obj_id_len, &pkey); + if (rv < 0 || pkey == NULL) { + UTIL_CTX_log(ctx, LOG_ERR, + "Failed to generate a key pair on the token. Error code: %d\n", + rv); + goto end; + } + + key = PKCS11_get_private_key(pkey); + if (key == NULL) + UTIL_CTX_log(ctx, LOG_ERR, + "Failed to create EVP_PKEY for the generated private key\n"); + +end: + pthread_mutex_unlock(&ctx->lock); + OPENSSL_free(parsed.obj_label); + OPENSSL_free(parsed.matched_slots); + OPENSSL_free(parsed.obj_id); + return key; +} + /* vim: set noexpandtab: */ diff --git a/tests/Makefile.am b/tests/Makefile.am index 855aca77..cb59a5e5 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -29,6 +29,7 @@ check_PROGRAMS = \ check-all-prov \ rsa-keygen \ ec-keygen \ + ec-duplicate-key \ ec-derive \ ec-derive-prov \ ed25519-keygen \ @@ -51,6 +52,7 @@ dist_check_SCRIPTS = \ rsa-check-privkey.softhsm \ rsa-cert-store.softhsm \ rsa-keygen.softhsm \ + ec-duplicate-key.softhsm \ ec-testfork.softhsm \ ec-evp-sign.softhsm \ ec-check-privkey.softhsm \ @@ -90,7 +92,8 @@ dist_check_SCRIPTS = \ provider-fork-change-slot.softhsm \ provider-case-insensitive.softhsm \ provider-pkcs11-uri-without-token.softhsm \ - provider-search-all-matching-tokens.softhsm + provider-search-all-matching-tokens.softhsm \ + provider-genpkey.softhsm dist_check_DATA = \ rsa-cert.der rsa-privkey.der rsa-pubkey.der \ ec-cert.der ec-privkey.der ec-pubkey.der \ diff --git a/tests/ec-duplicate-key.c b/tests/ec-duplicate-key.c new file mode 100644 index 00000000..057a8712 --- /dev/null +++ b/tests/ec-duplicate-key.c @@ -0,0 +1,199 @@ +/* + * Copyright © 2026 Mobi - Com Polska Sp. z o.o. + * Author: Małgorzata Olszówka + * All rights reserved. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include +#include + +#ifndef OPENSSL_NO_EC + +#define CHECK_ERR(cond, txt, code) \ + do { \ + if (cond) { \ + fprintf(stderr, "%s\n", (txt)); \ + rc = (code); \ + goto end; \ + } \ + } while (0) + +static void error_queue(const char *name) +{ + if (ERR_peek_last_error()) { + fprintf(stderr, "%s generated errors:\n", name); + ERR_print_errors_fp(stderr); + } +} + +static int pkey_equal(EVP_PKEY *a, EVP_PKEY *b) +{ +#if OPENSSL_VERSION_NUMBER >= 0x30000000L + return EVP_PKEY_eq(a, b) == 1; +#else + return EVP_PKEY_cmp(a, b) == 1; +#endif +} + +int main(int argc, char *argv[]) +{ + static unsigned char key_id[] = { 0x22, 0x33 }; + static char decoy_label[] = "duplicate-id-1"; + static char target_label[] = "duplicate-id-2"; + + PKCS11_CTX *ctx = NULL; + PKCS11_SLOT *slots = NULL, *slot; + PKCS11_KEY *generated_key = NULL; + PKCS11_KEY *public_keys = NULL; + PKCS11_KEY public_template = {0}; + EVP_PKEY *actual_public = NULL; + EVP_PKEY *expected_public = NULL; + unsigned int nslots = 0, npublic = 0; + int rc = 1; + + if (argc < 4) { + fprintf(stderr, "usage: %s [MODULE] [TOKEN] [PIN]\n", argv[0]); + return 1; + } + + ctx = PKCS11_CTX_new(); + error_queue("PKCS11_CTX_new"); + CHECK_ERR(ctx == NULL, "PKCS11_CTX_new failed", 2); + + /* Load PKCS#11 module. */ + rc = PKCS11_CTX_load(ctx, argv[1]); + error_queue("PKCS11_CTX_load"); + CHECK_ERR(rc < 0, "loading PKCS#11 module failed", 3); + + /* Get information on all slots. */ + rc = PKCS11_enumerate_slots(ctx, &slots, &nslots); + error_queue("PKCS11_enumerate_slots"); + CHECK_ERR(rc < 0, "no slots available", 4); + + slot = PKCS11_find_token(ctx, slots, nslots); + error_queue("PKCS11_find_token"); + + while (slot != NULL) { + if (slot->token != NULL && + slot->token->initialized && + slot->token->label != NULL && + strcmp(argv[2], slot->token->label) == 0) + break; + + slot = PKCS11_find_next_token(ctx, slots, nslots, slot); + } + + CHECK_ERR(slot == NULL || slot->token == NULL, + "no token available", 5); + + printf("Found token:\n"); + printf("Slot manufacturer.: %s\n", slot->manufacturer); + printf("Slot description.: %s\n", slot->description); + printf("Slot token label.: %s\n", slot->token->label); + printf("Slot token serialnr.: %s\n", slot->token->serialnr); + + rc = PKCS11_login(slot, 0, argv[3]); + error_queue("PKCS11_login"); + CHECK_ERR(rc < 0, "PKCS11_login failed", 6); + + /* + * Generate a first key pair with the shared CKA_ID. + * This key acts as a decoy for an ambiguous CKA_ID lookup. + */ + rc = PKCS11_generate_key(slot->token, EVP_PKEY_EC, + NID_X9_62_prime256v1, decoy_label, + key_id, sizeof(key_id)); + error_queue("PKCS11_generate_key"); + CHECK_ERR(rc < 0, "Failed to generate first key pair", 7); + + /* + * Generate another key pair with the same CKA_ID and retain the + * returned private-key object. + */ + rc = PKCS11_generate_key_ext(slot->token, EVP_PKEY_EC, + NID_X9_62_prime256v1, target_label, + key_id, sizeof(key_id), &generated_key); + error_queue("PKCS11_generate_key_ext"); + CHECK_ERR(rc < 0 || generated_key == NULL, + "Failed to generate second key pair", 8); + + /* + * PKCS11_get_public_key() must resolve the public object paired with + * generated_key rather than an arbitrary public object with the same + * CKA_ID. + */ + actual_public = PKCS11_get_public_key(generated_key); + error_queue("PKCS11_get_public_key"); + CHECK_ERR(actual_public == NULL, + "Failed to get generated public key", 9); + + /* + * Resolve the expected public key unambiguously by its unique label. + */ + public_template.label = target_label; + + rc = PKCS11_enumerate_public_keys_ext(slot->token, + &public_template, &public_keys, &npublic); + error_queue("PKCS11_enumerate_public_keys_ext"); + CHECK_ERR(rc < 0, "Failed to enumerate public keys", 10); + CHECK_ERR(npublic != 1, + "Expected exactly one public key with the target label", 11); + + expected_public = PKCS11_get_public_key(&public_keys[0]); + error_queue("PKCS11_get_public_key"); + CHECK_ERR(expected_public == NULL, + "Failed to get expected public key", 12); + + CHECK_ERR(!pkey_equal(actual_public, expected_public), + "PKCS11_get_public_key returned a public key from a different key pair", + 13); + + printf("Generated public key association is correct\n"); + rc = 0; + +end: + EVP_PKEY_free(expected_public); + EVP_PKEY_free(actual_public); + + if (slots != NULL) + PKCS11_release_all_slots(ctx, slots, nslots); + + if (ctx != NULL) { + PKCS11_CTX_unload(ctx); + PKCS11_CTX_free(ctx); + } + + if (rc) + printf("Failed (error code %d).\n", rc); + else + printf("Success.\n"); + + return rc; +} + +#else /* OPENSSL_NO_EC */ + +#include + +int main(void) +{ + fprintf(stderr, "Skipped: EC support not available\n"); + return 77; +} + +#endif /* OPENSSL_NO_EC */ + +/* vim: set noexpandtab: */ diff --git a/tests/ec-duplicate-key.softhsm b/tests/ec-duplicate-key.softhsm new file mode 100755 index 00000000..a3aa97a1 --- /dev/null +++ b/tests/ec-duplicate-key.softhsm @@ -0,0 +1,63 @@ +#!/bin/bash + +# Copyright © 2026 Mobi - Com Polska Sp. z o.o. +# Author: Małgorzata Olszówka + +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + +outdir="output.$$" + +# Load common test functions +. ${srcdir}/common.sh + +# Initialize SoftHSM DB +init_db + +# Create token +init_card "token1" + +trap cleanup EXIT + +${WRAPPER} ./ec-duplicate-key ${MODULE} token1 ${PIN} +rc=$? + +# Show generated objects also when the regression test fails +list_objects token1 + +if [[ $rc -eq 77 ]]; then + echo "Duplicate key ID test skipped." + rm -rf "$outdir" + exit 77 +elif [[ $rc -ne 0 ]]; then + echo "Duplicate key ID test failed." + exit 1 +fi + +echo "Checking pkcs11-tool result..." + +list_objects token1 | grep -q "duplicate-id-1" +if [[ $? -ne 0 ]]; then + echo "The first key pair was not properly generated." + exit 1 +fi + +list_objects token1 | grep -q "duplicate-id-2" +if [[ $? -ne 0 ]]; then + echo "The second key pair was not properly generated." + exit 1 +fi + +rm -rf "$outdir" + +exit 0 diff --git a/tests/provider-genpkey.softhsm b/tests/provider-genpkey.softhsm new file mode 100755 index 00000000..a9bc602c --- /dev/null +++ b/tests/provider-genpkey.softhsm @@ -0,0 +1,165 @@ +#!/bin/bash + +# Copyright © 2026 Mobi - Com Polska Sp. z o.o. +# Author: Małgorzata Olszówka + +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + +outdir="output.$$" + +# Load common test functions +. "${srcdir}/common.sh" + +if [[ "${OPENSSL_VERSION}" =~ ^[012].* ]]; then + echo "Skipping provider tests with OpenSSL ${OPENSSL_VERSION}" + rm -rf "$outdir" + exit 77 +fi + +# Initialize SoftHSM DB +init_db + +# Create token +init_card "libp11-0" + +# Ensure the use of the locally built provider +unset OPENSSL_ENGINES +export OPENSSL_MODULES="../src/.libs/" +export PKCS11_MODULE_PATH=${MODULE} + +echo "OPENSSL_MODULES=${OPENSSL_MODULES}" +echo "PKCS11_MODULE_PATH=${PKCS11_MODULE_PATH}" + +# Load OpenSSL settings +. ${srcdir}/openssl-settings.sh + +# Restore OpenSSL settings +trap cleanup EXIT + +GENPKEY_ID=1 + +genpkey() +{ + algorithm="$1" + label="$2" + shift 2 + + id=$(printf '%%01%%02%%03%%%02X' "${GENPKEY_ID}") + GENPKEY_ID=$((GENPKEY_ID + 1)) + + echo "Generating ${algorithm} key" + + # TODO: use -noout for non-exportable token keys to avoid a false genpkey failure + # Load default first to avoid SoftHSM recursively selecting pkcs11prov + # for its internal Ed25519/Ed448 key generation on OpenSSL 3.x. + ${OPENSSL} genpkey \ + -provider default -provider pkcs11prov \ + -propquery "?provider=pkcs11prov" \ + -algorithm "${algorithm}" \ + -pkeyopt "pkcs11_uri:pkcs11:token=libp11-0;object=${label};id=${id};pin-value=${PIN}" \ + "$@" || true + + # This is a workaround until genpkey can skip private-key output explicitly + if ! list_objects | grep "label:" | grep -qF "${label}"; then + echo "${algorithm} key generation failed." + return 1 + fi + + echo "${algorithm} key generation succeeded." + echo + return 0 +} + +if has_mechanism RSA-PKCS-KEY-PAIR-GEN; then + genpkey RSA rsa-genpkey -pkeyopt rsa_keygen_bits:2048 || exit 1 +else + echo "Skipping RSA: mechanism not supported." + echo +fi + +if has_mechanism ECDSA-KEY-PAIR-GEN; then + genpkey EC ec-genpkey -pkeyopt ec_paramgen_curve:P-256 || exit 1 +else + echo "Skipping EC: mechanism not supported." + echo +fi + +if has_mechanism EC-EDWARDS-KEY-PAIR-GEN; then + genpkey ED25519 ed25519-genpkey || exit 1 + genpkey ED448 ed448-genpkey || exit 1 +else + echo "Skipping ED25519/ED448: mechanism not supported." + echo +fi + +if has_mechanism EC-MONTGOMERY-KEY-PAIR-GEN || has_mechanism mechtype-0x1056; then + genpkey X25519 x25519-genpkey || exit 1 + genpkey X448 x448-genpkey || exit 1 +else + echo "Skipping X25519/X448: mechanism not supported." + echo +fi + +if has_mechanism ML-DSA-KEY-PAIR-GEN || has_mechanism mechtype-0x1C; then + genpkey ML-DSA-44 mldsa44-genpkey || exit 1 + genpkey ML-DSA-65 mldsa65-genpkey || exit 1 + genpkey ML-DSA-87 mldsa87-genpkey || exit 1 +else + echo "Skipping ML-DSA: mechanism not supported." + echo +fi + +if has_mechanism ML-KEM-KEY-PAIR-GEN || has_mechanism mechtype-0xF; then + genpkey ML-KEM-512 mlkem512-genpkey || exit 1 + genpkey ML-KEM-768 mlkem768-genpkey || exit 1 + genpkey ML-KEM-1024 mlkem1024-genpkey || exit 1 +else + echo "Skipping ML-KEM: mechanism not supported." + echo +fi + +if has_mechanism SLH-DSA-KEY-PAIR-GEN || has_mechanism mechtype-0x2D; then + genpkey SLH-DSA-SHA2-128s slhdsa-sha2-128s-genpkey || exit 1 + genpkey SLH-DSA-SHA2-128f slhdsa-sha2-128f-genpkey || exit 1 + genpkey SLH-DSA-SHA2-192s slhdsa-sha2-192s-genpkey || exit 1 + genpkey SLH-DSA-SHA2-192f slhdsa-sha2-192f-genpkey || exit 1 + genpkey SLH-DSA-SHA2-256s slhdsa-sha2-256s-genpkey || exit 1 + genpkey SLH-DSA-SHA2-256f slhdsa-sha2-256f-genpkey || exit 1 + + genpkey SLH-DSA-SHAKE-128s slhdsa-shake-128s-genpkey || exit 1 + genpkey SLH-DSA-SHAKE-128f slhdsa-shake-128f-genpkey || exit 1 + genpkey SLH-DSA-SHAKE-192s slhdsa-shake-192s-genpkey || exit 1 + genpkey SLH-DSA-SHAKE-192f slhdsa-shake-192f-genpkey || exit 1 + genpkey SLH-DSA-SHAKE-256s slhdsa-shake-256s-genpkey || exit 1 + genpkey SLH-DSA-SHAKE-256f slhdsa-shake-256f-genpkey || exit 1 +else + echo "Skipping SLH-DSA: mechanism not supported." + echo +fi + +if has_mechanism PQC-FALCON || has_mechanism mechtype-0x80010025; then + genpkey FALCON-512 falcon512-genpkey || exit 1 + genpkey FALCON-1024 falcon1024-genpkey || exit 1 +else + echo "Skipping FALCON: mechanism not supported." + echo +fi + +list_objects + +rm -rf "$outdir" + +exit 0 + +# vim: set noexpandtab: