File 0404-ssl-add-bloom-filter-tests.patch of Package erlang

From d4a0b00a02038a57e9477db25d41835592fcc783 Mon Sep 17 00:00:00 2001
From: Jakub Witczak <kuba@erlang.org>
Date: Mon, 6 Jun 2022 15:43:54 +0200
Subject: [PATCH] ssl: add bloom filter tests

---
 lib/ssl/test/ssl_session_ticket_SUITE.erl | 211 ++++++++++++++++++----
 1 file changed, 174 insertions(+), 37 deletions(-)

diff --git a/lib/ssl/test/ssl_session_ticket_SUITE.erl b/lib/ssl/test/ssl_session_ticket_SUITE.erl
index 444098044b..21804324e7 100644
--- a/lib/ssl/test/ssl_session_ticket_SUITE.erl
+++ b/lib/ssl/test/ssl_session_ticket_SUITE.erl
@@ -35,8 +35,16 @@
 %% Testcases
 -export([basic/0,
          basic/1,
-         basic_anti_replay/0,
-         basic_anti_replay/1,
+         ticketage_smaller_than_windowsize_anti_replay/0,
+         ticketage_smaller_than_windowsize_anti_replay/1,
+         ticketage_bigger_than_windowsize_anti_replay/0,
+         ticketage_bigger_than_windowsize_anti_replay/1,
+         ticketage_out_of_lifetime_anti_replay/0,
+         ticketage_out_of_lifetime_anti_replay/1,
+         ticket_reuse_anti_replay/0,
+         ticket_reuse_anti_replay/1,
+         ticket_reuse_anti_replay_server_restart/0,
+         ticket_reuse_anti_replay_server_restart/1,
          basic_stateful_stateless/0,
          basic_stateful_stateless/1,
          basic_stateless_stateful/0,
@@ -92,7 +100,11 @@ groups() ->
                       {group, stateless},
                       {group, mixed}]},
      {stateful, [], session_tests()},
-     {stateless, [], session_tests() ++ [basic_anti_replay]},
+     {stateless, [], session_tests() ++
+          [ticketage_smaller_than_windowsize_anti_replay,
+           ticketage_bigger_than_windowsize_anti_replay,
+           ticketage_out_of_lifetime_anti_replay, ticket_reuse_anti_replay,
+           ticket_reuse_anti_replay_server_restart]},
      {mixed, [], mixed_tests()}].
 
 session_tests() ->
@@ -212,60 +224,185 @@ basic(Config) when is_list(Config) ->
     ssl_test_lib:close(Server0),
     ssl_test_lib:close(Client1).
 
