Asterisk - The Open Source Telephony Project  18.5.0
Macros | 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 <openssl/asn1.h>
#include <openssl/crypto.h>
#include <openssl/err.h>
#include <openssl/opensslconf.h>
#include <openssl/opensslv.h>
#include <openssl/safestack.h>
#include <openssl/ssl.h>
#include <openssl/x509.h>
#include <openssl/x509v3.h>
#include <openssl/bio.h>
#include <openssl/dh.h>
#include <openssl/pem.h>
#include <openssl/ec.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.

Macros

#define SSL_CTRL_SET_ECDH_AUTO   94
 

Functions

static int __ssl_setup (struct ast_tls_config *cfg, int client)
 
static void __ssl_setup_certs (struct ast_tls_config *cfg, const size_t cert_file_len, const char *key_type_extension, const char *key_type)
 
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)
 
struct ast_tcptls_session_instanceast_tcptls_client_start (struct ast_tcptls_session_instance *tcptls_session)
 attempts to connect and start tcptls session, on error the tcptls_session's ref count is decremented, fd and file are closed, and NULL is returned. 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 int check_tcptls_cert_name (ASN1_STRING *cert_str, const char *hostname, const char *desc)
 
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 void write_openssl_error_to_log (void)
 

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.

Macro Definition Documentation

◆ SSL_CTRL_SET_ECDH_AUTO

#define SSL_CTRL_SET_ECDH_AUTO   94

Referenced by __ssl_setup().

Function Documentation

◆ __ssl_setup()

static int __ssl_setup ( struct ast_tls_config cfg,
int  client 
)
static

Definition at line 382 of file tcptls.c.

References __ssl_setup_certs(), 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_tls_config::enabled, ast_tls_config::flags, LOG_ERROR, LOG_WARNING, NULL, options, ast_tls_config::pvtfile, S_OR, SSL_CTRL_SET_ECDH_AUTO, ast_tls_config::ssl_ctx, and write_openssl_error_to_log().

Referenced by ast_ssl_setup(), and ast_tcptls_client_start().

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);
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);
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);
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);
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 }
char * pvtfile
Definition: tcptls.h:90
#define ast_test_flag(p, flag)
Definition: utils.h:63
#define LOG_WARNING
Definition: logger.h:274
#define SSL_CTRL_SET_ECDH_AUTO
#define NULL
Definition: resample.c:96
#define ast_verb(level,...)
Definition: logger.h:463
#define ast_strlen_zero(foo)
Definition: strings.h:52
#define ast_debug(level,...)
Log a DEBUG message.
Definition: logger.h:452
#define ast_log
Definition: astobj2.c:42
static void write_openssl_error_to_log(void)
Definition: tcptls.c:111
#define LOG_ERROR
Definition: logger.h:285
char * cafile
Definition: tcptls.h:92
char * certfile
Definition: tcptls.h:89
#define S_OR(a, b)
returns the equivalent of logic or for strings: first one if not empty, otherwise second one...
Definition: strings.h:79
struct ast_flags flags
Definition: tcptls.h:94
SSL_CTX * ssl_ctx
Definition: tcptls.h:95
char * capath
Definition: tcptls.h:93
static struct test_options options
char * cipher
Definition: tcptls.h:91
static void __ssl_setup_certs(struct ast_tls_config *cfg, const size_t cert_file_len, const char *key_type_extension, const char *key_type)
Definition: tcptls.c:362
int enabled
Definition: tcptls.h:88

◆ __ssl_setup_certs()

static void __ssl_setup_certs ( struct ast_tls_config cfg,
const size_t  cert_file_len,
const char *  key_type_extension,
const char *  key_type 
)
static

Definition at line 362 of file tcptls.c.

References ast_log, ast_strdupa, ast_tls_config::certfile, LOG_WARNING, ast_tls_config::ssl_ctx, and write_openssl_error_to_log().

Referenced by __ssl_setup().

363 {
364  char *cert_file = ast_strdupa(cfg->certfile);
365 
366  memcpy(cert_file + cert_file_len - 8, key_type_extension, 5);
367  if (access(cert_file, F_OK) == 0) {
368  if (SSL_CTX_use_certificate_chain_file(cfg->ssl_ctx, cert_file) == 0) {
369  ast_log(LOG_WARNING, "TLS/SSL error loading public %s key (certificate) from <%s>.\n", key_type, cert_file);
371  } else if (SSL_CTX_use_PrivateKey_file(cfg->ssl_ctx, cert_file, SSL_FILETYPE_PEM) == 0) {
372  ast_log(LOG_WARNING, "TLS/SSL error loading private %s key from <%s>.\n", key_type, cert_file);
374  } else if (SSL_CTX_check_private_key(cfg->ssl_ctx) == 0) {
375  ast_log(LOG_WARNING, "TLS/SSL error matching private %s key and certificate in <%s>.\n", key_type, cert_file);
377  }
378  }
379 }
#define LOG_WARNING
Definition: logger.h:274
#define ast_log
Definition: astobj2.c:42
static void write_openssl_error_to_log(void)
Definition: tcptls.c:111
#define ast_strdupa(s)
duplicate a string in memory from the stack
Definition: astmm.h:300
char * certfile
Definition: tcptls.h:89
SSL_CTX * ssl_ctx
Definition: tcptls.h:95

