#ifdef USE_OPENSSL
#include <proto/ssl_sock.h>
+#include <types/ssl_sock.h>
#endif
/* stats socket states */
STAT_CLI_O_PAT, /* list all entries of a pattern */
STAT_CLI_O_MLOOK, /* lookup a map entry */
STAT_CLI_O_POOLS, /* dump memory pools */
+ STAT_CLI_O_TLSK, /* list all TLS ticket keys references */
};
/* Actions available for the stats admin forms */
static int stats_pats_list(struct stream_interface *si);
static int stats_pat_list(struct stream_interface *si);
static int stats_map_lookup(struct stream_interface *si);
+#if (defined SSL_CTRL_SET_TLSEXT_TICKET_KEY_CB && TLS_TICKETS_NO > 0)
+static int stats_tlskeys_list(struct stream_interface *si);
+#endif
static void cli_release_handler(struct appctx *appctx);
/*
return sv;
}
+/* This function is used with TLS ticket keys management. It permits to browse
+ * each reference. The variable <getnext> must contain the current node,
+ * <end> point to the root node.
+ */
+#if (defined SSL_CTRL_SET_TLSEXT_TICKET_KEY_CB && TLS_TICKETS_NO > 0)
+static inline
+struct tls_keys_ref *tlskeys_list_get_next(struct tls_keys_ref *getnext, struct list *end)
+{
+ struct tls_keys_ref *ref = getnext;
+
+ while (1) {
+
+ /* Get next list entry. */
+ ref = LIST_NEXT(&ref->list, struct tls_keys_ref *, list);
+
+ /* If the entry is the last of the list, return NULL. */
+ if (&ref->list == end)
+ return NULL;
+
+ return ref;
+ }
+}
+
+static inline
+struct tls_keys_ref *tlskeys_ref_lookup_ref(const char *reference)
+{
+ int id;
+ char *error;
+
+ /* If the reference starts by a '#', this is numeric id. */
+ if (reference[0] == '#') {
+ /* Try to convert the numeric id. If the conversion fails, the lookup fails. */
+ id = strtol(reference + 1, &error, 10);
+ if (*error != '\0')
+ return NULL;
+
+ /* Perform the unique id lookup. */
+ return tlskeys_ref_lookupid(id);
+ }
+
+ /* Perform the string lookup. */
+ return tlskeys_ref_lookup(reference);
+}
+#endif
+
/* This function is used with map and acl management. It permits to browse
* each reference. The variable <getnext> must contain the current node,
* <end> point to the root node and the <flags> permit to filter required
else if (strcmp(args[1], "table") == 0) {
stats_sock_table_request(si, args, STAT_CLI_O_TAB);
}
+ else if (strcmp(args[1], "tls-keys") == 0) {
+#if (defined SSL_CTRL_SET_TLSEXT_TICKET_KEY_CB && TLS_TICKETS_NO > 0)
+ appctx->st2 = STAT_ST_INIT;
+ appctx->st0 = STAT_CLI_O_TLSK;
+#else
+ appctx->ctx.cli.msg = "HAProxy was compiled against a version of OpenSSL "
+ "that doesn't support specifying TLS ticket keys\n";
+ appctx->st0 = STAT_CLI_PRINT;
+#endif
+ return 1;
+ }
else if (strcmp(args[1], "map") == 0 ||
strcmp(args[1], "acl") == 0) {
appctx->ctx.cli.msg = "HAProxy was compiled against a version of OpenSSL that doesn't support OCSP stapling.\n";
appctx->st0 = STAT_CLI_PRINT;
return 1;
+#endif
+ }
+ else if (strcmp(args[2], "tls-key") == 0) {
+#if (defined SSL_CTRL_SET_TLSEXT_TICKET_KEY_CB && TLS_TICKETS_NO > 0)
+ /* Expect two parameters: the filename and the new new TLS key in encoding */
+ if (!*args[3] || !*args[4]) {
+ appctx->ctx.cli.msg = "'set ssl tls-key' expects a filename and the new TLS key in base64 encoding.\n";
+ appctx->st0 = STAT_CLI_PRINT;
+ return 1;
+ }
+
+ appctx->ctx.tlskeys.ref = tlskeys_ref_lookup_ref(args[3]);
+ if(!appctx->ctx.tlskeys.ref) {
+ appctx->ctx.cli.msg = "'set ssl tls-key' unable to locate referenced filename\n";
+ appctx->st0 = STAT_CLI_PRINT;
+ return 1;
+ }
+
+ trash.len = base64dec(args[4], strlen(args[4]), trash.str, trash.size);
+ if (trash.len != sizeof(struct tls_sess_key)) {
+ appctx->ctx.cli.msg = "'set ssl tls-key' received invalid base64 encoded TLS key.\n";
+ appctx->st0 = STAT_CLI_PRINT;
+ return 1;
+ }
+
+ memcpy(appctx->ctx.tlskeys.ref->tlskeys + 2 % TLS_TICKETS_NO, trash.str, trash.len);
+ appctx->ctx.tlskeys.ref->tls_ticket_enc_index = appctx->ctx.tlskeys.ref->tls_ticket_enc_index + 1 % TLS_TICKETS_NO;
+
+ appctx->ctx.cli.msg = "TLS ticket key updated!";
+ appctx->st0 = STAT_CLI_PRINT;
+ return 1;
+#else
+ appctx->ctx.cli.msg = "HAProxy was compiled against a version of OpenSSL "
+ "that doesn't support specifying TLS ticket keys\n";
+ appctx->st0 = STAT_CLI_PRINT;
+ return 1;
#endif
}
else {
if (stats_dump_pools_to_buffer(si))
appctx->st0 = STAT_CLI_PROMPT;
break;
+#if (defined SSL_CTRL_SET_TLSEXT_TICKET_KEY_CB && TLS_TICKETS_NO > 0)
+ case STAT_CLI_O_TLSK:
+ if (stats_tlskeys_list(si))
+ appctx->st0 = STAT_CLI_PROMPT;
+ break;
+#endif
default: /* abnormal state */
cli_release_handler(appctx);
appctx->st0 = STAT_CLI_PROMPT;
return 1;
}
+#if (defined SSL_CTRL_SET_TLSEXT_TICKET_KEY_CB && TLS_TICKETS_NO > 0)
+static int stats_tlskeys_list(struct stream_interface *si) {
+ struct appctx *appctx = __objt_appctx(si->end);
+
+ switch (appctx->st2) {
+ case STAT_ST_INIT:
+ /* Display the column headers. If the message cannot be sent,
+ * quit the fucntion with returning 0. The function is called
+ * later and restart at the state "STAT_ST_INIT".
+ */
+ chunk_reset(&trash);
+ chunk_appendf(&trash, "# id (file)\n");
+ if (bi_putchk(si_ic(si), &trash) == -1) {
+ si_applet_cant_put(si);
+ return 0;
+ }
+
+ /* Now, we start the browsing of the references lists.
+ * Note that the following call to LIST_ELEM return bad pointer. The only
+ * avalaible field of this pointer is <list>. It is used with the function
+ * tlskeys_list_get_next() for retruning the first avalaible entry
+ */
+ appctx->ctx.tlskeys.ref = LIST_ELEM(&tlskeys_reference, struct tls_keys_ref *, list);
+ appctx->ctx.tlskeys.ref = tlskeys_list_get_next(appctx->ctx.tlskeys.ref, &tlskeys_reference);
+
+ appctx->st2 = STAT_ST_LIST;
+ /* fall through */
+
+ case STAT_ST_LIST:
+ while (appctx->ctx.tlskeys.ref) {
+ chunk_reset(&trash);
+
+ chunk_appendf(&trash, "%d (%s)\n", appctx->ctx.tlskeys.ref->unique_id,
+ appctx->ctx.tlskeys.ref->filename);
+
+ if (bi_putchk(si_ic(si), &trash) == -1) {
+ /* let's try again later from this stream. We add ourselves into
+ * this stream's users so that it can remove us upon termination.
+ */
+ si_applet_cant_put(si);
+ return 0;
+ }
+
+ /* get next list entry and check the end of the list */
+ appctx->ctx.tlskeys.ref = tlskeys_list_get_next(appctx->ctx.tlskeys.ref, &tlskeys_reference);
+ }
+
+ appctx->st2 = STAT_ST_FIN;
+ /* fall through */
+
+ default:
+ appctx->st2 = STAT_ST_FIN;
+ return 1;
+ }
+ return 0;
+}
+#endif
+
static int stats_pats_list(struct stream_interface *si)
{
struct appctx *appctx = __objt_appctx(si->end);
int sslconns = 0;
int totalsslconns = 0;
+#if (defined SSL_CTRL_SET_TLSEXT_TICKET_KEY_CB && TLS_TICKETS_NO > 0)
+struct list tlskeys_reference = LIST_HEAD_INIT(tlskeys_reference);
+#endif
+
#ifndef OPENSSL_NO_DH
static DH *local_dh_1024 = NULL;
static DH *local_dh_2048 = NULL;
return i ? 2 : 1;
}
}
+
+struct tls_keys_ref *tlskeys_ref_lookup(const char *filename)
+{
+ struct tls_keys_ref *ref;
+
+ list_for_each_entry(ref, &tlskeys_reference, list)
+ if (ref->filename && strcmp(filename, ref->filename) == 0)
+ return ref;
+ return NULL;
+}
+
+struct tls_keys_ref *tlskeys_ref_lookupid(int unique_id)
+{
+ struct tls_keys_ref *ref;
+
+ list_for_each_entry(ref, &tlskeys_reference, list)
+ if (ref->unique_id == unique_id)
+ return ref;
+ return NULL;
+}
+
+int ssl_sock_update_tlskey(char *filename, struct chunk *tlskey, char **err) {
+ struct tls_keys_ref *ref = tlskeys_ref_lookup(filename);
+
+ if(!ref) {
+ memprintf(err, "Unable to locate the referenced filename: %s", filename);
+ return 1;
+ }
+
+ memcpy((char *) (ref->tlskeys + 2 % TLS_TICKETS_NO), tlskey->str, tlskey->len);
+ ref->tls_ticket_enc_index = ref->tls_ticket_enc_index + 1 % TLS_TICKETS_NO;
+
+ return 0;
+}
+
+/* This function finalize the configuration parsing. Its set all the
+ * automatic ids
+ */
+void tlskeys_finalize_config(void)
+{
+ int i = 0;
+ struct tls_keys_ref *ref, *ref2, *ref3;
+ struct list tkr = LIST_HEAD_INIT(tkr);
+
+ list_for_each_entry(ref, &tlskeys_reference, list) {
+ if (ref->unique_id == -1) {
+ /* Look for the first free id. */
+ while (1) {
+ list_for_each_entry(ref2, &tlskeys_reference, list) {
+ if (ref2->unique_id == i) {
+ i++;
+ break;
+ }
+ }
+ if (&ref2->list == &tlskeys_reference)
+ break;
+ }
+
+ /* Uses the unique id and increment it for the next entry. */
+ ref->unique_id = i;
+ i++;
+ }
+ }
+
+ /* This sort the reference list by id. */
+ list_for_each_entry_safe(ref, ref2, &tlskeys_reference, list) {
+ LIST_DEL(&ref->list);
+ list_for_each_entry(ref3, &tkr, list) {
+ if (ref->unique_id < ref3->unique_id) {
+ LIST_ADDQ(&ref3->list, &ref->list);
+ break;
+ }
+ }
+ if (&ref3->list == &tkr)
+ LIST_ADDQ(&tkr, &ref->list);
+ }
+
+ /* swap root */
+ LIST_ADD(&tkr, &tlskeys_reference);
+ LIST_DEL(&tkr);
+}
+
#endif /* SSL_CTRL_SET_TLSEXT_TICKET_KEY_CB */
/*
return ERR_ALERT | ERR_FATAL;
}
+ keys_ref = tlskeys_ref_lookup(args[cur_arg + 1]);
+ if(keys_ref) {
+ conf->keys_ref = keys_ref;
+ return 0;
+ }
+
keys_ref = malloc(sizeof(struct tls_keys_ref));
keys_ref->tlskeys = malloc(TLS_TICKETS_NO * sizeof(struct tls_sess_key));
/* Use penultimate key for encryption, handle when TLS_TICKETS_NO = 1 */
i-=2;
keys_ref->tls_ticket_enc_index = i < 0 ? 0 : i;
+ keys_ref->unique_id = -1;
conf->keys_ref = keys_ref;
+ LIST_ADD(&tlskeys_reference, &keys_ref->list);
+
return 0;
#else
if (err)