Asterisk - The Open Source Telephony Project GIT-master-6144b6b
Loading...
Searching...
No Matches
Functions
tcptls.c File Reference

Code to support TCP and TLS server/client. More...

#include "asterisk.h"
#include "asterisk/tcptls.h"
#include "asterisk/iostream.h"
#include <fcntl.h>
#include <netinet/in.h>
#include <pthread.h>
#include <signal.h>
#include <sys/socket.h>
#include <sys/stat.h>
#include "asterisk/app.h"
#include "asterisk/astobj2.h"
#include "asterisk/compat.h"
#include "asterisk/config.h"
#include "asterisk/io.h"
#include "asterisk/lock.h"
#include "asterisk/logger.h"
#include "asterisk/netsock2.h"
#include "asterisk/pbx.h"
#include "asterisk/utils.h"
Include dependency graph for tcptls.c:

Go to the source code of this file.

Functions

static int __ssl_setup (struct ast_tls_config *cfg, int client, int suppress_progress_msgs)
 
int ast_ssl_setup (struct ast_tls_config *cfg)
 Set up an SSL server.
 
int ast_ssl_setup_client (struct ast_tls_config *cfg)
 Set up an SSL client.
 
void ast_ssl_teardown (struct ast_tls_config *cfg)
 free resources used by an SSL server
 
struct ast_tcptls_session_instanceast_tcptls_client_create (struct ast_tcptls_session_args *desc)
 Creates a client connection's ast_tcptls_session_instance.
 
struct ast_tcptls_session_instanceast_tcptls_client_start (struct ast_tcptls_session_instance *tcptls_session)
 Attempt to connect and start a tcptls session.
 
struct ast_tcptls_session_instanceast_tcptls_client_start_timeout (struct ast_tcptls_session_instance *tcptls_session, int timeout)
 Attempt to connect and start a tcptls session within the given timeout.
 
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.
 
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.
 
struct ast_tcptls_session_instanceast_tcptls_start_tls (struct ast_tcptls_session_instance *tcptls_session)
 Start TLS negotiation on an existing unsecured connection.
 
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 socket_connect (int sockfd, const struct ast_sockaddr *addr, int timeout)
 

Detailed Description

Code to support TCP and TLS server/client.

Author
Luigi Rizzo
Brett Bryant brett.nosp@m.brya.nosp@m.nt@gm.nosp@m.ail..nosp@m.com

Definition in file tcptls.c.

Function Documentation

◆ __ssl_setup()

static int __ssl_setup ( struct ast_tls_config cfg,
int  client,
int  suppress_progress_msgs 
)
static

Definition at line 392 of file tcptls.c.