◆ 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.

References __ssl_setup().

Referenced by __ast_http_load(), __init_manager(), and reload_config().

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

◆ 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.

References NULL, and ast_tls_config::ssl_ctx.

Referenced by sip_tcptls_client_args_destructor(), unload_module(), and websocket_client_args_destroy().

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

◆ ast_tcptls_client_create()

struct ast_tcptls_session_instance* ast_tcptls_client_create ( struct ast_tcptls_session_args desc)

Definition at line 615 of file tcptls.c.

References ast_tcptls_session_args::accept_fd, ao2_alloc, ao2_cleanup, ast_bind(), ast_debug, ast_iostream_from_fd(), 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_str_create, ast_tcptls_session_instance::client, desc, errno, error(), ast_tcptls_session_args::local_address, LOG_ERROR, ast_tcptls_session_args::name, NULL, ast_tcptls_session_args::old_address, ast_tcptls_session_instance::overflow_buf, ast_tcptls_session_instance::parent, ast_tcptls_session_args::remote_address, 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(), sip_prepare_socket(), and websocket_client_connect().

616 {
617  int fd, x = 1;
618  struct ast_tcptls_session_instance *tcptls_session = NULL;
619 
620  /* Do nothing if nothing has changed */
621  if (!ast_sockaddr_cmp(&desc->old_address, &desc->remote_address)) {
622  ast_debug(1, "Nothing changed in %s\n", desc->name);
623  return NULL;
624  }
625 
626  /* If we return early, there is no connection */
628 
629  fd = desc->accept_fd = socket(ast_sockaddr_is_ipv6(&desc->remote_address) ?
630  AF_INET6 : AF_INET, SOCK_STREAM, IPPROTO_TCP);
631  if (desc->accept_fd < 0) {
632  ast_log(LOG_ERROR, "Unable to allocate socket for %s: %s\n",
633  desc->name, strerror(errno));
634  return NULL;
635  }
636 
637  /* if a local address was specified, bind to it so the connection will
638  originate from the desired address */
639  if (!ast_sockaddr_isnull(&desc->local_address) &&
641  setsockopt(desc->accept_fd, SOL_SOCKET, SO_REUSEADDR, &x, sizeof(x));
642  if (ast_bind(desc->accept_fd, &desc->local_address)) {
643  ast_log(LOG_ERROR, "Unable to bind %s to %s: %s\n",
644  desc->name,
646  strerror(errno));
647  goto error;
648  }
649  }
650 
651  tcptls_session = ao2_alloc(sizeof(*tcptls_session), session_instance_destructor);
652  if (!tcptls_session) {
653  goto error;
654  }
655 
656  tcptls_session->overflow_buf = ast_str_create(128);
657  if (!tcptls_session->overflow_buf) {
658  goto error;
659  }
660  tcptls_session->client = 1;
661  tcptls_session->stream = ast_iostream_from_fd(&fd);
662  if (!tcptls_session->stream) {
663  goto error;
664  }
665 
666  /* From here on out, the iostream owns the accept_fd and it will take
667  * care of closing it when the iostream is closed */
668 
669  tcptls_session->parent = desc;
670  tcptls_session->parent->worker_fn = NULL;
671  ast_sockaddr_copy(&tcptls_session->remote_address,
672  &desc->remote_address);
673 
674  /* Set current info */
676  return tcptls_session;
677 
678 error:
679  close(desc->accept_fd);
680  desc->accept_fd = -1;
681  ao2_cleanup(tcptls_session);
682  return NULL;
683 }
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:171
struct ast_str * overflow_buf
Definition: tcptls.h:158
struct ast_tcptls_session_args * parent
Definition: tcptls.h:152
static const char desc[]
Definition: cdr_mysql.c:73
struct ast_iostream * ast_iostream_from_fd(int *fd)
Create an iostream from a file descriptor.
Definition: iostream.c:604
#define NULL
Definition: resample.c:96
int ast_sockaddr_cmp(const struct ast_sockaddr *a, const struct ast_sockaddr *b)
Compares two ast_sockaddr structures.
Definition: netsock2.c:388
int ast_bind(int sockfd, const struct ast_sockaddr *addr)
Wrapper around bind(2) that uses struct ast_sockaddr.
Definition: netsock2.c:590
static void ast_sockaddr_setnull(struct ast_sockaddr *addr)
Sets address addr to null.
Definition: netsock2.h:140
static int ast_sockaddr_isnull(const struct ast_sockaddr *addr)
Checks if the ast_sockaddr is null. "null" in this sense essentially means uninitialized, or having a 0 length.
Definition: netsock2.h:127
#define ast_debug(level,...)
Log a DEBUG message.
Definition: logger.h:452
#define ast_log
Definition: astobj2.c:42
int ast_sockaddr_is_any(const struct ast_sockaddr *addr)
Determine if the address type is unspecified, or "any" address.
Definition: netsock2.c:534
struct ast_sockaddr remote_address
Definition: tcptls.h:132
describes a server instance
Definition: tcptls.h:149
#define LOG_ERROR
Definition: logger.h:285
int errno
static char * ast_sockaddr_stringify(const struct ast_sockaddr *addr)
Wrapper around ast_sockaddr_stringify_fmt() with default format.
Definition: netsock2.h:260
#define ao2_alloc(data_size, destructor_fn)
Definition: astobj2.h:411
static void session_instance_destructor(void *obj)
Definition: tcptls.c:72
void *(* worker_fn)(void *)
Definition: tcptls.h:141
struct ast_sockaddr old_address
Definition: tcptls.h:131
const char * name
Definition: tcptls.h:142
struct ast_iostream * stream
Definition: tcptls.h:160
#define ao2_cleanup(obj)
Definition: astobj2.h:1958
int error(const char *format,...)
Definition: utils/frame.c:999
struct ast_sockaddr local_address
Definition: tcptls.h:130
int ast_sockaddr_is_ipv6(const struct ast_sockaddr *addr)
Determine if this is an IPv6 address.
Definition: netsock2.c:524
#define ast_str_create(init_len)
Create a malloc&#39;ed dynamic length string.
Definition: strings.h:620
struct ast_sockaddr remote_address
Definition: tcptls.h:151

