From 5653506f8f02e2d2170209fde749a929bf7a0da1 Mon Sep 17 00:00:00 2001 From: olszomal Date: Tue, 24 Feb 2026 09:09:50 +0100 Subject: [PATCH 1/4] Initialize object handle and count in pkcs11_handle_from_template --- src/p11_key.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/p11_key.c b/src/p11_key.c index dd328e29..c8a2ba07 100644 --- a/src/p11_key.c +++ b/src/p11_key.c @@ -125,8 +125,8 @@ static CK_OBJECT_HANDLE pkcs11_handle_from_template(PKCS11_SLOT_private *slot, CK_SESSION_HANDLE session, PKCS11_TEMPLATE *tmpl) { PKCS11_CTX_private *ctx = slot->ctx; - CK_OBJECT_HANDLE object; - CK_ULONG count; + CK_OBJECT_HANDLE object = CK_INVALID_HANDLE; + CK_ULONG count = 0; CK_RV rv; rv = CRYPTOKI_call(ctx, From eb82255d2318f688749f19f17dc232c127621302 Mon Sep 17 00:00:00 2001 From: olszomal Date: Tue, 24 Feb 2026 09:11:46 +0100 Subject: [PATCH 2/4] EDDSA: implement public key resolution with certificate fallback --- src/p11_eddsa.c | 273 +++++++++++++++++++++++++++++++++++++++--------- 1 file changed, 223 insertions(+), 50 deletions(-) diff --git a/src/p11_eddsa.c b/src/p11_eddsa.c index 67a0e521..5ca5be7f 100644 --- a/src/p11_eddsa.c +++ b/src/p11_eddsa.c @@ -330,78 +330,251 @@ void pkcs11_ed_key_method_free(void) #endif /* OPENSSL_VERSION_NUMBER < 0x40000000L */ /* - * Retrieve the raw public key (EdDSA) from a PKCS#11 object. - * The buffer `*raw` is allocated and must be freed by the caller - * using OPENSSL_free(). + * Decode a DER OCTET STRING and return its contents. + * If decoding fails, duplicate the input buffer unchanged. + * Returns 1 on success, 0 on error. */ -static int pkcs11_get_raw_public_key(PKCS11_OBJECT_private *key, +static int strip_der_octet_string_alloc(const unsigned char *in, size_t inlen, + unsigned char **out, size_t *outlen) +{ + const unsigned char *p = in; + unsigned char *buf; + ASN1_OCTET_STRING *os = NULL; + + if (out == NULL || outlen == NULL || in == NULL || inlen == 0) + return 0; + + *out = NULL; + *outlen = 0; + + /* For EdDSA (RFC8032) the CKA_EC_POINT attribute may be + * encoded as a DER OCTET STRING */ + os = d2i_ASN1_OCTET_STRING(NULL, &p, (long)inlen); + if (os != NULL && p == in + inlen) { + buf = OPENSSL_malloc((size_t)os->length); + if (buf == NULL) { + ASN1_OCTET_STRING_free(os); + return 0; + } + memcpy(buf, os->data, (size_t)os->length); + *out = buf; + *outlen = (size_t)os->length; + ASN1_OCTET_STRING_free(os); + return 1; + } + ASN1_OCTET_STRING_free(os); + + /* Not DER OCTET STRING -> copy as-is */ + buf = OPENSSL_malloc(inlen); + if (buf == NULL) + return 0; + memcpy(buf, in, inlen); + *out = buf; + *outlen = inlen; + return 1; +} + +/* + * Parse a DER X.509 certificate and return raw Ed25519/Ed448 public key bytes. + * Returns 1 on success, 0 on error. + */ +static int extract_eddsa_raw_from_x509_der(const unsigned char *der, size_t derlen, unsigned char **raw, size_t *rawlen) { - CK_ATTRIBUTE attr; - CK_RV rv; - CK_SESSION_HANDLE session; - CK_MECHANISM mechanism; - PKCS11_SLOT_private *slot = key->slot; - PKCS11_CTX_private *ctx = slot->ctx; - PKCS11_OBJECT_private *pubkey; + const unsigned char *p = der; + X509 *cert = NULL; + EVP_PKEY *pkey = NULL; + unsigned char *buf = NULL; + size_t len = 0; + int type, ok = 0; + + if (raw == NULL || rawlen == NULL || der == NULL || derlen == 0) + return 0; *raw = NULL; *rawlen = 0; - memset(&mechanism, 0, sizeof(mechanism)); - mechanism.mechanism = CKM_EDDSA; + cert = d2i_X509(NULL, &p, (long)derlen); + if (cert == NULL) + goto end; - memset(&attr, 0, sizeof(attr)); + pkey = X509_get_pubkey(cert); + if (pkey == NULL) + goto end; - /* CKA_EC_POINT: DER-encoding of the b-bit public key value - * in little endian order as defined in RFC 8032 */ - attr.type = CKA_EC_POINT; + /* Ensure it's EdDSA (Ed25519/Ed448) */ + type = EVP_PKEY_id(pkey); + if (type != EVP_PKEY_ED25519 && type != EVP_PKEY_ED448) + goto end; - if (pkcs11_get_session(slot, 0, &session)) - return -1; - if (key->object_class == CKO_PRIVATE_KEY) - pubkey = pkcs11_object_from_object(key, session, CKO_PUBLIC_KEY); - else - pubkey = key; + /* Query required size */ + if (EVP_PKEY_get_raw_public_key(pkey, NULL, &len) != 1 || len == 0) + goto end; - rv = CRYPTOKI_call(ctx, C_GetAttributeValue(session, pubkey->object, &attr, 1)); - if (rv != CKR_OK) - return -1; + buf = OPENSSL_malloc(len); + if (buf == NULL) + goto end; - if (attr.ulValueLen <= 0 || attr.ulValueLen == CK_UNAVAILABLE_INFORMATION) - return -1; + /* Fetch raw public key bytes */ + if (EVP_PKEY_get_raw_public_key(pkey, buf, &len) != 1) { + OPENSSL_free(buf); + buf = NULL; + goto end; + } + + *raw = buf; + *rawlen = len; + buf = NULL; + ok = 1; + +end: + OPENSSL_free(buf); + EVP_PKEY_free(pkey); + X509_free(cert); + return ok; +} - *raw = OPENSSL_malloc(attr.ulValueLen); - if (!*raw) + +/* + * Extract raw EdDSA public key bytes from a CKO_PUBLIC_KEY object using CKA_EC_POINT. + * Returns 1 on success, 0 on failure. + */ +static int extract_pub_from_public_key_obj(PKCS11_CTX_private *ctx, CK_SESSION_HANDLE session, + CK_OBJECT_HANDLE obj, unsigned char **raw, size_t *rawlen) +{ + unsigned char *ecpt = NULL; + size_t ecptlen = 0; + int ok = 0; + + if (pkcs11_getattr_alloc(ctx, session, obj, CKA_EC_POINT, &ecpt, &ecptlen)) + return 0; + + ok = strip_der_octet_string_alloc(ecpt, ecptlen, raw, rawlen); + OPENSSL_free(ecpt); + return ok; +} + +/* + * Extract raw EdDSA public key bytes from a CKO_CERTIFICATE object. + * The certificate is read from CKA_VALUE (DER-encoded X.509) and + * the public key is obtained via X.509 parsing. + * Returns 1 on success, 0 on failure. + */ +static int extract_pub_from_cert_obj(PKCS11_CTX_private *ctx, CK_SESSION_HANDLE session, + CK_OBJECT_HANDLE obj, unsigned char **raw, size_t *rawlen) +{ + unsigned char *der = NULL; + size_t derlen = 0; + int ok = 0; + + if (pkcs11_getattr_alloc(ctx, session, obj, CKA_VALUE, &der, &derlen)) + return 0; + + ok = extract_eddsa_raw_from_x509_der(der, derlen, raw, rawlen); + OPENSSL_free(der); + return ok; +} + +/* + * Select an object that can provide public key material. + * + * For a private key object, try to locate a matching CKO_PUBLIC_KEY + * (same CKA_ID). If not found, fall back to CKO_CERTIFICATE. + * + * On success, returns a PKCS11_OBJECT_private pointer. + * If a new object is returned, *needs_free is set to 1 and the caller + * must free it with pkcs11_object_free(). + * + * Returns NULL on failure. + */ +static PKCS11_OBJECT_private *pkcs11_choose_public_source(PKCS11_OBJECT_private *key, + CK_SESSION_HANDLE session, int *needs_free) +{ + PKCS11_OBJECT_private *obj; + + *needs_free = 0; + + if (key->object_class != CKO_PRIVATE_KEY) + return key; + + obj = pkcs11_object_from_object(key, session, CKO_PUBLIC_KEY); + if (obj != NULL && obj->object != CK_INVALID_HANDLE) { + *needs_free = 1; + return obj; + } + if (obj != NULL) + pkcs11_object_free(obj); + + obj = pkcs11_object_from_object(key, session, CKO_CERTIFICATE); + if (obj != NULL && obj->object != CK_INVALID_HANDLE) { + *needs_free = 1; + return obj; + } + if (obj != NULL) + pkcs11_object_free(obj); + + return NULL; +} + +/* + * Retrieve raw EdDSA public key bytes. + * + * Preference order: + * 1. CKO_PUBLIC_KEY -> CKA_EC_POINT + * 2. CKO_CERTIFICATE -> CKA_VALUE (DER) + X.509 parsing + * + * The returned buffer is allocated with OPENSSL_malloc() + * and must be freed by the caller. + * + * Returns 0 on success, -1 on failure. + */ +static int pkcs11_get_raw_public_key(PKCS11_OBJECT_private *key, + unsigned char **raw, size_t *rawlen) +{ + PKCS11_SLOT_private *slot; + PKCS11_CTX_private *ctx; + CK_SESSION_HANDLE session = CK_INVALID_HANDLE; + PKCS11_OBJECT_private *obj = NULL; + int obj_needs_free = 0, ok = 0; + + if (key == NULL || key->slot == NULL || raw == NULL || rawlen == NULL) return -1; - attr.pValue = *raw; + *raw = NULL; + *rawlen = 0; + slot = key->slot; + ctx = slot->ctx; - rv = CRYPTOKI_call(ctx, C_GetAttributeValue(session, pubkey->object, &attr, 1)); + if (pkcs11_get_session(slot, 0, &session)) + return -1; - if (key->object_class == CKO_PRIVATE_KEY) - pkcs11_object_free(pubkey); + obj = pkcs11_choose_public_source(key, session, &obj_needs_free); + if (obj == NULL || obj->object == CK_INVALID_HANDLE) + goto end; + + switch (obj->object_class) { + case CKO_PUBLIC_KEY: + ok = extract_pub_from_public_key_obj(ctx, session, obj->object, raw, rawlen); + break; + case CKO_CERTIFICATE: + ok = extract_pub_from_cert_obj(ctx, session, obj->object, raw, rawlen); + break; + default: + ok = 0; + break; + } - if (rv != CKR_OK) { +end: + if (!ok) { OPENSSL_free(*raw); *raw = NULL; - return -1; + *rawlen = 0; } - *rawlen = attr.ulValueLen; - - /* For EdDSA (RFC8032) the CKA_EC_POINT attribute may be encoded - * as a DER OCTET STRING. In such a case, the ASN.1 header needs - * to be stripped, leaving only the raw key bytes. */ - if (*rawlen > 2 && (*raw)[0] == 0x04) { - /* simple OCTET STRING parser */ - size_t len = (*raw)[1]; - if (len + 2 == *rawlen) { - memmove(*raw, *raw + 2, len); - *rawlen = len; - } - } - return 0; + if (obj_needs_free && obj != NULL) + pkcs11_object_free(obj); + + return ok ? 0 : -1; } static EVP_PKEY *pkcs11_get_evp_key_ed25519(PKCS11_OBJECT_private *key) From 09af45bcec4aef073ee6ac708a81cc25f88e5c1c Mon Sep 17 00:00:00 2001 From: olszomal Date: Tue, 24 Feb 2026 09:16:19 +0100 Subject: [PATCH 3/4] tests: fix check-privkey-prov argument and drop unused engines.cnf --- tests/check-privkey-prov.c | 2 +- tests/provider-ec-check-privkey.softhsm | 6 ++---- tests/provider-rsa-check-privkey.softhsm | 6 ++---- 3 files changed, 5 insertions(+), 9 deletions(-) diff --git a/tests/check-privkey-prov.c b/tests/check-privkey-prov.c index 8c5096b6..63cda8ad 100644 --- a/tests/check-privkey-prov.c +++ b/tests/check-privkey-prov.c @@ -60,7 +60,7 @@ int main(int argc, char *argv[]) /* Load private key */ private_key = load_pkey(argv[2], NULL); if (!private_key) { - fprintf(stderr, "Cannot load private key: %s\n", argv[1]); + fprintf(stderr, "Cannot load private key: %s\n", argv[2]); display_openssl_errors(); goto cleanup; } diff --git a/tests/provider-ec-check-privkey.softhsm b/tests/provider-ec-check-privkey.softhsm index 30b82e77..d71af96b 100755 --- a/tests/provider-ec-check-privkey.softhsm +++ b/tests/provider-ec-check-privkey.softhsm @@ -45,8 +45,7 @@ ${OPENSSL} x509 -in ${srcdir}/ec-cert.der -inform DER -outform PEM \ CERTIFICATE="${outdir}/ec-cert.pem" # Run the test -${WRAPPER} ./check-privkey-prov ${CERTIFICATE} ${PRIVATE_KEY} \ - "${outdir}/engines.cnf" +${WRAPPER} ./check-privkey-prov ${CERTIFICATE} ${PRIVATE_KEY} rc=$? if [[ $rc -eq 77 ]]; then echo "EC key test skipped." @@ -57,8 +56,7 @@ elif [[ $rc -ne 0 ]]; then exit 1 fi -./check-privkey-prov ${CERTIFICATE_URL} ${PRIVATE_KEY} \ - "${outdir}/engines.cnf" +./check-privkey-prov ${CERTIFICATE_URL} ${PRIVATE_KEY} if [[ $? -ne 0 ]]; then echo "The private key loading couldn't get the public key from the certificate URL." exit 1 diff --git a/tests/provider-rsa-check-privkey.softhsm b/tests/provider-rsa-check-privkey.softhsm index 9f29d6df..2e32f1e7 100755 --- a/tests/provider-rsa-check-privkey.softhsm +++ b/tests/provider-rsa-check-privkey.softhsm @@ -45,8 +45,7 @@ ${OPENSSL} x509 -in ${srcdir}/rsa-cert.der -inform DER -outform PEM \ CERTIFICATE="${outdir}/rsa-cert.pem" # Run the test -${WRAPPER} ./check-privkey-prov ${CERTIFICATE} ${PRIVATE_KEY} \ - "${outdir}/engines.cnf" +${WRAPPER} ./check-privkey-prov ${CERTIFICATE} ${PRIVATE_KEY} rc=$? if [[ $rc -eq 77 ]]; then echo "RSA key test skipped." @@ -57,8 +56,7 @@ elif [[ $rc -ne 0 ]]; then exit 1 fi -./check-privkey-prov ${CERTIFICATE_URL} ${PRIVATE_KEY} \ - "${outdir}/engines.cnf" +./check-privkey-prov ${CERTIFICATE_URL} ${PRIVATE_KEY} if [[ $? -ne 0 ]]; then echo "The private key loading couldn't get the public key from the certificate URL." exit 1 From 1d79d31c656ce5fb033ecac7446d7186b3db9870 Mon Sep 17 00:00:00 2001 From: olszomal Date: Tue, 24 Feb 2026 10:55:38 +0100 Subject: [PATCH 4/4] tests: add Ed25519/Ed448 provider privkey tests --- tests/Makefile.am | 6 +- tests/common.sh | 13 ++- tests/ed25519-cert.der | Bin 0 -> 316 bytes tests/ed25519-privkey.der | Bin 0 -> 48 bytes tests/ed25519-pubkey.der | Bin 0 -> 44 bytes tests/ed448-cert.der | Bin 0 -> 388 bytes tests/ed448-privkey.der | Bin 0 -> 73 bytes tests/ed448-pubkey.der | Bin 0 -> 69 bytes tests/provider-ed25519-check-privkey.softhsm | 81 +++++++++++++++++++ tests/provider-ed448-check-privkey.softhsm | 81 +++++++++++++++++++ 10 files changed, 176 insertions(+), 5 deletions(-) create mode 100644 tests/ed25519-cert.der create mode 100644 tests/ed25519-privkey.der create mode 100644 tests/ed25519-pubkey.der create mode 100644 tests/ed448-cert.der create mode 100644 tests/ed448-privkey.der create mode 100644 tests/ed448-pubkey.der create mode 100755 tests/provider-ed25519-check-privkey.softhsm create mode 100755 tests/provider-ed448-check-privkey.softhsm diff --git a/tests/Makefile.am b/tests/Makefile.am index b18ddaec..208309c4 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -65,6 +65,8 @@ dist_check_SCRIPTS = \ provider-ec-check-privkey.softhsm \ provider-ec-check-all.softhsm \ provider-ec-copy.softhsm \ + provider-ed25519-check-privkey.softhsm \ + provider-ed448-check-privkey.softhsm \ provider-ed25519-keygen.softhsm \ provider-ed448-keygen.softhsm \ provider-fork-change-slot.softhsm \ @@ -73,7 +75,9 @@ dist_check_SCRIPTS = \ provider-search-all-matching-tokens.softhsm dist_check_DATA = \ rsa-cert.der rsa-privkey.der rsa-pubkey.der \ - ec-cert.der ec-privkey.der ec-pubkey.der + ec-cert.der ec-privkey.der ec-pubkey.der \ + ed25519-cert.der ed25519-privkey.der ed25519-pubkey.der \ + ed448-cert.der ed448-privkey.der ed448-pubkey.der ed25519_keygen_SOURCES = ed25519-keygen.c eddsa_common.c ed448_keygen_SOURCES = ed448-keygen.c eddsa_common.c diff --git a/tests/common.sh b/tests/common.sh index c2dcee54..e920c1b5 100755 --- a/tests/common.sh +++ b/tests/common.sh @@ -244,10 +244,15 @@ init_token () { import_objects ${key_type} "${common_label}-$i" ${obj_id} "${obj_label}-$i" "$@" # List the objects imported into the token - list_objects "${common_label}-$i" + if [[ $? -eq 0 ]]; then + list_objects "${common_label}-$i" + else + return 77 + fi i=$(($i + 1)) done + return 0 } # Write an object (privkey, pubkey, cert) to the token @@ -272,10 +277,10 @@ import_objects () { --id ${obj_id} --label "${obj_label}" >/dev/null if [[ $? -eq 0 ]]; then echo ok - else - echo failed - exit 1 + continue fi + echo "pkcs11-tool cannot import ${key_type} ${param}" + return 77 else echo "Skipping empty parameter" fi diff --git a/tests/ed25519-cert.der b/tests/ed25519-cert.der new file mode 100644 index 0000000000000000000000000000000000000000..5815cac6a13a11839d576f053efb77ebe8e3415f GIT binary patch literal 316 zcmXqLVze-5e7%5~iIIs(#NOc0^tb#^0u6smPJhX|eP&JK=Mx63Y|PrJ1qMQf0tS3+ z%%LpIJnX3{My95QmIiX-yhdgQMn=YlCI&`^mQmuo#vraCl#5l57SupyMF!zz44T2a zJZ8LOl>78Fb_s7;Fq_{@?$bO$b*e&guba*;4mJohkOkT)%f}+dA~I8qp_OBkQQg@U zEAGU_W~ff6did2q9we>IB4HrbfL#GUNP#dT<9`-b17;uvv)++`@deM8D-&nUG4}oW z;I!Ao%ki#>xA$uorvHCl*{l_n+}~>$D>ARLX}()i%MrtpBkNzQTP|_f-kHEBR;*gK H@H0CA=1yg+ literal 0 HcmV?d00001 diff --git a/tests/ed25519-privkey.der b/tests/ed25519-privkey.der new file mode 100644 index 0000000000000000000000000000000000000000..81c132fa5d93ba8adbaa6df207eac6d739f7e737 GIT binary patch literal 48 zcmV-00MGw0E&>4nFa-t!D`jv5A_O3~?KDZdzS3zfx)VM*dA1P#E6We5IK?5;<@2wpd6Q>vQ!5YIacX_Zy?(K!+0(vNzGQOWxyM$4r#3XLRpQ#e zhQ+}Kfd;Zbhsg4=h_Q&2vGy|`c(?J=g`z709q&XY9JoHS-asBCt;`}}Al86g0Y6BA zFeBrC7FGjhAO&+*F@yZZ|4SELQRjUl=M&O><4u8S-UUy_(5gfEMO8_gQqmv9^G9v3 zOmbIV?b;x<|D$1+^I=ccIZe_}8a`y568d!iPEB{PqVsdn&F2f_m|OJ~<_n)#RrR>g i?bhns7gnlX7E%5?RsZ+u6UT~!W~B?cDF@upWdH!CkdUna literal 0 HcmV?d00001 diff --git a/tests/ed448-privkey.der b/tests/ed448-privkey.der new file mode 100644 index 0000000000000000000000000000000000000000..9ec0984bbc260b48515ef19969197440ecc26643 GIT binary patch literal 73 zcmV-P0Ji@yM*;x=Fa-t!D`jy6I|MmYTNiZ^76jIs#JGs~IRzsc_Ve^xoFlRBO<;Wq f)3H31H1D^PdKO3T=5c^Cgbk@}#TZdb<_Uk8h>aZr literal 0 HcmV?d00001 diff --git a/tests/ed448-pubkey.der b/tests/ed448-pubkey.der new file mode 100644 index 0000000000000000000000000000000000000000..66432607253b6d3469f5834327be1705f824b196 GIT binary patch literal 69 zcmV-L0J{G$Lofvf11n{513Ca2uYsWp0z3wkCH}xXQ0| b-j5cgYnJwT=>kW&ygeWceN|?K7}oxP|4kqs literal 0 HcmV?d00001 diff --git a/tests/provider-ed25519-check-privkey.softhsm b/tests/provider-ed25519-check-privkey.softhsm new file mode 100755 index 00000000..8f3415fe --- /dev/null +++ b/tests/provider-ed25519-check-privkey.softhsm @@ -0,0 +1,81 @@ +#!/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 +# +# EdDSA public key resolution tests +# +# The provider resolves the public key for a private key as follows: +# 1. CKO_PUBLIC_KEY (CKA_EC_POINT) +# 2. CKO_CERTIFICATE (CKA_VALUE + X.509 parsing) +# +# Ed25519: +# Import privkey + cert only (no pubkey) to exercise the CKO_CERTIFICATE fallback path. + +outdir="output.$$" + +# Load common test functions +. ${srcdir}/common.sh + +PRIVATE_KEY="pkcs11:token=libp11-0;id=%01%02%03%04;object=server-key-0;type=private;pin-value=${PIN}" +CERTIFICATE_URL="pkcs11:token=libp11-0;id=%01%02%03%04;object=server-key-0;type=cert" + +# Do the token initialization +init_token "ed25519" "1" "libp11" ${ID} "server-key" "privkey" "" "cert" +if [[ $? -eq 77 ]]; then + echo "Ed448 key test skipped." + rm -rf "$outdir" + exit 77 +fi + +# Ensure the use of the locally built provider; applies after running 'pkcs11-tool' +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 + +${OPENSSL} x509 -in ${srcdir}/ed25519-cert.der -inform DER -outform PEM \ + -out ${outdir}/ed25519-cert.pem +CERTIFICATE="${outdir}/ed25519-cert.pem" + +# Run the test +${WRAPPER} ./check-privkey-prov ${CERTIFICATE} ${PRIVATE_KEY} +rc=$? +if [[ $rc -eq 77 ]]; then + echo "Ed25519 key test skipped." + rm -rf "$outdir" + exit 77 +elif [[ $rc -ne 0 ]]; then + echo "The private key loading couldn't get the public key from the certificate." + exit 1 +fi + +./check-privkey-prov ${CERTIFICATE_URL} ${PRIVATE_KEY} +if [[ $? -ne 0 ]]; then + echo "The private key loading couldn't get the public key from the certificate URL." + exit 1 +fi + +rm -rf "$outdir" + +exit 0 diff --git a/tests/provider-ed448-check-privkey.softhsm b/tests/provider-ed448-check-privkey.softhsm new file mode 100755 index 00000000..33730cad --- /dev/null +++ b/tests/provider-ed448-check-privkey.softhsm @@ -0,0 +1,81 @@ +#!/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 +# +# EdDSA public key resolution tests +# +# The provider resolves the public key for a private key as follows: +# 1. CKO_PUBLIC_KEY (CKA_EC_POINT) +# 2. CKO_CERTIFICATE (CKA_VALUE + X.509 parsing) +# +# Ed448: +# Import privkey + pubkey + cert to exercise the direct CKO_PUBLIC_KEY lookup path. + +outdir="output.$$" + +# Load common test functions +. ${srcdir}/common.sh + +PRIVATE_KEY="pkcs11:token=libp11-0;id=%01%02%03%04;object=server-key-0;type=private;pin-value=${PIN}" +CERTIFICATE_URL="pkcs11:token=libp11-0;id=%01%02%03%04;object=server-key-0;type=cert" + +# Do the token initialization +init_token "ed448" "1" "libp11" ${ID} "server-key" "privkey" "pubkey" "cert" +if [[ $? -eq 77 ]]; then + echo "Ed448 key test skipped." + rm -rf "$outdir" + exit 77 +fi + +# Ensure the use of the locally built provider; applies after running 'pkcs11-tool' +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 + +${OPENSSL} x509 -in ${srcdir}/ed448-cert.der -inform DER -outform PEM \ + -out ${outdir}/ed448-cert.pem +CERTIFICATE="${outdir}/ed448-cert.pem" + +# Run the test +${WRAPPER} ./check-privkey-prov ${CERTIFICATE} ${PRIVATE_KEY} +rc=$? +if [[ $rc -eq 77 ]]; then + echo "Ed448 key test skipped." + rm -rf "$outdir" + exit 77 +elif [[ $rc -ne 0 ]]; then + echo "The private key loading couldn't get the public key from the certificate." + exit 1 +fi + +./check-privkey-prov ${CERTIFICATE_URL} ${PRIVATE_KEY} +if [[ $? -ne 0 ]]; then + echo "The private key loading couldn't get the public key from the certificate URL." + exit 1 +fi + +rm -rf "$outdir" + +exit 0