That's my fault. I was aware of the versioning but forgot to wrap in ifdef
there.
Configuration prevents from setting those settings on unsupported versions.
On Sun, Jul 5, 2020 at 2:57 PM Илья Шипицин <chipits...@gmail.com
<mailto:chipits...@gmail.com>> wrote:
https://cirrus-ci.com/task/6191727960653824
seems, openssl-1.0.0 (used in CentOS6/RHEL6) does not support those methods.
haproxy claims to support openssl starting 0.9.8, I guess openssl-0.9.8 is
rarely tested
вс, 5 июл. 2020 г. в 16:48, Gersner <gers...@gmail.com
<mailto:gers...@gmail.com>>:
Awesome. I will run the manual tests on the variants later today.
Thanks.
On Sun, Jul 5, 2020 at 2:45 PM Илья Шипицин <chipits...@gmail.com
<mailto:chipits...@gmail.com>> wrote:
if you have tested your code (I'm sure you did), maybe manual
testing will be simple enough
you just need to rebuild haproxy against LibreSSL, BoringSSL, older
openssl
examples how to build ssl lib and build haproxy against it might be
taken from .travis.yml (I was about to write an article, but I'm lazy)
вс, 5 июл. 2020 г. в 16:16, Gersner <gers...@gmail.com
<mailto:gers...@gmail.com>>:
Oh, wasn't aware of that.
Is there some automation to test this or should I manually
verify this?
On Sun, Jul 5, 2020 at 2:13 PM Илья Шипицин <chipits...@gmail.com
<mailto:chipits...@gmail.com>> wrote:
I recall some issues with LibreSSL and chaining trust. Like
it was declared but never worked.
we'll see that in runtime if there are such issues
вс, 5 июл. 2020 г. в 16:06, Илья Шипицин <chipits...@gmail.com
<mailto:chipits...@gmail.com>>:
nice, all ssl variants build well
https://travis-ci.com/github/chipitsine/haproxy/builds/174323866
вс, 5 июл. 2020 г. в 15:48, Gersner <gers...@gmail.com
<mailto:gers...@gmail.com>>:
On Sun, Jul 5, 2020 at 1:42 PM Илья Шипицин
<chipits...@gmail.com <mailto:chipits...@gmail.com>> wrote:
do you have your patches on github fork ?
(I could not find your fork)
Yes. See branch
https://github.com/Azure/haproxy/tree/wip/sgersner/ca-sign-extra
вс, 5 июл. 2020 г. в 15:13, Gersner <gers...@gmail.com
<mailto:gers...@gmail.com>>:
On Sun, Jul 5, 2020 at 12:28 PM Илья Шипицин
<chipits...@gmail.com <mailto:chipits...@gmail.com>> wrote:
does it clearly applies to current
master ? either gmail scrambled patch or it is not.
can you try please ?
Exporting the eml and running 'git am' it
works cleanly.
I've reproduced the exact same output when
copy-pasting from gmail. It seems gmail converts the tabs to spaces and this
fails the patch (Not sure why).
Running patch with '-l' will resolve this,
but it's probably safer to run git am on the email.
$ patch -p1 < 1.patch
patching file doc/configuration.txt
patching file
include/haproxy/listener-t.h
Hunk #1 FAILED at 163.
1 out of 1 hunk FAILED -- saving
rejects to file include/haproxy/listener-t.h.rej
patching file src/cfgparse-ssl.c
Hunk #1 succeeded at 538 with fuzz 1.
Hunk #2 FAILED at 1720.
1 out of 2 hunks FAILED -- saving
rejects to file src/cfgparse-ssl.c.rej
patching file src/ssl_sock.c
Hunk #1 FAILED at 1750.
Hunk #2 FAILED at 1864.
Hunk #3 FAILED at 1912.
Hunk #4 FAILED at 1943.
Hunk #5 FAILED at 1970.
Hunk #6 FAILED at 4823.
Hunk #7 FAILED at 4843.
7 out of 7 hunks FAILED -- saving
rejects to file src/ssl_sock.c.rej
вс, 5 июл. 2020 г. в 11:46, <gers...@gmail.com
<mailto:gers...@gmail.com>>:
From: Shimi Gersner <sgers...@microsoft.com
<mailto:sgers...@microsoft.com>>
haproxy supports generating SSL
certificates based on SNI using a provided
CA signing certificate. Because CA
certificates may be signed by multiple
CAs, in some scenarios, it is
neccesary for the server to attach the trust chain
in addition to the generated
certificate.
The following patch adds the
ability to optionally serve all public
certificates provided in the
`ca-sign-file` PEM file.
Certificate loading was ported to
use `ca_sign_use_chain` structure,
instead of directly reading
public/private keys.
---
doc/configuration.txt | 8
+++
include/haproxy/listener-t.h | 4
+-
src/cfgparse-ssl.c | 13
+++++
src/ssl_sock.c | 98
++++++++++++++++++++----------------
4 files changed, 78
insertions(+), 45 deletions(-)
diff --git a/doc/configuration.txt
b/doc/configuration.txt
index 6d472134e..1d3878bc1 100644
--- a/doc/configuration.txt
+++ b/doc/configuration.txt
@@ -12158,6 +12158,14 @@ ca-sign-pass
<passphrase>
the dynamic generation of
certificates is enabled. See
'generate-certificates' for
details.
+ca-sign-use-chain
+ This setting is only available
when support for OpenSSL was built in. It is
+ the CA private key passphrase.
This setting is optional and used only when
+ the dynamic generation of
certificates is enabled. See
+ 'generate-certificates' for
details.
+ Enabling this flag will attach
all public certificates encoded in `ca-sign-file`
+ to the served certificate to the
client, enabling trust.
+
ca-verify-file <cafile>
This setting designates a PEM
file from which to load CA certificates used to
verify client's certificate. It
designates CA certificates which must not be
diff --git
a/include/haproxy/listener-t.h b/include/haproxy/listener-t.h
index 224e32513..38ca2839f 100644
--- a/include/haproxy/listener-t.h
+++ b/include/haproxy/listener-t.h
@@ -163,8 +163,8 @@ struct
bind_conf {
char *ca_sign_file;
/* CAFile used to generate and sign server certificates */
char *ca_sign_pass;
/* CAKey passphrase */
- X509 *ca_sign_cert;
/* CA certificate referenced by ca_file */
- EVP_PKEY *ca_sign_pkey;
/* CA private key referenced by ca_key */
+ int ca_sign_use_chain;
/* Optionally attached the certificate chain to the served certificate */
+ struct cert_key_and_chain *
ca_sign_ckch; /* CA and possible certificate chain for ca generation */
#endif
struct proxy *frontend;
/* the frontend all these listeners belong to, or NULL */
const struct mux_proto_list
*mux_proto; /* the mux to use for all incoming connections (specified by the
"proto" keyword) */
diff --git a/src/cfgparse-ssl.c
b/src/cfgparse-ssl.c
index 144cef882..270c857f9 100644
--- a/src/cfgparse-ssl.c
+++ b/src/cfgparse-ssl.c
@@ -538,6 +538,18 @@ static int
bind_parse_ca_sign_file(char **args, int cur_arg, struct proxy *px, s
return 0;
}
+/* parse the "ca-sign-use-chain"
bind keyword */
+static int
bind_parse_ca_sign_use_chain(char **args, int cur_arg, struct proxy *px, struct
bind_conf *conf, char **err)
+{
+#if (defined SSL_CTRL_SET_TLSEXT_HOSTNAME
&& !defined SSL_NO_GENERATE_CERTIFICATES && defined SSL_CTX_set1_chain)
+ conf->ca_sign_use_chain = 1;
+#else
+ memprintf(err, "%sthis version
of openssl cannot attach certificate chain for SSL certificate generation.\n",
+ err && *err ? *err :
"");
+#endif
+ return 0;
+}
+
/* parse the "ca-sign-pass" bind
keyword */
static int
bind_parse_ca_sign_pass(char **args, int cur_arg, struct proxy *px, struct
bind_conf *conf, char **err)
{
@@ -1708,6 +1720,7 @@ static struct
bind_kw_list bind_kws = { "SSL", { }, {
{ "ca-ignore-err",
bind_parse_ignore_err, 1 }, /* set error IDs to ignore on verify depth > 0 */
{ "ca-sign-file",
bind_parse_ca_sign_file, 1 }, /* set CAFile used to generate and sign server certs
*/
{ "ca-sign-pass",
bind_parse_ca_sign_pass, 1 }, /* set CAKey passphrase */
+ { "ca-sign-use-chain",
bind_parse_ca_sign_use_chain, 1 }, /* enable attaching ca chain to generated certificate
*/
{ "ciphers",
bind_parse_ciphers, 1 }, /* set SSL cipher suite */
#if (HA_OPENSSL_VERSION_NUMBER >=
0x10101000L)
{ "ciphersuites",
bind_parse_ciphersuites, 1 }, /* set TLS 1.3 cipher suite */
diff --git a/src/ssl_sock.c
b/src/ssl_sock.c
index a32db1a28..54829eb98 100644
--- a/src/ssl_sock.c
+++ b/src/ssl_sock.c
@@ -1750,8 +1750,8 @@ static int
ssl_sock_advertise_alpn_protos(SSL *s, const unsigned char **out,
static SSL_CTX *
ssl_sock_do_create_cert(const
char *servername, struct bind_conf *bind_conf, SSL *ssl)
{
- X509 *cacert =
bind_conf->ca_sign_cert;
- EVP_PKEY *capkey =
bind_conf->ca_sign_pkey;
+ X509 *cacert =
bind_conf->ca_sign_ckch->cert;
+ EVP_PKEY *capkey =
bind_conf->ca_sign_ckch->key;
SSL_CTX *ssl_ctx =
NULL;
X509 *newcrt =
NULL;
EVP_PKEY *pkey =
NULL;
@@ -1864,6 +1864,16 @@
ssl_sock_do_create_cert(const char *servername, struct bind_conf *bind_conf, SSL
if
(!SSL_CTX_check_private_key(ssl_ctx))
goto mkcert_error;
+ /* Assign chain if any */
+ if (bind_conf->ca_sign_use_chain
&& bind_conf->ca_sign_ckch->chain) {
+ if
(!SSL_CTX_set1_chain(ssl_ctx, bind_conf->ca_sign_ckch->chain)) {
+ goto
mkcert_error;
+ }
+ if
(!SSL_CTX_add1_chain_cert(ssl_ctx, bind_conf->ca_sign_ckch->cert)) {
+ goto
mkcert_error;
+ }
+ }
+
if (newcrt)
X509_free(newcrt);
#ifndef OPENSSL_NO_DH
@@ -1912,7 +1922,7 @@
ssl_sock_assign_generated_cert(unsigned int key, struct bind_conf *bind_conf, SS
if (ssl_ctx_lru_tree) {
HA_RWLOCK_WRLOCK(SSL_GEN_CERTS_LOCK, &ssl_ctx_lru_rwlock);
- lru =
lru64_lookup(key, ssl_ctx_lru_tree, bind_conf->ca_sign_cert, 0);
+ lru = lru64_lookup(key,
ssl_ctx_lru_tree, bind_conf->ca_sign_ckch->cert, 0);
if (lru &&
lru->domain) {
if (ssl)
SSL_set_SSL_CTX(ssl, (SSL_CTX *)lru->data);
@@ -1943,14 +1953,14 @@
ssl_sock_set_generated_cert(SSL_CTX *ssl_ctx, unsigned int key, struct bind_conf
if (ssl_ctx_lru_tree) {
HA_RWLOCK_WRLOCK(SSL_GEN_CERTS_LOCK, &ssl_ctx_lru_rwlock);
- lru = lru64_get(key,
ssl_ctx_lru_tree, bind_conf->ca_sign_cert, 0);
+ lru = lru64_get(key,
ssl_ctx_lru_tree, bind_conf->ca_sign_ckch->cert, 0);
if (!lru) {
HA_RWLOCK_WRUNLOCK(SSL_GEN_CERTS_LOCK, &ssl_ctx_lru_rwlock);
return -1;
}
if (lru->domain &&
lru->data)
lru->free((SSL_CTX *)lru->data);
- lru64_commit(lru,
ssl_ctx, bind_conf->ca_sign_cert, 0, (void (*)(void *))SSL_CTX_free);
+ lru64_commit(lru,
ssl_ctx, bind_conf->ca_sign_ckch->cert, 0, (void (*)(void *))SSL_CTX_free);
HA_RWLOCK_WRUNLOCK(SSL_GEN_CERTS_LOCK, &ssl_ctx_lru_rwlock);
return 0;
}
@@ -1970,7 +1980,7 @@
ssl_sock_generated_cert_key(const void *data, size_t len)
static int
ssl_sock_generate_certificate(const char *servername, struct bind_conf
*bind_conf, SSL *ssl)
{
- X509 *cacert =
bind_conf->ca_sign_cert;
+ X509 *cacert =
bind_conf->ca_sign_ckch->cert;
SSL_CTX *ssl_ctx =
NULL;
struct lru64 *lru =
NULL;
unsigned int key;
@@ -4823,13 +4833,12 @@ int
ssl_sock_load_ca(struct bind_conf
*bind_conf)
{
struct proxy *px =
bind_conf->frontend;
- FILE *fp;
- X509 *cacert = NULL;
- EVP_PKEY *capkey = NULL;
- int err = 0;
+ struct cert_key_and_chain
*ckch = NULL;
+ int ret = 0;
+ char *err = NULL;
if
(!bind_conf->generate_certs)
- return err;
+ return ret;
#if (defined SSL_CTRL_SET_TLSEXT_HOSTNAME
&& !defined SSL_NO_GENERATE_CERTIFICATES)
if (global_ssl.ctx_cache) {
@@ -4843,52 +4852,55 @@
ssl_sock_load_ca(struct bind_conf *bind_conf)
ha_alert("Proxy '%s':
cannot enable certificate generation, "
"no CA
certificate File configured at [%s:%d].\n",
px->id,
bind_conf->file, bind_conf->line);
- goto load_error;
+ goto failed;
}
- /* read in the CA
certificate */
- if (!(fp =
fopen(bind_conf->ca_sign_file, "r"))) {
- ha_alert("Proxy '%s':
Failed to read CA certificate file '%s' at [%s:%d].\n",
- px->id,
bind_conf->ca_sign_file, bind_conf->file, bind_conf->line);
- goto load_error;
+ /* Allocate cert structure
*/
+ ckch = calloc(1,
sizeof(struct cert_key_and_chain));
+ if (!ckch) {
+ ha_alert("Proxy '%s':
Failed to read CA certificate file '%s' at [%s:%d]. Chain allocation failure\n",
+ px->id,
bind_conf->ca_sign_file, bind_conf->file, bind_conf->line);
}
- if (!(cacert =
PEM_read_X509(fp, NULL, NULL, NULL))) {
- ha_alert("Proxy '%s':
Failed to read CA certificate file '%s' at [%s:%d].\n",
- px->id,
bind_conf->ca_sign_file, bind_conf->file, bind_conf->line);
- goto read_error;
+
+ /* Try to parse file */
+ if
(ssl_sock_load_files_into_ckch(bind_conf->ca_sign_file, ckch, &err)) {
+ ha_alert("Proxy '%s':
Failed to read CA certificate file '%s' at [%s:%d]. Chain loading failed: %s\n",
+ px->id,
bind_conf->ca_sign_file, bind_conf->file, bind_conf->line, err);
+ if (err) free(err);
+ goto failed;
}
- rewind(fp);
- if (!(capkey =
PEM_read_PrivateKey(fp, NULL, NULL, bind_conf->ca_sign_pass))) {
- ha_alert("Proxy '%s':
Failed to read CA private key file '%s' at [%s:%d].\n",
- px->id,
bind_conf->ca_sign_file, bind_conf->file, bind_conf->line);
- goto read_error;
+
+ /* Fail if missing cert or
pkey */
+ if ((!ckch->cert) ||
(!ckch->key)) {
+ ha_alert("Proxy '%s':
Failed to read CA certificate file '%s' at [%s:%d]. Chain missing certificate or private
key\n",
+ px->id,
bind_conf->ca_sign_file, bind_conf->file, bind_conf->line);
+ goto failed;
}
- fclose (fp);
- bind_conf->ca_sign_cert =
cacert;
- bind_conf->ca_sign_pkey =
capkey;
- return err;
+ /* Final assignment to bind
*/
+ bind_conf->ca_sign_ckch =
ckch;
+ return ret;
+
+ failed:
+ if (ckch) {
+
ssl_sock_free_cert_key_and_chain_contents(ckch);
+ free(ckch);
+ }
- read_error:
- fclose (fp);
- if (capkey)
EVP_PKEY_free(capkey);
- if (cacert)
X509_free(cacert);
- load_error:
bind_conf->generate_certs
= 0;
- err++;
- return err;
+ ret++;
+ return ret;
}
/* Release CA cert and private
key used to generate certificated */
void
ssl_sock_free_ca(struct bind_conf
*bind_conf)
{
- if (bind_conf->ca_sign_pkey)
-
EVP_PKEY_free(bind_conf->ca_sign_pkey);
- if (bind_conf->ca_sign_cert)
-
X509_free(bind_conf->ca_sign_cert);
- bind_conf->ca_sign_pkey =
NULL;
- bind_conf->ca_sign_cert =
NULL;
+ if
(bind_conf->ca_sign_ckch) {
+
ssl_sock_free_cert_key_and_chain_contents(bind_conf->ca_sign_ckch);
+
free(bind_conf->ca_sign_ckch);
+
bind_conf->ca_sign_ckch = NULL;
+ }
}
/*
--
2.27.0