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