Asterisk - The Open Source Telephony Project GIT-master-f36a736
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 ast_ssl_setup (struct ast_tls_config *cfg)
 Set up an SSL server. More...
 
void ast_ssl_teardown (struct ast_tls_config *cfg)
 free resources used by an SSL server More...
 
struct ast_tcptls_session_instanceast_tcptls_client_create (struct ast_tcptls_session_args *desc)
 Creates a client connection's ast_tcptls_session_instance. More...
 
struct ast_tcptls_session_instanceast_tcptls_client_start (struct ast_tcptls_session_instance *tcptls_session)
 Attempt to connect and start a tcptls session. More...
 
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. More...
 
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. More...
 
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(). More...
 
void ast_tcptls_server_stop (struct ast_tcptls_session_args *desc)
 Shutdown a running server if there is one. More...
 
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. More...
 
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. More...
 
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 
)
static

Definition at line 382 of file tcptls.c.

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

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(), 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 570 of file tcptls.c.

571{
572 return __ssl_setup(cfg, 0);
573}
static int __ssl_setup(struct ast_tls_config *cfg, int client)
Definition: tcptls.c:382

References __ssl_setup().

Referenced by __ast_http_load(), and __init_manager().

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

576{
577#ifdef DO_SSL
578 if (cfg && cfg->ssl_ctx) {
579 SSL_CTX_free(cfg->ssl_ctx);
580 cfg->ssl_ctx = NULL;
581 }
582#endif
583}

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

679{
680 int fd, x = 1;
681 struct ast_tcptls_session_instance *tcptls_session = NULL;
682
683 ast_assert(!desc->tls_cfg
684 || ast_test_flag(&desc->tls_cfg->flags, AST_SSL_DONT_VERIFY_SERVER)
685 || !ast_strlen_zero(desc->hostname));
686
687 /* Do nothing if nothing has changed */
688 if (!ast_sockaddr_cmp(&desc->old_address, &desc->remote_address)) {
689 ast_debug(1, "Nothing changed in %s\n", desc->name);
690 return NULL;
691 }
692
693 /* If we return early, there is no connection */
694 ast_sockaddr_setnull(&desc->old_address);
695
696 fd = desc->accept_fd = ast_socket_nonblock(ast_sockaddr_is_ipv6(&desc->remote_address) ?
697 AF_INET6 : AF_INET, SOCK_STREAM, IPPROTO_TCP);
698 if (desc->accept_fd < 0) {
699 ast_log(LOG_ERROR, "Unable to allocate socket for %s: %s\n",
700 desc->name, strerror(errno));
701 return NULL;
702 }
703
704 /* if a local address was specified, bind to it so the connection will
705 originate from the desired address */
706 if (!ast_sockaddr_isnull(&desc->local_address) &&
707 !ast_sockaddr_is_any(&desc->local_address)) {
708 setsockopt(desc->accept_fd, SOL_SOCKET, SO_REUSEADDR, &x, sizeof(x));
709 if (ast_bind(desc->accept_fd, &desc->local_address)) {
710 ast_log(LOG_ERROR, "Unable to bind %s to %s: %s\n",
711 desc->name,
712 ast_sockaddr_stringify(&desc->local_address),
713 strerror(errno));
714 goto error;
715 }
716 }
717
718 tcptls_session = ao2_alloc(sizeof(*tcptls_session), session_instance_destructor);
719 if (!tcptls_session) {
720 goto error;
721 }
722
723 tcptls_session->overflow_buf = ast_str_create(128);
724 if (!tcptls_session->overflow_buf) {
725 goto error;
726 }
727 tcptls_session->client = 1;
728 tcptls_session->stream = ast_iostream_from_fd(&fd);
729 if (!tcptls_session->stream) {
730 goto error;
731 }
732
733 /* From here on out, the iostream owns the accept_fd and it will take
734 * care of closing it when the iostream is closed */
735
736 tcptls_session->parent = desc;
737 tcptls_session->parent->worker_fn = NULL;
738 ast_sockaddr_copy(&tcptls_session->remote_address,
739 &desc->remote_address);
740
741 /* Set current info */
742 ast_sockaddr_copy(&desc->old_address, &desc->remote_address);
743
744 if (!ast_strlen_zero(desc->hostname)) {
745 if (ast_iostream_set_sni_hostname(tcptls_session->stream, desc->hostname) != 0) {
746 ast_log(LOG_WARNING, "Unable to set SNI hostname '%s' on connection '%s'\n",
747 desc->hostname, desc->name);
748 }
749 }
750
751 return tcptls_session;
752
753error:
754 close(desc->accept_fd);
755 desc->accept_fd = -1;
756 ao2_cleanup(tcptls_session);
757 return NULL;
758}
#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:611
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:156
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:150
struct ast_iostream * stream
Definition: tcptls.h:161
struct ast_sockaddr remote_address
Definition: tcptls.h:152
struct ast_tcptls_session_args * parent
Definition: tcptls.h:153
struct ast_str * overflow_buf
Definition: tcptls.h:159
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,...)
Definition: utils/frame.c:999
#define ast_assert(a)
Definition: utils.h:739
#define ast_socket_nonblock(domain, type, protocol)
Create a non-blocking socket.
Definition: utils.h:1073

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

