Skip to content

zpcprovider for sign/verify (ecdsa/eddsa)#41

Open
holger-dengler wants to merge 39 commits into
opencryptoki:mainfrom
holger-dengler:provider-sign
Open

zpcprovider for sign/verify (ecdsa/eddsa)#41
holger-dengler wants to merge 39 commits into
opencryptoki:mainfrom
holger-dengler:provider-sign

Conversation

@holger-dengler
Copy link
Copy Markdown
Contributor

This PR requires PR #40.

This PR adds OpenSSL provider support for libzpc. This first version covers the main functionality for store, keymgmt, sign/verify and decoder support.

As the series add a lot of new code, it is split into many commits to make the review (hopefully) a bit easier.

ToDo:

  • public key support for store/decoder
  • alloc/free needs some debugging

Restriction:

  • the tests uses hard-coded public keys, so running tests on other machines require code changes in tprovider.c.
  • the provider only supports uv origins, so testing is limited to SEL environments.

@ifranzki
Copy link
Copy Markdown
Contributor

Are you looking at the Travis build failures? You might need to build OpenSSL from source to have a 3.5.0 version to build against.

@holger-dengler
Copy link
Copy Markdown
Contributor Author

Yes, a fix for the travis is in progress. It looks like travis only provides 3.0 out of the box. So I'll build my own. At least 3.5, better 4.0.

Comment thread src/uri.c Outdated
Comment thread src/provider.c Outdated
Comment thread src/object.h Outdated
Comment thread src/signature.c Outdated
Comment thread src/signature.c
@holger-dengler holger-dengler force-pushed the provider-sign branch 2 times, most recently from 7c72889 to 1659e06 Compare May 2, 2026 15:53
@holger-dengler
Copy link
Copy Markdown
Contributor Author

holger-dengler commented May 2, 2026

The update contains:

  • re-order of the commits (move test to the end of the series)
  • rework of signature/eddsa
  • pick review comments
  • minor fixes

@holger-dengler holger-dengler requested a review from ifranzki May 2, 2026 16:10
The new dependency to OpenSSL requires a custom built OpenSSL, as long
it is available as distro package.

This workaround can be removed, if OpenSSL v3.5 or later is available
as distro package.

Signed-off-by: Holger Dengler <dengler@linux.ibm.com>
@holger-dengler
Copy link
Copy Markdown
Contributor Author

Another update (force push) to remove the merge conflicts and add a fix for travis.

@ifranzki
Copy link
Copy Markdown
Contributor

ifranzki commented May 4, 2026

I would suggest to also add tests that utilize the openssl application to use protected key origins. For example, creating/signing a certificate with a protected key origin specified via URI or PEM using openssl x509 -in cert.csr -out cert.pem -req -signkey <protected key origin> -days 1001.

Comment thread CMakeLists.txt Outdated
@holger-dengler
Copy link
Copy Markdown
Contributor Author

I would suggest to also add tests that utilize the openssl application to use protected key origins. For example, creating/signing a certificate with a protected key origin specified via URI or PEM using openssl x509 -in cert.csr -out cert.pem -req -signkey <protected key origin> -days 1001.

I plan to rework the test. tprovider will be renamed (t_provider) and changed to do only the lookup for the provider components. All key-related functional test will be moved to a new t_openssl test script, which uses openssl to create keys and call the functions. such a split is required to run the tests in a CI.

Comment thread src/provider.c Outdated
Comment thread src/provider.c Outdated
Comment thread src/provider.c Outdated
Comment thread src/provider.c Outdated
Comment thread src/keymgmt.c