-basic_anti_replay() ->
-    [{doc,"Test session resumption with stateless session tickets and anti_replay (erlang client - erlang server)"}].
-basic_anti_replay(Config) when is_list(Config) ->
+ticketage_smaller_than_windowsize_anti_replay() ->
+    [{doc, "Session resumption with stateless tickets and anti_replay enabled."
+      "ClientHello with DeltaAge smaller than Bloom filter window size - fresh ClientHello."
+      "DeltaAge treated as particular ClientHello adjective, calculated "
+      "as a difference between RealAge and ReportedAge of a ticket used in ClientHello."
+      "Ticket age smaller than windowsize."
+      "(Erlang client - Erlang server)"}].
+ticketage_smaller_than_windowsize_anti_replay(Config) when is_list(Config) ->
+    {Server0, Client0, Port0, ClientNode, Hostname, ClientOpts} =
+        anti_replay_helper_init(Config, auto, 10),
+    ssl_test_lib:check_result(Server0, ok, Client0, ok),
+    Client1 = anti_replay_helper_connect(Server0, Client0, Port0, ClientNode,
+                                         Hostname, ClientOpts, 0, true),
+    process_flag(trap_exit, false),
+    [ssl_test_lib:close(A) || A <- [Server0, Client0, Client1]].
+
+ticketage_bigger_than_windowsize_anti_replay() ->
+    [{doc, "Session resumption with stateless tickets and anti_replay enabled."
+      "Fresh ClientHellos."
+      "Ticket age bigger than windowsize. 0-RTT is expected to fail."
+      "(Erlang client - Erlang server)"}].
+ticketage_bigger_than_windowsize_anti_replay(Config) when is_list(Config) ->
+    WindowSize = 3,
+    {Server0, Client0, Port0, ClientNode, Hostname, ClientOpts} =
+        anti_replay_helper_init(Config, auto, WindowSize),
+    ssl_test_lib:check_result(Server0, ok, Client0, ok),
+    Client1 = anti_replay_helper_connect(Server0, Client0, Port0, ClientNode,
+                                         Hostname, ClientOpts,
+                                         {seconds, WindowSize + 2}, false),
+    Client2 = anti_replay_helper_connect(Server0, Client0, Port0, ClientNode,
+                                         Hostname, ClientOpts,
+                                         {seconds, 2*WindowSize + 2}, false),
+    process_flag(trap_exit, false),
+    [ssl_test_lib:close(A) || A <- [Server0, Client0, Client1, Client2]].
+
+ticketage_out_of_lifetime_anti_replay() ->
+    [{doc, "Session resumption with stateless tickets and anti_replay enabled."
+      "Fresh ClientHello."
+      "Ticket age beyond its lifetime. 0-RTT is expected to fail."
+      "(Erlang client - Erlang server)"}].
+ticketage_out_of_lifetime_anti_replay(Config) when is_list(Config) ->
+    Lifetime = 4,
+    WindowSize = 2,
+    {Server0, Client0, Port0, ClientNode, Hostname, ClientOpts} =
+        anti_replay_helper_init(Config, auto, WindowSize, Lifetime),
+    ssl_test_lib:check_result(Server0, ok, Client0, ok),
+    Client1 = anti_replay_helper_connect(Server0, Client0, Port0, ClientNode,
+                                         Hostname, ClientOpts,
+                                         {seconds, Lifetime + 2}, false),
+    process_flag(trap_exit, false),
+    [ssl_test_lib:close(A) || A <- [Server0, Client0, Client1]].
+
+ticket_reuse_anti_replay() ->
+    [{doc, "Verify that 2 connection attempts with same stateless tickets "
+      "are successful."
+      "Fresh ClientHellos."
+      "Ticket age smaller than windowsize."
+      "Anti_replay allows it because both "
+      "ClientHellos are unique, look fresh(small enough DeltaAge) "
+      "and do not look like a replay attempt."
+      "(Erlang client - Erlang server)"}].
+ticket_reuse_anti_replay(Config) when is_list(Config) ->
+    {Server0, Client0, Port0, ClientNode, Hostname, ClientOpts0} =
+        anti_replay_helper_init(Config, manual, 10),
+    [Ticket] = ssl_test_lib:check_tickets(Client0),
+    ssl_test_lib:check_result(Server0, ok),
+    ClientOpts1 = [{use_ticket, [Ticket]} | ClientOpts0],
+    Client1 = anti_replay_helper_connect(Server0, Client0, Port0, ClientNode,
+                                         Hostname, ClientOpts1, 0, true),
+    Client2 = anti_replay_helper_connect(Server0, Client1, Port0, ClientNode,
+                                         Hostname, ClientOpts1, 0, true),
+    process_flag(trap_exit, false),
+    [ssl_test_lib:close(A) || A <- [Server0, Client0, Client2]].
+
+ticket_reuse_anti_replay_server_restart() ->
+    [{doc, "Verify 2 connection attempts with same stateless tickets "
+      "and server restart between. Second attempt is expected to fail as long as "
+      "Bloom filter window overlaps with startup time."
+      "Fresh ClientHellos."
+      "(Erlang client - Erlang server)"
+
+      "RFC8446 8.2: When implementations are freshly started, they SHOULD reject "
+      "0-RTT as long as any portion of their recording window overlaps the startup "
+      "time. Otherwise, they run the risk of accepting replays which were "
+      "originally sent during that period."
+     }].
+ticket_reuse_anti_replay_server_restart(Config) when is_list(Config) ->
+    WindowSize = 10,
+    {Server0, Client0, Port0, ClientNode, Hostname, ClientOpts0} =
+        anti_replay_helper_init(Config, manual, WindowSize),
+    [Ticket] = ssl_test_lib:check_tickets(Client0),
+    ssl_test_lib:check_result(Server0, ok),
+    ClientOpts1 = [{use_ticket, [Ticket]} | ClientOpts0],
+    Client1 = anti_replay_helper_connect(Server0, Client0, Port0, ClientNode,
+                                         Hostname, ClientOpts1, 0, true),
+    {Server1, Port1} = anti_replay_helper_start_server(Config, WindowSize),
+    Client2 = anti_replay_helper_connect(Server1, Client1, Port1, ClientNode,
+                                         Hostname, ClientOpts1, 0, false, false),
+    process_flag(trap_exit, false),
+    [ssl_test_lib:close(A) || A <- [Server0, Client2, Server1]].
+
+anti_replay_helper_init(Config, Mode, WindowSize) ->
+    DefaultLifetime = ssl_config:get_ticket_lifetime(),
+    anti_replay_helper_init(Config, Mode, WindowSize, DefaultLifetime).
+
+anti_replay_helper_init(Config, Mode, WindowSize, Lifetime) ->
+    application:set_env(ssl, server_session_ticket_lifetime, Lifetime),
     ClientOpts0 = ssl_test_lib:ssl_options(client_rsa_verify_opts, Config),