674{
675 return ast_tcptls_client_start_timeout(tcptls_session, -1);
676}
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:645

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

647{
649
650 if (!(desc = tcptls_session->parent)) {
651 ao2_ref(tcptls_session, -1);
652 return NULL;
653 }
654
655 if (socket_connect(desc->accept_fd, &desc->remote_address, timeout)) {
656 ast_log(LOG_WARNING, "Unable to connect %s to %s: %s\n", desc->name,
657 ast_sockaddr_stringify(&desc->remote_address), strerror(errno));
658
659 ao2_ref(tcptls_session, -1);
660 return NULL;
661 }
662
663 ast_fd_clear_flags(desc->accept_fd, O_NONBLOCK);
664
665 if (desc->tls_cfg) {
666 desc->tls_cfg->enabled = 1;
667 __ssl_setup(desc->tls_cfg, 1);
668 }
669
670 return handle_tcptls_connection(tcptls_session);
671}
#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:601
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:140
#define ast_fd_clear_flags(fd, flags)
Clear flags on the given file descriptor.
Definition: utils.h:1055

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

916{
917 if (tcptls_session->stream) {
918 ast_iostream_close(tcptls_session->stream);
919 tcptls_session->stream = NULL;
920 } else {
921 ast_debug(1, "ast_tcptls_close_session_file invoked on session instance without file or file descriptor\n");
922 }
923}
int ast_iostream_close(struct ast_iostream *stream)
Close an iostream.
Definition: iostream.c:539

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

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

◆ ast_tcptls_server_root()

void * ast_tcptls_server_root ( void *  data)

Definition at line 280 of file tcptls.c.

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

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

