mirror of
https://git.haproxy.org/git/haproxy.git/
synced 2025-08-07 23:56:57 +02:00
MEDIUM: ssl: Add options to forge SSL certificates
With this patch, it is possible to configure HAProxy to forge the SSL certificate sent to a client using the SNI servername. We do it in the SNI callback. To enable this feature, you must pass following BIND options: * ca-sign-file <FILE> : This is the PEM file containing the CA certitifacte and the CA private key to create and sign server's certificates. * (optionally) ca-sign-pass <PASS>: This is the CA private key passphrase, if any. * generate-certificates: Enable the dynamic generation of certificates for a listener. Because generating certificates is expensive, there is a LRU cache to store them. Its size can be customized by setting the global parameter 'tune.ssl.ssl-ctx-cache-size'.
This commit is contained in:
parent
92939d20fa
commit
31af49d62b
@ -581,6 +581,7 @@ The following keywords are supported in the "global" section :
|
||||
- tune.ssl.force-private-cache
|
||||
- tune.ssl.maxrecord
|
||||
- tune.ssl.default-dh-param
|
||||
- tune.ssl.ssl-ctx-cache-size
|
||||
- tune.zlib.memlevel
|
||||
- tune.zlib.windowsize
|
||||
|
||||
@ -1278,6 +1279,12 @@ tune.ssl.default-dh-param <number>
|
||||
used if static Diffie-Hellman parameters are supplied either directly
|
||||
in the certificate file or by using the ssl-dh-param-file parameter.
|
||||
|
||||
tune.ssl.ssl-ctx-cache-size <number>
|
||||
Sets the size of the cache used to store generated certificates to <number>
|
||||
entries. This is a LRU cache. Because generating a SSL certificate
|
||||
dynamically is expensive, they are cached. The default cache size is set to
|
||||
1000 entries.
|
||||
|
||||
tune.zlib.memlevel <number>
|
||||
Sets the memLevel parameter in zlib initialization for each session. It
|
||||
defines how much memory should be allocated for the internal compression
|
||||
@ -9039,6 +9046,19 @@ ca-ignore-err [all|<errorID>,...]
|
||||
If set to 'all', all errors are ignored. SSL handshake is not aborted if an
|
||||
error is ignored.
|
||||
|
||||
ca-sign-file <cafile>
|
||||
This setting is only available when support for OpenSSL was built in. It
|
||||
designates a PEM file containing both the CA certificate and the CA private
|
||||
key used to create and sign server's certificates. This is a mandatory
|
||||
setting when the dynamic generation of certificates is enabled. See
|
||||
'generate-certificates' for details.
|
||||
|
||||
ca-sign-passphrase <passphrase>
|
||||
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.
|
||||
|
||||
ciphers <ciphers>
|
||||
This setting is only available when support for OpenSSL was built in. It sets
|
||||
the string describing the list of cipher algorithms ("cipher suite") that are
|
||||
@ -9164,6 +9184,24 @@ force-tlsv12
|
||||
this listener. This option is also available on global statement
|
||||
"ssl-default-bind-options". See also "no-tlsv*", and "no-sslv3".
|
||||
|
||||
generate-certificates
|
||||
This setting is only available when support for OpenSSL was built in. It
|
||||
enables the dynamic SSL certificates generation. A CA certificate and its
|
||||
private key are necessary (see 'ca-sign-file'). When HAProxy is configured as
|
||||
a transparent forward proxy, SSL requests generate errors because of a common
|
||||
name mismatch on the certificate presented to the client. With this option
|
||||
enabled, HAProxy will try to forge a certificate using the SNI hostname
|
||||
indicated by the client. This is done only if no certificate matches the SNI
|
||||
hostname (see 'crt-list'). If an error occurs, the default certificate is
|
||||
used, else the 'strict-sni' option is set.
|
||||
It can also be used when HAProxy is configured as a reverse proxy to ease the
|
||||
deployment of an architecture with many backends.
|
||||
|
||||
Creating a SSL certificate is an expensive operation, so a LRU cache is used
|
||||
to store forged certificates (see 'tune.ssl.ssl-ctx-cache-size'). It
|
||||
increases the HAProxy's memroy footprint to reduce latency when the same
|
||||
certificate is used many times.
|
||||
|
||||
gid <gid>
|
||||
Sets the group of the UNIX sockets to the designated system gid. It can also
|
||||
be set by default in the global section's "unix-bind" statement. Note that
|
||||
|
@ -257,6 +257,10 @@
|
||||
#define SSL_HANDSHAKE_MAX_COST (76*1024) // measured
|
||||
#endif
|
||||
|
||||
#ifndef DEFAULT_SSL_CTX_CACHE
|
||||
#define DEFAULT_SSL_CTX_CACHE 1000
|
||||
#endif
|
||||
|
||||
/* approximate stream size (for maxconn estimate) */
|
||||
#ifndef STREAM_MAX_COST
|
||||
#define STREAM_MAX_COST (sizeof(struct stream) + \
|
||||
|
@ -44,10 +44,11 @@ int ssl_sock_is_ssl(struct connection *conn)
|
||||
|
||||
int ssl_sock_handshake(struct connection *conn, unsigned int flag);
|
||||
int ssl_sock_prepare_ctx(struct bind_conf *bind_conf, SSL_CTX *ctx, struct proxy *proxy);
|
||||
void ssl_sock_free_certs(struct bind_conf *bind_conf);
|
||||
int ssl_sock_prepare_all_ctx(struct bind_conf *bind_conf, struct proxy *px);
|
||||
int ssl_sock_prepare_srv_ctx(struct server *srv, struct proxy *px);
|
||||
void ssl_sock_free_all_ctx(struct bind_conf *bind_conf);
|
||||
int ssl_sock_load_ca(struct bind_conf *bind_conf, struct proxy *px);
|
||||
void ssl_sock_free_ca(struct bind_conf *bind_conf);
|
||||
const char *ssl_sock_get_cipher_name(struct connection *conn);
|
||||
const char *ssl_sock_get_proto_version(struct connection *conn);
|
||||
char *ssl_sock_get_version(struct connection *conn);
|
||||
|
@ -154,6 +154,7 @@ struct global {
|
||||
unsigned int ssllifetime; /* SSL session lifetime in seconds */
|
||||
unsigned int ssl_max_record; /* SSL max record size */
|
||||
unsigned int ssl_default_dh_param; /* SSL maximum DH parameter size */
|
||||
int ssl_ctx_cache; /* max number of entries in the ssl_ctx cache. */
|
||||
#endif
|
||||
#ifdef USE_ZLIB
|
||||
int zlibmemlevel; /* zlib memlevel */
|
||||
|
@ -133,8 +133,15 @@ struct bind_conf {
|
||||
struct eb_root sni_ctx; /* sni_ctx tree of all known certs full-names sorted by name */
|
||||
struct eb_root sni_w_ctx; /* sni_ctx tree of all known certs wildcards sorted by name */
|
||||
struct tls_keys_ref *keys_ref; /* TLS ticket keys reference */
|
||||
|
||||
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 */
|
||||
#endif
|
||||
int is_ssl; /* SSL is required for these listeners */
|
||||
int generate_certs; /* 1 if generate-certificates option is set, else 0 */
|
||||
unsigned long bind_proc; /* bitmask of processes allowed to use these listeners */
|
||||
struct { /* UNIX socket permissions */
|
||||
uid_t uid; /* -1 to leave unchanged */
|
||||
|
@ -770,6 +770,22 @@ int cfg_parse_global(const char *file, int linenum, char **args, int kwm)
|
||||
}
|
||||
}
|
||||
#endif
|
||||
else if (!strcmp(args[0], "tune.ssl.ssl-ctx-cache-size")) {
|
||||
if (alertif_too_many_args(1, file, linenum, args, &err_code))
|
||||
goto out;
|
||||
if (*(args[1]) == 0) {
|
||||
Alert("parsing [%s:%d] : '%s' expects an integer argument.\n", file, linenum, args[0]);
|
||||
err_code |= ERR_ALERT | ERR_FATAL;
|
||||
goto out;
|
||||
}
|
||||
global.tune.ssl_ctx_cache = atoi(args[1]);
|
||||
if (global.tune.ssl_ctx_cache < 0) {
|
||||
Alert("parsing [%s:%d] : '%s' expects a positive numeric value\n",
|
||||
file, linenum, args[0]);
|
||||
err_code |= ERR_ALERT | ERR_FATAL;
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
else if (!strcmp(args[0], "tune.buffers.limit")) {
|
||||
if (alertif_too_many_args(1, file, linenum, args, &err_code))
|
||||
@ -8219,6 +8235,9 @@ int check_config_validity()
|
||||
|
||||
/* initialize all certificate contexts */
|
||||
cfgerr += ssl_sock_prepare_all_ctx(bind_conf, curproxy);
|
||||
|
||||
/* initialize CA variables if the certificates generation is enabled */
|
||||
cfgerr += ssl_sock_load_ca(bind_conf, curproxy);
|
||||
}
|
||||
#endif /* USE_OPENSSL */
|
||||
|
||||
@ -8287,8 +8306,11 @@ int check_config_validity()
|
||||
if (bind_conf->is_ssl)
|
||||
continue;
|
||||
#ifdef USE_OPENSSL
|
||||
ssl_sock_free_ca(bind_conf);
|
||||
ssl_sock_free_all_ctx(bind_conf);
|
||||
free(bind_conf->ca_file);
|
||||
free(bind_conf->ca_sign_file);
|
||||
free(bind_conf->ca_sign_pass);
|
||||
free(bind_conf->ciphers);
|
||||
free(bind_conf->ecdhe);
|
||||
free(bind_conf->crl_file);
|
||||
|
@ -161,6 +161,7 @@ struct global global = {
|
||||
#ifdef DEFAULT_SSL_MAX_RECORD
|
||||
.ssl_max_record = DEFAULT_SSL_MAX_RECORD,
|
||||
#endif
|
||||
.ssl_ctx_cache = DEFAULT_SSL_CTX_CACHE,
|
||||
#endif
|
||||
#ifdef USE_ZLIB
|
||||
.zlibmemlevel = 8,
|
||||
@ -1456,8 +1457,11 @@ void deinit(void)
|
||||
/* Release unused SSL configs. */
|
||||
list_for_each_entry_safe(bind_conf, bind_back, &p->conf.bind, by_fe) {
|
||||
#ifdef USE_OPENSSL
|
||||
ssl_sock_free_ca(bind_conf);
|
||||
ssl_sock_free_all_ctx(bind_conf);
|
||||
free(bind_conf->ca_file);
|
||||
free(bind_conf->ca_sign_file);
|
||||
free(bind_conf->ca_sign_pass);
|
||||
free(bind_conf->ciphers);
|
||||
free(bind_conf->ecdhe);
|
||||
free(bind_conf->crl_file);
|
||||
|
284
src/ssl_sock.c
284
src/ssl_sock.c
@ -35,7 +35,7 @@
|
||||
#include <sys/socket.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
#include <netdb.h>
|
||||
#include <netinet/tcp.h>
|
||||
|
||||
#include <openssl/ssl.h>
|
||||
@ -51,6 +51,9 @@
|
||||
#include <openssl/dh.h>
|
||||
#endif
|
||||
|
||||
#include <import/lru.h>
|
||||
#include <import/xxhash.h>
|
||||
|
||||
#include <common/buffer.h>
|
||||
#include <common/compat.h>
|
||||
#include <common/config.h>
|
||||
@ -75,6 +78,7 @@
|
||||
#include <proto/frontend.h>
|
||||
#include <proto/listener.h>
|
||||
#include <proto/pattern.h>
|
||||
#include <proto/proto_tcp.h>
|
||||
#include <proto/server.h>
|
||||
#include <proto/log.h>
|
||||
#include <proto/proxy.h>
|
||||
@ -138,6 +142,27 @@ struct certificate_ocsp {
|
||||
long expire;
|
||||
};
|
||||
|
||||
/* X509V3 Extensions that will be added on generated certificates */
|
||||
#define X509V3_EXT_SIZE 5
|
||||
static char *x509v3_ext_names[X509V3_EXT_SIZE] = {
|
||||
"basicConstraints",
|
||||
"nsComment",
|
||||
"subjectKeyIdentifier",
|
||||
"authorityKeyIdentifier",
|
||||
"keyUsage",
|
||||
};
|
||||
static char *x509v3_ext_values[X509V3_EXT_SIZE] = {
|
||||
"CA:FALSE",
|
||||
"\"OpenSSL Generated Certificate\"",
|
||||
"hash",
|
||||
"keyid,issuer:always",
|
||||
"nonRepudiation,digitalSignature,keyEncipherment"
|
||||
};
|
||||
|
||||
/* LRU cache to store generated certificate */
|
||||
static struct lru64_head *ssl_ctx_lru_tree = NULL;
|
||||
static unsigned int ssl_ctx_lru_seed = 0;
|
||||
|
||||
/*
|
||||
* This function returns the number of seconds elapsed
|
||||
* since the Epoch, 1970-01-01 00:00:00 +0000 (UTC) and the
|
||||
@ -978,6 +1003,134 @@ static int ssl_sock_advertise_alpn_protos(SSL *s, const unsigned char **out,
|
||||
}
|
||||
#endif
|
||||
|
||||
static SSL_CTX *
|
||||
ssl_sock_create_cert(const char *servername, unsigned int serial, X509 *cacert, EVP_PKEY *capkey)
|
||||
{
|
||||
SSL_CTX *ssl_ctx = NULL;
|
||||
X509 *newcrt = NULL;
|
||||
EVP_PKEY *pkey = NULL;
|
||||
RSA *rsa;
|
||||
X509_NAME *name;
|
||||
const EVP_MD *digest;
|
||||
X509V3_CTX ctx;
|
||||
unsigned int i;
|
||||
|
||||
/* Generate the public key */
|
||||
if (!(rsa = RSA_generate_key(2048, 3, NULL, NULL)))
|
||||
goto mkcert_error;
|
||||
if (!(pkey = EVP_PKEY_new()))
|
||||
goto mkcert_error;
|
||||
if (EVP_PKEY_assign_RSA(pkey, rsa) != 1)
|
||||
goto mkcert_error;
|
||||
|
||||
/* Create the certificate */
|
||||
if (!(newcrt = X509_new()))
|
||||
goto mkcert_error;
|
||||
|
||||
/* Set version number for the certificate (X509v3) and the serial
|
||||
* number */
|
||||
if (X509_set_version(newcrt, 2L) != 1)
|
||||
goto mkcert_error;
|
||||
ASN1_INTEGER_set(X509_get_serialNumber(newcrt), serial);
|
||||
|
||||
/* Set duration for the certificate */
|
||||
if (!X509_gmtime_adj(X509_get_notBefore(newcrt), (long)-60*60*24) ||
|
||||
!X509_gmtime_adj(X509_get_notAfter(newcrt),(long)60*60*24*365))
|
||||
goto mkcert_error;
|
||||
|
||||
/* set public key in the certificate */
|
||||
if (X509_set_pubkey(newcrt, pkey) != 1)
|
||||
goto mkcert_error;
|
||||
|
||||
/* Set issuer name from the CA */
|
||||
if (!(name = X509_get_subject_name(cacert)))
|
||||
goto mkcert_error;
|
||||
if (X509_set_issuer_name(newcrt, name) != 1)
|
||||
goto mkcert_error;
|
||||
|
||||
/* Set the subject name using the same, but the CN */
|
||||
name = X509_NAME_dup(name);
|
||||
if (X509_NAME_add_entry_by_txt(name, "CN", MBSTRING_ASC,
|
||||
(const unsigned char *)servername,
|
||||
-1, -1, 0) != 1) {
|
||||
X509_NAME_free(name);
|
||||
goto mkcert_error;
|
||||
}
|
||||
if (X509_set_subject_name(newcrt, name) != 1) {
|
||||
X509_NAME_free(name);
|
||||
goto mkcert_error;
|
||||
}
|
||||
X509_NAME_free(name);
|
||||
|
||||
/* Add x509v3 extensions as specified */
|
||||
X509V3_set_ctx(&ctx, cacert, newcrt, NULL, NULL, 0);
|
||||
for (i = 0; i < X509V3_EXT_SIZE; i++) {
|
||||
X509_EXTENSION *ext;
|
||||
|
||||
if (!(ext = X509V3_EXT_conf(NULL, &ctx, x509v3_ext_names[i], x509v3_ext_values[i])))
|
||||
goto mkcert_error;
|
||||
if (!X509_add_ext(newcrt, ext, -1)) {
|
||||
X509_EXTENSION_free(ext);
|
||||
goto mkcert_error;
|
||||
}
|
||||
X509_EXTENSION_free(ext);
|
||||
}
|
||||
|
||||
/* Sign the certificate with the CA private key */
|
||||
if (EVP_PKEY_type(capkey->type) == EVP_PKEY_DSA)
|
||||
digest = EVP_dss1();
|
||||
else if (EVP_PKEY_type (capkey->type) == EVP_PKEY_RSA)
|
||||
digest = EVP_sha256();
|
||||
else
|
||||
goto mkcert_error;
|
||||
if (!(X509_sign(newcrt, capkey, digest)))
|
||||
goto mkcert_error;
|
||||
|
||||
/* Create and set the new SSL_CTX */
|
||||
if (!(ssl_ctx = SSL_CTX_new(SSLv23_server_method())))
|
||||
goto mkcert_error;
|
||||
if (!SSL_CTX_use_PrivateKey(ssl_ctx, pkey))
|
||||
goto mkcert_error;
|
||||
if (!SSL_CTX_use_certificate(ssl_ctx, newcrt))
|
||||
goto mkcert_error;
|
||||
if (!SSL_CTX_check_private_key(ssl_ctx))
|
||||
goto mkcert_error;
|
||||
|
||||
if (newcrt) X509_free(newcrt);
|
||||
if (pkey) EVP_PKEY_free(pkey);
|
||||
return ssl_ctx;
|
||||
|
||||
mkcert_error:
|
||||
if (ssl_ctx) SSL_CTX_free(ssl_ctx);
|
||||
if (newcrt) X509_free(newcrt);
|
||||
if (pkey) EVP_PKEY_free(pkey);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static SSL_CTX *
|
||||
ssl_sock_generate_certificate(const char *servername, struct bind_conf *bind_conf)
|
||||
{
|
||||
X509 *cacert = bind_conf->ca_sign_cert;
|
||||
EVP_PKEY *capkey = bind_conf->ca_sign_pkey;
|
||||
SSL_CTX *ssl_ctx = NULL;
|
||||
struct lru64 *lru = NULL;
|
||||
unsigned int serial;
|
||||
|
||||
serial = XXH32(servername, strlen(servername), ssl_ctx_lru_seed);
|
||||
if (ssl_ctx_lru_tree) {
|
||||
lru = lru64_get(serial, ssl_ctx_lru_tree, cacert, 0);
|
||||
if (lru && lru->domain)
|
||||
ssl_ctx = (SSL_CTX *)lru->data;
|
||||
}
|
||||
|
||||
if (!ssl_ctx) {
|
||||
ssl_ctx = ssl_sock_create_cert(servername, serial, cacert, capkey);
|
||||
if (lru)
|
||||
lru64_commit(lru, ssl_ctx, cacert, 0, (void (*)(void *))SSL_CTX_free);
|
||||
}
|
||||
return ssl_ctx;
|
||||
}
|
||||
|
||||
#ifdef SSL_CTRL_SET_TLSEXT_HOSTNAME
|
||||
/* Sets the SSL ctx of <ssl> to match the advertised server name. Returns a
|
||||
* warning when no match is found, which implies the default (first) cert
|
||||
@ -1022,6 +1175,14 @@ static int ssl_sock_switchctx_cbk(SSL *ssl, int *al, struct bind_conf *s)
|
||||
node = ebst_lookup(&s->sni_w_ctx, wildp);
|
||||
}
|
||||
if (!node || container_of(node, struct sni_ctx, name)->neg) {
|
||||
SSL_CTX *ctx;
|
||||
|
||||
if (s->generate_certs &&
|
||||
(ctx = ssl_sock_generate_certificate(servername, s))) {
|
||||
/* switch ctx */
|
||||
SSL_set_SSL_CTX(ssl, ctx);
|
||||
return SSL_TLSEXT_ERR_OK;
|
||||
}
|
||||
return (s->strict_sni ?
|
||||
SSL_TLSEXT_ERR_ALERT_FATAL :
|
||||
SSL_TLSEXT_ERR_ALERT_WARNING);
|
||||
@ -2245,6 +2406,75 @@ void ssl_sock_free_all_ctx(struct bind_conf *bind_conf)
|
||||
bind_conf->default_ctx = NULL;
|
||||
}
|
||||
|
||||
/* Load CA cert file and private key used to generate certificates */
|
||||
int
|
||||
ssl_sock_load_ca(struct bind_conf *bind_conf, struct proxy *px)
|
||||
{
|
||||
FILE *fp;
|
||||
X509 *cacert = NULL;
|
||||
EVP_PKEY *capkey = NULL;
|
||||
int err = 0;
|
||||
|
||||
if (!bind_conf || !bind_conf->generate_certs)
|
||||
return err;
|
||||
|
||||
if (!bind_conf->ca_sign_file) {
|
||||
Alert("Proxy '%s': cannot enable certificate generation, "
|
||||
"no CA certificate File configured at [%s:%d].\n",
|
||||
px->id, bind_conf->file, bind_conf->line);
|
||||
err++;
|
||||
}
|
||||
|
||||
if (err)
|
||||
goto load_error;
|
||||
|
||||
/* read in the CA certificate */
|
||||
if (!(fp = fopen(bind_conf->ca_sign_file, "r"))) {
|
||||
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);
|
||||
err++;
|
||||
goto load_error;
|
||||
}
|
||||
if (!(cacert = PEM_read_X509(fp, NULL, NULL, NULL))) {
|
||||
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);
|
||||
fclose (fp);
|
||||
err++;
|
||||
goto load_error;
|
||||
}
|
||||
if (!(capkey = PEM_read_PrivateKey(fp, NULL, NULL, bind_conf->ca_sign_pass))) {
|
||||
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);
|
||||
fclose (fp);
|
||||
err++;
|
||||
goto load_error;
|
||||
}
|
||||
fclose (fp);
|
||||
|
||||
bind_conf->ca_sign_cert = cacert;
|
||||
bind_conf->ca_sign_pkey = capkey;
|
||||
return err;
|
||||
|
||||
load_error:
|
||||
bind_conf->generate_certs = 0;
|
||||
if (capkey) EVP_PKEY_free(capkey);
|
||||
if (cacert) X509_free(cacert);
|
||||
return err;
|
||||
}
|
||||
|
||||
/* Release CA cert and private key used to generate certificated */
|
||||
void
|
||||
ssl_sock_free_ca(struct bind_conf *bind_conf)
|
||||
{
|
||||
if (!bind_conf)
|
||||
return;
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
/*
|
||||
* This function is called if SSL * context is not yet allocated. The function
|
||||
* is designed to be called before any other data-layer operation and sets the
|
||||
@ -3994,6 +4224,36 @@ static int bind_parse_ca_file(char **args, int cur_arg, struct proxy *px, struct
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* parse the "ca-sign-file" bind keyword */
|
||||
static int bind_parse_ca_sign_file(char **args, int cur_arg, struct proxy *px, struct bind_conf *conf, char **err)
|
||||
{
|
||||
if (!*args[cur_arg + 1]) {
|
||||
if (err)
|
||||
memprintf(err, "'%s' : missing CAfile path", args[cur_arg]);
|
||||
return ERR_ALERT | ERR_FATAL;
|
||||
}
|
||||
|
||||
if ((*args[cur_arg + 1] != '/') && global.ca_base)
|
||||
memprintf(&conf->ca_sign_file, "%s/%s", global.ca_base, args[cur_arg + 1]);
|
||||
else
|
||||
memprintf(&conf->ca_sign_file, "%s", args[cur_arg + 1]);
|
||||
|
||||
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)
|
||||
{
|
||||
if (!*args[cur_arg + 1]) {
|
||||
if (err)
|
||||
memprintf(err, "'%s' : missing CAkey password", args[cur_arg]);
|
||||
return ERR_ALERT | ERR_FATAL;
|
||||
}
|
||||
memprintf(&conf->ca_sign_pass, "%s", args[cur_arg + 1]);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* parse the "ciphers" bind keyword */
|
||||
static int bind_parse_ciphers(char **args, int cur_arg, struct proxy *px, struct bind_conf *conf, char **err)
|
||||
{
|
||||
@ -4326,6 +4586,18 @@ static int bind_parse_ssl(char **args, int cur_arg, struct proxy *px, struct bin
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* parse the "generate-certificates" bind keyword */
|
||||
static int bind_parse_generate_certs(char **args, int cur_arg, struct proxy *px, struct bind_conf *conf, char **err)
|
||||
{
|
||||
#ifdef SSL_CTRL_SET_TLSEXT_HOSTNAME
|
||||
conf->generate_certs = 1;
|
||||
#else
|
||||
memprintf(err, "%sthis version of openssl cannot generate SSL certificates.\n",
|
||||
err && *err ? *err : "");
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* parse the "strict-sni" bind keyword */
|
||||
static int bind_parse_strict_sni(char **args, int cur_arg, struct proxy *px, struct bind_conf *conf, char **err)
|
||||
{
|
||||
@ -4833,6 +5105,8 @@ static struct bind_kw_list bind_kws = { "SSL", { }, {
|
||||
{ "alpn", bind_parse_alpn, 1 }, /* set ALPN supported protocols */
|
||||
{ "ca-file", bind_parse_ca_file, 1 }, /* set CAfile to process verify on client cert */
|
||||
{ "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 */
|
||||
{ "ciphers", bind_parse_ciphers, 1 }, /* set SSL cipher suite */
|
||||
{ "crl-file", bind_parse_crl_file, 1 }, /* set certificat revocation list file use on client cert verify */
|
||||
{ "crt", bind_parse_crt, 1 }, /* load SSL certificates from this location */
|
||||
@ -4843,6 +5117,7 @@ static struct bind_kw_list bind_kws = { "SSL", { }, {
|
||||
{ "force-tlsv10", bind_parse_force_tlsv10, 0 }, /* force TLSv10 */
|
||||
{ "force-tlsv11", bind_parse_force_tlsv11, 0 }, /* force TLSv11 */
|
||||
{ "force-tlsv12", bind_parse_force_tlsv12, 0 }, /* force TLSv12 */
|
||||
{ "generate-certificates", bind_parse_generate_certs, 0 }, /* enable the server certificates generation */
|
||||
{ "no-sslv3", bind_parse_no_sslv3, 0 }, /* disable SSLv3 */
|
||||
{ "no-tlsv10", bind_parse_no_tlsv10, 0 }, /* disable TLSv10 */
|
||||
{ "no-tlsv11", bind_parse_no_tlsv11, 0 }, /* disable TLSv11 */
|
||||
@ -4953,11 +5228,18 @@ static void __ssl_sock_init(void)
|
||||
#ifndef OPENSSL_NO_DH
|
||||
ssl_dh_ptr_index = SSL_CTX_get_ex_new_index(0, NULL, NULL, NULL, NULL);
|
||||
#endif
|
||||
|
||||
/* Add a global parameter for the LRU cache size */
|
||||
if (global.tune.ssl_ctx_cache)
|
||||
ssl_ctx_lru_tree = lru64_new(global.tune.ssl_ctx_cache);
|
||||
ssl_ctx_lru_seed = (unsigned int)time(NULL);
|
||||
}
|
||||
|
||||
__attribute__((destructor))
|
||||
static void __ssl_sock_deinit(void)
|
||||
{
|
||||
lru64_destroy(ssl_ctx_lru_tree);
|
||||
|
||||
#ifndef OPENSSL_NO_DH
|
||||
if (local_dh_1024) {
|
||||
DH_free(local_dh_1024);
|
||||
|
Loading…
Reference in New Issue
Block a user