394{
395#ifndef DO_SSL
396 if (cfg->enabled) {
397 ast_log(LOG_ERROR, "TLS server failed: Asterisk is compiled without OpenSSL support. Install OpenSSL development headers and rebuild Asterisk after running ./configure\n");
398 cfg->enabled = 0;
399 }
400 return 0;
401#else
402 int disable_ssl = 0;
403 long ssl_opts = 0;
404
405 if (!cfg->enabled) {
406 return 0;
407 }
408
409 /* Get rid of an old SSL_CTX since we're about to
410 * allocate a new one
411 */
412 if (cfg->ssl_ctx) {
413 SSL_CTX_free(cfg->ssl_ctx);
414 cfg->ssl_ctx = NULL;
415 }
416
417 if (client) {
418#if !defined(OPENSSL_NO_SSL2) && (OPENSSL_VERSION_NUMBER < 0x10100000L)
420 ast_log(LOG_WARNING, "Usage of SSLv2 is discouraged due to known vulnerabilities. Please use 'tlsv1' or leave the TLS method unspecified!\n");
421 cfg->ssl_ctx = SSL_CTX_new(SSLv2_client_method());
422 } else
423#endif
424#if !defined(OPENSSL_NO_SSL3_METHOD) && !(defined(OPENSSL_API_COMPAT) && (OPENSSL_API_COMPAT >= 0x10100000L)) && (OPENSSL_VERSION_NUMBER < 0x40000000L)
426 ast_log(LOG_WARNING, "Usage of SSLv3 is discouraged due to known vulnerabilities. Please use 'tlsv1' or leave the TLS method unspecified!\n");
427 cfg->ssl_ctx = SSL_CTX_new(SSLv3_client_method());
428 } else
429#endif
430#if OPENSSL_VERSION_NUMBER >= 0x10100000L
431 cfg->ssl_ctx = SSL_CTX_new(TLS_client_method());
432#else
434 cfg->ssl_ctx = SSL_CTX_new(TLSv1_client_method());
435 } else {
436 disable_ssl = 1;
437 cfg->ssl_ctx = SSL_CTX_new(SSLv23_client_method());
438 }
439#endif
440 } else {
441 disable_ssl = 1;
442 cfg->ssl_ctx = SSL_CTX_new(SSLv23_server_method());
443 }
444
445 if (!cfg->ssl_ctx) {
446 ast_debug(1, "Sorry, SSL_CTX_new call returned null...\n");
447 cfg->enabled = 0;
448 return 0;
449 }
450
451 /* Due to the POODLE vulnerability, completely disable
452 * SSLv2 and SSLv3 if we are not explicitly told to use
453 * them. SSLv23_*_method supports TLSv1+.
454 */
455 if (disable_ssl) {
456 ssl_opts |= SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3;
457 }
458
460 ssl_opts |= SSL_OP_CIPHER_SERVER_PREFERENCE;
461 }
462
464 ssl_opts |= SSL_OP_NO_TLSv1;
465 }
466#if defined(SSL_OP_NO_TLSv1_1) && defined(SSL_OP_NO_TLSv1_2)
468 ssl_opts |= SSL_OP_NO_TLSv1_1;
469 }
471 ssl_opts |= SSL_OP_NO_TLSv1_2;
472 }
473#else
474 ast_log(LOG_WARNING, "Your version of OpenSSL leaves you potentially vulnerable "
475 "to the SSL BEAST attack. Please upgrade to OpenSSL 1.0.1 or later\n");
476#endif
477
478 SSL_CTX_set_options(cfg->ssl_ctx, ssl_opts);
479
480 SSL_CTX_set_verify(cfg->ssl_ctx,
481 ast_test_flag(&cfg->flags, AST_SSL_VERIFY_CLIENT) ? SSL_VERIFY_PEER | SSL_VERIFY_FAIL_IF_NO_PEER_CERT : SSL_VERIFY_NONE,
482 NULL);
483
484 if (!ast_strlen_zero(cfg->certfile)) {
485 char *tmpprivate = ast_strlen_zero(cfg->pvtfile) ? cfg->certfile : cfg->pvtfile;
486 if (SSL_CTX_use_certificate_chain_file(cfg->ssl_ctx, cfg->certfile) == 0) {
487 if (!client) {
488 /* Clients don't need a certificate, but if its setup we can use it */
489 ast_log(LOG_ERROR, "TLS/SSL error loading cert file. <%s>\n", cfg->certfile);
490 write_openssl_error_to_log();
491 cfg->enabled = 0;
492 SSL_CTX_free(cfg->ssl_ctx);
493 cfg->ssl_ctx = NULL;
494 return 0;
495 }
496 }
497 if ((SSL_CTX_use_PrivateKey_file(cfg->ssl_ctx, tmpprivate, SSL_FILETYPE_PEM) == 0) || (SSL_CTX_check_private_key(cfg->ssl_ctx) == 0 )) {
498 if (!client) {
499 /* Clients don't need a private key, but if its setup we can use it */
500 ast_log(LOG_ERROR, "TLS/SSL error loading private key file. <%s>\n", tmpprivate);
501 write_openssl_error_to_log();
502 cfg->enabled = 0;
503 SSL_CTX_free(cfg->ssl_ctx);
504 cfg->ssl_ctx = NULL;
505 return 0;
506 }
507 }
508 if (!client) {
509 size_t certfile_len = strlen(cfg->certfile);
510
511 /* expects a file name which contains _rsa. like asterisk_rsa.pem
512 * ignores any 3-character file-extension like .pem, .cer, .crt
513 */
514 if (certfile_len >= 8 && !strncmp(cfg->certfile + certfile_len - 8, "_rsa.", 5)) {
515 __ssl_setup_certs(cfg, certfile_len, "_ecc.", "ECC");
516 __ssl_setup_certs(cfg, certfile_len, "_dsa.", "DSA");
517 }
518 }
519 }
520 if (!ast_strlen_zero(cfg->cipher)) {
521 if (SSL_CTX_set_cipher_list(cfg->ssl_ctx, cfg->cipher) == 0 ) {
522 if (!client) {
523 ast_log(LOG_ERROR, "TLS/SSL cipher error <%s>\n", cfg->cipher);
524 write_openssl_error_to_log();
525 cfg->enabled = 0;
526 SSL_CTX_free(cfg->ssl_ctx);
527 cfg->ssl_ctx = NULL;
528 return 0;
529 }
530 }
531 }
532 if (!ast_strlen_zero(cfg->cafile) || !ast_strlen_zero(cfg->capath)) {
533 if (SSL_CTX_load_verify_locations(cfg->ssl_ctx, S_OR(cfg->cafile, NULL), S_OR(cfg->capath,NULL)) == 0) {
534 ast_log(LOG_ERROR, "TLS/SSL CA file(%s)/path(%s) error\n", cfg->cafile, cfg->capath);
535 write_openssl_error_to_log();
536 }
537 }
538
539#ifndef OPENSSL_NO_DH
540 if (!ast_strlen_zero(cfg->pvtfile)) {
541 BIO *bio = BIO_new_file(cfg->pvtfile, "r");
542 if (bio != NULL) {
543 DH *dh = PEM_read_bio_DHparams(bio, NULL, NULL, NULL);
544 if (dh != NULL) {
545 if (SSL_CTX_set_tmp_dh(cfg->ssl_ctx, dh)) {
546 long options = SSL_OP_CIPHER_SERVER_PREFERENCE | SSL_OP_SINGLE_DH_USE | SSL_OP_SINGLE_ECDH_USE;
547 options = SSL_CTX_set_options(cfg->ssl_ctx, options);
548 if (!suppress_progress_msgs) {
549 ast_verb(2, "TLS/SSL DH initialized, PFS cipher-suites enabled\n");
550 }
551 }
552 DH_free(dh);
553 }
554 BIO_free(bio);
555 }
556 }
557#endif
558
559 #ifndef SSL_CTRL_SET_ECDH_AUTO
560 #define SSL_CTRL_SET_ECDH_AUTO 94
561 #endif
562 /* SSL_CTX_set_ecdh_auto(cfg->ssl_ctx, on); requires OpenSSL 1.0.2 which wraps: */
563 if (SSL_CTX_ctrl(cfg->ssl_ctx, SSL_CTRL_SET_ECDH_AUTO, 1, NULL)) {
564 if (!suppress_progress_msgs) {
565 ast_verb(2, "TLS/SSL ECDH initialized (automatic), faster PFS ciphers enabled\n");
566 }
567#if !defined(OPENSSL_NO_ECDH) && (OPENSSL_VERSION_NUMBER >= 0x10000000L) && (OPENSSL_VERSION_NUMBER < 0x10100000L)
568 } else {
569 /* enables AES-128 ciphers, to get AES-256 use NID_secp384r1 */
570 EC_KEY *ecdh = EC_KEY_new_by_curve_name(NID_X9_62_prime256v1);
571 if (ecdh != NULL) {
572 if (SSL_CTX_set_tmp_ecdh(cfg->ssl_ctx, ecdh)) {
573 ast_verb(2, "TLS/SSL ECDH initialized (secp256r1), faster PFS cipher-suites enabled\n");
574 }
575 EC_KEY_free(ecdh);
576 }
577#endif
578 }
579
580 if (!suppress_progress_msgs) {
581 ast_verb(2, "TLS/SSL certificate ok\n"); /* We should log which one that is ok. This message doesn't really make sense in production use */
582 }
583 return 1;
584#endif
585}
#define ast_log
Definition astobj2.c:42
#define ast_debug(level,...)
Log a DEBUG message.
#define LOG_ERROR
#define ast_verb(level,...)
#define LOG_WARNING
#define NULL
Definition resample.c:96
#define S_OR(a, b)
returns the equivalent of logic or for strings: first one if not empty, otherwise second one.
Definition strings.h:80
static force_inline int attribute_pure ast_strlen_zero(const char *s)
Definition strings.h:65
char * certfile
Definition tcptls.h:90
char * cipher
Definition tcptls.h:92
SSL_CTX * ssl_ctx
Definition tcptls.h:96
char * pvtfile
Definition tcptls.h:91
char * capath
Definition tcptls.h:94
char * cafile
Definition tcptls.h:93
struct ast_flags flags
Definition tcptls.h:95
@ AST_SSL_VERIFY_CLIENT
Definition tcptls.h:67
@ AST_SSL_SSLV3_CLIENT
Definition tcptls.h:75
@ AST_SSL_DISABLE_TLSV11
Definition tcptls.h:83
@ AST_SSL_TLSV1_CLIENT
Definition tcptls.h:77
@ AST_SSL_DISABLE_TLSV12
Definition tcptls.h:85
@ AST_SSL_SERVER_CIPHER_ORDER
Definition tcptls.h:79
@ AST_SSL_DISABLE_TLSV1
Definition tcptls.h:81
@ AST_SSL_SSLV2_CLIENT
Definition tcptls.h:73
static struct test_options options
#define ast_test_flag(p, flag)
Definition utils.h:64

References ast_debug, ast_log, AST_SSL_DISABLE_TLSV1, AST_SSL_DISABLE_TLSV11, AST_SSL_DISABLE_TLSV12, AST_SSL_SERVER_CIPHER_ORDER, AST_SSL_SSLV2_CLIENT, AST_SSL_SSLV3_CLIENT, AST_SSL_TLSV1_CLIENT, AST_SSL_VERIFY_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_tcptls_session_instance::client, ast_tls_config::enabled, ast_tls_config::flags, LOG_ERROR, LOG_WARNING, NULL, options, ast_tls_config::pvtfile, S_OR, and ast_tls_config::ssl_ctx.

Referenced by ast_ssl_setup(), ast_ssl_setup_client(), and ast_tcptls_client_start_timeout().

◆ ast_ssl_setup()

int ast_ssl_setup ( struct ast_tls_config cfg)

Set up an SSL server.

Parameters
cfgConfiguration for the SSL server
Return values
1Success
0Failure

Definition at line 587 of file tcptls.c.

588{
589 return __ssl_setup(cfg, 0, 0);
590}
static int __ssl_setup(struct ast_tls_config *cfg, int client, int suppress_progress_msgs)
Definition tcptls.c:392

References __ssl_setup().

Referenced by __ast_http_load(), and __init_manager().

◆ ast_ssl_setup_client()

int ast_ssl_setup_client ( struct ast_tls_config cfg)

Set up an SSL client.

Since
20.21.0
22.11.0
23.5.0
Note
This function only needs to be called if an unsecured tcptls session is already established and you need to switch it to TLS. This function doesn't actually start any negotiation. It just reads any certificates, key files and options from the config and creates the SSL context.
Parameters
cfgConfiguration for the SSL client
Return values
1Success
0Failure

Definition at line 592 of file tcptls.c.

593{
594 return __ssl_setup(cfg, 1, 1);
595}

References __ssl_setup().

Referenced by websocket_client_connect().

◆ ast_ssl_teardown()

void ast_ssl_teardown ( struct ast_tls_config cfg)

free resources used by an SSL server

Note
This only needs to be called if ast_ssl_setup() was directly called first.
Parameters
cfgConfiguration for the SSL server

Definition at line 597 of file tcptls.c.

598{
599#ifdef DO_SSL
600 if (cfg && cfg->ssl_ctx) {
601 SSL_CTX_free(cfg->ssl_ctx);
602 cfg->ssl_ctx = NULL;
603 }
604#endif
605}

References NULL, and ast_tls_config::ssl_ctx.

Referenced by websocket_client_args_destroy().

◆ ast_tcptls_client_create()

struct ast_tcptls_session_instance * ast_tcptls_client_create ( struct ast_tcptls_session_args desc)

Creates a client connection's ast_tcptls_session_instance.

Definition at line 701 of file tcptls.c.

702{
703 int fd, x = 1;
704 struct ast_tcptls_session_instance *tcptls_session = NULL;
705
706 ast_assert(!desc->tls_cfg
707 || ast_test_flag(&desc->tls_cfg->flags, AST_SSL_DONT_VERIFY_SERVER)
708 || !ast_strlen_zero(desc->hostname));
709
710 /* Do nothing if nothing has changed */
711 if (!ast_sockaddr_cmp(&desc->old_address, &desc->remote_address)) {
712 ast_debug(1, "Nothing changed in %s\n", desc->name);
713 return NULL;
714 }
715
716 /* If we return early, there is no connection */
717 ast_sockaddr_setnull(&desc->old_address);
718
719 fd = desc->accept_fd = ast_socket_nonblock(ast_sockaddr_is_ipv6(&desc->remote_address) ?
720 AF_INET6 : AF_INET, SOCK_STREAM, IPPROTO_TCP);
721 if (desc->accept_fd < 0) {
722 ast_log(LOG_ERROR, "Unable to allocate socket for %s: %s\n",
723 desc->name, strerror(errno));
724 return NULL;
725 }
726
727 /* if a local address was specified, bind to it so the connection will
728 originate from the desired address */
729 if (!ast_sockaddr_isnull(&desc->local_address) &&
730 !ast_sockaddr_is_any(&desc->local_address)) {
731 setsockopt(desc->accept_fd, SOL_SOCKET, SO_REUSEADDR, &x, sizeof(x));
732 if (ast_bind(desc->accept_fd, &desc->local_address)) {
733 ast_log(LOG_ERROR, "Unable to bind %s to %s: %s\n",
734 desc->name,
735 ast_sockaddr_stringify(&desc->local_address),
736 strerror(errno));
737 goto error;
738 }
739 }
740
741 tcptls_session = ao2_alloc(sizeof(*tcptls_session), session_instance_destructor);
742 if (!tcptls_session) {
743 goto error;
744 }
745
746 tcptls_session->overflow_buf = ast_str_create(128);
747 if (!tcptls_session->overflow_buf) {
748 goto error;
749 }
750 tcptls_session->client = 1;
751 tcptls_session->stream = ast_iostream_from_fd(&fd);
752 if (!tcptls_session->stream) {
753 goto error;
754 }
755
756 /* From here on out, the iostream owns the accept_fd and it will take
757 * care of closing it when the iostream is closed */
758
759 tcptls_session->parent = desc;
760 tcptls_session->parent->worker_fn = NULL;
761 ast_sockaddr_copy(&tcptls_session->remote_address,
762 &desc->remote_address);
763
764 /* Set current info */
765 ast_sockaddr_copy(&desc->old_address, &desc->remote_address);
766
767 if (!ast_strlen_zero(desc->hostname)) {
768 if (ast_iostream_set_sni_hostname(tcptls_session->stream, desc->hostname) != 0) {
769 ast_log(LOG_WARNING, "Unable to set SNI hostname '%s' on connection '%s'\n",
770 desc->hostname, desc->name);
771 }
772 }
773
774 return tcptls_session;
775
776error:
777 close(desc->accept_fd);
778 desc->accept_fd = -1;
779 ao2_cleanup(tcptls_session);
780 return NULL;
781}
#define ao2_cleanup(obj)
Definition astobj2.h:1934
#define ao2_alloc(data_size, destructor_fn)
Definition astobj2.h:409
static const char desc[]
Definition cdr_radius.c:84
struct ast_iostream * ast_iostream_from_fd(int *fd)
Create an iostream from a file descriptor.
Definition iostream.c:616
int ast_iostream_set_sni_hostname(struct ast_iostream *stream, const char *sni_hostname)
Set the iostream's SNI hostname for TLS client connections.
Definition iostream.c:161
int errno
static char * ast_sockaddr_stringify(const struct ast_sockaddr *addr)
Wrapper around ast_sockaddr_stringify_fmt() with default format.
Definition netsock2.h:256
static void ast_sockaddr_copy(struct ast_sockaddr *dst, const struct ast_sockaddr *src)
Copies the data from one ast_sockaddr to another.
Definition netsock2.h:167
int ast_sockaddr_is_ipv6(const struct ast_sockaddr *addr)
Determine if this is an IPv6 address.
Definition netsock2.c:524
int ast_bind(int sockfd, const struct ast_sockaddr *addr)
Wrapper around bind(2) that uses struct ast_sockaddr.
Definition netsock2.c:590
int ast_sockaddr_is_any(const struct ast_sockaddr *addr)
Determine if the address type is unspecified, or "any" address.
Definition netsock2.c:534
static int ast_sockaddr_isnull(const struct ast_sockaddr *addr)
Checks if the ast_sockaddr is null. "null" in this sense essentially means uninitialized,...
Definition netsock2.h:127
int ast_sockaddr_cmp(const struct ast_sockaddr *a, const struct ast_sockaddr *b)
Compares two ast_sockaddr structures.
Definition netsock2.c:388
static void ast_sockaddr_setnull(struct ast_sockaddr *addr)
Sets address addr to null.
Definition netsock2.h:138
#define ast_str_create(init_len)
Create a malloc'ed dynamic length string.
Definition strings.h:659
void *(* worker_fn)(void *)
Definition tcptls.h:142
describes a server instance
Definition tcptls.h:151
struct ast_iostream * stream
Definition tcptls.h:162
struct ast_sockaddr remote_address
Definition tcptls.h:153
struct ast_tcptls_session_args * parent
Definition tcptls.h:154
struct ast_str * overflow_buf
Definition tcptls.h:160
static void session_instance_destructor(void *obj)
Definition tcptls.c:72
@ AST_SSL_DONT_VERIFY_SERVER
Definition tcptls.h:69
int error(const char *format,...)
#define ast_assert(a)
Definition utils.h:779
#define ast_socket_nonblock(domain, type, protocol)
Create a non-blocking socket.
Definition utils.h:1113

References ao2_alloc, ao2_cleanup, ast_assert, ast_bind(), ast_debug, ast_iostream_from_fd(), ast_iostream_set_sni_hostname(), ast_log, ast_sockaddr_cmp(), ast_sockaddr_copy(), ast_sockaddr_is_any(), ast_sockaddr_is_ipv6(), ast_sockaddr_isnull(), ast_sockaddr_setnull(), ast_sockaddr_stringify(), ast_socket_nonblock, AST_SSL_DONT_VERIFY_SERVER, ast_str_create, ast_strlen_zero(), ast_test_flag, ast_tcptls_session_instance::client, desc, errno, error(), LOG_ERROR, LOG_WARNING, NULL, ast_tcptls_session_instance::overflow_buf, ast_tcptls_session_instance::parent, ast_tcptls_session_instance::remote_address, session_instance_destructor(), ast_tcptls_session_instance::stream, and ast_tcptls_session_args::worker_fn.

Referenced by app_exec(), and websocket_client_connect().

◆ ast_tcptls_client_start()

struct ast_tcptls_session_instance * ast_tcptls_client_start ( struct ast_tcptls_session_instance tcptls_session)

Attempt to connect and start a tcptls session.

Blocks until a connection is established, or an error occurs.

Note
On error the tcptls_session's ref count is decremented, fd and file are closed, and NULL is returned.
Parameters
tcptls_sessionThe session instance to connect and start
Returns
The tcptls_session, or NULL on error

Definition at line 696 of file tcptls.c.

697{
698 return ast_tcptls_client_start_timeout(tcptls_session, -1);
699}
struct ast_tcptls_session_instance * ast_tcptls_client_start_timeout(struct ast_tcptls_session_instance *tcptls_session, int timeout)
Attempt to connect and start a tcptls session within the given timeout.
Definition tcptls.c:667

References ast_tcptls_client_start_timeout().

Referenced by app_exec().

◆ ast_tcptls_client_start_timeout()

struct ast_tcptls_session_instance * ast_tcptls_client_start_timeout ( struct ast_tcptls_session_instance tcptls_session,
int  timeout 
)

Attempt to connect and start a tcptls session within the given timeout.

Note
On error the tcptls_session's ref count is decremented, fd and file are closed, and NULL is returned.
Parameters
tcptls_sessionThe session instance to connect and start
timeoutHow long (in milliseconds) to attempt to connect (-1 equals infinite)
Returns
The tcptls_session, or NULL on error

Definition at line 667 of file tcptls.c.

669{
671
672 if (!(desc = tcptls_session->parent)) {
673 ao2_ref(tcptls_session, -1);
674 return NULL;
675 }
676
677 if (socket_connect(desc->accept_fd, &desc->remote_address, timeout)) {
678 if (!desc->suppress_connection_msgs) {
679 ast_log(LOG_WARNING, "Unable to connect %s to %s: %s\n", desc->name,
680 ast_sockaddr_stringify(&desc->remote_address), strerror(errno));
681 }
682
683 ao2_ref(tcptls_session, -1);
684 return NULL;
685 }
686
687 ast_fd_clear_flags(desc->accept_fd, O_NONBLOCK);
688
689 if (desc->tls_cfg) {
690 __ssl_setup(desc->tls_cfg, 1, desc->suppress_connection_msgs);
691 }
692
693 return handle_tcptls_connection(tcptls_session);
694}
#define ao2_ref(o, delta)
Reference/unreference an object and return the old refcount.
Definition astobj2.h:459
arguments for the accepting thread
Definition tcptls.h:130
static int socket_connect(int sockfd, const struct ast_sockaddr *addr, int timeout)
Definition tcptls.c:623
static void * handle_tcptls_connection(void *data)
creates a FILE * from the fd passed by the accept thread. This operation is potentially expensive (ce...
Definition tcptls.c:248
#define ast_fd_clear_flags(fd, flags)
Clear flags on the given file descriptor.
Definition utils.h:1095

References __ssl_setup(), ao2_ref, ast_fd_clear_flags, ast_log, ast_sockaddr_stringify(), desc, errno, handle_tcptls_connection(), LOG_WARNING, NULL, ast_tcptls_session_instance::parent, and socket_connect().

Referenced by ast_tcptls_client_start(), and websocket_client_connect().

◆ ast_tcptls_close_session_file()

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 938 of file tcptls.c.

939{
940 if (tcptls_session->stream) {
941 ast_iostream_close(tcptls_session->stream);
942 tcptls_session->stream = NULL;
943 } else {
944 ast_debug(1, "ast_tcptls_close_session_file invoked on session instance without file or file descriptor\n");
945 }
946}
int ast_iostream_close(struct ast_iostream *stream)
Close an iostream.
Definition iostream.c:544

References ast_debug, ast_iostream_close(), NULL, and ast_tcptls_session_instance::stream.

Referenced by ast_http_create_response(), ast_http_send(), ast_tcptls_start_tls(), handle_tcptls_connection(), and httpd_helper_thread().

◆ ast_tcptls_server_root()

void * ast_tcptls_server_root ( void *  data)

Definition at line 290 of file tcptls.c.

291{
292 struct ast_tcptls_session_args *desc = data;
293 int fd;
294 struct ast_sockaddr addr;
295 struct ast_tcptls_session_instance *tcptls_session;
296 pthread_t launched;
297
298 for (;;) {
299 int i;
300
301 if (desc->periodic_fn) {
302 desc->periodic_fn(desc);
303 }
304 i = ast_wait_for_input(desc->accept_fd, desc->poll_timeout);
305 if (i <= 0) {
306 /* Prevent tight loop from hogging CPU */
307 usleep(1);
308 continue;
309 }
310 fd = ast_accept(desc->accept_fd, &addr);
311 if (fd < 0) {
312 if (errno != EAGAIN
313 && errno != EWOULDBLOCK
314 && errno != EINTR
315 && errno != ECONNABORTED) {
316 ast_log(LOG_ERROR, "TCP/TLS accept failed: %s\n", strerror(errno));
317 if (errno != EMFILE) {
318 break;
319 }
320 }
321 /* Prevent tight loop from hogging CPU */
322 usleep(1);
323 continue;
324 }
325 tcptls_session = ao2_alloc(sizeof(*tcptls_session), session_instance_destructor);
326 if (!tcptls_session) {
327 close(fd);
328 continue;
329 }
330
331 tcptls_session->overflow_buf = ast_str_create(128);
332 if (!tcptls_session->overflow_buf) {
333 ao2_ref(tcptls_session, -1);
334 close(fd);
335 continue;
336 }
337 ast_fd_clear_flags(fd, O_NONBLOCK);
338
339 tcptls_session->stream = ast_iostream_from_fd(&fd);
340 if (!tcptls_session->stream) {
341 ao2_ref(tcptls_session, -1);
342 close(fd);
343 continue;
344 }
345
346 tcptls_session->parent = desc;
347 ast_sockaddr_copy(&tcptls_session->remote_address, &addr);
348
349 tcptls_session->client = 0;
350
351 /* This thread is now the only place that controls the single ref to tcptls_session */
353 ast_log(LOG_ERROR, "TCP/TLS unable to launch helper thread for peer '%s': %s\n",
354 ast_sockaddr_stringify(&tcptls_session->remote_address),
355 strerror(errno));
356 ao2_ref(tcptls_session, -1);
357 }
358 }
359
360 ast_log(LOG_ERROR, "TCP/TLS listener thread ended abnormally\n");
361
362 /* Close the listener socket so Asterisk doesn't appear dead. */
363 fd = desc->accept_fd;
364 desc->accept_fd = -1;
365 if (0 <= fd) {
366 close(fd);
367 }
368 return NULL;
369}
int ast_accept(int sockfd, struct ast_sockaddr *addr)
Wrapper around accept(2) that uses struct ast_sockaddr.
Definition netsock2.c:584
Socket address structure.
Definition netsock2.h:97
int ast_wait_for_input(int fd, int ms)
Definition utils.c:1732
#define ast_pthread_create_detached_background(a, b, c, d)
Definition utils.h:637

References ao2_alloc, ao2_ref, ast_accept(), ast_fd_clear_flags, ast_iostream_from_fd(), ast_log, ast_pthread_create_detached_background, ast_sockaddr_copy(), ast_sockaddr_stringify(), ast_str_create, ast_wait_for_input(), ast_tcptls_session_instance::client, desc, errno, handle_tcptls_connection(), LOG_ERROR, NULL, ast_tcptls_session_instance::overflow_buf, ast_tcptls_session_instance::parent, ast_tcptls_session_instance::remote_address, session_instance_destructor(), and ast_tcptls_session_instance::stream.

Referenced by http_server_create().

◆ ast_tcptls_server_start()

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().

Version
1.6.1 changed desc parameter to be of ast_tcptls_session_args type

Definition at line 783 of file tcptls.c.

784{
785 int x = 1;
786 int tls_changed = 0;
787 int sd_socket;
788
789 if (desc->tls_cfg) {
790 char hash[41];
791 char *str = NULL;
792 struct stat st;
793
794 /* Store the hashes of the TLS certificate etc. */
795 if (stat(desc->tls_cfg->certfile, &st) || NULL == (str = ast_read_textfile(desc->tls_cfg->certfile))) {
796 memset(hash, 0, 41);
797 } else {
798 ast_sha1_hash(hash, str);
799 }
800 ast_free(str);
801 str = NULL;
802 memcpy(desc->tls_cfg->certhash, hash, 41);
803 if (stat(desc->tls_cfg->pvtfile, &st) || NULL == (str = ast_read_textfile(desc->tls_cfg->pvtfile))) {
804 memset(hash, 0, 41);
805 } else {
806 ast_sha1_hash(hash, str);
807 }
808 ast_free(str);
809 str = NULL;
810 memcpy(desc->tls_cfg->pvthash, hash, 41);
811 if (stat(desc->tls_cfg->cafile, &st) || NULL == (str = ast_read_textfile(desc->tls_cfg->cafile))) {
812 memset(hash, 0, 41);
813 } else {
814 ast_sha1_hash(hash, str);
815 }
816 ast_free(str);
817 str = NULL;
818 memcpy(desc->tls_cfg->cahash, hash, 41);
819
820 /* Check whether TLS configuration has changed */
821 if (!desc->old_tls_cfg) { /* No previous configuration */
822 tls_changed = 1;
823 desc->old_tls_cfg = ast_calloc(1, sizeof(*desc->old_tls_cfg));
824 } else if (memcmp(desc->tls_cfg->certhash, desc->old_tls_cfg->certhash, 41)) {
825 tls_changed = 1;
826 } else if (memcmp(desc->tls_cfg->pvthash, desc->old_tls_cfg->pvthash, 41)) {
827 tls_changed = 1;
828 } else if (strcmp(desc->tls_cfg->cipher, desc->old_tls_cfg->cipher)) {
829 tls_changed = 1;
830 } else if (memcmp(desc->tls_cfg->cahash, desc->old_tls_cfg->cahash, 41)) {
831 tls_changed = 1;
832 } else if (strcmp(desc->tls_cfg->capath, desc->old_tls_cfg->capath)) {
833 tls_changed = 1;
834 } else if (memcmp(&desc->tls_cfg->flags, &desc->old_tls_cfg->flags, sizeof(desc->tls_cfg->flags))) {
835 tls_changed = 1;
836 }
837
838 if (tls_changed) {
839 ast_debug(1, "Changed parameters for %s found\n", desc->name);
840 }
841 }
842
843 /* Do nothing if nothing has changed */
844 if (!tls_changed && !ast_sockaddr_cmp(&desc->old_address, &desc->local_address)) {
845 ast_debug(1, "Nothing changed in %s\n", desc->name);
846 return;
847 }
848
849 /* If we return early, there is no one listening */
850 ast_sockaddr_setnull(&desc->old_address);
851
852 /* Shutdown a running server if there is one */
853 if (desc->master != AST_PTHREADT_NULL) {
854 pthread_cancel(desc->master);
855 pthread_kill(desc->master, SIGURG);
856 pthread_join(desc->master, NULL);
857 }
858
859 sd_socket = ast_sd_get_fd(SOCK_STREAM, &desc->local_address);
860
861 if (sd_socket != -1) {
862 if (desc->accept_fd != sd_socket) {
863 if (desc->accept_fd != -1) {
864 close(desc->accept_fd);
865 }
866 desc->accept_fd = sd_socket;
867 }
868
869 goto systemd_socket_activation;
870 }
871
872 if (desc->accept_fd != -1) {
873 close(desc->accept_fd);
874 desc->accept_fd = -1;
875 }
876
877 /* If there's no new server, stop here */
878 if (ast_sockaddr_isnull(&desc->local_address)) {
879 ast_debug(2, "Server disabled: %s\n", desc->name);
880 return;
881 }
882
883 desc->accept_fd = ast_socket_nonblock(ast_sockaddr_is_ipv6(&desc->local_address) ?
884 AF_INET6 : AF_INET, SOCK_STREAM, 0);
885 if (desc->accept_fd < 0) {
886 ast_log(LOG_ERROR, "Unable to allocate socket for %s: %s\n", desc->name, strerror(errno));
887 return;
888 }
889
890 setsockopt(desc->accept_fd, SOL_SOCKET, SO_REUSEADDR, &x, sizeof(x));
891 if (ast_bind(desc->accept_fd, &desc->local_address)) {
892 ast_log(LOG_ERROR, "Unable to bind %s to %s: %s\n",
893 desc->name,
894 ast_sockaddr_stringify(&desc->local_address),
895 strerror(errno));
896 goto error;
897 }
898 if (listen(desc->accept_fd, 10)) {
899 ast_log(LOG_ERROR, "Unable to listen for %s!\n", desc->name);
900 goto error;
901 }
902
903systemd_socket_activation:
904 if (ast_pthread_create_background(&desc->master, NULL, desc->accept_fn, desc)) {
905 ast_log(LOG_ERROR, "Unable to launch thread for %s on %s: %s\n",
906 desc->name,
907 ast_sockaddr_stringify(&desc->local_address),
908 strerror(errno));
909 goto error;
910 }
911
912 /* Set current info */
913 ast_sockaddr_copy(&desc->old_address, &desc->local_address);
914 if (desc->old_tls_cfg) {
915 ast_free(desc->old_tls_cfg->certfile);
916 ast_free(desc->old_tls_cfg->pvtfile);
917 ast_free(desc->old_tls_cfg->cipher);
918 ast_free(desc->old_tls_cfg->cafile);
919 ast_free(desc->old_tls_cfg->capath);
920 desc->old_tls_cfg->certfile = ast_strdup(desc->tls_cfg->certfile);
921 desc->old_tls_cfg->pvtfile = ast_strdup(desc->tls_cfg->pvtfile);
922 desc->old_tls_cfg->cipher = ast_strdup(desc->tls_cfg->cipher);
923 desc->old_tls_cfg->cafile = ast_strdup(desc->tls_cfg->cafile);
924 desc->old_tls_cfg->capath = ast_strdup(desc->tls_cfg->capath);
925 memcpy(desc->old_tls_cfg->certhash, desc->tls_cfg->certhash, 41);
926 memcpy(desc->old_tls_cfg->pvthash, desc->tls_cfg->pvthash, 41);
927 memcpy(desc->old_tls_cfg->cahash, desc->tls_cfg->cahash, 41);
928 memcpy(&desc->old_tls_cfg->flags, &desc->tls_cfg->flags, sizeof(desc->old_tls_cfg->flags));
929 }
930
931 return;
932
933error:
934 close(desc->accept_fd);
935 desc->accept_fd = -1;
936}
const char * str
Definition app_jack.c:150
#define ast_free(a)
Definition astmm.h:180
#define ast_strdup(str)
A wrapper for strdup()
Definition astmm.h:241
#define ast_calloc(num, len)
A wrapper for calloc()
Definition astmm.h:202
char * ast_read_textfile(const char *file)
Read a file into asterisk.
Definition main/app.c:2950
int ast_sd_get_fd(int type, const struct ast_sockaddr *addr)
Find a listening file descriptor provided by socket activation.
Definition io.c:438
#define AST_PTHREADT_NULL
Definition lock.h:73
#define ast_pthread_create_background(a, b, c, d)
Definition utils.h:632
void ast_sha1_hash(char *output, const char *input)
Produces SHA1 hash based on input string.
Definition utils.c:266

References ast_bind(), ast_calloc, ast_debug, ast_free, ast_log, ast_pthread_create_background, AST_PTHREADT_NULL, ast_read_textfile(), ast_sd_get_fd(), ast_sha1_hash(), ast_sockaddr_cmp(), ast_sockaddr_copy(), ast_sockaddr_is_ipv6(), ast_sockaddr_isnull(), ast_sockaddr_setnull(), ast_sockaddr_stringify(), ast_socket_nonblock, ast_strdup, desc, errno, error(), LOG_ERROR, NULL, and str.

Referenced by __ast_http_load(), __init_manager(), and http_server_start().

◆ ast_tcptls_server_stop()

void ast_tcptls_server_stop ( struct ast_tcptls_session_args desc)

Shutdown a running server if there is one.

Version
1.6.1 changed desc parameter to be of ast_tcptls_session_args type

Definition at line 948 of file tcptls.c.

949{
950 if (desc->master != AST_PTHREADT_NULL) {
951 pthread_cancel(desc->master);
952 pthread_kill(desc->master, SIGURG);
953 pthread_join(desc->master, NULL);
954 desc->master = AST_PTHREADT_NULL;
955 }
956 if (desc->accept_fd != -1) {
957 close(desc->accept_fd);
958 }
959 desc->accept_fd = -1;
960
961 if (desc->old_tls_cfg) {
962 ast_free(desc->old_tls_cfg->certfile);
963 ast_free(desc->old_tls_cfg->pvtfile);
964 ast_free(desc->old_tls_cfg->cipher);
965 ast_free(desc->old_tls_cfg->cafile);
966 ast_free(desc->old_tls_cfg->capath);
967 ast_free(desc->old_tls_cfg);
968 desc->old_tls_cfg = NULL;
969 }
970
971 ast_debug(2, "Stopped server :: %s\n", desc->name);
972}

References ast_debug, ast_free, AST_PTHREADT_NULL, desc, and NULL.

Referenced by __ast_http_load(), __init_manager(), http_server_destroy(), manager_shutdown(), and unload_module().

◆ ast_tcptls_start_tls()

struct ast_tcptls_session_instance * ast_tcptls_start_tls ( struct ast_tcptls_session_instance tcptls_session)

Start TLS negotiation on an existing unsecured connection.

Since
20.21.0
22.11.0
23.5.0
Note
This function only needs to be called if an unsecured tcptls session is already established and you need to switch it to TLS. This function performs the handshake and validation. ast_ssl_setup_client must be called first to create the SSL context.
Parameters
tcptls_sessionThe existing unsecured session
Warning
If this function fails, it will automatically dereference tcptls_session and close the connection so don't attempt to dereference it again.
Return values
tcptls_sessionon Success
NULLFailure

Definition at line 133 of file tcptls.c.

