From deb61b5cd9b72566b203ab3b6d32774b73bff964 Mon Sep 17 00:00:00 2001 From: Ingo Franzki Date: Mon, 20 Oct 2025 14:55:33 +0200 Subject: [PATCH] libekmfweb: Add function to validate a certificate against the identity key MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Function ekmf_validate_cert() checks if the public key contained in a x509 certificate matches the public key of the identity key. Signed-off-by: Ingo Franzki Reviewed-by: Finn Callies Signed-off-by: Jan Höppner --- .gitignore | 2 +- include/ekmfweb/ekmfweb.h | 19 ++++++++++ libekmfweb/Makefile | 2 +- libekmfweb/ekmfweb.c | 79 +++++++++++++++++++++++++++++++++++++++ libekmfweb/libekmfweb.map | 7 ++++ 5 files changed, 107 insertions(+), 2 deletions(-) diff --git a/.gitignore b/.gitignore index 01c4ec98..70de1499 100644 --- a/.gitignore +++ b/.gitignore @@ -63,7 +63,7 @@ libekmfweb/check-dep-libekmfweb libekmfweb/detect-openssl-version.dep libekmfweb/libekmfweb.so libekmfweb/libekmfweb.so.1 -libekmfweb/libekmfweb.so.1.0 +libekmfweb/libekmfweb.so.1.1 libkmipclient/check-dep-libkmipclient libkmipclient/detect-openssl-version.dep libkmipclient/libkmipclient.so diff --git a/include/ekmfweb/ekmfweb.h b/include/ekmfweb/ekmfweb.h index 51ed23f6..b29c5788 100644 --- a/include/ekmfweb/ekmfweb.h +++ b/include/ekmfweb/ekmfweb.h @@ -379,6 +379,25 @@ int ekmf_generate_ss_cert(const struct ekmf_config *config, const char *cert_pem_filename, const struct ekmf_ext_lib *ext_lib, bool verbose); +/** + * Validates that a certificate has the same public key as the secure identity + * key (field identity_secure_key in config structure) . + * + * @param config the configuration structure. Only field + * identity_secure_key must be specified, all others + * are optional. + * @param x509_cert the X509 certificate object to validate + * @param ext_lib External secure key crypto library to use + * @param verbose if true, verbose messages are printed + * + * @returns a negative errno in case of an error, 0 if success. + * -EINVAL: invalid parameter, or certificate is not valid + * -ENOMEM: Failed to allocate memory + * any other errno from file I/O routines + */ +int ekmf_validate_cert(const struct ekmf_config *config, const X509 *x509_cert, + const struct ekmf_ext_lib *ext_lib, bool verbose); + /** * Retrieves settings from the EKMFWeb server, such as the template names for * generating keys in EKMFWeb. diff --git a/libekmfweb/Makefile b/libekmfweb/Makefile index 4e7ee1ac..f6c60eaa 100644 --- a/libekmfweb/Makefile +++ b/libekmfweb/Makefile @@ -1,6 +1,6 @@ include ../common.mak -VERSION = 1.0 +VERSION = 1.1 VERM = $(shell echo $(VERSION) | cut -d '.' -f 1) ifneq (${HAVE_OPENSSL},0) diff --git a/libekmfweb/ekmfweb.c b/libekmfweb/ekmfweb.c index 3a822e78..268e6474 100644 --- a/libekmfweb/ekmfweb.c +++ b/libekmfweb/ekmfweb.c @@ -5283,6 +5283,85 @@ out: return rc; } +/** + * Validates that a certificate has the same public key as the secure identity + * key (field identity_secure_key in config structure) . + * + * @param config the configuration structure. Only field + * identity_secure_key must be specified, all others + * are optional. + * @param x509_cert the X509 certificate object to validate + * @param ext_lib External secure key crypto library to use + * @param verbose if true, verbose messages are printed + * + * @returns a negative errno in case of an error, 0 if success. + * -EINVAL: invalid parameter, or certificate is not valid + * -ENOMEM: Failed to allocate memory + * any other errno from file I/O routines + */ +int ekmf_validate_cert(const struct ekmf_config *config, const X509 *x509_cert, + const struct ekmf_ext_lib *ext_lib, bool verbose) +{ + unsigned char key_blob[MAX_KEY_BLOB_SIZE]; + size_t key_blob_size = sizeof(key_blob); + struct ext_lib_info ext_lib_info; + EVP_PKEY *pkey = NULL; + int rc; + + if (config == NULL || ext_lib == NULL || x509_cert == NULL) + return -EINVAL; + if (config->identity_secure_key == NULL) + return -EINVAL; + + _ekmf_copy_ext_lib(ext_lib, &ext_lib_info); + + rc = SK_OPENSSL_init(verbose); + if (rc != 0) { + pr_verbose(verbose, "Failed to initialize secure key support: " + "%s", strerror(-rc)); + return rc; + } + + rc = read_key_blob(config->identity_secure_key, key_blob, + &key_blob_size); + if (rc != 0) { + pr_verbose(verbose, "Failed to read identity key from file " + "'%s': %s", config->identity_secure_key, + strerror(-rc)); + goto out; + } + + rc = SK_OPENSSL_get_secure_key_as_pkey(key_blob, key_blob_size, + false, &pkey, + &ext_lib_info.ext_lib, verbose); + if (rc != 0) { + pr_verbose(verbose, "Failed to get the PKEY from the identity " + "key: %s", strerror(-rc)); + goto out; + } + +#if !OPENSSL_VERSION_PREREQ(3, 0) + if (EVP_PKEY_cmp(pkey, X509_get0_pubkey(x509_cert)) != 1) { +#else + if (EVP_PKEY_eq(pkey, X509_get0_pubkey(x509_cert)) != 1) { +#endif + pr_verbose(verbose, "The certificate does not match with the " + "identity key"); + rc = -EINVAL; + goto out; + } + + pr_verbose(verbose, "Certificate successfully validated"); + +out: + if (pkey != NULL) + EVP_PKEY_free(pkey); + + SK_OPENSSL_term(); + + return rc; +} + /** * Close the connection to the EKMFWeb server by destroying the CURL handle. * diff --git a/libekmfweb/libekmfweb.map b/libekmfweb/libekmfweb.map index 6b77f2bf..6a714814 100644 --- a/libekmfweb/libekmfweb.map +++ b/libekmfweb/libekmfweb.map @@ -8,6 +8,7 @@ LIBEKMFWEB_1.0 { ekmf_reencipher_identity_key; ekmf_generate_csr; ekmf_generate_ss_cert; + ekmf_validate_cert; ekmf_get_public_key; ekmf_get_settings; ekmf_check_feature; @@ -28,3 +29,9 @@ LIBEKMFWEB_1.0 { ekmf_curl_destroy; local: *; }; + +LIBEKMFWEB_1.1 { + global: + ekmf_validate_cert; + local: *; +};