From: Nenad Merdanovic <[email protected]>
Signed-off-by: Nenad Merdanovic <[email protected]>
---
doc/configuration.txt | 10 ++++
include/types/listener.h | 1 +
include/types/server.h | 2 +
include/types/ssl_sock.h | 5 ++
src/ssl_sock.c | 133 +++++++++++++++++++++++++++++++++++++++++++++++
5 files changed, 151 insertions(+)
diff --git a/doc/configuration.txt b/doc/configuration.txt
index 43a6c3e1..08b646f5 100644
--- a/doc/configuration.txt
+++ b/doc/configuration.txt
@@ -10492,6 +10492,10 @@ process [ all | odd | even | <number 1-64>[-<number
1-64>] ]
and allow a smoother inter-process load balancing. Currently Linux 3.9 and
above is known for supporting this. See also "bind-process" and "nbproc".
+psk-file <file>
+ Enables use of PSK cipher suites with PSKs stored in the specified file.
+ The entries should be in form "identity:key", one per line.
+
ssl
This setting is only available when support for OpenSSL was built in. It
enables SSL deciphering on connections instantiated from this listener. A
@@ -11110,6 +11114,12 @@ port <port>
Supported in default-server: Yes
+psk <identity:key>
+ Sets the PSK to use when connecting to the backend server over SSL, if the
PSK
+ cipher suite is negotiated. The entry must be in form "identity:key".
+
+ Supported in default-server: No
+
redir <prefix>
The "redir" parameter enables the redirection mode for all GET and HEAD
requests addressing this server. This means that instead of having HAProxy
diff --git a/include/types/listener.h b/include/types/listener.h
index d813deb3..98e34a38 100644
--- a/include/types/listener.h
+++ b/include/types/listener.h
@@ -147,6 +147,7 @@ struct bind_conf {
int strict_sni; /* refuse negotiation if sni doesn't match a
certificate */
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 eb_root psk; /* PSK tree, keyed by identity */
struct tls_keys_ref *keys_ref; /* TLS ticket keys reference */
char *ca_sign_file; /* CAFile used to generate and sign server
certificates */
diff --git a/include/types/server.h b/include/types/server.h
index 51b7e535..25aa4bbd 100644
--- a/include/types/server.h
+++ b/include/types/server.h
@@ -262,6 +262,8 @@ struct server {
char *ca_file; /* CAfile to use on verify */
char *crl_file; /* CRLfile to use on verify */
char *client_crt; /* client certificate to send */
+ char *psk_identity; /* PSK identity */
+ char *psk_key; /* PSK key */
struct sample_expr *sni; /* sample expression for SNI */
} ssl_ctx;
#endif
diff --git a/include/types/ssl_sock.h b/include/types/ssl_sock.h
index a384f055..b51ddf49 100644
--- a/include/types/ssl_sock.h
+++ b/include/types/ssl_sock.h
@@ -26,6 +26,11 @@
#include <openssl/ssl.h>
#include <ebmbtree.h>
+struct psk_pair {
+ char *key;
+ struct ebmb_node node;
+};
+
struct sni_ctx {
SSL_CTX *ctx; /* context associated to the certificate */
int order; /* load order for the certificate */
diff --git a/src/ssl_sock.c b/src/ssl_sock.c
index 232a4970..664581c2 100644
--- a/src/ssl_sock.c
+++ b/src/ssl_sock.c
@@ -533,6 +533,31 @@ end:
}
#endif
+static int ssl_srv_psk_cb(SSL *ssl, char *identity, unsigned char *psk,
unsigned int max_psk_len)
+{
+ struct connection *conn;
+ struct ebmb_node *node;
+ struct psk_pair *pp;
+ int keylen;
+
+ conn = SSL_get_app_data(ssl);
+
+ node = ebst_lookup(&objt_listener(conn->target)->bind_conf->psk,
identity);
+
+ if (!node)
+ return 0;
+
+ pp = ebmb_entry(node, struct psk_pair, node);
+
+ keylen = strlen(pp->key);
+ if(keylen > max_psk_len)
+ return 0;
+
+ memcpy(psk, pp->key, keylen);
+
+ return keylen;
+}
+
#if (defined SSL_CTRL_SET_TLSEXT_TICKET_KEY_CB && TLS_TICKETS_NO > 0)
static int ssl_tlsext_ticket_key_cb(SSL *s, unsigned char key_name[16],
unsigned char *iv, EVP_CIPHER_CTX *ectx, HMAC_CTX *hctx, int enc)
{
@@ -2955,6 +2980,9 @@ int ssl_sock_prepare_ctx(struct bind_conf *bind_conf,
struct ssl_bind_conf *ssl_
}
#endif
+ if(ebmb_first(&bind_conf->psk))
+ SSL_CTX_set_psk_server_callback(ctx, ssl_srv_psk_cb);
+
if (global_ssl.life_time)
SSL_CTX_set_timeout(ctx, global_ssl.life_time);
@@ -3140,6 +3168,32 @@ static int ssl_sock_srv_hostcheck(const char *pattern,
const char *hostname)
return 1;
}
+static int ssl_sock_client_psk_cb(SSL *ssl, const char *hint, char *identity,
unsigned int max_identity_len, unsigned char *psk, unsigned int max_psk_len)
+{
+ struct connection *conn;
+ struct server *srv;
+ int keylen;
+ int ret;
+
+ (void) hint;
+
+ conn = SSL_get_app_data(ssl);
+ srv = objt_server(conn->target);
+
+ if(strlen(srv->ssl_ctx.psk_identity) + 1 > max_identity_len)
+ return 0;
+
+ strcpy(identity, srv->ssl_ctx.psk_identity);
+
+ keylen = strlen(srv->ssl_ctx.psk_key);
+ if(keylen > max_psk_len)
+ return 0;
+
+ memcpy(psk, srv->ssl_ctx.psk_key, keylen);
+
+ return keylen;
+}
+
static int ssl_sock_srv_verifycbk(int ok, X509_STORE_CTX *ctx)
{
SSL *ssl;
@@ -3367,6 +3421,9 @@ int ssl_sock_prepare_srv_ctx(struct server *srv)
cfgerr++;
}
+ if (srv->ssl_ctx.psk_identity && srv->ssl_ctx.psk_key)
+ SSL_CTX_set_psk_client_callback(srv->ssl_ctx.ctx,
ssl_sock_client_psk_cb);
+
return cfgerr;
}
@@ -5849,6 +5906,56 @@ static int bind_parse_alpn(char **args, int cur_arg,
struct proxy *px, struct bi
return ssl_bind_parse_alpn(args, cur_arg, px, &conf->ssl_conf, err);
}
+/* parse the "psk-file" bind keyword */
+static int bind_parse_psk_file(char **args, int cur_arg, struct proxy *px,
struct bind_conf *conf, char **err)
+{
+ FILE *f;
+ int i = 0;
+ char thisline[LINESIZE];
+ struct psk_pair *pp;
+ char *key;
+
+ if (!*args[cur_arg + 1]) {
+ if (err)
+ memprintf(err, "'%s' : missing PSK file path",
args[cur_arg]);
+ return ERR_ALERT | ERR_FATAL;
+ }
+
+ if ((f = fopen(args[cur_arg + 1], "r")) == NULL) {
+ if (err)
+ memprintf(err, "'%s' : unable to load ssl PSK file",
args[cur_arg+1]);
+ return ERR_ALERT | ERR_FATAL;
+ }
+
+ while (fgets(thisline, sizeof(thisline), f) != NULL) {
+ int len = strlen(thisline);
+ i++;
+ /* Strip newline characters from the end */
+ if(thisline[len - 1] == '\n')
+ thisline[--len] = 0;
+
+ if(thisline[len - 1] == '\r')
+ thisline[--len] = 0;
+
+ key = strchr(thisline, ':');
+ if (!key || key == thisline || key == thisline + len - 1) {
+ if (err)
+ memprintf(err, "'%s' : unable to load ssl PSK
file, syntax error at line %d", args[cur_arg+1], i);
+ return ERR_ALERT | ERR_FATAL;
+ }
+
+ *key++ = '\0';
+
+ pp = calloc(1, sizeof(*pp) + strlen(thisline) + 1);
+ memcpy(pp->node.key, thisline, strlen(thisline) + 1);
+ pp->key = strdup(key);
+
+ ebst_insert(&conf->psk, &pp->node);
+ }
+
+ return 0;
+}
+
/* parse the "ssl" bind keyword */
static int bind_parse_ssl(char **args, int cur_arg, struct proxy *px, struct
bind_conf *conf, char **err)
{
@@ -6148,6 +6255,30 @@ static int srv_parse_no_tls_tickets(char **args, int
*cur_arg, struct proxy *px,
newsrv->ssl_ctx.options |= SRV_SSL_O_NO_TLS_TICKETS;
return 0;
}
+
+static int srv_parse_psk(char **args, int *cur_arg, struct proxy *px, struct
server *newsrv, char **err)
+{
+ char *key;
+
+ if (!*args[*cur_arg + 1]) {
+ memprintf(err, "'%s' : missing PSK pair in format
<identity>:<key>", args[*cur_arg]);
+ return ERR_ALERT | ERR_FATAL;
+ }
+
+ key = strchr(args[*cur_arg + 1], ':');
+ if (!key || key == args[*cur_arg + 1] || key == args[*cur_arg + 1] +
strlen(args[*cur_arg + 1]) - 1) {
+ if (err)
+ memprintf(err, "'%s' : unable to load ssl PSK file in
format <identity>:<key>", args[*cur_arg+1]);
+ return ERR_ALERT | ERR_FATAL;
+ }
+
+ *key++ = '\0';
+ newsrv->ssl_ctx.psk_identity = strdup(args[*cur_arg+1]);
+ newsrv->ssl_ctx.psk_key = strdup(key);
+
+ return 0;
+}
+
/* parse the "send-proxy-v2-ssl" server keyword */
static int srv_parse_send_proxy_ssl(char **args, int *cur_arg, struct proxy
*px, struct server *newsrv, char **err)
{
@@ -6899,6 +7030,7 @@ static struct bind_kw_list bind_kws = { "SSL", { }, {
{ "no-tlsv11", bind_parse_no_tlsv11, 0 }, /* disable
TLSv11 */
{ "no-tlsv12", bind_parse_no_tlsv12, 0 }, /* disable
TLSv12 */
{ "no-tls-tickets", bind_parse_no_tls_tickets, 0 }, /* disable
session resumption tickets */
+ { "psk-file", bind_parse_psk_file, 1 }, /* load the
file containing PSKs */
{ "ssl", bind_parse_ssl, 0 }, /* enable
SSL processing */
{ "strict-sni", bind_parse_strict_sni, 0 }, /* refuse
negotiation if sni doesn't match a certificate */
{ "tls-ticket-keys", bind_parse_tls_ticket_keys, 1 }, /* set file
to load TLS ticket keys from */
@@ -6930,6 +7062,7 @@ static struct srv_kw_list srv_kws = { "SSL", { }, {
{ "no-tlsv11", srv_parse_no_tlsv11, 0, 0 }, /* disable
TLSv11 */
{ "no-tlsv12", srv_parse_no_tlsv12, 0, 0 }, /* disable
TLSv12 */
{ "no-tls-tickets", srv_parse_no_tls_tickets, 0, 0 }, /* disable
session resumption tickets */
+ { "psk", srv_parse_psk, 1, 0 }, /* PSK */
{ "send-proxy-v2-ssl", srv_parse_send_proxy_ssl, 0, 0 }, /* send
PROXY protocol header v2 with SSL info */
{ "send-proxy-v2-ssl-cn", srv_parse_send_proxy_cn, 0, 0 }, /* send
PROXY protocol header v2 with CN */
{ "sni", srv_parse_sni, 1, 0 }, /* send
SNI extension */
--
2.11.0