Asterisk - The Open Source Telephony Project GIT-master-70eff7f
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 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}
#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 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 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 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
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:946

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