nice, all ssl variants build well https://travis-ci.com/github/chipitsine/haproxy/builds/174323866
вс, 5 июл. 2020 г. в 15:48, Gersner <[email protected]>: > > > On Sun, Jul 5, 2020 at 1:42 PM Илья Шипицин <[email protected]> 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 <[email protected]>: >> >>> >>> >>> On Sun, Jul 5, 2020 at 12:28 PM Илья Шипицин <[email protected]> >>> 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, <[email protected]>: >>>> >>>>> From: Shimi Gersner <[email protected]> >>>>> >>>>> 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 >>>>> >>>>> >>>>>

