Sat Apr 26 2014 22:03:19

Asterisk developer's documentation


tcptls.h File Reference

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

#include "asterisk/netsock2.h"
#include "asterisk/utils.h"
#include <openssl/ssl.h>
#include <openssl/err.h>
Include dependency graph for tcptls.h:
This graph shows which files directly or indirectly include this file:

Go to the source code of this file.

Data Structures

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

Defines

#define AST_CERTFILE   "asterisk.pem"
#define DO_SSL   /* comment in/out if you want to support ssl */
#define HOOK_T   ssize_t
#define LEN_T   size_t

Enumerations

enum  ast_ssl_flags {
  AST_SSL_VERIFY_CLIENT = (1 << 0), AST_SSL_DONT_VERIFY_SERVER = (1 << 1), AST_SSL_IGNORE_COMMON_NAME = (1 << 2), AST_SSL_SSLV2_CLIENT = (1 << 3),
  AST_SSL_SSLV3_CLIENT = (1 << 4), AST_SSL_TLSV1_CLIENT = (1 << 5)
}

Functions

int ast_ssl_setup (struct ast_tls_config *cfg)
 Set up an SSL server.
void ast_ssl_teardown (struct ast_tls_config *cfg)
 free resources used by an SSL server
struct
ast_tcptls_session_instance
ast_tcptls_client_create (struct ast_tcptls_session_args *desc)
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.
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.
HOOK_T ast_tcptls_server_read (struct ast_tcptls_session_instance *ser, void *buf, size_t count)
void * ast_tcptls_server_root (void *)
void ast_tcptls_server_start (struct ast_tcptls_session_args *desc)
 This is a generic (re)start routine for a TCP server, which does the socket/bind/listen and starts a thread for handling accept().
void ast_tcptls_server_stop (struct ast_tcptls_session_args *desc)
 Shutdown a running server if there is one.
HOOK_T ast_tcptls_server_write (struct ast_tcptls_session_instance *ser, const void *buf, size_t count)
int ast_tls_read_conf (struct ast_tls_config *tls_cfg, struct ast_tcptls_session_args *tls_desc, const char *varname, const char *value)
 Used to parse conf files containing tls/ssl options.

Detailed Description

Generic support for tcp/tls servers in Asterisk.

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

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

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

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

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

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

TLS Implementation Overview

Todo:
For SIP, the SubjectAltNames should be checked on verification of the certificate. (Check RFC 5922)

Definition in file tcptls.h.


Define Documentation

#define AST_CERTFILE   "asterisk.pem"

SSL support

Definition at line 75 of file tcptls.h.

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

#define DO_SSL   /* comment in/out if you want to support ssl */

Definition at line 62 of file tcptls.h.

#define HOOK_T   ssize_t

Definition at line 170 of file tcptls.h.

#define LEN_T   size_t

Definition at line 171 of file tcptls.h.


Enumeration Type Documentation

Enumerator:
AST_SSL_VERIFY_CLIENT 

Verify certificate when acting as server

AST_SSL_DONT_VERIFY_SERVER 

Don't verify certificate when connecting to a server

AST_SSL_IGNORE_COMMON_NAME 

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

AST_SSL_SSLV2_CLIENT 

Use SSLv2 for outgoing client connections

AST_SSL_SSLV3_CLIENT 

Use SSLv3 for outgoing client connections

AST_SSL_TLSV1_CLIENT 

Use TLSv1 for outgoing client connections

Definition at line 77 of file tcptls.h.

                   {
   /*! Verify certificate when acting as server */
   AST_SSL_VERIFY_CLIENT = (1 << 0),
   /*! Don't verify certificate when connecting to a server */
   AST_SSL_DONT_VERIFY_SERVER = (1 << 1),
   /*! Don't compare "Common Name" against IP or hostname */
   AST_SSL_IGNORE_COMMON_NAME = (1 << 2),
   /*! Use SSLv2 for outgoing client connections */
   AST_SSL_SSLV2_CLIENT = (1 << 3),
   /*! Use SSLv3 for outgoing client connections */
   AST_SSL_SSLV3_CLIENT = (1 << 4),
   /*! Use TLSv1 for outgoing client connections */
   AST_SSL_TLSV1_CLIENT = (1 << 5)
};

Function Documentation

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

