Asterisk - The Open Source Telephony Project GIT-master-70eff7f
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 400 of file tcptls.c.

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

596{
597 return __ssl_setup(cfg, 0, 0);
598}
static int __ssl_setup(struct ast_tls_config *cfg, int client, int suppress_progress_msgs)
Definition tcptls.c:400

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

601{
602 return __ssl_setup(cfg, 1, 1);
603}

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

606{
607#ifdef DO_SSL
608 if (cfg && cfg->ssl_ctx) {
609 SSL_CTX_free(cfg->ssl_ctx);
610 cfg->ssl_ctx = NULL;
611 }
612#endif
613}

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

710{
711 int fd, x = 1;
712 struct ast_tcptls_session_instance *tcptls_session = NULL;
713
714 ast_assert(!desc->tls_cfg
715 || ast_test_flag(&desc->tls_cfg->flags, AST_SSL_DONT_VERIFY_SERVER)
716 || !ast_strlen_zero(desc->hostname));
717
718 /* Do nothing if nothing has changed */
719 if (!ast_sockaddr_cmp(&desc->old_address, &desc->remote_address)) {
720 ast_debug(1, "Nothing changed in %s\n", desc->name);
721 return NULL;
722 }
723
724 /* If we return early, there is no connection */
725 ast_sockaddr_setnull(&desc->old_address);
726
727 fd = desc->accept_fd = ast_socket_nonblock(ast_sockaddr_is_ipv6(&desc->remote_address) ?
728 AF_INET6 : AF_INET, SOCK_STREAM, IPPROTO_TCP);
729 if (desc->accept_fd < 0) {
730 ast_log(LOG_ERROR, "Unable to allocate socket for %s: %s\n",
731 desc->name, strerror(errno));
732 return NULL;
733 }
734
735 /* if a local address was specified, bind to it so the connection will
736 originate from the desired address */
737 if (!ast_sockaddr_isnull(&desc->local_address) &&
738 !ast_sockaddr_is_any(&desc->local_address)) {
739 setsockopt(desc->accept_fd, SOL_SOCKET, SO_REUSEADDR, &x, sizeof(x));
740 if (ast_bind(desc->accept_fd, &desc->local_address)) {
741 ast_log(LOG_ERROR, "Unable to bind %s to %s: %s\n",
742 desc->name,
743 ast_sockaddr_stringify(&desc->local_address),
744 strerror(errno));
745 goto error;
746 }
747 }
748
749 tcptls_session = ao2_alloc(sizeof(*tcptls_session), session_instance_destructor);
750 if (!tcptls_session) {
751 goto error;
752 }
753
754 tcptls_session->overflow_buf = ast_str_create(128);
755 if (!tcptls_session->overflow_buf) {
756 goto error;
757 }
758 tcptls_session->client = 1;
759 tcptls_session->stream = ast_iostream_from_fd(&fd);
760 if (!tcptls_session->stream) {
761 goto error;
762 }
763
764 /* From here on out, the iostream owns the accept_fd and it will take
765 * care of closing it when the iostream is closed */
766
767 tcptls_session->parent = desc;
768 tcptls_session->parent->worker_fn = NULL;
769 ast_sockaddr_copy(&tcptls_session->remote_address,
770 &desc->remote_address);
771
772 /* Set current info */
773 ast_sockaddr_copy(&desc->old_address, &desc->remote_address);
774
775 if (!ast_strlen_zero(desc->hostname)) {
776 if (ast_iostream_set_sni_hostname(tcptls_session->stream, desc->hostname) != 0) {
777 ast_log(LOG_WARNING, "Unable to set SNI hostname '%s' on connection '%s'\n",
778 desc->hostname, desc->name);
779 }
780 }
781
782 return tcptls_session;
783
784error:
785 close(desc->accept_fd);
786 desc->accept_fd = -1;
787 ao2_cleanup(tcptls_session);
788 return NULL;
789}
#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 704 of file tcptls.c.

705{
706 return ast_tcptls_client_start_timeout(tcptls_session, -1);
707}
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:675

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

