diff options
Diffstat (limited to 'lib/ssl')
-rw-r--r-- | lib/ssl/src/ssl.erl | 39 | ||||
-rw-r--r-- | lib/ssl/test/ssl_npn_handshake_SUITE.erl | 187 | ||||
-rw-r--r-- | lib/ssl/test/ssl_npn_hello_SUITE.erl | 6 |
3 files changed, 166 insertions, 66 deletions
diff --git a/lib/ssl/src/ssl.erl b/lib/ssl/src/ssl.erl index c72c4d7a93..9a562aa5a8 100644 --- a/lib/ssl/src/ssl.erl +++ b/lib/ssl/src/ssl.erl @@ -746,22 +746,39 @@ validate_option(hibernate_after, Value) when is_integer(Value), Value >= 0 -> validate_option(erl_dist,Value) when Value == true; Value == false -> Value; -validate_option(client_preferred_next_protocols, {Precedence, PreferredProtocols}) +validate_option(client_preferred_next_protocols = Opt, {Precedence, PreferredProtocols} = Value) when is_list(PreferredProtocols) -> - validate_binary_list(client_preferred_next_protocols, PreferredProtocols), - validate_npn_ordering(Precedence), - {Precedence, PreferredProtocols, ?NO_PROTOCOL}; -validate_option(client_preferred_next_protocols, {Precedence, PreferredProtocols, Default} = Value) + case ssl_record:highest_protocol_version([]) of + {3,0} -> + throw({error, {eoptions, {not_supported_in_sslv3, {Opt, Value}}}}); + _ -> + validate_binary_list(client_preferred_next_protocols, PreferredProtocols), + validate_npn_ordering(Precedence), + {Precedence, PreferredProtocols, ?NO_PROTOCOL} + end; +validate_option(client_preferred_next_protocols = Opt, {Precedence, PreferredProtocols, Default} = Value) when is_list(PreferredProtocols), is_binary(Default), byte_size(Default) > 0, byte_size(Default) < 256 -> - validate_binary_list(client_preferred_next_protocols, PreferredProtocols), - validate_npn_ordering(Precedence), - Value; + case ssl_record:highest_protocol_version([]) of + {3,0} -> + throw({error, {eoptions, {not_supported_in_sslv3, {Opt, Value}}}}); + _ -> + validate_binary_list(client_preferred_next_protocols, PreferredProtocols), + validate_npn_ordering(Precedence), + Value + end; + validate_option(client_preferred_next_protocols, undefined) -> undefined; -validate_option(next_protocols_advertised, Value) when is_list(Value) -> - validate_binary_list(next_protocols_advertised, Value), - Value; +validate_option(next_protocols_advertised = Opt, Value) when is_list(Value) -> + case ssl_record:highest_protocol_version([]) of + {3,0} -> + throw({error, {eoptions, {not_supported_in_sslv3, {Opt, Value}}}}); + _ -> + validate_binary_list(next_protocols_advertised, Value), + Value + end; + validate_option(next_protocols_advertised, undefined) -> undefined; validate_option(Opt, Value) -> diff --git a/lib/ssl/test/ssl_npn_handshake_SUITE.erl b/lib/ssl/test/ssl_npn_handshake_SUITE.erl index eef09f42f2..cfeb328e21 100644 --- a/lib/ssl/test/ssl_npn_handshake_SUITE.erl +++ b/lib/ssl/test/ssl_npn_handshake_SUITE.erl @@ -26,6 +26,39 @@ suite() -> [{ct_hooks,[ts_install_cth]}]. +all() -> + [{group, 'tlsv1.2'}, + {group, 'tlsv1.1'}, + {group, 'tlsv1'}, + {group, 'sslv3'}]. + +groups() -> + [ + {'tlsv1.2', [], next_protocol_tests()}, + {'tlsv1.1', [], next_protocol_tests()}, + {'tlsv1', [], next_protocol_tests()}, + {'sslv3', [], next_protocol_not_supported()} + ]. + +next_protocol_tests() -> + [validate_empty_protocols_are_not_allowed, + validate_empty_advertisement_list_is_allowed, + validate_advertisement_must_be_a_binary_list, + validate_client_protocols_must_be_a_tuple, + normal_npn_handshake_server_preference, + normal_npn_handshake_client_preference, + fallback_npn_handshake, + fallback_npn_handshake_server_preference, + client_tries_to_negotiate_but_server_does_not_support, + client_does_not_try_to_negotiate_but_server_supports_npn, + renegotiate_from_client_after_npn_handshake + ]. + +next_protocol_not_supported() -> + [npn_not_supported_client, + npn_not_supported_server + ]. + init_per_suite(Config) -> catch crypto:stop(), try crypto:start() of @@ -46,23 +79,30 @@ end_per_suite(_Config) -> application:stop(crypto). -all() -> - [validate_empty_protocols_are_not_allowed_test, - validate_empty_advertisement_list_is_allowed_test, - validate_advertisement_must_be_a_binary_list_test, - validate_client_protocols_must_be_a_tuple_test, - perform_normal_npn_handshake_server_preference_test, - perform_normal_npn_handshake_client_preference_test, - perform_fallback_npn_handshake_test, - perform_fallback_npn_handshake_server_preference_test, - perform_client_tries_to_negotiate_but_server_does_not_support_test, - perform_client_does_not_try_to_negotiate_but_server_supports_npn_test, - perform_renegotiate_from_client_after_npn_handshake]. +init_per_group(GroupName, Config) -> + case ssl_test_lib:is_tls_version(GroupName) of + true -> + case ssl_test_lib:sufficient_crypto_support(GroupName) of + true -> + ssl_test_lib:init_tls_version(GroupName), + Config; + false -> + {skip, "Missing crypto support"} + end; + _ -> + ssl:start(), + Config + end. -connection_info_result(Socket) -> - ssl:connection_info(Socket). -validate_empty_protocols_are_not_allowed_test(_Config) -> +end_per_group(_GroupName, Config) -> + Config. + + +%% Test cases starts here. +%%-------------------------------------------------------------------- + +validate_empty_protocols_are_not_allowed(Config) when is_list(Config) -> {error, {eoptions, {next_protocols_advertised, {invalid_protocol, <<>>}}}} = (catch ssl:listen(9443, [{next_protocols_advertised, [<<"foo/1">>, <<"">>]}])), @@ -73,64 +113,75 @@ validate_empty_protocols_are_not_allowed_test(_Config) -> Option = {client_preferred_next_protocols, {invalid_protocol, <<"">>}}, {error, {eoptions, Option}} = (catch ssl:connect({127,0,0,1}, 9443, [Option], infinity)). -validate_empty_advertisement_list_is_allowed_test(_Config) -> +%-------------------------------------------------------------------------------- + +validate_empty_advertisement_list_is_allowed(Config) when is_list(Config) -> Option = {next_protocols_advertised, []}, {ok, Socket} = ssl:listen(0, [Option]), ssl:close(Socket). +%-------------------------------------------------------------------------------- -validate_advertisement_must_be_a_binary_list_test(_Config) -> +validate_advertisement_must_be_a_binary_list(Config) when is_list(Config) -> Option = {next_protocols_advertised, blah}, {error, {eoptions, Option}} = (catch ssl:listen(9443, [Option])). +%-------------------------------------------------------------------------------- -validate_client_protocols_must_be_a_tuple_test(_Config) -> +validate_client_protocols_must_be_a_tuple(Config) when is_list(Config) -> Option = {client_preferred_next_protocols, [<<"foo/1">>]}, {error, {eoptions, Option}} = (catch ssl:connect({127,0,0,1}, 9443, [Option])). +%-------------------------------------------------------------------------------- +normal_npn_handshake_server_preference(Config) when is_list(Config) -> + run_npn_handshake(Config, + [{client_preferred_next_protocols, + {server, [<<"http/1.0">>, <<"http/1.1">>], <<"http/1.1">>}}], + [{next_protocols_advertised, [<<"spdy/2">>, <<"http/1.1">>, <<"http/1.0">>]}], + {ok, <<"http/1.1">>}). +%-------------------------------------------------------------------------------- -perform_client_does_not_try_to_negotiate_but_server_supports_npn_test(Config) -> - run_npn_handshake_test(Config, - [], - [{next_protocols_advertised, [<<"spdy/1">>, <<"http/1.1">>, <<"http/1.0">>]}], - {error, next_protocol_not_negotiated}). +normal_npn_handshake_client_preference(Config) when is_list(Config) -> + run_npn_handshake(Config, + [{client_preferred_next_protocols, + {client, [<<"http/1.0">>, <<"http/1.1">>], <<"http/1.1">>}}], + [{next_protocols_advertised, [<<"spdy/2">>, <<"http/1.1">>, <<"http/1.0">>]}], + {ok, <<"http/1.0">>}). -perform_client_tries_to_negotiate_but_server_does_not_support_test(Config) -> - run_npn_handshake_test(Config, - [{client_preferred_next_protocols, {client, [<<"spdy/2">>], <<"http/1.1">>}}], - [], - {error, next_protocol_not_negotiated}). +%-------------------------------------------------------------------------------- -perform_fallback_npn_handshake_test(Config) -> - run_npn_handshake_test(Config, - [{client_preferred_next_protocols, {client, [<<"spdy/2">>], <<"http/1.1">>}}], - [{next_protocols_advertised, [<<"spdy/1">>, <<"http/1.1">>, <<"http/1.0">>]}], - {ok, <<"http/1.1">>}). +fallback_npn_handshake(Config) when is_list(Config) -> + run_npn_handshake(Config, + [{client_preferred_next_protocols, {client, [<<"spdy/2">>], <<"http/1.1">>}}], + [{next_protocols_advertised, [<<"spdy/1">>, <<"http/1.1">>, <<"http/1.0">>]}], + {ok, <<"http/1.1">>}). +%-------------------------------------------------------------------------------- -perform_fallback_npn_handshake_server_preference_test(Config) -> - run_npn_handshake_test(Config, - [{client_preferred_next_protocols, {server, [<<"spdy/2">>], <<"http/1.1">>}}], - [{next_protocols_advertised, [<<"spdy/1">>, <<"http/1.1">>, <<"http/1.0">>]}], - {ok, <<"http/1.1">>}). +fallback_npn_handshake_server_preference(Config) when is_list(Config) -> + run_npn_handshake(Config, + [{client_preferred_next_protocols, {server, [<<"spdy/2">>], <<"http/1.1">>}}], + [{next_protocols_advertised, [<<"spdy/1">>, <<"http/1.1">>, <<"http/1.0">>]}], + {ok, <<"http/1.1">>}). +%-------------------------------------------------------------------------------- -perform_normal_npn_handshake_client_preference_test(Config) -> - run_npn_handshake_test(Config, - [{client_preferred_next_protocols, - {client, [<<"http/1.0">>, <<"http/1.1">>], <<"http/1.1">>}}], - [{next_protocols_advertised, [<<"spdy/2">>, <<"http/1.1">>, <<"http/1.0">>]}], - {ok, <<"http/1.0">>}). +client_does_not_try_to_negotiate_but_server_supports_npn(Config) when is_list(Config) -> + run_npn_handshake(Config, + [], + [{next_protocols_advertised, [<<"spdy/1">>, <<"http/1.1">>, <<"http/1.0">>]}], + {error, next_protocol_not_negotiated}). +%-------------------------------------------------------------------------------- -perform_normal_npn_handshake_server_preference_test(Config) -> - run_npn_handshake_test(Config, - [{client_preferred_next_protocols, - {server, [<<"http/1.0">>, <<"http/1.1">>], <<"http/1.1">>}}], - [{next_protocols_advertised, [<<"spdy/2">>, <<"http/1.1">>, <<"http/1.0">>]}], - {ok, <<"http/1.1">>}). +client_tries_to_negotiate_but_server_does_not_support(Config) when is_list(Config) -> + run_npn_handshake(Config, + [{client_preferred_next_protocols, {client, [<<"spdy/2">>], <<"http/1.1">>}}], + [], + {error, next_protocol_not_negotiated}). -perform_renegotiate_from_client_after_npn_handshake(Config) -> +%-------------------------------------------------------------------------------- +renegotiate_from_client_after_npn_handshake(Config) when is_list(Config) -> Data = "hello world", - + ClientOpts0 = ?config(client_opts, Config), ClientOpts = [{client_preferred_next_protocols, {client, [<<"http/1.0">>], <<"http/1.1">>}}] ++ ClientOpts0, @@ -155,8 +206,33 @@ perform_renegotiate_from_client_after_npn_handshake(Config) -> ssl_test_lib:check_result(Server, ok, Client, ok). %-------------------------------------------------------------------------------- +npn_not_supported_client(Config) when is_list(Config) -> + ClientOpts0 = ?config(client_opts, Config), + PrefProtocols = {client_preferred_next_protocols, + {client, [<<"http/1.0">>], <<"http/1.1">>}}, + ClientOpts = [PrefProtocols] ++ ClientOpts0, + {ClientNode, _ServerNode, Hostname} = ssl_test_lib:run_where(Config), + Client = ssl_test_lib:start_client_error([{node, ClientNode}, + {port, 8888}, {host, Hostname}, + {from, self()}, {options, ClientOpts}]), + + ssl_test_lib:check_result(Client, {error, + {eoptions, + {not_supported_in_sslv3, PrefProtocols}}}). + +%-------------------------------------------------------------------------------- +npn_not_supported_server(Config) when is_list(Config)-> + ServerOpts0 = ?config(server_opts, Config), + AdvProtocols = {next_protocols_advertised, [<<"spdy/2">>, <<"http/1.1">>, <<"http/1.0">>]}, + ServerOpts = [AdvProtocols] ++ ServerOpts0, + + {error, {eoptions, {not_supported_in_sslv3, AdvProtocols}}} = ssl:listen(0, ServerOpts). -run_npn_handshake_test(Config, ClientExtraOpts, ServerExtraOpts, ExpectedProtocol) -> +%%-------------------------------------------------------------------- +%%% Internal functions +%%-------------------------------------------------------------------- + +run_npn_handshake(Config, ClientExtraOpts, ServerExtraOpts, ExpectedProtocol) -> Data = "hello world", ClientOpts0 = ?config(client_opts, Config), @@ -179,6 +255,7 @@ run_npn_handshake_test(Config, ClientExtraOpts, ServerExtraOpts, ExpectedProtoco ssl_test_lib:check_result(Server, ok, Client, ok). + assert_npn(Socket, Protocol) -> test_server:format("Negotiated Protocol ~p, Expecting: ~p ~n", [ssl:negotiated_next_protocol(Socket), Protocol]), @@ -227,3 +304,7 @@ ssl_receive(Socket, Data, Buffer) -> after 4000 -> test_server:fail({did_not_get, Data}) end. + + +connection_info_result(Socket) -> + ssl:connection_info(Socket). diff --git a/lib/ssl/test/ssl_npn_hello_SUITE.erl b/lib/ssl/test/ssl_npn_hello_SUITE.erl index 0bca8bbeb4..5102c74e87 100644 --- a/lib/ssl/test/ssl_npn_hello_SUITE.erl +++ b/lib/ssl/test/ssl_npn_hello_SUITE.erl @@ -111,5 +111,7 @@ create_server_hello_with_no_advertised_protocols_test(_Config) -> undefined = Hello#server_hello.next_protocol_negotiation. create_server_hello_with_advertised_protocols_test(_Config) -> - Hello = ssl_handshake:server_hello(<<>>, {3, 0}, create_connection_states(), false, [<<"spdy/1">>, <<"http/1.0">>, <<"http/1.1">>]), - #next_protocol_negotiation{extension_data = <<6, "spdy/1", 8, "http/1.0", 8, "http/1.1">>} = Hello#server_hello.next_protocol_negotiation. + Hello = ssl_handshake:server_hello(<<>>, {3, 0}, create_connection_states(), + false, [<<"spdy/1">>, <<"http/1.0">>, <<"http/1.1">>]), + #next_protocol_negotiation{extension_data = <<6, "spdy/1", 8, "http/1.0", 8, "http/1.1">>} = + Hello#server_hello.next_protocol_negotiation. |