References __ssl_setup().

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

{
   return __ssl_setup(cfg, 0);
}
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 444 of file tcptls.c.

References ast_tls_config::ssl_ctx.

Referenced by sip_tcptls_client_args_destructor(), and unload_module().

{
#ifdef DO_SSL
   if (cfg->ssl_ctx) {
      SSL_CTX_free(cfg->ssl_ctx);
      cfg->ssl_ctx = NULL;
   }
#endif
}

Definition at line 491 of file tcptls.c.

References ast_tcptls_session_args::accept_fd, ao2_alloc, ao2_ref, ast_bind(), ast_debug, ast_log(), ast_sockaddr_cmp(), ast_sockaddr_copy(), ast_sockaddr_is_ipv6(), ast_sockaddr_isnull(), ast_sockaddr_setnull(), ast_sockaddr_stringify(), ast_str_create(), ast_tcptls_session_instance::client, desc, errno, ast_tcptls_session_instance::fd, ast_tcptls_session_args::local_address, LOG_ERROR, LOG_WARNING, ast_tcptls_session_args::name, 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(), and ast_tcptls_session_args::worker_fn.

Referenced by app_exec(), and sip_prepare_socket().

{
   int x = 1;
   struct ast_tcptls_session_instance *tcptls_session = NULL;

   /* Do nothing if nothing has changed */
   if (!ast_sockaddr_cmp(&desc->old_address, &desc->remote_address)) {
      ast_debug(1, "Nothing changed in %s\n", desc->name);
      return NULL;
   }

   /* If we return early, there is no connection */
   ast_sockaddr_setnull(&desc->old_address);

   if (desc->accept_fd != -1) {
      close(desc->accept_fd);
   }

   desc->accept_fd = socket(ast_sockaddr_is_ipv6(&desc->remote_address) ?
             AF_INET6 : AF_INET, SOCK_STREAM, IPPROTO_TCP);
   if (desc->accept_fd < 0) {
      ast_log(LOG_WARNING, "Unable to allocate socket for %s: %s\n",
         desc->name, strerror(errno));
      return NULL;
   }

   /* if a local address was specified, bind to it so the connection will
      originate from the desired address */
   if (!ast_sockaddr_isnull(&desc->local_address)) {
      setsockopt(desc->accept_fd, SOL_SOCKET, SO_REUSEADDR, &x, sizeof(x));
      if (ast_bind(desc->accept_fd, &desc->local_address)) {
         ast_log(LOG_ERROR, "Unable to bind %s to %s: %s\n",
            desc->name,
            ast_sockaddr_stringify(&desc->local_address),
            strerror(errno));
         goto error;
      }
   }

   if (!(tcptls_session = ao2_alloc(sizeof(*tcptls_session), session_instance_destructor))) {
      goto error;
   }

   tcptls_session->overflow_buf = ast_str_create(128);
   tcptls_session->client = 1;
   tcptls_session->fd = desc->accept_fd;
   tcptls_session->parent = desc;
   tcptls_session->parent->worker_fn = NULL;
   ast_sockaddr_copy(&tcptls_session->remote_address,
           &desc->remote_address);

   /* Set current info */
   ast_sockaddr_copy(&desc->old_address, &desc->remote_address);
   return tcptls_session;

error:
   close(desc->accept_fd);
   desc->accept_fd = -1;
   if (tcptls_session) {
      ao2_ref(tcptls_session, -1);
   }
   return NULL;
}

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

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

Referenced by _sip_tcp_helper_thread(), and app_exec().

{
   struct ast_tcptls_session_args *desc;
   int flags;

   if (!(desc = tcptls_session->parent)) {
      goto client_start_error;
   }

   if (ast_connect(desc->accept_fd, &desc->remote_address)) {
      ast_log(LOG_ERROR, "Unable to connect %s to %s: %s\n",
         desc->name,
         ast_sockaddr_stringify(&desc->remote_address),
         strerror(errno));
      goto client_start_error;
   }

   flags = fcntl(desc->accept_fd, F_GETFL);
   fcntl(desc->accept_fd, F_SETFL, flags & ~O_NONBLOCK);

   if (desc->tls_cfg) {
      desc->tls_cfg->enabled = 1;
      __ssl_setup(desc->tls_cfg, 1);
   }

   return handle_tcptls_connection(tcptls_session);

client_start_error:
   if (desc) {
      close(desc->accept_fd);
      desc->accept_fd = -1;
   }
   ao2_ref(tcptls_session, -1);
   return NULL;

}

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

