41 #include <sys/signal.h>
95 stream->
start.tv_sec = 0;
103 stream->
start = start;
129 struct timeval start;
138 if (!stream || stream->
fd == -1) {
143 if (stream->
start.tv_sec) {
144 start = stream->
start;
152 res = SSL_read(stream->
ssl, buf, size);
157 switch (SSL_get_error(stream->
ssl, res)) {
158 case SSL_ERROR_ZERO_RETURN:
160 ast_debug(1,
"TLS clean shutdown alert reading data\n");
162 case SSL_ERROR_WANT_READ:
179 ast_debug(1,
"TLS socket error waiting for read data: %s\n",
185 case SSL_ERROR_WANT_WRITE:
197 ast_debug(1,
"TLS socket error waiting for write space: %s\n",
205 ast_debug(1,
"TLS transport or SSL error reading data\n");
210 ast_debug(1,
"TLS timeout reading data\n");
218 res = read(stream->
fd, buf, size);
225 ast_debug(1,
"TCP socket error reading data: %s\n",
232 ast_debug(1,
"TCP timeout reading data\n");
253 struct timeval start;
264 if (!stream || stream->
fd == -1) {
269 if (stream->
start.tv_sec) {
270 start = stream->
start;
280 res = SSL_write(stream->
ssl, buf + written, remaining);
281 if (res == remaining) {
291 switch (SSL_get_error(stream->
ssl, res)) {
292 case SSL_ERROR_ZERO_RETURN:
293 ast_debug(1,
"TLS clean shutdown alert writing data\n");
300 case SSL_ERROR_WANT_READ:
304 ast_debug(1,
"TLS timeout writing data (want read)\n");
309 case SSL_ERROR_WANT_WRITE:
313 ast_debug(1,
"TLS timeout writing data (want write)\n");
320 ast_debug(1,
"TLS transport or SSL error writing data\n");
335 res = write(stream->
fd, buf + written, remaining);
336 if (res == remaining) {
357 ast_debug(1,
"TCP timeout writing data\n");
382 if (stream->
fd != -1) {
395 res = SSL_shutdown(stream->
ssl);
398 SSL_get_error(stream->
ssl, res));
401 if (!stream->
ssl->server) {
406 SSL_free(stream->
ssl);
416 shutdown(stream->
fd, SHUT_RDWR);
417 if (close(stream->
fd)) {
422 ao2_t_ref(stream, -1,
"Closed tcptls stream cookie");
482 #if defined(HAVE_FOPENCOOKIE)
483 static const cookie_io_functions_t cookie_funcs = {
499 ao2_t_ref(stream, +1,
"Opening tcptls stream cookie");
501 #if defined(HAVE_FUNOPEN)
504 #elif defined(HAVE_FOPENCOOKIE)
505 fp = fopencookie(stream,
"w+", cookie_funcs);
508 ast_debug(2,
"No stream FILE methods attempted!\n");
514 ao2_t_ref(stream, -1,
"Failed to open tcptls stream cookie");
564 int (*ssl_setup)(SSL *) = (tcptls_session->
client) ? SSL_connect : SSL_accept;
575 ast_log(
LOG_ERROR,
"Failed to inhibit privilege escalations; killing connection\n");
593 tcptls_session->
fd, -1);
594 if (tcptls_session->
f) {
595 if (setvbuf(tcptls_session->
f, NULL, _IONBF, 0)) {
602 SSL_set_fd(tcptls_session->
ssl, tcptls_session->
fd);
603 if ((ret = ssl_setup(tcptls_session->
ssl)) <= 0) {
604 ast_verb(2,
"Problem setting up ssl connection: %s\n", ERR_error_string(ERR_get_error(), err));
606 tcptls_session->
ssl, tcptls_session->
fd, -1))) {
611 peer = SSL_get_peer_certificate(tcptls_session->
ssl);
619 res = SSL_get_verify_result(tcptls_session->
ssl);
620 if (res != X509_V_OK) {
621 ast_log(
LOG_ERROR,
"Certificate did not verify: %s\n", X509_verify_cert_error_string(res));
630 X509_NAME *
name = X509_get_subject_name(peer);
637 pos = X509_NAME_get_index_by_NID(name, NID_commonName, pos);
640 str = X509_NAME_ENTRY_get_data(X509_NAME_get_entry(name, pos));
641 ret = ASN1_STRING_to_UTF8(&str2, str);
647 if (strlen((
char *) str2) != ret) {
648 ast_log(
LOG_WARNING,
"Invalid certificate common name length (contains NULL bytes?)\n");
649 }
else if (!strcasecmp(tcptls_session->
parent->
hostname, (
char *) str2)) {
669 if (!tcptls_session->
f)
670 SSL_free(tcptls_session->
ssl);
674 if (!tcptls_session->
f) {
679 ast_log(
LOG_WARNING,
"Attempted a TLS connection without OpenSSL support. This will not work!\n");
689 return tcptls_session;
716 if (!tcptls_session) {
727 flags = fcntl(fd, F_GETFL);
728 fcntl(fd, F_SETFL, flags & ~O_NONBLOCK);
729 tcptls_session->
fd =
fd;
733 tcptls_session->
client = 0;
765 #ifndef OPENSSL_NO_SSL2
767 ast_log(
LOG_WARNING,
"Usage of SSLv2 is discouraged due to known vulnerabilities. Please use 'tlsv1' or leave the TLS method unspecified!\n");
768 cfg->
ssl_ctx = SSL_CTX_new(SSLv2_client_method());
772 ast_log(
LOG_WARNING,
"Usage of SSLv3 is discouraged due to known vulnerabilities. Please use 'tlsv1' or leave the TLS method unspecified!\n");
773 cfg->
ssl_ctx = SSL_CTX_new(SSLv3_client_method());
775 cfg->
ssl_ctx = SSL_CTX_new(TLSv1_client_method());
778 cfg->
ssl_ctx = SSL_CTX_new(SSLv23_client_method());
782 cfg->
ssl_ctx = SSL_CTX_new(SSLv23_server_method());
786 ast_debug(1,
"Sorry, SSL_CTX_new call returned null...\n");
798 ssl_opts = SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3;
799 SSL_CTX_set_options(cfg->
ssl_ctx, ssl_opts);
802 SSL_CTX_set_verify(cfg->
ssl_ctx,
808 if (SSL_CTX_use_certificate_chain_file(cfg->
ssl_ctx, cfg->
certfile) == 0) {
818 if ((SSL_CTX_use_PrivateKey_file(cfg->
ssl_ctx, tmpprivate, SSL_FILETYPE_PEM) == 0) || (SSL_CTX_check_private_key(cfg->
ssl_ctx) == 0 )) {
821 ast_verb(0,
"SSL error loading private key file. <%s>", tmpprivate);
830 if (SSL_CTX_set_cipher_list(cfg->
ssl_ctx, cfg->
cipher) == 0 ) {
845 ast_verb(0,
"SSL certificate ok\n");
870 if (!(desc = tcptls_session->
parent)) {
871 goto client_start_error;
879 goto client_start_error;
883 fcntl(desc->
accept_fd, F_SETFL, flags & ~O_NONBLOCK);
920 AF_INET6 : AF_INET, SOCK_STREAM, IPPROTO_TCP);
930 setsockopt(desc->
accept_fd, SOL_SOCKET, SO_REUSEADDR, &x,
sizeof(x));
945 tcptls_session->
client = 1;
954 return tcptls_session;
980 pthread_cancel(desc->
master);
981 pthread_kill(desc->
master, SIGURG);
982 pthread_join(desc->
master, NULL);
995 AF_INET6 : AF_INET, SOCK_STREAM, 0);
1001 setsockopt(desc->
accept_fd, SOL_SOCKET, SO_REUSEADDR, &x,
sizeof(x));
1013 flags = fcntl(desc->
accept_fd, F_GETFL);
1014 fcntl(desc->
accept_fd, F_SETFL, flags | O_NONBLOCK);
1035 if (tcptls_session->
f) {
1036 fflush(tcptls_session->
f);
1037 if (fclose(tcptls_session->
f)) {
1040 tcptls_session->
f = NULL;
1041 tcptls_session->
fd = -1;
1042 }
else if (tcptls_session->
fd != -1) {
1048 shutdown(tcptls_session->
fd, SHUT_RDWR);
1049 if (close(tcptls_session->
fd)) {
1052 tcptls_session->
fd = -1;
1054 ast_log(
LOG_ERROR,
"ast_tcptls_close_session_file invoked on session instance without file or file descriptor\n");
1061 pthread_cancel(desc->
master);
1062 pthread_kill(desc->
master, SIGURG);
1063 pthread_join(desc->
master, NULL);
1074 if (!strcasecmp(varname,
"tlsenable") || !strcasecmp(varname,
"sslenable")) {
1076 }
else if (!strcasecmp(varname,
"tlscertfile") || !strcasecmp(varname,
"sslcert") || !strcasecmp(varname,
"tlscert")) {
1079 }
else if (!strcasecmp(varname,
"tlsprivatekey") || !strcasecmp(varname,
"sslprivatekey")) {
1082 }
else if (!strcasecmp(varname,
"tlscipher") || !strcasecmp(varname,
"sslcipher")) {
1085 }
else if (!strcasecmp(varname,
"tlscafile")) {
1088 }
else if (!strcasecmp(varname,
"tlscapath") || !strcasecmp(varname,
"tlscadir")) {
1091 }
else if (!strcasecmp(varname,
"tlsverifyclient")) {
1093 }
else if (!strcasecmp(varname,
"tlsdontverifyserver")) {
1095 }
else if (!strcasecmp(varname,
"tlsbindaddr") || !strcasecmp(varname,
"sslbindaddr")) {
1098 }
else if (!strcasecmp(varname,
"tlsclientmethod") || !strcasecmp(varname,
"sslclientmethod")) {
1099 if (!strcasecmp(value,
"tlsv1")) {
1103 }
else if (!strcasecmp(value,
"sslv3")) {
1107 }
else if (!strcasecmp(value,
"sslv2")) {
#define ao2_t_ref(o, delta, tag)
Reference/unreference an object and return the old refcount.
static HOOK_T tcptls_stream_read(void *cookie, char *buf, LEN_T size)
Asterisk main include file. File version handling, generic pbx functions.
static void tcptls_stream_dtor(void *cookie)
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 ...
String manipulation functions.
void ast_ssl_teardown(struct ast_tls_config *cfg)
free resources used by an SSL server
int ast_ssl_setup(struct ast_tls_config *cfg)
Set up an SSL server.
struct timeval start
Start time from when an I/O sequence must complete by struct ast_tcptls_stream.timeout.
#define ast_set2_flag(p, value, flag)
#define ast_test_flag(p, flag)
static void ast_sockaddr_copy(struct ast_sockaddr *dst, const struct ast_sockaddr *src)
Copies the data from one ast_sockaddr to another.
struct ast_str * overflow_buf
#define ast_set_flag(p, flag)
struct ast_tcptls_session_args * parent
static void * handle_tcptls_connection(void *data)
creates a FILE * from the fd passed by the accept thread. This operation is potentially expensive (ce...
struct timeval ast_tvnow(void)
Returns current timeval. Meant to replace calls to gettimeofday().
struct ast_str * ast_str_create(size_t init_len)
Create a malloc'ed dynamic length string.
arguments for the accepting thread
int ast_sockaddr_cmp(const struct ast_sockaddr *a, const struct ast_sockaddr *b)
Compares two ast_sockaddr structures.
Generic support for tcp/tls servers in Asterisk.
static FILE * tcptls_stream_fopen(struct ast_tcptls_stream *stream, SSL *ssl, int fd, int timeout)
int timeout
Timeout in ms relative to struct ast_tcptls_stream.start to wait for an event on struct ast_tcptls_st...
Socket address structure.
int ast_bind(int sockfd, const struct ast_sockaddr *addr)
Wrapper around bind(2) that uses struct ast_sockaddr.
#define ast_pthread_create_detached_background(a, b, c, d)
#define ast_verb(level,...)
static void ast_sockaddr_setnull(struct ast_sockaddr *addr)
Sets address addr to null.
#define ast_pthread_create_background(a, b, c, d)
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.
Support for Private Asterisk HTTP Servers.
#define ast_debug(level,...)
Log a DEBUG message.
void * ast_tcptls_server_root(void *)
int ast_accept(int sockfd, struct ast_sockaddr *addr)
Wrapper around accept(2) that uses struct ast_sockaddr.
int ast_parse_arg(const char *arg, enum ast_parse_flags flags, void *result,...)
The argument parsing routine.
#define AST_PTHREADT_NULL
static force_inline int attribute_pure ast_strlen_zero(const char *s)
struct ast_sockaddr remote_address
#define ao2_ref(o, delta)
static int __ssl_setup(struct ast_tls_config *cfg, int client)
void ast_tcptls_stream_set_exclusive_input(struct ast_tcptls_stream *stream, int exclusive_input)
Set the TCP/TLS stream I/O if it can exclusively depend upon the set timeouts.
struct ast_tcptls_stream * stream_cookie
Core PBX routines and definitions.
The AMI - Asterisk Manager Interface - is a TCP protocol created to manage Asterisk with third-party ...
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".
int ast_remaining_ms(struct timeval start, int max_ms)
Calculate remaining milliseconds given a starting timestamp and upper bound.
General Definitions for Asterisk top level program Included by asterisk.h to handle platform-specific...
static char * ast_sockaddr_stringify(const struct ast_sockaddr *addr)
Wrapper around ast_sockaddr_stringify_fmt() with default format.
HOOK_T ast_tcptls_server_read(struct ast_tcptls_session_instance *ser, void *buf, size_t count)
void ast_log(int level, const char *file, int line, const char *function, const char *fmt,...)
Used for sending a log message This is the standard logger function. Probably the only way you will i...
void *(* worker_fn)(void *)
#define ao2_alloc(data_size, destructor_fn)
static void session_instance_destructor(void *obj)
void ast_tcptls_stream_set_timeout_inactivity(struct ast_tcptls_stream *stream, int timeout)
Set the TCP/TLS stream inactivity timeout timer.
static struct ast_tcptls_stream * tcptls_stream_alloc(void)
struct ast_sockaddr old_address
#define ast_clear_flag(p, flag)
int fd
The socket returned by accept().
int ast_wait_for_output(int fd, int ms)
HOOK_T ast_tcptls_server_write(struct ast_tcptls_session_instance *ser, const void *buf, size_t count)
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...
#define S_OR(a, b)
returns the equivalent of logic or for strings: first one if not empty, otherwise second one...
static int tcptls_stream_close(void *cookie)
struct ast_tcptls_session_instance * ast_tcptls_client_create(struct ast_tcptls_session_args *desc)
int ast_thread_inhibit_escalations(void)
Inhibit (in the current thread) the execution of dialplan functions which cause privilege escalations...
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.
Options provided by main asterisk program.
void ast_tcptls_stream_set_timeout_sequence(struct ast_tcptls_stream *stream, struct timeval start, int timeout)
Set the TCP/TLS stream I/O sequence timeout timer.
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...
int ast_wait_for_input(int fd, int ms)
void ast_tcptls_server_stop(struct ast_tcptls_session_args *desc)
Shutdown a running server if there is one.
struct ast_tls_config * tls_cfg
#define ast_mutex_init(pmutex)
struct ast_sockaddr local_address
void(* periodic_fn)(void *)
#define ast_mutex_destroy(a)
void ast_tcptls_stream_set_timeout_disable(struct ast_tcptls_stream *stream)
Disable the TCP/TLS stream timeout timer.
int ast_sockaddr_is_ipv6(const struct ast_sockaddr *addr)
Determine if this is an IPv6 address.
int ast_connect(int sockfd, const struct ast_sockaddr *addr)
Wrapper around connect(2) that uses struct ast_sockaddr.
char hostname[MAXHOSTNAMELEN]
#define ASTERISK_FILE_VERSION(file, version)
Register/unregister a source code file with the core.
static HOOK_T tcptls_stream_write(void *cookie, const char *buf, LEN_T size)
struct ast_sockaddr remote_address
void *(* accept_fn)(void *)