@@ -11,8 +11,8 @@ use opentelemetry::{
1111} ;
1212use pool_nts:: {
1313 AlgorithmDescription , BufferBorrowingReader , ClientRequest , ErrorCode , ErrorResponse ,
14- FixedKeyRequest , KeyExchangeResponse , MAX_MESSAGE_SIZE , NoAgreementResponse , NtsError ,
15- ProtocolId ,
14+ FixedKeyRequest , KeyExchangeResponse , MAX_MESSAGE_SIZE , NoAeadAlgorithmAgreementResponse ,
15+ NoProtocolAgreementResponse , NtsError , ProtocolId ,
1616} ;
1717use rustls:: { pki_types:: pem:: PemObject , version:: TLS13 } ;
1818use tokio:: {
@@ -82,7 +82,6 @@ impl std::fmt::Display for ConnectionError {
8282enum SelectionOutcome {
8383 NoSharedProtocol ,
8484 NoSharedAlgorithm {
85- #[ expect( unused) ]
8685 protocol : ProtocolId ,
8786 } ,
8887 Selection {
@@ -522,8 +521,19 @@ impl<S: ServerManager + 'static> NtsPoolKe<S> {
522521 protocol,
523522 algorithm,
524523 } ) => ( protocol, algorithm) ,
525- Ok ( SelectionOutcome :: NoSharedAlgorithm { .. } | SelectionOutcome :: NoSharedProtocol ) => {
526- NoAgreementResponse
524+ Ok ( SelectionOutcome :: NoSharedAlgorithm { protocol } ) => {
525+ NoAeadAlgorithmAgreementResponse { protocol }
526+ . serialize ( & mut client_stream)
527+ . await
528+ . map_err ( ConnectionError :: SendResponse ) ?;
529+ client_stream
530+ . shutdown ( )
531+ . await
532+ . map_err ( ConnectionError :: SendResponse ) ?;
533+ return Ok ( ( ) ) ;
534+ }
535+ Ok ( SelectionOutcome :: NoSharedProtocol ) => {
536+ NoProtocolAgreementResponse
527537 . serialize ( & mut client_stream)
528538 . await
529539 . map_err ( ConnectionError :: SendResponse ) ?;
@@ -1187,6 +1197,146 @@ mod tests {
11871197 pool_handle. abort ( ) ;
11881198 }
11891199
1200+ #[ tokio:: test]
1201+ async fn test_keyexchange_protocol_negotiation_failure ( ) {
1202+ crate :: test_init ( ) ;
1203+ let pool_listener = TcpListener :: bind ( "127.0.0.1:0" ) . await . unwrap ( ) ;
1204+ let pool_addr = pool_listener. local_addr ( ) . unwrap ( ) ;
1205+
1206+ let manager = TestManager :: new (
1207+ "a.test" . into ( ) ,
1208+ vec ! [
1209+ 0x80 , 1 , 0 , 2 , 0 , 0 , 0x80 , 4 , 0 , 2 , 0 , 0 , 0 , 5 , 0 , 2 , 1 , 2 , 0 , 5 , 0 , 2 , 3 , 4 , 0x80 ,
1210+ 0 , 0 , 0 ,
1211+ ] ,
1212+ & [ 0 ] ,
1213+ & [ AlgorithmDescription { id : 0 , keysize : 16 } ] ,
1214+ false ,
1215+ ) ;
1216+ let pool_manager = manager. clone ( ) ;
1217+
1218+ let pool_handle = tokio:: spawn ( async move {
1219+ let pool_config = NtsPoolKeConfig {
1220+ certificate_chain : PathBuf :: from ( format ! (
1221+ "{}/testdata/pool.test.fullchain.pem" ,
1222+ env!( "CARGO_MANIFEST_DIR" ) ,
1223+ ) ) ,
1224+ private_key : PathBuf :: from ( format ! (
1225+ "{}/testdata/pool.test.key" ,
1226+ env!( "CARGO_MANIFEST_DIR" ) ,
1227+ ) ) ,
1228+ listen : pool_addr,
1229+ key_exchange_timeout : Duration :: from_millis ( 1000 ) ,
1230+ timesource_timeout : Duration :: from_millis ( 500 ) ,
1231+ max_connections : 1 ,
1232+ use_proxy_protocol : false ,
1233+ monitoring_keys : None ,
1234+ } ;
1235+
1236+ let pool = Arc :: new ( NtsPoolKe :: new ( pool_config, pool_manager) . await . unwrap ( ) ) ;
1237+ pool. serve_inner ( pool_listener) . await
1238+ } ) ;
1239+
1240+ let pool_connector = upstream_tls_config ( ) ;
1241+ let conn = TcpStream :: connect ( pool_addr) . await . unwrap ( ) ;
1242+ let mut conn = pool_connector
1243+ . connect ( ServerName :: try_from ( "pool.test" ) . unwrap ( ) , conn)
1244+ . await
1245+ . unwrap ( ) ;
1246+
1247+ conn. write_all ( & [ 0x80 , 1 , 0 , 2 , 0 , 2 , 0x80 , 4 , 0 , 2 , 0 , 0 , 0x80 , 0 , 0 , 0 ] )
1248+ . await
1249+ . unwrap ( ) ;
1250+ let mut buf = [ 0u8 ; MAX_MESSAGE_SIZE as _ ] ;
1251+ let response =
1252+ KeyExchangeResponse :: parse ( & mut BufferBorrowingReader :: new ( & mut conn, & mut buf) )
1253+ . await
1254+ . unwrap_err ( ) ;
1255+ conn. shutdown ( ) . await . unwrap ( ) ;
1256+
1257+ assert_eq ! ( manager. inner. written. lock( ) . unwrap( ) . len( ) , 0 ) ;
1258+ assert ! ( matches!( response, NtsError :: NoOverlappingProtocol ) ) ;
1259+ assert_eq ! (
1260+ manager
1261+ . inner
1262+ . reuse_count
1263+ . load( std:: sync:: atomic:: Ordering :: Relaxed ) ,
1264+ 0
1265+ ) ;
1266+
1267+ pool_handle. abort ( ) ;
1268+ }
1269+
1270+ #[ tokio:: test]
1271+ async fn test_keyexchange_algorithm_negotiation_failure ( ) {
1272+ crate :: test_init ( ) ;
1273+ let pool_listener = TcpListener :: bind ( "127.0.0.1:0" ) . await . unwrap ( ) ;
1274+ let pool_addr = pool_listener. local_addr ( ) . unwrap ( ) ;
1275+
1276+ let manager = TestManager :: new (
1277+ "a.test" . into ( ) ,
1278+ vec ! [
1279+ 0x80 , 1 , 0 , 2 , 0 , 0 , 0x80 , 4 , 0 , 2 , 0 , 0 , 0 , 5 , 0 , 2 , 1 , 2 , 0 , 5 , 0 , 2 , 3 , 4 , 0x80 ,
1280+ 0 , 0 , 0 ,
1281+ ] ,
1282+ & [ 0 ] ,
1283+ & [ AlgorithmDescription { id : 0 , keysize : 16 } ] ,
1284+ false ,
1285+ ) ;
1286+ let pool_manager = manager. clone ( ) ;
1287+
1288+ let pool_handle = tokio:: spawn ( async move {
1289+ let pool_config = NtsPoolKeConfig {
1290+ certificate_chain : PathBuf :: from ( format ! (
1291+ "{}/testdata/pool.test.fullchain.pem" ,
1292+ env!( "CARGO_MANIFEST_DIR" ) ,
1293+ ) ) ,
1294+ private_key : PathBuf :: from ( format ! (
1295+ "{}/testdata/pool.test.key" ,
1296+ env!( "CARGO_MANIFEST_DIR" ) ,
1297+ ) ) ,
1298+ listen : pool_addr,
1299+ key_exchange_timeout : Duration :: from_millis ( 1000 ) ,
1300+ timesource_timeout : Duration :: from_millis ( 500 ) ,
1301+ max_connections : 1 ,
1302+ use_proxy_protocol : false ,
1303+ monitoring_keys : None ,
1304+ } ;
1305+
1306+ let pool = Arc :: new ( NtsPoolKe :: new ( pool_config, pool_manager) . await . unwrap ( ) ) ;
1307+ pool. serve_inner ( pool_listener) . await
1308+ } ) ;
1309+
1310+ let pool_connector = upstream_tls_config ( ) ;
1311+ let conn = TcpStream :: connect ( pool_addr) . await . unwrap ( ) ;
1312+ let mut conn = pool_connector
1313+ . connect ( ServerName :: try_from ( "pool.test" ) . unwrap ( ) , conn)
1314+ . await
1315+ . unwrap ( ) ;
1316+
1317+ conn. write_all ( & [ 0x80 , 1 , 0 , 2 , 0 , 0 , 0x80 , 4 , 0 , 2 , 0 , 1 , 0x80 , 0 , 0 , 0 ] )
1318+ . await
1319+ . unwrap ( ) ;
1320+ let mut buf = [ 0u8 ; MAX_MESSAGE_SIZE as _ ] ;
1321+ let response =
1322+ KeyExchangeResponse :: parse ( & mut BufferBorrowingReader :: new ( & mut conn, & mut buf) )
1323+ . await
1324+ . unwrap_err ( ) ;
1325+ conn. shutdown ( ) . await . unwrap ( ) ;
1326+
1327+ assert_eq ! ( manager. inner. written. lock( ) . unwrap( ) . len( ) , 0 ) ;
1328+ assert ! ( matches!( response, NtsError :: NoOverlappingAeadAlgorithm ) ) ;
1329+ assert_eq ! (
1330+ manager
1331+ . inner
1332+ . reuse_count
1333+ . load( std:: sync:: atomic:: Ordering :: Relaxed ) ,
1334+ 0
1335+ ) ;
1336+
1337+ pool_handle. abort ( ) ;
1338+ }
1339+
11901340 #[ tokio:: test]
11911341 async fn test_keyexchange_keepalive ( ) {
11921342 crate :: test_init ( ) ;
0 commit comments