References ast_log(), errno, ast_tcptls_session_instance::f, ast_tcptls_session_instance::fd, and LOG_ERROR.

Referenced by _sip_tcp_helper_thread(), ast_http_send(), ast_tcptls_server_root(), handle_tcptls_connection(), and sip_prepare_socket().

{
   if (tcptls_session->f) {
      /*
       * Issuing shutdown() is necessary here to avoid a race
       * condition where the last data written may not appear
       * in the TCP stream.  See ASTERISK-23548
      */
      fflush(tcptls_session->f);
      if (tcptls_session->fd != -1) {
         shutdown(tcptls_session->fd, SHUT_RDWR);
      }
      if (fclose(tcptls_session->f)) {
         ast_log(LOG_ERROR, "fclose() failed: %s\n", strerror(errno));
      }
      tcptls_session->f = NULL;
      tcptls_session->fd = -1;
   } else if (tcptls_session->fd != -1) {
      shutdown(tcptls_session->fd, SHUT_RDWR);
      if (close(tcptls_session->fd)) {
         ast_log(LOG_ERROR, "close() failed: %s\n", strerror(errno));
      }
      tcptls_session->fd = -1;
   } else {
      ast_log(LOG_ERROR, "ast_tcptls_close_session_file invoked on session instance without file or file descriptor\n");
   }
}
HOOK_T ast_tcptls_server_read ( struct ast_tcptls_session_instance ser,
void *  buf,
size_t  count 
)

Definition at line 114 of file tcptls.c.

References ast_log(), errno, ast_tcptls_session_instance::fd, LOG_ERROR, ast_tcptls_session_instance::ssl, and ssl_read().

{
   if (tcptls_session->fd == -1) {
      ast_log(LOG_ERROR, "server_read called with an fd of -1\n");
      errno = EIO;
      return -1;
   }

#ifdef DO_SSL
   if (tcptls_session->ssl) {
      return ssl_read(tcptls_session->ssl, buf, count);
   }
#endif
   return read(tcptls_session->fd, buf, count);
}
void* ast_tcptls_server_root ( void *  )

Definition at line 291 of file tcptls.c.

References ast_tcptls_session_args::accept_fd, ao2_alloc, ao2_ref, ast_accept(), ast_log(), ast_pthread_create_detached_background, ast_sockaddr_copy(), ast_str_create(), ast_tcptls_close_session_file(), ast_wait_for_input(), ast_tcptls_session_instance::client, desc, errno, ast_tcptls_session_instance::fd, handle_tcptls_connection(), LOG_ERROR, LOG_WARNING, 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, and session_instance_destructor().

{
   struct ast_tcptls_session_args *desc = data;
   int fd;
   struct ast_sockaddr addr;
   struct ast_tcptls_session_instance *tcptls_session;
   pthread_t launched;

   for (;;) {
      int i, flags;

      if (desc->periodic_fn) {
         desc->periodic_fn(desc);
      }
      i = ast_wait_for_input(desc->accept_fd, desc->poll_timeout);
      if (i <= 0) {
         continue;
      }
      fd = ast_accept(desc->accept_fd, &addr);
      if (fd < 0) {
         if ((errno != EAGAIN) && (errno != EINTR)) {
            ast_log(LOG_WARNING, "Accept failed: %s\n", strerror(errno));
         }
         continue;
      }
      tcptls_session = ao2_alloc(sizeof(*tcptls_session), session_instance_destructor);
      if (!tcptls_session) {
         ast_log(LOG_WARNING, "No memory for new session: %s\n", strerror(errno));
         if (close(fd)) {
            ast_log(LOG_ERROR, "close() failed: %s\n", strerror(errno));
         }
         continue;
      }

      tcptls_session->overflow_buf = ast_str_create(128);
      flags = fcntl(fd, F_GETFL);
      fcntl(fd, F_SETFL, flags & ~O_NONBLOCK);
      tcptls_session->fd = fd;
      tcptls_session->parent = desc;
      ast_sockaddr_copy(&tcptls_session->remote_address, &addr);

      tcptls_session->client = 0;

      /* This thread is now the only place that controls the single ref to tcptls_session */
      if (ast_pthread_create_detached_background(&launched, NULL, handle_tcptls_connection, tcptls_session)) {
         ast_log(LOG_WARNING, "Unable to launch helper thread: %s\n", strerror(errno));
         ast_tcptls_close_session_file(tcptls_session);
         ao2_ref(tcptls_session, -1);
      }
   }
   return NULL;
}

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

