Sign Up
Log In
Log In
or
Sign Up
Places
All Projects
Status Monitor
Collapse sidebar
home:Ledest:erlang
erlang
2802-Reject-stateless-tickets-until-2-WindowSiz...
Overview
Repositories
Revisions
Requests
Users
Attributes
Meta
File 2802-Reject-stateless-tickets-until-2-WindowSize-has-pass.patch of Package erlang
From 489c3a3f86eab939d5e4b6bbb1a7c0f4f618a577 Mon Sep 17 00:00:00 2001 From: Anders Kiel Hovgaard <anders.hovgaard@motorolasolutions.com> Date: Thu, 7 Jul 2022 11:40:39 +0200 Subject: [PATCH 2/2] Reject stateless tickets until 2*WindowSize has passed As per RFC 8446 8.2 Client Hello Recording: "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." Before the `stateless_tickets_seed` option, when ticket encryption secrets were generated upon socket creation, this wasn't necessary since tickets from a previous instance of a server were not usable anyway. The "warm-up" is only enabled when the `stateless_tickets_seed` option is specified, such that this change doesn't affect legacy flows when the options isn't specified. Only enable warm up when seed option is specified --- lib/ssl/src/tls_server_session_ticket.erl | 25 +++++++++++-- lib/ssl/test/ssl_session_ticket_SUITE.erl | 43 ++++++++++++++++++++++- 2 files changed, 65 insertions(+), 3 deletions(-) diff --git a/lib/ssl/src/tls_server_session_ticket.erl b/lib/ssl/src/tls_server_session_ticket.erl index 08f3b19111..609df77f1f 100644 --- a/lib/ssl/src/tls_server_session_ticket.erl +++ b/lib/ssl/src/tls_server_session_ticket.erl @@ -122,10 +122,13 @@ handle_cast(_Request, State) -> {noreply, NewState :: term()}. handle_info(rotate_bloom_filters, #state{stateless = #{bloom_filter := BloomFilter0, + warm_up_windows_remaining := WarmUp0, window := Window} = Stateless} = State) -> BloomFilter = tls_bloom_filter:rotate(BloomFilter0), erlang:send_after(Window * 1000, self(), rotate_bloom_filters), - {noreply, State#state{stateless = Stateless#{bloom_filter => BloomFilter}}}; + WarmUp = max(WarmUp0 - 1, 0), + {noreply, State#state{stateless = Stateless#{bloom_filter => BloomFilter, + warm_up_windows_remaining => WarmUp}}}; handle_info({'DOWN', Monitor, _, _, _}, #state{listen_monitor = Monitor} = State) -> {stop, normal, State}; handle_info(_Info, State) -> @@ -163,6 +166,7 @@ inital_state([stateless, Lifetime, _, MaxEarlyDataSize, {Window, K, M}, Seed]) - erlang:send_after(Window * 1000, self(), rotate_bloom_filters), #state{nonce = 0, stateless = #{bloom_filter => tls_bloom_filter:new(K, M), + warm_up_windows_remaining => warm_up_windows(Seed), seed => stateless_seed(Seed), window => Window}, lifetime = Lifetime, @@ -431,7 +435,15 @@ in_window(_, undefined) -> in_window(Age, Window) when is_integer(Window) -> Age =< Window. -stateless_anti_replay(Index, PSK, Binder, +stateless_anti_replay(_Index, _PSK, _Binder, + #state{stateless = #{warm_up_windows_remaining := WarmUpRemaining} + } = State) when WarmUpRemaining > 0 -> + %% Reject all tickets during the warm-up period: + %% RFC 8446 8.2 Client Hello Recording + %% "When implementations are freshly started, they SHOULD reject 0-RTT as + %% long as any portion of their recording window overlaps the startup time." + {{ok, undefined}, State}; +stateless_anti_replay(Index, PSK, Binder, #state{stateless = #{bloom_filter := BloomFilter0} = Stateless} = State) -> case tls_bloom_filter:contains(BloomFilter0, Binder) of @@ -453,3 +465,12 @@ stateless_seed(undefined) -> stateless_seed(Seed) -> <<IV:16/binary, Shard:32/binary, _/binary>> = crypto:hash(sha512, Seed), {IV, Shard}. + +-spec warm_up_windows(Seed :: undefined | binary()) -> 0 | 2. +warm_up_windows(undefined) -> + 0; +warm_up_windows(_) -> + %% When the encryption seed is specified, "warm up" the bloom filter for + %% 2*WindowSize to ensure tickets from a previous instance of the server + %% (before a restart) cannot be reused, if the ticket encryption seed is reused. + 2. diff --git a/lib/ssl/test/ssl_session_ticket_SUITE.erl b/lib/ssl/test/ssl_session_ticket_SUITE.erl index 6000117f6f..9bb57c6f8d 100644 --- a/lib/ssl/test/ssl_session_ticket_SUITE.erl +++ b/lib/ssl/test/ssl_session_ticket_SUITE.erl @@ -45,6 +45,8 @@ ticket_reuse_anti_replay/1, ticket_reuse_anti_replay_server_restart/0, ticket_reuse_anti_replay_server_restart/1, + ticket_reuse_anti_replay_server_restart_reused_seed/0, + ticket_reuse_anti_replay_server_restart_reused_seed/1, basic_stateful_stateless/0, basic_stateful_stateless/1, basic_stateless_stateful/0, @@ -107,6 +109,7 @@ groups() -> ticketage_bigger_than_windowsize_anti_replay, ticketage_out_of_lifetime_anti_replay, ticket_reuse_anti_replay, ticket_reuse_anti_replay_server_restart, + ticket_reuse_anti_replay_server_restart_reused_seed, stateless_multiple_servers]}, {mixed, [], mixed_tests()}]. @@ -328,6 +331,36 @@ ticket_reuse_anti_replay_server_restart(Config) when is_list(Config) -> process_flag(trap_exit, false), [ssl_test_lib:close(A) || A <- [Server0, Client2, Server1]]. +ticket_reuse_anti_replay_server_restart_reused_seed() -> + [{doc, "Verify 2 connection attempts with same stateless tickets " + "and server restart between, with the server using the same session " + "ticket encryption seed between restarts. Second attempt is expected to " + "fail as long as the Bloom filter window overlaps with startup time." + }]. +ticket_reuse_anti_replay_server_restart_reused_seed(Config) when is_list(Config) -> + WindowSize = 10, + Seed = crypto:strong_rand_bytes(32), + Config1 = [{server_ticket_seed, Seed} | Config], + {Server1 , Port1} = anti_replay_helper_start_server(Config1, WindowSize), + {ClientNode, _ServerNode, Hostname} = ssl_test_lib:run_where(Config), + ClientOpts0 = ssl_test_lib:ssl_options(client_rsa_verify_opts, Config), + ClientOpts1 = [{session_tickets, manual}, + {versions, ['tlsv1.2','tlsv1.3']} | ClientOpts0], + Client1 = ssl_test_lib:start_client([{node, ClientNode}, + {port, Port1}, {host, Hostname}, + {mfa, {ssl_test_lib, %% full handshake + verify_active_session_resumption, + [false, wait_reply, {tickets, 1}]}}, + {from, self()}, {options, ClientOpts1}]), + [Ticket] = ssl_test_lib:check_tickets(Client1), + ssl_test_lib:check_result(Server1, ok), + ClientOpts2 = [{use_ticket, [Ticket]} | ClientOpts1], + {Server2, Port2} = anti_replay_helper_start_server(Config1, WindowSize), + Client2 = anti_replay_helper_connect(Server2, Client1, Port2, ClientNode, + Hostname, ClientOpts2, 0, false, false), + process_flag(trap_exit, false), + [ssl_test_lib:close(A) || A <- [Server1, Client2, Server2]]. + anti_replay_helper_init(Config, Mode, WindowSize) -> DefaultLifetime = ssl_config:get_ticket_lifetime(), anti_replay_helper_init(Config, Mode, WindowSize, DefaultLifetime). @@ -363,9 +396,17 @@ 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), ServerTicketMode = proplists:get_value(server_ticket_mode, Config), + ServerTicketSeed = + case proplists:get_value(server_ticket_seed, Config) of + undefined -> + []; + Seed -> + [{stateless_tickets_seed, Seed}] + end, ServerOpts = [{session_tickets, ServerTicketMode}, {anti_replay, {WindowSize, 5, 72985}}, - {versions, ['tlsv1.2','tlsv1.3']}|ServerOpts0], + {versions, ['tlsv1.2','tlsv1.3']}|ServerOpts0 + ] ++ ServerTicketSeed, Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0}, -- 2.35.3
Locations
Projects
Search
Status Monitor
Help
OpenBuildService.org
Documentation
API Documentation
Code of Conduct
Contact
Support
@OBShq
Terms
openSUSE Build Service is sponsored by
The Open Build Service is an
openSUSE project
.
Sign Up
Log In
Places
Places
All Projects
Status Monitor