crypto-util: move functions

Implementations for loading private/public keys and X.509 certificates
were scattered. Group them together to improve readability.
This commit is contained in:
Yu Watanabe
2026-07-03 03:02:56 +09:00
parent 7c21061f09
commit 7301e2602d
+165 -165
View File
@@ -2070,6 +2070,49 @@ static int load_key_from_engine(const char *engine, const char *private_key_uri,
#endif
}
static int openssl_load_private_key_from_file(const char *path, EVP_PKEY **ret) {
_cleanup_(erase_and_freep) char *rawkey = NULL;
_cleanup_(BIO_freep) BIO *kb = NULL;
_cleanup_(EVP_PKEY_freep) EVP_PKEY *pk = NULL;
size_t rawkeysz;
int r;
assert(path);
assert(ret);
r = read_full_file_full(
AT_FDCWD, path, UINT64_MAX, SIZE_MAX,
READ_FULL_FILE_SECURE|READ_FULL_FILE_WARN_WORLD_READABLE|READ_FULL_FILE_CONNECT_SOCKET,
NULL,
&rawkey, &rawkeysz);
if (r < 0)
return log_debug_errno(r, "Failed to read key file '%s': %m", path);
kb = sym_BIO_new_mem_buf(rawkey, rawkeysz);
if (!kb)
return log_oom_debug();
pk = sym_PEM_read_bio_PrivateKey(kb, NULL, NULL, NULL);
if (!pk)
return log_openssl_errors(LOG_DEBUG, "Failed to parse PEM private key");
*ret = TAKE_PTR(pk);
return 0;
}
OpenSSLAskPasswordUI* openssl_ask_password_ui_free(OpenSSLAskPasswordUI *ui) {
if (!ui)
return NULL;
#ifndef OPENSSL_NO_UI_CONSOLE
assert(sym_UI_get_default_method() == ui->method);
sym_UI_set_default_method(sym_UI_OpenSSL());
sym_UI_destroy_method(ui->method);
#endif
return mfree(ui);
}
#ifndef OPENSSL_NO_UI_CONSOLE
static int openssl_ask_password_ui_read(UI *ui, UI_STRING *uis) {
int r;
@@ -2108,37 +2151,6 @@ static int openssl_ask_password_ui_read(UI *ui, UI_STRING *uis) {
}
#endif
static int openssl_load_private_key_from_file(const char *path, EVP_PKEY **ret) {
_cleanup_(erase_and_freep) char *rawkey = NULL;
_cleanup_(BIO_freep) BIO *kb = NULL;
_cleanup_(EVP_PKEY_freep) EVP_PKEY *pk = NULL;
size_t rawkeysz;
int r;
assert(path);
assert(ret);
r = read_full_file_full(
AT_FDCWD, path, UINT64_MAX, SIZE_MAX,
READ_FULL_FILE_SECURE|READ_FULL_FILE_WARN_WORLD_READABLE|READ_FULL_FILE_CONNECT_SOCKET,
NULL,
&rawkey, &rawkeysz);
if (r < 0)
return log_debug_errno(r, "Failed to read key file '%s': %m", path);
kb = sym_BIO_new_mem_buf(rawkey, rawkeysz);
if (!kb)
return log_oom_debug();
pk = sym_PEM_read_bio_PrivateKey(kb, NULL, NULL, NULL);
if (!pk)
return log_openssl_errors(LOG_DEBUG, "Failed to parse PEM private key");
*ret = TAKE_PTR(pk);
return 0;
}
static int openssl_ask_password_ui_new(const AskPasswordRequest *request, OpenSSLAskPasswordUI **ret) {
#ifndef OPENSSL_NO_UI_CONSOLE
assert(request);
@@ -2172,140 +2184,6 @@ static int openssl_ask_password_ui_new(const AskPasswordRequest *request, OpenSS
#endif
}
static int load_x509_certificate_from_file(const char *path, X509 **ret) {
_cleanup_free_ char *rawcert = NULL;
_cleanup_(X509_freep) X509 *cert = NULL;
_cleanup_(BIO_freep) BIO *cb = NULL;
size_t rawcertsz;
int r;
assert(path);
assert(ret);
r = read_full_file_full(
AT_FDCWD, path, UINT64_MAX, SIZE_MAX,
READ_FULL_FILE_CONNECT_SOCKET,
NULL,
&rawcert, &rawcertsz);
if (r < 0)
return log_debug_errno(r, "Failed to read certificate file '%s': %m", path);
cb = sym_BIO_new_mem_buf(rawcert, rawcertsz);
if (!cb)
return log_oom_debug();
cert = sym_PEM_read_bio_X509(cb, NULL, NULL, NULL);
if (!cert)
return log_debug_errno(SYNTHETIC_ERRNO(EBADMSG), "Failed to parse X.509 certificate: %s",
sym_ERR_error_string(sym_ERR_get_error(), NULL));
*ret = TAKE_PTR(cert);
return 0;
}
static int load_x509_certificate_from_provider(const char *provider, const char *certificate_uri, X509 **ret) {
assert(provider);
assert(certificate_uri);
assert(ret);
/* Load the provider so that this can work without any custom written configuration in /etc/.
* Also load the 'default' as that seems to be the recommendation. */
if (!sym_OSSL_PROVIDER_try_load(/* ctx= */ NULL, provider, /* retain_fallbacks= */ true))
return log_openssl_errors(LOG_DEBUG, "Failed to load OpenSSL provider '%s'", provider);
if (!sym_OSSL_PROVIDER_try_load(/* ctx= */ NULL, "default", /* retain_fallbacks= */ true))
return log_openssl_errors(LOG_DEBUG, "Failed to load OpenSSL provider 'default'");
_cleanup_(OSSL_STORE_closep) OSSL_STORE_CTX *store = sym_OSSL_STORE_open(
certificate_uri,
/* ui_method= */ NULL,
/* ui_method= */ NULL,
/* post_process= */ NULL,
/* post_process_data= */ NULL);
if (!store)
return log_openssl_errors(LOG_DEBUG, "Failed to open OpenSSL store via '%s'", certificate_uri);
if (sym_OSSL_STORE_expect(store, OSSL_STORE_INFO_CERT) == 0)
return log_openssl_errors(LOG_DEBUG, "Failed to filter store by X.509 certificates");
_cleanup_(OSSL_STORE_INFO_freep) OSSL_STORE_INFO *info = sym_OSSL_STORE_load(store);
if (!info)
return log_openssl_errors(LOG_DEBUG, "Failed to load OpenSSL store via '%s'", certificate_uri);
_cleanup_(X509_freep) X509 *cert = sym_OSSL_STORE_INFO_get1_CERT(info);
if (!cert)
return log_openssl_errors(LOG_DEBUG, "Failed to load certificate via '%s'", certificate_uri);
*ret = TAKE_PTR(cert);
return 0;
}
OpenSSLAskPasswordUI* openssl_ask_password_ui_free(OpenSSLAskPasswordUI *ui) {
if (!ui)
return NULL;
#ifndef OPENSSL_NO_UI_CONSOLE
assert(sym_UI_get_default_method() == ui->method);
sym_UI_set_default_method(sym_UI_OpenSSL());
sym_UI_destroy_method(ui->method);
#endif
return mfree(ui);
}
int x509_fingerprint(X509 *cert, uint8_t buffer[static SHA256_DIGEST_SIZE]) {
_cleanup_(OPENSSL_freep) void *der = NULL;
int dersz, r;
assert(cert);
r = dlopen_libcrypto(LOG_DEBUG);
if (r < 0)
return r;
dersz = sym_i2d_X509(cert, (unsigned char**) &der);
if (dersz < 0)
return log_openssl_errors(LOG_DEBUG, "Unable to convert PEM certificate to DER format");
sha256_direct(der, dersz, buffer);
return 0;
}
int openssl_load_x509_certificate(
CertificateSourceType certificate_source_type,
const char *certificate_source,
const char *certificate,
X509 **ret) {
int r;
assert(certificate);
r = dlopen_libcrypto(LOG_DEBUG);
if (r < 0)
return r;
switch (certificate_source_type) {
case OPENSSL_CERTIFICATE_SOURCE_FILE:
r = load_x509_certificate_from_file(certificate, ret);
break;
case OPENSSL_CERTIFICATE_SOURCE_PROVIDER:
r = load_x509_certificate_from_provider(certificate_source, certificate, ret);
break;
default:
assert_not_reached();
}
if (r < 0)
return log_debug_errno(
r,
"Failed to load certificate '%s' from OpenSSL certificate source %s: %m",
certificate,
certificate_source);
return 0;
}
int openssl_load_private_key(
KeySourceType private_key_source_type,
const char *private_key_source,
@@ -2390,6 +2268,128 @@ int openssl_extract_public_key(EVP_PKEY *private_key, EVP_PKEY **ret) {
return 0;
}
static int load_x509_certificate_from_file(const char *path, X509 **ret) {
_cleanup_free_ char *rawcert = NULL;
_cleanup_(X509_freep) X509 *cert = NULL;
_cleanup_(BIO_freep) BIO *cb = NULL;
size_t rawcertsz;
int r;
assert(path);
assert(ret);
r = read_full_file_full(
AT_FDCWD, path, UINT64_MAX, SIZE_MAX,
READ_FULL_FILE_CONNECT_SOCKET,
NULL,
&rawcert, &rawcertsz);
if (r < 0)
return log_debug_errno(r, "Failed to read certificate file '%s': %m", path);
cb = sym_BIO_new_mem_buf(rawcert, rawcertsz);
if (!cb)
return log_oom_debug();
cert = sym_PEM_read_bio_X509(cb, NULL, NULL, NULL);
if (!cert)
return log_debug_errno(SYNTHETIC_ERRNO(EBADMSG), "Failed to parse X.509 certificate: %s",
sym_ERR_error_string(sym_ERR_get_error(), NULL));
*ret = TAKE_PTR(cert);
return 0;
}
static int load_x509_certificate_from_provider(const char *provider, const char *certificate_uri, X509 **ret) {
assert(provider);
assert(certificate_uri);
assert(ret);
/* Load the provider so that this can work without any custom written configuration in /etc/.
* Also load the 'default' as that seems to be the recommendation. */
if (!sym_OSSL_PROVIDER_try_load(/* ctx= */ NULL, provider, /* retain_fallbacks= */ true))
return log_openssl_errors(LOG_DEBUG, "Failed to load OpenSSL provider '%s'", provider);
if (!sym_OSSL_PROVIDER_try_load(/* ctx= */ NULL, "default", /* retain_fallbacks= */ true))
return log_openssl_errors(LOG_DEBUG, "Failed to load OpenSSL provider 'default'");
_cleanup_(OSSL_STORE_closep) OSSL_STORE_CTX *store = sym_OSSL_STORE_open(
certificate_uri,
/* ui_method= */ NULL,
/* ui_method= */ NULL,
/* post_process= */ NULL,
/* post_process_data= */ NULL);
if (!store)
return log_openssl_errors(LOG_DEBUG, "Failed to open OpenSSL store via '%s'", certificate_uri);
if (sym_OSSL_STORE_expect(store, OSSL_STORE_INFO_CERT) == 0)
return log_openssl_errors(LOG_DEBUG, "Failed to filter store by X.509 certificates");
_cleanup_(OSSL_STORE_INFO_freep) OSSL_STORE_INFO *info = sym_OSSL_STORE_load(store);
if (!info)
return log_openssl_errors(LOG_DEBUG, "Failed to load OpenSSL store via '%s'", certificate_uri);
_cleanup_(X509_freep) X509 *cert = sym_OSSL_STORE_INFO_get1_CERT(info);
if (!cert)
return log_openssl_errors(LOG_DEBUG, "Failed to load certificate via '%s'", certificate_uri);
*ret = TAKE_PTR(cert);
return 0;
}
int x509_fingerprint(X509 *cert, uint8_t buffer[static SHA256_DIGEST_SIZE]) {
_cleanup_(OPENSSL_freep) void *der = NULL;
int dersz, r;
assert(cert);
r = dlopen_libcrypto(LOG_DEBUG);
if (r < 0)
return r;
dersz = sym_i2d_X509(cert, (unsigned char**) &der);
if (dersz < 0)
return log_openssl_errors(LOG_DEBUG, "Unable to convert PEM certificate to DER format");
sha256_direct(der, dersz, buffer);
return 0;
}
int openssl_load_x509_certificate(
CertificateSourceType certificate_source_type,
const char *certificate_source,
const char *certificate,
X509 **ret) {
int r;
assert(certificate);
r = dlopen_libcrypto(LOG_DEBUG);
if (r < 0)
return r;
switch (certificate_source_type) {
case OPENSSL_CERTIFICATE_SOURCE_FILE:
r = load_x509_certificate_from_file(certificate, ret);
break;
case OPENSSL_CERTIFICATE_SOURCE_PROVIDER:
r = load_x509_certificate_from_provider(certificate_source, certificate, ret);
break;
default:
assert_not_reached();
}
if (r < 0)
return log_debug_errno(
r,
"Failed to load certificate '%s' from OpenSSL certificate source %s: %m",
certificate,
certificate_source);
return 0;
}
#endif
int parse_openssl_certificate_source_argument(