aboutsummaryrefslogtreecommitdiffstats
path: root/lib
diff options
context:
space:
mode:
Diffstat (limited to 'lib')
-rw-r--r--lib/compiler/src/beam_type.erl44
-rw-r--r--lib/dialyzer/doc/src/dialyzer.xml7
-rw-r--r--lib/dialyzer/src/dialyzer_options.erl3
-rw-r--r--lib/dialyzer/test/plt_SUITE.erl37
-rw-r--r--lib/kernel/test/prim_file_SUITE.erl47
-rw-r--r--lib/sasl/test/systools_SUITE.erl16
-rw-r--r--lib/ssh/src/ssh_connection_handler.erl168
-rw-r--r--lib/ssh/src/ssh_transport.erl4
-rw-r--r--lib/ssl/test/ssl_ECC_SUITE.erl6
-rw-r--r--lib/ssl/test/ssl_certificate_verify_SUITE.erl561
-rw-r--r--lib/ssl/test/ssl_test_lib.erl31
-rw-r--r--lib/ssl/test/x509_test.erl82
-rw-r--r--lib/stdlib/doc/src/erl_tar.xml4
-rw-r--r--lib/stdlib/doc/src/re.xml10
-rw-r--r--lib/stdlib/src/erl_lint.erl63
-rw-r--r--lib/stdlib/src/erl_tar.erl59
-rw-r--r--lib/stdlib/src/re.erl7
-rw-r--r--lib/stdlib/test/erl_lint_SUITE.erl52
-rw-r--r--lib/stdlib/test/re_SUITE.erl14
-rw-r--r--lib/stdlib/test/tar_SUITE.erl37
-rw-r--r--lib/tools/src/lcnt.erl39
-rw-r--r--lib/tools/test/xref_SUITE.erl8
22 files changed, 716 insertions, 583 deletions
diff --git a/lib/compiler/src/beam_type.erl b/lib/compiler/src/beam_type.erl
index 2b5d558ee4..7e9a243ada 100644
--- a/lib/compiler/src/beam_type.erl
+++ b/lib/compiler/src/beam_type.erl
@@ -26,6 +26,8 @@
-import(lists, [filter/2,foldl/3,keyfind/3,member/2,
reverse/1,reverse/2,sort/1]).
+-define(UNICODE_INT, {integer,{0,16#10FFFF}}).
+
-spec module(beam_utils:module_code(), [compile:option()]) ->
{'ok',beam_utils:module_code()}.
@@ -494,6 +496,10 @@ update({test,test_arity,_Fail,[Src,Arity]}, Ts0) ->
tdb_update([{Src,{tuple,Arity,[]}}], Ts0);
update({test,is_map,_Fail,[Src]}, Ts0) ->
tdb_update([{Src,map}], Ts0);
+update({get_map_elements,_,Src,{list,Elems0}}, Ts0) ->
+ {_Ss,Ds} = beam_utils:split_even(Elems0),
+ Elems = [{Dst,kill} || Dst <- Ds],
+ tdb_update([{Src,map}|Elems], Ts0);
update({test,is_nonempty_list,_Fail,[Src]}, Ts0) ->
tdb_update([{Src,nonempty_list}], Ts0);
update({test,is_eq_exact,_,[Reg,{atom,_}=Atom]}, Ts) ->
@@ -507,10 +513,39 @@ update({test,is_eq_exact,_,[Reg,{atom,_}=Atom]}, Ts) ->
end;
update({test,is_record,_Fail,[Src,Tag,{integer,Arity}]}, Ts) ->
tdb_update([{Src,{tuple,Arity,[Tag]}}], Ts);
-update({test,_Test,_Fail,_Other}, Ts) ->
- Ts;
+
+%% Binary matching
+
update({test,bs_get_integer2,_,_,Args,Dst}, Ts) ->
tdb_update([{Dst,get_bs_integer_type(Args)}], Ts);
+update({test,bs_get_utf8,_,_,_,Dst}, Ts) ->
+ tdb_update([{Dst,?UNICODE_INT}], Ts);
+update({test,bs_get_utf16,_,_,_,Dst}, Ts) ->
+ tdb_update([{Dst,?UNICODE_INT}], Ts);
+update({test,bs_get_utf32,_,_,_,Dst}, Ts) ->
+ tdb_update([{Dst,?UNICODE_INT}], Ts);
+update({bs_init,_,_,_,_,Dst}, Ts) ->
+ tdb_update([{Dst,kill}], Ts);
+update({bs_put,_,_,_}, Ts) ->
+ Ts;
+update({bs_save2,_,_}, Ts) ->
+ Ts;
+update({bs_restore2,_,_}, Ts) ->
+ Ts;
+update({bs_context_to_binary,Dst}, Ts) ->
+ tdb_update([{Dst,kill}], Ts);
+update({test,bs_start_match2,_,_,_,Dst}, Ts) ->
+ tdb_update([{Dst,kill}], Ts);
+update({test,bs_get_binary2,_,_,_,Dst}, Ts) ->
+ tdb_update([{Dst,kill}], Ts);
+update({test,bs_get_float2,_,_,_,Dst}, Ts) ->
+ tdb_update([{Dst,float}], Ts);
+
+update({test,_Test,_Fail,_Other}, Ts) ->
+ Ts;
+
+%% Calls
+
update({call_ext,Ar,{extfunc,math,Math,Ar}}, Ts) ->
case is_math_bif(Math, Ar) of
true -> tdb_update([{{x,0},float}], Ts);
@@ -537,9 +572,10 @@ update({call_ext,3,{extfunc,erlang,setelement,3}}, Ts0) ->
update({call,_Arity,_Func}, Ts) -> tdb_kill_xregs(Ts);
update({call_ext,_Arity,_Func}, Ts) -> tdb_kill_xregs(Ts);
update({make_fun2,_,_,_,_}, Ts) -> tdb_kill_xregs(Ts);
+update({call_fun, _}, Ts) -> tdb_kill_xregs(Ts);
+update({apply, _}, Ts) -> tdb_kill_xregs(Ts);
+
update({line,_}, Ts) -> Ts;
-update({bs_save2,_,_}, Ts) -> Ts;
-update({bs_restore2,_,_}, Ts) -> Ts;
%% The instruction is unknown. Kill all information.
update(_I, _Ts) -> tdb_new().
diff --git a/lib/dialyzer/doc/src/dialyzer.xml b/lib/dialyzer/doc/src/dialyzer.xml
index 4b7eb4ad68..e34ffd6def 100644
--- a/lib/dialyzer/doc/src/dialyzer.xml
+++ b/lib/dialyzer/doc/src/dialyzer.xml
@@ -4,7 +4,7 @@
<erlref>
<header>
<copyright>
- <year>2006</year><year>2016</year>
+ <year>2006</year><year>2017</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
@@ -457,11 +457,6 @@ dialyzer --plts plt_1 ... plt_n -- files_to_analyze</code>
<c>gui/1</c></seealso> below (<c>WarnOpts</c>).</p>
<note>
- <p>Attribute <c>-dialyzer()</c> is not checked by the Erlang
- compiler, but by Dialyzer itself.</p>
- </note>
-
- <note>
<p>Warning option <c>-Wrace_conditions</c> has no effect when
set in source files.</p>
</note>
diff --git a/lib/dialyzer/src/dialyzer_options.erl b/lib/dialyzer/src/dialyzer_options.erl
index 616e8834f5..ec3f41311d 100644
--- a/lib/dialyzer/src/dialyzer_options.erl
+++ b/lib/dialyzer/src/dialyzer_options.erl
@@ -277,6 +277,9 @@ assert_solvers([Term|_]) ->
-spec build_warnings([atom()], dial_warn_tags()) -> dial_warn_tags().
+%% The warning options are checked by the code linter.
+%% The function erl_lint:is_module_dialyzer_option/1 must
+%% be updated if options are added or removed.
build_warnings([Opt|Opts], Warnings) ->
NewWarnings =
case Opt of
diff --git a/lib/dialyzer/test/plt_SUITE.erl b/lib/dialyzer/test/plt_SUITE.erl
index ba153c1c27..92c63bdb0c 100644
--- a/lib/dialyzer/test/plt_SUITE.erl
+++ b/lib/dialyzer/test/plt_SUITE.erl
@@ -259,26 +259,41 @@ remove_plt(Config) ->
{init_plt, Plt}] ++ Opts),
ok.
+%% ERL-283, OTP-13979. As of OTP-14323 this test no longer does what
+%% it is designed to do--the linter stops every attempt to run the
+%% checks of Dialyzer's on bad dialyzer attributes. For the time
+%% being, the linter's error message are checked instead. The test
+%% needs to be updated when/if the Dialyzer can analyze Core Erlang
+%% without compiling abstract code.
bad_dialyzer_attr(Config) ->
PrivDir = ?config(priv_dir, Config),
- Plt = filename:join(PrivDir, "plt_bad_dialyzer_attr.plt"),
+ Source = lists:concat([dial, ".erl"]),
+ Filename = filename:join(PrivDir, Source),
+ ok = dialyzer_common:check_plt(PrivDir),
+ PltFilename = dialyzer_common:plt_file(PrivDir),
+ Opts = [{files, [Filename]},
+ {check_plt, false},
+ {from, src_code},
+ {init_plt, PltFilename}],
+
Prog1 = <<"-module(dial).
-dialyzer({no_return, [undef/0]}).">>,
- {ok, Beam1} = compile(Config, Prog1, dial, []),
+ ok = file:write_file(Filename, Prog1),
{dialyzer_error,
- "Analysis failed with error:\n"
- "Could not scan the following file(s):\n"
- " Unknown function undef/0 in line " ++ _} =
- (catch run_dialyzer(plt_build, [Beam1], [{output_plt, Plt}])),
+ "Analysis failed with error:\n" ++ Str1} =
+ (catch dialyzer:run(Opts)),
+ P1 = string:str(Str1, "dial.erl:2: function undef/0 undefined"),
+ true = P1 > 0,
Prog2 = <<"-module(dial).
-dialyzer({no_return, [{undef,1,2}]}).">>,
- {ok, Beam2} = compile(Config, Prog2, dial, []),
+ ok = file:write_file(Filename, Prog2),
{dialyzer_error,
- "Analysis failed with error:\n"
- "Could not scan the following file(s):\n"
- " Bad function {undef,1,2} in line " ++ _} =
- (catch run_dialyzer(plt_build, [Beam2], [{output_plt, Plt}])),
+ "Analysis failed with error:\n" ++ Str2} =
+ (catch dialyzer:run(Opts)),
+ P2 = string:str(Str2, "dial.erl:2: badly formed dialyzer "
+ "attribute: {no_return,{undef,1,2}}"),
+ true = P2 > 0,
ok.
diff --git a/lib/kernel/test/prim_file_SUITE.erl b/lib/kernel/test/prim_file_SUITE.erl
index 8be94f1e57..0c84a7d1cc 100644
--- a/lib/kernel/test/prim_file_SUITE.erl
+++ b/lib/kernel/test/prim_file_SUITE.erl
@@ -19,8 +19,8 @@
%%
-module(prim_file_SUITE).
-export([all/0, suite/0,groups/0,init_per_suite/1, end_per_suite/1,
- init_per_group/2,end_per_group/2,
- read_write_file/1]).
+ init_per_group/2,end_per_group/2, init_per_testcase/2, end_per_testcase/2,
+ read_write_file/1, free_memory/0]).
-export([cur_dir_0a/1, cur_dir_0b/1,
cur_dir_1a/1, cur_dir_1b/1,
make_del_dir_a/1, make_del_dir_b/1,
@@ -115,6 +115,18 @@ groups() ->
[make_link_a, make_link_b, read_link_info_for_non_link,
symlinks_a, symlinks_b, list_dir_error]}].
+init_per_testcase(large_write, Config) ->
+ {ok, Started} = application:ensure_all_started(os_mon),
+ [{started, Started}|Config];
+init_per_testcase(_TestCase, Config) ->
+ Config.
+
+end_per_testcase(large_write, Config) ->
+ [application:stop(App) || App <- lists:reverse(proplists:get_value(started, Config))],
+ ok;
+end_per_testcase(_, _Config) ->
+ ok.
+
init_per_group(_GroupName, Config) ->
Config.
@@ -2022,11 +2034,13 @@ run_large_file_test(Config, Run, Name) ->
{{unix,sunos},OsVersion} when OsVersion < {5,5,1} ->
{skip,"Only supported on Win32, Unix or SunOS >= 5.5.1"};
{{unix,_},_} ->
- N = unix_free(proplists:get_value(priv_dir, Config)),
- io:format("Free disk: ~w KByte~n", [N]),
- if N < 5 bsl 20 ->
+ DiscFree = unix_free(proplists:get_value(priv_dir, Config)),
+ MemFree = free_memory(),
+ io:format("Free disk: ~w KByte~n", [DiscFree]),
+ io:format("Free mem: ~w MByte~n", [MemFree]),
+ if DiscFree < 5 bsl 20; MemFree < 5 bsl 10 ->
%% Less than 5 GByte free
- {skip,"Less than 5 GByte free disk"};
+ {skip,"Less than 5 GByte free disk/mem"};
true ->
do_run_large_file_test(Config, Run, Name)
end;
@@ -2079,6 +2093,27 @@ zip_data([], Bs) ->
zip_data(As, []) ->
As.
+%% Stolen from emulator -> alloc_SUITE
+free_memory() ->
+ %% Free memory in MB.
+ try
+ SMD = memsup:get_system_memory_data(),
+ {value, {free_memory, Free}} = lists:keysearch(free_memory, 1, SMD),
+ TotFree = (Free +
+ case lists:keysearch(cached_memory, 1, SMD) of
+ {value, {cached_memory, Cached}} -> Cached;
+ false -> 0
+ end +
+ case lists:keysearch(buffered_memory, 1, SMD) of
+ {value, {buffered_memory, Buffed}} -> Buffed;
+ false -> 0
+ end),
+ TotFree div (1024*1024)
+ catch
+ error : undef ->
+ ct:fail({"os_mon not built"})
+ end.
+
%%%-----------------------------------------------------------------
%%% Utilities
rm_rf(Mod,Dir) ->
diff --git a/lib/sasl/test/systools_SUITE.erl b/lib/sasl/test/systools_SUITE.erl
index 0c98232467..1a8bd3f607 100644
--- a/lib/sasl/test/systools_SUITE.erl
+++ b/lib/sasl/test/systools_SUITE.erl
@@ -87,25 +87,25 @@ end_per_group(_GroupName, Config) ->
init_per_suite(Config) when is_list(Config) ->
+ %% To use in end_per_testcase
+ Path = code:get_path(),
+ {ok,Cwd} = file:get_cwd(),
+
%% Make of copy of the data directory.
DataDir = ?datadir,
PrivDir = ?privdir,
CopyDir = fname(PrivDir, "datacopy"),
+ ok = file:make_dir(CopyDir),
TarFile = fname(PrivDir, "datacopy.tgz"),
- {ok, Tar} = erl_tar:open(TarFile, [write, compressed]),
- ok = erl_tar:add(Tar, DataDir, CopyDir, [compressed]),
- ok = erl_tar:close(Tar),
- ok = erl_tar:extract(TarFile, [compressed]),
+ ok = file:set_cwd(DataDir),
+ ok = erl_tar:create(TarFile, ["."], [compressed]),
+ ok = erl_tar:extract(TarFile, [compressed, {cwd,CopyDir}]),
ok = file:delete(TarFile),
%% Compile source files in the copy directory.
Sources = filelib:wildcard(fname([CopyDir,'*','*','*','*','*.erl'])),
lists:foreach(fun compile_source/1, Sources),
- %% To use in end_per_testcase
- Path = code:get_path(),
- {ok,Cwd} = file:get_cwd(),
-
[{copy_dir, CopyDir}, {cwd,Cwd}, {path,Path} | Config].
compile_source(File) ->
diff --git a/lib/ssh/src/ssh_connection_handler.erl b/lib/ssh/src/ssh_connection_handler.erl
index 84adf952e6..84bb7dc23f 100644
--- a/lib/ssh/src/ssh_connection_handler.erl
+++ b/lib/ssh/src/ssh_connection_handler.erl
@@ -60,7 +60,7 @@
]).
%%% Behaviour callbacks
--export([callback_mode/0, handle_event/4, terminate/3,
+-export([init/1, callback_mode/0, handle_event/4, terminate/3,
format_status/2, code_change/4]).
%%% Exports not intended to be used :). They are used for spawning and tests
@@ -337,8 +337,7 @@ renegotiate_data(ConnectionHandler) ->
transport_protocol :: atom(), % ex: tcp
transport_cb :: atom(), % ex: gen_tcp
transport_close_tag :: atom(), % ex: tcp_closed
- ssh_params :: #ssh{}
- | undefined,
+ ssh_params :: #ssh{},
socket :: inet:socket(),
decrypted_data_buffer = <<>> :: binary(),
encrypted_data_buffer = <<>> :: binary(),
@@ -362,71 +361,78 @@ renegotiate_data(ConnectionHandler) ->
) -> no_return().
%% . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
init_connection_handler(Role, Socket, Opts) ->
- process_flag(trap_exit, true),
- S0 = init_process_state(Role, Socket, Opts),
- try
- {Protocol, Callback, CloseTag} = ?GET_OPT(transport, Opts),
- S0#data{ssh_params = init_ssh_record(Role, Socket, Opts),
- transport_protocol = Protocol,
- transport_cb = Callback,
- transport_close_tag = CloseTag
- }
- of
- S ->
- gen_statem:enter_loop(?MODULE,
- [], %%[{debug,[trace,log,statistics,debug]} || Role==server],
- {hello,Role},
- S)
- catch
- _:Error ->
- gen_statem:enter_loop(?MODULE,
- [],
- {init_error,Error},
- S0)
- end.
-
-
-init_process_state(Role, Socket, Opts) ->
- D = #data{connection_state =
- C = #connection{channel_cache = ssh_channel:cache_create(),
- channel_id_seed = 0,
- port_bindings = [],
- requests = [],
- options = Opts},
- starter = ?GET_INTERNAL_OPT(user_pid, Opts),
- socket = Socket,
- opts = Opts
- },
- case Role of
- client ->
- %% Start the renegotiation timers
- timer:apply_after(?REKEY_TIMOUT, gen_statem, cast, [self(), renegotiate]),
- timer:apply_after(?REKEY_DATA_TIMOUT, gen_statem, cast, [self(), data_size]),
- cache_init_idle_timer(D);
- server ->
- cache_init_idle_timer(
- D#data{connection_state = init_connection(Role, C, Opts)}
- )
+ case init([Role, Socket, Opts]) of
+ {ok, StartState, D} ->
+ process_flag(trap_exit, true),
+ gen_statem:enter_loop(?MODULE,
+ [], %%[{debug,[trace,log,statistics,debug]} || Role==server],
+ StartState,
+ D);
+
+ {stop, enotconn} ->
+ %% Handles the abnormal sequence:
+ %% SYN->
+ %% <-SYNACK
+ %% ACK->
+ %% RST->
+ exit({shutdown, "TCP connection to server was prematurely closed by the client"});
+
+ {stop, OtherError} ->
+ exit({shutdown, {init,OtherError}})
end.
-init_connection(server, C = #connection{}, Opts) ->
- Sups = ?GET_INTERNAL_OPT(supervisors, Opts),
- SystemSup = proplists:get_value(system_sup, Sups),
- SubSystemSup = proplists:get_value(subsystem_sup, Sups),
- ConnectionSup = proplists:get_value(connection_sup, Sups),
+init([Role,Socket,Opts]) ->
+ case inet:peername(Socket) of
+ {ok, PeerAddr} ->
+ {Protocol, Callback, CloseTag} = ?GET_OPT(transport, Opts),
+ C = #connection{channel_cache = ssh_channel:cache_create(),
+ channel_id_seed = 0,
+ port_bindings = [],
+ requests = [],
+ options = Opts},
+ D0 = #data{starter = ?GET_INTERNAL_OPT(user_pid, Opts),
+ connection_state = C,
+ socket = Socket,
+ transport_protocol = Protocol,
+ transport_cb = Callback,
+ transport_close_tag = CloseTag,
+ ssh_params = init_ssh_record(Role, Socket, PeerAddr, Opts),
+ opts = Opts
+ },
+ D = case Role of
+ client ->
+ %% Start the renegotiation timers
+ timer:apply_after(?REKEY_TIMOUT, gen_statem, cast, [self(), renegotiate]),
+ timer:apply_after(?REKEY_DATA_TIMOUT, gen_statem, cast, [self(), data_size]),
+ cache_init_idle_timer(D0);
+ server ->
+ Sups = ?GET_INTERNAL_OPT(supervisors, Opts),
+ cache_init_idle_timer(
+ D0#data{connection_state =
+ C#connection{cli_spec = ?GET_OPT(ssh_cli, Opts, {ssh_cli,[?GET_OPT(shell, Opts)]}),
+ exec = ?GET_OPT(exec, Opts),
+ system_supervisor = proplists:get_value(system_sup, Sups),
+ sub_system_supervisor = proplists:get_value(subsystem_sup, Sups),
+ connection_supervisor = proplists:get_value(connection_sup, Sups)
+ }})
+ end,
+ {ok, {hello,Role}, D};
+
+ {error,Error} ->
+ {stop, Error}
+ end.
- C#connection{cli_spec = ?GET_OPT(ssh_cli, Opts, {ssh_cli,[?GET_OPT(shell, Opts)]}),
- exec = ?GET_OPT(exec, Opts),
- system_supervisor = SystemSup,
- sub_system_supervisor = SubSystemSup,
- connection_supervisor = ConnectionSup
- }.
init_ssh_record(Role, Socket, Opts) ->
- {ok, PeerAddr} = inet:peername(Socket),
+ %% Export of this internal function is
+ %% intended for low-level protocol test suites
+ {ok,PeerAddr} = inet:peername(Socket),
+ init_ssh_record(Role, Socket, PeerAddr, Opts).
+
+init_ssh_record(Role, _Socket, PeerAddr, Opts) ->
KeyCb = ?GET_OPT(key_cb, Opts),
AuthMethods =
case Role of
@@ -481,8 +487,7 @@ init_ssh_record(Role, Socket, Opts) ->
-type renegotiate_flag() :: init | renegotiate.
-type state_name() ::
- {init_error,any()}
- | {hello, role()}
+ {hello, role()}
| {kexinit, role(), renegotiate_flag()}
| {key_exchange, role(), renegotiate_flag()}
| {key_exchange_dh_gex_init, server, renegotiate_flag()}
@@ -504,26 +509,9 @@ init_ssh_record(Role, Socket, Opts) ->
%% . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
-%%% ######## Error in the initialisation ####
-
callback_mode() ->
handle_event_function.
-handle_event(_, _Event, {init_error,Error}, _) ->
- case Error of
- {badmatch,{error,enotconn}} ->
- %% Handles the abnormal sequence:
- %% SYN->
- %% <-SYNACK
- %% ACK->
- %% RST->
- {stop, {shutdown,"TCP connenction to server was prematurely closed by the client"}};
-
- OtherError ->
- {stop, {shutdown,{init,OtherError}}}
- end;
-
-
%%% ######## {hello, client|server} ####
%% The very first event that is sent when the we are set as controlling process of Socket
handle_event(_, socket_control, {hello,_}, D) ->
@@ -813,7 +801,7 @@ handle_event(_, #ssh_msg_userauth_info_request{} = Msg, {userauth_keyboard_inter
send_bytes(Reply, D),
{next_state, {userauth_keyboard_interactive_info_response,client}, D#data{ssh_params = Ssh}};
not_ok ->
- {next_state, {userauth,client}, D, [{next_event, internal, Msg}]}
+ {next_state, {userauth,client}, D, [postpone]}
end;
handle_event(_, #ssh_msg_userauth_info_response{} = Msg, {userauth_keyboard_interactive, server}, D) ->
@@ -842,14 +830,14 @@ handle_event(_, #ssh_msg_userauth_info_response{} = Msg, {userauth_keyboard_inte
{next_state, {connected,server}, D#data{auth_user = User,
ssh_params = Ssh#ssh{authenticated = true}}};
-handle_event(_, Msg = #ssh_msg_userauth_failure{}, {userauth_keyboard_interactive, client},
+handle_event(_, #ssh_msg_userauth_failure{}, {userauth_keyboard_interactive, client},
#data{ssh_params = Ssh0} = D0) ->
Prefs = [{Method,M,F,A} || {Method,M,F,A} <- Ssh0#ssh.userauth_preference,
Method =/= "keyboard-interactive"],
D = D0#data{ssh_params = Ssh0#ssh{userauth_preference=Prefs}},
- {next_state, {userauth,client}, D, [{next_event, internal, Msg}]};
+ {next_state, {userauth,client}, D, [postpone]};
-handle_event(_, Msg=#ssh_msg_userauth_failure{}, {userauth_keyboard_interactive_info_response, client},
+handle_event(_, #ssh_msg_userauth_failure{}, {userauth_keyboard_interactive_info_response, client},
#data{ssh_params = Ssh0} = D0) ->
Opts = Ssh0#ssh.opts,
D = case ?GET_OPT(password, Opts) of
@@ -859,23 +847,23 @@ handle_event(_, Msg=#ssh_msg_userauth_failure{}, {userauth_keyboard_interactive_
D0#data{ssh_params =
Ssh0#ssh{opts = ?PUT_OPT({password,not_ok}, Opts)}} % FIXME:intermodule dependency
end,
- {next_state, {userauth,client}, D, [{next_event, internal, Msg}]};
+ {next_state, {userauth,client}, D, [postpone]};
-handle_event(_, Msg=#ssh_msg_userauth_success{}, {userauth_keyboard_interactive_info_response, client}, D) ->
- {next_state, {userauth,client}, D, [{next_event, internal, Msg}]};
+handle_event(_, #ssh_msg_userauth_success{}, {userauth_keyboard_interactive_info_response, client}, D) ->
+ {next_state, {userauth,client}, D, [postpone]};
-handle_event(_, Msg=#ssh_msg_userauth_info_request{}, {userauth_keyboard_interactive_info_response, client}, D) ->
- {next_state, {userauth_keyboard_interactive,client}, D, [{next_event, internal, Msg}]};
+handle_event(_, #ssh_msg_userauth_info_request{}, {userauth_keyboard_interactive_info_response, client}, D) ->
+ {next_state, {userauth_keyboard_interactive,client}, D, [postpone]};
%%% ######## {connected, client|server} ####
-handle_event(_, {#ssh_msg_kexinit{},_} = Event, {connected,Role}, D0) ->
+handle_event(_, {#ssh_msg_kexinit{},_}, {connected,Role}, D0) ->
{KeyInitMsg, SshPacket, Ssh} = ssh_transport:key_exchange_init_msg(D0#data.ssh_params),
D = D0#data{ssh_params = Ssh,
key_exchange_init_msg = KeyInitMsg},
send_bytes(SshPacket, D),
- {next_state, {kexinit,Role,renegotiate}, D, [{next_event, internal, Event}]};
+ {next_state, {kexinit,Role,renegotiate}, D, [postpone]};
handle_event(_, #ssh_msg_disconnect{description=Desc} = Msg, StateName, D0) ->
{disconnect, _, {{replies,Replies}, _}} =
diff --git a/lib/ssh/src/ssh_transport.erl b/lib/ssh/src/ssh_transport.erl
index 54ea80c727..6b47868d5c 100644
--- a/lib/ssh/src/ssh_transport.erl
+++ b/lib/ssh/src/ssh_transport.erl
@@ -181,7 +181,7 @@ ssh_vsn() ->
end.
random_id(Nlo, Nup) ->
- [crypto:rand_uniform($a,$z+1) || _<- lists:duplicate(crypto:rand_uniform(Nlo,Nup+1),x) ].
+ [$a + rand:uniform($z-$a+1) - 1 || _<- lists:duplicate(Nlo + rand:uniform(Nup-Nlo+1) - 1, x)].
hello_version_msg(Data) ->
[Data,"\r\n"].
@@ -1041,7 +1041,7 @@ padding_length(Size, #ssh{encrypt_block_size = BlockSize,
end,
PadBlockSize = max(BlockSize,4),
MaxExtraBlocks = (max(RandomLengthPadding,MinPaddingLen) - MinPaddingLen) div PadBlockSize,
- ExtraPaddingLen = try crypto:rand_uniform(0,MaxExtraBlocks)*PadBlockSize
+ ExtraPaddingLen = try (rand:uniform(MaxExtraBlocks+1) - 1) * PadBlockSize
catch _:_ -> 0
end,
MinPaddingLen + ExtraPaddingLen.
diff --git a/lib/ssl/test/ssl_ECC_SUITE.erl b/lib/ssl/test/ssl_ECC_SUITE.erl
index b77f909dfa..b05e2c74db 100644
--- a/lib/ssl/test/ssl_ECC_SUITE.erl
+++ b/lib/ssl/test/ssl_ECC_SUITE.erl
@@ -91,11 +91,7 @@ init_per_suite(Config0) ->
end_per_suite(Config0),
try crypto:start() of
ok ->
- %% make rsa certs using oppenssl
- Config1 = ssl_test_lib:make_rsa_cert(Config0),
- Config2 = ssl_test_lib:make_ecdsa_cert(Config1),
- Config = ssl_test_lib:make_ecdh_rsa_cert(Config2),
- ssl_test_lib:cert_options(Config)
+ Config0
catch _:_ ->
{skip, "Crypto did not start"}
end.
diff --git a/lib/ssl/test/ssl_certificate_verify_SUITE.erl b/lib/ssl/test/ssl_certificate_verify_SUITE.erl
index 66b0c09b73..45bcdf1f78 100644
--- a/lib/ssl/test/ssl_certificate_verify_SUITE.erl
+++ b/lib/ssl/test/ssl_certificate_verify_SUITE.erl
@@ -74,7 +74,7 @@ tests() ->
cert_expired,
invalid_signature_client,
invalid_signature_server,
- extended_key_usage_verify_client,
+ extended_key_usage_verify_both,
extended_key_usage_verify_server,
critical_extension_verify_client,
critical_extension_verify_server,
@@ -88,18 +88,14 @@ error_handling_tests()->
unknown_server_ca_accept_verify_peer,
unknown_server_ca_accept_backwardscompatibility,
no_authority_key_identifier,
- no_authority_key_identifier_and_nonstandard_encoding].
+ no_authority_key_identifier_keyEncipherment].
-init_per_suite(Config0) ->
+init_per_suite(Config) ->
catch crypto:stop(),
try crypto:start() of
ok ->
- ssl_test_lib:clean_start(),
- %% make rsa certs using oppenssl
- {ok, _} = make_certs:all(proplists:get_value(data_dir, Config0),
- proplists:get_value(priv_dir, Config0)),
- Config = ssl_test_lib:make_dsa_cert(Config0),
- ssl_test_lib:cert_options(Config)
+ ssl_test_lib:clean_start(),
+ ssl_test_lib:make_rsa_cert(Config)
catch _:_ ->
{skip, "Crypto did not start"}
end.
@@ -108,49 +104,39 @@ end_per_suite(_Config) ->
ssl:stop(),
application:stop(crypto).
-init_per_group(tls, Config) ->
+init_per_group(tls, Config0) ->
Version = tls_record:protocol_version(tls_record:highest_protocol_version([])),
ssl:stop(),
application:load(ssl),
application:set_env(ssl, protocol_version, Version),
- application:set_env(ssl, bypass_pem_cache, Version),
ssl:start(),
- NewConfig = proplists:delete(protocol, Config),
- [{protocol, tls}, {version, tls_record:protocol_version(Version)} | NewConfig];
+ Config = proplists:delete(protocol, Config0),
+ [{protocol, tls}, {version, tls_record:protocol_version(Version)} | Config];
-init_per_group(dtls, Config) ->
+init_per_group(dtls, Config0) ->
Version = dtls_record:protocol_version(dtls_record:highest_protocol_version([])),
ssl:stop(),
application:load(ssl),
application:set_env(ssl, protocol_version, Version),
- application:set_env(ssl, bypass_pem_cache, Version),
ssl:start(),
- NewConfig = proplists:delete(protocol_opts, proplists:delete(protocol, Config)),
- [{protocol, dtls}, {protocol_opts, [{protocol, dtls}]}, {version, dtls_record:protocol_version(Version)} | NewConfig];
+ Config = proplists:delete(protocol_opts, proplists:delete(protocol, Config0)),
+ [{protocol, dtls}, {protocol_opts, [{protocol, dtls}]}, {version, dtls_record:protocol_version(Version)} | Config];
init_per_group(active, Config) ->
- [{active, true}, {receive_function, send_recv_result_active} | Config];
+ [{active, true}, {receive_function, send_recv_result_active} | Config];
init_per_group(active_once, Config) ->
- [{active, once}, {receive_function, send_recv_result_active_once} | Config];
+ [{active, once}, {receive_function, send_recv_result_active_once} | Config];
init_per_group(passive, Config) ->
- [{active, false}, {receive_function, send_recv_result} | Config];
+ [{active, false}, {receive_function, send_recv_result} | Config];
+init_per_group(error_handling, Config) ->
+ [{active, false}, {receive_function, send_recv_result} | Config];
+
init_per_group(_, Config) ->
Config.
end_per_group(_GroupName, Config) ->
Config.
-init_per_testcase(TestCase, Config) when TestCase == cert_expired;
- TestCase == invalid_signature_client;
- TestCase == invalid_signature_server;
- TestCase == extended_key_usage_verify_none;
- TestCase == extended_key_usage_verify_peer;
- TestCase == critical_extension_verify_none;
- TestCase == critical_extension_verify_peer;
- TestCase == no_authority_key_identifier;
- TestCase == no_authority_key_identifier_and_nonstandard_encoding->
- ssl:clear_pem_cache(),
- init_per_testcase(common, Config);
init_per_testcase(_TestCase, Config) ->
ssl:stop(),
ssl:start(),
@@ -168,23 +154,23 @@ end_per_testcase(_TestCase, Config) ->
verify_peer() ->
[{doc,"Test option verify_peer"}].
verify_peer(Config) when is_list(Config) ->
- ClientOpts = ssl_test_lib:ssl_options(client_opts, Config),
- ServerOpts = ssl_test_lib:ssl_options(server_verification_opts, Config),
+ ClientOpts = ssl_test_lib:ssl_options(client_rsa_opts, Config),
+ ServerOpts = ssl_test_lib:ssl_options(server_rsa_opts, Config),
Active = proplists:get_value(active, Config),
ReceiveFunction = proplists:get_value(receive_function, Config),
{ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0},
{from, self()},
- {mfa, {ssl_test_lib, ReceiveFunction, []}},
- {options, [{active, Active}, {verify, verify_peer}
- | ServerOpts]}]),
+ {mfa, {ssl_test_lib, ReceiveFunction, []}},
+ {options, [{active, Active}, {verify, verify_peer}
+ | ServerOpts]}]),
Port = ssl_test_lib:inet_port(Server),
Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port},
{host, Hostname},
- {from, self()},
- {mfa, {ssl_test_lib, ReceiveFunction, []}},
- {options, [{active, Active} | ClientOpts]}]),
-
+ {from, self()},
+ {mfa, {ssl_test_lib, ReceiveFunction, []}},
+ {options, [{active, Active}, {verify, verify_peer} | ClientOpts]}]),
+
ssl_test_lib:check_result(Server, ok, Client, ok),
ssl_test_lib:close(Server),
ssl_test_lib:close(Client).
@@ -194,23 +180,24 @@ verify_none() ->
[{doc,"Test option verify_none"}].
verify_none(Config) when is_list(Config) ->
- ClientOpts = ssl_test_lib:ssl_options(client_verification_opts, Config),
- ServerOpts = ssl_test_lib:ssl_options(server_verification_opts, Config),
+ ClientOpts = ssl_test_lib:ssl_options(client_rsa_opts, Config),
+ ServerOpts = ssl_test_lib:ssl_options(server_rsa_opts, Config),
Active = proplists:get_value(active, Config),
ReceiveFunction = proplists:get_value(receive_function, Config),
{ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0},
{from, self()},
- {mfa, {ssl_test_lib, ReceiveFunction, []}},
- {options, [{active, Active}, {verify, verify_none}
- | ServerOpts]}]),
+ {mfa, {ssl_test_lib, ReceiveFunction, []}},
+ {options, [{active, Active}, {verify, verify_none}
+ | ServerOpts]}]),
Port = ssl_test_lib:inet_port(Server),
Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port},
{host, Hostname},
- {from, self()},
- {mfa, {ssl_test_lib, ReceiveFunction, []}},
- {options, [{active, Active} | ClientOpts]}]),
+ {from, self()},
+ {mfa, {ssl_test_lib, ReceiveFunction, []}},
+ {options, [{active, Active},
+ {verify, verify_none} | ClientOpts]}]),
ssl_test_lib:check_result(Server, ok, Client, ok),
ssl_test_lib:close(Server),
@@ -222,8 +209,8 @@ server_verify_client_once() ->
[{doc,"Test server option verify_client_once"}].
server_verify_client_once(Config) when is_list(Config) ->
- ClientOpts = ssl_test_lib:ssl_options(client_opts, []),
- ServerOpts = ssl_test_lib:ssl_options(server_verification_opts, Config),
+ ClientOpts = ssl_test_lib:ssl_options(client_rsa_opts, []),
+ ServerOpts = ssl_test_lib:ssl_options(server_rsa_opts, Config),
Active = proplists:get_value(active, Config),
ReceiveFunction = proplists:get_value(receive_function, Config),
@@ -239,7 +226,7 @@ server_verify_client_once(Config) when is_list(Config) ->
{host, Hostname},
{from, self()},
{mfa, {ssl_test_lib, ReceiveFunction, []}},
- {options, [{active, Active} | ClientOpts]}]),
+ {options, [{active, Active} | ClientOpts]}]),
ssl_test_lib:check_result(Server, ok, Client0, ok),
Server ! {listen, {mfa, {ssl_test_lib, no_result, []}}},
@@ -261,8 +248,8 @@ server_require_peer_cert_ok() ->
server_require_peer_cert_ok(Config) when is_list(Config) ->
ServerOpts = [{verify, verify_peer}, {fail_if_no_peer_cert, true}
- | ssl_test_lib:ssl_options(server_verification_opts, Config)],
- ClientOpts = ssl_test_lib:ssl_options(client_opts, Config),
+ | ssl_test_lib:ssl_options(server_rsa_opts, Config)],
+ ClientOpts = ssl_test_lib:ssl_options(client_rsa_opts, Config),
Active = proplists:get_value(active, Config),
ReceiveFunction = proplists:get_value(receive_function, Config),
{ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
@@ -290,20 +277,21 @@ server_require_peer_cert_fail() ->
server_require_peer_cert_fail(Config) when is_list(Config) ->
ServerOpts = [{verify, verify_peer}, {fail_if_no_peer_cert, true}
- | ssl_test_lib:ssl_options(server_verification_opts, Config)],
+ | ssl_test_lib:ssl_options(server_rsa_opts, Config)],
BadClientOpts = ssl_test_lib:ssl_options(empty_client_opts, Config),
+ Active = proplists:get_value(active, Config),
{ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
Server = ssl_test_lib:start_server_error([{node, ServerNode}, {port, 0},
{from, self()},
- {options, [{active, false} | ServerOpts]}]),
+ {options, [{active, Active} | ServerOpts]}]),
Port = ssl_test_lib:inet_port(Server),
Client = ssl_test_lib:start_client_error([{node, ClientNode}, {port, Port},
{host, Hostname},
{from, self()},
- {options, [{active, false} | BadClientOpts]}]),
+ {options, [{active, Active} | BadClientOpts]}]),
receive
{Server, {error, {tls_alert, "handshake failure"}}} ->
receive
@@ -321,24 +309,25 @@ server_require_peer_cert_partial_chain() ->
server_require_peer_cert_partial_chain(Config) when is_list(Config) ->
ServerOpts = [{verify, verify_peer}, {fail_if_no_peer_cert, true}
- | ssl_test_lib:ssl_options(server_verification_opts, Config)],
- ClientOpts = ssl_test_lib:ssl_options(client_opts, Config),
+ | ssl_test_lib:ssl_options(server_rsa_opts, Config)],
+ ClientOpts = ssl_test_lib:ssl_options(client_rsa_opts, Config),
+ Active = proplists:get_value(active, Config),
{ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
{ok, ClientCAs} = file:read_file(proplists:get_value(cacertfile, ClientOpts)),
- [{_,RootCA,_}, {_, _, _}] = public_key:pem_decode(ClientCAs),
+ [{_,RootCA,_} | _] = public_key:pem_decode(ClientCAs),
Server = ssl_test_lib:start_server_error([{node, ServerNode}, {port, 0},
{from, self()},
{mfa, {ssl_test_lib, no_result, []}},
- {options, [{active, false} | ServerOpts]}]),
+ {options, [{active, Active} | ServerOpts]}]),
Port = ssl_test_lib:inet_port(Server),
Client = ssl_test_lib:start_client_error([{node, ClientNode}, {port, Port},
{host, Hostname},
{from, self()},
{mfa, {ssl_test_lib, no_result, []}},
- {options, [{active, false},
+ {options, [{active, Active},
{cacerts, [RootCA]} |
proplists:delete(cacertfile, ClientOpts)]}]),
receive
@@ -356,14 +345,14 @@ server_require_peer_cert_allow_partial_chain() ->
server_require_peer_cert_allow_partial_chain(Config) when is_list(Config) ->
ServerOpts = [{verify, verify_peer}, {fail_if_no_peer_cert, true}
- | ssl_test_lib:ssl_options(server_verification_opts, Config)],
- ClientOpts = ssl_test_lib:ssl_options(client_opts, Config),
+ | ssl_test_lib:ssl_options(server_rsa_opts, Config)],
+ ClientOpts = ssl_test_lib:ssl_options(client_rsa_opts, Config),
{ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
Active = proplists:get_value(active, Config),
ReceiveFunction = proplists:get_value(receive_function, Config),
{ok, ClientCAs} = file:read_file(proplists:get_value(cacertfile, ClientOpts)),
- [{_,_,_}, {_, IntermidiateCA, _}] = public_key:pem_decode(ClientCAs),
+ [{_,_,_}, {_, IntermidiateCA, _} | _] = public_key:pem_decode(ClientCAs),
PartialChain = fun(CertChain) ->
case lists:member(IntermidiateCA, CertChain) of
@@ -398,12 +387,12 @@ server_require_peer_cert_do_not_allow_partial_chain() ->
server_require_peer_cert_do_not_allow_partial_chain(Config) when is_list(Config) ->
ServerOpts = [{verify, verify_peer}, {fail_if_no_peer_cert, true}
- | ssl_test_lib:ssl_options(server_verification_opts, Config)],
- ClientOpts = ssl_test_lib:ssl_options(client_opts, Config),
+ | ssl_test_lib:ssl_options(server_rsa_opts, Config)],
+ ClientOpts = ssl_test_lib:ssl_options(client_rsa_opts, Config),
{ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
{ok, ServerCAs} = file:read_file(proplists:get_value(cacertfile, ServerOpts)),
- [{_,_,_}, {_, IntermidiateCA, _}] = public_key:pem_decode(ServerCAs),
+ [{_,_,_}, {_, IntermidiateCA, _} | _] = public_key:pem_decode(ServerCAs),
PartialChain = fun(_CertChain) ->
unknown_ca
@@ -439,12 +428,12 @@ server_require_peer_cert_partial_chain_fun_fail() ->
server_require_peer_cert_partial_chain_fun_fail(Config) when is_list(Config) ->
ServerOpts = [{verify, verify_peer}, {fail_if_no_peer_cert, true}
- | ssl_test_lib:ssl_options(server_verification_opts, Config)],
- ClientOpts = ssl_test_lib:ssl_options(client_opts, Config),
+ | ssl_test_lib:ssl_options(server_rsa_opts, Config)],
+ ClientOpts = ssl_test_lib:ssl_options(client_rsa_opts, Config),
{ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
{ok, ServerCAs} = file:read_file(proplists:get_value(cacertfile, ServerOpts)),
- [{_,_,_}, {_, IntermidiateCA, _}] = public_key:pem_decode(ServerCAs),
+ [{_,_,_}, {_, IntermidiateCA, _} | _] = public_key:pem_decode(ServerCAs),
PartialChain = fun(_CertChain) ->
ture = false %% crash on purpose
@@ -479,8 +468,8 @@ verify_fun_always_run_client() ->
[{doc,"Verify that user verify_fun is always run (for valid and valid_peer not only unknown_extension)"}].
verify_fun_always_run_client(Config) when is_list(Config) ->
- ClientOpts = ssl_test_lib:ssl_options(client_verification_opts, Config),
- ServerOpts = ssl_test_lib:ssl_options(server_opts, Config),
+ ClientOpts = ssl_test_lib:ssl_options(client_rsa_opts, Config),
+ ServerOpts = ssl_test_lib:ssl_options(server_rsa_opts, Config),
{ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
Server = ssl_test_lib:start_server_error([{node, ServerNode}, {port, 0},
{from, self()},
@@ -524,8 +513,8 @@ verify_fun_always_run_client(Config) when is_list(Config) ->
verify_fun_always_run_server() ->
[{doc,"Verify that user verify_fun is always run (for valid and valid_peer not only unknown_extension)"}].
verify_fun_always_run_server(Config) when is_list(Config) ->
- ClientOpts = ssl_test_lib:ssl_options(client_opts, Config),
- ServerOpts = ssl_test_lib:ssl_options(server_verification_opts, Config),
+ ClientOpts = ssl_test_lib:ssl_options(client_rsa_opts, Config),
+ ServerOpts = ssl_test_lib:ssl_options(server_rsa_verify_opts, Config),
{ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
%% If user verify fun is called correctly we fail the connection.
@@ -573,63 +562,28 @@ cert_expired() ->
[{doc,"Test server with expired certificate"}].
cert_expired(Config) when is_list(Config) ->
- ClientOpts = ssl_test_lib:ssl_options(client_verification_opts, Config),
- ServerOpts = ssl_test_lib:ssl_options(server_opts, Config),
- PrivDir = proplists:get_value(priv_dir, Config),
-
- KeyFile = filename:join(PrivDir, "otpCA/private/key.pem"),
- [KeyEntry] = ssl_test_lib:pem_to_der(KeyFile),
- Key = ssl_test_lib:public_key(public_key:pem_entry_decode(KeyEntry)),
-
- ServerCertFile = proplists:get_value(certfile, ServerOpts),
- NewServerCertFile = filename:join(PrivDir, "server/expired_cert.pem"),
- [{'Certificate', DerCert, _}] = ssl_test_lib:pem_to_der(ServerCertFile),
- OTPCert = public_key:pkix_decode_cert(DerCert, otp),
- OTPTbsCert = OTPCert#'OTPCertificate'.tbsCertificate,
-
{Year, Month, Day} = date(),
- {Hours, Min, Sec} = time(),
- NotBeforeStr = lists:flatten(io_lib:format("~p~s~s~s~s~sZ",[Year-2,
- two_digits_str(Month),
- two_digits_str(Day),
- two_digits_str(Hours),
- two_digits_str(Min),
- two_digits_str(Sec)])),
- NotAfterStr = lists:flatten(io_lib:format("~p~s~s~s~s~sZ",[Year-1,
- two_digits_str(Month),
- two_digits_str(Day),
- two_digits_str(Hours),
- two_digits_str(Min),
- two_digits_str(Sec)])),
- NewValidity = {'Validity', {generalTime, NotBeforeStr}, {generalTime, NotAfterStr}},
-
- ct:log("Validity: ~p ~n NewValidity: ~p ~n",
- [OTPTbsCert#'OTPTBSCertificate'.validity, NewValidity]),
-
- NewOTPTbsCert = OTPTbsCert#'OTPTBSCertificate'{validity = NewValidity},
- NewServerDerCert = public_key:pkix_sign(NewOTPTbsCert, Key),
- ssl_test_lib:der_to_pem(NewServerCertFile, [{'Certificate', NewServerDerCert, not_encrypted}]),
- NewServerOpts = [{certfile, NewServerCertFile} | proplists:delete(certfile, ServerOpts)],
-
+ Active = proplists:get_value(active, Config),
+ {ClientOpts0, ServerOpts0} = ssl_test_lib:make_rsa_cert_chains([{server_ca_0,
+ [{validity, {{Year-2, Month, Day},
+ {Year-1, Month, Day}}}]}],
+ Config, "_expired"),
+ ClientOpts = ssl_test_lib:ssl_options(ClientOpts0, Config),
+ ServerOpts = ssl_test_lib:ssl_options(ServerOpts0, Config),
+
{ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
Server = ssl_test_lib:start_server_error([{node, ServerNode}, {port, 0},
{from, self()},
- {options, NewServerOpts}]),
+ {options, [{active, Active}| ServerOpts]}]),
Port = ssl_test_lib:inet_port(Server),
Client = ssl_test_lib:start_client_error([{node, ClientNode}, {port, Port},
{host, Hostname},
{from, self()},
- {options, [{verify, verify_peer} | ClientOpts]}]),
- receive
- {Client, {error, {tls_alert, "certificate expired"}}} ->
- receive
- {Server, {error, {tls_alert, "certificate expired"}}} ->
- ok;
- {Server, {error, closed}} ->
- ok
- end
- end.
+ {options, [{verify, verify_peer}, {active, Active} | ClientOpts]}]),
+
+ tcp_delivery_workaround(Server, {error, {tls_alert, "certificate expired"}},
+ Client, {error, {tls_alert, "certificate expired"}}).
two_digits_str(N) when N < 10 ->
lists:flatten(io_lib:format("0~p", [N]));
@@ -638,60 +592,32 @@ two_digits_str(N) ->
%%--------------------------------------------------------------------
extended_key_usage_verify_server() ->
- [{doc,"Test cert that has a critical extended_key_usage extension in verify_peer mode for server"}].
-
-extended_key_usage_verify_server(Config) when is_list(Config) ->
- ClientOpts = ssl_test_lib:ssl_options(client_opts, Config),
- ServerOpts = ssl_test_lib:ssl_options(server_verification_opts, Config),
- PrivDir = proplists:get_value(priv_dir, Config),
+ [{doc,"Test cert that has a critical extended_key_usage extension in server cert"}].
+
+extended_key_usage_verify_server(Config) when is_list(Config) ->
+ {ClientOpts0, ServerOpts0} = ssl_test_lib:make_rsa_cert_chains([{server_peer_opts,
+ [{extensions,
+ [{?'id-ce-extKeyUsage',
+ [?'id-kp-serverAuth'], true}]
+ }]}], Config, "_keyusage_server"),
+ ClientOpts = ssl_test_lib:ssl_options(ClientOpts0, Config),
+ ServerOpts = ssl_test_lib:ssl_options(ServerOpts0, Config),
Active = proplists:get_value(active, Config),
ReceiveFunction = proplists:get_value(receive_function, Config),
- KeyFile = filename:join(PrivDir, "otpCA/private/key.pem"),
- [KeyEntry] = ssl_test_lib:pem_to_der(KeyFile),
- Key = ssl_test_lib:public_key(public_key:pem_entry_decode(KeyEntry)),
-
- ServerCertFile = proplists:get_value(certfile, ServerOpts),
- NewServerCertFile = filename:join(PrivDir, "server/new_cert.pem"),
- [{'Certificate', ServerDerCert, _}] = ssl_test_lib:pem_to_der(ServerCertFile),
- ServerOTPCert = public_key:pkix_decode_cert(ServerDerCert, otp),
- ServerExtKeyUsageExt = {'Extension', ?'id-ce-extKeyUsage', true, [?'id-kp-serverAuth']},
- ServerOTPTbsCert = ServerOTPCert#'OTPCertificate'.tbsCertificate,
- ServerExtensions = ServerOTPTbsCert#'OTPTBSCertificate'.extensions,
- NewServerOTPTbsCert = ServerOTPTbsCert#'OTPTBSCertificate'{extensions =
- [ServerExtKeyUsageExt |
- ServerExtensions]},
- NewServerDerCert = public_key:pkix_sign(NewServerOTPTbsCert, Key),
- ssl_test_lib:der_to_pem(NewServerCertFile, [{'Certificate', NewServerDerCert, not_encrypted}]),
- NewServerOpts = [{certfile, NewServerCertFile} | proplists:delete(certfile, ServerOpts)],
-
- ClientCertFile = proplists:get_value(certfile, ClientOpts),
- NewClientCertFile = filename:join(PrivDir, "client/new_cert.pem"),
- [{'Certificate', ClientDerCert, _}] = ssl_test_lib:pem_to_der(ClientCertFile),
- ClientOTPCert = public_key:pkix_decode_cert(ClientDerCert, otp),
- ClientExtKeyUsageExt = {'Extension', ?'id-ce-extKeyUsage', true, [?'id-kp-clientAuth']},
- ClientOTPTbsCert = ClientOTPCert#'OTPCertificate'.tbsCertificate,
- ClientExtensions = ClientOTPTbsCert#'OTPTBSCertificate'.extensions,
- NewClientOTPTbsCert = ClientOTPTbsCert#'OTPTBSCertificate'{extensions =
- [ClientExtKeyUsageExt |
- ClientExtensions]},
- NewClientDerCert = public_key:pkix_sign(NewClientOTPTbsCert, Key),
- ssl_test_lib:der_to_pem(NewClientCertFile, [{'Certificate', NewClientDerCert, not_encrypted}]),
- NewClientOpts = [{certfile, NewClientCertFile} | proplists:delete(certfile, ClientOpts)],
-
{ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0},
{from, self()},
{mfa, {ssl_test_lib, ReceiveFunction, []}},
- {options, [{verify, verify_peer}, {active, Active} | NewServerOpts]}]),
+ {options, [{verify, verify_none}, {active, Active} | ServerOpts]}]),
Port = ssl_test_lib:inet_port(Server),
Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port},
{host, Hostname},
{from, self()},
{mfa, {ssl_test_lib, ReceiveFunction, []}},
- {options, [{verify, verify_none}, {active, Active} |
- NewClientOpts]}]),
+ {options, [{verify, verify_peer}, {active, Active} |
+ ClientOpts]}]),
ssl_test_lib:check_result(Server, ok, Client, ok),
@@ -699,60 +625,35 @@ extended_key_usage_verify_server(Config) when is_list(Config) ->
ssl_test_lib:close(Client).
%%--------------------------------------------------------------------
-extended_key_usage_verify_client() ->
+extended_key_usage_verify_both() ->
[{doc,"Test cert that has a critical extended_key_usage extension in client verify_peer mode"}].
-extended_key_usage_verify_client(Config) when is_list(Config) ->
- ClientOpts = ssl_test_lib:ssl_options(client_verification_opts, Config),
- ServerOpts = ssl_test_lib:ssl_options(server_opts, Config),
- PrivDir = proplists:get_value(priv_dir, Config),
+extended_key_usage_verify_both(Config) when is_list(Config) ->
+ {ClientOpts0, ServerOpts0} = ssl_test_lib:make_rsa_cert_chains([{server_peer_opts,
+ [{extensions, [{?'id-ce-extKeyUsage',
+ [?'id-kp-serverAuth'], true}]
+ }]},
+ {client_peer_opts,
+ [{extensions, [{?'id-ce-extKeyUsage',
+ [?'id-kp-clientAuth'], true}]
+ }]}], Config, "_keyusage_both"),
+ ClientOpts = ssl_test_lib:ssl_options(ClientOpts0, Config),
+ ServerOpts = ssl_test_lib:ssl_options(ServerOpts0, Config),
Active = proplists:get_value(active, Config),
ReceiveFunction = proplists:get_value(receive_function, Config),
- KeyFile = filename:join(PrivDir, "otpCA/private/key.pem"),
- [KeyEntry] = ssl_test_lib:pem_to_der(KeyFile),
- Key = ssl_test_lib:public_key(public_key:pem_entry_decode(KeyEntry)),
-
- ServerCertFile = proplists:get_value(certfile, ServerOpts),
- NewServerCertFile = filename:join(PrivDir, "server/new_cert.pem"),
- [{'Certificate', ServerDerCert, _}] = ssl_test_lib:pem_to_der(ServerCertFile),
- ServerOTPCert = public_key:pkix_decode_cert(ServerDerCert, otp),
- ServerExtKeyUsageExt = {'Extension', ?'id-ce-extKeyUsage', true, [?'id-kp-serverAuth']},
- ServerOTPTbsCert = ServerOTPCert#'OTPCertificate'.tbsCertificate,
- ServerExtensions = ServerOTPTbsCert#'OTPTBSCertificate'.extensions,
- NewServerOTPTbsCert = ServerOTPTbsCert#'OTPTBSCertificate'{extensions =
- [ServerExtKeyUsageExt |
- ServerExtensions]},
- NewServerDerCert = public_key:pkix_sign(NewServerOTPTbsCert, Key),
- ssl_test_lib:der_to_pem(NewServerCertFile, [{'Certificate', NewServerDerCert, not_encrypted}]),
- NewServerOpts = [{certfile, NewServerCertFile} | proplists:delete(certfile, ServerOpts)],
-
- ClientCertFile = proplists:get_value(certfile, ClientOpts),
- NewClientCertFile = filename:join(PrivDir, "client/new_cert.pem"),
- [{'Certificate', ClientDerCert, _}] = ssl_test_lib:pem_to_der(ClientCertFile),
- ClientOTPCert = public_key:pkix_decode_cert(ClientDerCert, otp),
- ClientExtKeyUsageExt = {'Extension', ?'id-ce-extKeyUsage', true, [?'id-kp-clientAuth']},
- ClientOTPTbsCert = ClientOTPCert#'OTPCertificate'.tbsCertificate,
- ClientExtensions = ClientOTPTbsCert#'OTPTBSCertificate'.extensions,
- NewClientOTPTbsCert = ClientOTPTbsCert#'OTPTBSCertificate'{extensions =
- [ClientExtKeyUsageExt |
- ClientExtensions]},
- NewClientDerCert = public_key:pkix_sign(NewClientOTPTbsCert, Key),
- ssl_test_lib:der_to_pem(NewClientCertFile, [{'Certificate', NewClientDerCert, not_encrypted}]),
- NewClientOpts = [{certfile, NewClientCertFile} | proplists:delete(certfile, ClientOpts)],
-
{ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0},
{from, self()},
{mfa, {ssl_test_lib, ReceiveFunction, []}},
- {options, [{verify, verify_none}, {active, Active} | NewServerOpts]}]),
+ {options, [{verify, verify_peer}, {active, Active} | ServerOpts]}]),
Port = ssl_test_lib:inet_port(Server),
Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port},
{host, Hostname},
{from, self()},
{mfa, {ssl_test_lib, ReceiveFunction, []}},
- {options, [{verify, verify_none}, {active, Active} | NewClientOpts]}]),
+ {options, [{verify, verify_peer}, {active, Active} | ClientOpts]}]),
ssl_test_lib:check_result(Server, ok, Client, ok),
@@ -764,132 +665,103 @@ critical_extension_verify_server() ->
[{doc,"Test cert that has a critical unknown extension in verify_peer mode"}].
critical_extension_verify_server(Config) when is_list(Config) ->
- ClientOpts = ssl_test_lib:ssl_options(client_opts, Config),
- ServerOpts = ssl_test_lib:ssl_options(server_verification_opts, Config),
- PrivDir = proplists:get_value(priv_dir, Config),
+ {ClientOpts0, ServerOpts0} = ssl_test_lib:make_rsa_cert_chains([{client_peer_opts,
+ [{extensions, [{{2,16,840,1,113730,1,1},
+ <<3,2,6,192>>, true}]
+ }]}], Config, "_client_unknown_extension"),
+ ClientOpts = ssl_test_lib:ssl_options(ClientOpts0, Config),
+ ServerOpts = ssl_test_lib:ssl_options(ServerOpts0, Config),
Active = proplists:get_value(active, Config),
ReceiveFunction = proplists:get_value(receive_function, Config),
- KeyFile = filename:join(PrivDir, "otpCA/private/key.pem"),
- NewCertName = integer_to_list(erlang:unique_integer()) ++ ".pem",
-
- ServerCertFile = proplists:get_value(certfile, ServerOpts),
- NewServerCertFile = filename:join([PrivDir, "server", NewCertName]),
- add_critical_netscape_cert_type(ServerCertFile, NewServerCertFile, KeyFile),
- NewServerOpts = [{certfile, NewServerCertFile} | proplists:delete(certfile, ServerOpts)],
-
- ClientCertFile = proplists:get_value(certfile, ClientOpts),
- NewClientCertFile = filename:join([PrivDir, "client", NewCertName]),
- add_critical_netscape_cert_type(ClientCertFile, NewClientCertFile, KeyFile),
- NewClientOpts = [{certfile, NewClientCertFile} | proplists:delete(certfile, ClientOpts)],
-
{ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
Server = ssl_test_lib:start_server_error(
[{node, ServerNode}, {port, 0},
{from, self()},
{mfa, {ssl_test_lib, ReceiveFunction, []}},
- {options, [{verify, verify_peer}, {active, Active} | NewServerOpts]}]),
+ {options, [{verify, verify_peer}, {active, Active} | ServerOpts]}]),
Port = ssl_test_lib:inet_port(Server),
Client = ssl_test_lib:start_client_error(
[{node, ClientNode}, {port, Port},
{host, Hostname},
{from, self()},
{mfa, {ssl_test_lib, ReceiveFunction, []}},
- {options, [{verify, verify_none}, {active, Active} | NewClientOpts]}]),
+ {options, [{verify, verify_none}, {active, Active} | ClientOpts]}]),
%% This certificate has a critical extension that we don't
- %% understand. Therefore, verification should fail.
- tcp_delivery_workaround(Server, {error, {tls_alert, "unsupported certificate"}},
- Client, {error, {tls_alert, "unsupported certificate"}}),
+ %% understand. Therefore, verification should fail.
- ssl_test_lib:close(Server),
- ok.
+ tcp_delivery_workaround(Server, {error, {tls_alert, "unsupported certificate"}},
+ Client, {error, {tls_alert, "unsupported certificate"}}),
+
+ ssl_test_lib:close(Server).
%%--------------------------------------------------------------------
critical_extension_verify_client() ->
[{doc,"Test cert that has a critical unknown extension in verify_peer mode"}].
critical_extension_verify_client(Config) when is_list(Config) ->
- ClientOpts = ssl_test_lib:ssl_options(client_verification_opts, Config),
- ServerOpts = ssl_test_lib:ssl_options(server_opts, Config),
- PrivDir = proplists:get_value(priv_dir, Config),
+ {ClientOpts0, ServerOpts0} = ssl_test_lib:make_rsa_cert_chains([{server_peer_opts,
+ [{extensions, [{{2,16,840,1,113730,1,1},
+ <<3,2,6,192>>, true}]
+ }]}], Config, "_server_unknown_extensions"),
+ ClientOpts = ssl_test_lib:ssl_options(ClientOpts0, Config),
+ ServerOpts = ssl_test_lib:ssl_options(ServerOpts0, Config),
Active = proplists:get_value(active, Config),
ReceiveFunction = proplists:get_value(receive_function, Config),
- KeyFile = filename:join(PrivDir, "otpCA/private/key.pem"),
- NewCertName = integer_to_list(erlang:unique_integer()) ++ ".pem",
-
- ServerCertFile = proplists:get_value(certfile, ServerOpts),
- NewServerCertFile = filename:join([PrivDir, "server", NewCertName]),
- add_critical_netscape_cert_type(ServerCertFile, NewServerCertFile, KeyFile),
- NewServerOpts = [{certfile, NewServerCertFile} | proplists:delete(certfile, ServerOpts)],
-
- ClientCertFile = proplists:get_value(certfile, ClientOpts),
- NewClientCertFile = filename:join([PrivDir, "client", NewCertName]),
- add_critical_netscape_cert_type(ClientCertFile, NewClientCertFile, KeyFile),
- NewClientOpts = [{certfile, NewClientCertFile} | proplists:delete(certfile, ClientOpts)],
-
{ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
Server = ssl_test_lib:start_server_error(
[{node, ServerNode}, {port, 0},
{from, self()},
{mfa, {ssl_test_lib, ReceiveFunction, []}},
- {options, [{verify, verify_none}, {active, Active} | NewServerOpts]}]),
+ {options, [{verify, verify_none}, {active, Active} | ServerOpts]}]),
Port = ssl_test_lib:inet_port(Server),
Client = ssl_test_lib:start_client_error(
[{node, ClientNode}, {port, Port},
{host, Hostname},
{from, self()},
{mfa, {ssl_test_lib, ReceiveFunction, []}},
- {options, [{verify, verify_peer}, {active, Active} | NewClientOpts]}]),
+ {options, [{verify, verify_peer}, {active, Active} | ClientOpts]}]),
%% This certificate has a critical extension that we don't
%% understand. Therefore, verification should fail.
- tcp_delivery_workaround(Server, {error, {tls_alert, "unsupported certificate"}},
- Client, {error, {tls_alert, "unsupported certificate"}}),
+ ssl_test_lib:check_result(Server, {error, {tls_alert, "unsupported certificate"}},
+ Client, {error, {tls_alert, "unsupported certificate"}}),
+
+ ssl_test_lib:close(Server).
- ssl_test_lib:close(Server),
- ok.
%%--------------------------------------------------------------------
critical_extension_verify_none() ->
[{doc,"Test cert that has a critical unknown extension in verify_none mode"}].
critical_extension_verify_none(Config) when is_list(Config) ->
- ClientOpts = ssl_test_lib:ssl_options(client_verification_opts, Config),
- ServerOpts = ssl_test_lib:ssl_options(server_opts, Config),
- PrivDir = proplists:get_value(priv_dir, Config),
+ {ClientOpts0, ServerOpts0} = ssl_test_lib:make_rsa_cert_chains([{client_peer_opts,
+ [{extensions,
+ [{{2,16,840,1,113730,1,1},
+ <<3,2,6,192>>, true}]
+ }]}], Config, "_unknown_extensions"),
+ ClientOpts = ssl_test_lib:ssl_options(ClientOpts0, Config),
+ ServerOpts = ssl_test_lib:ssl_options(ServerOpts0, Config),
Active = proplists:get_value(active, Config),
ReceiveFunction = proplists:get_value(receive_function, Config),
- KeyFile = filename:join(PrivDir, "otpCA/private/key.pem"),
- NewCertName = integer_to_list(erlang:unique_integer()) ++ ".pem",
-
- ServerCertFile = proplists:get_value(certfile, ServerOpts),
- NewServerCertFile = filename:join([PrivDir, "server", NewCertName]),
- add_critical_netscape_cert_type(ServerCertFile, NewServerCertFile, KeyFile),
- NewServerOpts = [{certfile, NewServerCertFile} | proplists:delete(certfile, ServerOpts)],
-
- ClientCertFile = proplists:get_value(certfile, ClientOpts),
- NewClientCertFile = filename:join([PrivDir, "client", NewCertName]),
- add_critical_netscape_cert_type(ClientCertFile, NewClientCertFile, KeyFile),
- NewClientOpts = [{certfile, NewClientCertFile} | proplists:delete(certfile, ClientOpts)],
-
{ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
Server = ssl_test_lib:start_server(
[{node, ServerNode}, {port, 0},
{from, self()},
{mfa, {ssl_test_lib, ReceiveFunction, []}},
- {options, [{verify, verify_none}, {active, Active} | NewServerOpts]}]),
+ {options, [{verify, verify_none}, {active, Active} | ServerOpts]}]),
Port = ssl_test_lib:inet_port(Server),
Client = ssl_test_lib:start_client(
[{node, ClientNode}, {port, Port},
{host, Hostname},
{from, self()},
{mfa, {ssl_test_lib, ReceiveFunction, []}},
- {options, [{verify, verify_none}, {active, Active} | NewClientOpts]}]),
+ {options, [{verify, verify_none}, {active, Active} | ClientOpts]}]),
%% This certificate has a critical extension that we don't
%% understand. But we're using `verify_none', so verification
@@ -897,28 +769,7 @@ critical_extension_verify_none(Config) when is_list(Config) ->
ssl_test_lib:check_result(Server, ok, Client, ok),
ssl_test_lib:close(Server),
- ssl_test_lib:close(Client),
- ok.
-
-add_critical_netscape_cert_type(CertFile, NewCertFile, KeyFile) ->
- [KeyEntry] = ssl_test_lib:pem_to_der(KeyFile),
- Key = ssl_test_lib:public_key(public_key:pem_entry_decode(KeyEntry)),
-
- [{'Certificate', DerCert, _}] = ssl_test_lib:pem_to_der(CertFile),
- OTPCert = public_key:pkix_decode_cert(DerCert, otp),
- %% This is the "Netscape Cert Type" extension, telling us that the
- %% certificate can be used for SSL clients and SSL servers.
- NetscapeCertTypeExt = #'Extension'{
- extnID = {2,16,840,1,113730,1,1},
- critical = true,
- extnValue = <<3,2,6,192>>},
- OTPTbsCert = OTPCert#'OTPCertificate'.tbsCertificate,
- Extensions = OTPTbsCert#'OTPTBSCertificate'.extensions,
- NewOTPTbsCert = OTPTbsCert#'OTPTBSCertificate'{
- extensions = [NetscapeCertTypeExt] ++ Extensions},
- NewDerCert = public_key:pkix_sign(NewOTPTbsCert, Key),
- ssl_test_lib:der_to_pem(NewCertFile, [{'Certificate', NewDerCert, not_encrypted}]),
- ok.
+ ssl_test_lib:close(Client).
%%--------------------------------------------------------------------
no_authority_key_identifier() ->
@@ -926,35 +777,21 @@ no_authority_key_identifier() ->
" but are present in trusted certs db."}].
no_authority_key_identifier(Config) when is_list(Config) ->
- ClientOpts = ssl_test_lib:ssl_options(client_verification_opts, Config),
- ServerOpts = ssl_test_lib:ssl_options(server_verification_opts, Config),
- PrivDir = proplists:get_value(priv_dir, Config),
-
- KeyFile = filename:join(PrivDir, "otpCA/private/key.pem"),
- [KeyEntry] = ssl_test_lib:pem_to_der(KeyFile),
- Key = ssl_test_lib:public_key(public_key:pem_entry_decode(KeyEntry)),
-
- CertFile = proplists:get_value(certfile, ServerOpts),
- NewCertFile = filename:join(PrivDir, "server/new_cert.pem"),
- [{'Certificate', DerCert, _}] = ssl_test_lib:pem_to_der(CertFile),
- OTPCert = public_key:pkix_decode_cert(DerCert, otp),
- OTPTbsCert = OTPCert#'OTPCertificate'.tbsCertificate,
- Extensions = OTPTbsCert#'OTPTBSCertificate'.extensions,
- NewExtensions = delete_authority_key_extension(Extensions, []),
- NewOTPTbsCert = OTPTbsCert#'OTPTBSCertificate'{extensions = NewExtensions},
-
- ct:log("Extensions ~p~n, NewExtensions: ~p~n", [Extensions, NewExtensions]),
-
- NewDerCert = public_key:pkix_sign(NewOTPTbsCert, Key),
- ssl_test_lib:der_to_pem(NewCertFile, [{'Certificate', NewDerCert, not_encrypted}]),
- NewServerOpts = [{certfile, NewCertFile} | proplists:delete(certfile, ServerOpts)],
+ {ClientOpts0, ServerOpts0} = ssl_test_lib:make_rsa_cert_chains([{server_peer_opts,
+ [{extensions, [{auth_key_id, undefined}]
+ }]},
+ {client_peer_opts,
+ [{extensions, [{auth_key_id, undefined}]
+ }]}], Config, "_peer_no_auth_key_id"),
+ ClientOpts = ssl_test_lib:ssl_options(ClientOpts0, Config),
+ ServerOpts = ssl_test_lib:ssl_options(ServerOpts0, Config),
{ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0},
{from, self()},
{mfa, {ssl_test_lib, send_recv_result_active, []}},
- {options, NewServerOpts}]),
+ {options, ServerOpts}]),
Port = ssl_test_lib:inet_port(Server),
Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port},
{host, Hostname},
@@ -970,53 +807,35 @@ no_authority_key_identifier(Config) when is_list(Config) ->
delete_authority_key_extension([], Acc) ->
lists:reverse(Acc);
delete_authority_key_extension([#'Extension'{extnID = ?'id-ce-authorityKeyIdentifier'} | Rest],
- Acc) ->
+ Acc) ->
delete_authority_key_extension(Rest, Acc);
delete_authority_key_extension([Head | Rest], Acc) ->
delete_authority_key_extension(Rest, [Head | Acc]).
%%--------------------------------------------------------------------
-no_authority_key_identifier_and_nonstandard_encoding() ->
- [{doc, "Test cert with nonstandard encoding that does not have"
- " authorityKeyIdentifier extension but are present in trusted certs db."}].
-
-no_authority_key_identifier_and_nonstandard_encoding(Config) when is_list(Config) ->
- ClientOpts = ssl_test_lib:ssl_options(client_verification_opts, Config),
- ServerOpts = ssl_test_lib:ssl_options(server_verification_opts, Config),
- PrivDir = proplists:get_value(priv_dir, Config),
-
- KeyFile = filename:join(PrivDir, "otpCA/private/key.pem"),
- [KeyEntry] = ssl_test_lib:pem_to_der(KeyFile),
- Key = ssl_test_lib:public_key(public_key:pem_entry_decode(KeyEntry)),
-
- CertFile = proplists:get_value(certfile, ServerOpts),
- NewCertFile = filename:join(PrivDir, "server/new_cert.pem"),
- [{'Certificate', DerCert, _}] = ssl_test_lib:pem_to_der(CertFile),
- ServerCert = public_key:pkix_decode_cert(DerCert, plain),
- ServerTbsCert = ServerCert#'Certificate'.tbsCertificate,
- Extensions0 = ServerTbsCert#'TBSCertificate'.extensions,
- %% need to remove authorityKeyIdentifier extension to cause DB lookup by signature
- Extensions = delete_authority_key_extension(Extensions0, []),
- NewExtensions = replace_key_usage_extension(Extensions, []),
- NewServerTbsCert = ServerTbsCert#'TBSCertificate'{extensions = NewExtensions},
-
- ct:log("Extensions ~p~n, NewExtensions: ~p~n", [Extensions, NewExtensions]),
-
- TbsDer = public_key:pkix_encode('TBSCertificate', NewServerTbsCert, plain),
- Sig = public_key:sign(TbsDer, md5, Key),
- NewServerCert = ServerCert#'Certificate'{tbsCertificate = NewServerTbsCert, signature = Sig},
- NewDerCert = public_key:pkix_encode('Certificate', NewServerCert, plain),
- ssl_test_lib:der_to_pem(NewCertFile, [{'Certificate', NewDerCert, not_encrypted}]),
- NewServerOpts = [{certfile, NewCertFile} | proplists:delete(certfile, ServerOpts)],
-
+no_authority_key_identifier_keyEncipherment() ->
+ [{doc, "Test cert with keyEncipherment key_usage an no"
+ " authorityKeyIdentifier extension, but are present in trusted certs db."}].
+
+no_authority_key_identifier_keyEncipherment(Config) when is_list(Config) ->
+ {ClientOpts0, ServerOpts0} = ssl_test_lib:make_rsa_cert_chains([{server_peer_opts,
+ [{extensions, [{auth_key_id, undefined},
+ {key_usage, [digitalSignature,
+ keyEncipherment]}]
+ }]},
+ {client_peer_opts,
+ [{extensions, [{auth_key_id, undefined}]
+ }]}], Config, "_peer_keyEncipherment"),
+ ClientOpts = ssl_test_lib:ssl_options(ClientOpts0, Config),
+ ServerOpts = ssl_test_lib:ssl_options(ServerOpts0, Config),
{ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0},
{from, self()},
{mfa, {ssl_test_lib,
send_recv_result_active, []}},
- {options, [{active, true} | NewServerOpts]}]),
+ {options, [{active, true} | ServerOpts]}]),
Port = ssl_test_lib:inet_port(Server),
Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port},
{host, Hostname},
@@ -1028,14 +847,6 @@ no_authority_key_identifier_and_nonstandard_encoding(Config) when is_list(Config
ssl_test_lib:close(Server),
ssl_test_lib:close(Client).
-replace_key_usage_extension([], Acc) ->
- lists:reverse(Acc);
-replace_key_usage_extension([#'Extension'{extnID = ?'id-ce-keyUsage'} = E | Rest], Acc) ->
- %% A nonstandard DER encoding of [digitalSignature, keyEncipherment]
- Val = <<3, 2, 0, 16#A0>>,
- replace_key_usage_extension(Rest, [E#'Extension'{extnValue = Val} | Acc]);
-replace_key_usage_extension([Head | Rest], Acc) ->
- replace_key_usage_extension(Rest, [Head | Acc]).
%%--------------------------------------------------------------------
@@ -1043,16 +854,16 @@ invalid_signature_server() ->
[{doc,"Test client with invalid signature"}].
invalid_signature_server(Config) when is_list(Config) ->
- ClientOpts = ssl_test_lib:ssl_options(client_verification_opts, Config),
- ServerOpts = ssl_test_lib:ssl_options(server_verification_opts, Config),
+ ClientOpts = ssl_test_lib:ssl_options(client_rsa_opts, Config),
+ ServerOpts = ssl_test_lib:ssl_options(server_rsa_opts, Config),
PrivDir = proplists:get_value(priv_dir, Config),
- KeyFile = filename:join(PrivDir, "server/key.pem"),
+ KeyFile = proplists:get_value(keyfile, ServerOpts),
[KeyEntry] = ssl_test_lib:pem_to_der(KeyFile),
Key = ssl_test_lib:public_key(public_key:pem_entry_decode(KeyEntry)),
ServerCertFile = proplists:get_value(certfile, ServerOpts),
- NewServerCertFile = filename:join(PrivDir, "server/invalid_cert.pem"),
+ NewServerCertFile = filename:join(PrivDir, "server_invalid_cert.pem"),
[{'Certificate', ServerDerCert, _}] = ssl_test_lib:pem_to_der(ServerCertFile),
ServerOTPCert = public_key:pkix_decode_cert(ServerDerCert, otp),
ServerOTPTbsCert = ServerOTPCert#'OTPCertificate'.tbsCertificate,
@@ -1071,8 +882,8 @@ invalid_signature_server(Config) when is_list(Config) ->
{from, self()},
{options, [{verify, verify_peer} | ClientOpts]}]),
- tcp_delivery_workaround(Server, {error, {tls_alert, "bad certificate"}},
- Client, {error, {tls_alert, "bad certificate"}}).
+ tcp_delivery_workaround(Server, {error, {tls_alert, "unknown ca"}},
+ Client, {error, {tls_alert, "unknown ca"}}).
%%--------------------------------------------------------------------
@@ -1080,16 +891,16 @@ invalid_signature_client() ->
[{doc,"Test server with invalid signature"}].
invalid_signature_client(Config) when is_list(Config) ->
- ClientOpts = ssl_test_lib:ssl_options(client_verification_opts, Config),
- ServerOpts = ssl_test_lib:ssl_options(server_verification_opts, Config),
+ ClientOpts = ssl_test_lib:ssl_options(client_rsa_opts, Config),
+ ServerOpts = ssl_test_lib:ssl_options(server_rsa_opts, Config),
PrivDir = proplists:get_value(priv_dir, Config),
- KeyFile = filename:join(PrivDir, "client/key.pem"),
+ KeyFile = proplists:get_value(keyfile, ClientOpts),
[KeyEntry] = ssl_test_lib:pem_to_der(KeyFile),
Key = ssl_test_lib:public_key(public_key:pem_entry_decode(KeyEntry)),
ClientCertFile = proplists:get_value(certfile, ClientOpts),
- NewClientCertFile = filename:join(PrivDir, "client/invalid_cert.pem"),
+ NewClientCertFile = filename:join(PrivDir, "client_invalid_cert.pem"),
[{'Certificate', ClientDerCert, _}] = ssl_test_lib:pem_to_der(ClientCertFile),
ClientOTPCert = public_key:pkix_decode_cert(ClientDerCert, otp),
ClientOTPTbsCert = ClientOTPCert#'OTPCertificate'.tbsCertificate,
@@ -1108,8 +919,8 @@ invalid_signature_client(Config) when is_list(Config) ->
{from, self()},
{options, NewClientOpts}]),
- tcp_delivery_workaround(Server, {error, {tls_alert, "bad certificate"}},
- Client, {error, {tls_alert, "bad certificate"}}).
+ tcp_delivery_workaround(Server, {error, {tls_alert, "unknown ca"}},
+ Client, {error, {tls_alert, "unknown ca"}}).
%%--------------------------------------------------------------------
@@ -1118,8 +929,14 @@ client_with_cert_cipher_suites_handshake() ->
[{doc, "Test that client with a certificate without keyEncipherment usage "
" extension can connect to a server with restricted cipher suites "}].
client_with_cert_cipher_suites_handshake(Config) when is_list(Config) ->
- ClientOpts = ssl_test_lib:ssl_options(client_verification_opts_digital_signature_only, Config),
- ServerOpts = ssl_test_lib:ssl_options(server_verification_opts, Config),
+ {ClientOpts0, ServerOpts0} = ssl_test_lib:make_rsa_cert_chains([{client_peer_opts,
+ [{extensions,
+ [{key_usage, [digitalSignature]}]
+ }]}], Config, "_sign_only_extensions"),
+
+
+ ClientOpts = ssl_test_lib:ssl_options(ClientOpts0, Config),
+ ServerOpts = ssl_test_lib:ssl_options(ServerOpts0, Config),
{ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0},
@@ -1148,7 +965,7 @@ client_with_cert_cipher_suites_handshake(Config) when is_list(Config) ->
server_verify_no_cacerts() ->
[{doc,"Test server must have cacerts if it wants to verify client"}].
server_verify_no_cacerts(Config) when is_list(Config) ->
- ServerOpts = proplists:delete(cacertfile, ssl_test_lib:ssl_options(server_opts, Config)),
+ ServerOpts = proplists:delete(cacertfile, ssl_test_lib:ssl_options(server_rsa_opts, Config)),
{_, ServerNode, _} = ssl_test_lib:run_where(Config),
Server = ssl_test_lib:start_server_error([{node, ServerNode}, {port, 0},
{from, self()},
@@ -1163,7 +980,7 @@ unknown_server_ca_fail() ->
[{doc,"Test that the client fails if the ca is unknown in verify_peer mode"}].
unknown_server_ca_fail(Config) when is_list(Config) ->
ClientOpts = ssl_test_lib:ssl_options(empty_client_opts, Config),
- ServerOpts = ssl_test_lib:ssl_options(server_verification_opts, Config),
+ ServerOpts = ssl_test_lib:ssl_options(server_rsa_verify_opts, Config),
{ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
Server = ssl_test_lib:start_server_error([{node, ServerNode}, {port, 0},
{from, self()},
@@ -1207,7 +1024,7 @@ unknown_server_ca_accept_verify_none() ->
[{doc,"Test that the client succeds if the ca is unknown in verify_none mode"}].
unknown_server_ca_accept_verify_none(Config) when is_list(Config) ->
ClientOpts = ssl_test_lib:ssl_options(empty_client_opts, Config),
- ServerOpts = ssl_test_lib:ssl_options(server_verification_opts, Config),
+ ServerOpts = ssl_test_lib:ssl_options(server_rsa_verify_opts, Config),
{ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0},
{from, self()},
@@ -1232,7 +1049,7 @@ unknown_server_ca_accept_verify_peer() ->
" with a verify_fun that accepts the unknown ca error"}].
unknown_server_ca_accept_verify_peer(Config) when is_list(Config) ->
ClientOpts = ssl_test_lib:ssl_options(empty_client_opts, Config),
- ServerOpts = ssl_test_lib:ssl_options(server_verification_opts, Config),
+ ServerOpts = ssl_test_lib:ssl_options(server_rsa_verify_opts, Config),
{ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0},
{from, self()},
@@ -1271,7 +1088,7 @@ unknown_server_ca_accept_backwardscompatibility() ->
[{doc,"Test that old style verify_funs will work"}].
unknown_server_ca_accept_backwardscompatibility(Config) when is_list(Config) ->
ClientOpts = ssl_test_lib:ssl_options(empty_client_opts, Config),
- ServerOpts = ssl_test_lib:ssl_options(server_verification_opts, Config),
+ ServerOpts = ssl_test_lib:ssl_options(server_rsa_verify_opts, Config),
{ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0},
{from, self()},
diff --git a/lib/ssl/test/ssl_test_lib.erl b/lib/ssl/test/ssl_test_lib.erl
index 302b5178a5..b8fd5dc975 100644
--- a/lib/ssl/test/ssl_test_lib.erl
+++ b/lib/ssl/test/ssl_test_lib.erl
@@ -485,6 +485,18 @@ make_dsa_cert(Config) ->
{certfile, ClientCertFile}, {keyfile, ClientKeyFile}]}
| Config].
+make_rsa_cert_chains(ChainConf, Config, Suffix) ->
+ CryptoSupport = crypto:supports(),
+ KeyGenSpec = key_gen_info(rsa, rsa),
+ ClientFileBase = filename:join([proplists:get_value(priv_dir, Config), "rsa" ++ Suffix]),
+ ServerFileBase = filename:join([proplists:get_value(priv_dir, Config), "rsa" ++ Suffix]),
+ GenCertData = x509_test:gen_test_certs([{digest, appropriate_sha(CryptoSupport)} | KeyGenSpec] ++ ChainConf),
+ [{server_config, ServerConf},
+ {client_config, ClientConf}] =
+ x509_test:gen_pem_config_files(GenCertData, ClientFileBase, ServerFileBase),
+ {[{verify, verify_peer} | ClientConf],
+ [{reuseaddr, true}, {verify, verify_peer} | ServerConf]
+ }.
make_ec_cert_chains(ClientChainType, ServerChainType, Config) ->
CryptoSupport = crypto:supports(),
@@ -524,6 +536,11 @@ key_gen_spec(Role, ecdhe_rsa) ->
[{list_to_atom(Role ++ "_key_gen"), hardcode_rsa_key(1)},
{list_to_atom(Role ++ "_key_gen_chain"), [hardcode_rsa_key(2),
hardcode_rsa_key(3)]}
+ ];
+key_gen_spec(Role, rsa) ->
+ [{list_to_atom(Role ++ "_key_gen"), hardcode_rsa_key(1)},
+ {list_to_atom(Role ++ "_key_gen_chain"), [hardcode_rsa_key(2),
+ hardcode_rsa_key(3)]}
].
make_ecdsa_cert(Config) ->
CryptoSupport = crypto:supports(),
@@ -571,7 +588,8 @@ make_rsa_cert(Config) ->
{server_rsa_verify_opts, [{ssl_imp, new}, {reuseaddr, true},
{verify, verify_peer} | ServerConf]},
- {client_rsa_opts, ClientConf}
+ {client_rsa_opts, ClientConf},
+ {client_rsa_verify_opts, [{verify, verify_peer} |ClientConf]}
| Config];
false ->
Config
@@ -935,9 +953,9 @@ available_suites(Version) ->
rsa_non_signed_suites(Version) ->
lists:filter(fun({rsa, _, _}) ->
- true;
+ false;
(_) ->
- false
+ true
end,
available_suites(Version)).
@@ -1398,10 +1416,13 @@ do_supports_ssl_tls_version(Port) ->
true
end.
-ssl_options(Option, Config) ->
+ssl_options(Option, Config) when is_atom(Option) ->
ProtocolOpts = proplists:get_value(protocol_opts, Config, []),
Opts = proplists:get_value(Option, Config, []),
- Opts ++ ProtocolOpts.
+ Opts ++ ProtocolOpts;
+ssl_options(Options, Config) ->
+ ProtocolOpts = proplists:get_value(protocol_opts, Config, []),
+ Options ++ ProtocolOpts.
protocol_version(Config) ->
protocol_version(Config, atom).
diff --git a/lib/ssl/test/x509_test.erl b/lib/ssl/test/x509_test.erl
index 13f8dfdaa9..c36e96013b 100644
--- a/lib/ssl/test/x509_test.erl
+++ b/lib/ssl/test/x509_test.erl
@@ -96,7 +96,7 @@ gen_pem_config_files(GenCertData, ClientBase, ServerBase) ->
public_key:generate_key(KeyGen)
end.
- root_cert(Role, PrivKey, Opts) ->
+root_cert(Role, PrivKey, Opts) ->
TBS = cert_template(),
Issuer = issuer("root", Role, " ROOT CA"),
OTPTBS = TBS#'OTPTBSCertificate'{
@@ -105,7 +105,7 @@ gen_pem_config_files(GenCertData, ClientBase, ServerBase) ->
validity = validity(Opts),
subject = Issuer,
subjectPublicKeyInfo = public_key(PrivKey),
- extensions = extensions(Opts)
+ extensions = extensions(ca, Opts)
},
public_key:pkix_sign(OTPTBS, PrivKey).
@@ -175,32 +175,31 @@ validity(Opts) ->
#'Validity'{notBefore={generalTime, Format(DefFrom)},
notAfter ={generalTime, Format(DefTo)}}.
-extensions(Opts) ->
- case proplists:get_value(extensions, Opts, []) of
- false ->
- asn1_NOVALUE;
- Exts ->
- lists:flatten([extension(Ext) || Ext <- default_extensions(Exts)])
- end.
+extensions(Type, Opts) ->
+ Exts = proplists:get_value(extensions, Opts, []),
+ lists:flatten([extension(Ext) || Ext <- default_extensions(Type, Exts)]).
+
+%% Common extension: name_constraints, policy_constraints, ext_key_usage, inhibit_any,
+%% auth_key_id, subject_key_id, policy_mapping,
+
+default_extensions(ca, Exts) ->
+ Def = [{key_usage, [keyCertSign, cRLSign]},
+ {basic_constraints, default}],
+ add_default_extensions(Def, Exts);
-default_extensions(Exts) ->
- Def = [{key_usage,undefined},
- {subject_altname, undefined},
- {issuer_altname, undefined},
- {basic_constraints, default},
- {name_constraints, undefined},
- {policy_constraints, undefined},
- {ext_key_usage, undefined},
- {inhibit_any, undefined},
- {auth_key_id, undefined},
- {subject_key_id, undefined},
- {policy_mapping, undefined}],
+default_extensions(peer, Exts) ->
+ Def = [{key_usage, [digitalSignature, keyAgreement]}],
+ add_default_extensions(Def, Exts).
+
+add_default_extensions(Def, Exts) ->
Filter = fun({Key, _}, D) ->
- lists:keydelete(Key, 1, D)
+ lists:keydelete(Key, 1, D);
+ ({Key, _, _}, D) ->
+ lists:keydelete(Key, 1, D)
end,
Exts ++ lists:foldl(Filter, Def, Exts).
-
-extension({_, undefined}) ->
+
+extension({_, undefined}) ->
[];
extension({basic_constraints, Data}) ->
case Data of
@@ -218,6 +217,17 @@ extension({basic_constraints, Data}) ->
#'Extension'{extnID = ?'id-ce-basicConstraints',
extnValue = Data}
end;
+extension({auth_key_id, {Oid, Issuer, SNr}}) ->
+ #'Extension'{extnID = ?'id-ce-authorityKeyIdentifier',
+ extnValue = #'AuthorityKeyIdentifier'{
+ keyIdentifier = Oid,
+ authorityCertIssuer = Issuer,
+ authorityCertSerialNumber = SNr},
+ critical = false};
+extension({key_usage, Value}) ->
+ #'Extension'{extnID = ?'id-ce-keyUsage',
+ extnValue = Value,
+ critical = false};
extension({Id, Data, Critical}) ->
#'Extension'{extnID = Id, extnValue = Data, critical = Critical}.
@@ -277,24 +287,31 @@ cert_chain(Role, Root, RootKey, Opts, Keys) ->
cert_chain(Role, Root, RootKey, Opts, Keys, 0, []).
cert_chain(Role, IssuerCert, IssuerKey, Opts, [Key], _, Acc) ->
+ PeerOpts = list_to_atom(atom_to_list(Role) ++ "_peer_opts"),
Cert = cert(Role, public_key:pkix_decode_cert(IssuerCert, otp),
- IssuerKey, Key, "admin", " Peer cert", Opts),
+ IssuerKey, Key, "admin", " Peer cert", Opts, PeerOpts, peer),
[{Cert, Key}, {IssuerCert, IssuerKey} | Acc];
cert_chain(Role, IssuerCert, IssuerKey, Opts, [Key | Keys], N, Acc) ->
+ CAOpts = list_to_atom(atom_to_list(Role) ++ "_ca_" ++ integer_to_list(N)),
Cert = cert(Role, public_key:pkix_decode_cert(IssuerCert, otp), IssuerKey, Key, "webadmin",
- " Intermidiate CA " ++ integer_to_list(N), Opts),
+ " Intermidiate CA " ++ integer_to_list(N), Opts, CAOpts, ca),
cert_chain(Role, Cert, Key, Opts, Keys, N+1, [{IssuerCert, IssuerKey} | Acc]).
-cert(Role, #'OTPCertificate'{tbsCertificate = #'OTPTBSCertificate'{subject = Issuer}},
- PrivKey, Key, Contact, Name, Opts) ->
+cert(Role, #'OTPCertificate'{tbsCertificate = #'OTPTBSCertificate'{subject = Issuer,
+ serialNumber = SNr
+ }},
+ PrivKey, Key, Contact, Name, Opts, CertOptsName, Type) ->
+ CertOpts = proplists:get_value(CertOptsName, Opts, []),
TBS = cert_template(),
OTPTBS = TBS#'OTPTBSCertificate'{
signature = sign_algorithm(PrivKey, Opts),
issuer = Issuer,
- validity = validity(Opts),
+ validity = validity(CertOpts),
subject = subject(Contact, atom_to_list(Role) ++ Name),
subjectPublicKeyInfo = public_key(Key),
- extensions = extensions(Opts)
+ extensions = extensions(Type,
+ add_default_extensions([{auth_key_id, {auth_key_oid(Role), Issuer, SNr}}],
+ CertOpts))
},
public_key:pkix_sign(OTPTBS, PrivKey).
@@ -319,3 +336,8 @@ default_key_gen() ->
[{namedCurve, hd(tls_v1:ecc_curves(0))},
{namedCurve, hd(tls_v1:ecc_curves(0))}]
end.
+
+auth_key_oid(server) ->
+ ?'id-kp-serverAuth';
+auth_key_oid(client) ->
+ ?'id-kp-clientAuth'.
diff --git a/lib/stdlib/doc/src/erl_tar.xml b/lib/stdlib/doc/src/erl_tar.xml
index f28d8b425b..fab7c832d5 100644
--- a/lib/stdlib/doc/src/erl_tar.xml
+++ b/lib/stdlib/doc/src/erl_tar.xml
@@ -292,6 +292,10 @@
<c>Fd</c> is assumed to be a file descriptor returned from function
<c>file:open/2</c>.</p>
<p>Otherwise, <c>Name</c> is to be a filename.</p>
+ <note><p>Leading slashes in tar member names will be removed before
+ writing the file. That is, absolute paths will be turned into
+ relative paths. There will be an info message written to the error
+ logger when paths are changed in this way.</p></note>
</desc>
</func>
diff --git a/lib/stdlib/doc/src/re.xml b/lib/stdlib/doc/src/re.xml
index aadb5beaba..078ca0e38c 100644
--- a/lib/stdlib/doc/src/re.xml
+++ b/lib/stdlib/doc/src/re.xml
@@ -5,7 +5,7 @@
<header>
<copyright>
<year>2007</year>
- <year>2016</year>
+ <year>2017</year>
<holder>Ericsson AB, All Rights Reserved</holder>
</copyright>
<legalnotice>
@@ -79,6 +79,14 @@
<funcs>
<func>
+ <name name="version" arity="0"/>
+ <fsummary>Gives the PCRE version of the system in a string format</fsummary>
+ <desc>
+ <p>The return of this function is a string with the PCRE version of the system that was used in the Erlang/OTP compilation.</p>
+ </desc>
+ </func>
+
+ <func>
<name name="compile" arity="1"/>
<fsummary>Compile a regular expression into a match program</fsummary>
<desc>
diff --git a/lib/stdlib/src/erl_lint.erl b/lib/stdlib/src/erl_lint.erl
index 0789f5dfb7..78b7a0e751 100644
--- a/lib/stdlib/src/erl_lint.erl
+++ b/lib/stdlib/src/erl_lint.erl
@@ -404,6 +404,10 @@ format_error({not_exported_opaque, {TypeName, Arity}}) ->
format_error({underspecified_opaque, {TypeName, Arity}}) ->
io_lib:format("opaque type ~w~s is underspecified and therefore meaningless",
[TypeName, gen_type_paren(Arity)]);
+format_error({bad_dialyzer_attribute,Term}) ->
+ io_lib:format("badly formed dialyzer attribute: ~w", [Term]);
+format_error({bad_dialyzer_option,Term}) ->
+ io_lib:format("unknown dialyzer warning option: ~w", [Term]);
%% --- obsolete? unused? ---
format_error({format_error, {Fmt, Args}}) ->
io_lib:format(Fmt, Args).
@@ -796,8 +800,7 @@ attribute_state(Form, St) ->
%% State'
%% Allow for record, type and opaque type definitions and spec
%% declarations to be intersperced within function definitions.
-%% Dialyzer attributes are also allowed everywhere, but are not
-%% checked at all.
+%% Dialyzer attributes are also allowed everywhere.
function_state({attribute,L,record,{Name,Fields}}, St) ->
record_def(L, Name, Fields, St);
@@ -883,7 +886,8 @@ post_traversal_check(Forms, St0) ->
StD = check_on_load(StC),
StE = check_unused_records(Forms, StD),
StF = check_local_opaque_types(StE),
- check_callback_information(StF).
+ StG = check_dialyzer_attribute(Forms, StF),
+ check_callback_information(StG).
%% check_behaviour(State0) -> State
%% Check that the behaviour attribute is valid.
@@ -3116,6 +3120,59 @@ check_local_opaque_types(St) ->
end,
dict:fold(FoldFun, St, Ts).
+check_dialyzer_attribute(Forms, St0) ->
+ Vals = [{L,V} ||
+ {attribute,L,dialyzer,Val} <- Forms,
+ V0 <- lists:flatten([Val]),
+ V <- case V0 of
+ {O,F} ->
+ [{A,B} ||
+ A <- lists:flatten([O]),
+ B <- lists:flatten([F])];
+ T -> [T]
+ end],
+ {Wellformed, Bad} =
+ lists:partition(fun ({_,{Option,FA}}) when is_atom(Option) ->
+ is_fa(FA);
+ ({_,Option}) when is_atom(Option) -> true;
+ (_) -> false
+ end, Vals),
+ St1 = foldl(fun ({L,Term}, St) ->
+ add_error(L, {bad_dialyzer_attribute,Term}, St)
+ end, St0, Bad),
+ DefFunctions = (gb_sets:to_list(St0#lint.defined) -- pseudolocals()),
+ Fun = fun ({L,{Option,FA}}, St) ->
+ case is_function_dialyzer_option(Option) of
+ true ->
+ case lists:member(FA, DefFunctions) of
+ true -> St;
+ false ->
+ add_error(L, {undefined_function,FA}, St)
+ end;
+ false ->
+ add_error(L, {bad_dialyzer_option,Option}, St)
+ end;
+ ({L,Option}, St) ->
+ case is_module_dialyzer_option(Option) of
+ true -> St;
+ false ->
+ add_error(L, {bad_dialyzer_option,Option}, St)
+ end
+ end,
+ foldl(Fun, St1, Wellformed).
+
+is_function_dialyzer_option(nowarn_function) -> true;
+is_function_dialyzer_option(Option) ->
+ is_module_dialyzer_option(Option).
+
+is_module_dialyzer_option(Option) ->
+ lists:member(Option,
+ [no_return,no_unused,no_improper_lists,no_fun_app,
+ no_match,no_opaque,no_fail_call,no_contracts,
+ no_behaviours,no_undefined_callbacks,unmatched_returns,
+ error_handling,race_conditions,no_missing_calls,
+ specdiffs,overspecs,underspecs,unknown]).
+
%% icrt_clauses(Clauses, In, ImportVarTable, State) ->
%% {UpdVt,State}.
diff --git a/lib/stdlib/src/erl_tar.erl b/lib/stdlib/src/erl_tar.erl
index a54df939bf..168ea4002c 100644
--- a/lib/stdlib/src/erl_tar.erl
+++ b/lib/stdlib/src/erl_tar.erl
@@ -69,6 +69,8 @@ format_error(invalid_gnu_1_0_sparsemap) ->
"Invalid GNU sparse map (version 1.0)";
format_error({invalid_gnu_0_1_sparsemap, Format}) ->
lists:flatten(io_lib:format("Invalid GNU sparse map (version ~s)", [Format]));
+format_error(unsafe_path) ->
+ "The path points above the current working directory";
format_error({Name,Reason}) ->
lists:flatten(io_lib:format("~ts: ~ts", [Name,format_error(Reason)]));
format_error(Atom) when is_atom(Atom) ->
@@ -120,26 +122,38 @@ do_extract(Handle, Opts) when is_list(Opts) ->
extract1(eof, Reader, _, Acc) when is_list(Acc) ->
{ok, {ok, lists:reverse(Acc)}, Reader};
+extract1(eof, Reader, _, leading_slash) ->
+ error_logger:info_msg("erl_tar: removed leading '/' from member names\n"),
+ {ok, ok, Reader};
extract1(eof, Reader, _, Acc) ->
{ok, Acc, Reader};
-extract1(#tar_header{name=Name,size=Size}=Header, Reader, Opts, Acc) ->
+extract1(#tar_header{name=Name,size=Size}=Header, Reader0, Opts, Acc0) ->
case check_extract(Name, Opts) of
true ->
- case do_read(Reader, Size) of
- {ok, Bin, Reader2} ->
- case write_extracted_element(Header, Bin, Opts) of
- ok ->
- {ok, Acc, Reader2};
- {ok, NameBin} when is_list(Acc) ->
- {ok, [NameBin | Acc], Reader2};
- {error, _} = Err ->
- throw(Err)
- end;
+ case do_read(Reader0, Size) of
+ {ok, Bin, Reader1} ->
+ Acc = extract2(Header, Bin, Opts, Acc0),
+ {ok, Acc, Reader1};
{error, _} = Err ->
throw(Err)
end;
false ->
- {ok, Acc, skip_file(Reader)}
+ {ok, Acc0, skip_file(Reader0)}
+ end.
+
+extract2(Header, Bin, Opts, Acc) ->
+ case write_extracted_element(Header, Bin, Opts) of
+ ok ->
+ case Header of
+ #tar_header{name="/"++_} ->
+ leading_slash;
+ #tar_header{} ->
+ Acc
+ end;
+ {ok, NameBin} when is_list(Acc) ->
+ [NameBin | Acc];
+ {error, _} = Err ->
+ throw(Err)
end.
%% Checks if the file Name should be extracted.
@@ -1052,14 +1066,11 @@ unpack_modern(Format, #header_v7{}=V7, Bin, #tar_header{}=Header0)
safe_join_path([], Name) ->
- strip_slashes(Name, both);
+ filename:join([Name]);
safe_join_path(Prefix, []) ->
- strip_slashes(Prefix, right);
+ filename:join([Prefix]);
safe_join_path(Prefix, Name) ->
- filename:join(strip_slashes(Prefix, right), strip_slashes(Name, both)).
-
-strip_slashes(Str, Direction) ->
- string:strip(Str, Direction, $/).
+ filename:join(Prefix, Name).
new_sparse_file_reader(Reader, Sparsemap, RealSize) ->
true = validate_sparse_entries(Sparsemap, RealSize),
@@ -1557,7 +1568,7 @@ write_extracted_element(#tar_header{name=Name,typeflag=Type},
ok
end;
write_extracted_element(#tar_header{name=Name0}=Header, Bin, Opts) ->
- Name1 = filename:absname(Name0, Opts#read_opts.cwd),
+ Name1 = make_safe_path(Name0, Opts),
Created =
case typeflag(Header#tar_header.typeflag) of
regular ->
@@ -1585,6 +1596,16 @@ write_extracted_element(#tar_header{name=Name0}=Header, Bin, Opts) ->
not_written -> ok
end.
+make_safe_path([$/|Path], Opts) ->
+ make_safe_path(Path, Opts);
+make_safe_path(Path, #read_opts{cwd=Cwd}) ->
+ case filename:safe_relative_path(Path) of
+ unsafe ->
+ throw({error,{Path,unsafe_path}});
+ SafePath ->
+ filename:absname(SafePath, Cwd)
+ end.
+
create_regular(Name, NameInArchive, Bin, Opts) ->
case write_extracted_file(Name, Bin, Opts) of
not_written ->
diff --git a/lib/stdlib/src/re.erl b/lib/stdlib/src/re.erl
index 52d3c35608..28aab7b590 100644
--- a/lib/stdlib/src/re.erl
+++ b/lib/stdlib/src/re.erl
@@ -33,7 +33,12 @@
%%% BIFs
--export([compile/1, compile/2, run/2, run/3, inspect/2]).
+-export([version/0, compile/1, compile/2, run/2, run/3, inspect/2]).
+
+-spec version() -> binary().
+
+version() ->
+ erlang:nif_error(undef).
-spec compile(Regexp) -> {ok, MP} | {error, ErrSpec} when
Regexp :: iodata(),
diff --git a/lib/stdlib/test/erl_lint_SUITE.erl b/lib/stdlib/test/erl_lint_SUITE.erl
index fd7de65302..c469624fb4 100644
--- a/lib/stdlib/test/erl_lint_SUITE.erl
+++ b/lib/stdlib/test/erl_lint_SUITE.erl
@@ -64,8 +64,8 @@
predef/1,
maps/1,maps_type/1,maps_parallel_match/1,
otp_11851/1,otp_11879/1,otp_13230/1,
- record_errors/1, otp_xxxxx/1,
- non_latin1_module/1]).
+ record_errors/1, otp_11879_cont/1,
+ non_latin1_module/1, otp_14323/1]).
suite() ->
[{ct_hooks,[ts_install_cth]},
@@ -85,7 +85,7 @@ all() ->
too_many_arguments, basic_errors, bin_syntax_errors, predef,
maps, maps_type, maps_parallel_match,
otp_11851, otp_11879, otp_13230,
- record_errors, otp_xxxxx, non_latin1_module].
+ record_errors, otp_11879_cont, non_latin1_module, otp_14323].
groups() ->
[{unused_vars_warn, [],
@@ -3875,7 +3875,7 @@ record_errors(Config) when is_list(Config) ->
{3,erl_lint,{redefine_field,r,a}}],[]}}],
run(Config, Ts).
-otp_xxxxx(Config) ->
+otp_11879_cont(Config) ->
Ts = [{constraint1,
<<"-export([t/1]).
-spec t(X) -> X when is_subtype(integer()).
@@ -3942,6 +3942,50 @@ do_non_latin1_module(Mod) ->
ok.
+%% OTP-14323: Check the dialyzer attribute.
+otp_14323(Config) ->
+ Ts = [
+ {otp_14323_1,
+ <<"-import(mod, [m/1]).
+
+ -export([f/0, g/0, h/0]).
+
+ -dialyzer({nowarn_function,module_info/0}). % undefined function
+ -dialyzer({nowarn_function,record_info/2}). % undefined function
+ -dialyzer({nowarn_function,m/1}). % undefined function
+
+ -dialyzer(nowarn_function). % unknown option
+ -dialyzer(1). % badly formed
+ -dialyzer(malformed). % unkonwn option
+ -dialyzer({malformed,f/0}). % unkonwn option
+ -dialyzer({nowarn_function,a/1}). % undefined function
+ -dialyzer({nowarn_function,{a,-1}}). % badly formed
+
+ -dialyzer([no_return, no_match]).
+ -dialyzer({nowarn_function, f/0}).
+ -dialyzer(no_improper_lists).
+ -dialyzer([{nowarn_function, [f/0]}, no_improper_lists]).
+ -dialyzer({no_improper_lists, g/0}).
+ -dialyzer({[no_return, no_match], [g/0, h/0]}).
+
+ f() -> a.
+ g() -> b.
+ h() -> c.">>,
+ [],
+ {errors,[{5,erl_lint,{undefined_function,{module_info,0}}},
+ {6,erl_lint,{undefined_function,{record_info,2}}},
+ {7,erl_lint,{undefined_function,{m,1}}},
+ {9,erl_lint,{bad_dialyzer_option,nowarn_function}},
+ {10,erl_lint,{bad_dialyzer_attribute,1}},
+ {11,erl_lint,{bad_dialyzer_option,malformed}},
+ {12,erl_lint,{bad_dialyzer_option,malformed}},
+ {13,erl_lint,{undefined_function,{a,1}}},
+ {14,erl_lint,{bad_dialyzer_attribute,
+ {nowarn_function,{a,-1}}}}],
+ []}}],
+ [] = run(Config, Ts),
+ ok.
+
run(Config, Tests) ->
F = fun({N,P,Ws,E}, BadL) ->
case catch run_test(Config, P, Ws) of
diff --git a/lib/stdlib/test/re_SUITE.erl b/lib/stdlib/test/re_SUITE.erl
index a76ded5f60..71f86e32e5 100644
--- a/lib/stdlib/test/re_SUITE.erl
+++ b/lib/stdlib/test/re_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2008-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2008-2017. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -24,7 +24,7 @@
run_options/1,combined_options/1,replace_autogen/1,
global_capture/1,replace_input_types/1,replace_return/1,
split_autogen/1,split_options/1,split_specials/1,
- error_handling/1,pcre_cve_2008_2371/1,
+ error_handling/1,pcre_cve_2008_2371/1,re_version/1,
pcre_compile_workspace_overflow/1,re_infinite_loop/1,
re_backwards_accented/1,opt_dupnames/1,opt_all_names/1,inspect/1,
opt_no_start_optimize/1,opt_never_utf/1,opt_ucp/1,
@@ -45,7 +45,7 @@ all() ->
pcre_compile_workspace_overflow, re_infinite_loop,
re_backwards_accented, opt_dupnames, opt_all_names,
inspect, opt_no_start_optimize,opt_never_utf,opt_ucp,
- match_limit, sub_binaries].
+ match_limit, sub_binaries, re_version].
groups() ->
[].
@@ -194,6 +194,14 @@ run_options(Config) when is_list(Config) ->
+%% Test the version is retorned correctly
+re_version(_Config) ->
+ Version = re:version(),
+ {match,[Version]} = re:run(Version,"^[0-9]\\.[0-9]{2} 20[0-9]{2}-[0-9]{2}-[0-9]{2}",[{capture,all,binary}]),
+ ok.
+
+
+
%% Test compile options given directly to run.
combined_options(Config) when is_list(Config) ->
ok = crtest("ABDabcdABCD","abcd",[],true,{match,[{3,4}]}),
diff --git a/lib/stdlib/test/tar_SUITE.erl b/lib/stdlib/test/tar_SUITE.erl
index 2e1ae7bcff..76fa760fa8 100644
--- a/lib/stdlib/test/tar_SUITE.erl
+++ b/lib/stdlib/test/tar_SUITE.erl
@@ -27,7 +27,7 @@
extract_from_binary_compressed/1, extract_filtered/1,
extract_from_open_file/1, symlinks/1, open_add_close/1, cooked_compressed/1,
memory/1,unicode/1,read_other_implementations/1,
- sparse/1, init/1]).
+ sparse/1, init/1, leading_slash/1, dotdot/1]).
-include_lib("common_test/include/ct.hrl").
-include_lib("kernel/include/file.hrl").
@@ -41,7 +41,7 @@ all() ->
extract_filtered,
symlinks, open_add_close, cooked_compressed, memory, unicode,
read_other_implementations,
- sparse,init].
+ sparse,init,leading_slash,dotdot].
groups() ->
[].
@@ -920,6 +920,39 @@ unicode_create_files() ->
[]
end].
+leading_slash(Config) ->
+ PrivDir = proplists:get_value(priv_dir, Config),
+ Dir = filename:join(PrivDir, ?FUNCTION_NAME),
+ TarFile = filename:join(Dir, "leading_slash.tar"),
+ ok = filelib:ensure_dir(TarFile),
+ {ok,Fd} = erl_tar:open(TarFile, [write]),
+ TarMemberName = "e/d/c/b/a_member",
+ TarMemberNameAbs = "/" ++ TarMemberName,
+ Contents = <<"contents\n">>,
+ ok = erl_tar:add(Fd, Contents, TarMemberNameAbs, [verbose]),
+ ok = erl_tar:close(Fd),
+
+ ok = erl_tar:extract(TarFile, [{cwd,Dir}]),
+
+ {ok,Contents} = file:read_file(filename:join(Dir, TarMemberName)),
+ ok.
+
+dotdot(Config) ->
+ PrivDir = proplists:get_value(priv_dir, Config),
+ Dir = filename:join(PrivDir, ?FUNCTION_NAME),
+ ok = file:make_dir(Dir),
+ Tar = filename:join(Dir, "dotdot.tar"),
+ {ok,Fd} = erl_tar:open(Tar, [write]),
+ BeamFile = code:which(?MODULE),
+ ok = erl_tar:add(Fd, BeamFile, "a/./../../some_file", []),
+ ok = erl_tar:close(Fd),
+
+ {error,{_,unsafe_path=Error}} = erl_tar:extract(Tar, [{cwd,Dir}]),
+ false = filelib:is_regular(filename:join(PrivDir, "some_file")),
+ io:format("~s\n", [erl_tar:format_error(Error)]),
+
+ ok.
+
%% Delete the given list of files.
delete_files([]) -> ok;
delete_files([Item|Rest]) ->
diff --git a/lib/tools/src/lcnt.erl b/lib/tools/src/lcnt.erl
index 22db947e7a..864d62f6c5 100644
--- a/lib/tools/src/lcnt.erl
+++ b/lib/tools/src/lcnt.erl
@@ -698,19 +698,47 @@ stats2record([{{File,Line},{Tries,Colls,{S,Ns,N}}}|Stats]) ->
nt = N} | stats2record(Stats)];
stats2record([]) -> [].
+
clean_id_creation(Id) when is_pid(Id) ->
Bin = term_to_binary(Id),
- <<H:3/binary, L:16, Node:L/binary, Ids:8/binary, _Creation/binary>> = Bin,
- Bin2 = list_to_binary([H, bytes16(L), Node, Ids, 0]),
+ <<H:3/binary, Rest/binary>> = Bin,
+ <<131, PidTag, AtomTag>> = H,
+ LL = atomlen_bits(AtomTag),
+ CL = creation_bits(PidTag),
+ <<L:LL, Node:L/binary, Ids:8/binary, _Creation/binary>> = Rest,
+ Bin2 = list_to_binary([H, <<L:LL>>, Node, Ids, <<0:CL>>]),
binary_to_term(Bin2);
clean_id_creation(Id) when is_port(Id) ->
Bin = term_to_binary(Id),
- <<H:3/binary, L:16, Node:L/binary, Ids:4/binary, _Creation/binary>> = Bin,
- Bin2 = list_to_binary([H, bytes16(L), Node, Ids, 0]),
+ <<H:3/binary, Rest/binary>> = Bin,
+ <<131, PortTag, AtomTag>> = H,
+ LL = atomlen_bits(AtomTag),
+ CL = creation_bits(PortTag),
+ <<L:LL, Node:L/binary, Ids:4/binary, _Creation/binary>> = Rest,
+ Bin2 = list_to_binary([H, <<L:LL>>, Node, Ids, <<0:CL>>]),
binary_to_term(Bin2);
clean_id_creation(Id) ->
Id.
+-define(PID_EXT, $g).
+-define(NEW_PID_EXT, $X).
+-define(PORT_EXT, $f).
+-define(NEW_PORT_EXT, $Y).
+-define(ATOM_EXT, $d).
+-define(SMALL_ATOM_EXT, $s).
+-define(ATOM_UTF8_EXT, $v).
+-define(SMALL_ATOM_UTF8_EXT, $w).
+
+atomlen_bits(?ATOM_EXT) -> 16;
+atomlen_bits(?SMALL_ATOM_EXT) -> 8;
+atomlen_bits(?ATOM_UTF8_EXT) -> 16;
+atomlen_bits(?SMALL_ATOM_UTF8_EXT) -> 8.
+
+creation_bits(?PID_EXT) -> 8;
+creation_bits(?NEW_PID_EXT) -> 32;
+creation_bits(?PORT_EXT) -> 8;
+creation_bits(?NEW_PORT_EXT) -> 32.
+
%% serializer
state_default(Field) -> proplists:get_value(Field, state2list(#state{})).
@@ -932,9 +960,6 @@ strings([{space, N, S} | Ss], Out) -> strings(Ss, Out ++ term2string(term2
strings([{left, N, S} | Ss], Out) -> strings(Ss, Out ++ term2string(term2string(" ~~s~~~ws", [N]), [S,""]));
strings([S|Ss], Out) -> strings(Ss, Out ++ term2string("~ts", [S])).
--define(SMALL_ATOM_UTF8_EXT, $w).
--define(ATOM_UTF8_EXT, $v).
--define(ATOM_EXT, $d).
term2string({M,F,A}) when is_atom(M), is_atom(F), is_integer(A) -> term2string("~p:~p/~p", [M,F,A]);
term2string(Term) when is_port(Term) ->
diff --git a/lib/tools/test/xref_SUITE.erl b/lib/tools/test/xref_SUITE.erl
index f308ea1204..b8e7113595 100644
--- a/lib/tools/test/xref_SUITE.erl
+++ b/lib/tools/test/xref_SUITE.erl
@@ -89,11 +89,11 @@ init_per_suite(Conf) when is_list(Conf) ->
DataDir = ?datadir,
PrivDir = ?privdir,
CopyDir = fname(PrivDir, "datacopy"),
+ ok = file:make_dir(CopyDir),
TarFile = fname(PrivDir, "datacopy.tgz"),
- {ok, Tar} = erl_tar:open(TarFile, [write, compressed]),
- ok = erl_tar:add(Tar, DataDir, CopyDir, [compressed]),
- ok = erl_tar:close(Tar),
- ok = erl_tar:extract(TarFile, [compressed]),
+ ok = file:set_cwd(DataDir),
+ ok = erl_tar:create(TarFile, ["."], [compressed]),
+ ok = erl_tar:extract(TarFile, [compressed, {cwd,CopyDir}]),
ok = file:delete(TarFile),
[{copy_dir, CopyDir}|Conf].