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