return SWITCH_STATUS_SUCCESS;
}
+SWITCH_STANDARD_API(reload_cert_function)
+{
+ switch_event_t *event;
+
+ if (switch_event_create(&event, SWITCH_EVENT_CERT_RELOAD) == SWITCH_STATUS_SUCCESS) {
+ switch_event_fire(&event);
+ stream->write_function(stream, "+OK cert reload event sent\n");
+
+ return SWITCH_STATUS_SUCCESS;
+ }
+
+ stream->write_function(stream, "-ERR failed to create event\n");
+
+ return SWITCH_STATUS_FALSE;
+}
+
#define KILL_SYNTAX "<uuid> [cause]"
SWITCH_STANDARD_API(kill_function)
{
SWITCH_ADD_API(commands_api_interface, "reloadacl", "Reload ACL", reload_acl_function, "");
SWITCH_ADD_API(commands_api_interface, "reload", "Reload module", reload_function, UNLOAD_SYNTAX);
SWITCH_ADD_API(commands_api_interface, "reloadxml", "Reload XML", reload_xml_function, "");
+ SWITCH_ADD_API(commands_api_interface, "reloadcert", "Reload SSL/TLS certificates", reload_cert_function, "");
SWITCH_ADD_API(commands_api_interface, "replace", "Replace a string", replace_function, "<data>|<string1>|<string2>");
SWITCH_ADD_API(commands_api_interface, "say_string", "", say_string_function, SAY_STRING_SYNTAX);
SWITCH_ADD_API(commands_api_interface, "sched_api", "Schedule an api command", sched_api_function, SCHED_SYNTAX);
switch_console_set_complete("add nat_map status");
switch_console_set_complete("add reload ::console::list_loaded_modules");
switch_console_set_complete("add reloadacl reloadxml");
+ switch_console_set_complete("add reloadcert");
switch_console_set_complete("add show aliases");
switch_console_set_complete("add show api");
switch_console_set_complete("add show application");
}
}
-static void close_file(ks_socket_t *sock)
+static SSL_CTX *verto_create_ssl_ctx(verto_profile_t *profile, const char **errp)
{
- if (*sock != KS_SOCK_INVALID) {
-#ifndef WIN32
- close(*sock);
-#else
- closesocket(*sock);
-#endif
- *sock = KS_SOCK_INVALID;
- }
-}
+ SSL_CTX *ctx = SSL_CTX_new(profile->ssl_method);
-static void close_socket(ks_socket_t *sock)
-{
- if (*sock != KS_SOCK_INVALID) {
- shutdown(*sock, 2);
- close_file(sock);
- }
-}
-
-void verto_broadcast(const char *event_channel, cJSON *json, const char *key, switch_event_channel_id_t id, void *user_data);
+ if (!ctx) {
+ *errp = "Failed to create SSL context";
-static int verto_init_ssl(verto_profile_t *profile)
-{
- const char *err;
- int i = 0;
-
- profile->ssl_method = SSLv23_server_method(); /* create server instance */
- profile->ssl_ctx = SSL_CTX_new(profile->ssl_method); /* create context */
- profile->ssl_ready = 1;
- assert(profile->ssl_ctx);
+ return NULL;
+ }
/* Disable SSLv2 */
- SSL_CTX_set_options(profile->ssl_ctx, SSL_OP_NO_SSLv2);
+ SSL_CTX_set_options(ctx, SSL_OP_NO_SSLv2);
/* Disable SSLv3 */
- SSL_CTX_set_options(profile->ssl_ctx, SSL_OP_NO_SSLv3);
+ SSL_CTX_set_options(ctx, SSL_OP_NO_SSLv3);
/* Disable TLSv1 */
- SSL_CTX_set_options(profile->ssl_ctx, SSL_OP_NO_TLSv1);
+ SSL_CTX_set_options(ctx, SSL_OP_NO_TLSv1);
/* Disable Compression CRIME (Compression Ratio Info-leak Made Easy) */
- SSL_CTX_set_options(profile->ssl_ctx, SSL_OP_NO_COMPRESSION);
+ SSL_CTX_set_options(ctx, SSL_OP_NO_COMPRESSION);
- /* set the local certificate from CertFile */
if (!zstr(profile->chain)) {
if (switch_file_exists(profile->chain, NULL) != SWITCH_STATUS_SUCCESS) {
- err = "SUPPLIED CHAIN FILE NOT FOUND\n";
+ *errp = "SUPPLIED CHAIN FILE NOT FOUND";
goto fail;
}
- if (!SSL_CTX_use_certificate_chain_file(profile->ssl_ctx, profile->chain)) {
- err = "CERT CHAIN FILE ERROR";
+ if (!SSL_CTX_use_certificate_chain_file(ctx, profile->chain)) {
+ *errp = "CERT CHAIN FILE ERROR";
goto fail;
}
}
if (switch_file_exists(profile->cert, NULL) != SWITCH_STATUS_SUCCESS) {
- err = "SUPPLIED CERT FILE NOT FOUND\n";
+ *errp = "SUPPLIED CERT FILE NOT FOUND";
goto fail;
}
- if (!SSL_CTX_use_certificate_file(profile->ssl_ctx, profile->cert, SSL_FILETYPE_PEM)) {
- err = "CERT FILE ERROR";
+ if (!SSL_CTX_use_certificate_file(ctx, profile->cert, SSL_FILETYPE_PEM)) {
+ *errp = "CERT FILE ERROR";
goto fail;
}
- /* set the private key from KeyFile */
-
if (switch_file_exists(profile->key, NULL) != SWITCH_STATUS_SUCCESS) {
- err = "SUPPLIED KEY FILE NOT FOUND\n";
+ *errp = "SUPPLIED KEY FILE NOT FOUND";
goto fail;
}
- if (!SSL_CTX_use_PrivateKey_file(profile->ssl_ctx, profile->key, SSL_FILETYPE_PEM)) {
- err = "PRIVATE KEY FILE ERROR";
+ if (!SSL_CTX_use_PrivateKey_file(ctx, profile->key, SSL_FILETYPE_PEM)) {
+ *errp = "PRIVATE KEY FILE ERROR";
goto fail;
}
- /* verify private key */
- if ( !SSL_CTX_check_private_key(profile->ssl_ctx) ) {
- err = "PRIVATE KEY FILE ERROR";
+ if (!SSL_CTX_check_private_key(ctx)) {
+ *errp = "PRIVATE KEY FILE ERROR";
goto fail;
}
- SSL_CTX_set_cipher_list(profile->ssl_ctx, "HIGH:!DSS:!aNULL@STRENGTH");
+ SSL_CTX_set_cipher_list(ctx, "HIGH:!DSS:!aNULL@STRENGTH");
- return 1;
+ return ctx;
fail:
- switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "SSL ERR: %s\n", err);
+ SSL_CTX_free(ctx);
- profile->ssl_ready = 0;
- verto_deinit_ssl(profile);
+ return NULL;
+}
- for (i = 0; i < profile->i; i++) {
- if (profile->ip[i].secure) {
- switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "SSL NOT ENABLED FOR LISTENER %s:%d. REVERTING TO WS\n",
- profile->ip[i].local_ip, profile->ip[i].local_port);
- profile->ip[i].secure = 0;
+static int verto_reload_ssl(verto_profile_t *profile)
+{
+ const char *err = NULL;
+ SSL_CTX *new_ctx = verto_create_ssl_ctx(profile, &err);
+
+ if (!new_ctx) {
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "SSL reload failed for profile %s: %s\n", profile->name, err);
+
+ return 0;
+ }
+
+ SSL_CTX_free(profile->ssl_ctx);
+
+ profile->ssl_ctx = new_ctx;
+ profile->ssl_ready = 1;
+
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "SSL certificates reloaded for profile %s\n", profile->name);
+
+ return 1;
+}
+
+static void cert_reload_handler(switch_event_t *event)
+{
+ verto_profile_t *p;
+
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "Certificate reload event received, processing\n");
+
+ switch_mutex_lock(verto_globals.mutex);
+
+ for (p = verto_globals.profile_head; p; p = p->next) {
+ if (p->running) {
+ switch_thread_rwlock_wrlock(p->rwlock);
+ verto_reload_ssl(p);
+ switch_thread_rwlock_unlock(p->rwlock);
}
}
- return 0;
+ switch_mutex_unlock(verto_globals.mutex);
+
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "Certificate reload event processed\n");
+}
+
+static void close_file(ks_socket_t *sock)
+{
+ if (*sock != KS_SOCK_INVALID) {
+#ifndef WIN32
+ close(*sock);
+#else
+ closesocket(*sock);
+#endif
+ *sock = KS_SOCK_INVALID;
+ }
+}
+
+static void close_socket(ks_socket_t *sock)
+{
+ if (*sock != KS_SOCK_INVALID) {
+ shutdown(*sock, 2);
+ close_file(sock);
+ }
+}
+
+void verto_broadcast(const char *event_channel, cJSON *json, const char *key, switch_event_channel_id_t id, void *user_data);
+
+static int verto_init_ssl(verto_profile_t *profile)
+{
+ const char *err = NULL;
+ int i = 0;
+
+ profile->ssl_method = SSLv23_server_method();
+ profile->ssl_ctx = verto_create_ssl_ctx(profile, &err);
+
+ if (!profile->ssl_ctx) {
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "SSL ERR: %s\n", err);
+
+ profile->ssl_ready = 0;
+
+ for (i = 0; i < profile->i; i++) {
+ if (profile->ip[i].secure) {
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "SSL NOT READY FOR LISTENER %s:%d. USE reloadcert AFTER FIXING CERTIFICATES\n",
+ profile->ip[i].local_ip, profile->ip[i].local_port);
+ }
+ }
+
+ return 0;
+ }
+
+ profile->ssl_ready = 1;
+ return 1;
}
ks_pool_open(&jsock->kpool);
+ switch_thread_rwlock_rdlock(jsock->profile->rwlock);
#if defined(KS_VERSION_NUM) && KS_VERSION_NUM >= 20000
params = ks_json_create_object();
ks_json_add_number_to_object(params, "payload_size_max", 1000000);
#else
if (kws_init(&jsock->ws, jsock->client_socket, (jsock->ptype & PTYPE_CLIENT_SSL) ? jsock->profile->ssl_ctx : NULL, 0, flags, jsock->kpool) != KS_STATUS_SUCCESS) {
#endif
+ switch_thread_rwlock_unlock(jsock->profile->rwlock);
log_and_exit(SWITCH_LOG_NOTICE, "%s WS SETUP FAILED\n", jsock->name);
}
+ switch_thread_rwlock_unlock(jsock->profile->rwlock);
if (kws_test_flag(jsock->ws, KWS_HTTP)) {
http_run(jsock);
for (i = 0; i < profile->i; i++) {
if ( profile->server_socket[i] == sock ) {
- if (profile->ip[i].secure) {
+ if (profile->ip[i].secure && profile->ssl_ready) {
ptype = PTYPE_CLIENT_SSL;
}
break;
switch_core_register_secondary_recover_callback(modname, verto_recover_callback);
+ switch_event_bind(modname, SWITCH_EVENT_CERT_RELOAD, SWITCH_EVENT_SUBCLASS_ANY, cert_reload_handler, NULL);
+
if (verto_globals.enable_presence) {
switch_event_bind(modname, SWITCH_EVENT_CHANNEL_CALLSTATE, SWITCH_EVENT_SUBCLASS_ANY, presence_event_handler, NULL);
}
switch_core_hash_destroy(&json_GLOBALS.store_hash);
switch_event_channel_unbind(NULL, verto_broadcast, NULL);
+ switch_event_unbind_callback(cert_reload_handler);
switch_event_unbind_callback(presence_event_handler);
switch_event_unbind_callback(event_handler);