#include "asterisk.h"
#include <fcntl.h>
#include <signal.h>
#include <sys/signal.h>
#include "asterisk/compat.h"
#include "asterisk/tcptls.h"
#include "asterisk/http.h"
#include "asterisk/utils.h"
#include "asterisk/strings.h"
#include "asterisk/options.h"
#include "asterisk/manager.h"
#include "asterisk/astobj2.h"
Go to the source code of this file.
Functions | |
static int | __ssl_setup (struct ast_tls_config *cfg, int client) |
int | ast_ssl_setup (struct ast_tls_config *cfg) |
Set up an SSL server. | |
void | ast_ssl_teardown (struct ast_tls_config *cfg) |
free resources used by an SSL server | |
ast_tcptls_session_instance * | ast_tcptls_client_create (struct ast_tcptls_session_args *desc) |
ast_tcptls_session_instance * | ast_tcptls_client_start (struct ast_tcptls_session_instance *tcptls_session) |
attempts to connect and start tcptls session, on error the tcptls_session's ref count is decremented, fd and file are closed, and NULL is returned. | |
void | ast_tcptls_close_session_file (struct ast_tcptls_session_instance *tcptls_session) |
Closes a tcptls session instance's file and/or file descriptor. The tcptls_session will be set to NULL and it's file descriptor will be set to -1 by this function. | |
HOOK_T | ast_tcptls_server_read (struct ast_tcptls_session_instance *tcptls_session, void *buf, size_t count) |
void * | ast_tcptls_server_root (void *data) |
void | ast_tcptls_server_start (struct ast_tcptls_session_args *desc) |
This is a generic (re)start routine for a TCP server, which does the socket/bind/listen and starts a thread for handling accept(). | |
void | ast_tcptls_server_stop (struct ast_tcptls_session_args *desc) |
Shutdown a running server if there is one. | |
HOOK_T | ast_tcptls_server_write (struct ast_tcptls_session_instance *tcptls_session, const void *buf, size_t count) |
int | ast_tls_read_conf (struct ast_tls_config *tls_cfg, struct ast_tcptls_session_args *tls_desc, const char *varname, const char *value) |
Used to parse conf files containing tls/ssl options. | |
static void * | handle_tcptls_connection (void *data) |
creates a FILE * from the fd passed by the accept thread. This operation is potentially expensive (certificate verification), so we do it in the child thread context. | |
static void | session_instance_destructor (void *obj) |
static int | ssl_close (void *cookie) |
static HOOK_T | ssl_read (void *cookie, char *buf, LEN_T len) |
replacement read/write functions for SSL support. We use wrappers rather than SSL_read/SSL_write directly so we can put in some debugging. | |
static HOOK_T | ssl_write (void *cookie, const char *buf, LEN_T len) |
Brett Bryant <brettbryant@gmail.com>
Definition in file tcptls.c.
static int __ssl_setup | ( | struct ast_tls_config * | cfg, | |
int | client | |||
) | [static] |
Definition at line 307 of file tcptls.c.
References ast_debug, AST_SSL_SSLV2_CLIENT, AST_SSL_SSLV3_CLIENT, AST_SSL_TLSV1_CLIENT, ast_strlen_zero(), ast_test_flag, ast_verb, ast_tls_config::cafile, ast_tls_config::capath, ast_tls_config::certfile, ast_tls_config::cipher, ast_tls_config::enabled, ast_tls_config::flags, ast_tls_config::pvtfile, S_OR, and ast_tls_config::ssl_ctx.
Referenced by ast_ssl_setup(), and ast_tcptls_client_start().
00308 { 00309 #ifndef DO_SSL 00310 cfg->enabled = 0; 00311 return 0; 00312 #else 00313 if (!cfg->enabled) 00314 return 0; 00315 00316 SSL_load_error_strings(); 00317 SSLeay_add_ssl_algorithms(); 00318 00319 /* Get rid of an old SSL_CTX since we're about to 00320 * allocate a new one 00321 */ 00322 if (cfg->ssl_ctx) { 00323 SSL_CTX_free(cfg->ssl_ctx); 00324 cfg->ssl_ctx = NULL; 00325 } 00326 00327 if (client) { 00328 #ifndef OPENSSL_NO_SSL2 00329 if (ast_test_flag(&cfg->flags, AST_SSL_SSLV2_CLIENT)) { 00330 cfg->ssl_ctx = SSL_CTX_new(SSLv2_client_method()); 00331 } else 00332 #endif 00333 if (ast_test_flag(&cfg->flags, AST_SSL_SSLV3_CLIENT)) { 00334 cfg->ssl_ctx = SSL_CTX_new(SSLv3_client_method()); 00335 } else if (ast_test_flag(&cfg->flags, AST_SSL_TLSV1_CLIENT)) { 00336 cfg->ssl_ctx = SSL_CTX_new(TLSv1_client_method()); 00337 } else { 00338 /* SSLv23_client_method() sends SSLv2, this was the original 00339 * default for ssl clients before the option was given to 00340 * pick what protocol a client should use. In order not 00341 * to break expected behavior it remains the default. */ 00342 cfg->ssl_ctx = SSL_CTX_new(SSLv23_client_method()); 00343 } 00344 } else { 00345 /* SSLv23_server_method() supports TLSv1, SSLv2, and SSLv3 inbound connections. */ 00346 cfg->ssl_ctx = SSL_CTX_new(SSLv23_server_method()); 00347 } 00348 00349 if (!cfg->ssl_ctx) { 00350 ast_debug(1, "Sorry, SSL_CTX_new call returned null...\n"); 00351 cfg->enabled = 0; 00352 return 0; 00353 } 00354 if (!ast_strlen_zero(cfg->certfile)) { 00355 char *tmpprivate = ast_strlen_zero(cfg->pvtfile) ? cfg->certfile : cfg->pvtfile; 00356 if (SSL_CTX_use_certificate_file(cfg->ssl_ctx, cfg->certfile, SSL_FILETYPE_PEM) == 0) { 00357 if (!client) { 00358 /* Clients don't need a certificate, but if its setup we can use it */ 00359 ast_verb(0, "SSL error loading cert file. <%s>", cfg->certfile); 00360 sleep(2); 00361 cfg->enabled = 0; 00362 SSL_CTX_free(cfg->ssl_ctx); 00363 cfg->ssl_ctx = NULL; 00364 return 0; 00365 } 00366 } 00367 if ((SSL_CTX_use_PrivateKey_file(cfg->ssl_ctx, tmpprivate, SSL_FILETYPE_PEM) == 0) || (SSL_CTX_check_private_key(cfg->ssl_ctx) == 0 )) { 00368 if (!client) { 00369 /* Clients don't need a private key, but if its setup we can use it */ 00370 ast_verb(0, "SSL error loading private key file. <%s>", tmpprivate); 00371 sleep(2); 00372 cfg->enabled = 0; 00373 SSL_CTX_free(cfg->ssl_ctx); 00374 cfg->ssl_ctx = NULL; 00375 return 0; 00376 } 00377 } 00378 } 00379 if (!ast_strlen_zero(cfg->cipher)) { 00380 if (SSL_CTX_set_cipher_list(cfg->ssl_ctx, cfg->cipher) == 0 ) { 00381 if (!client) { 00382 ast_verb(0, "SSL cipher error <%s>", cfg->cipher); 00383 sleep(2); 00384 cfg->enabled = 0; 00385 SSL_CTX_free(cfg->ssl_ctx); 00386 cfg->ssl_ctx = NULL; 00387 return 0; 00388 } 00389 } 00390 } 00391 if (!ast_strlen_zero(cfg->cafile) || !ast_strlen_zero(cfg->capath)) { 00392 if (SSL_CTX_load_verify_locations(cfg->ssl_ctx, S_OR(cfg->cafile, NULL), S_OR(cfg->capath,NULL)) == 0) 00393 ast_verb(0, "SSL CA file(%s)/path(%s) error\n", cfg->cafile, cfg->capath); 00394 } 00395 00396 ast_verb(0, "SSL certificate ok\n"); 00397 return 1; 00398 #endif 00399 }
int ast_ssl_setup | ( | struct ast_tls_config * | cfg | ) |
Set up an SSL server.
cfg | Configuration for the SSL server |
1 | Success | |
0 | Failure |
Definition at line 401 of file tcptls.c.
References __ssl_setup().
00402 { 00403 return __ssl_setup(cfg, 0); 00404 }
void ast_ssl_teardown | ( | struct ast_tls_config * | cfg | ) |
free resources used by an SSL server
cfg | Configuration for the SSL server |
Definition at line 406 of file tcptls.c.
References ast_tls_config::ssl_ctx.
Referenced by unload_module().
00407 { 00408 #ifdef DO_SSL 00409 if (cfg->ssl_ctx) { 00410 SSL_CTX_free(cfg->ssl_ctx); 00411 cfg->ssl_ctx = NULL; 00412 } 00413 #endif 00414 }
struct ast_tcptls_session_instance* ast_tcptls_client_create | ( | struct ast_tcptls_session_args * | desc | ) |
Definition at line 453 of file tcptls.c.
References ao2_alloc, ao2_ref, ast_bind(), ast_debug, ast_log(), ast_mutex_init, ast_sockaddr_cmp(), ast_sockaddr_copy(), ast_sockaddr_is_ipv6(), ast_sockaddr_isnull(), ast_sockaddr_setnull(), ast_sockaddr_stringify(), desc, errno, LOG_ERROR, LOG_WARNING, and session_instance_destructor().
Referenced by sip_prepare_socket().
00454 { 00455 int x = 1; 00456 struct ast_tcptls_session_instance *tcptls_session = NULL; 00457 00458 /* Do nothing if nothing has changed */ 00459 if (!ast_sockaddr_cmp(&desc->old_address, &desc->remote_address)) { 00460 ast_debug(1, "Nothing changed in %s\n", desc->name); 00461 return NULL; 00462 } 00463 00464 /* If we return early, there is no connection */ 00465 ast_sockaddr_setnull(&desc->old_address); 00466 00467 if (desc->accept_fd != -1) 00468 close(desc->accept_fd); 00469 00470 desc->accept_fd = socket(ast_sockaddr_is_ipv6(&desc->remote_address) ? 00471 AF_INET6 : AF_INET, SOCK_STREAM, IPPROTO_TCP); 00472 if (desc->accept_fd < 0) { 00473 ast_log(LOG_WARNING, "Unable to allocate socket for %s: %s\n", 00474 desc->name, strerror(errno)); 00475 return NULL; 00476 } 00477 00478 /* if a local address was specified, bind to it so the connection will 00479 originate from the desired address */ 00480 if (!ast_sockaddr_isnull(&desc->local_address)) { 00481 setsockopt(desc->accept_fd, SOL_SOCKET, SO_REUSEADDR, &x, sizeof(x)); 00482 if (ast_bind(desc->accept_fd, &desc->local_address)) { 00483 ast_log(LOG_ERROR, "Unable to bind %s to %s: %s\n", 00484 desc->name, 00485 ast_sockaddr_stringify(&desc->local_address), 00486 strerror(errno)); 00487 goto error; 00488 } 00489 } 00490 00491 if (!(tcptls_session = ao2_alloc(sizeof(*tcptls_session), session_instance_destructor))) 00492 goto error; 00493 00494 ast_mutex_init(&tcptls_session->lock); 00495 tcptls_session->client = 1; 00496 tcptls_session->fd = desc->accept_fd; 00497 tcptls_session->parent = desc; 00498 tcptls_session->parent->worker_fn = NULL; 00499 ast_sockaddr_copy(&tcptls_session->remote_address, 00500 &desc->remote_address); 00501 00502 /* Set current info */ 00503 ast_sockaddr_copy(&desc->old_address, &desc->remote_address); 00504 return tcptls_session; 00505 00506 error: 00507 close(desc->accept_fd); 00508 desc->accept_fd = -1; 00509 if (tcptls_session) 00510 ao2_ref(tcptls_session, -1); 00511 return NULL; 00512 }
struct ast_tcptls_session_instance* ast_tcptls_client_start | ( | struct ast_tcptls_session_instance * | tcptls_session | ) |
attempts to connect and start tcptls session, on error the tcptls_session's ref count is decremented, fd and file are closed, and NULL is returned.
Definition at line 416 of file tcptls.c.
References __ssl_setup(), ao2_ref, ast_connect(), ast_log(), ast_sockaddr_stringify(), desc, errno, handle_tcptls_connection(), LOG_ERROR, and ast_tcptls_session_instance::parent.
Referenced by _sip_tcp_helper_thread().
00417 { 00418 struct ast_tcptls_session_args *desc; 00419 int flags; 00420 00421 if (!(desc = tcptls_session->parent)) { 00422 goto client_start_error; 00423 } 00424 00425 if (ast_connect(desc->accept_fd, &desc->remote_address)) { 00426 ast_log(LOG_ERROR, "Unable to connect %s to %s: %s\n", 00427 desc->name, 00428 ast_sockaddr_stringify(&desc->remote_address), 00429 strerror(errno)); 00430 goto client_start_error; 00431 } 00432 00433 flags = fcntl(desc->accept_fd, F_GETFL); 00434 fcntl(desc->accept_fd, F_SETFL, flags & ~O_NONBLOCK); 00435 00436 if (desc->tls_cfg) { 00437 desc->tls_cfg->enabled = 1; 00438 __ssl_setup(desc->tls_cfg, 1); 00439 } 00440 00441 return handle_tcptls_connection(tcptls_session); 00442 00443 client_start_error: 00444 if (desc) { 00445 close(desc->accept_fd); 00446 desc->accept_fd = -1; 00447 } 00448 ao2_ref(tcptls_session, -1); 00449 return NULL; 00450 00451 }
void ast_tcptls_close_session_file | ( | struct ast_tcptls_session_instance * | tcptls_session | ) |
Closes a tcptls session instance's file and/or file descriptor. The tcptls_session will be set to NULL and it's file descriptor will be set to -1 by this function.
Definition at line 583 of file tcptls.c.
References ast_log(), errno, ast_tcptls_session_instance::f, ast_tcptls_session_instance::fd, and LOG_ERROR.
Referenced by ast_tcptls_server_root(), handle_tcptls_connection(), and sip_prepare_socket().
00584 { 00585 if (tcptls_session->f) { 00586 if (fclose(tcptls_session->f)) { 00587 ast_log(LOG_ERROR, "fclose() failed: %s\n", strerror(errno)); 00588 } 00589 tcptls_session->f = NULL; 00590 tcptls_session->fd = -1; 00591 } else if (tcptls_session->fd != -1) { 00592 if (close(tcptls_session->fd)) { 00593 ast_log(LOG_ERROR, "close() failed: %s\n", strerror(errno)); 00594 } 00595 tcptls_session->fd = -1; 00596 } else { 00597 ast_log(LOG_ERROR, "ast_tcptls_close_session_file invoked on session instance without file or file descriptor\n"); 00598 } 00599 }
HOOK_T ast_tcptls_server_read | ( | struct ast_tcptls_session_instance * | tcptls_session, | |
void * | buf, | |||
size_t | count | |||
) |
Definition at line 104 of file tcptls.c.
References ast_log(), errno, ast_tcptls_session_instance::fd, LOG_ERROR, ast_tcptls_session_instance::ssl, and ssl_read().
00105 { 00106 if (tcptls_session->fd == -1) { 00107 ast_log(LOG_ERROR, "server_read called with an fd of -1\n"); 00108 errno = EIO; 00109 return -1; 00110 } 00111 00112 #ifdef DO_SSL 00113 if (tcptls_session->ssl) 00114 return ssl_read(tcptls_session->ssl, buf, count); 00115 #endif 00116 return read(tcptls_session->fd, buf, count); 00117 }
void* ast_tcptls_server_root | ( | void * | data | ) |
Definition at line 256 of file tcptls.c.
References ao2_alloc, ao2_ref, ast_accept(), ast_log(), ast_mutex_init, ast_pthread_create_detached_background, ast_sockaddr_copy(), ast_tcptls_close_session_file(), ast_wait_for_input(), desc, errno, handle_tcptls_connection(), LOG_ERROR, LOG_WARNING, and session_instance_destructor().
00257 { 00258 struct ast_tcptls_session_args *desc = data; 00259 int fd; 00260 struct ast_sockaddr addr; 00261 struct ast_tcptls_session_instance *tcptls_session; 00262 pthread_t launched; 00263 00264 for (;;) { 00265 int i, flags; 00266 00267 if (desc->periodic_fn) 00268 desc->periodic_fn(desc); 00269 i = ast_wait_for_input(desc->accept_fd, desc->poll_timeout); 00270 if (i <= 0) 00271 continue; 00272 fd = ast_accept(desc->accept_fd, &addr); 00273 if (fd < 0) { 00274 if ((errno != EAGAIN) && (errno != EINTR)) 00275 ast_log(LOG_WARNING, "Accept failed: %s\n", strerror(errno)); 00276 continue; 00277 } 00278 tcptls_session = ao2_alloc(sizeof(*tcptls_session), session_instance_destructor); 00279 if (!tcptls_session) { 00280 ast_log(LOG_WARNING, "No memory for new session: %s\n", strerror(errno)); 00281 if (close(fd)) { 00282 ast_log(LOG_ERROR, "close() failed: %s\n", strerror(errno)); 00283 } 00284 continue; 00285 } 00286 00287 ast_mutex_init(&tcptls_session->lock); 00288 00289 flags = fcntl(fd, F_GETFL); 00290 fcntl(fd, F_SETFL, flags & ~O_NONBLOCK); 00291 tcptls_session->fd = fd; 00292 tcptls_session->parent = desc; 00293 ast_sockaddr_copy(&tcptls_session->remote_address, &addr); 00294 00295 tcptls_session->client = 0; 00296 00297 /* This thread is now the only place that controls the single ref to tcptls_session */ 00298 if (ast_pthread_create_detached_background(&launched, NULL, handle_tcptls_connection, tcptls_session)) { 00299 ast_log(LOG_WARNING, "Unable to launch helper thread: %s\n", strerror(errno)); 00300 ast_tcptls_close_session_file(tcptls_session); 00301 ao2_ref(tcptls_session, -1); 00302 } 00303 } 00304 return NULL; 00305 }
void ast_tcptls_server_start | ( | struct ast_tcptls_session_args * | desc | ) |
This is a generic (re)start routine for a TCP server, which does the socket/bind/listen and starts a thread for handling accept().
Definition at line 514 of file tcptls.c.
References ast_bind(), ast_debug, ast_log(), ast_pthread_create_background, AST_PTHREADT_NULL, ast_sockaddr_cmp(), ast_sockaddr_copy(), ast_sockaddr_is_ipv6(), ast_sockaddr_isnull(), ast_sockaddr_setnull(), ast_sockaddr_stringify(), desc, errno, and LOG_ERROR.
00515 { 00516 int flags; 00517 int x = 1; 00518 00519 /* Do nothing if nothing has changed */ 00520 if (!ast_sockaddr_cmp(&desc->old_address, &desc->local_address)) { 00521 ast_debug(1, "Nothing changed in %s\n", desc->name); 00522 return; 00523 } 00524 00525 /* If we return early, there is no one listening */ 00526 ast_sockaddr_setnull(&desc->old_address); 00527 00528 /* Shutdown a running server if there is one */ 00529 if (desc->master != AST_PTHREADT_NULL) { 00530 pthread_cancel(desc->master); 00531 pthread_kill(desc->master, SIGURG); 00532 pthread_join(desc->master, NULL); 00533 } 00534 00535 if (desc->accept_fd != -1) 00536 close(desc->accept_fd); 00537 00538 /* If there's no new server, stop here */ 00539 if (ast_sockaddr_isnull(&desc->local_address)) { 00540 ast_debug(2, "Server disabled: %s\n", desc->name); 00541 return; 00542 } 00543 00544 desc->accept_fd = socket(ast_sockaddr_is_ipv6(&desc->local_address) ? 00545 AF_INET6 : AF_INET, SOCK_STREAM, 0); 00546 if (desc->accept_fd < 0) { 00547 ast_log(LOG_ERROR, "Unable to allocate socket for %s: %s\n", desc->name, strerror(errno)); 00548 return; 00549 } 00550 00551 setsockopt(desc->accept_fd, SOL_SOCKET, SO_REUSEADDR, &x, sizeof(x)); 00552 if (ast_bind(desc->accept_fd, &desc->local_address)) { 00553 ast_log(LOG_ERROR, "Unable to bind %s to %s: %s\n", 00554 desc->name, 00555 ast_sockaddr_stringify(&desc->local_address), 00556 strerror(errno)); 00557 goto error; 00558 } 00559 if (listen(desc->accept_fd, 10)) { 00560 ast_log(LOG_ERROR, "Unable to listen for %s!\n", desc->name); 00561 goto error; 00562 } 00563 flags = fcntl(desc->accept_fd, F_GETFL); 00564 fcntl(desc->accept_fd, F_SETFL, flags | O_NONBLOCK); 00565 if (ast_pthread_create_background(&desc->master, NULL, desc->accept_fn, desc)) { 00566 ast_log(LOG_ERROR, "Unable to launch thread for %s on %s: %s\n", 00567 desc->name, 00568 ast_sockaddr_stringify(&desc->local_address), 00569 strerror(errno)); 00570 goto error; 00571 } 00572 00573 /* Set current info */ 00574 ast_sockaddr_copy(&desc->old_address, &desc->local_address); 00575 00576 return; 00577 00578 error: 00579 close(desc->accept_fd); 00580 desc->accept_fd = -1; 00581 }
void ast_tcptls_server_stop | ( | struct ast_tcptls_session_args * | desc | ) |
Shutdown a running server if there is one.
Definition at line 601 of file tcptls.c.
References ast_debug, AST_PTHREADT_NULL, and desc.
Referenced by unload_module().
00602 { 00603 if (desc->master != AST_PTHREADT_NULL) { 00604 pthread_cancel(desc->master); 00605 pthread_kill(desc->master, SIGURG); 00606 pthread_join(desc->master, NULL); 00607 desc->master = AST_PTHREADT_NULL; 00608 } 00609 if (desc->accept_fd != -1) 00610 close(desc->accept_fd); 00611 desc->accept_fd = -1; 00612 ast_debug(2, "Stopped server :: %s\n", desc->name); 00613 }
HOOK_T ast_tcptls_server_write | ( | struct ast_tcptls_session_instance * | tcptls_session, | |
const void * | buf, | |||
size_t | count | |||
) |
Definition at line 119 of file tcptls.c.
References ast_log(), errno, ast_tcptls_session_instance::fd, LOG_ERROR, ast_tcptls_session_instance::ssl, and ssl_write().
00120 { 00121 if (tcptls_session->fd == -1) { 00122 ast_log(LOG_ERROR, "server_write called with an fd of -1\n"); 00123 errno = EIO; 00124 return -1; 00125 } 00126 00127 #ifdef DO_SSL 00128 if (tcptls_session->ssl) 00129 return ssl_write(tcptls_session->ssl, buf, count); 00130 #endif 00131 return write(tcptls_session->fd, buf, count); 00132 }
int ast_tls_read_conf | ( | struct ast_tls_config * | tls_cfg, | |
struct ast_tcptls_session_args * | tls_desc, | |||
const char * | varname, | |||
const char * | value | |||
) |
Used to parse conf files containing tls/ssl options.
Definition at line 615 of file tcptls.c.
References ast_clear_flag, ast_free, ast_log(), ast_parse_arg(), ast_set2_flag, ast_set_flag, AST_SSL_DONT_VERIFY_SERVER, AST_SSL_SSLV2_CLIENT, AST_SSL_SSLV3_CLIENT, AST_SSL_TLSV1_CLIENT, AST_SSL_VERIFY_CLIENT, ast_strdup, ast_true(), ast_tls_config::cafile, ast_tls_config::capath, ast_tls_config::certfile, ast_tls_config::cipher, ast_tls_config::enabled, ast_tls_config::flags, ast_tcptls_session_args::local_address, LOG_WARNING, PARSE_ADDR, and ast_tls_config::pvtfile.
Referenced by __ast_http_load(), __init_manager(), and reload_config().
00616 { 00617 if (!strcasecmp(varname, "tlsenable") || !strcasecmp(varname, "sslenable")) { 00618 tls_cfg->enabled = ast_true(value) ? 1 : 0; 00619 } else if (!strcasecmp(varname, "tlscertfile") || !strcasecmp(varname, "sslcert") || !strcasecmp(varname, "tlscert")) { 00620 ast_free(tls_cfg->certfile); 00621 tls_cfg->certfile = ast_strdup(value); 00622 } else if (!strcasecmp(varname, "tlsprivatekey") || !strcasecmp(varname, "sslprivatekey")) { 00623 ast_free(tls_cfg->pvtfile); 00624 tls_cfg->pvtfile = ast_strdup(value); 00625 } else if (!strcasecmp(varname, "tlscipher") || !strcasecmp(varname, "sslcipher")) { 00626 ast_free(tls_cfg->cipher); 00627 tls_cfg->cipher = ast_strdup(value); 00628 } else if (!strcasecmp(varname, "tlscafile")) { 00629 ast_free(tls_cfg->cafile); 00630 tls_cfg->cafile = ast_strdup(value); 00631 } else if (!strcasecmp(varname, "tlscapath") || !strcasecmp(varname, "tlscadir")) { 00632 ast_free(tls_cfg->capath); 00633 tls_cfg->capath = ast_strdup(value); 00634 } else if (!strcasecmp(varname, "tlsverifyclient")) { 00635 ast_set2_flag(&tls_cfg->flags, ast_true(value), AST_SSL_VERIFY_CLIENT); 00636 } else if (!strcasecmp(varname, "tlsdontverifyserver")) { 00637 ast_set2_flag(&tls_cfg->flags, ast_true(value), AST_SSL_DONT_VERIFY_SERVER); 00638 } else if (!strcasecmp(varname, "tlsbindaddr") || !strcasecmp(varname, "sslbindaddr")) { 00639 if (ast_parse_arg(value, PARSE_ADDR, &tls_desc->local_address)) 00640 ast_log(LOG_WARNING, "Invalid %s '%s'\n", varname, value); 00641 } else if (!strcasecmp(varname, "tlsclientmethod") || !strcasecmp(varname, "sslclientmethod")) { 00642 if (!strcasecmp(value, "tlsv1")) { 00643 ast_set_flag(&tls_cfg->flags, AST_SSL_TLSV1_CLIENT); 00644 ast_clear_flag(&tls_cfg->flags, AST_SSL_SSLV3_CLIENT); 00645 ast_clear_flag(&tls_cfg->flags, AST_SSL_SSLV2_CLIENT); 00646 } else if (!strcasecmp(value, "sslv3")) { 00647 ast_set_flag(&tls_cfg->flags, AST_SSL_SSLV3_CLIENT); 00648 ast_clear_flag(&tls_cfg->flags, AST_SSL_SSLV2_CLIENT); 00649 ast_clear_flag(&tls_cfg->flags, AST_SSL_TLSV1_CLIENT); 00650 } else if (!strcasecmp(value, "sslv2")) { 00651 ast_set_flag(&tls_cfg->flags, AST_SSL_SSLV2_CLIENT); 00652 ast_clear_flag(&tls_cfg->flags, AST_SSL_TLSV1_CLIENT); 00653 ast_clear_flag(&tls_cfg->flags, AST_SSL_SSLV3_CLIENT); 00654 } 00655 } else { 00656 return -1; 00657 } 00658 00659 return 0; 00660 }
static void* handle_tcptls_connection | ( | void * | data | ) | [static] |
creates a FILE * from the fd passed by the accept thread. This operation is potentially expensive (certificate verification), so we do it in the child thread context.
Definition at line 147 of file tcptls.c.
References ao2_ref, ast_debug, ast_log(), AST_SSL_DONT_VERIFY_SERVER, AST_SSL_IGNORE_COMMON_NAME, AST_SSL_VERIFY_CLIENT, ast_tcptls_close_session_file(), ast_test_flag, ast_verb, ast_tcptls_session_instance::client, ast_tcptls_session_instance::f, ast_tcptls_session_instance::fd, ast_tls_config::flags, ast_tcptls_session_args::hostname, LOG_ERROR, LOG_WARNING, name, ast_tcptls_session_instance::parent, ast_tcptls_session_instance::ssl, ssl_close(), ast_tls_config::ssl_ctx, ssl_read(), ssl_write(), str, ast_tcptls_session_args::tls_cfg, and ast_tcptls_session_args::worker_fn.
Referenced by ast_tcptls_client_start(), and ast_tcptls_server_root().
00148 { 00149 struct ast_tcptls_session_instance *tcptls_session = data; 00150 #ifdef DO_SSL 00151 int (*ssl_setup)(SSL *) = (tcptls_session->client) ? SSL_connect : SSL_accept; 00152 int ret; 00153 char err[256]; 00154 #endif 00155 00156 /* 00157 * open a FILE * as appropriate. 00158 */ 00159 if (!tcptls_session->parent->tls_cfg) { 00160 if ((tcptls_session->f = fdopen(tcptls_session->fd, "w+"))) { 00161 if(setvbuf(tcptls_session->f, NULL, _IONBF, 0)) { 00162 ast_tcptls_close_session_file(tcptls_session); 00163 } 00164 } 00165 } 00166 #ifdef DO_SSL 00167 else if ( (tcptls_session->ssl = SSL_new(tcptls_session->parent->tls_cfg->ssl_ctx)) ) { 00168 SSL_set_fd(tcptls_session->ssl, tcptls_session->fd); 00169 if ((ret = ssl_setup(tcptls_session->ssl)) <= 0) { 00170 ast_verb(2, "Problem setting up ssl connection: %s\n", ERR_error_string(ERR_get_error(), err)); 00171 } else { 00172 #if defined(HAVE_FUNOPEN) /* the BSD interface */ 00173 tcptls_session->f = funopen(tcptls_session->ssl, ssl_read, ssl_write, NULL, ssl_close); 00174 00175 #elif defined(HAVE_FOPENCOOKIE) /* the glibc/linux interface */ 00176 static const cookie_io_functions_t cookie_funcs = { 00177 ssl_read, ssl_write, NULL, ssl_close 00178 }; 00179 tcptls_session->f = fopencookie(tcptls_session->ssl, "w+", cookie_funcs); 00180 #else 00181 /* could add other methods here */ 00182 ast_debug(2, "no tcptls_session->f methods attempted!\n"); 00183 #endif 00184 if ((tcptls_session->client && !ast_test_flag(&tcptls_session->parent->tls_cfg->flags, AST_SSL_DONT_VERIFY_SERVER)) 00185 || (!tcptls_session->client && ast_test_flag(&tcptls_session->parent->tls_cfg->flags, AST_SSL_VERIFY_CLIENT))) { 00186 X509 *peer; 00187 long res; 00188 peer = SSL_get_peer_certificate(tcptls_session->ssl); 00189 if (!peer) 00190 ast_log(LOG_WARNING, "No peer SSL certificate\n"); 00191 res = SSL_get_verify_result(tcptls_session->ssl); 00192 if (res != X509_V_OK) 00193 ast_log(LOG_ERROR, "Certificate did not verify: %s\n", X509_verify_cert_error_string(res)); 00194 if (!ast_test_flag(&tcptls_session->parent->tls_cfg->flags, AST_SSL_IGNORE_COMMON_NAME)) { 00195 ASN1_STRING *str; 00196 unsigned char *str2; 00197 X509_NAME *name = X509_get_subject_name(peer); 00198 int pos = -1; 00199 int found = 0; 00200 00201 for (;;) { 00202 /* Walk the certificate to check all available "Common Name" */ 00203 /* XXX Probably should do a gethostbyname on the hostname and compare that as well */ 00204 pos = X509_NAME_get_index_by_NID(name, NID_commonName, pos); 00205 if (pos < 0) 00206 break; 00207 str = X509_NAME_ENTRY_get_data(X509_NAME_get_entry(name, pos)); 00208 ASN1_STRING_to_UTF8(&str2, str); 00209 if (str2) { 00210 if (!strcasecmp(tcptls_session->parent->hostname, (char *) str2)) 00211 found = 1; 00212 ast_debug(3, "SSL Common Name compare s1='%s' s2='%s'\n", tcptls_session->parent->hostname, str2); 00213 OPENSSL_free(str2); 00214 } 00215 if (found) 00216 break; 00217 } 00218 if (!found) { 00219 ast_log(LOG_ERROR, "Certificate common name did not match (%s)\n", tcptls_session->parent->hostname); 00220 if (peer) { 00221 X509_free(peer); 00222 } 00223 ast_tcptls_close_session_file(tcptls_session); 00224 ao2_ref(tcptls_session, -1); 00225 return NULL; 00226 } 00227 } 00228 if (peer) 00229 X509_free(peer); 00230 } 00231 } 00232 if (!tcptls_session->f) /* no success opening descriptor stacking */ 00233 SSL_free(tcptls_session->ssl); 00234 } 00235 #endif /* DO_SSL */ 00236 00237 if (!tcptls_session->f) { 00238 ast_tcptls_close_session_file(tcptls_session); 00239 ast_log(LOG_WARNING, "FILE * open failed!\n"); 00240 #ifndef DO_SSL 00241 if (tcptls_session->parent->tls_cfg) { 00242 ast_log(LOG_WARNING, "Attempted a TLS connection without OpenSSL support. This will not work!\n"); 00243 } 00244 #endif 00245 ao2_ref(tcptls_session, -1); 00246 return NULL; 00247 } 00248 00249 if (tcptls_session->parent->worker_fn) { 00250 return tcptls_session->parent->worker_fn(tcptls_session); 00251 } else { 00252 return tcptls_session; 00253 } 00254 }
static void session_instance_destructor | ( | void * | obj | ) | [static] |
Definition at line 134 of file tcptls.c.
References ast_mutex_destroy, and ast_tcptls_session_instance::lock.
Referenced by ast_tcptls_client_create(), and ast_tcptls_server_root().
00135 { 00136 struct ast_tcptls_session_instance *i = obj; 00137 ast_mutex_destroy(&i->lock); 00138 }
static int ssl_close | ( | void * | cookie | ) | [static] |
Definition at line 81 of file tcptls.c.
References ast_log(), errno, and LOG_ERROR.
Referenced by handle_tcptls_connection().
00082 { 00083 int cookie_fd = SSL_get_fd(cookie); 00084 int ret; 00085 if (cookie_fd > -1) { 00086 /* 00087 * According to the TLS standard, it is acceptable for an application to only send its shutdown 00088 * alert and then close the underlying connection without waiting for the peer's response (this 00089 * way resources can be saved, as the process can already terminate or serve another connection). 00090 */ 00091 if ((ret = SSL_shutdown(cookie)) < 0) { 00092 ast_log(LOG_ERROR, "SSL_shutdown() failed: %d\n", SSL_get_error(cookie, ret)); 00093 } 00094 SSL_free(cookie); 00095 /* adding shutdown(2) here has no added benefit */ 00096 if (close(cookie_fd)) { 00097 ast_log(LOG_ERROR, "close() failed: %s\n", strerror(errno)); 00098 } 00099 } 00100 return 0; 00101 }
static HOOK_T ssl_read | ( | void * | cookie, | |
char * | buf, | |||
LEN_T | len | |||
) | [static] |
replacement read/write functions for SSL support. We use wrappers rather than SSL_read/SSL_write directly so we can put in some debugging.
Definition at line 59 of file tcptls.c.
References ast_verb.
Referenced by ast_tcptls_server_read(), and handle_tcptls_connection().
00060 { 00061 int i = SSL_read(cookie, buf, len-1); 00062 #if 0 00063 if (i >= 0) 00064 buf[i] = '\0'; 00065 ast_verb(0, "ssl read size %d returns %d <%s>\n", (int)len, i, buf); 00066 #endif 00067 return i; 00068 }
static HOOK_T ssl_write | ( | void * | cookie, | |
const char * | buf, | |||
LEN_T | len | |||
) | [static] |
Definition at line 70 of file tcptls.c.
References ast_verb.
Referenced by ast_tcptls_server_write(), and handle_tcptls_connection().
00071 { 00072 #if 0 00073 char *s = alloca(len+1); 00074 strncpy(s, buf, len); 00075 s[len] = '\0'; 00076 ast_verb(0, "ssl write size %d <%s>\n", (int)len, s); 00077 #endif 00078 return SSL_write(cookie, buf, len); 00079 }