◆ ast_tcptls_client_start()

struct ast_tcptls_session_instance* ast_tcptls_client_start ( struct ast_tcptls_session_instance tcptls_session)

attempts to connect and start tcptls session, on error the tcptls_session's ref count is decremented, fd and file are closed, and NULL is returned.

Definition at line 585 of file tcptls.c.

References __ssl_setup(), ast_tcptls_session_args::accept_fd, ao2_ref, ast_connect(), ast_fd_clear_flags, ast_log, ast_sockaddr_stringify(), desc, ast_tls_config::enabled, errno, handle_tcptls_connection(), LOG_ERROR, ast_tcptls_session_args::name, NULL, ast_tcptls_session_instance::parent, ast_tcptls_session_args::remote_address, and ast_tcptls_session_args::tls_cfg.

Referenced by _sip_tcp_helper_thread(), app_exec(), and websocket_client_connect().

586 {
588 
589  if (!(desc = tcptls_session->parent)) {
590  goto client_start_error;
591  }
592 
593  if (ast_connect(desc->accept_fd, &desc->remote_address)) {
594  ast_log(LOG_ERROR, "Unable to connect %s to %s: %s\n",
595  desc->name,
597  strerror(errno));
598  goto client_start_error;
599  }
600 
601  ast_fd_clear_flags(desc->accept_fd, O_NONBLOCK);
602 
603  if (desc->tls_cfg) {
604  desc->tls_cfg->enabled = 1;
605  __ssl_setup(desc->tls_cfg, 1);
606  }
607 
608  return handle_tcptls_connection(tcptls_session);
609 
610 client_start_error:
611  ao2_ref(tcptls_session, -1);
612  return NULL;
613 }
struct ast_tcptls_session_args * parent
Definition: tcptls.h:152
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
static const char desc[]
Definition: cdr_mysql.c:73
arguments for the accepting thread
Definition: tcptls.h:129
#define NULL
Definition: resample.c:96
#define ast_log
Definition: astobj2.c:42
struct ast_sockaddr remote_address
Definition: tcptls.h:132
#define ao2_ref(o, delta)
Definition: astobj2.h:464
static int __ssl_setup(struct ast_tls_config *cfg, int client)
Definition: tcptls.c:382
#define LOG_ERROR
Definition: logger.h:285
int errno
static char * ast_sockaddr_stringify(const struct ast_sockaddr *addr)
Wrapper around ast_sockaddr_stringify_fmt() with default format.
Definition: netsock2.h:260
#define ast_fd_clear_flags(fd, flags)
Clear flags on the given file descriptor.
Definition: utils.h:1025
const char * name
Definition: tcptls.h:142
struct ast_tls_config * tls_cfg
Definition: tcptls.h:134
int ast_connect(int sockfd, const struct ast_sockaddr *addr)
Wrapper around connect(2) that uses struct ast_sockaddr.
Definition: netsock2.c:595
int enabled
Definition: tcptls.h:88

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

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

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

840 {
841  if (tcptls_session->stream) {
842  ast_iostream_close(tcptls_session->stream);
843  tcptls_session->stream = NULL;
844  } else {
845  ast_debug(1, "ast_tcptls_close_session_file invoked on session instance without file or file descriptor\n");
846  }
847 }
#define NULL
Definition: resample.c:96
#define ast_debug(level,...)
Log a DEBUG message.
Definition: logger.h:452
int ast_iostream_close(struct ast_iostream *stream)
Close an iostream.
Definition: iostream.c:528
struct ast_iostream * stream
Definition: tcptls.h:160

◆ ast_tcptls_server_root()

void* ast_tcptls_server_root ( void *  data)

Definition at line 280 of file tcptls.c.

References ast_tcptls_session_args::accept_fd, 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_args::periodic_fn, ast_tcptls_session_args::poll_timeout, ast_tcptls_session_instance::remote_address, session_instance_destructor(), and ast_tcptls_session_instance::stream.

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 */
342  if (ast_pthread_create_detached_background(&launched, NULL, handle_tcptls_connection, 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 }
void(* periodic_fn)(void *)
Definition: tcptls.h:140
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:171
struct ast_str * overflow_buf
Definition: tcptls.h:158
struct ast_tcptls_session_args * parent
Definition: tcptls.h:152
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
static const char desc[]
Definition: cdr_mysql.c:73
struct ast_iostream * ast_iostream_from_fd(int *fd)
Create an iostream from a file descriptor.
Definition: iostream.c:604
arguments for the accepting thread
Definition: tcptls.h:129
#define NULL
Definition: resample.c:96
Socket address structure.
Definition: netsock2.h:97
#define ast_pthread_create_detached_background(a, b, c, d)
Definition: utils.h:572
#define ast_log
Definition: astobj2.c:42
int ast_accept(int sockfd, struct ast_sockaddr *addr)
Wrapper around accept(2) that uses struct ast_sockaddr.
Definition: netsock2.c:584
#define ao2_ref(o, delta)
Definition: astobj2.h:464
describes a server instance
Definition: tcptls.h:149
#define LOG_ERROR
Definition: logger.h:285
int errno
static char * ast_sockaddr_stringify(const struct ast_sockaddr *addr)
Wrapper around ast_sockaddr_stringify_fmt() with default format.
Definition: netsock2.h:260
#define ao2_alloc(data_size, destructor_fn)
Definition: astobj2.h:411
static void session_instance_destructor(void *obj)
Definition: tcptls.c:72
#define ast_fd_clear_flags(fd, flags)
Clear flags on the given file descriptor.
Definition: utils.h:1025
struct ast_iostream * stream
Definition: tcptls.h:160
int ast_wait_for_input(int fd, int ms)
Definition: main/utils.c:1519
#define ast_str_create(init_len)
Create a malloc&#39;ed dynamic length string.
Definition: strings.h:620
struct ast_sockaddr remote_address
Definition: tcptls.h:151

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

References ast_tcptls_session_args::accept_fd, ast_tcptls_session_args::accept_fn, 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, ast_tls_config::cafile, ast_tls_config::cahash, ast_tls_config::capath, ast_tls_config::certfile, ast_tls_config::certhash, ast_tls_config::cipher, errno, error(), ast_tls_config::flags, ast_tcptls_session_args::local_address, LOG_ERROR, ast_tcptls_session_args::master, ast_tcptls_session_args::name, NULL, ast_tcptls_session_args::old_address, ast_tcptls_session_args::old_tls_cfg, ast_tls_config::pvtfile, ast_tls_config::pvthash, str, and ast_tcptls_session_args::tls_cfg.

Referenced by __ast_http_load(), __init_manager(), and reload_config().

686 {
687  int x = 1;
688  int tls_changed = 0;
689  int sd_socket;
690 
691  if (desc->tls_cfg) {
692  char hash[41];
693  char *str = NULL;
694  struct stat st;
695 
696  /* Store the hashes of the TLS certificate etc. */
697  if (stat(desc->tls_cfg->certfile, &st) || NULL == (str = ast_read_textfile(desc->tls_cfg->certfile))) {
698  memset(hash, 0, 41);
699  } else {
700  ast_sha1_hash(hash, str);
701  }
702  ast_free(str);
703  str = NULL;
704  memcpy(desc->tls_cfg->certhash, hash, 41);
705  if (stat(desc->tls_cfg->pvtfile, &st) || NULL == (str = ast_read_textfile(desc->tls_cfg->pvtfile))) {
706  memset(hash, 0, 41);
707  } else {
708  ast_sha1_hash(hash, str);
709  }
710  ast_free(str);
711  str = NULL;
712  memcpy(desc->tls_cfg->pvthash, hash, 41);
713  if (stat(desc->tls_cfg->cafile, &st) || NULL == (str = ast_read_textfile(desc->tls_cfg->cafile))) {
714  memset(hash, 0, 41);
715  } else {
716  ast_sha1_hash(hash, str);
717  }
718  ast_free(str);
719  str = NULL;
720  memcpy(desc->tls_cfg->cahash, hash, 41);
721 
722  /* Check whether TLS configuration has changed */
723  if (!desc->old_tls_cfg) { /* No previous configuration */
724  tls_changed = 1;
725  desc->old_tls_cfg = ast_calloc(1, sizeof(*desc->old_tls_cfg));
726  } else if (memcmp(desc->tls_cfg->certhash, desc->old_tls_cfg->certhash, 41)) {
727  tls_changed = 1;
728  } else if (memcmp(desc->tls_cfg->pvthash, desc->old_tls_cfg->pvthash, 41)) {
729  tls_changed = 1;
730  } else if (strcmp(desc->tls_cfg->cipher, desc->old_tls_cfg->cipher)) {
731  tls_changed = 1;
732  } else if (memcmp(desc->tls_cfg->cahash, desc->old_tls_cfg->cahash, 41)) {
733  tls_changed = 1;
734  } else if (strcmp(desc->tls_cfg->capath, desc->old_tls_cfg->capath)) {
735  tls_changed = 1;
736  } else if (memcmp(&desc->tls_cfg->flags, &desc->old_tls_cfg->flags, sizeof(desc->tls_cfg->flags))) {
737  tls_changed = 1;
738  }
739 
740  if (tls_changed) {
741  ast_debug(1, "Changed parameters for %s found\n", desc->name);
742  }
743  }
744 
745  /* Do nothing if nothing has changed */
746  if (!tls_changed && !ast_sockaddr_cmp(&desc->old_address, &desc->local_address)) {
747  ast_debug(1, "Nothing changed in %s\n", desc->name);
748  return;
749  }
750 
751  /* If we return early, there is no one listening */
753 
754  /* Shutdown a running server if there is one */
755  if (desc->master != AST_PTHREADT_NULL) {
756  pthread_cancel(desc->master);
757  pthread_kill(desc->master, SIGURG);
758  pthread_join(desc->master, NULL);
759  }
760 
761  sd_socket = ast_sd_get_fd(SOCK_STREAM, &desc->local_address);
762 
763  if (sd_socket != -1) {
764  if (desc->accept_fd != sd_socket) {
765  if (desc->accept_fd != -1) {
766  close(desc->accept_fd);
767  }
768  desc->accept_fd = sd_socket;
769  }
770 
771  goto systemd_socket_activation;
772  }
773 
774  if (desc->accept_fd != -1) {
775  close(desc->accept_fd);
776  }
777 
778  /* If there's no new server, stop here */
779  if (ast_sockaddr_isnull(&desc->local_address)) {
780  ast_debug(2, "Server disabled: %s\n", desc->name);
781  return;
782  }
783 
785  AF_INET6 : AF_INET, SOCK_STREAM, 0);
786  if (desc->accept_fd < 0) {
787  ast_log(LOG_ERROR, "Unable to allocate socket for %s: %s\n", desc->name, strerror(errno));
788  return;
789  }
790 
791  setsockopt(desc->accept_fd, SOL_SOCKET, SO_REUSEADDR, &x, sizeof(x));
792  if (ast_bind(desc->accept_fd, &desc->local_address)) {
793  ast_log(LOG_ERROR, "Unable to bind %s to %s: %s\n",
794  desc->name,
796  strerror(errno));
797  goto error;
798  }
799  if (listen(desc->accept_fd, 10)) {
800  ast_log(LOG_ERROR, "Unable to listen for %s!\n", desc->name);
801  goto error;
802  }
803 
804 systemd_socket_activation:
805  if (ast_pthread_create_background(&desc->master, NULL, desc->accept_fn, desc)) {
806  ast_log(LOG_ERROR, "Unable to launch thread for %s on %s: %s\n",
807  desc->name,
809  strerror(errno));
810  goto error;
811  }
812 
813  /* Set current info */
815  if (desc->old_tls_cfg) {
816  ast_free(desc->old_tls_cfg->certfile);
817  ast_free(desc->old_tls_cfg->pvtfile);
818  ast_free(desc->old_tls_cfg->cipher);
819  ast_free(desc->old_tls_cfg->cafile);
820  ast_free(desc->old_tls_cfg->capath);
822  desc->old_tls_cfg->pvtfile = ast_strdup(desc->tls_cfg->pvtfile);
823  desc->old_tls_cfg->cipher = ast_strdup(desc->tls_cfg->cipher);
824  desc->old_tls_cfg->cafile = ast_strdup(desc->tls_cfg->cafile);
825  desc->old_tls_cfg->capath = ast_strdup(desc->tls_cfg->capath);
826  memcpy(desc->old_tls_cfg->certhash, desc->tls_cfg->certhash, 41);
827  memcpy(desc->old_tls_cfg->pvthash, desc->tls_cfg->pvthash, 41);
828  memcpy(desc->old_tls_cfg->cahash, desc->tls_cfg->cahash, 41);
829  memcpy(&desc->old_tls_cfg->flags, &desc->tls_cfg->flags, sizeof(desc->old_tls_cfg->flags));
830  }
831 
832  return;
833 
834 error:
835  close(desc->accept_fd);
836  desc->accept_fd = -1;
837 }
char * pvtfile
Definition: tcptls.h:90
char pvthash[41]
Definition: tcptls.h:97
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:171
#define ast_socket_nonblock(domain, type, protocol)
Create a non-blocking socket.
Definition: utils.h:1043
char certhash[41]
Definition: tcptls.h:96
#define ast_strdup(str)
A wrapper for strdup()
Definition: astmm.h:243
const char * str
Definition: app_jack.c:147
#define NULL
Definition: resample.c:96
int ast_sockaddr_cmp(const struct ast_sockaddr *a, const struct ast_sockaddr *b)
Compares two ast_sockaddr structures.
Definition: netsock2.c:388
int ast_bind(int sockfd, const struct ast_sockaddr *addr)
Wrapper around bind(2) that uses struct ast_sockaddr.
Definition: netsock2.c:590
char * ast_read_textfile(const char *file)
Read a file into asterisk.
Definition: main/app.c:2792
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
static void ast_sockaddr_setnull(struct ast_sockaddr *addr)
Sets address addr to null.
Definition: netsock2.h:140
#define ast_pthread_create_background(a, b, c, d)
Definition: utils.h:567
static int ast_sockaddr_isnull(const struct ast_sockaddr *addr)
Checks if the ast_sockaddr is null. "null" in this sense essentially means uninitialized, or having a 0 length.
Definition: netsock2.h:127
#define ast_debug(level,...)
Log a DEBUG message.
Definition: logger.h:452
#define ast_log
Definition: astobj2.c:42
#define AST_PTHREADT_NULL
Definition: lock.h:66
void ast_sha1_hash(char *output, const char *input)
Produces SHA1 hash based on input string.
Definition: main/utils.c:264
#define LOG_ERROR
Definition: logger.h:285
int errno
static char * ast_sockaddr_stringify(const struct ast_sockaddr *addr)
Wrapper around ast_sockaddr_stringify_fmt() with default format.
Definition: netsock2.h:260
char * cafile
Definition: tcptls.h:92
#define ast_free(a)
Definition: astmm.h:182
#define ast_calloc(num, len)
A wrapper for calloc()
Definition: astmm.h:204
struct ast_sockaddr old_address
Definition: tcptls.h:131
struct ast_tls_config * old_tls_cfg
Definition: tcptls.h:143
char * certfile
Definition: tcptls.h:89
const char * name
Definition: tcptls.h:142
char cahash[41]
Definition: tcptls.h:98
struct ast_flags flags
Definition: tcptls.h:94
int error(const char *format,...)
Definition: utils/frame.c:999
char * capath
Definition: tcptls.h:93
struct ast_tls_config * tls_cfg
Definition: tcptls.h:134
struct ast_sockaddr local_address
Definition: tcptls.h:130
char * cipher
Definition: tcptls.h:91
int ast_sockaddr_is_ipv6(const struct ast_sockaddr *addr)
Determine if this is an IPv6 address.
Definition: netsock2.c:524
void *(* accept_fn)(void *)
Definition: tcptls.h:139

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

References ast_tcptls_session_args::accept_fd, ast_debug, ast_free, AST_PTHREADT_NULL, ast_tls_config::cafile, ast_tls_config::capath, ast_tls_config::certfile, ast_tls_config::cipher, ast_tcptls_session_args::master, ast_tcptls_session_args::name, NULL, ast_tcptls_session_args::old_tls_cfg, and ast_tls_config::pvtfile.

Referenced by __ast_http_load(), __init_manager(), manager_shutdown(), and unload_module().

850 {
851  if (desc->master != AST_PTHREADT_NULL) {
852  pthread_cancel(desc->master);
853  pthread_kill(desc->master, SIGURG);
854  pthread_join(desc->master, NULL);
855  desc->master = AST_PTHREADT_NULL;
856  }
857  if (desc->accept_fd != -1) {
858  close(desc->accept_fd);
859  }
860  desc->accept_fd = -1;
861 
862  if (desc->old_tls_cfg) {
863  ast_free(desc->old_tls_cfg->certfile);
864  ast_free(desc->old_tls_cfg->pvtfile);
865  ast_free(desc->old_tls_cfg->cipher);
866  ast_free(desc->old_tls_cfg->cafile);
867  ast_free(desc->old_tls_cfg->capath);
868  ast_free(desc->old_tls_cfg);
869  desc->old_tls_cfg = NULL;
870  }
871 
872  ast_debug(2, "Stopped server :: %s\n", desc->name);
873 }
char * pvtfile
Definition: tcptls.h:90
#define NULL
Definition: resample.c:96
#define ast_debug(level,...)
Log a DEBUG message.
Definition: logger.h:452
#define AST_PTHREADT_NULL
Definition: lock.h:66
char * cafile
Definition: tcptls.h:92
#define ast_free(a)
Definition: astmm.h:182
struct ast_tls_config * old_tls_cfg
Definition: tcptls.h:143
char * certfile
Definition: tcptls.h:89
const char * name
Definition: tcptls.h:142
char * capath
Definition: tcptls.h:93
char * cipher
Definition: tcptls.h:91

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

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, and ast_tls_config::pvtfile.

