1- use anyhow:: { Context as _, Result , anyhow, bail} ;
2- use core:: future:: { Future as _, poll_fn} ;
3- use core:: pin:: pin;
4- use core:: str;
5- use core:: task:: { Poll , ready} ;
1+ use anyhow:: { Context as _, Result , anyhow} ;
2+ use core:: future:: Future ;
63use futures:: try_join;
74use test_programs:: p3:: wasi:: sockets:: ip_name_lookup:: resolve_addresses;
85use test_programs:: p3:: wasi:: sockets:: types:: { IpAddress , IpSocketAddress , TcpSocket } ;
9- use test_programs:: p3:: wasi:: tls;
10- use test_programs:: p3:: wasi:: tls:: client:: Hello ;
6+ use test_programs:: p3:: wasi:: tls:: client:: Connector ;
117use test_programs:: p3:: wit_stream;
12- use wit_bindgen:: StreamResult ;
138
149struct Component ;
1510
@@ -27,63 +22,52 @@ async fn test_tls_sample_application(domain: &str, ip: IpAddress) -> Result<()>
2722 . await
2823 . context ( "tcp connect failed" ) ?;
2924
25+ let conn = Connector :: new ( ) ;
26+
3027 let ( sock_rx, sock_rx_fut) = sock. receive ( ) ;
31- let hello = Hello :: new ( ) ;
32- hello
33- . set_server_name ( domain)
34- . map_err ( |( ) | anyhow ! ( "failed to set SNI" ) ) ?;
35- let ( sock_tx, conn) = tls:: client:: connect ( hello, sock_rx) ;
36- let sock_tx_fut = sock. send ( sock_tx) ;
37-
38- let mut conn = pin ! ( conn. into_future( ) ) ;
39- let mut sock_rx_fut = pin ! ( sock_rx_fut. into_future( ) ) ;
40- let mut sock_tx_fut = pin ! ( sock_tx_fut) ;
41- let conn = poll_fn ( |cx| match conn. as_mut ( ) . poll ( cx) {
42- Poll :: Ready ( Ok ( conn) ) => Poll :: Ready ( Ok ( conn) ) ,
43- Poll :: Ready ( Err ( ( ) ) ) => Poll :: Ready ( Err ( anyhow ! ( "tls handshake failed" ) ) ) ,
44- Poll :: Pending => match sock_tx_fut. as_mut ( ) . poll ( cx) {
45- Poll :: Ready ( Ok ( ( ) ) ) => Poll :: Ready ( Err ( anyhow ! ( "Tx stream closed unexpectedly" ) ) ) ,
46- Poll :: Ready ( Err ( err) ) => {
47- Poll :: Ready ( Err ( anyhow ! ( "Tx stream closed with error: {err:?}" ) ) )
48- }
49- Poll :: Pending => match ready ! ( sock_rx_fut. as_mut( ) . poll( cx) ) {
50- Ok ( _) => Poll :: Ready ( Err ( anyhow ! ( "Rx stream closed unexpectedly" ) ) ) ,
51- Err ( err) => Poll :: Ready ( Err ( anyhow ! ( "Rx stream closed with error: {err:?}" ) ) ) ,
52- } ,
53- } ,
54- } )
55- . await ?;
28+ let ( tls_rx, tls_rx_fut) = conn. receive ( sock_rx) ;
5629
57- let ( mut req_tx, req_rx) = wit_stream:: new ( ) ;
58- let ( mut res_rx, result_fut) = tls:: client:: Handshake :: finish ( conn, req_rx) ;
30+ let ( mut data_tx, data_rx) = wit_stream:: new ( ) ;
31+ let ( tls_tx, tls_tx_err_fut) = conn. send ( data_rx) ;
32+ let sock_tx_fut = sock. send ( tls_tx) ;
5933
60- let res = Vec :: with_capacity ( 8192 ) ;
6134 try_join ! (
6235 async {
63- let buf = req_tx. write_all( request. into( ) ) . await ;
64- assert_eq!( buf, [ ] ) ;
65- drop( req_tx) ;
36+ Connector :: connect( conn, domain. into( ) )
37+ . await
38+ . map_err( |err| {
39+ anyhow!( err. to_debug_string( ) ) . context( "failed to establish connection" )
40+ } )
41+ } ,
42+ async {
43+ let buf = data_tx. write_all( request. into( ) ) . await ;
44+ assert!( buf. is_empty( ) ) ;
45+ drop( data_tx) ;
6646 Ok ( ( ) )
6747 } ,
6848 async {
69- let ( result, buf) = res_rx. read( res) . await ;
70- match result {
71- StreamResult :: Complete ( ..) => {
72- drop( res_rx) ;
73- let res = String :: from_utf8( buf) ?;
74- if res. contains( "HTTP/1.1 200 OK" ) {
75- Ok ( ( ) )
76- } else {
77- bail!( "server did not respond with 200 OK: {res}" )
78- }
79- }
80- StreamResult :: Dropped => bail!( "read dropped" ) ,
81- StreamResult :: Cancelled => bail!( "read cancelled" ) ,
49+ let response = tls_rx. collect( ) . await ;
50+ let response = String :: from_utf8( response) ?;
51+ if response. contains( "HTTP/1.1 200 OK" ) {
52+ Ok ( ( ) )
53+ } else {
54+ Err ( anyhow!( "server did not respond with 200 OK: {response}" ) )
8255 }
8356 } ,
84- async { result_fut. await . map_err( |( ) | anyhow!( "TLS session failed" ) ) } ,
85- async { sock_rx_fut. await . context( "TCP receipt failed" ) } ,
86- async { sock_tx_fut. await . context( "TCP transmit failed" ) } ,
57+ async { sock_rx_fut. await . context( "failed to receive ciphertext" ) } ,
58+ async { sock_tx_fut. await . context( "failed to send ciphertext" ) } ,
59+ async {
60+ tls_rx_fut
61+ . await
62+ . map_err( |err| anyhow!( err. to_debug_string( ) ) )
63+ . context( "failed to receive plaintext" )
64+ } ,
65+ async {
66+ tls_tx_err_fut
67+ . await
68+ . map_err( |err| anyhow!( err. to_debug_string( ) ) )
69+ . context( "failed to send plaintext" )
70+ } ,
8771 ) ?;
8872 Ok ( ( ) )
8973}
@@ -92,32 +76,57 @@ async fn test_tls_sample_application(domain: &str, ip: IpAddress) -> Result<()>
9276/// perform a TLS handshake using another unrelated domain. This should result
9377/// in a handshake error.
9478async fn test_tls_invalid_certificate ( _domain : & str , ip : IpAddress ) -> Result < ( ) > {
95- const BAD_DOMAIN : & ' static str = "wrongdomain.localhost" ;
79+ const BAD_DOMAIN : & str = "wrongdomain.localhost" ;
9680
9781 let sock = TcpSocket :: create ( ip. family ( ) ) . unwrap ( ) ;
9882 sock. connect ( IpSocketAddress :: new ( ip, PORT ) )
9983 . await
10084 . context ( "tcp connect failed" ) ?;
10185
86+ let conn = Connector :: new ( ) ;
87+
10288 let ( sock_rx, sock_rx_fut) = sock. receive ( ) ;
103- let hello = Hello :: new ( ) ;
104- hello
105- . set_server_name ( BAD_DOMAIN )
106- . map_err ( |( ) | anyhow ! ( "failed to set SNI" ) ) ?;
107- let ( sock_tx, conn) = tls:: client:: connect ( hello, sock_rx) ;
108- let sock_tx_fut = sock. send ( sock_tx) ;
89+ let ( tls_rx, tls_rx_fut) = conn. receive ( sock_rx) ;
10990
110- try_join ! (
91+ let ( _, data_rx) = wit_stream:: new ( ) ;
92+ let ( tls_tx, tls_tx_err_fut) = conn. send ( data_rx) ;
93+ let sock_tx_fut = sock. send ( tls_tx) ;
94+ let res = try_join ! (
11195 async {
112- match conn. await {
113- Err ( ( ) ) => Ok ( ( ) ) ,
114- Ok ( _ ) => panic! ( "expecting server name mismatch" ) ,
115- }
96+ Connector :: connect ( conn, BAD_DOMAIN . into ( ) )
97+ . await
98+ . expect ( "`connect` failed" ) ;
99+ Ok ( ( ) )
116100 } ,
117- async { sock_rx_fut. await . context( "TCP receipt failed" ) } ,
118- async { sock_tx_fut. await . context( "TCP transmit failed" ) } ,
119- ) ?;
120- Ok ( ( ) )
101+ async {
102+ let response = tls_rx. collect( ) . await ;
103+ assert_eq!( response, [ ] ) ;
104+ Ok ( ( ) )
105+ } ,
106+ async {
107+ sock_rx_fut. await . expect( "failed to receive ciphertext" ) ;
108+ Ok ( ( ) )
109+ } ,
110+ async {
111+ sock_tx_fut. await . expect( "failed to send ciphertext" ) ;
112+ Ok ( ( ) )
113+ } ,
114+ async { tls_rx_fut. await } ,
115+ async { tls_tx_err_fut. await } ,
116+ ) ;
117+ match res {
118+ Err ( e) => {
119+ let debug_string = e. to_debug_string ( ) ;
120+ // We're expecting an error regarding certificates in some form or
121+ // another. When we add more TLS backends this naive check will
122+ // likely need to be revisited/expanded:
123+ if debug_string. contains ( "certificate" ) || debug_string. contains ( "HandshakeFailure" ) {
124+ return Ok ( ( ) ) ;
125+ }
126+ Err ( anyhow ! ( debug_string) )
127+ }
128+ Ok ( _) => panic ! ( "expecting server name mismatch" ) ,
129+ }
121130}
122131
123132async fn try_live_endpoints < ' a , Fut > ( test : impl Fn ( & ' a str , IpAddress ) -> Fut )
@@ -126,7 +135,7 @@ where
126135{
127136 // since this is testing remote endpoints to ensure system cert store works
128137 // the test uses a couple different endpoints to reduce the number of flakes
129- const DOMAINS : & ' static [ & ' static str ] = & [
138+ const DOMAINS : & [ & str ] = & [
130139 "example.com" ,
131140 "api.github.com" ,
132141 "docs.wasmtime.dev" ,
@@ -141,7 +150,7 @@ where
141150 . first ( )
142151 . map ( |a| a. to_owned ( ) )
143152 . ok_or_else ( || anyhow ! ( "DNS lookup failed." ) ) ?;
144- test ( & domain, ip) . await
153+ test ( domain, ip) . await
145154 } ) ( ) ;
146155
147156 match result. await {
0 commit comments