From 86cacac91a2837ccca0c69102a33c8ac52faea98 Mon Sep 17 00:00:00 2001 From: lhuang04 Date: Fri, 21 Jan 2022 07:34:27 -0800 Subject: [PATCH] Port ALPN support for tls13 client from tls13-prototype Summary: Port ALPN implementation of tls13 client from [tls13-prototype](https://github.com/hannestschofenig/mbedtls/blob/tls13-prototype/library/ssl_tls13_client.c#L1124). Test Plan: Reviewers: Subscribers: Tasks: Tags: Signed-off-by: lhuang04 --- ChangeLog.d/mbedtls_ssl_tls13_client.txt | 4 + library/ssl_tls13_client.c | 132 +++++++++++++++++++++++ tests/ssl-opt.sh | 70 ++++++++++++ 3 files changed, 206 insertions(+) create mode 100644 ChangeLog.d/mbedtls_ssl_tls13_client.txt diff --git a/ChangeLog.d/mbedtls_ssl_tls13_client.txt b/ChangeLog.d/mbedtls_ssl_tls13_client.txt new file mode 100644 index 000000000..855945b11 --- /dev/null +++ b/ChangeLog.d/mbedtls_ssl_tls13_client.txt @@ -0,0 +1,4 @@ +Features + * Add ALPN support in tls13 client. Client is able to write ALPN extension + in client hello, and able to parse the response from server encrypted + extension. diff --git a/library/ssl_tls13_client.c b/library/ssl_tls13_client.c index f556c0f26..99c12cd7a 100644 --- a/library/ssl_tls13_client.c +++ b/library/ssl_tls13_client.c @@ -113,6 +113,120 @@ static int ssl_tls13_parse_supported_versions_ext( mbedtls_ssl_context *ssl, return( 0 ); } +#if defined(MBEDTLS_SSL_ALPN) +/* + * ssl_tls13_write_alpn_ext( ) structure: + * + * opaque ProtocolName<1..2^8-1>; + * + * struct { + * ProtocolName protocol_name_list<2..2^16-1> + * } ProtocolNameList; + * + */ +static int ssl_tls13_write_alpn_ext( mbedtls_ssl_context *ssl, + unsigned char *buf, + const unsigned char *end, + size_t *olen ) +{ + unsigned char *p = buf; + size_t alpnlen = 0; + const char **cur; + + *olen = 0; + + if( ssl->conf->alpn_list == NULL ) + return( 0 ); + + MBEDTLS_SSL_DEBUG_MSG( 3, ( "client hello, adding alpn extension" ) ); + + for( cur = ssl->conf->alpn_list; *cur != NULL; cur++ ) + alpnlen += strlen( *cur ) + 1; + + MBEDTLS_SSL_CHK_BUF_PTR( p, end, 6 + alpnlen ); + + MBEDTLS_PUT_UINT16_BE( MBEDTLS_TLS_EXT_ALPN, p, 0 ); + p += 2; + + /* + * opaque ProtocolName<1..2^8-1>; + * + * struct { + * ProtocolName protocol_name_list<2..2^16-1> + * } ProtocolNameList; + */ + + /* Skip writing extension and list length for now */ + p += 4; + + for( cur = ssl->conf->alpn_list; *cur != NULL; cur++ ) + { + /* + * mbedtls_ssl_conf_set_alpn_protocols() checked that the length of + * protocol names is less than 255. + */ + *p = (unsigned char)strlen( *cur ); + memcpy( p + 1, *cur, *p ); + p += 1 + *p; + } + + *olen = p - buf; + + /* List length = olen - 2 (ext_type) - 2 (ext_len) - 2 (list_len) */ + MBEDTLS_PUT_UINT16_BE( *olen - 6, buf, 4 ); + + /* Extension length = olen - 2 (ext_type) - 2 (ext_len) */ + MBEDTLS_PUT_UINT16_BE( *olen - 4, buf, 2 ); + + return( 0 ); +} + +static int ssl_tls13_parse_alpn_ext( mbedtls_ssl_context *ssl, + const unsigned char *buf, size_t len ) +{ + size_t list_len, name_len; + const unsigned char *p = buf; + const unsigned char *end = buf + len; + + /* If we didn't send it, the server shouldn't send it */ + if( ssl->conf->alpn_list == NULL ) + return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA ); + + /* + * opaque ProtocolName<1..2^8-1>; + * + * struct { + * ProtocolName protocol_name_list<2..2^16-1> + * } ProtocolNameList; + * + * the "ProtocolNameList" MUST contain exactly one "ProtocolName" + */ + + /* Min length is 2 ( list_len ) + 1 ( name_len ) + 1 ( name ) */ + MBEDTLS_SSL_CHK_BUF_READ_PTR( p, end, 4 ); + + list_len = MBEDTLS_GET_UINT16_BE( p, 0 ); + p += 2; + MBEDTLS_SSL_CHK_BUF_READ_PTR( p, end, list_len ); + + name_len = *p++; + MBEDTLS_SSL_CHK_BUF_READ_PTR( p, end, list_len - 1 ); + + /* Check that the server chosen protocol was in our list and save it */ + for ( const char **alpn = ssl->conf->alpn_list; *alpn != NULL; alpn++ ) + { + if( name_len == strlen( *alpn ) && + memcmp( buf + 3, *alpn, name_len ) == 0 ) + { + ssl->alpn_chosen = *alpn; + return( 0 ); + } + } + + return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA ); +} +#endif /* MBEDTLS_SSL_ALPN */ + #if defined(MBEDTLS_KEY_EXCHANGE_WITH_CERT_ENABLED) static int ssl_tls13_reset_key_share( mbedtls_ssl_context *ssl ) @@ -753,6 +867,13 @@ static int ssl_tls13_write_client_hello_body( mbedtls_ssl_context *ssl, return( ret ); p += output_len; +#if defined(MBEDTLS_SSL_ALPN) + ssl_tls13_write_alpn_ext( ssl, p, end, &output_len ); + if( ret != 0 ) + return( ret ); + p += output_len; +#endif /* MBEDTLS_SSL_ALPN */ + #if defined(MBEDTLS_KEY_EXCHANGE_WITH_CERT_ENABLED) /* @@ -1622,6 +1743,17 @@ static int ssl_tls13_parse_encrypted_extensions( mbedtls_ssl_context *ssl, MBEDTLS_SSL_DEBUG_MSG( 3, ( "found extensions supported groups" ) ); break; +#if defined(MBEDTLS_SSL_ALPN) + case MBEDTLS_TLS_EXT_ALPN: + MBEDTLS_SSL_DEBUG_MSG( 3, ( "found alpn extension" ) ); + + if( ( ret = ssl_tls13_parse_alpn_ext( ssl, p, (size_t)extension_data_len ) ) != 0 ) + { + return( ret ); + } + + break; +#endif /* MBEDTLS_SSL_ALPN */ default: MBEDTLS_SSL_DEBUG_MSG( 3, ( "unsupported extension found: %u ", extension_type) ); diff --git a/tests/ssl-opt.sh b/tests/ssl-opt.sh index 2480713fd..eb2462f78 100755 --- a/tests/ssl-opt.sh +++ b/tests/ssl-opt.sh @@ -9106,6 +9106,76 @@ run_test "TLS 1.3: minimal feature sets - gnutls" \ -c "<= parse finished message" \ -c "HTTP/1.0 200 OK" +requires_openssl_tls1_3 +requires_config_enabled MBEDTLS_SSL_PROTO_TLS1_3 +requires_config_enabled MBEDTLS_SSL_TLS1_3_COMPATIBILITY_MODE +requires_config_enabled MBEDTLS_DEBUG_C +requires_config_enabled MBEDTLS_SSL_CLI_C +requires_config_enabled MBEDTLS_SSL_ALPN +requires_config_disabled MBEDTLS_USE_PSA_CRYPTO +run_test "TLS 1.3: alpn - openssl" \ + "$O_NEXT_SRV -msg -tls1_3 -num_tickets 0 -no_resume_ephemeral -no_cache -alpn h2" \ + "$P_CLI debug_level=3 min_version=tls13 max_version=tls13 alpn=h2" \ + 0 \ + -c "tls13 client state: MBEDTLS_SSL_HELLO_REQUEST" \ + -c "tls13 client state: MBEDTLS_SSL_SERVER_HELLO" \ + -c "tls13 client state: MBEDTLS_SSL_ENCRYPTED_EXTENSIONS" \ + -c "tls13 client state: MBEDTLS_SSL_CERTIFICATE_REQUEST" \ + -c "tls13 client state: MBEDTLS_SSL_SERVER_CERTIFICATE" \ + -c "tls13 client state: MBEDTLS_SSL_CERTIFICATE_VERIFY" \ + -c "tls13 client state: MBEDTLS_SSL_SERVER_FINISHED" \ + -c "tls13 client state: MBEDTLS_SSL_CLIENT_FINISHED" \ + -c "tls13 client state: MBEDTLS_SSL_FLUSH_BUFFERS" \ + -c "tls13 client state: MBEDTLS_SSL_HANDSHAKE_WRAPUP" \ + -c "<= ssl_tls13_process_server_hello" \ + -c "server hello, chosen ciphersuite: ( 1301 ) - TLS1-3-AES-128-GCM-SHA256" \ + -c "ECDH curve: x25519" \ + -c "=> ssl_tls13_process_server_hello" \ + -c "<= parse encrypted extensions" \ + -c "Certificate verification flags clear" \ + -c "=> parse certificate verify" \ + -c "<= parse certificate verify" \ + -c "mbedtls_ssl_tls13_process_certificate_verify() returned 0" \ + -c "<= parse finished message" \ + -c "HTTP/1.0 200 ok" \ + -c "Application Layer Protocol is h2" + +requires_gnutls_tls1_3 +requires_gnutls_next_no_ticket +requires_config_enabled MBEDTLS_SSL_PROTO_TLS1_3 +requires_config_enabled MBEDTLS_SSL_TLS1_3_COMPATIBILITY_MODE +requires_config_enabled MBEDTLS_DEBUG_C +requires_config_enabled MBEDTLS_SSL_CLI_C +requires_config_enabled MBEDTLS_SSL_ALPN +requires_config_disabled MBEDTLS_USE_PSA_CRYPTO +run_test "TLS 1.3: alpn - gnutls" \ + "$G_NEXT_SRV --debug=4 --priority=NORMAL:-VERS-ALL:+VERS-TLS1.3:+CIPHER-ALL:%NO_TICKETS --disable-client-cert --alpn=h2" \ + "$P_CLI debug_level=3 min_version=tls13 max_version=tls13 alpn=h2" \ + 0 \ + -s "SERVER HELLO was queued" \ + -c "tls13 client state: MBEDTLS_SSL_HELLO_REQUEST" \ + -c "tls13 client state: MBEDTLS_SSL_SERVER_HELLO" \ + -c "tls13 client state: MBEDTLS_SSL_ENCRYPTED_EXTENSIONS" \ + -c "tls13 client state: MBEDTLS_SSL_CERTIFICATE_REQUEST" \ + -c "tls13 client state: MBEDTLS_SSL_SERVER_CERTIFICATE" \ + -c "tls13 client state: MBEDTLS_SSL_CERTIFICATE_VERIFY" \ + -c "tls13 client state: MBEDTLS_SSL_SERVER_FINISHED" \ + -c "tls13 client state: MBEDTLS_SSL_CLIENT_FINISHED" \ + -c "tls13 client state: MBEDTLS_SSL_FLUSH_BUFFERS" \ + -c "tls13 client state: MBEDTLS_SSL_HANDSHAKE_WRAPUP" \ + -c "<= ssl_tls13_process_server_hello" \ + -c "server hello, chosen ciphersuite: ( 1301 ) - TLS1-3-AES-128-GCM-SHA256" \ + -c "ECDH curve: x25519" \ + -c "=> ssl_tls13_process_server_hello" \ + -c "<= parse encrypted extensions" \ + -c "Certificate verification flags clear" \ + -c "=> parse certificate verify" \ + -c "<= parse certificate verify" \ + -c "mbedtls_ssl_tls13_process_certificate_verify() returned 0" \ + -c "<= parse finished message" \ + -c "HTTP/1.0 200 OK" \ + -c "Application Layer Protocol is h2" + requires_config_enabled MBEDTLS_SSL_PROTO_TLS1_3 requires_config_enabled MBEDTLS_DEBUG_C requires_config_enabled MBEDTLS_SSL_CLI_C