+    {ClientNode, _ServerNode, Hostname} = ssl_test_lib:run_where(Config),
+    %% Configure session tickets
+    ClientOpts = [{session_tickets, Mode},
+                  {versions, ['tlsv1.2','tlsv1.3']} | ClientOpts0],
+
+    {Server0 , Port0} = anti_replay_helper_start_server(Config, WindowSize),
+    MFA = case Mode of
+              auto ->
+                  {ssl_test_lib,
+                   verify_active_session_resumption,
+                   [false]};
+              manual ->
+                  {ssl_test_lib,
+                   verify_active_session_resumption,
+                   [false, wait_reply, {tickets, 1}]}
+          end,
+
+    %% Store ticket from first connection
+    Client0 = ssl_test_lib:start_client([{node, ClientNode},
+                                         {port, Port0}, {host, Hostname},
+                                         {mfa, MFA},
+                                         {from, self()}, {options, ClientOpts}]),
+    {Server0, Client0, Port0, ClientNode, Hostname, ClientOpts}.
+
+anti_replay_helper_start_server(Config, WindowSize) ->
+    {_ClientNode, ServerNode, _Hostname} = ssl_test_lib:run_where(Config),
     ServerOpts0 = ssl_test_lib:ssl_options(server_rsa_verify_opts, Config),
-    {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
     ServerTicketMode = proplists:get_value(server_ticket_mode, Config),
-
-    %% Configure session tickets
-    ClientOpts = [{session_tickets, auto},
-                  {versions, ['tlsv1.2','tlsv1.3']}|ClientOpts0],
     ServerOpts = [{session_tickets, ServerTicketMode},
-                  {anti_replay, '10k'},
+                  {anti_replay, {WindowSize, 5, 72985}},
                   {versions, ['tlsv1.2','tlsv1.3']}|ServerOpts0],
 
-    Server0 =
+    Server =
 	ssl_test_lib:start_server([{node, ServerNode}, {port, 0},
 				   {from, self()},
 				   {mfa, {ssl_test_lib,
                                           verify_active_session_resumption,
                                           [false]}},
 				   {options, ServerOpts}]),
-    Port0 = ssl_test_lib:inet_port(Server0),
-
-    %% Store ticket from first connection
-    Client0 = ssl_test_lib:start_client([{node, ClientNode},
-                                         {port, Port0}, {host, Hostname},
-                                         {mfa, {ssl_test_lib,  %% Full handshake
-                                                verify_active_session_resumption,
-                                                [false]}},
-                                         {from, self()}, {options, ClientOpts}]),
-    ssl_test_lib:check_result(Server0, ok, Client0, ok),
-
-    Server0 ! {listen, {mfa, {ssl_test_lib,
-                              verify_active_session_resumption,
-                              [true]}}},
+    Port0 = ssl_test_lib:inet_port(Server),
+    {Server, Port0}.
+
+anti_replay_helper_connect(Server, Client0, Port0, ClientNode, Hostname,
+                           ClientOpts, Delay, ExpectedResumption) ->
+    anti_replay_helper_connect(Server, Client0, Port0, ClientNode, Hostname,
+                               ClientOpts, Delay, ExpectedResumption, true).
+
+anti_replay_helper_connect(Server, Client0, Port0, ClientNode, Hostname,
+                           ClientOpts, Delay, ExpectedResumption, SendListen) ->
+    case SendListen of
+        true ->
+            Server ! {listen, {mfa, {ssl_test_lib,
+                                     verify_active_session_resumption,
+                                     [ExpectedResumption]}}};
+        _ ->
+            ok
+    end,
 
     %% Wait for session ticket
     ct:sleep(100),
-
     ssl_test_lib:close(Client0),
-
+    ct:sleep(Delay),
     %% Use ticket
     Client1 = ssl_test_lib:start_client([{node, ClientNode},
                                          {port, Port0}, {host, Hostname},
                                          {mfa, {ssl_test_lib,  %% Short handshake
                                                 verify_active_session_resumption,
-                                                [true]}},
+                                                [ExpectedResumption]}},
                                          {from, self()}, {options, ClientOpts}]),
-    ssl_test_lib:check_result(Server0, ok, Client1, ok),
-
-    process_flag(trap_exit, false),
-    ssl_test_lib:close(Server0),
-    ssl_test_lib:close(Client1).
+    ssl_test_lib:check_result(Server, ok, Client1, ok),
+    Client1.
 
 basic_stateful_stateless() ->
     [{doc,"Test session resumption with session tickets (erlang client - erlang server)"}].
-- 
2.35.3

openSUSE Build Service is sponsored by