677{
679
680 if (!(desc = tcptls_session->parent)) {
681 ao2_ref(tcptls_session, -1);
682 return NULL;
683 }
684
685 if (socket_connect(desc->accept_fd, &desc->remote_address, timeout)) {
686 if (!desc->suppress_connection_msgs) {
687 ast_log(LOG_WARNING, "Unable to connect %s to %s: %s\n", desc->name,
688 ast_sockaddr_stringify(&desc->remote_address), strerror(errno));
689 }
690
691 ao2_ref(tcptls_session, -1);
692 return NULL;
693 }
694
695 ast_fd_clear_flags(desc->accept_fd, O_NONBLOCK);
696
697 if (desc->tls_cfg) {
698 __ssl_setup(desc->tls_cfg, 1, desc->suppress_connection_msgs);
699 }
700
701 return handle_tcptls_connection(tcptls_session);
702}
#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:631
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 946 of file tcptls.c.

947{
948 if (tcptls_session->stream) {
949 ast_iostream_close(tcptls_session->stream);
950 tcptls_session->stream = NULL;
951 } else {
952 ast_debug(1, "ast_tcptls_close_session_file invoked on session instance without file or file descriptor\n");
953 }
954}
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 298 of file tcptls.c.

299{
300 struct ast_tcptls_session_args *desc = data;
301 int fd;
302 struct ast_sockaddr addr;
303 struct ast_tcptls_session_instance *tcptls_session;
304 pthread_t launched;
305
306 for (;;) {
307 int i;
308
309 if (desc->periodic_fn) {
310 desc->periodic_fn(desc);
311 }
312 i = ast_wait_for_input(desc->accept_fd, desc->poll_timeout);
313 if (i <= 0) {
314 /* Prevent tight loop from hogging CPU */
315 usleep(1);
316 continue;
317 }
318 fd = ast_accept(desc->accept_fd, &addr);
319 if (fd < 0) {
320 if (errno != EAGAIN
321 && errno != EWOULDBLOCK
322 && errno != EINTR
323 && errno != ECONNABORTED) {
324 ast_log(LOG_ERROR, "TCP/TLS accept failed: %s\n", strerror(errno));
325 if (errno != EMFILE) {
326 break;
327 }
328 }
329 /* Prevent tight loop from hogging CPU */
330 usleep(1);
331 continue;
332 }
333 tcptls_session = ao2_alloc(sizeof(*tcptls_session), session_instance_destructor);
334 if (!tcptls_session) {
335 close(fd);
336 continue;
337 }
338
339 tcptls_session->overflow_buf = ast_str_create(128);
340 if (!tcptls_session->overflow_buf) {
341 ao2_ref(tcptls_session, -1);
342 close(fd);
343 continue;
344 }
345 ast_fd_clear_flags(fd, O_NONBLOCK);
346
347 tcptls_session->stream = ast_iostream_from_fd(&fd);
348 if (!tcptls_session->stream) {
349 ao2_ref(tcptls_session, -1);
350 close(fd);
351 continue;
352 }
353
354 tcptls_session->parent = desc;
355 ast_sockaddr_copy(&tcptls_session->remote_address, &addr);
356
357 tcptls_session->client = 0;
358
359 /* This thread is now the only place that controls the single ref to tcptls_session */
361 ast_log(LOG_ERROR, "TCP/TLS unable to launch helper thread for peer '%s': %s\n",
362 ast_sockaddr_stringify(&tcptls_session->remote_address),
363 strerror(errno));
364 ao2_ref(tcptls_session, -1);
365 }
366 }
367
368 ast_log(LOG_ERROR, "TCP/TLS listener thread ended abnormally\n");
369
370 /* Close the listener socket so Asterisk doesn't appear dead. */
371 fd = desc->accept_fd;
372 desc->accept_fd = -1;
373 if (0 <= fd) {
374 close(fd);
375 }
376 return NULL;
377}
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 791 of file tcptls.c.

