mirror of
				https://github.com/asterisk/asterisk.git
				synced 2025-10-31 10:47:18 +00:00 
			
		
		
		
	tcptls/iostream: Add support for setting SNI on client TLS connections
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.
This commit is contained in:
		| @@ -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); | 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. |  * \brief Get an iostream's file descriptor. | ||||||
|  * |  * | ||||||
|   | |||||||
| @@ -46,6 +46,7 @@ struct ast_iostream { | |||||||
| 	int rbuflen; | 	int rbuflen; | ||||||
| 	char *rbufhead; | 	char *rbufhead; | ||||||
| 	char rbuf[2048]; | 	char rbuf[2048]; | ||||||
|  | 	char *sni_hostname; | ||||||
| }; | }; | ||||||
|  |  | ||||||
| #if defined(DO_SSL) | #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; | 	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) | static ssize_t iostream_read(struct ast_iostream *stream, void *buf, size_t size) | ||||||
| { | { | ||||||
| 	struct timeval start; | 	struct timeval start; | ||||||
| @@ -591,13 +602,9 @@ int ast_iostream_close(struct ast_iostream *stream) | |||||||
|  |  | ||||||
| static void iostream_dtor(void *cookie) | 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; | 	struct ast_iostream *stream = cookie; | ||||||
| #endif |  | ||||||
|  |  | ||||||
|  | 	ast_free(stream->sni_hostname); | ||||||
| 	ast_assert(stream->fd == -1); | 	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); | 	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); | 	res = ssl_setup(stream->ssl); | ||||||
| 	if (res <= 0) { | 	if (res <= 0) { | ||||||
| 		int sslerr = SSL_get_error(stream->ssl, res); | 		int sslerr = SSL_get_error(stream->ssl, res); | ||||||
|   | |||||||
| @@ -741,6 +741,13 @@ struct ast_tcptls_session_instance *ast_tcptls_client_create(struct ast_tcptls_s | |||||||
| 	/* Set current info */ | 	/* Set current info */ | ||||||
| 	ast_sockaddr_copy(&desc->old_address, &desc->remote_address); | 	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; | 	return tcptls_session; | ||||||
|  |  | ||||||
| error: | error: | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user