]> git.ipfire.org Git - thirdparty/asterisk.git/commitdiff
tcptls/iostream: Add support for setting SNI on client TLS connections
authorGeorge Joseph <gjoseph@sangoma.com>
Tue, 23 Apr 2024 20:15:20 +0000 (14:15 -0600)
committerasterisk-org-access-app[bot] <120671045+asterisk-org-access-app[bot]@users.noreply.github.com>
Mon, 29 Apr 2024 13:23:40 +0000 (13:23 +0000)
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: #713

UserNote: Secure websocket client connections now send SNI in
the TLS client hello.

include/asterisk/iostream.h
main/iostream.c
main/tcptls.c

index ed09041701da035d99bd67fa830a6d59dcc374b4..71e40c405b0777a6c008687f88c0427b351e6185 100644 (file)
@@ -116,6 +116,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.
  *
index d060b6d6d445cda68d6ce6968ad4ce8b4b15b9fe..48edf8a897471c29813decc44a7dd651cfe5a24c 100644 (file)
@@ -46,6 +46,7 @@ struct ast_iostream {
        int rbuflen;
        char *rbufhead;
        char rbuf[2048];
+       char *sni_hostname;
 };
 
 #if defined(DO_SSL)
@@ -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;
@@ -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);
 }
 
@@ -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);
index 45eb29bf6c442104d36e9847413912723f7918af..b6a77f72b44a6e7767673784a9b68c6d765ed67a 100644 (file)
@@ -673,6 +673,14 @@ 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: