From 2124b930fd9cf2cf19a2eeeeae3cc77f5dc17051 Mon Sep 17 00:00:00 2001 From: Unbit Date: Sat, 14 Dec 2013 17:54:19 +0100 Subject: [PATCH] subscription system can now create sni contexts --- core/ssl.c | 32 ++++++++++++++++- core/subscription.c | 61 +++++++++++++++++++++++++++++---- plugins/corerouter/corerouter.c | 13 +++++++ uwsgi.h | 13 ++++++- 4 files changed, 111 insertions(+), 8 deletions(-) diff --git a/core/ssl.c b/core/ssl.c index eb2bbca1..88c3df16 100644 --- a/core/ssl.c +++ b/core/ssl.c @@ -132,7 +132,6 @@ static int uwsgi_sni_cb(SSL *ssl, int *ad, void *arg) { free(sni_dir_key); free(sni_dir_client_ca); SSL_set_SSL_CTX(ssl, usl->custom_ptr); - uwsgi_log("[uwsgi-sni for pid %d] added context for %s\n", (int) getpid(), servername); return SSL_TLSEXT_ERR_OK; } done: @@ -511,10 +510,41 @@ struct uwsgi_string_list *uwsgi_ssl_add_sni_item(char *name, char *crt, char *ke SSL_CTX *ctx = uwsgi_ssl_new_server_context(name, crt, key, ciphers, client_ca); if (!ctx) { uwsgi_log("[uwsgi-ssl] DANGER unable to initialize context for \"%s\"\n", name); + free(name); return NULL; } struct uwsgi_string_list *usl = uwsgi_string_new_list(&uwsgi.sni, name); usl->custom_ptr = ctx; + // mark it as dynamic + usl->custom = 1; + uwsgi_log_verbose("[uwsgi-sni for pid %d] added SSL context for %s\n", (int) getpid(), name); return usl; } + +void uwsgi_ssl_del_sni_item(char *name, uint16_t name_len) { + struct uwsgi_string_list *usl = NULL, *last_sni = NULL, *sni_item = NULL; + uwsgi_foreach(usl, uwsgi.sni) { + if (!uwsgi_strncmp(usl->value, usl->len, name, name_len) && usl->custom) { + sni_item = usl; + break; + } + last_sni = NULL; + } + + if (!sni_item) return; + + if (last_sni) { + last_sni = sni_item->next; + } + else { + uwsgi.sni = sni_item->next; + } + + // we are free to destroy it as no more clients are using it + SSL_CTX_free((SSL_CTX *) sni_item->custom_ptr); + free(sni_item->value); + free(sni_item); + + uwsgi_log_verbose("[uwsgi-sni for pid %d] destroyed SSL context for %s\n",(int) getpid(), name); +} diff --git a/core/subscription.c b/core/subscription.c index 7f3ee654..03629c6a 100644 --- a/core/subscription.c +++ b/core/subscription.c @@ -20,6 +20,27 @@ extern struct uwsgi_server uwsgi; +#ifdef UWSGI_SSL +static void uwsgi_subscription_sni_check(struct uwsgi_subscribe_slot *current_slot, struct uwsgi_subscribe_req *usr) { + if (usr->sni_key_len > 0 && usr->sni_crt_len > 0) { + if (!current_slot->sni_enabled) { + char *sni_key = uwsgi_concat2n(usr->sni_key, usr->sni_key_len, "", 0); + char *sni_crt = uwsgi_concat2n(usr->sni_crt, usr->sni_crt_len, "", 0); + char *sni_ca = NULL; + if (usr->sni_ca_len > 0) { + sni_ca = uwsgi_concat2n(usr->sni_ca, usr->sni_ca_len, "", 0); + } + if (uwsgi_ssl_add_sni_item(uwsgi_concat2n(current_slot->key, current_slot->keylen, "", 0), sni_crt, sni_key, uwsgi.sni_dir_ciphers , sni_ca)) { + current_slot->sni_enabled = 1; + } + if (sni_key) free(sni_key); + if (sni_crt) free(sni_crt); + if (sni_ca) free(sni_ca); + } + } +} +#endif + struct uwsgi_subscribe_slot *uwsgi_get_subscribe_slot(struct uwsgi_subscribe_slot **slot, char *key, uint16_t keylen) { if (keylen > 0xff) @@ -305,6 +326,12 @@ int uwsgi_remove_subscribe_node(struct uwsgi_subscribe_slot **slot, struct uwsgi EVP_PKEY_free(node_slot->sign_public_key); EVP_MD_CTX_destroy(node_slot->sign_ctx); } +#ifdef SSL_CTRL_SET_TLSEXT_HOSTNAME + // if there is a SNI context active, destroy it + if (node_slot->sni_enabled) { + uwsgi_ssl_del_sni_item(node_slot->key, node_slot->keylen); + } +#endif #endif free(node_slot); slot[hash_key] = NULL; @@ -388,6 +415,8 @@ struct uwsgi_subscribe_node *uwsgi_add_subscribe_node(struct uwsgi_subscribe_slo uwsgi_log("[uwsgi-subscription for pid %d] invalid (sniffed ?) packet sent for slot: %.*s node: %.*s unix_check: %lu\n", (int) uwsgi.mypid, usr->keylen, usr->key, usr->address_len, usr->address, (unsigned long) usr->unix_check); return NULL; } + // check here as we are sure the node will be added + uwsgi_subscription_sni_check(current_slot, usr); #endif node = uwsgi_malloc(sizeof(struct uwsgi_subscribe_node)); @@ -466,7 +495,10 @@ struct uwsgi_subscribe_node *uwsgi_add_subscribe_node(struct uwsgi_subscribe_slo memcpy(current_slot->key, usr->key, usr->keylen); current_slot->key[usr->keylen] = 0; current_slot->hits = 0; - +#ifdef UWSGI_SSL + current_slot->sni_enabled = 0; + uwsgi_subscription_sni_check(current_slot, usr); +#endif current_slot->nodes = uwsgi_malloc(sizeof(struct uwsgi_subscribe_node)); current_slot->nodes->slot = current_slot; current_slot->nodes->len = usr->address_len; @@ -517,7 +549,7 @@ struct uwsgi_subscribe_node *uwsgi_add_subscribe_node(struct uwsgi_subscribe_slo } -void uwsgi_send_subscription(char *udp_address, char *key, size_t keysize, uint8_t modifier1, uint8_t modifier2, uint8_t cmd, char *socket_name, char *sign) { +void uwsgi_send_subscription(char *udp_address, char *key, size_t keysize, uint8_t modifier1, uint8_t modifier2, uint8_t cmd, char *socket_name, char *sign, char *sni_key, char *sni_crt, char *sni_ca) { if (socket_name == NULL && !uwsgi.sockets) return; @@ -560,6 +592,17 @@ void uwsgi_send_subscription(char *udp_address, char *key, size_t keysize, uint8 } #endif + if (sni_key) { + if (uwsgi_buffer_append_keyval(ub, "sni_key", 7, sni_key, strlen(sni_key))) goto end; + } + + if (sni_crt) { + if (uwsgi_buffer_append_keyval(ub, "sni_crt", 7, sni_crt, strlen(sni_crt))) goto end; + } + + if (sni_ca) { + if (uwsgi_buffer_append_keyval(ub, "sni_ca", 6, sni_ca, strlen(sni_ca))) goto end; + } send_udp_message(224, cmd, udp_address, ub->buf, ub->pos - 4); end: @@ -679,7 +722,7 @@ void uwsgi_subscribe(char *subscription, uint8_t cmd) { modifier1_len = strlen(modifier1); keysize = strlen(key); } - uwsgi_send_subscription(udp_address, key, keysize, uwsgi_str_num(modifier1, modifier1_len), 0, cmd, socket_name, sign); + uwsgi_send_subscription(udp_address, key, keysize, uwsgi_str_num(modifier1, modifier1_len), 0, cmd, socket_name, sign, NULL, NULL, NULL); modifier1 = NULL; modifier1_len = 0; } @@ -697,7 +740,7 @@ void uwsgi_subscribe(char *subscription, uint8_t cmd) { modifier1_len = strlen(modifier1); keysize = strlen(key); } - uwsgi_send_subscription(udp_address, key, keysize, uwsgi_str_num(modifier1, modifier1_len), 0, cmd, socket_name, sign); + uwsgi_send_subscription(udp_address, key, keysize, uwsgi_str_num(modifier1, modifier1_len), 0, cmd, socket_name, sign, NULL, NULL, NULL); modifier1 = NULL; modifier1_len = 0; lines[i] = '\n'; @@ -727,7 +770,7 @@ void uwsgi_subscribe(char *subscription, uint8_t cmd) { modifier1_len = strlen(modifier1); } - uwsgi_send_subscription(udp_address, subscription_key + 1, strlen(subscription_key + 1), uwsgi_str_num(modifier1, modifier1_len), 0, cmd, socket_name, sign); + uwsgi_send_subscription(udp_address, subscription_key + 1, strlen(subscription_key + 1), uwsgi_str_num(modifier1, modifier1_len), 0, cmd, socket_name, sign, NULL, NULL, NULL); if (modifier1) modifier1[-1] = ','; if (sign) @@ -752,6 +795,9 @@ void uwsgi_subscribe2(char *arg, uint8_t cmd) { char *s2_modifier1 = NULL; char *s2_modifier2 = NULL; char *s2_check = NULL; + char *s2_sni_key = NULL; + char *s2_sni_crt = NULL; + char *s2_sni_ca = NULL; if (uwsgi_kvlist_parse(arg, strlen(arg), ',', '=', "server", &s2_server, @@ -763,6 +809,9 @@ void uwsgi_subscribe2(char *arg, uint8_t cmd) { "modifier2", &s2_modifier2, "sign", &s2_sign, "check", &s2_check, + "sni_key", &s2_sni_key, + "sni_crt", &s2_sni_crt, + "sni_ca", &s2_sni_ca, NULL)) { return; } @@ -798,7 +847,7 @@ void uwsgi_subscribe2(char *arg, uint8_t cmd) { modifier2 = atoi(s2_modifier2); } - uwsgi_send_subscription(s2_server, s2_key, strlen(s2_key), modifier1, modifier2, cmd, s2_addr, s2_sign); + uwsgi_send_subscription(s2_server, s2_key, strlen(s2_key), modifier1, modifier2, cmd, s2_addr, s2_sign, s2_sni_key, s2_sni_crt, s2_sni_ca); end: if (s2_server) free(s2_server); if (s2_key) free(s2_key); diff --git a/plugins/corerouter/corerouter.c b/plugins/corerouter/corerouter.c index 46a33384..453a86a1 100644 --- a/plugins/corerouter/corerouter.c +++ b/plugins/corerouter/corerouter.c @@ -272,6 +272,18 @@ void corerouter_manage_subscription(char *key, uint16_t keylen, char *val, uint1 usr->sign = val; usr->sign_len = vallen; } + else if (!uwsgi_strncmp("sni_key", 7, key, keylen)) { + usr->sni_key = val; + usr->sni_key_len = vallen; + } + else if (!uwsgi_strncmp("sni_crt", 7, key, keylen)) { + usr->sni_crt = val; + usr->sni_crt_len = vallen; + } + else if (!uwsgi_strncmp("sni_ca", 6, key, keylen)) { + usr->sni_ca = val; + usr->sni_ca_len = vallen; + } } void corerouter_close_peer(struct uwsgi_corerouter *ucr, struct corerouter_peer *peer) { @@ -1021,6 +1033,7 @@ void corerouter_send_stats(struct uwsgi_corerouter *ucr) { if (uwsgi_stats_keyvaln_comma(us, "key", s_slot->key, s_slot->keylen)) goto end0; if (uwsgi_stats_keylong_comma(us, "hash", (unsigned long long) s_slot->hash)) goto end0; if (uwsgi_stats_keylong_comma(us, "hits", (unsigned long long) s_slot->hits)) goto end0; + if (uwsgi_stats_keylong_comma(us, "sni_enabled", (unsigned long long) s_slot->sni_enabled)) goto end0; if (uwsgi_stats_key(us , "nodes")) goto end0; if (uwsgi_stats_list_open(us)) goto end0; diff --git a/uwsgi.h b/uwsgi.h index 579ae4b6..f2c01628 100644 --- a/uwsgi.h +++ b/uwsgi.h @@ -3201,6 +3201,15 @@ struct uwsgi_subscribe_req { char *base; uint16_t base_len; + + char *sni_key; + uint16_t sni_key_len; + + char *sni_crt; + uint16_t sni_crt_len; + + char *sni_ca; + uint16_t sni_ca_len; }; void uwsgi_nuclear_blast(); @@ -3479,6 +3488,7 @@ struct uwsgi_subscribe_slot { #ifdef UWSGI_SSL EVP_PKEY *sign_public_key; EVP_MD_CTX *sign_ctx; + uint8_t sni_enabled; #endif }; @@ -3506,7 +3516,7 @@ void uwsgi_configure(); int uwsgi_read_response(int, struct uwsgi_header *, int, char **); char *uwsgi_simple_file_read(char *); -void uwsgi_send_subscription(char *, char *, size_t, uint8_t, uint8_t, uint8_t, char *, char *); +void uwsgi_send_subscription(char *, char *, size_t, uint8_t, uint8_t, uint8_t, char *, char *, char *, char *, char *); void uwsgi_subscribe(char *, uint8_t); void uwsgi_subscribe2(char *, uint8_t); @@ -3599,6 +3609,7 @@ void uwsgi_opt_add_legion_cron(char *, char *, void *); void uwsgi_opt_add_unique_legion_cron(char *, char *, void *); void uwsgi_opt_sni(char *, char *, void *); struct uwsgi_string_list *uwsgi_ssl_add_sni_item(char *, char *, char *, char *, char *); +void uwsgi_ssl_del_sni_item(char *, uint16_t); #endif void uwsgi_opt_flock(char *, char *, void *); void uwsgi_opt_flock_wait(char *, char *, void *);