Asterisk - The Open Source Telephony Project GIT-master-6144b6b
Loading...
Searching...
No Matches
Data Structures | Macros | Enumerations | Functions
tcptls.h File Reference

Generic support for tcp/tls servers in Asterisk. More...

#include <pthread.h>
#include <sys/param.h>
#include "asterisk/iostream.h"
#include "asterisk/netsock2.h"
#include "asterisk/utils.h"
Include dependency graph for tcptls.h:
This graph shows which files directly or indirectly include this file:

Go to the source code of this file.

Data Structures

struct  ast_tcptls_session_args
 arguments for the accepting thread More...
 
struct  ast_tcptls_session_instance
 describes a server instance More...
 
struct  ast_tls_config
 

Macros

#define AST_CERTFILE   "asterisk.pem"
 

Enumerations

enum  ast_ssl_flags {
  AST_SSL_VERIFY_CLIENT = (1 << 0) , AST_SSL_DONT_VERIFY_SERVER = (1 << 1) , AST_SSL_IGNORE_COMMON_NAME = (1 << 2) , AST_SSL_SSLV2_CLIENT = (1 << 3) ,
  AST_SSL_SSLV3_CLIENT = (1 << 4) , AST_SSL_TLSV1_CLIENT = (1 << 5) , AST_SSL_SERVER_CIPHER_ORDER = (1 << 6) , AST_SSL_DISABLE_TLSV1 = (1 << 7) ,
  AST_SSL_DISABLE_TLSV11 = (1 << 8) , AST_SSL_DISABLE_TLSV12 = (1 << 9)
}
 

Functions

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

Detailed Description

Generic support for tcp/tls servers in Asterisk.

Note
In order to have TLS/SSL support, we need the openssl libraries. Still we can decide whether or not to use them by commenting in or out the DO_SSL macro.

TLS/SSL support is basically implemented by reading from a config file (currently manager.conf, http.conf and pjsip.conf) the names of the certificate files and cipher to use, and then run ssl_setup() to create an appropriate data structure named ssl_ctx.

If we support multiple domains, presumably we need to read multiple certificates.

When we are requested to open a TLS socket, we run make_file_from_fd() on the socket, to do the necessary setup. At the moment the context's name is hardwired in the function, but we can certainly make it into an extra parameter to the function.

We declare most of ssl support variables unconditionally, because their number is small and this simplifies the code.

Note
The ssl-support variables (ssl_ctx, do_ssl, certfile, cipher) and their setup should be moved to a more central place, e.g. asterisk.conf and the source files that processes it. Similarly, ssl_setup() should be run earlier in the startup process so modules have it available.

TLS Implementation Overview

Definition in file tcptls.h.

Macro Definition Documentation

◆ AST_CERTFILE

#define AST_CERTFILE   "asterisk.pem"

SSL support

Definition at line 63 of file tcptls.h.

Enumeration Type Documentation

◆ ast_ssl_flags

Enumerator
AST_SSL_VERIFY_CLIENT 

Verify certificate when acting as server

AST_SSL_DONT_VERIFY_SERVER 

Don't verify certificate when connecting to a server

AST_SSL_IGNORE_COMMON_NAME 

Don't compare "Common Name" against IP or hostname

AST_SSL_SSLV2_CLIENT 

Use SSLv2 for outgoing client connections

AST_SSL_SSLV3_CLIENT 

Use SSLv3 for outgoing client connections

AST_SSL_TLSV1_CLIENT 

Use TLSv1 for outgoing client connections

AST_SSL_SERVER_CIPHER_ORDER 

Use server cipher order instead of the client order

AST_SSL_DISABLE_TLSV1 

Disable TLSv1 support

AST_SSL_DISABLE_TLSV11 

Disable TLSv1.1 support

AST_SSL_DISABLE_TLSV12 

Disable TLSv1.2 support

Definition at line 65 of file tcptls.h.

65 {
66 /*! Verify certificate when acting as server */
67 AST_SSL_VERIFY_CLIENT = (1 << 0),
68 /*! Don't verify certificate when connecting to a server */
70 /*! Don't compare "Common Name" against IP or hostname */
72 /*! Use SSLv2 for outgoing client connections */
73 AST_SSL_SSLV2_CLIENT = (1 << 3),
74 /*! Use SSLv3 for outgoing client connections */
75 AST_SSL_SSLV3_CLIENT = (1 << 4),
76 /*! Use TLSv1 for outgoing client connections */
77 AST_SSL_TLSV1_CLIENT = (1 << 5),
78 /*! Use server cipher order instead of the client order */
80 /*! Disable TLSv1 support */
81 AST_SSL_DISABLE_TLSV1 = (1 << 7),
82 /*! Disable TLSv1.1 support */
83 AST_SSL_DISABLE_TLSV11 = (1 << 8),
84 /*! Disable TLSv1.2 support */
85 AST_SSL_DISABLE_TLSV12 = (1 << 9),
86};
@ AST_SSL_VERIFY_CLIENT
Definition tcptls.h:67
@ AST_SSL_DONT_VERIFY_SERVER
Definition tcptls.h:69
@ AST_SSL_SSLV3_CLIENT
Definition tcptls.h:75
@ AST_SSL_DISABLE_TLSV11
Definition tcptls.h:83
@ AST_SSL_IGNORE_COMMON_NAME
Definition tcptls.h:71
@ 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

Function Documentation

◆ 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}
#define NULL
Definition resample.c:96
SSL_CTX * ssl_ctx
Definition tcptls.h:96

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 ast_log
Definition astobj2.c:42
#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
#define ast_debug(level,...)
Log a DEBUG message.
#define LOG_ERROR
#define LOG_WARNING
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
static force_inline int attribute_pure ast_strlen_zero(const char *s)
Definition strings.h:65
#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
int error(const char *format,...)
#define ast_test_flag(p, flag)
Definition utils.h:64
#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
struct ast_flags flags
Definition tcptls.h:95
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

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
char * certfile
Definition tcptls.h:90
char * cipher
Definition tcptls.h:92
char * pvtfile
Definition tcptls.h:91
char * capath
Definition tcptls.h:94
char * cafile
Definition tcptls.h:93
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().