References ast_tcptls_session_args::accept_fd, ast_tcptls_session_args::accept_fn, ast_bind(), ast_debug, ast_log(), ast_pthread_create_background, AST_PTHREADT_NULL, ast_sockaddr_cmp(), ast_sockaddr_copy(), ast_sockaddr_is_ipv6(), ast_sockaddr_isnull(), ast_sockaddr_setnull(), ast_sockaddr_stringify(), errno, ast_tcptls_session_args::local_address, LOG_ERROR, ast_tcptls_session_args::master, ast_tcptls_session_args::name, and ast_tcptls_session_args::old_address.

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

{
   int flags;
   int x = 1;

   /* Do nothing if nothing has changed */
   if (!ast_sockaddr_cmp(&desc->old_address, &desc->local_address)) {
      ast_debug(1, "Nothing changed in %s\n", desc->name);
      return;
   }

   /* If we return early, there is no one listening */
   ast_sockaddr_setnull(&desc->old_address);

   /* Shutdown a running server if there is one */
   if (desc->master != AST_PTHREADT_NULL) {
      pthread_cancel(desc->master);
      pthread_kill(desc->master, SIGURG);
      pthread_join(desc->master, NULL);
   }

   if (desc->accept_fd != -1) {
      close(desc->accept_fd);
   }

   /* If there's no new server, stop here */
   if (ast_sockaddr_isnull(&desc->local_address)) {
      ast_debug(2, "Server disabled:  %s\n", desc->name);
      return;
   }

   desc->accept_fd = socket(ast_sockaddr_is_ipv6(&desc->local_address) ?
             AF_INET6 : AF_INET, SOCK_STREAM, 0);
   if (desc->accept_fd < 0) {
      ast_log(LOG_ERROR, "Unable to allocate socket for %s: %s\n", desc->name, strerror(errno));
      return;
   }

   setsockopt(desc->accept_fd, SOL_SOCKET, SO_REUSEADDR, &x, sizeof(x));
   if (ast_bind(desc->accept_fd, &desc->local_address)) {
      ast_log(LOG_ERROR, "Unable to bind %s to %s: %s\n",
         desc->name,
         ast_sockaddr_stringify(&desc->local_address),
         strerror(errno));
      goto error;
   }
   if (listen(desc->accept_fd, 10)) {
      ast_log(LOG_ERROR, "Unable to listen for %s!\n", desc->name);
      goto error;
   }
   flags = fcntl(desc->accept_fd, F_GETFL);
   fcntl(desc->accept_fd, F_SETFL, flags | O_NONBLOCK);
   if (ast_pthread_create_background(&desc->master, NULL, desc->accept_fn, desc)) {
      ast_log(LOG_ERROR, "Unable to launch thread for %s on %s: %s\n",
         desc->name,
         ast_sockaddr_stringify(&desc->local_address),
         strerror(errno));
      goto error;
   }

   /* Set current info */
   ast_sockaddr_copy(&desc->old_address, &desc->local_address);

   return;

error:
   close(desc->accept_fd);
   desc->accept_fd = -1;
}

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

References ast_tcptls_session_args::accept_fd, ast_debug, AST_PTHREADT_NULL, ast_tcptls_session_args::master, and ast_tcptls_session_args::name.

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

{
   if (desc->master != AST_PTHREADT_NULL) {
      pthread_cancel(desc->master);
      pthread_kill(desc->master, SIGURG);
      pthread_join(desc->master, NULL);
      desc->master = AST_PTHREADT_NULL;
   }
   if (desc->accept_fd != -1) {
      close(desc->accept_fd);
   }
   desc->accept_fd = -1;
   ast_debug(2, "Stopped server :: %s\n", desc->name);
}
HOOK_T ast_tcptls_server_write ( struct ast_tcptls_session_instance ser,
const void *  buf,
size_t  count 
)

Definition at line 130 of file tcptls.c.

References ast_log(), errno, ast_tcptls_session_instance::fd, LOG_ERROR, ast_tcptls_session_instance::ssl, and ssl_write().

Referenced by _sip_tcp_helper_thread().

{
   if (tcptls_session->fd == -1) {
      ast_log(LOG_ERROR, "server_write called with an fd of -1\n");
      errno = EIO;
      return -1;
   }

#ifdef DO_SSL
   if (tcptls_session->ssl) {
      return ssl_write(tcptls_session->ssl, buf, count);
   }
#endif
   return write(tcptls_session->fd, buf, count);
}
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 668 of file tcptls.c.

References ast_clear_flag, ast_free, ast_log(), ast_parse_arg(), ast_set2_flag, ast_set_flag, AST_SSL_DONT_VERIFY_SERVER, 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_WARNING, PARSE_ADDR, and ast_tls_config::pvtfile.

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

{
   if (!strcasecmp(varname, "tlsenable") || !strcasecmp(varname, "sslenable")) {
      tls_cfg->enabled = ast_true(value) ? 1 : 0;
   } else if (!strcasecmp(varname, "tlscertfile") || !strcasecmp(varname, "sslcert") || !strcasecmp(varname, "tlscert")) {
      ast_free(tls_cfg->certfile);
      tls_cfg->certfile = ast_strdup(value);
   } else if (!strcasecmp(varname, "tlsprivatekey") || !strcasecmp(varname, "sslprivatekey")) {
      ast_free(tls_cfg->pvtfile);
      tls_cfg->pvtfile = ast_strdup(value);
   } else if (!strcasecmp(varname, "tlscipher") || !strcasecmp(varname, "sslcipher")) {
      ast_free(tls_cfg->cipher);
      tls_cfg->cipher = ast_strdup(value);
   } else if (!strcasecmp(varname, "tlscafile")) {
      ast_free(tls_cfg->cafile);
      tls_cfg->cafile = ast_strdup(value);
   } else if (!strcasecmp(varname, "tlscapath") || !strcasecmp(varname, "tlscadir")) {
      ast_free(tls_cfg->capath);
      tls_cfg->capath = ast_strdup(value);
   } else if (!strcasecmp(varname, "tlsverifyclient")) {
      ast_set2_flag(&tls_cfg->flags, ast_true(value), AST_SSL_VERIFY_CLIENT);
   } else if (!strcasecmp(varname, "tlsdontverifyserver")) {
      ast_set2_flag(&tls_cfg->flags, ast_true(value), AST_SSL_DONT_VERIFY_SERVER);
   } else if (!strcasecmp(varname, "tlsbindaddr") || !strcasecmp(varname, "sslbindaddr")) {
      if (ast_parse_arg(value, PARSE_ADDR, &tls_desc->local_address))
         ast_log(LOG_WARNING, "Invalid %s '%s'\n", varname, value);
   } else if (!strcasecmp(varname, "tlsclientmethod") || !strcasecmp(varname, "sslclientmethod")) {
      if (!strcasecmp(value, "tlsv1")) {
         ast_set_flag(&tls_cfg->flags, AST_SSL_TLSV1_CLIENT);
         ast_clear_flag(&tls_cfg->flags, AST_SSL_SSLV3_CLIENT);
         ast_clear_flag(&tls_cfg->flags, AST_SSL_SSLV2_CLIENT);
      } else if (!strcasecmp(value, "sslv3")) {
         ast_set_flag(&tls_cfg->flags, AST_SSL_SSLV3_CLIENT);
         ast_clear_flag(&tls_cfg->flags, AST_SSL_SSLV2_CLIENT);
         ast_clear_flag(&tls_cfg->flags, AST_SSL_TLSV1_CLIENT);
      } else if (!strcasecmp(value, "sslv2")) {
         ast_set_flag(&tls_cfg->flags, AST_SSL_SSLV2_CLIENT);
         ast_clear_flag(&tls_cfg->flags, AST_SSL_TLSV1_CLIENT);
         ast_clear_flag(&tls_cfg->flags, AST_SSL_SSLV3_CLIENT);
      }
   } else {
      return -1;
   }

   return 0;
}