Referenced by __ast_http_load(), __init_manager(), and reload_config().

876 {
877  if (!strcasecmp(varname, "tlsenable") || !strcasecmp(varname, "sslenable")) {
878  tls_cfg->enabled = ast_true(value) ? 1 : 0;
879  } else if (!strcasecmp(varname, "tlscertfile") || !strcasecmp(varname, "sslcert") || !strcasecmp(varname, "tlscert")) {
880  ast_free(tls_cfg->certfile);
881  tls_cfg->certfile = ast_strdup(value);
882  } else if (!strcasecmp(varname, "tlsprivatekey") || !strcasecmp(varname, "sslprivatekey")) {
883  ast_free(tls_cfg->pvtfile);
884  tls_cfg->pvtfile = ast_strdup(value);
885  } else if (!strcasecmp(varname, "tlscipher") || !strcasecmp(varname, "sslcipher")) {
886  ast_free(tls_cfg->cipher);
887  tls_cfg->cipher = ast_strdup(value);
888  } else if (!strcasecmp(varname, "tlscafile")) {
889  ast_free(tls_cfg->cafile);
890  tls_cfg->cafile = ast_strdup(value);
891  } else if (!strcasecmp(varname, "tlscapath") || !strcasecmp(varname, "tlscadir")) {
892  ast_free(tls_cfg->capath);
893  tls_cfg->capath = ast_strdup(value);
894  } else if (!strcasecmp(varname, "tlsverifyclient")) {
896  } else if (!strcasecmp(varname, "tlsdontverifyserver")) {
898  } else if (!strcasecmp(varname, "tlsbindaddr") || !strcasecmp(varname, "sslbindaddr")) {
899  if (ast_parse_arg(value, PARSE_ADDR, &tls_desc->local_address))
900  ast_log(LOG_ERROR, "Invalid %s '%s'\n", varname, value);
901  } else if (!strcasecmp(varname, "tlsclientmethod") || !strcasecmp(varname, "sslclientmethod")) {
902  if (!strcasecmp(value, "tlsv1")) {
906  } else if (!strcasecmp(value, "sslv3")) {
910  } else if (!strcasecmp(value, "sslv2")) {
914  }
915  } else if (!strcasecmp(varname, "tlsservercipherorder")) {
917  } else if (!strcasecmp(varname, "tlsdisablev1")) {
919  } else if (!strcasecmp(varname, "tlsdisablev11")) {
921  } else if (!strcasecmp(varname, "tlsdisablev12")) {
923  } else {
924  return -1;
925  }
926 
927  return 0;
928 }
char * pvtfile
Definition: tcptls.h:90
#define ast_set2_flag(p, value, flag)
Definition: utils.h:94
#define ast_set_flag(p, flag)
Definition: utils.h:70
#define ast_strdup(str)
A wrapper for strdup()
Definition: astmm.h:243
int value
Definition: syslog.c:37
#define ast_log
Definition: astobj2.c:42
#define LOG_ERROR
Definition: logger.h:285
int attribute_pure ast_true(const char *val)
Make sure something is true. Determine if a string containing a boolean value is "true". This function checks to see whether a string passed to it is an indication of an "true" value. It checks to see if the string is "yes", "true", "y", "t", "on" or "1".
Definition: main/utils.c:1951
char * cafile
Definition: tcptls.h:92
#define ast_free(a)
Definition: astmm.h:182
int ast_parse_arg(const char *arg, enum ast_parse_flags flags, void *result,...)
The argument parsing routine.
Definition: main/config.c:3657
char * certfile
Definition: tcptls.h:89
#define ast_clear_flag(p, flag)
Definition: utils.h:77
struct ast_flags flags
Definition: tcptls.h:94
char * capath
Definition: tcptls.h:93
struct ast_sockaddr local_address
Definition: tcptls.h:130
char * cipher
Definition: tcptls.h:91
int enabled
Definition: tcptls.h:88

◆ check_tcptls_cert_name()

static int check_tcptls_cert_name ( ASN1_STRING *  cert_str,
const char *  hostname,
const char *  desc 
)
static

Definition at line 85 of file tcptls.c.

References ast_debug, ast_log, LOG_WARNING, and str.

Referenced by handle_tcptls_connection().

86 {
87  unsigned char *str;
88  int ret;
89 
90  ret = ASN1_STRING_to_UTF8(&str, cert_str);
91  if (ret < 0 || !str) {
92  return -1;
93  }
94 
95  if (strlen((char *) str) != ret) {
96  ast_log(LOG_WARNING, "Invalid certificate %s length (contains NULL bytes?)\n", desc);
97 
98  ret = -1;
99  } else if (!strcasecmp(hostname, (char *) str)) {
100  ret = 0;
101  } else {
102  ret = -1;
103  }
104 
105  ast_debug(3, "SSL %s compare s1='%s' s2='%s'\n", desc, hostname, str);
106  OPENSSL_free(str);
107 
108  return ret;
109 }
#define LOG_WARNING
Definition: logger.h:274
static const char desc[]
Definition: cdr_mysql.c:73
const char * str
Definition: app_jack.c:147
#define ast_debug(level,...)
Log a DEBUG message.
Definition: logger.h:452
#define ast_log
Definition: astobj2.c:42
static struct ast_str * hostname
Definition: cdr_mysql.c:77

◆ 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.

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(), check_tcptls_cert_name(), 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(), and ast_tcptls_server_root().

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 }
int ast_iostream_start_tls(struct ast_iostream **stream, SSL_CTX *ctx, int client)
Begin TLS on an iostream.
Definition: iostream.c:620
#define ast_test_flag(p, flag)
Definition: utils.h:63
struct ast_tcptls_session_args * parent
Definition: tcptls.h:152
const char * str
Definition: app_jack.c:147
#define NULL
Definition: resample.c:96
struct ssl_st SSL
Definition: iostream.h:37
SSL * ast_iostream_get_ssl(struct ast_iostream *stream)
Get a pointer to an iostream&#39;s OpenSSL SSL structure.
Definition: iostream.c:108
#define ast_log
Definition: astobj2.c:42
#define ao2_ref(o, delta)
Definition: astobj2.h:464
describes a server instance
Definition: tcptls.h:149
#define LOG_ERROR
Definition: logger.h:285
static char * ast_sockaddr_stringify(const struct ast_sockaddr *addr)
Wrapper around ast_sockaddr_stringify_fmt() with default format.
Definition: netsock2.h:260
static const char name[]
Definition: cdr_mysql.c:74
void *(* worker_fn)(void *)
Definition: tcptls.h:141
struct ast_iostream * stream
Definition: tcptls.h:160
void ast_tcptls_close_session_file(struct ast_tcptls_session_instance *tcptls_session)
Closes a tcptls session instance&#39;s file and/or file descriptor. The tcptls_session will be set to NUL...
Definition: tcptls.c:839
int ast_thread_user_interface_set(int is_user_interface)
Set the current thread&#39;s user interface status.
Definition: main/utils.c:2981
int ast_thread_inhibit_escalations(void)
Inhibit (in the current thread) the execution of dialplan functions which cause privilege escalations...
static int check_tcptls_cert_name(ASN1_STRING *cert_str, const char *hostname, const char *desc)
Definition: tcptls.c:85
struct ast_flags flags
Definition: tcptls.h:94
SSL_CTX * ssl_ctx
Definition: tcptls.h:95
struct ast_tls_config * tls_cfg
Definition: tcptls.h:134
char hostname[MAXHOSTNAMELEN]
Definition: tcptls.h:133
struct ast_sockaddr remote_address
Definition: tcptls.h:151

◆ session_instance_destructor()

static void session_instance_destructor ( void *  obj)
static

Definition at line 72 of file tcptls.c.

References ao2_cleanup, ast_free, ast_iostream_close(), NULL, ast_tcptls_session_instance::overflow_buf, ast_tcptls_session_instance::private_data, and ast_tcptls_session_instance::stream.

Referenced by ast_tcptls_client_create(), and ast_tcptls_server_root().

73 {
74  struct ast_tcptls_session_instance *i = obj;
75 
76  if (i->stream) {
78  i->stream = NULL;
79  }
82 }
struct ast_str * overflow_buf
Definition: tcptls.h:158
#define NULL
Definition: resample.c:96
int ast_iostream_close(struct ast_iostream *stream)
Close an iostream.
Definition: iostream.c:528
describes a server instance
Definition: tcptls.h:149
#define ast_free(a)
Definition: astmm.h:182
struct ast_iostream * stream
Definition: tcptls.h:160
#define ao2_cleanup(obj)
Definition: astobj2.h:1958

◆ write_openssl_error_to_log()

static void write_openssl_error_to_log ( void  )
static

Definition at line 111 of file tcptls.c.

References ast_free, ast_log, and LOG_ERROR.

Referenced by __ssl_setup(), and __ssl_setup_certs().

112 {
113  FILE *fp;
114  char *buffer;
115  size_t length;
116 
117  fp = open_memstream(&buffer, &length);
118  if (!fp) {
119  return;
120  }
121 
122  ERR_print_errors_fp(fp);
123  fclose(fp);
124 
125  if (length) {
126  ast_log(LOG_ERROR, "%.*s\n", (int) length, buffer);
127  }
128 
129  ast_free(buffer);
130 }
#define ast_log
Definition: astobj2.c:42
#define LOG_ERROR
Definition: logger.h:285
#define ast_free(a)
Definition: astmm.h:182