Skip to content

Commit

Permalink
tcptls/iostream: Add support for setting SNI on client TLS connections
Browse files Browse the repository at this point in the history
If the hostname field of the ast_tcptls_session_args structure is
set (which it is for websocket client connections), that hostname
will now automatically be used in an SNI TLS extension in the client
hello.

Resolves: asterisk#713

UserNote: Secure websocket client connections now send SNI in
the TLS client hello.
  • Loading branch information
gtjoseph authored and asterisk-org-access-app[bot] committed Apr 29, 2024
1 parent 758ed2b commit 8e119a7
Show file tree
Hide file tree
Showing 3 changed files with 39 additions and 5 deletions.
11 changes: 11 additions & 0 deletions include/asterisk/iostream.h
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,17 @@ void ast_iostream_set_timeout_sequence(struct ast_iostream *stream, struct timev
*/
void ast_iostream_set_exclusive_input(struct ast_iostream *stream, int exclusive_input);

/*!
* \brief Set the iostream's SNI hostname for TLS client connections
*
* \param stream A pointer to an iostream
* \param sni_hostname The hostname to use for SNI when in client mode
*
* \retval 0 if the hostname was set successfully.
* \retval -1 if memory could not be allocated for the hostname.
*/
int ast_iostream_set_sni_hostname(struct ast_iostream *stream, const char *sni_hostname);

/*!
* \brief Get an iostream's file descriptor.
*
Expand Down
26 changes: 21 additions & 5 deletions main/iostream.c
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ struct ast_iostream {
int rbuflen;
char *rbufhead;
char rbuf[2048];
char *sni_hostname;
};

#if defined(DO_SSL)
Expand Down Expand Up @@ -152,6 +153,16 @@ void ast_iostream_set_exclusive_input(struct ast_iostream *stream, int exclusive
stream->exclusive_input = exclusive_input;
}

int ast_iostream_set_sni_hostname(struct ast_iostream *stream, const char *sni_hostname)
{
ast_assert(stream != NULL);

ast_free(stream->sni_hostname);
stream->sni_hostname = ast_strdup(sni_hostname);

return stream->sni_hostname ? 0 : -1;
}

static ssize_t iostream_read(struct ast_iostream *stream, void *buf, size_t size)
{
struct timeval start;
Expand Down Expand Up @@ -591,13 +602,9 @@ int ast_iostream_close(struct ast_iostream *stream)

static void iostream_dtor(void *cookie)
{
#ifdef AST_DEVMODE
/* Since the ast_assert below is the only one using stream,
* and ast_assert is only available with AST_DEVMODE, we
* put this in a conditional to avoid compiler warnings. */
struct ast_iostream *stream = cookie;
#endif

ast_free(stream->sni_hostname);
ast_assert(stream->fd == -1);
}

Expand Down Expand Up @@ -639,6 +646,15 @@ int ast_iostream_start_tls(struct ast_iostream **pstream, SSL_CTX *ssl_ctx, int
*/
SSL_set_fd(stream->ssl, stream->fd);

if (client && !ast_strlen_zero(stream->sni_hostname)) {
if (!SSL_set_tlsext_host_name(stream->ssl, stream->sni_hostname)) {
ast_log(LOG_ERROR, "Unable to set SNI hostname '%s'\n",
stream->sni_hostname);
errno = EIO;
return -1;
}
}

res = ssl_setup(stream->ssl);
if (res <= 0) {
int sslerr = SSL_get_error(stream->ssl, res);
Expand Down
7 changes: 7 additions & 0 deletions main/tcptls.c
Original file line number Diff line number Diff line change
Expand Up @@ -741,6 +741,13 @@ struct ast_tcptls_session_instance *ast_tcptls_client_create(struct ast_tcptls_s
/* Set current info */
ast_sockaddr_copy(&desc->old_address, &desc->remote_address);

if (!ast_strlen_zero(desc->hostname)) {
if (ast_iostream_set_sni_hostname(tcptls_session->stream, desc->hostname) != 0) {
ast_log(LOG_WARNING, "Unable to set SNI hostname '%s' on connection '%s'\n",
desc->hostname, desc->name);
}
}

return tcptls_session;

error:
Expand Down

0 comments on commit 8e119a7

Please sign in to comment.