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