openssl: change default file type to provider

Openssl 3+ encourages using providers for all data storages. This
commit sets it as the default file type when supported, when the file
type is not explicitly defined (instead of PEM by default).
This change also removes the explicit check on a provider being loaded,
before trying to open the matching store: openssl should raise an
explicit error when opening it, and an explicit check in libcurl breaks
the possibility of a default provider in Openssl.

This change should not have any impact on behavior, since openssl
default implementation embeds a provider for PEM file types.
This change full leverages the Openssl store providers: with this, the
end user does not need to maintain the actual storage type in calls to
libcurl, and can freely ignore storage types by changing the URI (or
file path).
This commit is contained in:
Alexandre Besnard 2026-03-23 11:10:36 +01:00
parent 372d721e92
commit a27665b872

View file

@ -861,7 +861,11 @@ static CURLcode ossl_seed(struct Curl_easy *data)
static int ossl_do_file_type(const char *type)
{
if(!type || !type[0])
#ifdef OPENSSL_HAS_PROVIDERS
return SSL_FILETYPE_PROVIDER;
#else
return SSL_FILETYPE_PEM;
#endif
if(curl_strequal(type, "PEM"))
return SSL_FILETYPE_PEM;
if(curl_strequal(type, "DER"))
@ -1113,6 +1117,10 @@ static int providercheck(struct Curl_easy *data,
const char *key_file)
{
#ifdef OPENSSL_HAS_PROVIDERS
EVP_PKEY *priv_key = NULL;
OSSL_STORE_CTX *store = NULL;
OSSL_STORE_INFO *info = NULL;
UI_METHOD *ui_method = NULL;
char error_buffer[256];
/* Implicitly use pkcs11 provider if none was provided and the
* key_file is a PKCS#11 URI */
@ -1124,67 +1132,58 @@ static int providercheck(struct Curl_easy *data,
}
}
if(data->state.provider_loaded) {
/* Load the private key from the provider */
EVP_PKEY *priv_key = NULL;
OSSL_STORE_CTX *store = NULL;
OSSL_STORE_INFO *info = NULL;
UI_METHOD *ui_method = UI_create_method("curl user interface");
if(!ui_method) {
failf(data, "unable to create " OSSL_PACKAGE " user-interface method");
return 0;
}
UI_method_set_opener(ui_method, UI_method_get_opener(UI_OpenSSL()));
UI_method_set_closer(ui_method, UI_method_get_closer(UI_OpenSSL()));
UI_method_set_reader(ui_method, ssl_ui_reader);
UI_method_set_writer(ui_method, ssl_ui_writer);
store = OSSL_STORE_open_ex(key_file, data->state.libctx,
data->state.propq, ui_method, NULL, NULL,
NULL, NULL);
if(!store) {
failf(data, "Failed to open OpenSSL store: %s",
ossl_strerror(ERR_get_error(), error_buffer,
sizeof(error_buffer)));
UI_destroy_method(ui_method);
return 0;
}
if(OSSL_STORE_expect(store, OSSL_STORE_INFO_PKEY) != 1) {
failf(data, "Failed to set store preference. Ignoring the error: %s",
ossl_strerror(ERR_get_error(), error_buffer,
sizeof(error_buffer)));
}
info = OSSL_STORE_load(store);
if(info) {
int ossl_type = OSSL_STORE_INFO_get_type(info);
if(ossl_type == OSSL_STORE_INFO_PKEY)
priv_key = OSSL_STORE_INFO_get1_PKEY(info);
OSSL_STORE_INFO_free(info);
}
OSSL_STORE_close(store);
UI_destroy_method(ui_method);
if(!priv_key) {
failf(data, "No private key found in the openssl store: %s",
ossl_strerror(ERR_get_error(), error_buffer,
sizeof(error_buffer)));
return 0;
}
if(SSL_CTX_use_PrivateKey(ctx, priv_key) != 1) {
failf(data, "unable to set private key [%s]",
ossl_strerror(ERR_get_error(), error_buffer,
sizeof(error_buffer)));
EVP_PKEY_free(priv_key);
return 0;
}
EVP_PKEY_free(priv_key); /* we do not need the handle any more... */
}
else {
failf(data, "crypto provider not set, cannot load private key");
/* Load the private key from the provider */
ui_method = UI_create_method("curl user interface");
if(!ui_method) {
failf(data, "unable to create " OSSL_PACKAGE " user-interface method");
return 0;
}
UI_method_set_opener(ui_method, UI_method_get_opener(UI_OpenSSL()));
UI_method_set_closer(ui_method, UI_method_get_closer(UI_OpenSSL()));
UI_method_set_reader(ui_method, ssl_ui_reader);
UI_method_set_writer(ui_method, ssl_ui_writer);
store = OSSL_STORE_open_ex(key_file, data->state.libctx,
data->state.propq, ui_method, NULL, NULL,
NULL, NULL);
if(!store) {
failf(data, "Failed to open OpenSSL store: %s",
ossl_strerror(ERR_get_error(), error_buffer,
sizeof(error_buffer)));
UI_destroy_method(ui_method);
return 0;
}
if(OSSL_STORE_expect(store, OSSL_STORE_INFO_PKEY) != 1) {
failf(data, "Failed to set store preference. Ignoring the error: %s",
ossl_strerror(ERR_get_error(), error_buffer,
sizeof(error_buffer)));
}
info = OSSL_STORE_load(store);
if(info) {
int ossl_type = OSSL_STORE_INFO_get_type(info);
if(ossl_type == OSSL_STORE_INFO_PKEY)
priv_key = OSSL_STORE_INFO_get1_PKEY(info);
OSSL_STORE_INFO_free(info);
}
OSSL_STORE_close(store);
UI_destroy_method(ui_method);
if(!priv_key) {
failf(data, "No private key found in the openssl store: %s",
ossl_strerror(ERR_get_error(), error_buffer,
sizeof(error_buffer)));
return 0;
}
if(SSL_CTX_use_PrivateKey(ctx, priv_key) != 1) {
failf(data, "unable to set private key [%s]",
ossl_strerror(ERR_get_error(), error_buffer,
sizeof(error_buffer)));
EVP_PKEY_free(priv_key);
return 0;
}
EVP_PKEY_free(priv_key); /* we do not need the handle any more... */
return 1;
#else
(void)ctx;
@ -1269,6 +1268,10 @@ static int providerload(struct Curl_easy *data,
const char *cert_file)
{
#ifdef OPENSSL_HAS_PROVIDERS
OSSL_STORE_INFO *info = NULL;
X509 *cert = NULL;
OSSL_STORE_CTX *store = NULL;
int rc;
char error_buffer[256];
/* Implicitly use pkcs11 provider if none was provided and the
* cert_file is a PKCS#11 URI */
@ -1280,55 +1283,46 @@ static int providerload(struct Curl_easy *data,
}
}
if(data->state.provider_loaded) {
/* Load the certificate from the provider */
OSSL_STORE_INFO *info = NULL;
X509 *cert = NULL;
OSSL_STORE_CTX *store =
OSSL_STORE_open_ex(cert_file, data->state.libctx,
NULL, NULL, NULL, NULL, NULL, NULL);
int rc;
/* Load the certificate from the provider */
if(!store) {
failf(data, "Failed to open OpenSSL store: %s",
ossl_strerror(ERR_get_error(), error_buffer,
sizeof(error_buffer)));
return 0;
}
if(OSSL_STORE_expect(store, OSSL_STORE_INFO_CERT) != 1) {
failf(data, "Failed to set store preference. Ignoring the error: %s",
ossl_strerror(ERR_get_error(), error_buffer,
sizeof(error_buffer)));
}
store = OSSL_STORE_open_ex(cert_file, data->state.libctx,
NULL, NULL, NULL, NULL, NULL, NULL);
info = OSSL_STORE_load(store);
if(info) {
int ossl_type = OSSL_STORE_INFO_get_type(info);
if(ossl_type == OSSL_STORE_INFO_CERT)
cert = OSSL_STORE_INFO_get1_CERT(info);
OSSL_STORE_INFO_free(info);
}
OSSL_STORE_close(store);
if(!cert) {
failf(data, "No cert found in the openssl store: %s",
ossl_strerror(ERR_get_error(), error_buffer,
sizeof(error_buffer)));
return 0;
}
rc = SSL_CTX_use_certificate(ctx, cert);
X509_free(cert); /* we do not need the handle any more... */
if(rc != 1) {
failf(data, "unable to set client certificate [%s]",
ossl_strerror(ERR_get_error(), error_buffer,
sizeof(error_buffer)));
return 0;
}
if(!store) {
failf(data, "Failed to open OpenSSL store: %s",
ossl_strerror(ERR_get_error(), error_buffer,
sizeof(error_buffer)));
return 0;
}
else {
failf(data, "crypto provider not set, cannot load certificate");
if(OSSL_STORE_expect(store, OSSL_STORE_INFO_CERT) != 1) {
failf(data, "Failed to set store preference. Ignoring the error: %s",
ossl_strerror(ERR_get_error(), error_buffer,
sizeof(error_buffer)));
}
info = OSSL_STORE_load(store);
if(info) {
int ossl_type = OSSL_STORE_INFO_get_type(info);
if(ossl_type == OSSL_STORE_INFO_CERT)
cert = OSSL_STORE_INFO_get1_CERT(info);
OSSL_STORE_INFO_free(info);
}
OSSL_STORE_close(store);
if(!cert) {
failf(data, "No cert found in the openssl store: %s",
ossl_strerror(ERR_get_error(), error_buffer,
sizeof(error_buffer)));
return 0;
}
rc = SSL_CTX_use_certificate(ctx, cert);
X509_free(cert); /* we do not need the handle any more... */
if(rc != 1) {
failf(data, "unable to set client certificate [%s]",
ossl_strerror(ERR_get_error(), error_buffer,
sizeof(error_buffer)));
return 0;
}
return 1;