761{
762 int x = 1;
763 int tls_changed = 0;
764 int sd_socket;
765
766 if (desc->tls_cfg) {
767 char hash[41];
768 char *str = NULL;
769 struct stat st;
770
771 /* Store the hashes of the TLS certificate etc. */
772 if (stat(desc->tls_cfg->certfile, &st) || NULL == (str = ast_read_textfile(desc->tls_cfg->certfile))) {
773 memset(hash, 0, 41);
774 } else {
775 ast_sha1_hash(hash, str);
776 }
777 ast_free(str);
778 str = NULL;
779 memcpy(desc->tls_cfg->certhash, hash, 41);
780 if (stat(desc->tls_cfg->pvtfile, &st) || NULL == (str = ast_read_textfile(desc->tls_cfg->pvtfile))) {
781 memset(hash, 0, 41);
782 } else {
783 ast_sha1_hash(hash, str);
784 }
785 ast_free(str);
786 str = NULL;
787 memcpy(desc->tls_cfg->pvthash, hash, 41);
788 if (stat(desc->tls_cfg->cafile, &st) || NULL == (str = ast_read_textfile(desc->tls_cfg->cafile))) {
789 memset(hash, 0, 41);
790 } else {
791 ast_sha1_hash(hash, str);
792 }
793 ast_free(str);
794 str = NULL;
795 memcpy(desc->tls_cfg->cahash, hash, 41);
796
797 /* Check whether TLS configuration has changed */
798 if (!desc->old_tls_cfg) { /* No previous configuration */
799 tls_changed = 1;
800 desc->old_tls_cfg = ast_calloc(1, sizeof(*desc->old_tls_cfg));
801 } else if (memcmp(desc->tls_cfg->certhash, desc->old_tls_cfg->certhash, 41)) {
802 tls_changed = 1;
803 } else if (memcmp(desc->tls_cfg->pvthash, desc->old_tls_cfg->pvthash, 41)) {
804 tls_changed = 1;
805 } else if (strcmp(desc->tls_cfg->cipher, desc->old_tls_cfg->cipher)) {
806 tls_changed = 1;
807 } else if (memcmp(desc->tls_cfg->cahash, desc->old_tls_cfg->cahash, 41)) {
808 tls_changed = 1;
809 } else if (strcmp(desc->tls_cfg->capath, desc->old_tls_cfg->capath)) {
810 tls_changed = 1;
811 } else if (memcmp(&desc->tls_cfg->flags, &desc->old_tls_cfg->flags, sizeof(desc->tls_cfg->flags))) {
812 tls_changed = 1;
813 }
814
815 if (tls_changed) {
816 ast_debug(1, "Changed parameters for %s found\n", desc->name);
817 }
818 }
819
820 /* Do nothing if nothing has changed */
821 if (!tls_changed && !ast_sockaddr_cmp(&desc->old_address, &desc->local_address)) {
822 ast_debug(1, "Nothing changed in %s\n", desc->name);
823 return;
824 }
825
826 /* If we return early, there is no one listening */
827 ast_sockaddr_setnull(&desc->old_address);
828
829 /* Shutdown a running server if there is one */
830 if (desc->master != AST_PTHREADT_NULL) {
831 pthread_cancel(desc->master);
832 pthread_kill(desc->master, SIGURG);
833 pthread_join(desc->master, NULL);
834 }
835
836 sd_socket = ast_sd_get_fd(SOCK_STREAM, &desc->local_address);
837
838 if (sd_socket != -1) {
839 if (desc->accept_fd != sd_socket) {
840 if (desc->accept_fd != -1) {
841 close(desc->accept_fd);
842 }
843 desc->accept_fd = sd_socket;
844 }
845
846 goto systemd_socket_activation;
847 }
848
849 if (desc->accept_fd != -1) {
850 close(desc->accept_fd);
851 desc->accept_fd = -1;
852 }
853
854 /* If there's no new server, stop here */
855 if (ast_sockaddr_isnull(&desc->local_address)) {
856 ast_debug(2, "Server disabled: %s\n", desc->name);
857 return;
858 }
859
860 desc->accept_fd = ast_socket_nonblock(ast_sockaddr_is_ipv6(&desc->local_address) ?
861 AF_INET6 : AF_INET, SOCK_STREAM, 0);
862 if (desc->accept_fd < 0) {
863 ast_log(LOG_ERROR, "Unable to allocate socket for %s: %s\n", desc->name, strerror(errno));
864 return;
865 }
866
867 setsockopt(desc->accept_fd, SOL_SOCKET, SO_REUSEADDR, &x, sizeof(x));
868 if (ast_bind(desc->accept_fd, &desc->local_address)) {
869 ast_log(LOG_ERROR, "Unable to bind %s to %s: %s\n",
870 desc->name,
871 ast_sockaddr_stringify(&desc->local_address),
872 strerror(errno));
873 goto error;
874 }
875 if (listen(desc->accept_fd, 10)) {
876 ast_log(LOG_ERROR, "Unable to listen for %s!\n", desc->name);
877 goto error;
878 }
879
880systemd_socket_activation:
881 if (ast_pthread_create_background(&desc->master, NULL, desc->accept_fn, desc)) {
882 ast_log(LOG_ERROR, "Unable to launch thread for %s on %s: %s\n",
883 desc->name,
884 ast_sockaddr_stringify(&desc->local_address),
885 strerror(errno));
886 goto error;
887 }
888
889 /* Set current info */
890 ast_sockaddr_copy(&desc->old_address, &desc->local_address);
891 if (desc->old_tls_cfg) {
892 ast_free(desc->old_tls_cfg->certfile);
893 ast_free(desc->old_tls_cfg->pvtfile);
894 ast_free(desc->old_tls_cfg->cipher);
895 ast_free(desc->old_tls_cfg->cafile);
896 ast_free(desc->old_tls_cfg->capath);
897 desc->old_tls_cfg->certfile = ast_strdup(desc->tls_cfg->certfile);
898 desc->old_tls_cfg->pvtfile = ast_strdup(desc->tls_cfg->pvtfile);
899 desc->old_tls_cfg->cipher = ast_strdup(desc->tls_cfg->cipher);
900 desc->old_tls_cfg->cafile = ast_strdup(desc->tls_cfg->cafile);
901 desc->old_tls_cfg->capath = ast_strdup(desc->tls_cfg->capath);
902 memcpy(desc->old_tls_cfg->certhash, desc->tls_cfg->certhash, 41);
903 memcpy(desc->old_tls_cfg->pvthash, desc->tls_cfg->pvthash, 41);
904 memcpy(desc->old_tls_cfg->cahash, desc->tls_cfg->cahash, 41);
905 memcpy(&desc->old_tls_cfg->flags, &desc->tls_cfg->flags, sizeof(desc->old_tls_cfg->flags));
906 }
907
908 return;
909
910error:
911 close(desc->accept_fd);
912 desc->accept_fd = -1;
913}
const char * str
Definition: app_jack.c:147
#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:2949
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:66
#define ast_pthread_create_background(a, b, c, d)
Definition: utils.h:592
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 925 of file tcptls.c.

926{
927 if (desc->master != AST_PTHREADT_NULL) {
928 pthread_cancel(desc->master);
929 pthread_kill(desc->master, SIGURG);
930 pthread_join(desc->master, NULL);
931 desc->master = AST_PTHREADT_NULL;
932 }
933 if (desc->accept_fd != -1) {
934 close(desc->accept_fd);
935 }
936 desc->accept_fd = -1;
937
938 if (desc->old_tls_cfg) {
939 ast_free(desc->old_tls_cfg->certfile);
940 ast_free(desc->old_tls_cfg->pvtfile);
941 ast_free(desc->old_tls_cfg->cipher);
942 ast_free(desc->old_tls_cfg->cafile);
943 ast_free(desc->old_tls_cfg->capath);
944 ast_free(desc->old_tls_cfg);
945 desc->old_tls_cfg = NULL;
946 }
947
948 ast_debug(2, "Stopped server :: %s\n", desc->name);
949}

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

952{
953 if (!strcasecmp(varname, "tlsenable") || !strcasecmp(varname, "sslenable")) {
954 tls_cfg->enabled = ast_true(value) ? 1 : 0;
955 } else if (!strcasecmp(varname, "tlscertfile") || !strcasecmp(varname, "sslcert") || !strcasecmp(varname, "tlscert")) {
956 ast_free(tls_cfg->certfile);
957 tls_cfg->certfile = ast_strdup(value);
958 } else if (!strcasecmp(varname, "tlsprivatekey") || !strcasecmp(varname, "sslprivatekey")) {
959 ast_free(tls_cfg->pvtfile);
960 tls_cfg->pvtfile = ast_strdup(value);
961 } else if (!strcasecmp(varname, "tlscipher") || !strcasecmp(varname, "sslcipher")) {
962 ast_free(tls_cfg->cipher);
963 tls_cfg->cipher = ast_strdup(value);
964 } else if (!strcasecmp(varname, "tlscafile")) {
965 ast_free(tls_cfg->cafile);
966 tls_cfg->cafile = ast_strdup(value);
967 } else if (!strcasecmp(varname, "tlscapath") || !strcasecmp(varname, "tlscadir")) {
968 ast_free(tls_cfg->capath);
969 tls_cfg->capath = ast_strdup(value);
970 } else if (!strcasecmp(varname, "tlsverifyclient")) {
972 } else if (!strcasecmp(varname, "tlsdontverifyserver")) {
974 } else if (!strcasecmp(varname, "tlsbindaddr") || !strcasecmp(varname, "sslbindaddr")) {
976 ast_log(LOG_ERROR, "Invalid %s '%s'\n", varname, value);
977 } else if (!strcasecmp(varname, "tlsclientmethod") || !strcasecmp(varname, "sslclientmethod")) {
978 if (!strcasecmp(value, "tlsv1")) {
982 } else if (!strcasecmp(value, "sslv3")) {
986 } else if (!strcasecmp(value, "sslv2")) {
990 }
991 } else if (!strcasecmp(varname, "tlsservercipherorder")) {
993 } else if (!strcasecmp(varname, "tlsdisablev1")) {
995 } else if (!strcasecmp(varname, "tlsdisablev11")) {
997 } else if (!strcasecmp(varname, "tlsdisablev12")) {
999 } else {
1000 return -1;
1001 }
1002
1003 return 0;
1004}
int ast_parse_arg(const char *arg, enum ast_parse_flags flags, void *p_result,...)
The argument parsing routine.
Definition: main/config.c:3842
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:2199
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:94
#define ast_clear_flag(p, flag)
Definition: utils.h:77
#define ast_set_flag(p, flag)
Definition: utils.h:70

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

141{
142 struct ast_tcptls_session_instance *tcptls_session = data;
143#ifdef DO_SSL
144 SSL *ssl;
145#endif
146
147 /* TCP/TLS connections are associated with external protocols, and
148 * should not be allowed to execute 'dangerous' functions. This may
149 * need to be pushed down into the individual protocol handlers, but
150 * this seems like a good general policy.
151 */
153 ast_log(LOG_ERROR, "Failed to inhibit privilege escalations; killing connection from peer '%s'\n",
154 ast_sockaddr_stringify(&tcptls_session->remote_address));
155 ast_tcptls_close_session_file(tcptls_session);
156 ao2_ref(tcptls_session, -1);
157 return NULL;
158 }
159
160 /*
161 * TCP/TLS connections are associated with external protocols which can
162 * be considered to be user interfaces (even for SIP messages), and
163 * will not handle channel media. This may need to be pushed down into
164 * the individual protocol handlers, but this seems like a good start.
165 */
167 ast_log(LOG_ERROR, "Failed to set user interface status; killing connection from peer '%s'\n",
168 ast_sockaddr_stringify(&tcptls_session->remote_address));
169 ast_tcptls_close_session_file(tcptls_session);
170 ao2_ref(tcptls_session, -1);
171 return NULL;
172 }
173
174 if (tcptls_session->parent->tls_cfg) {
175#ifdef DO_SSL
176 if (ast_iostream_start_tls(&tcptls_session->stream, tcptls_session->parent->tls_cfg->ssl_ctx, tcptls_session->client) < 0) {
177 SSL *ssl = ast_iostream_get_ssl(tcptls_session->stream);
178 if (ssl) {
179 ast_log(LOG_ERROR, "Unable to set up ssl connection with peer '%s'\n",
180 ast_sockaddr_stringify(&tcptls_session->remote_address));
181 }
182 ast_tcptls_close_session_file(tcptls_session);
183 ao2_ref(tcptls_session, -1);
184 return NULL;
185 }
186
187 ssl = ast_iostream_get_ssl(tcptls_session->stream);
188 if ((tcptls_session->client && !ast_test_flag(&tcptls_session->parent->tls_cfg->flags, AST_SSL_DONT_VERIFY_SERVER))
189 || (!tcptls_session->client && ast_test_flag(&tcptls_session->parent->tls_cfg->flags, AST_SSL_VERIFY_CLIENT))) {
190 X509 *peer;
191 long res;
192 peer = SSL_get_peer_certificate(ssl);
193 if (!peer) {
194 ast_log(LOG_ERROR, "No SSL certificate to verify from peer '%s'\n",
195 ast_sockaddr_stringify(&tcptls_session->remote_address));
196 ast_tcptls_close_session_file(tcptls_session);
197 ao2_ref(tcptls_session, -1);
198 return NULL;
199 }
200
201 res = SSL_get_verify_result(ssl);
202 if (res != X509_V_OK) {
203 ast_log(LOG_ERROR, "Certificate from peer '%s' did not verify: %s\n",
204 ast_sockaddr_stringify(&tcptls_session->remote_address),
205 X509_verify_cert_error_string(res));
206 X509_free(peer);
207 ast_tcptls_close_session_file(tcptls_session);
208 ao2_ref(tcptls_session, -1);
209 return NULL;
210 }
211 if (!ast_test_flag(&tcptls_session->parent->tls_cfg->flags, AST_SSL_IGNORE_COMMON_NAME)) {
212 ASN1_STRING *str;
213 X509_NAME *name = X509_get_subject_name(peer);
214 STACK_OF(GENERAL_NAME) *alt_names;
215 int pos = -1;
216 int found = 0;
217
218 for (;;) {
219 /* Walk the certificate to check all available "Common Name" */
220 /* XXX Probably should do a gethostbyname on the hostname and compare that as well */
221 pos = X509_NAME_get_index_by_NID(name, NID_commonName, pos);
222 if (pos < 0) {
223 break;
224 }
225 str = X509_NAME_ENTRY_get_data(X509_NAME_get_entry(name, pos));
226 if (!check_tcptls_cert_name(str, tcptls_session->parent->hostname, "common name")) {
227 found = 1;
228 break;
229 }
230 }
231
232 if (!found) {
233 alt_names = X509_get_ext_d2i(peer, NID_subject_alt_name, NULL, NULL);
234 if (alt_names != NULL) {
235 int alt_names_count = sk_GENERAL_NAME_num(alt_names);
236
237 for (pos = 0; pos < alt_names_count; pos++) {
238 const GENERAL_NAME *alt_name = sk_GENERAL_NAME_value(alt_names, pos);
239
240 if (alt_name->type != GEN_DNS) {
241 continue;
242 }
243
244 if (!check_tcptls_cert_name(alt_name->d.dNSName, tcptls_session->parent->hostname, "alt name")) {
245 found = 1;
246 break;
247 }
248 }
249
250 sk_GENERAL_NAME_pop_free(alt_names, GENERAL_NAME_free);
251 }
252 }
253
254 if (!found) {
255 ast_log(LOG_ERROR, "Certificate common name from peer '%s' did not match (%s)\n",
256 ast_sockaddr_stringify(&tcptls_session->remote_address), tcptls_session->parent->hostname);
257 X509_free(peer);
258 ast_tcptls_close_session_file(tcptls_session);
259 ao2_ref(tcptls_session, -1);
260 return NULL;
261 }
262 }
263 X509_free(peer);
264 }
265#else
266 ast_log(LOG_ERROR, "TLS client failed: Asterisk is compiled without OpenSSL support. Install OpenSSL development headers and rebuild Asterisk after running ./configure\n");
267 ast_tcptls_close_session_file(tcptls_session);
268 ao2_ref(tcptls_session, -1);
269 return NULL;
270#endif /* DO_SSL */
271 }
272
273 if (tcptls_session->parent->worker_fn) {
274 return tcptls_session->parent->worker_fn(tcptls_session);
275 } else {
276 return tcptls_session;
277 }
278}
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:109
int ast_iostream_start_tls(struct ast_iostream **stream, SSL_CTX *ctx, int client)
Begin TLS on an iostream.
Definition: iostream.c:627
struct ssl_st SSL
Definition: iostream.h:37
int ast_thread_inhibit_escalations(void)
Inhibit (in the current thread) the execution of dialplan functions which cause privilege escalations...
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:915
@ AST_SSL_IGNORE_COMMON_NAME
Definition: tcptls.h:71
int ast_thread_user_interface_set(int is_user_interface)
Set the current thread's user interface status.
Definition: utils.c:3233

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_thread_inhibit_escalations(), ast_thread_user_interface_set(), ast_tcptls_session_instance::client, 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, ast_tcptls_session_args::tls_cfg, 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 601 of file tcptls.c.

602{
603 int optval = 0;
604 socklen_t optlen = sizeof(int);
605
606 errno = 0;
607
608 if (ast_connect(sockfd, addr)) {
609 int res;
610
611 /*
612 * A connect failure could mean things are still in progress.
613 * If so wait for it to complete.
614 */
615
616 if (errno != EINPROGRESS) {
617 return -1;
618 }
619
620 while ((res = ast_wait_for_output(sockfd, timeout)) != 1) {
621 if (res == 0) {
622 errno = ETIMEDOUT;
623 return -1;
624 }
625
626 if (errno != EINTR) {
627 return -1;
628 }
629 }
630 }
631
632 /* Check the status to ensure it actually connected successfully */
633 if (getsockopt(sockfd, SOL_SOCKET, SO_ERROR, &optval, &optlen) < 0) {
634 return -1;
635 }
636
637 if (optval) {
638 errno = optval;
639 return -1;
640 }
641
642 return 0;
643}
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:1708

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

Referenced by ast_tcptls_client_start_timeout().