mirror of
http://git.haproxy.org/git/haproxy.git/
synced 2024-12-11 14:05:12 +00:00
MINOR: ssl: load the key from a dedicated file
For a certificate on a bind line, if the private key was not found in the PEM file, look for a .key and load it. This default behavior can be changed by using the ssl-load-extra-files directive in the global section This feature was mentionned in the issue #221.
This commit is contained in:
parent
d43183d05f
commit
4c5adbf595
@ -1320,7 +1320,7 @@ ssl-dh-param-file <file>
|
||||
"openssl dhparam <size>", where size should be at least 2048, as 1024-bit DH
|
||||
parameters should not be considered secure anymore.
|
||||
|
||||
ssl-load-extra-files <none|all|bundle|sctl|ocsp|issuer>*
|
||||
ssl-load-extra-files <none|all|bundle|sctl|ocsp|issuer|key>*
|
||||
This setting alters the way HAProxy will look for unspecified files during
|
||||
the loading of the SSL certificates.
|
||||
|
||||
@ -1333,7 +1333,7 @@ ssl-load-extra-files <none|all|bundle|sctl|ocsp|issuer>*
|
||||
it won't try to bundle the certificates if they have the same basename.
|
||||
|
||||
"all": This is the default behavior, it will try to load everything,
|
||||
bundles, sctl, ocsp, issuer.
|
||||
bundles, sctl, ocsp, issuer, key.
|
||||
|
||||
"bundle": When a file specified in the configuration does not exist, HAProxy
|
||||
will try to load a certificate bundle. This is done by looking for
|
||||
@ -1351,6 +1351,9 @@ ssl-load-extra-files <none|all|bundle|sctl|ocsp|issuer>*
|
||||
"issuer": Try to load "<basename>.issuer" if the issuer of the OCSP file is
|
||||
not provided in the PEM file.
|
||||
|
||||
"key": If the private key was not provided by the PEM file, try to load a
|
||||
file "<basename>.key" containing a private key.
|
||||
|
||||
The default behavior is "all".
|
||||
|
||||
Example:
|
||||
@ -11331,6 +11334,9 @@ crt <cert>
|
||||
file. Intermediate certificate can also be shared in a directory via
|
||||
"issuers-chain-path" directive.
|
||||
|
||||
If the file does not contain a private key, HAProxy will try to load
|
||||
the key at the same path suffixed by a ".key".
|
||||
|
||||
If the OpenSSL used supports Diffie-Hellman, parameters present in this file
|
||||
are loaded.
|
||||
|
||||
|
123
src/ssl_sock.c
123
src/ssl_sock.c
@ -130,8 +130,9 @@
|
||||
#define SSL_GF_SCTL 0x00000002 /* try to open the .sctl file */
|
||||
#define SSL_GF_OCSP 0x00000004 /* try to open the .ocsp file */
|
||||
#define SSL_GF_OCSP_ISSUER 0x00000008 /* try to open the .issuer file if an OCSP file was loaded */
|
||||
#define SSL_GF_KEY 0x00000010 /* try to open the .key file to load a private key */
|
||||
|
||||
#define SSL_GF_ALL (SSL_GF_BUNDLE|SSL_GF_SCTL|SSL_GF_OCSP|SSL_GF_OCSP_ISSUER)
|
||||
#define SSL_GF_ALL (SSL_GF_BUNDLE|SSL_GF_SCTL|SSL_GF_OCSP|SSL_GF_OCSP_ISSUER|SSL_GF_KEY)
|
||||
|
||||
/* ssl_methods versions */
|
||||
enum {
|
||||
@ -3287,8 +3288,8 @@ end:
|
||||
|
||||
/*
|
||||
* Try to load a PEM file from a <path> or a buffer <buf>
|
||||
* The PEM must contain at least a Private Key and a Certificate,
|
||||
* It could contain a DH and a certificate chain.
|
||||
* The PEM must contain at least a Certificate,
|
||||
* It could contain a DH, a certificate chain and a PrivateKey.
|
||||
*
|
||||
* If it failed you should not attempt to use the ckch but free it.
|
||||
*
|
||||
@ -3325,11 +3326,7 @@ static int ssl_sock_load_pem_into_ckch(const char *path, char *buf, struct cert_
|
||||
|
||||
/* Read Private Key */
|
||||
key = PEM_read_bio_PrivateKey(in, NULL, NULL, NULL);
|
||||
if (key == NULL) {
|
||||
memprintf(err, "%sunable to load private key from file '%s'.\n",
|
||||
err && *err ? *err : "", path);
|
||||
goto end;
|
||||
}
|
||||
/* no need to check for errors here, because the private key could be loaded later */
|
||||
|
||||
#ifndef OPENSSL_NO_DH
|
||||
/* Seek back to beginning of file */
|
||||
@ -3358,12 +3355,6 @@ static int ssl_sock_load_pem_into_ckch(const char *path, char *buf, struct cert_
|
||||
goto end;
|
||||
}
|
||||
|
||||
if (!X509_check_private_key(cert, key)) {
|
||||
memprintf(err, "%sinconsistencies between private key and certificate loaded from PEM file '%s'.\n",
|
||||
err && *err ? *err : "", path);
|
||||
goto end;
|
||||
}
|
||||
|
||||
/* Look for a Certificate Chain */
|
||||
while ((ca = PEM_read_bio_X509(in, NULL, NULL, NULL))) {
|
||||
if (chain == NULL)
|
||||
@ -3458,6 +3449,60 @@ end:
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* Try to load a private key file from a <path> or a buffer <buf>
|
||||
*
|
||||
* If it failed you should not attempt to use the ckch but free it.
|
||||
*
|
||||
* Return 0 on success or != 0 on failure
|
||||
*/
|
||||
static int ssl_sock_load_key_into_ckch(const char *path, char *buf, struct cert_key_and_chain *ckch , char **err)
|
||||
{
|
||||
BIO *in = NULL;
|
||||
int ret = 1;
|
||||
EVP_PKEY *key = NULL;
|
||||
|
||||
if (buf) {
|
||||
/* reading from a buffer */
|
||||
in = BIO_new_mem_buf(buf, -1);
|
||||
if (in == NULL) {
|
||||
memprintf(err, "%sCan't allocate memory\n", err && *err ? *err : "");
|
||||
goto end;
|
||||
}
|
||||
|
||||
} else {
|
||||
/* reading from a file */
|
||||
in = BIO_new(BIO_s_file());
|
||||
if (in == NULL)
|
||||
goto end;
|
||||
|
||||
if (BIO_read_filename(in, path) <= 0)
|
||||
goto end;
|
||||
}
|
||||
|
||||
/* Read Private Key */
|
||||
key = PEM_read_bio_PrivateKey(in, NULL, NULL, NULL);
|
||||
if (key == NULL) {
|
||||
memprintf(err, "%sunable to load private key from file '%s'.\n",
|
||||
err && *err ? *err : "", path);
|
||||
goto end;
|
||||
}
|
||||
|
||||
ret = 0;
|
||||
|
||||
SWAP(ckch->key, key);
|
||||
|
||||
end:
|
||||
|
||||
ERR_clear_error();
|
||||
if (in)
|
||||
BIO_free(in);
|
||||
if (key)
|
||||
EVP_PKEY_free(key);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* Try to load in a ckch every files related to a ckch.
|
||||
* (PEM, sctl, ocsp, issuer etc.)
|
||||
@ -3482,6 +3527,32 @@ static int ssl_sock_load_files_into_ckch(const char *path, struct cert_key_and_c
|
||||
goto end;
|
||||
}
|
||||
|
||||
/* try to load an external private key if it wasn't in the PEM */
|
||||
if ((ckch->key == NULL) && (global_ssl.extra_files & SSL_GF_KEY)) {
|
||||
char fp[MAXPATHLEN+1];
|
||||
struct stat st;
|
||||
|
||||
snprintf(fp, MAXPATHLEN+1, "%s.key", path);
|
||||
if (stat(fp, &st) == 0) {
|
||||
if (ssl_sock_load_key_into_ckch(fp, NULL, ckch, err)) {
|
||||
memprintf(err, "%s '%s' is present but cannot be read or parsed'.\n",
|
||||
err && *err ? *err : "", fp);
|
||||
goto end;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (ckch->key == NULL) {
|
||||
memprintf(err, "%sNo Private Key found in '%s' or '%s.key'.\n", err && *err ? *err : "", path, path);
|
||||
goto end;
|
||||
}
|
||||
|
||||
if (!X509_check_private_key(ckch->cert, ckch->key)) {
|
||||
memprintf(err, "%sinconsistencies between private key and certificate loaded '%s'.\n",
|
||||
err && *err ? *err : "", path);
|
||||
goto end;
|
||||
}
|
||||
|
||||
#if (HA_OPENSSL_VERSION_NUMBER >= 0x1000200fL && !defined OPENSSL_NO_TLSEXT && !defined OPENSSL_IS_BORINGSSL)
|
||||
/* try to load the sctl file */
|
||||
if (global_ssl.extra_files & SSL_GF_SCTL) {
|
||||
@ -10179,6 +10250,9 @@ static int ssl_parse_global_extra_files(char **args, int section_type, struct pr
|
||||
} else if (!strcmp("issuer", args[i])){
|
||||
gf |= SSL_GF_OCSP_ISSUER;
|
||||
|
||||
} else if (!strcmp("key", args[i])) {
|
||||
gf |= SSL_GF_KEY;
|
||||
|
||||
} else if (!strcmp("none", args[i])) {
|
||||
if (gf != SSL_GF_NONE)
|
||||
goto err_alone;
|
||||
@ -10436,6 +10510,7 @@ static int cli_parse_set_tlskeys(char **args, char *payload, struct appctx *appc
|
||||
|
||||
enum {
|
||||
CERT_TYPE_PEM = 0,
|
||||
CERT_TYPE_KEY,
|
||||
#if ((defined SSL_CTRL_SET_TLSEXT_STATUS_REQ_CB && !defined OPENSSL_NO_OCSP) || defined OPENSSL_IS_BORINGSSL)
|
||||
CERT_TYPE_OCSP,
|
||||
#endif
|
||||
@ -10453,6 +10528,7 @@ struct {
|
||||
/* add a parsing callback */
|
||||
} cert_exts[CERT_TYPE_MAX+1] = {
|
||||
[CERT_TYPE_PEM] = { "", CERT_TYPE_PEM, &ssl_sock_load_pem_into_ckch }, /* default mode, no extensions */
|
||||
[CERT_TYPE_KEY] = { "key", CERT_TYPE_KEY, &ssl_sock_load_key_into_ckch },
|
||||
#if ((defined SSL_CTRL_SET_TLSEXT_STATUS_REQ_CB && !defined OPENSSL_NO_OCSP) || defined OPENSSL_IS_BORINGSSL)
|
||||
[CERT_TYPE_OCSP] = { "ocsp", CERT_TYPE_OCSP, &ssl_sock_load_ocsp_response_from_file },
|
||||
#endif
|
||||
@ -10928,6 +11004,25 @@ static int cli_parse_commit_cert(char **args, char *payload, struct appctx *appc
|
||||
goto error;
|
||||
}
|
||||
|
||||
#if HA_OPENSSL_VERSION_NUMBER >= 0x1000200fL
|
||||
if (ckchs_transaction.new_ckchs->multi) {
|
||||
int n;
|
||||
|
||||
for (n = 0; n < SSL_SOCK_NUM_KEYTYPES; n++) {
|
||||
if (ckchs_transaction.new_ckchs->ckch[n].cert && !X509_check_private_key(ckchs_transaction.new_ckchs->ckch[n].cert, ckchs_transaction.new_ckchs->ckch[n].key)) {
|
||||
memprintf(&err, "inconsistencies between private key and certificate loaded '%s'.\n", ckchs_transaction.path);
|
||||
goto error;
|
||||
}
|
||||
}
|
||||
} else
|
||||
#endif
|
||||
{
|
||||
if (!X509_check_private_key(ckchs_transaction.new_ckchs->ckch->cert, ckchs_transaction.new_ckchs->ckch->key)) {
|
||||
memprintf(&err, "inconsistencies between private key and certificate loaded '%s'.\n", ckchs_transaction.path);
|
||||
goto error;
|
||||
}
|
||||
}
|
||||
|
||||
/* init the appctx structure */
|
||||
appctx->st2 = SETCERT_ST_INIT;
|
||||
appctx->ctx.ssl.next_ckchi = NULL;
|
||||
|
Loading…
Reference in New Issue
Block a user