#include <common/ticks.h>
#include <common/time.h>
#include <common/cfgparse.h>
+#include <common/base64.h>
#include <ebsttree.h>
#define SSL_SOCK_ST_TO_CAEDEPTH(s) ((s >> (6+16)) & 15)
#define SSL_SOCK_ST_TO_CRTERROR(s) ((s >> (4+6+16)) & 63)
+/* Supported hash function for TLS tickets */
+#ifdef OPENSSL_NO_SHA256
+#define HASH_FUNCT EVP_sha1
+#else
+#define HASH_FUNCT EVP_sha256
+#endif /* OPENSSL_NO_SHA256 */
+
/* server and bind verify method, it uses a global value as default */
enum {
SSL_SOCK_VERIFY_DEFAULT = 0,
return ret;
}
+#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)
+{
+ struct tls_sess_key *keys;
+ struct connection *conn;
+ int head;
+ int i;
+
+ conn = (struct connection *)SSL_get_app_data(s);
+ keys = objt_listener(conn->target)->bind_conf->tls_ticket_keys;
+ head = objt_listener(conn->target)->bind_conf->tls_ticket_enc_index;
+
+ if (enc) {
+ memcpy(key_name, keys[head].name, 16);
+
+ if(!RAND_pseudo_bytes(iv, EVP_MAX_IV_LENGTH))
+ return -1;
+
+ if(!EVP_EncryptInit_ex(ectx, EVP_aes_128_cbc(), NULL, keys[head].aes_key, iv))
+ return -1;
+
+ HMAC_Init_ex(hctx, keys[head].hmac_key, 16, HASH_FUNCT(), NULL);
+
+ return 1;
+ } else {
+ for (i = 0; i < TLS_TICKETS_NO; i++) {
+ if (!memcmp(key_name, keys[(head + i) % TLS_TICKETS_NO].name, 16))
+ goto found;
+ }
+ return 0;
+
+ found:
+ HMAC_Init_ex(hctx, keys[(head + i) % TLS_TICKETS_NO].hmac_key, 16, HASH_FUNCT(), NULL);
+ if(!EVP_DecryptInit_ex(ectx, EVP_aes_128_cbc(), NULL, keys[(head + i) % TLS_TICKETS_NO].aes_key, iv))
+ return -1;
+ /* 2 for key renewal, 1 if current key is still valid */
+ return i ? 2 : 1;
+ }
+}
+#endif /* SSL_CTRL_SET_TLSEXT_TICKET_KEY_CB */
+
/*
* Callback used to set OCSP status extension content in server hello.
*/
ERR_clear_error();
}
+#if (defined SSL_CTRL_SET_TLSEXT_TICKET_KEY_CB && TLS_TICKETS_NO > 0)
+ if(bind_conf->tls_ticket_keys) {
+ if (!SSL_CTX_set_tlsext_ticket_key_cb(ctx, ssl_tlsext_ticket_key_cb)) {
+ Alert("Proxy '%s': unable to set callback for TLS ticket validation for bind '%s' at [%s:%d].\n",
+ curproxy->id, bind_conf->arg, bind_conf->file, bind_conf->line);
+ cfgerr++;
+ }
+ }
+#endif
+
if (global.tune.ssllifetime)
SSL_CTX_set_timeout(ctx, global.tune.ssllifetime);
return 0;
}
+/* parse the "tls-ticket-keys" bind keyword */
+static int bind_parse_tls_ticket_keys(char **args, int cur_arg, struct proxy *px, struct bind_conf *conf, char **err)
+{
+#if (defined SSL_CTRL_SET_TLSEXT_TICKET_KEY_CB && TLS_TICKETS_NO > 0)
+ FILE *f;
+ int i = 0;
+ char thisline[LINESIZE];
+
+ if (!*args[cur_arg + 1]) {
+ if (err)
+ memprintf(err, "'%s' : missing TLS ticket keys file path", args[cur_arg]);
+ return ERR_ALERT | ERR_FATAL;
+ }
+
+ conf->tls_ticket_keys = malloc(TLS_TICKETS_NO * sizeof(struct tls_sess_key));
+
+ if ((f = fopen(args[cur_arg + 1], "r")) == NULL) {
+ if (err)
+ memprintf(err, "'%s' : unable to load ssl tickets keys file", args[cur_arg+1]);
+ return ERR_ALERT | ERR_FATAL;
+ }
+
+ while (fgets(thisline, sizeof(thisline), f) != NULL) {
+ int len = strlen(thisline);
+ /* Strip newline characters from the end */
+ if(thisline[len - 1] == '\n')
+ thisline[--len] = 0;
+
+ if(thisline[len - 1] == '\r')
+ thisline[--len] = 0;
+
+ if (base64dec(thisline, len, (char *) (conf->tls_ticket_keys + i % TLS_TICKETS_NO), sizeof(struct tls_sess_key)) != sizeof(struct tls_sess_key)) {
+ if (err)
+ memprintf(err, "'%s' : unable to decode base64 key on line %d", args[cur_arg+1], i + 1);
+ return ERR_ALERT | ERR_FATAL;
+ }
+ i++;
+ }
+
+ if (i < TLS_TICKETS_NO) {
+ if (err)
+ memprintf(err, "'%s' : please supply at least %d keys in the tls-tickets-file", args[cur_arg+1], TLS_TICKETS_NO);
+ return ERR_ALERT | ERR_FATAL;
+ }
+
+ fclose(f);
+
+ /* Use penultimate key for encryption, handle when TLS_TICKETS_NO = 1 */
+ i-=2;
+ conf->tls_ticket_enc_index = i < 0 ? 0 : i;
+
+ return 0;
+#else
+ if (err)
+ memprintf(err, "'%s' : TLS ticket callback extension not supported", args[cur_arg]);
+ return ERR_ALERT | ERR_FATAL;
+#endif /* SSL_CTRL_SET_TLSEXT_TICKET_KEY_CB */
+}
+
/* parse the "verify" bind keyword */
static int bind_parse_verify(char **args, int cur_arg, struct proxy *px, struct bind_conf *conf, char **err)
{
* not enabled.
*/
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 */
- { "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 */
- { "crt-ignore-err", bind_parse_ignore_err, 1 }, /* set error IDs to ingore on verify depth == 0 */
- { "crt-list", bind_parse_crt_list, 1 }, /* load a list of crt from this location */
- { "ecdhe", bind_parse_ecdhe, 1 }, /* defines named curve for elliptic curve Diffie-Hellman */
- { "force-sslv3", bind_parse_force_sslv3, 0 }, /* force SSLv3 */
- { "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 */
- { "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 */
- { "no-tlsv12", bind_parse_no_tlsv12, 0 }, /* disable TLSv12 */
- { "no-tls-tickets", bind_parse_no_tls_tickets, 0 }, /* disable session resumption tickets */
- { "ssl", bind_parse_ssl, 0 }, /* enable SSL processing */
- { "strict-sni", bind_parse_strict_sni, 0 }, /* refuse negotiation if sni doesn't match a certificate */
- { "verify", bind_parse_verify, 1 }, /* set SSL verify method */
- { "npn", bind_parse_npn, 1 }, /* set NPN supported protocols */
+ { "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 */
+ { "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 */
+ { "crt-ignore-err", bind_parse_ignore_err, 1 }, /* set error IDs to ingore on verify depth == 0 */
+ { "crt-list", bind_parse_crt_list, 1 }, /* load a list of crt from this location */
+ { "ecdhe", bind_parse_ecdhe, 1 }, /* defines named curve for elliptic curve Diffie-Hellman */
+ { "force-sslv3", bind_parse_force_sslv3, 0 }, /* force SSLv3 */
+ { "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 */
+ { "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 */
+ { "no-tlsv12", bind_parse_no_tlsv12, 0 }, /* disable TLSv12 */
+ { "no-tls-tickets", bind_parse_no_tls_tickets, 0 }, /* disable session resumption tickets */
+ { "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 */
+ { "verify", bind_parse_verify, 1 }, /* set SSL verify method */
+ { "npn", bind_parse_npn, 1 }, /* set NPN supported protocols */
{ NULL, NULL, 0 },
}};