From: Remi Tricot-Le Breton Date: Mon, 26 Jan 2026 10:54:45 +0000 (+0100) Subject: BUG/MINOR: ssl: Encrypted keys could not be loaded when given alongside certificate X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=9b1faee4c972cbe74919fe01ac77b00225f46c43;p=thirdparty%2Fhaproxy.git BUG/MINOR: ssl: Encrypted keys could not be loaded when given alongside certificate The SSL passphrase callback function was only called when loading private keys from a dedicated file (separate from the corresponding certificate) but not when both the certificate and the key were in the same file. We can now load them properly, regardless of how they are provided. A flas had to be added in the 'passphrase_cb_data' structure because in the 'ssl_sock_load_pem_into_ckch' function, when calling 'PEM_read_bio_PrivateKey' there might be no private key in the PEM file which would mean that the callback never gets called (and cannot set the 'passphrase_idx' to -1). This patch can be backported to 3.3. --- diff --git a/include/haproxy/ssl_sock-t.h b/include/haproxy/ssl_sock-t.h index 593f51a5b..b1d660f30 100644 --- a/include/haproxy/ssl_sock-t.h +++ b/include/haproxy/ssl_sock-t.h @@ -361,6 +361,7 @@ struct passphrase_cb_data { const char *path; struct ckch_data *ckch_data; int passphrase_idx; + int callback_called; }; #endif /* USE_OPENSSL */ diff --git a/src/ssl_ckch.c b/src/ssl_ckch.c index 900e89de3..749002b08 100644 --- a/src/ssl_ckch.c +++ b/src/ssl_ckch.c @@ -593,7 +593,7 @@ int ssl_sock_load_key_into_ckch(const char *path, char *buf, struct ckch_data *d BIO *in = NULL; int ret = 1; EVP_PKEY *key = NULL; - struct passphrase_cb_data cb_data = { path, data, 0 }; + struct passphrase_cb_data cb_data = { path, data, 0, 0 }; if (buf) { /* reading from a buffer */ @@ -625,7 +625,7 @@ int ssl_sock_load_key_into_ckch(const char *path, char *buf, struct ckch_data *d */ do { key = PEM_read_bio_PrivateKey(in, NULL, ssl_sock_passwd_cb, &cb_data); - } while (!key && cb_data.passphrase_idx != -1); + } while (!key && cb_data.passphrase_idx != -1 && cb_data.callback_called); if (key == NULL) { memprintf(err, "%sunable to load private key from file '%s'.\n", @@ -667,6 +667,7 @@ int ssl_sock_load_pem_into_ckch(const char *path, char *buf, struct ckch_data *d HASSL_DH *dh = NULL; STACK_OF(X509) *chain = NULL; struct issuer_chain *issuer_chain = NULL; + struct passphrase_cb_data cb_data = { path, data, 0, 0 }; if (buf) { /* reading from a buffer */ @@ -691,8 +692,18 @@ int ssl_sock_load_pem_into_ckch(const char *path, char *buf, struct ckch_data *d } } - /* Read Private Key */ - key = PEM_read_bio_PrivateKey(in, NULL, NULL, NULL); + /* Read Private Key + * Since multiple private keys might have different passphrases that are + * stored in a local cache, we want to try all the already known + * passphrases first before raising an error. The passphrase_idx field + * of the cb_data parameter will be modified in the callback and set to + * -1 after the external passphrase tool is called. + */ + /* We don't know yet if the private key requires a password. */ + data->encrypted_privkey = 0; + do { + key = PEM_read_bio_PrivateKey(in, NULL, ssl_sock_passwd_cb, &cb_data); + } while (!key && cb_data.passphrase_idx != -1 && cb_data.callback_called); /* no need to check for errors here, because the private key could be loaded later */ #ifndef OPENSSL_NO_DH diff --git a/src/ssl_sock.c b/src/ssl_sock.c index 3f25b93ce..1fcec4ab4 100644 --- a/src/ssl_sock.c +++ b/src/ssl_sock.c @@ -3813,6 +3813,8 @@ int ssl_sock_passwd_cb(char *buf, int size, int rwflag, void *userdata) if (!data || data->passphrase_idx == -1) return -1; + data->callback_called = 1; + ckch_data = data->ckch_data; if (ckch_data)