792{
793 int x = 1;
794 int tls_changed = 0;
795 int sd_socket;
796
797 if (desc->tls_cfg) {
798 char hash[41];
799 char *str = NULL;
800 struct stat st;
801
802 /* Store the hashes of the TLS certificate etc. */
803 if (stat(desc->tls_cfg->certfile, &st) || NULL == (str = ast_read_textfile(desc->tls_cfg->certfile))) {
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->certhash, hash, 41);
811 if (stat(desc->tls_cfg->pvtfile, &st) || NULL == (str = ast_read_textfile(desc->tls_cfg->pvtfile))) {
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->pvthash, hash, 41);
819 if (stat(desc->tls_cfg->cafile, &st) || NULL == (str = ast_read_textfile(desc->tls_cfg->cafile))) {
820 memset(hash, 0, 41);
821 } else {
822 ast_sha1_hash(hash, str);
823 }
824 ast_free(str);
825 str = NULL;
826 memcpy(desc->tls_cfg->cahash, hash, 41);
827
828 /* Check whether TLS configuration has changed */
829 if (!desc->old_tls_cfg) { /* No previous configuration */
830 tls_changed = 1;
831 desc->old_tls_cfg = ast_calloc(1, sizeof(*desc->old_tls_cfg));
832 } else if (memcmp(desc->tls_cfg->certhash, desc->old_tls_cfg->certhash, 41)) {
833 tls_changed = 1;
834 } else if (memcmp(desc->tls_cfg->pvthash, desc->old_tls_cfg->pvthash, 41)) {
835 tls_changed = 1;
836 } else if (strcmp(desc->tls_cfg->cipher, desc->old_tls_cfg->cipher)) {
837 tls_changed = 1;
838 } else if (memcmp(desc->tls_cfg->cahash, desc->old_tls_cfg->cahash, 41)) {
839 tls_changed = 1;
840 } else if (strcmp(desc->tls_cfg->capath, desc->old_tls_cfg->capath)) {
841 tls_changed = 1;
842 } else if (memcmp(&desc->tls_cfg->flags, &desc->old_tls_cfg->flags, sizeof(desc->tls_cfg->flags))) {
843 tls_changed = 1;
844 }
845
846 if (tls_changed) {
847 ast_debug(1, "Changed parameters for %s found\n", desc->name);
848 }
849 }
850
851 /* Do nothing if nothing has changed */
852 if (!tls_changed && !ast_sockaddr_cmp(&desc->old_address, &desc->local_address)) {
853 ast_debug(1, "Nothing changed in %s\n", desc->name);
854 return;
855 }
856
857 /* If we return early, there is no one listening */
858 ast_sockaddr_setnull(&desc->old_address);
859
860 /* Shutdown a running server if there is one */
861 if (desc->master != AST_PTHREADT_NULL) {
862 pthread_cancel(desc->master);
863 pthread_kill(desc->master, SIGURG);
864 pthread_join(desc->master, NULL);
865 }
866
867 sd_socket = ast_sd_get_fd(SOCK_STREAM, &desc->local_address);
868
869 if (sd_socket != -1) {
870 if (desc->accept_fd != sd_socket) {
871 if (desc->accept_fd != -1) {
872 close(desc->accept_fd);
873 }
874 desc->accept_fd = sd_socket;
875 }
876
877 goto systemd_socket_activation;
878 }
879
880 if (desc->accept_fd != -1) {
881 close(desc->accept_fd);
882 desc->accept_fd = -1;
883 }
884
885 /* If there's no new server, stop here */
886 if (ast_sockaddr_isnull(&desc->local_address)) {
887 ast_debug(2, "Server disabled: %s\n", desc->name);
888 return;
889 }
890
891 desc->accept_fd = ast_socket_nonblock(ast_sockaddr_is_ipv6(&desc->local_address) ?
892 AF_INET6 : AF_INET, SOCK_STREAM, 0);
893 if (desc->accept_fd < 0) {
894 ast_log(LOG_ERROR, "Unable to allocate socket for %s: %s\n", desc->name, strerror(errno));
895 return;
896 }
897
898 setsockopt(desc->accept_fd, SOL_SOCKET, SO_REUSEADDR, &x, sizeof(x));
899 if (ast_bind(desc->accept_fd, &desc->local_address)) {
900 ast_log(LOG_ERROR, "Unable to bind %s to %s: %s\n",
901 desc->name,
902 ast_sockaddr_stringify(&desc->local_address),
903 strerror(errno));
904 goto error;
905 }
906 if (listen(desc->accept_fd, 10)) {
907 ast_log(LOG_ERROR, "Unable to listen for %s!\n", desc->name);
908 goto error;
909 }
910
911systemd_socket_activation:
912 if (ast_pthread_create_background(&desc->master, NULL, desc->accept_fn, desc)) {
913 ast_log(LOG_ERROR, "Unable to launch thread for %s on %s: %s\n",
914 desc->name,
915 ast_sockaddr_stringify(&desc->local_address),
916 strerror(errno));
917 goto error;
918 }
919
920 /* Set current info */
921 ast_sockaddr_copy(&desc->old_address, &desc->local_address);
922 if (desc->old_tls_cfg) {
923 ast_free(desc->old_tls_cfg->certfile);
924 ast_free(desc->old_tls_cfg->pvtfile);
925 ast_free(desc->old_tls_cfg->cipher);
926 ast_free(desc->old_tls_cfg->cafile);
927 ast_free(desc->old_tls_cfg->capath);
928 desc->old_tls_cfg->certfile = ast_strdup(desc->tls_cfg->certfile);
929 desc->old_tls_cfg->pvtfile = ast_strdup(desc->tls_cfg->pvtfile);
930 desc->old_tls_cfg->cipher = ast_strdup(desc->tls_cfg->cipher);
931 desc->old_tls_cfg->cafile = ast_strdup(desc->tls_cfg->cafile);
932 desc->old_tls_cfg->capath = ast_strdup(desc->tls_cfg->capath);
933 memcpy(desc->old_tls_cfg->certhash, desc->tls_cfg->certhash, 41);
934 memcpy(desc->old_tls_cfg->pvthash, desc->tls_cfg->pvthash, 41);
935 memcpy(desc->old_tls_cfg->cahash, desc->tls_cfg->cahash, 41);
936 memcpy(&desc->old_tls_cfg->flags, &desc->tls_cfg->flags, sizeof(desc->old_tls_cfg->flags));
937 }
938
939 return;
940
941error:
942 close(desc->accept_fd);
943 desc->accept_fd = -1;
944}
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 956 of file tcptls.c.