if (strcmp(obj->origin_type, "uv") == 0) {
/* uv only: import pubkey */
if ((rc = zpc_ec_key_import_clear(key, obj->origin_pubkey.p,
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The pub key is optional. If I try to load a URI without a pub key I get:

OSSL_STORE_load() [uri=hbkzpc:origin-type=uv;origin-alg=prime256v1;origin-blob=19ac19eb0e630b2dd14a935ff3d5614b2e458efe25da35b06c52e1e23c347b22]
000003FFF7FA8720:error:41000036:zpcprovider:zpc_key_update:No EC key parts given:/root/libzpc/src/keymgmt.c:69:

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I was unsure, if a private key without public key makes any sense. But anyhow, I will change it.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

When the ypckey tool allows to create URIs without a pub key then you must be able to handle it :-)

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

IIRC zpckey requires the public key for UV ec-keys.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Aehm no:

# ./zpckey compose -t uv -a prime256v1 --uv-secret-id 19ac19eb0e630b2dd14a935ff3d5614b2e458efe25da35b06c52e1e23c347b22 p256.asr --outform URI
hbkzpc:origin-type=uv;origin-alg=prime256v1;origin-blob=19ac19eb0e630b2dd14a935ff3d5614b2e458efe25da35b06c52e1e23c347b22

No error about the missing public key. I agree that for most use cases, the public key should be there, but there can be legit use cases for keys without a public key. So I think it is technically possible to handle keys with just the private key.

This change works for me:

--- "a/src/keymgmt.c"
+++ "b/src/keymgmt.c"
@@ -53,7 +53,8 @@ static int zpc_key_update(struct obj *obj)
 
 	if (strcmp(obj->origin_type, "uv") == 0) {
 		/* uv only: import pubkey */
-		if ((rc = zpc_ec_key_import_clear(key, obj->origin_pubkey.p,
+		if (obj->origin_pubkey.p != NULL &&
+		    (rc = zpc_ec_key_import_clear(key, obj->origin_pubkey.p,
 						  obj->origin_pubkey.plen,
 						  NULL, 0)))
 			goto err;

Comment thread src/keymgmt.c
Comment thread src/keymgmt.c
The gtest release 1.11.0 produce build problems because of outdated
versions. Updating to version v1.12.1 fixes the problems. While at it,
migrate from archive-download to git checkout.

Signed-off-by: Holger Dengler <dengler@linux.ibm.com>
The libzpc API is no longer exposed as static or shared library. The object module is only available for internal purpose.

Signed-off-by: Holger Dengler <dengler@linux.ibm.com>
@ifranzki
Copy link
Copy Markdown
Contributor

ifranzki commented May 5, 2026

I would move the provider sources into a subdirectory, e.g. src/provider/. Maybe even move the library sources into a subdirectory e.g. src/lib/.

Add signature algorithms for sign/verify with ECDSA and EDDSA keys.

Signed-off-by: Holger Dengler <dengler@linux.ibm.com>
Signed-off-by: Holger Dengler <dengler@linux.ibm.com>
Add the supported TLS properties of the hbkzpc provider.

Signed-off-by: Holger Dengler <dengler@linux.ibm.com>
Signed-off-by: Holger Dengler <dengler@linux.ibm.com>
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 <dengler@linux.ibm.com>
Add internal object build target for ASN.1 module. The internal object
can be shared between targets.

Signed-off-by: Holger Dengler <dengler@linux.ibm.com>
Add decoders for PEM and DER to support hbkzpc-URI files.

Signed-off-by: Holger Dengler <dengler@linux.ibm.com>
Signed-off-by: Holger Dengler <dengler@linux.ibm.com>
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 <dengler@linux.ibm.com>
Add provider test framework with a base retrieval of the hbkzpc
provider.

Signed-off-by: Holger Dengler <dengler@linux.ibm.com>
Integrate new provider testcases for builds with test enabled.

Signed-off-by: Holger Dengler <dengler@linux.ibm.com>
Add tests for the sore-loader. It covers mainly the
open()/load()/eof() sequence.

Signed-off-by: Holger Dengler <dengler@linux.ibm.com>
Add test for loading a EVP PKEY object from a hbkzpc-URI via
store and keymgmt.

Signed-off-by: Holger Dengler <dengler@linux.ibm.com>
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 <dengler@linux.ibm.com>
Add tests for the DER encoding. It takes the hard-coded ECDSA key and
stores it as a file.

Signed-off-by: Holger Dengler <dengler@linux.ibm.com>
Add simple decoder fetch test.

Signed-off-by: Holger Dengler <dengler@linux.ibm.com>
Add tests to use hbkzpc-URI file for sign/verify (instead of loading
the URI via store).

Signed-off-by: Holger Dengler <dengler@linux.ibm.com>
Signed-off-by: Holger Dengler <dengler@linux.ibm.com>
Signed-off-by: Holger Dengler <dengler@linux.ibm.com>
@holger-dengler
Copy link
Copy Markdown
Contributor Author

ed-curves still need additional testing.

Comment thread src/keymgmt.c
}

static const OSSL_DISPATCH kmgmt_ecdsa_functions[] = {
DISPATCH_DEFN(KEYMGMT, NEW, kmgmt_new),
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You should also implement the KEYMGMT_dup function. If this is missing, then an EVP_PKEY_dup() will not work.

Internally EVP_PKEY_dup() tries to be smart: if the dup function is not implemented, then it attempts to duplicate the key by exporting the old key and importing it into the new key.
BUT: You only export the public key, you can't export the private key, so it fails already here. Furthermore, you don't implement the import function either, so it won't work anyway.

Solution: Implement the dup function to properly duplicate the key internals.

Comment thread src/signature.c
}

static const OSSL_DISPATCH ecdsa_functions[] = {
DISPATCH_DEFN(SIGNATURE, NEWCTX, ecdsa_newctx),
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You should also implement the SIGNATURE_dupctx function. Without that functions like EVP_PKEY_CTX_dup() and EVP_MD_CTX_dup() won't work.

Comment thread src/keymgmt.c
static const OSSL_DISPATCH kmgmt_ecdsa_functions[] = {
DISPATCH_DEFN(KEYMGMT, NEW, kmgmt_new),
DISPATCH_DEFN(KEYMGMT, FREE, kmgmt_free),
DISPATCH_DEFN(KEYMGMT, LOAD, kmgmt_load),
Copy link
Copy Markdown
Contributor

@ifranzki ifranzki May 12, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You might consider to also implement the KEYMGMT_match function. This is used with EVP_PKEY_eq() / EVP_PKEY_cmp().

As long as one of the two PKEYs are from a provider that supports the match function, it works by exporting the (public) key data from the one pkey who's provider does not have a match function and import it into the other provider and then call match of that provider. So this works, e.g. compare a PKEY from your provider with a PKEY from the default provider.

What not works is to compare two PKEYs which are both from a provider that does not support the match function. I.e. comparing two PKEYs from your provider. Here the comparison always returns 0 (different) because evp_keymgmt_match() return 0 if no match function is available.

Not sure how important that case is though, so feel free to move this to a later stage.

Comment thread src/tls.c
return OSSL_RV_ERR;
}

return rv;
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should return OSSL_RV_OK, here, but rv is initialized with OSSL_RV_ERR.

Comment thread src/tls.c
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),
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I wonder if you should really supply the x25519 and x448 entries. Your provider does not support Montgomery keys of those types, and also no ECDH with Montgomery keys.

Comment thread src/signature.c
if (p) {
const char *mdname = NULL;

if (OSSL_PARAM_get_utf8_ptr(p, &mdname) != OSSL_RV_OK ||
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

OSSL_PARAM_get_utf8_ptr() does not work here. OSSL_SIGNATURE_PARAM_DIGEST is of data type utf8_string, but not utf8_ptr.

So you must use OSSL_PARAM_get_utf8_string_ptr() instead.

Comment thread src/signature.c
if (p) {
const char *edi = NULL;

if (OSSL_PARAM_get_utf8_ptr(p, &edi) != OSSL_RV_OK ||
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Use OSSL_PARAM_get_utf8_string_ptr() instead.

Comment thread src/keymgmt.c
if (bits)
*bits = alg_param_map[i].bits;
if (secbits)
*bits = alg_param_map[i].secbits;
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

should be *secbits = alg_param_map[i].secbits;

Comment thread src/keymgmt.c
if (secbits)
*bits = alg_param_map[i].secbits;
if (sigsz)
*bits = alg_param_map[i].sigsz;
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

should be *sigsz = alg_param_map[i].sigsz;

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants