Asterisk - The Open Source Telephony Project GIT-master-8f1982c
All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Macros Modules Pages
Functions
tcptls.c File Reference

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

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

Go to the source code of this file.

Functions

static int __ssl_setup (struct ast_tls_config *cfg, int client, int suppress_progress_msgs)
 
int ast_ssl_setup (struct ast_tls_config *cfg)
 Set up an SSL server. 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,
int  suppress_progress_msgs 
)
static

Definition at line 382 of file tcptls.c.

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

578{
579 return __ssl_setup(cfg, 0, 0);
580}
static int __ssl_setup(struct ast_tls_config *cfg, int client, int suppress_progress_msgs)
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 582 of file tcptls.c.

583{
584#ifdef DO_SSL
585 if (cfg && cfg->ssl_ctx) {
586 SSL_CTX_free(cfg->ssl_ctx);
587 cfg->ssl_ctx = NULL;
588 }
589#endif
590}

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

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

682{
683 return ast_tcptls_client_start_timeout(tcptls_session, -1);
684}
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:652

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

654{
656
657 if (!(desc = tcptls_session->parent)) {
658 ao2_ref(tcptls_session, -1);
659 return NULL;
660 }
661
662 if (socket_connect(desc->accept_fd, &desc->remote_address, timeout)) {
663 if (!desc->suppress_connection_msgs) {
664 ast_log(LOG_WARNING, "Unable to connect %s to %s: %s\n", desc->name,
665 ast_sockaddr_stringify(&desc->remote_address), strerror(errno));
666 }
667
668 ao2_ref(tcptls_session, -1);
669 return NULL;
670 }
671
672 ast_fd_clear_flags(desc->accept_fd, O_NONBLOCK);
673
674 if (desc->tls_cfg) {
675 __ssl_setup(desc->tls_cfg, 1, desc->suppress_connection_msgs);
676 }
677
678 return handle_tcptls_connection(tcptls_session);
679}
#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:608
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 923 of file tcptls.c.

924{
925 if (tcptls_session->stream) {
926 ast_iostream_close(tcptls_session->stream);
927 tcptls_session->stream = NULL;
928 } else {
929 ast_debug(1, "ast_tcptls_close_session_file invoked on session instance without file or file descriptor\n");
930 }
931}
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 768 of file tcptls.c.

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

934{
935 if (desc->master != AST_PTHREADT_NULL) {
936 pthread_cancel(desc->master);
937 pthread_kill(desc->master, SIGURG);
938 pthread_join(desc->master, NULL);
939 desc->master = AST_PTHREADT_NULL;
940 }
941 if (desc->accept_fd != -1) {
942 close(desc->accept_fd);
943 }
944 desc->accept_fd = -1;
945
946 if (desc->old_tls_cfg) {
947 ast_free(desc->old_tls_cfg->certfile);
948 ast_free(desc->old_tls_cfg->pvtfile);
949 ast_free(desc->old_tls_cfg->cipher);
950 ast_free(desc->old_tls_cfg->cafile);
951 ast_free(desc->old_tls_cfg->capath);
952 ast_free(desc->old_tls_cfg);
953 desc->old_tls_cfg = NULL;
954 }
955
956 ast_debug(2, "Stopped server :: %s\n", desc->name);
957}

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

960{
961 if (!strcasecmp(varname, "tlsenable") || !strcasecmp(varname, "sslenable")) {
962 tls_cfg->enabled = ast_true(value) ? 1 : 0;
963 } else if (!strcasecmp(varname, "tlscertfile") || !strcasecmp(varname, "sslcert") || !strcasecmp(varname, "tlscert")) {
964 ast_free(tls_cfg->certfile);
965 tls_cfg->certfile = ast_strdup(value);
966 } else if (!strcasecmp(varname, "tlsprivatekey") || !strcasecmp(varname, "sslprivatekey")) {
967 ast_free(tls_cfg->pvtfile);
968 tls_cfg->pvtfile = ast_strdup(value);
969 } else if (!strcasecmp(varname, "tlscipher") || !strcasecmp(varname, "sslcipher")) {
970 ast_free(tls_cfg->cipher);
971 tls_cfg->cipher = ast_strdup(value);
972 } else if (!strcasecmp(varname, "tlscafile")) {
973 ast_free(tls_cfg->cafile);
974 tls_cfg->cafile = ast_strdup(value);
975 } else if (!strcasecmp(varname, "tlscapath") || !strcasecmp(varname, "tlscadir")) {
976 ast_free(tls_cfg->capath);
977 tls_cfg->capath = ast_strdup(value);
978 } else if (!strcasecmp(varname, "tlsverifyclient")) {
980 } else if (!strcasecmp(varname, "tlsdontverifyserver")) {
982 } else if (!strcasecmp(varname, "tlsbindaddr") || !strcasecmp(varname, "sslbindaddr")) {
984 ast_log(LOG_ERROR, "Invalid %s '%s'\n", varname, value);
985 } else if (!strcasecmp(varname, "tlsclientmethod") || !strcasecmp(varname, "sslclientmethod")) {
986 if (!strcasecmp(value, "tlsv1")) {
990 } else if (!strcasecmp(value, "sslv3")) {
994 } else if (!strcasecmp(value, "sslv2")) {
998 }
999 } else if (!strcasecmp(varname, "tlsservercipherorder")) {
1001 } else if (!strcasecmp(varname, "tlsdisablev1")) {
1003 } else if (!strcasecmp(varname, "tlsdisablev11")) {
1005 } else if (!strcasecmp(varname, "tlsdisablev12")) {
1007 } else {
1008 return -1;
1009 }
1010
1011 return 0;
1012}
int ast_parse_arg(const char *arg, enum ast_parse_flags flags, void *p_result,...)
The argument parsing routine.
Definition: main/config.c:4047
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:923
@ 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 608 of file tcptls.c.

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