957{
958 if (desc->master != AST_PTHREADT_NULL) {
959 pthread_cancel(desc->master);
960 pthread_kill(desc->master, SIGURG);
961 pthread_join(desc->master, NULL);
962 desc->master = AST_PTHREADT_NULL;
963 }
964 if (desc->accept_fd != -1) {
965 close(desc->accept_fd);
966 }
967 desc->accept_fd = -1;
968
969 if (desc->old_tls_cfg) {
970 ast_free(desc->old_tls_cfg->certfile);
971 ast_free(desc->old_tls_cfg->pvtfile);
972 ast_free(desc->old_tls_cfg->cipher);
973 ast_free(desc->old_tls_cfg->cafile);
974 ast_free(desc->old_tls_cfg->capath);
975 ast_free(desc->old_tls_cfg);
976 desc->old_tls_cfg = NULL;
977 }
978
979 ast_debug(2, "Stopped server :: %s\n", desc->name);
980}

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:946
@ 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 982 of file tcptls.c.

983{
984 if (!strcasecmp(varname, "tlsenable") || !strcasecmp(varname, "sslenable")) {
985 tls_cfg->enabled = ast_true(value) ? 1 : 0;
986 } else if (!strcasecmp(varname, "tlscertfile") || !strcasecmp(varname, "sslcert") || !strcasecmp(varname, "tlscert")) {
987 ast_free(tls_cfg->certfile);
988 tls_cfg->certfile = ast_strdup(value);
989 } else if (!strcasecmp(varname, "tlsprivatekey") || !strcasecmp(varname, "sslprivatekey")) {
990 ast_free(tls_cfg->pvtfile);
991 tls_cfg->pvtfile = ast_strdup(value);
992 } else if (!strcasecmp(varname, "tlscipher") || !strcasecmp(varname, "sslcipher")) {
993 ast_free(tls_cfg->cipher);
994 tls_cfg->cipher = ast_strdup(value);
995 } else if (!strcasecmp(varname, "tlscafile")) {
996 ast_free(tls_cfg->cafile);
997 tls_cfg->cafile = ast_strdup(value);
998 } else if (!strcasecmp(varname, "tlscapath") || !strcasecmp(varname, "tlscadir")) {
999 ast_free(tls_cfg->capath);
1000 tls_cfg->capath = ast_strdup(value);
1001 } else if (!strcasecmp(varname, "tlsverifyclient")) {
1003 } else if (!strcasecmp(varname, "tlsdontverifyserver")) {
1005 } else if (!strcasecmp(varname, "tlsbindaddr") || !strcasecmp(varname, "sslbindaddr")) {
1006 if (ast_parse_arg(value, PARSE_ADDR, &tls_desc->local_address))
1007 ast_log(LOG_ERROR, "Invalid %s '%s'\n", varname, value);
1008 } else if (!strcasecmp(varname, "tlsclientmethod") || !strcasecmp(varname, "sslclientmethod")) {
1009 if (!strcasecmp(value, "tlsv1")) {
1013 } else if (!strcasecmp(value, "sslv3")) {
1017 } else if (!strcasecmp(value, "sslv2")) {
1021 }
1022 } else if (!strcasecmp(varname, "tlsservercipherorder")) {
1024 } else if (!strcasecmp(varname, "tlsdisablev1")) {
1026 } else if (!strcasecmp(varname, "tlsdisablev11")) {
1028 } else if (!strcasecmp(varname, "tlsdisablev12")) {
1030 } else {
1031 return -1;
1032 }
1033
1034 return 0;
1035}
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 /*
253 * Inbound (server) TCP/TLS connections are associated with external
254 * protocols and are treated as untrusted user interfaces: they should
255 * not be allowed to execute 'dangerous' functions, and can be considered
256 * to be user interfaces (even for SIP messages) which will not handle
257 * channel media. This may need to be pushed down into the individual
258 * protocol handlers, but this seems like a good general policy. Each
259 * inbound connection runs on its own dedicated worker thread, so setting
260 * these thread-local flags here is safe.
261 *
262 * Outbound (client) connections are initiated by Asterisk itself, are not
263 * external user interfaces, and run synchronously on the caller's thread
264 * (for example a channel/PBX thread performing an outbound WebSocket dial,
265 * or ExternalIVR). Setting these flags for them would permanently poison
266 * that thread and make it refuse dangerous functions (STAT, SHELL, ...)
267 * for the remainder of its life, so skip them for client connections.
268 */
269 if (!tcptls_session->client) {
271 ast_log(LOG_ERROR, "Failed to inhibit privilege escalations; killing connection from peer '%s'\n",
272 ast_sockaddr_stringify(&tcptls_session->remote_address));
273 ast_tcptls_close_session_file(tcptls_session);
274 ao2_ref(tcptls_session, -1);
275 return NULL;
276 }
277
279 ast_log(LOG_ERROR, "Failed to set user interface status; killing connection from peer '%s'\n",
280 ast_sockaddr_stringify(&tcptls_session->remote_address));
281 ast_tcptls_close_session_file(tcptls_session);
282 ao2_ref(tcptls_session, -1);
283 return NULL;
284 }
285 }
286
287 if (ast_tcptls_start_tls(tcptls_session) == NULL) {
288 return NULL;
289 }
290
291 if (tcptls_session->parent->worker_fn) {
292 return tcptls_session->parent->worker_fn(tcptls_session);
293 } else {
294 return tcptls_session;
295 }
296}
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(), ast_tcptls_session_instance::client, 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 631 of file tcptls.c.

632{
633 int optval = 0;
634 socklen_t optlen = sizeof(int);
635
636 errno = 0;
637
638 if (ast_connect(sockfd, addr)) {
639 int res;
640
641 /*
642 * A connect failure could mean things are still in progress.
643 * If so wait for it to complete.
644 */
645
646 if (errno != EINPROGRESS) {
647 return -1;
648 }
649
650 while ((res = ast_wait_for_output(sockfd, timeout)) != 1) {
651 if (res == 0) {
652 errno = ETIMEDOUT;
653 return -1;
654 }
655
656 if (errno != EINTR) {
657 return -1;
658 }
659 }
660 }
661
662 /* Check the status to ensure it actually connected successfully */
663 if (getsockopt(sockfd, SOL_SOCKET, SO_ERROR, &optval, &optlen) < 0) {
664 return -1;
665 }
666
667 if (optval) {
668 errno = optval;
669 return -1;
670 }
671
672 return 0;
673}
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().