134{
135#ifdef DO_SSL
136 SSL *ssl;
137#endif
138
139 if (tcptls_session->parent->tls_cfg && tcptls_session->parent->tls_cfg->enabled) {
140#ifdef DO_SSL
141 if (ast_iostream_start_tls(&tcptls_session->stream, tcptls_session->parent->tls_cfg->ssl_ctx, tcptls_session->client) < 0) {
142 SSL *ssl = ast_iostream_get_ssl(tcptls_session->stream);
143 if (ssl) {
144 ast_log(LOG_ERROR, "Unable to set up ssl connection with peer '%s'\n",
145 ast_sockaddr_stringify(&tcptls_session->remote_address));
146 }
147 ast_tcptls_close_session_file(tcptls_session);
148 ao2_ref(tcptls_session, -1);
149 return NULL;
150 }
151
152 ssl = ast_iostream_get_ssl(tcptls_session->stream);
153 if ((tcptls_session->client && !ast_test_flag(&tcptls_session->parent->tls_cfg->flags, AST_SSL_DONT_VERIFY_SERVER))
154 || (!tcptls_session->client && ast_test_flag(&tcptls_session->parent->tls_cfg->flags, AST_SSL_VERIFY_CLIENT))) {
155 X509 *peer;
156 long res;
157 peer = SSL_get_peer_certificate(ssl);
158 if (!peer) {
159 ast_log(LOG_ERROR, "No SSL certificate to verify from peer '%s'\n",
160 ast_sockaddr_stringify(&tcptls_session->remote_address));
161 ast_tcptls_close_session_file(tcptls_session);
162 ao2_ref(tcptls_session, -1);
163 return NULL;
164 }
165
166 res = SSL_get_verify_result(ssl);
167 if (res != X509_V_OK) {
168 ast_log(LOG_ERROR, "Certificate from peer '%s' did not verify: %s\n",
169 ast_sockaddr_stringify(&tcptls_session->remote_address),
170 X509_verify_cert_error_string(res));
171 X509_free(peer);
172 ast_tcptls_close_session_file(tcptls_session);
173 ao2_ref(tcptls_session, -1);
174 return NULL;
175 }
176 if (!ast_test_flag(&tcptls_session->parent->tls_cfg->flags, AST_SSL_IGNORE_COMMON_NAME)) {
177 ASN1_STRING *str;
178 X509_NAME *name = X509_get_subject_name(peer);
179 STACK_OF(GENERAL_NAME) *alt_names;
180 int pos = -1;
181 int found = 0;
182
183 for (;;) {
184 /* Walk the certificate to check all available "Common Name" */
185 /* XXX Probably should do a gethostbyname on the hostname and compare that as well */
186 pos = X509_NAME_get_index_by_NID(name, NID_commonName, pos);
187 if (pos < 0) {
188 break;
189 }
190 str = X509_NAME_ENTRY_get_data(X509_NAME_get_entry(name, pos));
191 if (!check_tcptls_cert_name(str, tcptls_session->parent->hostname, "common name")) {
192 found = 1;
193 break;
194 }
195 }
196
197 if (!found) {
198 alt_names = X509_get_ext_d2i(peer, NID_subject_alt_name, NULL, NULL);
199 if (alt_names != NULL) {
200 int alt_names_count = sk_GENERAL_NAME_num(alt_names);
201
202 for (pos = 0; pos < alt_names_count; pos++) {
203 const GENERAL_NAME *alt_name = sk_GENERAL_NAME_value(alt_names, pos);
204
205 if (alt_name->type != GEN_DNS) {
206 continue;
207 }
208
209 if (!check_tcptls_cert_name(alt_name->d.dNSName, tcptls_session->parent->hostname, "alt name")) {
210 found = 1;
211 break;
212 }
213 }
214
215 sk_GENERAL_NAME_pop_free(alt_names, GENERAL_NAME_free);
216 }
217 }
218
219 if (!found) {
220 ast_log(LOG_ERROR, "Certificate common name from peer '%s' did not match (%s)\n",
221 ast_sockaddr_stringify(&tcptls_session->remote_address), tcptls_session->parent->hostname);
222 X509_free(peer);
223 ast_tcptls_close_session_file(tcptls_session);
224 ao2_ref(tcptls_session, -1);
225 return NULL;
226 }
227 }
228 X509_free(peer);
229 }
230#else
231 ast_log(LOG_ERROR, "TLS client failed: Asterisk is compiled without OpenSSL support. Install OpenSSL development headers and rebuild Asterisk after running ./configure\n");
232 ast_tcptls_close_session_file(tcptls_session);
233 ao2_ref(tcptls_session, -1);
234 return NULL;
235#endif /* DO_SSL */
236 }
237
238 return tcptls_session;
239}
static const char name[]
Definition format_mp3.c:68
SSL * ast_iostream_get_ssl(struct ast_iostream *stream)
Get a pointer to an iostream's OpenSSL SSL structure.
Definition iostream.c:114
int ast_iostream_start_tls(struct ast_iostream **stream, SSL_CTX *ctx, int client)
Begin TLS on an iostream.
Definition iostream.c:632
struct ssl_st SSL
Definition iostream.h:37
struct ast_tls_config * tls_cfg
Definition tcptls.h:135
char hostname[MAXHOSTNAMELEN]
Definition tcptls.h:134
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 NUL...
Definition tcptls.c:938
@ AST_SSL_IGNORE_COMMON_NAME
Definition tcptls.h:71

References ao2_ref, ast_iostream_get_ssl(), ast_iostream_start_tls(), ast_log, ast_sockaddr_stringify(), AST_SSL_DONT_VERIFY_SERVER, AST_SSL_IGNORE_COMMON_NAME, AST_SSL_VERIFY_CLIENT, ast_tcptls_close_session_file(), ast_test_flag, ast_tcptls_session_instance::client, ast_tls_config::enabled, ast_tls_config::flags, ast_tcptls_session_args::hostname, LOG_ERROR, name, NULL, ast_tcptls_session_instance::parent, ast_tcptls_session_instance::remote_address, ast_tls_config::ssl_ctx, str, ast_tcptls_session_instance::stream, and ast_tcptls_session_args::tls_cfg.

Referenced by handle_tcptls_connection(), and websocket_client_connect().

◆ ast_tls_read_conf()

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 974 of file tcptls.c.

975{
976 if (!strcasecmp(varname, "tlsenable") || !strcasecmp(varname, "sslenable")) {
977 tls_cfg->enabled = ast_true(value) ? 1 : 0;
978 } else if (!strcasecmp(varname, "tlscertfile") || !strcasecmp(varname, "sslcert") || !strcasecmp(varname, "tlscert")) {
979 ast_free(tls_cfg->certfile);
980 tls_cfg->certfile = ast_strdup(value);
981 } else if (!strcasecmp(varname, "tlsprivatekey") || !strcasecmp(varname, "sslprivatekey")) {
982 ast_free(tls_cfg->pvtfile);
983 tls_cfg->pvtfile = ast_strdup(value);
984 } else if (!strcasecmp(varname, "tlscipher") || !strcasecmp(varname, "sslcipher")) {
985 ast_free(tls_cfg->cipher);
986 tls_cfg->cipher = ast_strdup(value);
987 } else if (!strcasecmp(varname, "tlscafile")) {
988 ast_free(tls_cfg->cafile);
989 tls_cfg->cafile = ast_strdup(value);
990 } else if (!strcasecmp(varname, "tlscapath") || !strcasecmp(varname, "tlscadir")) {
991 ast_free(tls_cfg->capath);
992 tls_cfg->capath = ast_strdup(value);
993 } else if (!strcasecmp(varname, "tlsverifyclient")) {
995 } else if (!strcasecmp(varname, "tlsdontverifyserver")) {
997 } else if (!strcasecmp(varname, "tlsbindaddr") || !strcasecmp(varname, "sslbindaddr")) {
999 ast_log(LOG_ERROR, "Invalid %s '%s'\n", varname, value);
1000 } else if (!strcasecmp(varname, "tlsclientmethod") || !strcasecmp(varname, "sslclientmethod")) {
1001 if (!strcasecmp(value, "tlsv1")) {
1005 } else if (!strcasecmp(value, "sslv3")) {
1009 } else if (!strcasecmp(value, "sslv2")) {
1013 }
1014 } else if (!strcasecmp(varname, "tlsservercipherorder")) {
1016 } else if (!strcasecmp(varname, "tlsdisablev1")) {
1018 } else if (!strcasecmp(varname, "tlsdisablev11")) {
1020 } else if (!strcasecmp(varname, "tlsdisablev12")) {
1022 } else {
1023 return -1;
1024 }
1025
1026 return 0;
1027}
int ast_parse_arg(const char *arg, enum ast_parse_flags flags, void *p_result,...)
The argument parsing routine.
int attribute_pure ast_true(const char *val)
Make sure something is true. Determine if a string containing a boolean value is "true"....
Definition utils.c:2233
struct ast_sockaddr local_address
Definition tcptls.h:131
int value
Definition syslog.c:37
#define ast_set2_flag(p, value, flag)
Definition utils.h:95
#define ast_clear_flag(p, flag)
Definition utils.h:78
#define ast_set_flag(p, flag)
Definition utils.h:71

References ast_clear_flag, ast_free, ast_log, ast_parse_arg(), ast_set2_flag, ast_set_flag, AST_SSL_DISABLE_TLSV1, AST_SSL_DISABLE_TLSV11, AST_SSL_DISABLE_TLSV12, AST_SSL_DONT_VERIFY_SERVER, AST_SSL_SERVER_CIPHER_ORDER, 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_ERROR, PARSE_ADDR, ast_tls_config::pvtfile, and value.

Referenced by __ast_http_load(), and __init_manager().

◆ handle_tcptls_connection()

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.

Note
must decrement ref count before returning NULL on error

Definition at line 248 of file tcptls.c.

249{
250 struct ast_tcptls_session_instance *tcptls_session = data;
251
252 /* TCP/TLS connections are associated with external protocols, and
253 * should not be allowed to execute 'dangerous' functions. This may
254 * need to be pushed down into the individual protocol handlers, but
255 * this seems like a good general policy.
256 */
258 ast_log(LOG_ERROR, "Failed to inhibit privilege escalations; killing connection from peer '%s'\n",
259 ast_sockaddr_stringify(&tcptls_session->remote_address));
260 ast_tcptls_close_session_file(tcptls_session);
261 ao2_ref(tcptls_session, -1);
262 return NULL;
263 }
264
265 /*
266 * TCP/TLS connections are associated with external protocols which can
267 * be considered to be user interfaces (even for SIP messages), and
268 * will not handle channel media. This may need to be pushed down into
269 * the individual protocol handlers, but this seems like a good start.
270 */
272 ast_log(LOG_ERROR, "Failed to set user interface status; killing connection from peer '%s'\n",
273 ast_sockaddr_stringify(&tcptls_session->remote_address));
274 ast_tcptls_close_session_file(tcptls_session);
275 ao2_ref(tcptls_session, -1);
276 return NULL;
277 }
278
279 if (ast_tcptls_start_tls(tcptls_session) == NULL) {
280 return NULL;
281 }
282
283 if (tcptls_session->parent->worker_fn) {
284 return tcptls_session->parent->worker_fn(tcptls_session);
285 } else {
286 return tcptls_session;
287 }
288}
int ast_thread_inhibit_escalations(void)
Inhibit (in the current thread) the execution of dialplan functions which cause privilege escalations...
struct ast_tcptls_session_instance * ast_tcptls_start_tls(struct ast_tcptls_session_instance *tcptls_session)
Start TLS negotiation on an existing unsecured connection.
Definition tcptls.c:133
int ast_thread_user_interface_set(int is_user_interface)
Set the current thread's user interface status.
Definition utils.c:3267

References ao2_ref, ast_log, ast_sockaddr_stringify(), ast_tcptls_close_session_file(), ast_tcptls_start_tls(), ast_thread_inhibit_escalations(), ast_thread_user_interface_set(), LOG_ERROR, NULL, ast_tcptls_session_instance::parent, ast_tcptls_session_instance::remote_address, and ast_tcptls_session_args::worker_fn.

Referenced by ast_tcptls_client_start_timeout(), and ast_tcptls_server_root().

◆ session_instance_destructor()

static void session_instance_destructor ( void *  obj)
static

◆ socket_connect()

static int socket_connect ( int  sockfd,
const struct ast_sockaddr addr,
int  timeout 
)
static

Definition at line 623 of file tcptls.c.

624{
625 int optval = 0;
626 socklen_t optlen = sizeof(int);
627
628 errno = 0;
629
630 if (ast_connect(sockfd, addr)) {
631 int res;
632
633 /*
634 * A connect failure could mean things are still in progress.
635 * If so wait for it to complete.
636 */
637
638 if (errno != EINPROGRESS) {
639 return -1;
640 }
641
642 while ((res = ast_wait_for_output(sockfd, timeout)) != 1) {
643 if (res == 0) {
644 errno = ETIMEDOUT;
645 return -1;
646 }
647
648 if (errno != EINTR) {
649 return -1;
650 }
651 }
652 }
653
654 /* Check the status to ensure it actually connected successfully */
655 if (getsockopt(sockfd, SOL_SOCKET, SO_ERROR, &optval, &optlen) < 0) {
656 return -1;
657 }
658
659 if (optval) {
660 errno = optval;
661 return -1;
662 }
663
664 return 0;
665}
int ast_connect(int sockfd, const struct ast_sockaddr *addr)
Wrapper around connect(2) that uses struct ast_sockaddr.
Definition netsock2.c:595
int ast_wait_for_output(int fd, int ms)
Definition utils.c:1742

References ast_connect(), ast_wait_for_output(), and errno.

Referenced by ast_tcptls_client_start_timeout().