diff --git a/src/shared/crypto-util.c b/src/shared/crypto-util.c index fddb2ba206..60e2730bc7 100644 --- a/src/shared/crypto-util.c +++ b/src/shared/crypto-util.c @@ -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(