2
2
// SPDX-License-Identifier: Apache-2.0
3
3
4
4
use super :: * ;
5
- use crate :: { client, client:: ClientProviders , server, server:: ServerProviders } ;
5
+ use crate :: { client, client:: ClientProviders , provider :: dc , server, server:: ServerProviders } ;
6
6
use s2n_quic_core:: {
7
7
dc:: testing:: MockDcEndpoint ,
8
8
event:: { api:: DcState , Timestamp } ,
9
9
stateless_reset:: token:: testing:: { TEST_TOKEN_1 , TEST_TOKEN_2 } ,
10
10
} ;
11
+ use std:: io:: ErrorKind ;
11
12
12
13
// Client Server
13
14
//
@@ -42,7 +43,7 @@ fn dc_handshake_self_test() {
42
43
let server = Server :: builder ( ) . with_tls ( SERVER_CERTS ) . unwrap ( ) ;
43
44
let client = Client :: builder ( ) . with_tls ( certificates:: CERT_PEM ) . unwrap ( ) ;
44
45
45
- self_test ( server, client) ;
46
+ self_test ( server, client, None ) ;
46
47
}
47
48
48
49
// Client Server
@@ -81,17 +82,28 @@ fn dc_mtls_handshake_self_test() {
81
82
let client_tls = build_client_mtls_provider ( certificates:: MTLS_CA_CERT ) . unwrap ( ) ;
82
83
let client = Client :: builder ( ) . with_tls ( client_tls) . unwrap ( ) ;
83
84
84
- self_test ( server, client) ;
85
+ self_test ( server, client, None ) ;
86
+ }
87
+
88
+ #[ test]
89
+ fn dc_mtls_handshake_auth_failure_self_test ( ) {
90
+ let server_tls = build_server_mtls_provider ( certificates:: UNTRUSTED_CERT_PEM ) . unwrap ( ) ;
91
+ let server = Server :: builder ( ) . with_tls ( server_tls) . unwrap ( ) ;
92
+
93
+ let client_tls = build_client_mtls_provider ( certificates:: MTLS_CA_CERT ) . unwrap ( ) ;
94
+ let client = Client :: builder ( ) . with_tls ( client_tls) . unwrap ( ) ;
95
+
96
+ self_test ( server, client, Some ( ErrorKind :: ConnectionReset ) ) ;
85
97
}
86
98
87
99
fn self_test < S : ServerProviders , C : ClientProviders > (
88
100
server : server:: Builder < S > ,
89
101
client : client:: Builder < C > ,
102
+ expected_error : Option < ErrorKind > ,
90
103
) {
91
104
let model = Model :: default ( ) ;
92
105
let rtt = Duration :: from_millis ( 100 ) ;
93
106
model. set_delay ( rtt / 2 ) ;
94
- const LEN : usize = 1000 ;
95
107
96
108
let server_subscriber = DcStateChanged :: new ( ) ;
97
109
let server_events = server_subscriber. clone ( ) ;
@@ -103,60 +115,68 @@ fn self_test<S: ServerProviders, C: ClientProviders>(
103
115
test ( model, |handle| {
104
116
let mut server = server
105
117
. with_io ( handle. builder ( ) . build ( ) ?) ?
106
- . with_event ( ( tracing_events ( ) , server_subscriber) ) ?
118
+ . with_event ( ( dc :: ConfirmComplete , ( tracing_events ( ) , server_subscriber) ) ) ?
107
119
. with_random ( Random :: with_seed ( 456 ) ) ?
108
120
. with_dc ( MockDcEndpoint :: new ( & server_tokens) ) ?
109
121
. start ( ) ?;
110
122
111
123
let addr = server. local_addr ( ) ?;
112
124
spawn ( async move {
113
- let mut conn = server. accept ( ) . await . unwrap ( ) ;
114
- let mut stream = conn. open_bidirectional_stream ( ) . await . unwrap ( ) ;
115
- stream. send ( vec ! [ 42 ; LEN ] . into ( ) ) . await . unwrap ( ) ;
116
- stream. flush ( ) . await . unwrap ( ) ;
125
+ let conn = server. accept ( ) . await ;
126
+ if expected_error. is_some ( ) {
127
+ assert ! ( conn. is_none( ) ) ;
128
+ } else {
129
+ assert ! ( dc:: ConfirmComplete :: wait_ready( & mut conn. unwrap( ) )
130
+ . await
131
+ . is_ok( ) ) ;
132
+ }
117
133
} ) ;
118
134
119
135
let client = client
120
136
. with_io ( handle. builder ( ) . build ( ) . unwrap ( ) ) ?
121
- . with_event ( ( tracing_events ( ) , client_subscriber) ) ?
137
+ . with_event ( ( dc :: ConfirmComplete , ( tracing_events ( ) , client_subscriber) ) ) ?
122
138
. with_random ( Random :: with_seed ( 456 ) ) ?
123
139
. with_dc ( MockDcEndpoint :: new ( & client_tokens) ) ?
124
140
. start ( ) ?;
125
141
142
+ let client_events = client_events. clone ( ) ;
143
+
126
144
primary:: spawn ( async move {
127
145
let connect = Connect :: new ( addr) . with_server_name ( "localhost" ) ;
128
146
let mut conn = client. connect ( connect) . await . unwrap ( ) ;
129
- let mut stream = conn . accept_bidirectional_stream ( ) . await . unwrap ( ) . unwrap ( ) ;
147
+ let result = dc :: ConfirmComplete :: wait_ready ( & mut conn ) . await ;
130
148
131
- let mut recv_len = 0 ;
132
- while let Some ( chunk) = stream. receive ( ) . await . unwrap ( ) {
133
- recv_len += chunk. len ( ) ;
149
+ if let Some ( error) = expected_error {
150
+ assert_eq ! ( error, result. err( ) . unwrap( ) . kind( ) ) ;
151
+ } else {
152
+ assert ! ( result. is_ok( ) ) ;
153
+ let client_events = client_events. events ( ) . lock ( ) . unwrap ( ) . clone ( ) ;
154
+ assert_dc_complete ( & client_events) ;
155
+ // wait briefly so the ack for the `DC_STATELESS_RESET_TOKENS` frame from the server is sent
156
+ // before the client closes the connection. This is only necessary to confirm the `dc::State`
157
+ // on the server moves to `DcState::Complete`
158
+ delay ( Duration :: from_millis ( 100 ) ) . await ;
134
159
}
135
- assert_eq ! ( LEN , recv_len) ;
136
160
} ) ;
137
161
138
162
Ok ( addr)
139
163
} )
140
164
. unwrap ( ) ;
141
165
166
+ if expected_error. is_some ( ) {
167
+ return ;
168
+ }
169
+
142
170
let server_events = server_events. events ( ) . lock ( ) . unwrap ( ) . clone ( ) ;
143
171
let client_events = client_events. events ( ) . lock ( ) . unwrap ( ) . clone ( ) ;
144
172
173
+ assert_dc_complete ( & server_events) ;
174
+ assert_dc_complete ( & client_events) ;
175
+
145
176
// 3 state transitions (VersionNegotiated -> PathSecretsReady -> Complete)
146
177
assert_eq ! ( 3 , server_events. len( ) ) ;
147
178
assert_eq ! ( 3 , client_events. len( ) ) ;
148
179
149
- for events in [ server_events. clone ( ) , client_events. clone ( ) ] {
150
- if let DcState :: VersionNegotiated { version, .. } = events[ 0 ] . state {
151
- assert_eq ! ( version, s2n_quic_core:: dc:: SUPPORTED_VERSIONS [ 0 ] ) ;
152
- } else {
153
- panic ! ( "VersionNegotiated should be the first dc state" ) ;
154
- }
155
-
156
- assert ! ( matches!( events[ 1 ] . state, DcState :: PathSecretsReady { .. } ) ) ;
157
- assert ! ( matches!( events[ 2 ] . state, DcState :: Complete { .. } ) ) ;
158
- }
159
-
160
180
// Server path secrets are ready in 1.5 RTTs measured from the start of the test, since it takes
161
181
// .5 RTT for the Initial from the client to reach the server
162
182
assert_eq ! (
@@ -175,6 +195,20 @@ fn self_test<S: ServerProviders, C: ClientProviders>(
175
195
assert_eq ! ( rtt * 2 , client_events[ 2 ] . timestamp. duration_since_start( ) ) ;
176
196
}
177
197
198
+ fn assert_dc_complete ( events : & [ DcStateChangedEvent ] ) {
199
+ // 3 state transitions (VersionNegotiated -> PathSecretsReady -> Complete)
200
+ assert_eq ! ( 3 , events. len( ) ) ;
201
+
202
+ if let DcState :: VersionNegotiated { version, .. } = events[ 0 ] . state {
203
+ assert_eq ! ( version, s2n_quic_core:: dc:: SUPPORTED_VERSIONS [ 0 ] ) ;
204
+ } else {
205
+ panic ! ( "VersionNegotiated should be the first dc state" ) ;
206
+ }
207
+
208
+ assert ! ( matches!( events[ 1 ] . state, DcState :: PathSecretsReady { .. } ) ) ;
209
+ assert ! ( matches!( events[ 2 ] . state, DcState :: Complete { .. } ) ) ;
210
+ }
211
+
178
212
#[ derive( Clone ) ]
179
213
struct DcStateChangedEvent {
180
214
timestamp : Timestamp ,
0 commit comments