aboutsummaryrefslogtreecommitdiffstats
path: root/lib
diff options
context:
space:
mode:
Diffstat (limited to 'lib')
-rw-r--r--lib/common_test/src/ct_logs.erl47
-rw-r--r--lib/common_test/src/ct_telnet.erl73
-rw-r--r--lib/common_test/src/ct_telnet_client.erl8
-rw-r--r--lib/common_test/src/unix_telnet.erl36
-rw-r--r--lib/common_test/test/Makefile1
-rw-r--r--lib/common_test/test/ct_telnet_SUITE.erl69
-rw-r--r--lib/common_test/test/ct_telnet_SUITE_data/ct_telnet_own_server_SUITE.erl184
-rw-r--r--lib/common_test/test/telnet_server.erl228
-rw-r--r--lib/compiler/src/beam_receive.erl92
-rw-r--r--lib/compiler/test/receive_SUITE.erl13
-rw-r--r--lib/compiler/test/receive_SUITE_data/ref_opt/yes_14.S71
-rw-r--r--lib/crypto/c_src/crypto.c863
-rw-r--r--[-rwxr-xr-x]lib/crypto/doc/src/crypto.xml1548
-rw-r--r--lib/crypto/doc/src/crypto_app.xml79
-rw-r--r--lib/crypto/src/crypto.erl692
-rw-r--r--lib/crypto/test/crypto_SUITE.erl312
-rw-r--r--lib/dialyzer/src/dialyzer_gui.erl5
-rw-r--r--lib/dialyzer/src/dialyzer_gui_wx.erl5
-rw-r--r--lib/erl_interface/src/connect/ei_connect.c3
-rw-r--r--lib/et/doc/src/et_desc.xmlsrc2
-rw-r--r--lib/ic/java_src/com/ericsson/otp/ic/Environment.java4
-rw-r--r--lib/ic/src/icparse.yrl3
-rw-r--r--lib/jinterface/test/jinterface_SUITE.erl3
-rw-r--r--lib/jinterface/test/jitu.erl38
-rw-r--r--lib/jinterface/test/nc_SUITE.erl12
-rw-r--r--lib/kernel/doc/src/inet.xml4
-rw-r--r--lib/kernel/src/gen_sctp.erl4
-rw-r--r--lib/kernel/src/gen_udp.erl4
-rw-r--r--lib/kernel/src/inet.erl5
-rw-r--r--lib/kernel/src/inet_int.hrl4
-rw-r--r--lib/kernel/test/inet_sockopt_SUITE.erl8
-rw-r--r--lib/megaco/.gitignore35
-rw-r--r--lib/megaco/doc/src/Makefile5
-rw-r--r--lib/megaco/doc/src/notes.xml781
-rw-r--r--lib/megaco/src/app/megaco.appup.src326
-rw-r--r--lib/megaco/src/flex/megaco_flex_scanner_drv.flex.src31
-rw-r--r--lib/megaco/src/flex/megaco_flex_scanner_handler.erl6
-rw-r--r--lib/megaco/test/megaco_appup_test.erl31
-rw-r--r--lib/megaco/test/megaco_codec_flex_lib.erl8
-rw-r--r--lib/megaco/test/megaco_codec_prev3a_test.erl140
-rw-r--r--lib/megaco/test/megaco_codec_prev3b_test.erl147
-rw-r--r--lib/megaco/test/megaco_codec_prev3c_test.erl150
-rw-r--r--lib/megaco/test/megaco_codec_v1_test.erl110
-rw-r--r--lib/megaco/test/megaco_codec_v2_test.erl1103
-rw-r--r--lib/megaco/test/megaco_codec_v3_test.erl147
-rw-r--r--lib/megaco/test/megaco_test_lib.erl167
-rw-r--r--lib/megaco/vsn.mk2
-rw-r--r--lib/mnesia/src/mnesia_index.erl10
-rw-r--r--lib/mnesia/src/mnesia_loader.erl14
-rw-r--r--lib/mnesia/test/mnesia_evil_coverage_test.erl51
-rw-r--r--lib/public_key/asn1/ECPrivateKey.asn124
-rw-r--r--lib/public_key/asn1/OTP-PKIX.asn130
-rw-r--r--lib/public_key/asn1/OTP-PUB-KEY.set.asn1
-rw-r--r--lib/public_key/asn1/PKCS-1.asn132
-rw-r--r--lib/public_key/asn1/PKIX1Algorithms88.asn1118
-rw-r--r--lib/public_key/doc/src/public_key.xml47
-rw-r--r--lib/public_key/include/public_key.hrl8
-rw-r--r--lib/public_key/src/pubkey_cert_records.erl88
-rw-r--r--lib/public_key/src/pubkey_pem.erl16
-rw-r--r--lib/public_key/src/public_key.erl185
-rw-r--r--lib/public_key/test/erl_make_certs.erl67
-rw-r--r--lib/public_key/test/pkits_SUITE.erl11
-rw-r--r--lib/public_key/test/public_key_SUITE.erl2
-rw-r--r--lib/reltool/src/reltool_utils.erl2
-rw-r--r--lib/ssl/doc/src/ssl.xml15
-rw-r--r--lib/ssl/src/ssl.erl18
-rw-r--r--lib/ssl/src/ssl_certificate.erl15
-rw-r--r--lib/ssl/src/ssl_certificate_db.erl2
-rw-r--r--lib/ssl/src/ssl_cipher.erl450
-rw-r--r--lib/ssl/src/ssl_cipher.hrl120
-rw-r--r--lib/ssl/src/ssl_connection.erl207
-rw-r--r--lib/ssl/src/ssl_handshake.erl348
-rw-r--r--lib/ssl/src/ssl_handshake.hrl52
-rw-r--r--lib/ssl/src/ssl_internal.hrl6
-rw-r--r--lib/ssl/src/ssl_manager.erl4
-rw-r--r--lib/ssl/src/ssl_record.erl10
-rw-r--r--lib/ssl/src/ssl_ssl3.erl10
-rw-r--r--lib/ssl/src/ssl_tls1.erl115
-rw-r--r--lib/ssl/test/erl_make_certs.erl65
-rw-r--r--lib/ssl/test/ssl_basic_SUITE.erl204
-rw-r--r--lib/ssl/test/ssl_certificate_verify_SUITE.erl18
-rw-r--r--lib/ssl/test/ssl_npn_handshake_SUITE.erl12
-rw-r--r--lib/ssl/test/ssl_npn_hello_SUITE.erl16
-rw-r--r--lib/ssl/test/ssl_packet_SUITE.erl4
-rw-r--r--lib/ssl/test/ssl_payload_SUITE.erl12
-rw-r--r--lib/ssl/test/ssl_session_cache_SUITE.erl2
-rw-r--r--lib/ssl/test/ssl_test_lib.erl286
-rw-r--r--lib/ssl/test/ssl_to_openssl_SUITE.erl129
-rw-r--r--lib/stdlib/doc/src/lists.xml25
-rw-r--r--lib/stdlib/src/epp.erl2
-rw-r--r--lib/stdlib/src/erl_pp.erl33
-rw-r--r--lib/stdlib/src/lists.erl24
-rw-r--r--lib/stdlib/src/otp_internal.erl133
-rw-r--r--lib/stdlib/test/epp_SUITE.erl4
-rw-r--r--lib/stdlib/test/erl_pp_SUITE.erl43
-rw-r--r--lib/stdlib/test/ets_SUITE.erl68
-rw-r--r--lib/stdlib/test/gen_server_SUITE.erl16
-rw-r--r--lib/stdlib/test/lists_SUITE.erl4
-rw-r--r--lib/stdlib/test/zip_SUITE.erl25
-rw-r--r--lib/test_server/src/test_server_ctrl.erl4
-rw-r--r--lib/test_server/src/test_server_io.erl17
101 files changed, 7008 insertions, 3825 deletions
diff --git a/lib/common_test/src/ct_logs.erl b/lib/common_test/src/ct_logs.erl
index 1f8160ff03..f5355bfefe 100644
--- a/lib/common_test/src/ct_logs.erl
+++ b/lib/common_test/src/ct_logs.erl
@@ -200,12 +200,19 @@ clear_stylesheet(TC) ->
%%%-----------------------------------------------------------------
%%% @spec get_log_dir() -> {ok,Dir} | {error,Reason}
get_log_dir() ->
- call({get_log_dir,false}).
+ get_log_dir(false).
%%%-----------------------------------------------------------------
%%% @spec get_log_dir(ReturnAbsName) -> {ok,Dir} | {error,Reason}
get_log_dir(ReturnAbsName) ->
- call({get_log_dir,ReturnAbsName}).
+ case call({get_log_dir,ReturnAbsName}) of
+ {error,does_not_exist} when ReturnAbsName == true ->
+ {ok,filename:absname(".")};
+ {error,does_not_exist} ->
+ {ok,"."};
+ Result ->
+ Result
+ end.
%%%-----------------------------------------------------------------
%%% make_last_run_index() -> ok
@@ -552,7 +559,6 @@ log_timestamp({MS,S,US}) ->
logger(Parent, Mode, Verbosity) ->
register(?MODULE,self()),
-
%%! Below is a temporary workaround for the limitation of
%%! max one test run per second.
%%! --->
@@ -984,12 +990,11 @@ print_style_error(Fd,StyleSheet,Reason) ->
print_style(Fd,undefined).
close_ctlog(Fd) ->
- io:format(Fd,"\n</pre>\n",[]),
- io:format(Fd,footer(),[]),
+ io:format(Fd, "\n</pre>\n", []),
+ io:format(Fd, [xhtml("<br><br>\n", "<br /><br />\n") | footer()], []),
file:close(Fd).
-
%%%-----------------------------------------------------------------
%%% Make an index page for the last run
make_last_run_index(StartTime) ->
@@ -1043,7 +1048,7 @@ make_last_run_index1(StartTime,IndexName) ->
0, 0, 0, 0, 0, Missing),
%% write current Totals to file, later to be used in all_runs log
write_totals_file(?totals_name,Label,Logs1,Totals),
- Index = [Index0|index_footer()],
+ Index = [Index0|last_run_index_footer()],
case force_write_file(IndexName, unicode:characters_to_binary(Index)) of
ok ->
@@ -1452,17 +1457,30 @@ header1(Title, SubTitle, TableCols) ->
"</center>\n",
SubTitleHTML,"\n"].
-index_footer() ->
- ["</table>\n"
+last_run_index_footer() ->
+ AllRuns = filename:join("../",?all_runs_name),
+ TestIndex = filename:join("../",?index_name),
+ ["</table>\n",
+ xhtml("<br><hr><p>\n", "<br /><hr /><p>\n"),
+ "<a href=\"", uri(AllRuns),
+ "\">Test run history\n</a> | ",
+ "<a href=\"", uri(TestIndex),
+ "\">Top level test index\n</a>\n</p>\n",
"</center>\n" | footer()].
+all_suites_index_footer() ->
+ ["</table>\n",
+ "</center>\n",
+ xhtml("<br><br>\n", "<br /><br />\n") | footer()].
+
all_runs_index_footer() ->
- ["</tbody>\n</table>\n"
- "</center>\n" | footer()].
+ ["</tbody>\n</table>\n",
+ "</center>\n",
+ xhtml("<br><br>\n", "<br /><br />\n") | footer()].
footer() ->
["<center>\n",
- xhtml("<br><br>\n<hr>\n", "<br /><br />\n"),
+ xhtml("<hr>\n", ""),
xhtml("<p><font size=\"-1\">\n", "<div class=\"copyright\">"),
"Copyright &copy; ", year(),
" <a href=\"http://www.erlang.org\">Open Telecom Platform</a>",
@@ -1474,7 +1492,6 @@ footer() ->
"</body>\n"
"</html>\n"].
-
body_tag() ->
CTPath = code:lib_dir(common_test),
TileFile = filename:join(filename:join(CTPath,"priv"),"tile1.jpg"),
@@ -2376,7 +2393,7 @@ make_all_suites_index2(IndexName, AllTestLogDirs) ->
make_all_suites_index3(AllTestLogDirs,
all_suites_index_header(),
0, 0, 0, 0, 0, [], []),
- Index = [Index0|index_footer()],
+ Index = [Index0|all_suites_index_footer()],
case force_write_file(IndexName, unicode:characters_to_binary(Index)) of
ok ->
{ok,TempData};
@@ -2482,7 +2499,7 @@ make_all_suites_ix_temp(AbsIndexName, NewTestData, Label, AllTestLogDirs) ->
Index0 = make_all_suites_ix_temp1(AllTestLogDirs1,
all_suites_index_header(IndexDir),
0, 0, 0, 0, 0),
- Index = [Index0|index_footer()],
+ Index = [Index0|all_suites_index_footer()],
case force_write_file(AbsIndexName, unicode:characters_to_binary(Index)) of
ok ->
ok;
diff --git a/lib/common_test/src/ct_telnet.erl b/lib/common_test/src/ct_telnet.erl
index beb3c1d649..4755d939e0 100644
--- a/lib/common_test/src/ct_telnet.erl
+++ b/lib/common_test/src/ct_telnet.erl
@@ -309,7 +309,7 @@ expect(Connection,Patterns) ->
%%% Tag = term()
%%% Opts = [Opt]
%%% Opt = {timeout,Timeout} | repeat | {repeat,N} | sequence |
-%%% {halt,HaltPatterns} | ignore_prompt
+%%% {halt,HaltPatterns} | ignore_prompt | no_prompt_check
%%% Timeout = integer()
%%% N = integer()
%%% HaltPatterns = Patterns
@@ -336,14 +336,28 @@ expect(Connection,Patterns) ->
%%% will also include the matched <code>Tag</code>. Else, only
%%% <code>RxMatch</code> is returned.</p>
%%%
-%%% <p>The function will always return when a prompt is found, unless
-%%% the <code>ignore_prompt</code> options is used.</p>
-%%%
%%% <p>The <code>timeout</code> option indicates that the function
%%% shall return if the telnet client is idle (i.e. if no data is
%%% received) for more than <code>Timeout</code> milliseconds. Default
%%% timeout is 10 seconds.</p>
%%%
+%%% <p>The function will always return when a prompt is found, unless
+%%% any of the <code>ignore_prompt</code> or
+%%% <code>no_prompt_check</code> options are used, in which case it
+%%% will return when a match is found or after a timeout.</p>
+%%%
+%%% <p>If the <code>ignore_prompt</code> option is used,
+%%% <code>ct_telnet</code> will ignore any prompt found. This option
+%%% is useful if data sent by the server could include a pattern that
+%%% would match the prompt regexp (as returned by
+%%% <code>TargedMod:get_prompt_regexp/0</code>), but which should not
+%%% cause the function to return.</p>
+%%%
+%%% <p>If the <code>no_prompt_check</code> option is used,
+%%% <code>ct_telnet</code> will not search for a prompt at all. This
+%%% is useful if, for instance, the <code>Pattern</code> itself
+%%% matches the prompt.</p>
+%%%
%%% <p>The <code>repeat</code> option indicates that the pattern(s)
%%% shall be matched multiple times. If <code>N</code> is given, the
%%% pattern(s) will be matched <code>N</code> times, and the function
@@ -729,7 +743,7 @@ teln_get_all_data(Pid,Prx,Data,Acc,LastLine) ->
seq=false,
repeat=false,
found_prompt=false,
- wait_for_linebreak=true}).
+ prompt_check=true}).
%% @hidden
%% @doc Externally the silent_teln_expect function shall only be used
@@ -755,25 +769,27 @@ silent_teln_expect(Pid,Data,Pattern,Prx,Opts) ->
%% condition is fullfilled.
%% 3b) Repeat (sequence): 2) is repeated either N times or until a
%% halt condition is fullfilled.
-teln_expect(Pid,Data,Pattern0,Prx,Opts) ->
- HaltPatterns = case get_ignore_prompt(Opts) of
- true ->
- get_haltpatterns(Opts);
- false ->
- [prompt | get_haltpatterns(Opts)]
- end,
- WaitForLineBreak = get_line_break_opt(Opts),
+teln_expect(Pid,Data,Pattern0,Prx,Opts) ->
+ HaltPatterns =
+ case get_ignore_prompt(Opts) of
+ true ->
+ get_haltpatterns(Opts);
+ false ->
+ [prompt | get_haltpatterns(Opts)]
+ end,
+
+ PromptCheck = get_prompt_check(Opts),
Seq = get_seq(Opts),
Pattern = convert_pattern(Pattern0,Seq),
-
+
Timeout = get_timeout(Opts),
-
+
EO = #eo{teln_pid=Pid,
prx=Prx,
timeout=Timeout,
seq=Seq,
haltpatterns=HaltPatterns,
- wait_for_linebreak=WaitForLineBreak},
+ prompt_check=PromptCheck},
case get_repeat(Opts) of
false ->
@@ -814,11 +830,6 @@ get_timeout(Opts) ->
{value,{timeout,T}} -> T;
false -> ?DEFAULT_TIMEOUT
end.
-get_line_break_opt(Opts) ->
- case lists:keysearch(wait_for_linebreak,1,Opts) of
- {value,{wait_for_linebreak,false}} -> false;
- _ -> true
- end.
get_repeat(Opts) ->
case lists:keysearch(repeat,1,Opts) of
{value,{repeat,N}} when is_integer(N) ->
@@ -842,7 +853,9 @@ get_haltpatterns(Opts) ->
end.
get_ignore_prompt(Opts) ->
lists:member(ignore_prompt,Opts).
-
+get_prompt_check(Opts) ->
+ not lists:member(no_prompt_check,Opts).
+
%% Repeat either single or sequence. All match results are accumulated
%% and returned when a halt condition is fulllfilled.
repeat_expect(Rest,_Pattern,Acc,#eo{repeat=0}) ->
@@ -903,6 +916,9 @@ get_data1(Pid) ->
%% lines and each line is matched against each pattern.
%% one_expect: split data chunk at prompts
+one_expect(Data,Pattern,EO) when EO#eo.prompt_check==false ->
+% io:format("Raw Data ~p Pattern ~p EO ~p ",[Data,Pattern,EO]),
+ one_expect1(Data,Pattern,[],EO#eo{found_prompt=false});
one_expect(Data,Pattern,EO) ->
case match_prompt(Data,EO#eo.prx) of
{prompt,UptoPrompt,PromptType,Rest} ->
@@ -961,6 +977,8 @@ seq_expect(Data,[],Acc,_EO) ->
{match,lists:reverse(Acc),Data};
seq_expect([],Patterns,Acc,_EO) ->
{continue,Patterns,lists:reverse(Acc),[]};
+seq_expect(Data,Patterns,Acc,EO) when EO#eo.prompt_check==false ->
+ seq_expect1(Data,Patterns,Acc,[],EO#eo{found_prompt=false});
seq_expect(Data,Patterns,Acc,EO) ->
case match_prompt(Data,EO#eo.prx) of
{prompt,UptoPrompt,PromptType,Rest} ->
@@ -1015,9 +1033,8 @@ seq_expect1(Data,[],Acc,Rest,_EO) ->
%% Split prompt-chunk at lines
match_lines(Data,Patterns,EO) ->
FoundPrompt = EO#eo.found_prompt,
- NeedLineBreak = EO#eo.wait_for_linebreak,
case one_line(Data,[]) of
- {noline,Rest} when FoundPrompt=/=false, NeedLineBreak =:= true ->
+ {noline,Rest} when FoundPrompt=/=false ->
%% This is the line including the prompt
case match_line(Rest,Patterns,FoundPrompt,EO) of
nomatch ->
@@ -1025,14 +1042,14 @@ match_lines(Data,Patterns,EO) ->
{Tag,Match} ->
{Tag,Match,[]}
end;
- {noline,Rest} when NeedLineBreak =:= false ->
- case match_line(Rest,Patterns,FoundPrompt,EO) of
+ {noline,Rest} when EO#eo.prompt_check==false ->
+ case match_line(Rest,Patterns,false,EO) of
nomatch ->
- {nomatch,prompt};
+ {nomatch,Rest};
{Tag,Match} ->
{Tag,Match,[]}
end;
- {noline, Rest} ->
+ {noline,Rest} ->
{nomatch,Rest};
{Line,Rest} ->
case match_line(Line,Patterns,false,EO) of
diff --git a/lib/common_test/src/ct_telnet_client.erl b/lib/common_test/src/ct_telnet_client.erl
index 7329498ed6..2cbcba9c77 100644
--- a/lib/common_test/src/ct_telnet_client.erl
+++ b/lib/common_test/src/ct_telnet_client.erl
@@ -143,7 +143,9 @@ loop(State, Sock, Acc) ->
State
end;
_ ->
- Pid ! {data,lists:reverse(lists:append(Acc))},
+ Data = lists:reverse(lists:append(Acc)),
+ dbg("get_data ~p\n",[Data]),
+ Pid ! {data,Data},
State
end,
loop(NewState, Sock, []);
@@ -161,7 +163,9 @@ loop(State, Sock, Acc) ->
NewAcc =
case erlang:is_process_alive(Pid) of
true ->
- Pid ! {data,lists:reverse(lists:append(Acc))},
+ Data = lists:reverse(lists:append(Acc)),
+ dbg("get_data_delayed ~p\n",[Data]),
+ Pid ! {data,Data},
[];
false ->
Acc
diff --git a/lib/common_test/src/unix_telnet.erl b/lib/common_test/src/unix_telnet.erl
index 71df2ab44e..88199b07d0 100644
--- a/lib/common_test/src/unix_telnet.erl
+++ b/lib/common_test/src/unix_telnet.erl
@@ -94,16 +94,11 @@ connect(Ip,Port,Timeout,KeepAlive,Extra) ->
{Username,Password} ->
connect1(Ip,Port,Timeout,KeepAlive,Username,Password);
Name ->
- case not_require_user_and_pass(Name) of
- true ->
- connect_without_username_and_pass(Ip,Port,Timeout,KeepAlive);
- _ ->
- case get_username_and_password(Name) of
- {ok,{Username,Password}} ->
- connect1(Ip,Port,Timeout,KeepAlive,Username,Password);
- Error ->
- Error
- end
+ case get_username_and_password(Name) of
+ {ok,{Username,Password}} ->
+ connect1(Ip,Port,Timeout,KeepAlive,Username,Password);
+ Error ->
+ Error
end
end.
@@ -149,27 +144,6 @@ connect1(Ip,Port,Timeout,KeepAlive,Username,Password) ->
end_log(),
Result.
-connect_without_username_and_pass(Ip,Port,Timeout,KeepAlive) ->
- start_log("unix_telnet:connect"),
- Result =
- case ct_telnet_client:open(Ip,Port,Timeout,KeepAlive) of
- {ok,Pid} ->
- {ok, Pid};
- Error ->
- cont_log("Could not open telnet connection\n~p\n",[Error]),
- Error
- end,
- end_log(),
- Result.
-
-not_require_user_and_pass(Name) ->
- case ct:get_config({Name, not_require_user_and_pass}) of
- undefined ->
- false;
- _ ->
- true
- end.
-
get_username_and_password(Name) ->
case ct:get_config({Name,username}) of
undefined ->
diff --git a/lib/common_test/test/Makefile b/lib/common_test/test/Makefile
index 94569fa87f..31ab28c41d 100644
--- a/lib/common_test/test/Makefile
+++ b/lib/common_test/test/Makefile
@@ -28,6 +28,7 @@ MODULES= \
ct_test_support \
ct_test_support_eh \
ct_userconfig_callback \
+ telnet_server \
ct_smoke_test_SUITE \
ct_priv_dir_SUITE \
ct_event_handler_SUITE \
diff --git a/lib/common_test/test/ct_telnet_SUITE.erl b/lib/common_test/test/ct_telnet_SUITE.erl
index b4f24baa0c..17617f59eb 100644
--- a/lib/common_test/test/ct_telnet_SUITE.erl
+++ b/lib/common_test/test/ct_telnet_SUITE.erl
@@ -33,6 +33,10 @@
-define(eh, ct_test_support_eh).
+-define(erl_telnet_server_port,1234).
+-define(erl_telnet_server_user,"telnuser").
+-define(erl_telnet_server_pwd,"telnpwd").
+
%%--------------------------------------------------------------------
%% TEST SERVER CALLBACK FUNCTIONS
%%--------------------------------------------------------------------
@@ -48,17 +52,27 @@ init_per_suite(Config) ->
end_per_suite(Config) ->
ct_test_support:end_per_suite(Config).
+init_per_testcase(TestCase, Config) when TestCase=/=unix_telnet->
+ TS = telnet_server:start([{port,?erl_telnet_server_port},
+ {users,[{?erl_telnet_server_user,
+ ?erl_telnet_server_pwd}]}]),
+ ct_test_support:init_per_testcase(TestCase, [{telnet_server,TS}|Config]);
init_per_testcase(TestCase, Config) ->
ct_test_support:init_per_testcase(TestCase, Config).
end_per_testcase(TestCase, Config) ->
+ case ?config(telnet_server,Config) of
+ undefined -> ok;
+ TS -> telnet_server:stop(TS)
+ end,
ct_test_support:end_per_testcase(TestCase, Config).
suite() -> [{ct_hooks,[ts_install_cth]}].
all() ->
[
- default
+ unix_telnet,
+ own_server
].
%%--------------------------------------------------------------------
@@ -67,19 +81,29 @@ all() ->
%%%-----------------------------------------------------------------
%%%
-default(Config) when is_list(Config) ->
- DataDir = ?config(data_dir, Config),
- Suite = filename:join(DataDir, "ct_telnet_basic_SUITE"),
- Cfg = {unix, ct:get_config(unix)},
- ok = file:write_file(filename:join(DataDir, "telnet.cfg"), io_lib:write(Cfg) ++ "."),
- CfgFile = filename:join(DataDir, "telnet.cfg"),
- {Opts,ERPid} = setup([{suite,Suite},{label,default}, {config, CfgFile}], Config),
- ok = execute(default, Opts, ERPid, Config).
+unix_telnet(Config) when is_list(Config) ->
+ all_tests_in_suite(unix_telnet,"ct_telnet_basic_SUITE","telnet.cfg",Config).
+
+own_server(Config) ->
+ all_tests_in_suite(own_server,"ct_telnet_own_server_SUITE",
+ "telnet2.cfg",Config).
%%%-----------------------------------------------------------------
%%% HELP FUNCTIONS
%%%-----------------------------------------------------------------
+all_tests_in_suite(TestCase, SuiteName, CfgFileName, Config) ->
+ DataDir = ?config(data_dir, Config),
+ Suite = filename:join(DataDir, SuiteName),
+ CfgFile = filename:join(DataDir, CfgFileName),
+ Cfg = telnet_config(TestCase),
+ ok = file:write_file(CfgFile, io_lib:write(Cfg) ++ "."),
+ {Opts,ERPid} = setup([{suite,Suite},
+ {label,TestCase},
+ {config,CfgFile}],
+ Config),
+ ok = execute(TestCase, Opts, ERPid, Config).
+
setup(Test, Config) ->
Opts0 = ct_test_support:get_opts(Config),
Level = ?config(trace_level, Config),
@@ -103,19 +127,34 @@ execute(Name, Opts, ERPid, Config) ->
reformat(Events, EH) ->
ct_test_support:reformat(Events, EH).
+
+telnet_config(unix_telnet) ->
+ {unix, ct:get_config(unix)};
+telnet_config(_) ->
+ {unix,[{telnet,"localhost"},
+ {port, ?erl_telnet_server_port},
+ {username,?erl_telnet_server_user},
+ {password,?erl_telnet_server_pwd},
+ {keep_alive,true}]}.
+
%%%-----------------------------------------------------------------
%%% TEST EVENTS
%%%-----------------------------------------------------------------
-events_to_check(default,Config) ->
+events_to_check(unix_telnet,Config) ->
+ all_cases(ct_telnet_basic_SUITE,Config);
+events_to_check(own_server,Config) ->
+ all_cases(ct_telnet_own_server_SUITE,Config).
+
+all_cases(Suite,Config) ->
{module,_} = code:load_abs(filename:join(?config(data_dir,Config),
- ct_telnet_basic_SUITE)),
- TCs = ct_telnet_basic_SUITE:all(),
- code:purge(ct_telnet_basic_SUITE),
- code:delete(ct_telnet_basic_SUITE),
+ Suite)),
+ TCs = Suite:all(),
+ code:purge(Suite),
+ code:delete(Suite),
OneTest =
[{?eh,start_logging,{'DEF','RUNDIR'}}] ++
- [{?eh,tc_done,{ct_telnet_basic_SUITE,TC,ok}} || TC <- TCs] ++
+ [{?eh,tc_done,{Suite,TC,ok}} || TC <- TCs] ++
[{?eh,stop_logging,[]}],
%% 2 tests (ct:run_test + script_start) is default
diff --git a/lib/common_test/test/ct_telnet_SUITE_data/ct_telnet_own_server_SUITE.erl b/lib/common_test/test/ct_telnet_SUITE_data/ct_telnet_own_server_SUITE.erl
new file mode 100644
index 0000000000..3f7c0d68bf
--- /dev/null
+++ b/lib/common_test/test/ct_telnet_SUITE_data/ct_telnet_own_server_SUITE.erl
@@ -0,0 +1,184 @@
+-module(ct_telnet_own_server_SUITE).
+
+-compile(export_all).
+
+-include_lib("common_test/include/ct.hrl").
+
+%%--------------------------------------------------------------------
+%% TEST SERVER CALLBACK FUNCTIONS
+%%--------------------------------------------------------------------
+
+init_per_suite(Config) ->
+ Config.
+
+end_per_suite(_Config) ->
+ ok.
+
+
+suite() -> [{require,erl_telnet_server,{unix,[telnet]}}].
+
+all() ->
+ [expect,
+ expect_repeat,
+ expect_sequence,
+ expect_error_prompt,
+ expect_error_timeout,
+ no_prompt_check,
+ no_prompt_check_repeat,
+ no_prompt_check_sequence,
+ no_prompt_check_timeout,
+ ignore_prompt,
+ ignore_prompt_repeat,
+ ignore_prompt_sequence,
+ ignore_prompt_timeout].
+
+groups() ->
+ [].
+
+init_per_group(_GroupName, Config) ->
+ Config.
+
+end_per_group(_GroupName, Config) ->
+ Config.
+
+%% Simple expect
+expect(_) ->
+ {ok, Handle} = ct_telnet:open(erl_telnet_server),
+ ok = ct_telnet:send(Handle, "echo ayt"),
+ {ok,["ayt"]} = ct_telnet:expect(Handle, ["ayt"]),
+ ok = ct_telnet:close(Handle),
+ ok.
+
+%% Expect with repeat option
+expect_repeat(_) ->
+ {ok, Handle} = ct_telnet:open(erl_telnet_server),
+ ok = ct_telnet:send(Handle, "echo_ml xy xy"),
+ {ok,[["xy"],["xy"]],done} = ct_telnet:expect(Handle, ["xy"],[{repeat,2}]),
+ ok = ct_telnet:close(Handle),
+ ok.
+
+%% Expect with sequence option
+expect_sequence(_) ->
+ {ok, Handle} = ct_telnet:open(erl_telnet_server),
+ ok = ct_telnet:send(Handle, "echo_ml ab cd ef"),
+ {ok,[["ab"],["cd"],["ef"]]} = ct_telnet:expect(Handle,
+ [["ab"],["cd"],["ef"]],
+ [sequence]),
+ ok = ct_telnet:close(Handle),
+ ok.
+
+%% Check that expect returns when a prompt is found, even if pattern
+%% is not matched.
+expect_error_prompt(_) ->
+ {ok, Handle} = ct_telnet:open(erl_telnet_server),
+ ok = ct_telnet:send(Handle, "echo xxx> yyy"),
+ {error,{prompt,"> "}} = ct_telnet:expect(Handle, ["yyy"]),
+ ok = ct_telnet:close(Handle),
+ ok.
+
+%% Check that expect returns after idle timeout, and even if the
+%% expected pattern is received - as long as not newline or prompt is
+%% received it will not match.
+expect_error_timeout(_) ->
+ {ok, Handle} = ct_telnet:open(erl_telnet_server),
+ ok = ct_telnet:send(Handle, "echo_no_prompt xxx"),
+ {error,timeout} = ct_telnet:expect(Handle, ["xxx"], [{timeout,1000}]),
+ ok = ct_telnet:close(Handle),
+ ok.
+
+%% expect with ignore_prompt option should not return even if a prompt
+%% is found. The pattern after the prompt (here "> ") can be matched.
+ignore_prompt(_) ->
+ {ok, Handle} = ct_telnet:open(erl_telnet_server),
+ ok = ct_telnet:send(Handle, "echo xxx> yyy"),
+ {ok,["yyy"]} = ct_telnet:expect(Handle, ["yyy"], [ignore_prompt]),
+ ok = ct_telnet:close(Handle),
+ ok.
+
+%% expect with ignore_prompt and repeat options.
+ignore_prompt_repeat(_) ->
+ {ok, Handle} = ct_telnet:open(erl_telnet_server),
+ ok = ct_telnet:send(Handle, "echo_ml yyy> yyy>"),
+ {ok,[["yyy"],["yyy"]],done} = ct_telnet:expect(Handle, ["yyy"],
+ [{repeat,2},
+ ignore_prompt]),
+ ok = ct_telnet:close(Handle),
+ ok.
+
+%% expect with ignore_prompt and sequence options.
+ignore_prompt_sequence(_) ->
+ {ok, Handle} = ct_telnet:open(erl_telnet_server),
+ ok = ct_telnet:send(Handle, "echo_ml xxx> yyy> zzz> "),
+ {ok,[["xxx"],["yyy"],["zzz"]]} = ct_telnet:expect(Handle,
+ [["xxx"],["yyy"],["zzz"]],
+ [sequence,
+ ignore_prompt]),
+ ok = ct_telnet:close(Handle),
+ ok.
+
+%% Check that expect returns after idle timeout when ignore_prompt
+%% option is used.
+%% As for expect without the ignore_prompt option, it a newline or a
+%% prompt is required in order for the pattern to match.
+ignore_prompt_timeout(_) ->
+ {ok, Handle} = ct_telnet:open(erl_telnet_server),
+ ok = ct_telnet:send(Handle, "echo xxx"),
+ {error,timeout} = ct_telnet:expect(Handle, ["yyy"], [ignore_prompt,
+ {timeout,1000}]),
+ ok = ct_telnet:send(Handle, "echo xxx"), % sends prompt and newline
+ {ok,["xxx"]} = ct_telnet:expect(Handle, ["xxx"], [ignore_prompt,
+ {timeout,1000}]),
+ ok = ct_telnet:send(Handle, "echo_no_prompt xxx\n"), % no prompt, but newline
+ {ok,["xxx"]} = ct_telnet:expect(Handle, ["xxx"], [ignore_prompt,
+ {timeout,1000}]),
+ ok = ct_telnet:send(Handle, "echo_no_prompt xxx"), % no prompt, no newline
+ {error,timeout} = ct_telnet:expect(Handle, ["xxx"], [ignore_prompt,
+ {timeout,1000}]),
+ ok = ct_telnet:close(Handle),
+ ok.
+
+%% no_prompt_check option shall match pattern both when prompt is sent
+%% and when it is not.
+no_prompt_check(_) ->
+ {ok, Handle} = ct_telnet:open(erl_telnet_server),
+ ok = ct_telnet:send(Handle, "echo xxx"),
+ {ok,["xxx"]} = ct_telnet:expect(Handle, ["xxx"], [no_prompt_check]),
+ ok = ct_telnet:send(Handle, "echo_no_prompt yyy"),
+ {ok,["yyy"]} = ct_telnet:expect(Handle, ["yyy"], [no_prompt_check]),
+ ok = ct_telnet:close(Handle),
+ ok.
+
+%% no_prompt_check and repeat options
+no_prompt_check_repeat(_) ->
+ {ok, Handle} = ct_telnet:open(erl_telnet_server),
+ ok = ct_telnet:send(Handle, "echo_ml xxx xxx"),
+ {ok,[["xxx"],["xxx"]],done} = ct_telnet:expect(Handle,["xxx"],
+ [{repeat,2},
+ no_prompt_check]),
+ ok = ct_telnet:send(Handle, "echo_ml_no_prompt yyy yyy"),
+ {ok,[["yyy"],["yyy"]],done} = ct_telnet:expect(Handle,["yyy"],
+ [{repeat,2},
+ no_prompt_check]),
+ ok = ct_telnet:close(Handle),
+ ok.
+
+%% no_prompt_check and sequence options
+no_prompt_check_sequence(_) ->
+ {ok, Handle} = ct_telnet:open(erl_telnet_server),
+ ok = ct_telnet:send(Handle, "echo_ml_no_prompt ab cd ef"),
+ {ok,[["ab"],["cd"],["ef"]]} = ct_telnet:expect(Handle,
+ [["ab"],["cd"],["ef"]],
+ [sequence,
+ no_prompt_check]),
+ ok = ct_telnet:close(Handle),
+ ok.
+
+%% Check that expect returns after idle timeout when no_prompt_check
+%% option is used.
+no_prompt_check_timeout(_) ->
+ {ok, Handle} = ct_telnet:open(erl_telnet_server),
+ ok = ct_telnet:send(Handle, "echo xxx"),
+ {error,timeout} = ct_telnet:expect(Handle, ["yyy"], [no_prompt_check,
+ {timeout,1000}]),
+ ok = ct_telnet:close(Handle),
+ ok.
diff --git a/lib/common_test/test/telnet_server.erl b/lib/common_test/test/telnet_server.erl
new file mode 100644
index 0000000000..31884aa182
--- /dev/null
+++ b/lib/common_test/test/telnet_server.erl
@@ -0,0 +1,228 @@
+-module(telnet_server).
+-compile(export_all).
+
+%% telnet control characters
+-define(SE, 240).
+-define(NOP, 241).
+-define(DM, 242).
+-define(BRK, 243).
+-define(IP, 244).
+-define(AO, 245).
+-define(AYT, 246).
+-define(EC, 247).
+-define(EL, 248).
+-define(GA, 249).
+-define(SB, 250).
+-define(WILL, 251).
+-define(WONT, 252).
+-define(DO, 253).
+-define(DONT, 254).
+-define(IAC, 255).
+
+%% telnet options
+-define(BINARY, 0).
+-define(ECHO, 1).
+-define(SUPPRESS_GO_AHEAD, 3).
+-define(TERMINAL_TYPE, 24).
+
+-record(state,
+ {listen,
+ client,
+ users,
+ authorized=false,
+ suppress_go_ahead=false,
+ buffer=[]}).
+
+-type options() :: [{port,pos_integer()} | {users,users()}].
+-type users() :: [{user(),password()}].
+-type user() :: string().
+-type password() :: string().
+
+-spec start(Opts::options()) -> Pid::pid().
+start(Opts) when is_list(Opts) ->
+ spawn_link(fun() -> init(Opts) end).
+
+-spec stop(Pid::pid()) -> ok.
+stop(Pid) ->
+ Ref = erlang:monitor(process,Pid),
+ Pid ! stop,
+ receive {'DOWN',Ref,_,_,_} -> ok end.
+
+init(Opts) ->
+ Port = proplists:get_value(port,Opts),
+ Users = proplists:get_value(users,Opts,[]),
+ {ok, LSock} = gen_tcp:listen(Port, [list, {packet, 0},
+ {active, true}]),
+ State = #state{listen=LSock,users=Users},
+ accept(State),
+ ok = gen_tcp:close(LSock).
+
+accept(#state{listen=LSock}=State) ->
+ Server = self(),
+ Acceptor = spawn_link(fun() -> do_accept(LSock,Server) end),
+ receive
+ {Acceptor,Sock} when is_port(Sock) ->
+ case init_client(State#state{client=Sock}) of
+ stopped ->
+ io:format("telnet_server stopped\n"),
+ ok;
+ R ->
+ io:format("connection to client closed with reason ~p~n",[R]),
+ accept(State)
+ end;
+ {Acceptor,closed} ->
+ io:format("listen socket closed unexpectedly, "
+ "terminating telnet_server\n"),
+ ok;
+ stop ->
+ io:format("telnet_server stopped\n"),
+ ok
+ end.
+
+do_accept(LSock,Server) ->
+ case gen_tcp:accept(LSock) of
+ {ok, Sock} ->
+ ok = gen_tcp:controlling_process(Sock,Server),
+ Server ! {self(),Sock};
+ {error,closed} ->
+ %% This will happen when stop/1 is called, since listen
+ %% socket is closed. Then the server is probably already
+ %% dead by now, but to be 100% sure not to hang, we send a
+ %% message to say what happened.
+ Server ! {self(),closed}
+ end.
+
+init_client(#state{client=Sock}=State) ->
+ dbg("Server sending: ~p~n",["login: "]),
+ R = case gen_tcp:send(Sock,"login: ") of
+ ok ->
+ loop(State);
+ Error ->
+ Error
+ end,
+ _ = gen_tcp:close(Sock),
+ R.
+
+loop(State) ->
+ receive
+ {tcp,_,Data} ->
+ try handle_data(Data,State) of
+ {ok,State1} ->
+ loop(State1)
+ catch
+ throw:Error ->
+ Error
+ end;
+ {tcp_closed, _} ->
+ closed;
+ {tcp_error,_,Error} ->
+ {error,tcp,Error};
+ stop ->
+ stopped
+ end.
+
+handle_data([?IAC|Cmd],State) ->
+ dbg("Server got cmd: ~p~n",[Cmd]),
+ handle_cmd(Cmd,State);
+handle_data(Data,State) ->
+ dbg("Server got data: ~p~n",[Data]),
+ case get_line(Data,[]) of
+ {Line,Rest} ->
+ WholeLine = lists:flatten(lists:reverse(State#state.buffer,Line)),
+ {ok,State1} = do_handle_data(WholeLine,State),
+ case Rest of
+ [] -> {ok,State1};
+ _ -> handle_data(Rest,State1)
+ end;
+ false ->
+ {ok,State#state{buffer=[Data|State#state.buffer]}}
+ end.
+
+%% Add function clause below to handle new telnet commands (sent with
+%% ?IAC from client - this is not possible to do from ct_telnet API,
+%% but ct_telnet sends DONT SUPPRESS_GO_AHEAD)
+handle_cmd([?DO,?SUPPRESS_GO_AHEAD|T],State) ->
+ send([?IAC,?WILL,?SUPPRESS_GO_AHEAD],State),
+ handle_cmd(T,State#state{suppress_go_ahead=true});
+handle_cmd([?DONT,?SUPPRESS_GO_AHEAD|T],State) ->
+ send([?IAC,?WONT,?SUPPRESS_GO_AHEAD],State),
+ handle_cmd(T,State#state{suppress_go_ahead=false});
+handle_cmd([?IAC|T],State) ->
+ %% Multiple commands in one packet
+ handle_cmd(T,State);
+handle_cmd([_H|T],State) ->
+ %% Not responding to this command
+ handle_cmd(T,State);
+handle_cmd([],State) ->
+ {ok,State}.
+
+%% Add function clause below to handle new text command (text entered
+%% from the telnet prompt)
+do_handle_data(Data,#state{authorized=false}=State) ->
+ check_user(Data,State);
+do_handle_data(Data,#state{authorized={user,_}}=State) ->
+ check_pwd(Data,State);
+do_handle_data("echo "++ Data,State) ->
+ send(Data++"\r\n> ",State),
+ {ok,State};
+do_handle_data("echo_no_prompt "++ Data,State) ->
+ send(Data,State),
+ {ok,State};
+do_handle_data("echo_ml "++ Data,State) ->
+ Lines = string:tokens(Data," "),
+ ReturnData = string:join(Lines,"\n"),
+ send(ReturnData++"\r\n> ",State),
+ {ok,State};
+do_handle_data("echo_ml_no_prompt "++ Data,State) ->
+ Lines = string:tokens(Data," "),
+ ReturnData = string:join(Lines,"\n"),
+ send(ReturnData,State),
+ {ok,State};
+do_handle_data([],State) ->
+ send("> ",State),
+ {ok,State};
+do_handle_data(_Data,State) ->
+ send("error: unknown command\r\n> ",State),
+ {ok,State}.
+
+check_user(User,State) ->
+ case lists:keyfind(User,1,State#state.users) of
+ {User,Pwd} ->
+ dbg("user ok\n"),
+ send("Password: ",State),
+ {ok,State#state{authorized={user,Pwd}}};
+ false ->
+ throw({error,unknown_user})
+ end.
+
+check_pwd(Pwd,#state{authorized={user,Pwd}}=State) ->
+ dbg("password ok\n"),
+ send("Welcome to the ultimate telnet server!\r\n> ",State),
+ {ok,State#state{authorized=true}};
+check_pwd(_,_State) ->
+ throw({error,authentication}).
+
+send(Data,State) ->
+ dbg("Server sending: ~p~n",[Data]),
+ case gen_tcp:send(State#state.client,Data) of
+ ok ->
+ ok;
+ {error,Error} ->
+ throw({error,send,Error})
+ end.
+
+get_line([$\r,$\n|Rest],Acc) ->
+ {lists:reverse(Acc),Rest};
+get_line([$\r,0|Rest],Acc) ->
+ {lists:reverse(Acc),Rest};
+get_line([$\n|Rest],Acc) ->
+ {lists:reverse(Acc),Rest};
+get_line([H|T],Acc) ->
+ get_line(T,[H|Acc]);
+get_line([],_) ->
+ false.
+
+dbg(_F) ->
+ io:format(_F).
+dbg(_F,_A) ->
+ io:format(_F,_A).
diff --git a/lib/compiler/src/beam_receive.erl b/lib/compiler/src/beam_receive.erl
index 3dd5ed182e..97a9188ee7 100644
--- a/lib/compiler/src/beam_receive.erl
+++ b/lib/compiler/src/beam_receive.erl
@@ -151,20 +151,20 @@ opt_recv(Is, Regs, D) ->
opt_recv([{label,L}=Lbl,{loop_rec,{f,Fail},_}=Loop|Is], D, R0, _, Acc) ->
R = regs_kill_not_live(0, R0),
- case regs_to_list(R) of
- [{y,_}=RefReg] ->
- %% We now have the new reference in the Y register RefReg
+ case regs_empty(R) of
+ false ->
+ %% We now have the new reference in Y registers
%% and the current instruction is the beginning of a
%% receive statement. We must now verify that only messages
%% that contain the reference will be matched.
- case opt_ref_used(Is, RefReg, Fail, D) of
+ case opt_ref_used(Is, R, Fail, D) of
false ->
no;
true ->
RecvSet = {recv_set,{f,L}},
{yes,reverse(Acc, [RecvSet,Lbl,Loop|Is]),L}
end;
- [] ->
+ true ->
no
end;
opt_recv([I|Is], D, R0, L0, Acc) ->
@@ -226,9 +226,9 @@ opt_update_regs_bl([{set,Ds,_,_}|Is], Regs0) ->
opt_update_regs_bl(Is, Regs);
opt_update_regs_bl([], Regs) -> Regs.
-%% opt_ref_used([Instruction], RefRegister, FailLabel, LabelIndex) -> true|false
+%% opt_ref_used([Instruction], RefRegs, FailLabel, LabelIndex) -> true|false
%% Return 'true' if it is certain that only messages that contain the same
-%% reference as in RefRegister can be matched out. Otherwise return 'false'.
+%% reference as in RefRegs can be matched out. Otherwise return 'false'.
%%
%% Basically, we follow all possible paths through the receive statement.
%% If all paths are safe, we return 'true'.
@@ -236,7 +236,7 @@ opt_update_regs_bl([], Regs) -> Regs.
%% A branch to FailLabel is safe, because it exits the receive statement
%% and no further message may be matched out.
%%
-%% If a path hits an comparision between RefRegister and part of the message,
+%% If a path hits an comparision between RefRegs and part of the message,
%% that path is safe (any messages that may be matched further down the
%% path is guaranteed to contain the reference).
%%
@@ -245,11 +245,11 @@ opt_update_regs_bl([], Regs) -> Regs.
%% we hit an unrecognized instruction, we also give up and return
%% 'false' (the optimization may be unsafe).
-opt_ref_used(Is, RefReg, Fail, D) ->
+opt_ref_used(Is, RefRegs, Fail, D) ->
Done = gb_sets:singleton(Fail),
Regs = regs_init_x0(),
try
- _ = opt_ref_used_1(Is, RefReg, D, Done, Regs),
+ _ = opt_ref_used_1(Is, RefRegs, D, Done, Regs),
true
catch
throw:not_used ->
@@ -258,37 +258,39 @@ opt_ref_used(Is, RefReg, Fail, D) ->
%% This functions only returns if all paths through the receive
%% statement are safe, and throws an 'not_used' term otherwise.
-opt_ref_used_1([{block,Bl}|Is], RefReg, D, Done, Regs0) ->
+opt_ref_used_1([{block,Bl}|Is], RefRegs, D, Done, Regs0) ->
Regs = opt_ref_used_bl(Bl, Regs0),
- opt_ref_used_1(Is, RefReg, D, Done, Regs);
-opt_ref_used_1([{test,is_eq_exact,{f,Fail},Args}|Is], RefReg, D, Done0, Regs) ->
- Done = opt_ref_used_at(Fail, RefReg, D, Done0, Regs),
- case is_ref_msg_comparison(Args, RefReg, Regs) of
+ opt_ref_used_1(Is, RefRegs, D, Done, Regs);
+opt_ref_used_1([{test,is_eq_exact,{f,Fail},Args}|Is],
+ RefRegs, D, Done0, Regs) ->
+ Done = opt_ref_used_at(Fail, RefRegs, D, Done0, Regs),
+ case is_ref_msg_comparison(Args, RefRegs, Regs) of
false ->
- opt_ref_used_1(Is, RefReg, D, Done, Regs);
+ opt_ref_used_1(Is, RefRegs, D, Done, Regs);
true ->
%% The instructions that follow (Is) can only be executed
- %% if the message contains the same reference as in RefReg.
+ %% if the message contains the same reference as in RefRegs.
Done
end;
-opt_ref_used_1([{test,is_ne_exact,{f,Fail},Args}|Is], RefReg, D, Done0, Regs) ->
- Done = opt_ref_used_1(Is, RefReg, D, Done0, Regs),
- case is_ref_msg_comparison(Args, RefReg, Regs) of
+opt_ref_used_1([{test,is_ne_exact,{f,Fail},Args}|Is],
+ RefRegs, D, Done0, Regs) ->
+ Done = opt_ref_used_1(Is, RefRegs, D, Done0, Regs),
+ case is_ref_msg_comparison(Args, RefRegs, Regs) of
false ->
- opt_ref_used_at(Fail, RefReg, D, Done, Regs);
+ opt_ref_used_at(Fail, RefRegs, D, Done, Regs);
true ->
Done
end;
-opt_ref_used_1([{test,_,{f,Fail},_}|Is], RefReg, D, Done0, Regs) ->
- Done = opt_ref_used_at(Fail, RefReg, D, Done0, Regs),
- opt_ref_used_1(Is, RefReg, D, Done, Regs);
-opt_ref_used_1([{select,_,_,{f,Fail},List}|_], RefReg, D, Done, Regs) ->
+opt_ref_used_1([{test,_,{f,Fail},_}|Is], RefRegs, D, Done0, Regs) ->
+ Done = opt_ref_used_at(Fail, RefRegs, D, Done0, Regs),
+ opt_ref_used_1(Is, RefRegs, D, Done, Regs);
+opt_ref_used_1([{select,_,_,{f,Fail},List}|_], RefRegs, D, Done, Regs) ->
Lbls = [F || {f,F} <- List] ++ [Fail],
- opt_ref_used_in_all(Lbls, RefReg, D, Done, Regs);
-opt_ref_used_1([{label,Lbl}|Is], RefReg, D, Done, Regs) ->
+ opt_ref_used_in_all(Lbls, RefRegs, D, Done, Regs);
+opt_ref_used_1([{label,Lbl}|Is], RefRegs, D, Done, Regs) ->
case gb_sets:is_member(Lbl, Done) of
true -> Done;
- false -> opt_ref_used_1(Is, RefReg, D, Done, Regs)
+ false -> opt_ref_used_1(Is, RefRegs, D, Done, Regs)
end;
opt_ref_used_1([{loop_rec_end,_}|_], _, _, Done, _) ->
Done;
@@ -296,27 +298,25 @@ opt_ref_used_1([_I|_], _RefReg, _D, _Done, _Regs) ->
%% The optimization may be unsafe.
throw(not_used).
-%% is_ref_msg_comparison(Args, RefReg, RegisterSet) -> true|false.
+%% is_ref_msg_comparison(Args, RefRegs, RegisterSet) -> true|false.
%% Return 'true' if Args denotes a comparison between the
%% reference and message or part of the message.
-is_ref_msg_comparison([R,RefReg], RefReg, Regs) ->
- regs_is_member(R, Regs);
-is_ref_msg_comparison([RefReg,R], RefReg, Regs) ->
- regs_is_member(R, Regs);
-is_ref_msg_comparison([_,_], _, _) -> false.
-
-opt_ref_used_in_all([L|Ls], RefReg, D, Done0, Regs) ->
- Done = opt_ref_used_at(L, RefReg, D, Done0, Regs),
- opt_ref_used_in_all(Ls, RefReg, D, Done, Regs);
+is_ref_msg_comparison([R1,R2], RefRegs, Regs) ->
+ (regs_is_member(R2, RefRegs) andalso regs_is_member(R1, Regs)) orelse
+ (regs_is_member(R1, RefRegs) andalso regs_is_member(R2, Regs)).
+
+opt_ref_used_in_all([L|Ls], RefRegs, D, Done0, Regs) ->
+ Done = opt_ref_used_at(L, RefRegs, D, Done0, Regs),
+ opt_ref_used_in_all(Ls, RefRegs, D, Done, Regs);
opt_ref_used_in_all([], _, _, Done, _) -> Done.
-opt_ref_used_at(Fail, RefReg, D, Done0, Regs) ->
+opt_ref_used_at(Fail, RefRegs, D, Done0, Regs) ->
case gb_sets:is_member(Fail, Done0) of
true ->
Done0;
false ->
Is = beam_utils:code_at(Fail, D),
- Done = opt_ref_used_1(Is, RefReg, D, Done0, Regs),
+ Done = opt_ref_used_1(Is, RefRegs, D, Done0, Regs),
gb_sets:add(Fail, Done)
end.
@@ -408,15 +408,3 @@ regs_all_members([], _) -> true.
regs_is_member({x,N}, {Regs,_}) -> Regs band (1 bsl N) =/= 0;
regs_is_member({y,N}, {_,Regs}) -> Regs band (1 bsl N) =/= 0;
regs_is_member(_, _) -> false.
-
-%% regs_to_list(RegisterSet) -> [Register]
-%% Convert the register set to an explicit list of registers.
-regs_to_list({Xregs,Yregs}) ->
- regs_to_list_1(Xregs, 0, x, regs_to_list_1(Yregs, 0, y, [])).
-
-regs_to_list_1(0, _, _, Acc) ->
- Acc;
-regs_to_list_1(Regs, N, Tag, Acc) when (Regs band 1) =:= 1 ->
- regs_to_list_1(Regs bsr 1, N+1, Tag, [{Tag,N}|Acc]);
-regs_to_list_1(Regs, N, Tag, Acc) ->
- regs_to_list_1(Regs bsr 1, N+1, Tag, Acc).
diff --git a/lib/compiler/test/receive_SUITE.erl b/lib/compiler/test/receive_SUITE.erl
index b91f2922fb..e60584d4ab 100644
--- a/lib/compiler/test/receive_SUITE.erl
+++ b/lib/compiler/test/receive_SUITE.erl
@@ -188,7 +188,7 @@ ref_opt(Config) when is_list(Config) ->
ref_opt_1(Config) ->
?line DataDir = ?config(data_dir, Config),
?line PrivDir = ?config(priv_dir, Config),
- ?line Sources = filelib:wildcard(filename:join([DataDir,"ref_opt","*.erl"])),
+ Sources = filelib:wildcard(filename:join([DataDir,"ref_opt","*.{erl,S}"])),
?line test_lib:p_run(fun(Src) ->
do_ref_opt(Src, PrivDir)
end, Sources),
@@ -196,10 +196,15 @@ ref_opt_1(Config) ->
do_ref_opt(Source, PrivDir) ->
try
- {ok,Mod} = c:c(Source, [{outdir,PrivDir}]),
+ Ext = filename:extension(Source),
+ {ok,Mod} = compile:file(Source, [report_errors,report_warnings,
+ {outdir,PrivDir}] ++
+ [from_asm || Ext =:= ".S" ]),
+ Base = filename:rootname(filename:basename(Source), Ext),
+ code:purge(list_to_atom(Base)),
+ BeamFile = filename:join(PrivDir, Base),
+ code:load_abs(BeamFile),
ok = Mod:Mod(),
- Base = filename:rootname(filename:basename(Source), ".erl"),
- BeamFile = filename:join(PrivDir, Base),
{beam_file,Mod,_,_,_,Code} = beam_disasm:file(BeamFile),
case Base of
"no_"++_ ->
diff --git a/lib/compiler/test/receive_SUITE_data/ref_opt/yes_14.S b/lib/compiler/test/receive_SUITE_data/ref_opt/yes_14.S
new file mode 100644
index 0000000000..fd14228135
--- /dev/null
+++ b/lib/compiler/test/receive_SUITE_data/ref_opt/yes_14.S
@@ -0,0 +1,71 @@
+{module, yes_14}. %% version = 0
+
+{exports, [{f,2},{module_info,0},{module_info,1},{yes_14,0}]}.
+
+{attributes, []}.
+
+{labels, 12}.
+
+
+{function, yes_14, 0, 2}.
+ {label,1}.
+ {func_info,{atom,yes_14},{atom,yes_14},0}.
+ {label,2}.
+ {move,{atom,ok},{x,0}}.
+ return.
+
+
+{function, f, 2, 4}.
+ {label,3}.
+ {func_info,{atom,yes_14},{atom,f},2}.
+ {label,4}.
+ {allocate_heap,2,3,2}.
+ {move,{x,0},{y,1}}.
+ {put_tuple,2,{y,0}}.
+ {put,{atom,data}}.
+ {put,{x,1}}.
+ {call_ext,0,{extfunc,erlang,make_ref,0}}. % Ref in [x0]
+ {test_heap,4,1}.
+ {put_tuple,3,{x,1}}.
+ {put,{atom,request}}.
+ {put,{x,0}}.
+ {put,{y,0}}.
+ {move,{x,0},{y,0}}. % Ref in [x0,y0]
+ {move,{y,1},{x,0}}. % Ref in [y0]
+ {kill,{y,1}}.
+ send.
+ {move,{y,0},{x,0}}. % Ref in [x0,y0]
+ {move,{x,0},{y,1}}. % Ref in [x0,y0,y1]
+ {label,5}.
+ {loop_rec,{f,7},{x,0}}. % Ref in [y0,y1]
+ {test,is_tuple,{f,6},[{x,0}]}.
+ {test,test_arity,{f,6},[{x,0},2]}.
+ {get_tuple_element,{x,0},0,{x,1}}.
+ {get_tuple_element,{x,0},1,{x,2}}.
+ {test,is_eq_exact,{f,6},[{x,1},{atom,reply}]}.
+ {test,is_eq_exact,{f,6},[{x,2},{y,1}]}.
+ remove_message.
+ {move,{atom,ok},{x,0}}.
+ {deallocate,2}.
+ return.
+ {label,6}.
+ {loop_rec_end,{f,5}}.
+ {label,7}.
+ {wait,{f,5}}.
+
+
+{function, module_info, 0, 9}.
+ {label,8}.
+ {func_info,{atom,yes_14},{atom,module_info},0}.
+ {label,9}.
+ {move,{atom,yes_14},{x,0}}.
+ {call_ext_only,1,{extfunc,erlang,get_module_info,1}}.
+
+
+{function, module_info, 1, 11}.
+ {label,10}.
+ {func_info,{atom,yes_14},{atom,module_info},1}.
+ {label,11}.
+ {move,{x,0},{x,1}}.
+ {move,{atom,yes_14},{x,0}}.
+ {call_ext_only,2,{extfunc,erlang,get_module_info,2}}.
diff --git a/lib/crypto/c_src/crypto.c b/lib/crypto/c_src/crypto.c
index fac77308f6..9d43a1d907 100644
--- a/lib/crypto/c_src/crypto.c
+++ b/lib/crypto/c_src/crypto.c
@@ -74,6 +74,19 @@
# define HAVE_DES_ede3_cfb_encrypt
#endif
+#if OPENSSL_VERSION_NUMBER >= 0x009080ffL \
+ && !defined(OPENSSL_NO_EC) \
+ && !defined(OPENSSL_NO_ECDH) \
+ && !defined(OPENSSL_NO_ECDSA)
+# define HAVE_EC
+#endif
+
+#if defined(HAVE_EC)
+#include <openssl/ec.h>
+#include <openssl/ecdh.h>
+#include <openssl/ecdsa.h>
+#endif
+
#ifdef VALGRIND
# include <valgrind/memcheck.h>
@@ -192,7 +205,7 @@ static ERL_NIF_TERM rand_bytes_3(ErlNifEnv* env, int argc, const ERL_NIF_TERM ar
static ERL_NIF_TERM strong_rand_mpint_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
static ERL_NIF_TERM rand_uniform_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
static ERL_NIF_TERM mod_exp_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
-static ERL_NIF_TERM dss_verify(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
+static ERL_NIF_TERM dss_verify_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
static ERL_NIF_TERM rsa_verify_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
static ERL_NIF_TERM aes_cbc_crypt(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
static ERL_NIF_TERM exor(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
@@ -209,13 +222,19 @@ static ERL_NIF_TERM dh_check(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]
static ERL_NIF_TERM dh_generate_key_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
static ERL_NIF_TERM dh_compute_key_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
static ERL_NIF_TERM srp_value_B_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
-static ERL_NIF_TERM srp_client_secret_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
-static ERL_NIF_TERM srp_server_secret_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
+static ERL_NIF_TERM srp_user_secret_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
+static ERL_NIF_TERM srp_host_secret_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
static ERL_NIF_TERM bf_cfb64_crypt(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
static ERL_NIF_TERM bf_cbc_crypt(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
static ERL_NIF_TERM bf_ecb_crypt(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
static ERL_NIF_TERM blowfish_ofb64_encrypt(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
+static ERL_NIF_TERM ec_key_to_term_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
+static ERL_NIF_TERM term_to_ec_key_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
+static ERL_NIF_TERM ec_key_generate(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
+static ERL_NIF_TERM ecdsa_sign_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
+static ERL_NIF_TERM ecdsa_verify_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
+static ERL_NIF_TERM ecdh_compute_key_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
/* helpers */
@@ -247,6 +266,11 @@ static void hmac_sha512(unsigned char *key, int klen,
unsigned char *dbuf, int dlen,
unsigned char *hmacbuf);
#endif
+#ifdef HAVE_EC
+static EC_KEY* ec_key_new(ErlNifEnv* env, ERL_NIF_TERM curve_arg);
+static int term2point(ErlNifEnv* env, ERL_NIF_TERM term,
+ EC_GROUP *group, EC_POINT **pptr);
+#endif
static int library_refc = 0; /* number of users of this dynamic library */
@@ -311,7 +335,7 @@ static ErlNifFunc nif_funcs[] = {
{"strong_rand_mpint_nif", 3, strong_rand_mpint_nif},
{"rand_uniform_nif", 2, rand_uniform_nif},
{"mod_exp_nif", 4, mod_exp_nif},
- {"dss_verify", 4, dss_verify},
+ {"dss_verify_nif", 4, dss_verify_nif},
{"rsa_verify_nif", 4, rsa_verify_nif},
{"aes_cbc_crypt", 4, aes_cbc_crypt},
{"exor", 2, exor},
@@ -325,16 +349,120 @@ static ErlNifFunc nif_funcs[] = {
{"rsa_private_crypt", 4, rsa_private_crypt},
{"dh_generate_parameters_nif", 2, dh_generate_parameters_nif},
{"dh_check", 1, dh_check},
- {"dh_generate_key_nif", 2, dh_generate_key_nif},
+ {"dh_generate_key_nif", 3, dh_generate_key_nif},
{"dh_compute_key_nif", 3, dh_compute_key_nif},
{"srp_value_B_nif", 5, srp_value_B_nif},
- {"srp_client_secret_nif", 7, srp_client_secret_nif},
- {"srp_server_secret_nif", 5, srp_server_secret_nif},
+ {"srp_user_secret_nif", 7, srp_user_secret_nif},
+ {"srp_host_secret_nif", 5, srp_host_secret_nif},
{"bf_cfb64_crypt", 4, bf_cfb64_crypt},
{"bf_cbc_crypt", 4, bf_cbc_crypt},
{"bf_ecb_crypt", 3, bf_ecb_crypt},
- {"blowfish_ofb64_encrypt", 3, blowfish_ofb64_encrypt}
+ {"blowfish_ofb64_encrypt", 3, blowfish_ofb64_encrypt},
+
+ {"ec_key_to_term_nif", 1, ec_key_to_term_nif},
+ {"term_to_ec_key_nif", 3, term_to_ec_key_nif},
+ {"ec_key_generate", 1, ec_key_generate},
+ {"ecdsa_sign_nif", 3, ecdsa_sign_nif},
+ {"ecdsa_verify_nif", 4, ecdsa_verify_nif},
+ {"ecdh_compute_key_nif", 2, ecdh_compute_key_nif}
+};
+
+#if defined(HAVE_EC)
+struct nid_map {
+ char *name;
+ int nid;
+ ERL_NIF_TERM atom;
+};
+
+static struct nid_map ec_curves[] = {
+ /* prime field curves */
+ /* secg curves */
+ { "secp112r1", NID_secp112r1 },
+ { "secp112r2", NID_secp112r2 },
+ { "secp128r1", NID_secp128r1 },
+ { "secp128r2", NID_secp128r2 },
+ { "secp160k1", NID_secp160k1 },
+ { "secp160r1", NID_secp160r1 },
+ { "secp160r2", NID_secp160r2 },
+ /* SECG secp192r1 is the same as X9.62 prime192v1 */
+ { "secp192r1", NID_X9_62_prime192v1 },
+ { "secp192k1", NID_secp192k1 },
+ { "secp224k1", NID_secp224k1 },
+ { "secp224r1", NID_secp224r1 },
+ { "secp256k1", NID_secp256k1 },
+ /* SECG secp256r1 is the same as X9.62 prime256v1 */
+ { "secp256r1", NID_X9_62_prime256v1 },
+ { "secp384r1", NID_secp384r1 },
+ { "secp521r1", NID_secp521r1 },
+ /* X9.62 curves */
+ { "prime192v1", NID_X9_62_prime192v1 },
+ { "prime192v2", NID_X9_62_prime192v2 },
+ { "prime192v3", NID_X9_62_prime192v3 },
+ { "prime239v1", NID_X9_62_prime239v1 },
+ { "prime239v2", NID_X9_62_prime239v2 },
+ { "prime239v3", NID_X9_62_prime239v3 },
+ { "prime256v1", NID_X9_62_prime256v1 },
+ /* characteristic two field curves */
+ /* NIST/SECG curves */
+ { "sect113r1", NID_sect113r1 },
+ { "sect113r2", NID_sect113r2 },
+ { "sect131r1", NID_sect131r1 },
+ { "sect131r2", NID_sect131r2 },
+ { "sect163k1", NID_sect163k1 },
+ { "sect163r1", NID_sect163r1 },
+ { "sect163r2", NID_sect163r2 },
+ { "sect193r1", NID_sect193r1 },
+ { "sect193r2", NID_sect193r2 },
+ { "sect233k1", NID_sect233k1 },
+ { "sect233r1", NID_sect233r1 },
+ { "sect239k1", NID_sect239k1 },
+ { "sect283k1", NID_sect283k1 },
+ { "sect283r1", NID_sect283r1 },
+ { "sect409k1", NID_sect409k1 },
+ { "sect409r1", NID_sect409r1 },
+ { "sect571k1", NID_sect571k1 },
+ { "sect571r1", NID_sect571r1 },
+ /* X9.62 curves */
+ { "c2pnb163v1", NID_X9_62_c2pnb163v1 },
+ { "c2pnb163v2", NID_X9_62_c2pnb163v2 },
+ { "c2pnb163v3", NID_X9_62_c2pnb163v3 },
+ { "c2pnb176v1", NID_X9_62_c2pnb176v1 },
+ { "c2tnb191v1", NID_X9_62_c2tnb191v1 },
+ { "c2tnb191v2", NID_X9_62_c2tnb191v2 },
+ { "c2tnb191v3", NID_X9_62_c2tnb191v3 },
+ { "c2pnb208w1", NID_X9_62_c2pnb208w1 },
+ { "c2tnb239v1", NID_X9_62_c2tnb239v1 },
+ { "c2tnb239v2", NID_X9_62_c2tnb239v2 },
+ { "c2tnb239v3", NID_X9_62_c2tnb239v3 },
+ { "c2pnb272w1", NID_X9_62_c2pnb272w1 },
+ { "c2pnb304w1", NID_X9_62_c2pnb304w1 },
+ { "c2tnb359v1", NID_X9_62_c2tnb359v1 },
+ { "c2pnb368w1", NID_X9_62_c2pnb368w1 },
+ { "c2tnb431r1", NID_X9_62_c2tnb431r1 },
+ /* the WAP/WTLS curves
+ * [unlike SECG, spec has its own OIDs for curves from X9.62] */
+ { "wtls1", NID_wap_wsg_idm_ecid_wtls1 },
+ { "wtls3", NID_wap_wsg_idm_ecid_wtls3 },
+ { "wtls4", NID_wap_wsg_idm_ecid_wtls4 },
+ { "wtls5", NID_wap_wsg_idm_ecid_wtls5 },
+ { "wtls6", NID_wap_wsg_idm_ecid_wtls6 },
+ { "wtls7", NID_wap_wsg_idm_ecid_wtls7 },
+ { "wtls8", NID_wap_wsg_idm_ecid_wtls8 },
+ { "wtls9", NID_wap_wsg_idm_ecid_wtls9 },
+ { "wtls10", NID_wap_wsg_idm_ecid_wtls10 },
+ { "wtls11", NID_wap_wsg_idm_ecid_wtls11 },
+ { "wtls12", NID_wap_wsg_idm_ecid_wtls12 },
+ /* IPSec curves */
+ { "ipsec3", NID_ipsec3 },
+ { "ipsec4", NID_ipsec4 }
+};
+
+#define EC_CURVES_CNT (sizeof(ec_curves)/sizeof(struct nid_map))
+
+struct nif_ec_key {
+ EC_KEY *key;
};
+#endif
ERL_NIF_INIT(crypto,nif_funcs,load,NULL,upgrade,unload)
@@ -368,6 +496,7 @@ static ERL_NIF_TERM atom_sha256;
static ERL_NIF_TERM atom_sha384;
static ERL_NIF_TERM atom_sha512;
static ERL_NIF_TERM atom_md5;
+static ERL_NIF_TERM atom_md4;
static ERL_NIF_TERM atom_ripemd160;
static ERL_NIF_TERM atom_error;
static ERL_NIF_TERM atom_rsa_pkcs1_padding;
@@ -386,6 +515,19 @@ static ERL_NIF_TERM atom_none;
static ERL_NIF_TERM atom_notsup;
static ERL_NIF_TERM atom_digest;
+static ERL_NIF_TERM atom_ec;
+
+#if defined(HAVE_EC)
+static ERL_NIF_TERM atom_prime_field;
+static ERL_NIF_TERM atom_characteristic_two_field;
+static ERL_NIF_TERM atom_tpbasis;
+static ERL_NIF_TERM atom_ppbasis;
+static ERL_NIF_TERM atom_onbasis;
+
+static ErlNifResourceType* res_type_ec_key;
+static void ec_key_dtor(ErlNifEnv* env, void* obj);
+#endif
+
/*
#define PRINTF_ERR0(FMT) enif_fprintf(stderr, FMT "\n")
#define PRINTF_ERR1(FMT, A1) enif_fprintf(stderr, FMT "\n", A1)
@@ -415,6 +557,7 @@ static void error_handler(void* null, const char* errstr)
static int init(ErlNifEnv* env, ERL_NIF_TERM load_info)
{
+ int i;
ErlNifSysInfo sys_info;
get_crypto_callbacks_t* funcp;
struct crypto_callbacks* ccb;
@@ -448,6 +591,7 @@ static int init(ErlNifEnv* env, ERL_NIF_TERM load_info)
atom_sha256 = enif_make_atom(env,"sha256");
atom_sha384 = enif_make_atom(env,"sha384");
atom_sha512 = enif_make_atom(env,"sha512");
+ atom_md4 = enif_make_atom(env,"md4");
atom_md5 = enif_make_atom(env,"md5");
atom_ripemd160 = enif_make_atom(env,"ripemd160");
atom_error = enif_make_atom(env,"error");
@@ -466,6 +610,23 @@ static int init(ErlNifEnv* env, ERL_NIF_TERM load_info)
atom_notsup = enif_make_atom(env,"notsup");
atom_digest = enif_make_atom(env,"digest");
+#if defined(HAVE_EC)
+ atom_ec = enif_make_atom(env,"ec");
+ atom_prime_field = enif_make_atom(env,"prime_field");
+ atom_characteristic_two_field = enif_make_atom(env,"characteristic_two_field");
+ atom_tpbasis = enif_make_atom(env,"tpbasis");
+ atom_ppbasis = enif_make_atom(env,"ppbasis");
+ atom_onbasis = enif_make_atom(env,"onbasis");
+
+ for (i = 0; i < EC_CURVES_CNT; i++)
+ ec_curves[i].atom = enif_make_atom(env,ec_curves[i].name);
+
+ res_type_ec_key = enif_open_resource_type(env,NULL,"crypto.EC_KEY",
+ ec_key_dtor,
+ ERL_NIF_RT_CREATE|ERL_NIF_RT_TAKEOVER,
+ NULL);
+#endif
+
init_digest_types(env);
init_algorithms_types();
@@ -549,12 +710,12 @@ static void unload(ErlNifEnv* env, void* priv_data)
}
static int algos_cnt;
-static ERL_NIF_TERM algos[7]; /* increase when extending the list */
+static ERL_NIF_TERM algos[9]; /* increase when extending the list */
static void init_algorithms_types(void)
{
algos_cnt = 0;
-
+ algos[algos_cnt++] = atom_md4;
algos[algos_cnt++] = atom_md5;
algos[algos_cnt++] = atom_sha;
algos[algos_cnt++] = atom_ripemd160;
@@ -570,6 +731,9 @@ static void init_algorithms_types(void)
#ifdef HAVE_SHA512
algos[algos_cnt++] = atom_sha512;
#endif
+#if defined(HAVE_EC)
+ algos[algos_cnt++] = atom_ec;
+#endif
}
static ERL_NIF_TERM algorithms(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
@@ -1631,13 +1795,7 @@ static ERL_NIF_TERM mod_exp_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM arg
return ret;
}
-static int inspect_mpint(ErlNifEnv* env, ERL_NIF_TERM term, ErlNifBinary* bin)
-{
- return enif_inspect_binary(env, term, bin) &&
- bin->size >= 4 && get_int32(bin->data) == bin->size-4;
-}
-
-static ERL_NIF_TERM dss_verify(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
+static ERL_NIF_TERM dss_verify_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
{/* (DigestType|none, Data|{digest,Digest}, Signature,Key=[P, Q, G, Y]) */
ErlNifBinary data_bin, sign_bin;
BIGNUM *dsa_p = NULL, *dsa_q = NULL, *dsa_g = NULL, *dsa_y = NULL;
@@ -1660,10 +1818,10 @@ static ERL_NIF_TERM dss_verify(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv
digest = data_bin.data;
}
else {
- if (!inspect_mpint(env, argv[1], &data_bin)) {
+ if (!enif_inspect_binary(env, argv[1], &data_bin)) {
return enif_make_badarg(env);
}
- SHA1(data_bin.data+4, data_bin.size-4, hmacbuf);
+ SHA1(data_bin.data, data_bin.size, hmacbuf);
digest = hmacbuf;
}
}
@@ -1675,15 +1833,15 @@ static ERL_NIF_TERM dss_verify(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv
return enif_make_badarg(env);
}
- if (!inspect_mpint(env, argv[2], &sign_bin)
+ if (!enif_inspect_binary(env, argv[2], &sign_bin)
|| !enif_get_list_cell(env, argv[3], &head, &tail)
- || !get_bn_from_mpint(env, head, &dsa_p)
+ || !get_bn_from_bin(env, head, &dsa_p)
|| !enif_get_list_cell(env, tail, &head, &tail)
- || !get_bn_from_mpint(env, head, &dsa_q)
+ || !get_bn_from_bin(env, head, &dsa_q)
|| !enif_get_list_cell(env, tail, &head, &tail)
- || !get_bn_from_mpint(env, head, &dsa_g)
+ || !get_bn_from_bin(env, head, &dsa_g)
|| !enif_get_list_cell(env, tail, &head, &tail)
- || !get_bn_from_mpint(env, head, &dsa_y)
+ || !get_bn_from_bin(env, head, &dsa_y)
|| !enif_is_empty_list(env,tail)) {
if (dsa_p) BN_free(dsa_p);
@@ -1700,7 +1858,7 @@ static ERL_NIF_TERM dss_verify(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv
dsa->priv_key = NULL;
dsa->pub_key = dsa_y;
i = DSA_verify(0, digest, SHA_DIGEST_LENGTH,
- sign_bin.data+4, sign_bin.size-4, dsa);
+ sign_bin.data, sign_bin.size, dsa);
DSA_free(dsa);
return(i > 0) ? atom_true : atom_false;
}
@@ -1826,11 +1984,11 @@ static ERL_NIF_TERM rsa_verify_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM
rsa = RSA_new();
- if (!inspect_mpint(env, argv[2], &sign_bin)
+ if (!enif_inspect_binary(env, argv[2], &sign_bin)
|| !enif_get_list_cell(env, argv[3], &head, &tail)
- || !get_bn_from_mpint(env, head, &rsa->e)
+ || !get_bn_from_bin(env, head, &rsa->e)
|| !enif_get_list_cell(env, tail, &head, &tail)
- || !get_bn_from_mpint(env, head, &rsa->n)
+ || !get_bn_from_bin(env, head, &rsa->n)
|| !enif_is_empty_list(env, tail)) {
ret = enif_make_badarg(env);
@@ -1846,9 +2004,9 @@ static ERL_NIF_TERM rsa_verify_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM
}
digest = data_bin.data;
}
- else if (inspect_mpint(env, argv[1], &data_bin)) {
+ else if (enif_inspect_binary(env, argv[1], &data_bin)) {
digest = hmacbuf;
- digp->funcp(data_bin.data+4, data_bin.size-4, digest);
+ digp->funcp(data_bin.data, data_bin.size, digest);
}
else {
ret = enif_make_badarg(env);
@@ -1856,7 +2014,7 @@ static ERL_NIF_TERM rsa_verify_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM
}
i = RSA_verify(digp->NID_type, digest, digp->len,
- sign_bin.data+4, sign_bin.size-4, rsa);
+ sign_bin.data, sign_bin.size, rsa);
ret = (i==1 ? atom_true : atom_false);
@@ -2001,22 +2159,22 @@ static int get_rsa_private_key(ErlNifEnv* env, ERL_NIF_TERM key, RSA *rsa)
ERL_NIF_TERM head, tail;
if (!enif_get_list_cell(env, key, &head, &tail)
- || !get_bn_from_mpint(env, head, &rsa->e)
+ || !get_bn_from_bin(env, head, &rsa->e)
|| !enif_get_list_cell(env, tail, &head, &tail)
- || !get_bn_from_mpint(env, head, &rsa->n)
+ || !get_bn_from_bin(env, head, &rsa->n)
|| !enif_get_list_cell(env, tail, &head, &tail)
- || !get_bn_from_mpint(env, head, &rsa->d)
+ || !get_bn_from_bin(env, head, &rsa->d)
|| (!enif_is_empty_list(env, tail) &&
(!enif_get_list_cell(env, tail, &head, &tail)
- || !get_bn_from_mpint(env, head, &rsa->p)
+ || !get_bn_from_bin(env, head, &rsa->p)
|| !enif_get_list_cell(env, tail, &head, &tail)
- || !get_bn_from_mpint(env, head, &rsa->q)
+ || !get_bn_from_bin(env, head, &rsa->q)
|| !enif_get_list_cell(env, tail, &head, &tail)
- || !get_bn_from_mpint(env, head, &rsa->dmp1)
+ || !get_bn_from_bin(env, head, &rsa->dmp1)
|| !enif_get_list_cell(env, tail, &head, &tail)
- || !get_bn_from_mpint(env, head, &rsa->dmq1)
+ || !get_bn_from_bin(env, head, &rsa->dmq1)
|| !enif_get_list_cell(env, tail, &head, &tail)
- || !get_bn_from_mpint(env, head, &rsa->iqmp)
+ || !get_bn_from_bin(env, head, &rsa->iqmp)
|| !enif_is_empty_list(env, tail)))) {
return 0;
}
@@ -2053,11 +2211,11 @@ static ERL_NIF_TERM rsa_sign_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM ar
digest = data_bin.data;
}
else {
- if (!inspect_mpint(env,argv[1],&data_bin)) {
+ if (!enif_inspect_binary(env,argv[1],&data_bin)) {
return enif_make_badarg(env);
}
digest = hmacbuf;
- digp->funcp(data_bin.data+4, data_bin.size-4, digest);
+ digp->funcp(data_bin.data, data_bin.size, digest);
}
rsa = RSA_new();
@@ -2112,10 +2270,10 @@ static ERL_NIF_TERM dss_sign_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM ar
digest = data_bin.data;
}
else {
- if (!inspect_mpint(env,argv[1],&data_bin)) {
+ if (!enif_inspect_binary(env,argv[1],&data_bin)) {
return enif_make_badarg(env);
}
- SHA1(data_bin.data+4, data_bin.size-4, hmacbuf);
+ SHA1(data_bin.data, data_bin.size, hmacbuf);
digest = hmacbuf;
}
}
@@ -2133,13 +2291,13 @@ static ERL_NIF_TERM dss_sign_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM ar
dsa->pub_key = NULL;
if (!enif_get_list_cell(env, argv[2], &head, &tail)
- || !get_bn_from_mpint(env, head, &dsa->p)
+ || !get_bn_from_bin(env, head, &dsa->p)
|| !enif_get_list_cell(env, tail, &head, &tail)
- || !get_bn_from_mpint(env, head, &dsa->q)
+ || !get_bn_from_bin(env, head, &dsa->q)
|| !enif_get_list_cell(env, tail, &head, &tail)
- || !get_bn_from_mpint(env, head, &dsa->g)
+ || !get_bn_from_bin(env, head, &dsa->g)
|| !enif_get_list_cell(env, tail, &head, &tail)
- || !get_bn_from_mpint(env, head, &dsa->priv_key)
+ || !get_bn_from_bin(env, head, &dsa->priv_key)
|| !enif_is_empty_list(env,tail)) {
DSA_free(dsa);
return enif_make_badarg(env);
@@ -2187,9 +2345,9 @@ static ERL_NIF_TERM rsa_public_crypt(ErlNifEnv* env, int argc, const ERL_NIF_TER
if (!enif_inspect_binary(env, argv[0], &data_bin)
|| !enif_get_list_cell(env, argv[1], &head, &tail)
- || !get_bn_from_mpint(env, head, &rsa->e)
+ || !get_bn_from_bin(env, head, &rsa->e)
|| !enif_get_list_cell(env, tail, &head, &tail)
- || !get_bn_from_mpint(env, head, &rsa->n)
+ || !get_bn_from_bin(env, head, &rsa->n)
|| !enif_is_empty_list(env,tail)
|| !rsa_pad(argv[2], &padding)) {
@@ -2286,14 +2444,12 @@ static ERL_NIF_TERM dh_generate_parameters_nif(ErlNifEnv* env, int argc, const E
}
p_len = BN_num_bytes(dh_params->p);
g_len = BN_num_bytes(dh_params->g);
- p_ptr = enif_make_new_binary(env, p_len+4, &ret_p);
- g_ptr = enif_make_new_binary(env, g_len+4, &ret_g);
- put_int32(p_ptr, p_len);
- put_int32(g_ptr, g_len);
- BN_bn2bin(dh_params->p, p_ptr+4);
- BN_bn2bin(dh_params->g, g_ptr+4);
- ERL_VALGRIND_MAKE_MEM_DEFINED(p_ptr+4, p_len);
- ERL_VALGRIND_MAKE_MEM_DEFINED(g_ptr+4, g_len);
+ p_ptr = enif_make_new_binary(env, p_len, &ret_p);
+ g_ptr = enif_make_new_binary(env, g_len, &ret_g);
+ BN_bn2bin(dh_params->p, p_ptr);
+ BN_bn2bin(dh_params->g, g_ptr);
+ ERL_VALGRIND_MAKE_MEM_DEFINED(p_ptr, p_len);
+ ERL_VALGRIND_MAKE_MEM_DEFINED(g_ptr, g_len);
DH_free(dh_params);
return enif_make_list2(env, ret_p, ret_g);
}
@@ -2305,9 +2461,9 @@ static ERL_NIF_TERM dh_check(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]
ERL_NIF_TERM ret, head, tail;
if (!enif_get_list_cell(env, argv[0], &head, &tail)
- || !get_bn_from_mpint(env, head, &dh_params->p)
+ || !get_bn_from_bin(env, head, &dh_params->p)
|| !enif_get_list_cell(env, tail, &head, &tail)
- || !get_bn_from_mpint(env, head, &dh_params->g)
+ || !get_bn_from_bin(env, head, &dh_params->g)
|| !enif_is_empty_list(env,tail)) {
DH_free(dh_params);
@@ -2329,19 +2485,21 @@ static ERL_NIF_TERM dh_check(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]
}
static ERL_NIF_TERM dh_generate_key_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
-{/* (PrivKey, DHParams=[P,G]) */
+{/* (PrivKey, DHParams=[P,G], Mpint) */
DH* dh_params = DH_new();
int pub_len, prv_len;
unsigned char *pub_ptr, *prv_ptr;
ERL_NIF_TERM ret, ret_pub, ret_prv, head, tail;
+ int mpint; /* 0 or 4 */
- if (!(get_bn_from_mpint(env, argv[0], &dh_params->priv_key)
+ if (!(get_bn_from_bin(env, argv[0], &dh_params->priv_key)
|| argv[0] == atom_undefined)
|| !enif_get_list_cell(env, argv[1], &head, &tail)
- || !get_bn_from_mpint(env, head, &dh_params->p)
+ || !get_bn_from_bin(env, head, &dh_params->p)
|| !enif_get_list_cell(env, tail, &head, &tail)
- || !get_bn_from_mpint(env, head, &dh_params->g)
- || !enif_is_empty_list(env, tail)) {
+ || !get_bn_from_bin(env, head, &dh_params->g)
+ || !enif_is_empty_list(env, tail)
+ || !enif_get_int(env, argv[2], &mpint) || (mpint & ~4)) {
DH_free(dh_params);
return enif_make_badarg(env);
}
@@ -2349,14 +2507,16 @@ static ERL_NIF_TERM dh_generate_key_nif(ErlNifEnv* env, int argc, const ERL_NIF_
if (DH_generate_key(dh_params)) {
pub_len = BN_num_bytes(dh_params->pub_key);
prv_len = BN_num_bytes(dh_params->priv_key);
- pub_ptr = enif_make_new_binary(env, pub_len+4, &ret_pub);
- prv_ptr = enif_make_new_binary(env, prv_len+4, &ret_prv);
- put_int32(pub_ptr, pub_len);
- put_int32(prv_ptr, prv_len);
- BN_bn2bin(dh_params->pub_key, pub_ptr+4);
- BN_bn2bin(dh_params->priv_key, prv_ptr+4);
- ERL_VALGRIND_MAKE_MEM_DEFINED(pub_ptr+4, pub_len);
- ERL_VALGRIND_MAKE_MEM_DEFINED(prv_ptr+4, prv_len);
+ pub_ptr = enif_make_new_binary(env, pub_len+mpint, &ret_pub);
+ prv_ptr = enif_make_new_binary(env, prv_len+mpint, &ret_prv);
+ if (mpint) {
+ put_int32(pub_ptr, pub_len); pub_ptr += 4;
+ put_int32(prv_ptr, prv_len); prv_ptr += 4;
+ }
+ BN_bn2bin(dh_params->pub_key, pub_ptr);
+ BN_bn2bin(dh_params->priv_key, prv_ptr);
+ ERL_VALGRIND_MAKE_MEM_DEFINED(pub_ptr, pub_len);
+ ERL_VALGRIND_MAKE_MEM_DEFINED(prv_ptr, prv_len);
ret = enif_make_tuple2(env, ret_pub, ret_prv);
}
else {
@@ -2374,12 +2534,12 @@ static ERL_NIF_TERM dh_compute_key_nif(ErlNifEnv* env, int argc, const ERL_NIF_T
ErlNifBinary ret_bin;
ERL_NIF_TERM ret, head, tail;
- if (!get_bn_from_mpint(env, argv[0], &pubkey)
- || !get_bn_from_mpint(env, argv[1], &dh_params->priv_key)
+ if (!get_bn_from_bin(env, argv[0], &pubkey)
+ || !get_bn_from_bin(env, argv[1], &dh_params->priv_key)
|| !enif_get_list_cell(env, argv[2], &head, &tail)
- || !get_bn_from_mpint(env, head, &dh_params->p)
+ || !get_bn_from_bin(env, head, &dh_params->p)
|| !enif_get_list_cell(env, tail, &head, &tail)
- || !get_bn_from_mpint(env, head, &dh_params->g)
+ || !get_bn_from_bin(env, head, &dh_params->g)
|| !enif_is_empty_list(env, tail)) {
ret = enif_make_badarg(env);
@@ -2457,7 +2617,7 @@ static ERL_NIF_TERM srp_value_B_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM
return ret;
}
-static ERL_NIF_TERM srp_client_secret_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
+static ERL_NIF_TERM srp_user_secret_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
{/* (a, u, B, Multiplier, Prime, Exponent, Generator) */
/*
<premaster secret> = (B - (k * g^x)) ^ (a + (u * x)) % N
@@ -2537,7 +2697,7 @@ static ERL_NIF_TERM srp_client_secret_nif(ErlNifEnv* env, int argc, const ERL_NI
return ret;
}
-static ERL_NIF_TERM srp_server_secret_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
+static ERL_NIF_TERM srp_host_secret_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
{/* (Verifier, b, u, A, Prime) */
/*
<premaster secret> = (A * v^u) ^ b % N
@@ -2686,7 +2846,554 @@ static ERL_NIF_TERM blowfish_ofb64_encrypt(ErlNifEnv* env, int argc, const ERL_N
return ret;
}
+#if defined(HAVE_EC)
+static int term2curve_id(ERL_NIF_TERM nid)
+{
+ int i;
+
+ for (i = 0; i < EC_CURVES_CNT; i++)
+ if (ec_curves[i].atom == nid)
+ return ec_curves[i].nid;
+
+ return 0;
+}
+static EC_KEY* ec_key_new(ErlNifEnv* env, ERL_NIF_TERM curve_arg)
+{
+ EC_KEY *key = NULL;
+ int nid = 0;
+ int c_arity = -1;
+ const ERL_NIF_TERM* curve;
+ ErlNifBinary seed;
+ BIGNUM *p = NULL;
+ BIGNUM *a = NULL;
+ BIGNUM *b = NULL;
+ BIGNUM *bn_order = NULL;
+ BIGNUM *cofactor = NULL;
+ EC_GROUP *group = NULL;
+ EC_POINT *point = NULL;
+
+ if (enif_is_atom(env, curve_arg)) {
+ nid = term2curve_id(curve_arg);
+ if (nid == 0)
+ return NULL;
+ key = EC_KEY_new_by_curve_name(nid);
+ }
+ else if (enif_is_tuple(env, curve_arg)
+ && enif_get_tuple(env,curve_arg,&c_arity,&curve)
+ && c_arity == 5
+ && get_bn_from_bin(env, curve[3], &bn_order)
+ && (curve[4] != atom_none && get_bn_from_bin(env, curve[4], &cofactor))) {
+ //* {Field, Prime, Point, Order, CoFactor} = Curve */
+
+ int f_arity = -1;
+ const ERL_NIF_TERM* field;
+ int p_arity = -1;
+ const ERL_NIF_TERM* prime;
+
+ long field_bits;
+
+ /* {A, B, Seed} = Prime */
+ if (!enif_get_tuple(env,curve[1],&p_arity,&prime)
+ || !get_bn_from_bin(env, prime[0], &a)
+ || !get_bn_from_bin(env, prime[1], &b))
+ goto out_err;
+
+ if (!enif_get_tuple(env,curve[0],&f_arity,&field))
+ goto out_err;
+
+ if (f_arity == 2 && field[0] == atom_prime_field) {
+ /* {prime_field, Prime} */
+
+ if (!get_bn_from_bin(env, field[1], &p))
+ goto out_err;
+
+ if (BN_is_negative(p) || BN_is_zero(p))
+ goto out_err;
+
+ field_bits = BN_num_bits(p);
+ if (field_bits > OPENSSL_ECC_MAX_FIELD_BITS)
+ goto out_err;
+
+ /* create the EC_GROUP structure */
+ group = EC_GROUP_new_curve_GFp(p, a, b, NULL);
+
+ } else if (f_arity == 3 && field[0] == atom_characteristic_two_field) {
+ /* {characteristic_two_field, M, Basis} */
+
+ int b_arity = -1;
+ const ERL_NIF_TERM* basis;
+ unsigned int k1, k2, k3;
+
+ if ((p = BN_new()) == NULL)
+ goto out_err;
+
+ if (!enif_get_long(env, field[1], &field_bits)
+ || field_bits > OPENSSL_ECC_MAX_FIELD_BITS)
+ goto out_err;
+
+ if (enif_get_tuple(env,field[2],&b_arity,&basis)) {
+ if (b_arity == 2
+ && basis[0] == atom_tpbasis
+ && enif_get_uint(env, basis[1], &k1)) {
+ /* {tpbasis, k} = Basis */
+
+ if (!(field_bits > k1 && k1 > 0))
+ goto out_err;
+
+ /* create the polynomial */
+ if (!BN_set_bit(p, (int)field_bits)
+ || !BN_set_bit(p, (int)k1)
+ || !BN_set_bit(p, 0))
+ goto out_err;
+
+ } else if (b_arity == 4
+ && basis[0] == atom_ppbasis
+ && enif_get_uint(env, basis[1], &k1)
+ && enif_get_uint(env, basis[2], &k2)
+ && enif_get_uint(env, basis[3], &k3)) {
+ /* {ppbasis, k1, k2, k3} = Basis */
+
+ if (!(field_bits > k3 && k3 > k2 && k2 > k1 && k1 > 0))
+ goto out_err;
+
+ /* create the polynomial */
+ if (!BN_set_bit(p, (int)field_bits)
+ || !BN_set_bit(p, (int)k1)
+ || !BN_set_bit(p, (int)k2)
+ || !BN_set_bit(p, (int)k3)
+ || !BN_set_bit(p, 0))
+ goto out_err;
+
+ } else
+ goto out_err;
+ } else if (field[2] == atom_onbasis) {
+ /* onbasis = Basis */
+ /* no parameters */
+ goto out_err;
+
+ } else
+ goto out_err;
+
+ group = EC_GROUP_new_curve_GF2m(p, a, b, NULL);
+ } else
+ goto out_err;
+
+ if (enif_inspect_binary(env, prime[2], &seed)) {
+ EC_GROUP_set_seed(group, seed.data, seed.size);
+ }
+
+ if (!term2point(env, curve[2], group, &point))
+ goto out_err;
+
+ if (BN_is_negative(bn_order)
+ || BN_is_zero(bn_order)
+ || BN_num_bits(bn_order) > (int)field_bits + 1)
+ goto out_err;
+
+ if (!EC_GROUP_set_generator(group, point, bn_order, cofactor))
+ goto out_err;
+
+ EC_GROUP_set_asn1_flag(group, 0x0);
+
+ key = EC_KEY_new();
+ if (!key)
+ goto out_err;
+ EC_KEY_set_group(key, group);
+ }
+ else {
+ goto out_err;
+ }
+
+
+ goto out;
+
+out_err:
+ if (key) EC_KEY_free(key);
+ key = NULL;
+
+out:
+ /* some OpenSSL structures are mem-dup'ed into the key,
+ so we have to free our copies here */
+ if (p) BN_free(p);
+ if (a) BN_free(a);
+ if (b) BN_free(b);
+ if (bn_order) BN_free(bn_order);
+ if (cofactor) BN_free(cofactor);
+ if (group) EC_GROUP_free(group);
+
+ return key;
+}
+
+
+static ERL_NIF_TERM bn2term(ErlNifEnv* env, const BIGNUM *bn)
+{
+ unsigned dlen;
+ unsigned char* ptr;
+ ERL_NIF_TERM ret;
+
+ if (!bn)
+ return atom_undefined;
+
+ dlen = BN_num_bytes(bn);
+ ptr = enif_make_new_binary(env, dlen, &ret);
+ BN_bn2bin(bn, ptr);
+
+ return ret;
+}
+
+static ERL_NIF_TERM point2term(ErlNifEnv* env,
+ const EC_GROUP *group,
+ const EC_POINT *point,
+ point_conversion_form_t form)
+{
+ unsigned dlen;
+ ErlNifBinary bin;
+
+ dlen = EC_POINT_point2oct(group, point, form, NULL, 0, NULL);
+ if (dlen == 0)
+ return atom_undefined;
+
+ if (!enif_alloc_binary(dlen, &bin))
+ return enif_make_badarg(env);
+
+ if (!EC_POINT_point2oct(group, point, form, bin.data, bin.size, NULL)) {
+ enif_release_binary(&bin);
+ return enif_make_badarg(env);
+ }
+
+ return enif_make_binary(env, &bin);
+}
+#endif
+
+static ERL_NIF_TERM ec_key_to_term_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
+{
+#if defined(HAVE_EC)
+ struct nif_ec_key *obj;
+ const EC_GROUP *group;
+ const EC_POINT *public_key;
+ const BIGNUM *priv_key = NULL;
+ ERL_NIF_TERM pub_key = atom_undefined;
+
+ if (!enif_get_resource(env, argv[0], res_type_ec_key, (void **)&obj))
+ return enif_make_badarg(env);
+
+ group = EC_KEY_get0_group(obj->key);
+ public_key = EC_KEY_get0_public_key(obj->key);
+ priv_key = EC_KEY_get0_private_key(obj->key);
+
+ if (group) {
+ if (public_key)
+ pub_key = point2term(env, group, public_key, EC_KEY_get_conv_form(obj->key));
+ }
+
+ return enif_make_tuple2(env, bn2term(env, priv_key), pub_key);
+#else
+ return atom_notsup;
+#endif
+}
+
+#if defined(HAVE_EC)
+static int term2point(ErlNifEnv* env, ERL_NIF_TERM term,
+ EC_GROUP *group, EC_POINT **pptr)
+{
+ int ret = 0;
+ ErlNifBinary bin;
+ EC_POINT *point;
+
+ if (!enif_inspect_binary(env,term,&bin)) {
+ return 0;
+ }
+
+ if ((*pptr = point = EC_POINT_new(group)) == NULL) {
+ return 0;
+ }
+
+ /* set the point conversion form */
+ EC_GROUP_set_point_conversion_form(group, (point_conversion_form_t)(bin.data[0] & ~0x01));
+
+ /* extract the ec point */
+ if (!EC_POINT_oct2point(group, point, bin.data, bin.size, NULL)) {
+ EC_POINT_free(point);
+ *pptr = NULL;
+ } else
+ ret = 1;
+
+ return ret;
+}
+#endif
+
+static ERL_NIF_TERM term_to_ec_key_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
+{
+#if defined(HAVE_EC)
+ ERL_NIF_TERM ret;
+ EC_KEY *key = NULL;
+ BIGNUM *priv_key = NULL;
+ EC_POINT *pub_key = NULL;
+ struct nif_ec_key *obj;
+ EC_GROUP *group = NULL;
+
+ if (!(argv[1] == atom_undefined || get_bn_from_bin(env, argv[1], &priv_key))
+ || !(argv[2] == atom_undefined || enif_is_binary(env, argv[2]))) {
+ goto out_err;
+ }
+
+ key = ec_key_new(env, argv[0]);
+
+ if (!key) {
+ goto out_err;
+ }
+
+ if (!group)
+ group = EC_GROUP_dup(EC_KEY_get0_group(key));
+
+ if (term2point(env, argv[2], group, &pub_key)) {
+ if (!EC_KEY_set_public_key(key, pub_key)) {
+ goto out_err;
+ }
+ }
+ if (argv[1] != atom_undefined
+ && !BN_is_zero(priv_key)) {
+ if (!EC_KEY_set_private_key(key, priv_key))
+ goto out_err;
+
+ /* calculate public key (if necessary) */
+ if (EC_KEY_get0_public_key(key) == NULL)
+ {
+ /* the public key was not included in the SEC1 private
+ * key => calculate the public key */
+ pub_key = EC_POINT_new(group);
+ if (pub_key == NULL
+ || !EC_POINT_copy(pub_key, EC_GROUP_get0_generator(group))
+ || !EC_POINT_mul(group, pub_key, priv_key, NULL, NULL, NULL)
+ || !EC_KEY_set_public_key(key, pub_key))
+ goto out_err;
+ }
+ }
+
+ obj = enif_alloc_resource(res_type_ec_key, sizeof(struct nif_ec_key));
+ if (!obj)
+ goto out_err;
+
+ obj->key = key;
+ ret = enif_make_resource(env, obj);
+ enif_release_resource(obj);
+
+ goto out;
+
+out_err:
+ if (key) EC_KEY_free(key);
+ ret = enif_make_badarg(env);
+
+out:
+ /* some OpenSSL structures are mem-dup'ed into the key,
+ so we have to free our copies here */
+ if (priv_key) BN_clear_free(priv_key);
+ if (pub_key) EC_POINT_free(pub_key);
+ if (group) EC_GROUP_free(group);
+ return ret;
+#else
+ return atom_notsup;
+#endif
+}
+
+static ERL_NIF_TERM ec_key_generate(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
+{
+#if defined(HAVE_EC)
+ EC_KEY *key = ec_key_new(env, argv[0]);
+
+ if (key && EC_KEY_generate_key(key)) {
+ ERL_NIF_TERM term;
+ struct nif_ec_key *obj = enif_alloc_resource(res_type_ec_key, sizeof(struct nif_ec_key));
+ if (!obj)
+ return atom_error;
+ obj->key = key;
+ term = enif_make_resource(env, obj);
+ enif_release_resource(obj);
+ return term;
+ }
+ else
+ return enif_make_badarg(env);
+#else
+ return atom_notsup;
+#endif
+}
+
+#if defined(HAVE_EC)
+static void ec_key_dtor(ErlNifEnv* env, void* obj)
+{
+ struct nif_ec_key *key = (struct nif_ec_key*) obj;
+ EC_KEY_free(key->key);
+}
+#endif
+
+static ERL_NIF_TERM ecdsa_sign_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
+{/* (Type, Data|{digest,Digest}, Key) */
+#if defined(HAVE_EC)
+ ErlNifBinary data_bin, ret_bin;
+ unsigned char hmacbuf[SHA_DIGEST_LENGTH];
+ unsigned int dsa_s_len;
+ struct nif_ec_key *obj;
+ int i;
+ const ERL_NIF_TERM* tpl_terms;
+ int tpl_arity;
+ struct digest_type_t *digp;
+ unsigned char* digest;
+
+ digp = get_digest_type(argv[0]);
+ if (!digp) {
+ return enif_make_badarg(env);
+ }
+ if (!digp->len) {
+ return atom_notsup;
+ }
+
+ if (!enif_get_resource(env, argv[2], res_type_ec_key, (void **)&obj))
+ return enif_make_badarg(env);
+
+ if (enif_get_tuple(env, argv[1], &tpl_arity, &tpl_terms)) {
+ if (tpl_arity != 2 || tpl_terms[0] != atom_digest
+ || !enif_inspect_binary(env, tpl_terms[1], &data_bin)
+ || data_bin.size != digp->len) {
+
+ return enif_make_badarg(env);
+ }
+ digest = data_bin.data;
+ }
+ else {
+ if (!enif_inspect_binary(env,argv[1],&data_bin)) {
+ return enif_make_badarg(env);
+ }
+ digest = hmacbuf;
+ digp->funcp(data_bin.data, data_bin.size, digest);
+ }
+
+ enif_alloc_binary(ECDSA_size(obj->key), &ret_bin);
+
+ i = ECDSA_sign(digp->NID_type, digest, digp->len,
+ ret_bin.data, &dsa_s_len, obj->key);
+ if (i) {
+ if (dsa_s_len != ret_bin.size) {
+ enif_realloc_binary(&ret_bin, dsa_s_len);
+ }
+ return enif_make_binary(env, &ret_bin);
+ }
+ else {
+ enif_release_binary(&ret_bin);
+ return atom_error;
+ }
+#else
+ return atom_notsup;
+#endif
+}
+
+static ERL_NIF_TERM ecdsa_verify_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
+{/* (Type, Data|{digest,Digest}, Signature, Key) */
+#if defined(HAVE_EC)
+ ErlNifBinary data_bin, sign_bin;
+ unsigned char hmacbuf[SHA512_LEN];
+ int i;
+ struct nif_ec_key *obj;
+ const ERL_NIF_TERM type = argv[0];
+ const ERL_NIF_TERM* tpl_terms;
+ int tpl_arity;
+ struct digest_type_t* digp = NULL;
+ unsigned char* digest = NULL;
+
+ digp = get_digest_type(type);
+ if (!digp) {
+ return enif_make_badarg(env);
+ }
+ if (!digp->len) {
+ return atom_notsup;
+ }
+
+ if (!enif_inspect_binary(env, argv[2], &sign_bin)
+ || !enif_get_resource(env, argv[3], res_type_ec_key, (void **)&obj))
+ return enif_make_badarg(env);
+
+ if (enif_get_tuple(env, argv[1], &tpl_arity, &tpl_terms)) {
+ if (tpl_arity != 2 || tpl_terms[0] != atom_digest
+ || !enif_inspect_binary(env, tpl_terms[1], &data_bin)
+ || data_bin.size != digp->len) {
+
+ return enif_make_badarg(env);
+ }
+ digest = data_bin.data;
+ }
+ else if (enif_inspect_binary(env, argv[1], &data_bin)) {
+ digest = hmacbuf;
+ digp->funcp(data_bin.data, data_bin.size, digest);
+ }
+ else {
+ return enif_make_badarg(env);
+ }
+
+ i = ECDSA_verify(digp->NID_type, digest, digp->len,
+ sign_bin.data, sign_bin.size, obj->key);
+
+ return (i==1 ? atom_true : atom_false);
+#else
+ return atom_notsup;
+#endif
+}
+
+/*
+ (_OthersPublicKey, _MyPrivateKey)
+ (_OthersPublicKey, _MyEC_Point)
+*/
+static ERL_NIF_TERM ecdh_compute_key_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
+{
+#if defined(HAVE_EC)
+ ERL_NIF_TERM ret;
+ unsigned char *p;
+ struct nif_ec_key *other_key;
+ int field_size = 0;
+ int i;
+
+ EC_GROUP *group;
+ const BIGNUM *priv_key;
+ EC_POINT *my_ecpoint;
+ EC_KEY *other_ecdh = NULL;
+
+ if (!enif_get_resource(env, argv[1], res_type_ec_key, (void **)&other_key))
+ return enif_make_badarg(env);
+
+ group = EC_GROUP_dup(EC_KEY_get0_group(other_key->key));
+ priv_key = EC_KEY_get0_private_key(other_key->key);
+
+ if (!term2point(env, argv[0], group, &my_ecpoint)) {
+ goto out_err;
+ }
+
+ if ((other_ecdh = EC_KEY_new()) == NULL
+ || !EC_KEY_set_group(other_ecdh, group)
+ || !EC_KEY_set_private_key(other_ecdh, priv_key))
+ goto out_err;
+
+ field_size = EC_GROUP_get_degree(group);
+ if (field_size <= 0)
+ goto out_err;
+
+ p = enif_make_new_binary(env, (field_size+7)/8, &ret);
+ i = ECDH_compute_key(p, (field_size+7)/8, my_ecpoint, other_ecdh, NULL);
+
+ if (i < 0)
+ goto out_err;
+out:
+ if (group) EC_GROUP_free(group);
+ if (my_ecpoint) EC_POINT_free(my_ecpoint);
+ if (other_ecdh) EC_KEY_free(other_ecdh);
+
+ return ret;
+
+out_err:
+ ret = enif_make_badarg(env);
+ goto out;
+#else
+ return atom_notsup;
+#endif
+}
/* HMAC */
diff --git a/lib/crypto/doc/src/crypto.xml b/lib/crypto/doc/src/crypto.xml
index 29fc885152..df765ade87 100755..100644
--- a/lib/crypto/doc/src/crypto.xml
+++ b/lib/crypto/doc/src/crypto.xml
@@ -22,263 +22,222 @@
</legalnotice>
<title>crypto</title>
- <prepared>Peter H&ouml;gfeldt</prepared>
- <docno></docno>
- <date>2000-06-20</date>
- <rev>B</rev>
</header>
<module>crypto</module>
<modulesummary>Crypto Functions</modulesummary>
<description>
<p>This module provides a set of cryptographic functions.
</p>
- <p>References:</p>
<list type="bulleted">
<item>
- <p>md4: The MD4 Message Digest Algorithm (RFC 1320)</p>
- </item>
- <item>
- <p>md5: The MD5 Message Digest Algorithm (RFC 1321)</p>
- </item>
- <item>
- <p>sha: Secure Hash Standard (FIPS 180-2)</p>
- </item>
- <item>
- <p>hmac: Keyed-Hashing for Message Authentication (RFC 2104)</p>
- </item>
- <item>
- <p>des: Data Encryption Standard (FIPS 46-3)</p>
+ <p>Hash functions -
+ <url href="http://csrc.nist.gov/publications/fips/fips180-4/fips-180-4.pdf"> Secure Hash Standard</url>,
+ <url href="http://www.ietf.org/rfc/rfc1321.txt"> The MD5 Message Digest Algorithm (RFC 1321)</url> and
+ <url href="http://www.ietf.org/rfc/rfc1320.txt">The MD4 Message Digest Algorithm (RFC 1320)</url>
+ </p>
</item>
<item>
- <p>aes: Advanced Encryption Standard (AES) (FIPS 197) </p>
+ <p>Hmac functions - <url href="http://www.ietf.org/rfc/rfc2104.txt"> Keyed-Hashing for Message Authentication (RFC 2104) </url></p>
</item>
<item>
- <p>ecb, cbc, cfb, ofb, ctr: Recommendation for Block Cipher Modes
- of Operation (NIST SP 800-38A).</p>
+ <p>Block ciphers - <url href="http://csrc.nist.gov/groups/ST/toolkit/block_ciphers.html"> </url> DES and AES in
+ Block Cipher Modes - <url href="http://csrc.nist.gov/groups/ST/toolkit/BCM/index.html"> ECB, CBC, CFB, OFB and CTR </url></p>
</item>
<item>
- <p>rsa: Recommendation for Block Cipher Modes of Operation
- (NIST 800-38A)</p>
+ <p><url href="http://www.ietf.org/rfc/rfc1321.txt"> RSA encryption RFC 1321 </url> </p>
</item>
<item>
- <p>dss: Digital Signature Standard (FIPS 186-2)</p>
+ <p>Digital signatures <url href="http://csrc.nist.gov/publications/drafts/fips186-3/fips_186-3.pdf">Digital Signature Standard (DSS)</url> and<url href="http://csrc.nist.gov/groups/STM/cavp/documents/dss2/ecdsa2vs.pdf"> Elliptic Curve Digital
+ Signature Algorithm (ECDSA) </url> </p>
</item>
<item>
- <p>srp: Secure Remote Password Protocol (RFC 2945)</p>
+ <p><url href="http://www.ietf.org/rfc/rfc2945.txt"> Secure Remote Password Protocol (SRP - RFC 2945) </url></p>
</item>
-
-
</list>
- <p>The above publications can be found at <url href="http://csrc.nist.gov/publications">NIST publications</url>, at <url href="http://www.ietf.org">IETF</url>.
- </p>
- <p><em>Types</em></p>
- <pre>
-byte() = 0 ... 255
-ioelem() = byte() | binary() | iolist()
-iolist() = [ioelem()]
-Mpint() = <![CDATA[<<ByteLen:32/integer-big, Bytes:ByteLen/binary>>]]>
- </pre>
- <p></p>
</description>
+
+ <section>
+ <title>DATA TYPES </title>
+
+ <p><code>key_value() = integer() | binary() </code></p>
+
+ <p><code>rsa_public() = [key_value()] = [E, N] </code></p>
+ <p> Where E is the public exponent and N is public modulus. </p>
+
+ <p><code>rsa_private() = [key_value()] = [E, N, D] | [E, N, D, P1, P2, E1, E2, C] </code></p>
+ <p>Where E is the public exponent, N is public modulus and D is
+ the private exponent.The longer key format contains redundant
+ information that will make the calculation faster. P1,P2 are first
+ and second prime factors. E1,E2 are first and second exponents. C
+ is the CRT coefficient. Terminology is taken from <url href="http://www.ietf.org/rfc/rfc3477.txt"> RFC 3447</url>.</p>
+
+ <p><code>dss_public() = [key_value()] = [P, Q, G, Y] </code></p>
+ <p>Where P, Q and G are the dss parameters and Y is the public key.</p>
+
+ <p><code>dss_private() = [key_value()] = [P, Q, G, X] </code></p>
+ <p>Where P, Q and G are the dss parameters and X is the private key.</p>
+
+ <p><code>dss_public() = [key_value()] =[P, Q, G, Y] </code></p>
+
+ <p><code>srp_public() = key_value() </code></p>
+ <p>Where is <c>A</c> or <c>B</c> from <url href="http://srp.stanford.edu/design.html">SRP design</url></p>
+
+ <p><code>srp_private() = key_value() </code></p>
+ <p>Where is <c>a</c> or <c>b</c> from <url href="http://srp.stanford.edu/design.html">SRP design</url></p>
+
+ <p><code>srp_params() = {user, [Generator::binary(), Prime::binary(), Version::atom()]} |
+ {host, [Verifier::binary(), Generator::binary(), Prime::binary(), Version::atom()]}
+ | {user, [DerivedKey::binary(), Prime::binary(), Generator::binary(), Version::atom() | [Scrambler:binary()]]}
+ | {host,[Verifier::binary(), Prime::binary(), Version::atom() | [Scrambler::binary]]} </code></p>
+
+ <p>Where Verifier is <c>v</c>, Generator is <c>g</c> and Prime is<c> N</c>, DerivedKey is <c>X</c>, and Scrambler is
+ <c>u</c> (optional will be genrated if not provided) from <url href="http://srp.stanford.edu/design.html">SRP design</url>
+ Version = '3' | '6' | '6a'
+ </p>
+
+ <p><code>dh_public() = key_value() </code></p>
+
+ <p><code>dh_private() = key_value() </code></p>
+
+ <p><code>dh_params() = [key_value()] = [P, G] </code></p>
+
+ <p><code>ecdh_public() = key_value() </code></p>
+
+ <p><code>ecdh_private() = key_value() </code></p>
+
+ <p><code>ecdh_params() = ec_named_curve() |
+ {ec_field(), Prime :: key_value(), Point :: key_value(), Order :: integer(), CoFactor :: none | integer()} </code></p>
+
+ <p><code>ec_field() = {prime_field, Prime :: integer()} |
+ {characteristic_two_field, M :: integer(), Basis :: ec_basis()}</code></p>
+
+ <p><code>ec_basis() = {tpbasis, K :: non_neg_integer()} |
+ {ppbasis, K1 :: non_neg_integer(), K2 :: non_neg_integer(), K3 :: non_neg_integer()} |
+ onbasis</code></p>
+
+ <p><code>ec_named_curve() ->
+ sect571r1| sect571k1| sect409r1| sect409k1| secp521r1| secp384r1| secp224r1| secp224k1|
+ secp192k1| secp160r2| secp128r2| secp128r1| sect233r1| sect233k1| sect193r2| sect193r1|
+ sect131r2| sect131r1| sect283r1| sect283k1| sect163r2| secp256k1| secp160k1| secp160r1|
+ secp112r2| secp112r1| sect113r2| sect113r1| sect239k1| sect163r1| sect163k1| secp256r1|
+ secp192r1 </code></p>
+
+ <p><code>stream_cipher() = rc4 | aes_ctr </code></p>
+
+ <p><code>block_cipher() = aes_cbc128 | aes_cfb128 | blowfish_cbc |
+ blowfish_cfb64 | des_cbc | des_cfb | des3_cbc | des3_cbf
+ | des_ede3 | rc2_cbc </code></p>
+
+ <p><code>stream_key() = aes_key() | rc4_key() </code></p>
+
+ <p><code>block_key() = aes_key() | blowfish_key() | des_key()| des3_key() </code></p>
+
+ <p><code>aes_key() = iodata() </code> Key length is 128, 192 or 256 bits</p>
+
+ <p><code>rc4_key() = iodata() </code> Variable key length from 8 bits up to 2048 bits (usually between 40 and 256)</p>
+
+ <p><code>blowfish_key() = iodata() </code> Variable key length from 32 bits up to 448 bits</p>
+
+ <p><code>des_key() = iodata() </code> Key length is 64 bits (in CBC mode only 8 bits are used)</p>
+
+ <p><code>des3_key() = [binary(), binary(), binary()] </code> Each key part is 64 bits (in CBC mode only 8 bits are used)</p>
+
+ <p><code> message_digest_algorithms() = md5 | ripemd160 | sha | sha224 | sha256 | sha384 | sha512 </code> md4 is aslo supported for hash_init/1 and hash/2.
+ Note that both md4 and md5 are recommended only for compatibility with existing applications.
+ </p>
+ </section>
+
<funcs>
<func>
- <name>start() -> ok</name>
- <fsummary>Start the crypto server.</fsummary>
- <desc>
- <p>Starts the crypto server.</p>
- </desc>
- </func>
- <func>
- <name>stop() -> ok</name>
- <fsummary>Stop the crypto server.</fsummary>
- <desc>
- <p>Stops the crypto server.</p>
- </desc>
- </func>
- <func>
- <name>info() -> [atom()]</name>
- <fsummary>Provide a list of available crypto functions.</fsummary>
- <desc>
- <p>Provides the available crypto functions in terms of a list
- of atoms.</p>
- </desc>
- </func>
- <func>
- <name>algorithms() -> [atom()]</name>
+ <name>algorithms() -> [message_digest_algorithms() | md4 | ec]</name>
<fsummary>Provide a list of available crypto algorithms.</fsummary>
<desc>
- <p>Provides the available crypto algorithms in terms of a list
- of atoms.</p>
- </desc>
- </func>
- <func>
- <name>info_lib() -> [{Name,VerNum,VerStr}]</name>
- <fsummary>Provides information about the libraries used by crypto.</fsummary>
- <type>
- <v>Name = binary()</v>
- <v>VerNum = integer()</v>
- <v>VerStr = binary()</v>
- </type>
- <desc>
- <p>Provides the name and version of the libraries used by crypto.</p>
- <p><c>Name</c> is the name of the library. <c>VerNum</c> is
- the numeric version according to the library's own versioning
- scheme. <c>VerStr</c> contains a text variant of the version.</p>
- <pre>
-> <input>info_lib().</input>
-[{&lt;&lt;"OpenSSL"&gt;&gt;,9469983,&lt;&lt;"OpenSSL 0.9.8a 11 Oct 2005"&gt;&gt;}]
- </pre>
- <note><p>
- From OTP R16 the <em>numeric version</em> represents the version of the OpenSSL
- <em>header files</em> (<c>openssl/opensslv.h</c>) used when crypto was compiled.
- The text variant represents the OpenSSL library used at runtime.
- In earlier OTP versions both numeric and text was taken from the library.
- </p></note>
- </desc>
- </func>
- <func>
- <name>md4(Data) -> Digest</name>
- <fsummary>Compute an <c>MD4</c>message digest from <c>Data</c></fsummary>
- <type>
- <v>Data = iolist() | binary()</v>
- <v>Digest = binary()</v>
- </type>
- <desc>
- <p>Computes an <c>MD4</c> message digest from <c>Data</c>, where
- the length of the digest is 128 bits (16 bytes).</p>
- </desc>
- </func>
- <func>
- <name>md4_init() -> Context</name>
- <fsummary>Creates an MD4 context</fsummary>
- <type>
- <v>Context = binary()</v>
- </type>
- <desc>
- <p>Creates an MD4 context, to be used in subsequent calls to
- <c>md4_update/2</c>.</p>
- </desc>
- </func>
- <func>
- <name>md4_update(Context, Data) -> NewContext</name>
- <fsummary>Update an MD4 <c>Context</c>with <c>Data</c>, and return a <c>NewContext</c></fsummary>
- <type>
- <v>Data = iolist() | binary()</v>
- <v>Context = NewContext = binary()</v>
- </type>
- <desc>
- <p>Updates an MD4 <c>Context</c> with <c>Data</c>, and returns
- a <c>NewContext</c>.</p>
- </desc>
- </func>
- <func>
- <name>md4_final(Context) -> Digest</name>
- <fsummary>Finish the update of an MD4 <c>Context</c>and return the computed <c>MD4</c>message digest</fsummary>
- <type>
- <v>Context = Digest = binary()</v>
- </type>
- <desc>
- <p>Finishes the update of an MD4 <c>Context</c> and returns
- the computed <c>MD4</c> message digest.</p>
- </desc>
- </func>
- <func>
- <name>md5(Data) -> Digest</name>
- <fsummary>Compute an <c>MD5</c>message digest from <c>Data</c></fsummary>
- <type>
- <v>Data = iolist() | binary()</v>
- <v>Digest = binary()</v>
- </type>
- <desc>
- <p>Computes an <c>MD5</c> message digest from <c>Data</c>, where
- the length of the digest is 128 bits (16 bytes).</p>
+ <p> Can be used to determine if the crypto library has support for elliptic curve (ec) and
+ which message digest algorithms that are supported.</p>
</desc>
</func>
- <func>
- <name>md5_init() -> Context</name>
- <fsummary>Creates an MD5 context</fsummary>
- <type>
- <v>Context = binary()</v>
- </type>
- <desc>
- <p>Creates an MD5 context, to be used in subsequent calls to
- <c>md5_update/2</c>.</p>
- </desc>
- </func>
- <func>
- <name>md5_update(Context, Data) -> NewContext</name>
- <fsummary>Update an MD5 <c>Context</c>with <c>Data</c>, and return a <c>NewContext</c></fsummary>
- <type>
- <v>Data = iolist() | binary()</v>
- <v>Context = NewContext = binary()</v>
- </type>
- <desc>
- <p>Updates an MD5 <c>Context</c> with <c>Data</c>, and returns
- a <c>NewContext</c>.</p>
- </desc>
- </func>
- <func>
- <name>md5_final(Context) -> Digest</name>
- <fsummary>Finish the update of an MD5 <c>Context</c>and return the computed <c>MD5</c>message digest</fsummary>
+
+ <func>
+ <name>block_encrypt(Type, Key, Ivec, PlainText) -> CipherText</name>
+ <fsummary>Encrypt <c>PlainText</c>according to <c>Type</c> block cipher</fsummary>
<type>
- <v>Context = Digest = binary()</v>
+ <v>Key = block_key() </v>
+ <v>PlainText = iodata() </v>
+ <v>IVec = CipherText = binary()</v>
</type>
<desc>
- <p>Finishes the update of an MD5 <c>Context</c> and returns
- the computed <c>MD5</c> message digest.</p>
+ <p>Encrypt <c>PlainText</c>according to <c>Type</c> block cipher.
+ <c>IVec</c> is an arbitrary initializing vector.
+ </p>
</desc>
</func>
+
<func>
- <name>sha(Data) -> Digest</name>
- <fsummary>Compute an <c>SHA</c>message digest from <c>Data</c></fsummary>
+ <name>block_decrypt(Type, Key, Ivec, CipherText) -> PlainText</name>
+ <fsummary>Decrypt <c>CipherText</c>according to <c>Type</c> block cipher</fsummary>
<type>
- <v>Data = iolist() | binary()</v>
- <v>Digest = binary()</v>
+ <v>Key = block_key() </v>
+ <v>PlainText = iodata() </v>
+ <v>IVec = CipherText = binary()</v>
</type>
<desc>
- <p>Computes an <c>SHA</c> message digest from <c>Data</c>, where
- the length of the digest is 160 bits (20 bytes).</p>
+ <p>Decrypt <c>CipherText</c>according to <c>Type</c> block cipher.
+ <c>IVec</c> is an arbitrary initializing vector.
+ </p>
</desc>
</func>
+
<func>
- <name>sha_init() -> Context</name>
- <fsummary>Create an SHA context</fsummary>
+ <name>compute_key(Type, OthersPublicKey, MyPrivateKey, Params) -> SharedSecret</name>
+ <fsummary>Computes the shared secret</fsummary>
<type>
- <v>Context = binary()</v>
+ <v> Type = dh | ecdh | srp </v>
+ <v>OthersPublicKey = dh_public() | ecdh_public() | srp_public() </v>
+ <v>MyPrivate = dh_private() | ecdh_private() | srp_private() </v>
+ <v>Params = dh_params() | edhc_params() | srp_params() </v>
+ <v>SharedSecret = binary()</v>
</type>
<desc>
- <p>Creates an SHA context, to be used in subsequent calls to
- <c>sha_update/2</c>.</p>
+ <p>Computes the shared secret from the private key and the other party's public key.
+ See also <seealso marker="public_key:public_key#compute_key/2">public_key:compute_key/2</seealso>
+ </p>
</desc>
</func>
+
<func>
- <name>sha_update(Context, Data) -> NewContext</name>
- <fsummary>Update an SHA context</fsummary>
+ <name>exor(Data1, Data2) -> Result</name>
+ <fsummary>XOR data</fsummary>
<type>
- <v>Data = iolist() | binary()</v>
- <v>Context = NewContext = binary()</v>
+ <v>Data1, Data2 = iodata()</v>
+ <v>Result = binary()</v>
</type>
<desc>
- <p>Updates an SHA <c>Context</c> with <c>Data</c>, and returns
- a <c>NewContext</c>.</p>
+ <p>Performs bit-wise XOR (exclusive or) on the data supplied.</p>
</desc>
</func>
- <func>
- <name>sha_final(Context) -> Digest</name>
- <fsummary>Finish the update of an SHA context</fsummary>
+
+ <func>
+ <name>generate_key(Type, Params) -> {PublicKey, PrivateKey} </name>
+ <name>generate_key(Type, Params, PrivateKey) -> {PublicKey, PrivateKey} </name>
+ <fsummary>Generates a public keys of type <c>Type</c></fsummary>
<type>
- <v>Context = Digest = binary()</v>
+ <v> Type = dh | ecdh | srp </v>
+ <v>Params = dh_params() | edhc_params() | srp_params() </v>
+ <v>PublicKey = dh_public() | ecdh_public() | srp_public() </v>
+ <v>PrivateKey = dh_private() | ecdh_private() | srp_private() </v>
</type>
<desc>
- <p>Finishes the update of an SHA <c>Context</c> and returns
- the computed <c>SHA</c> message digest.</p>
+ <p>Generates public keys of type <c>Type</c>.
+ See also <seealso marker="public_key:public_key#generate_key/1">public_key:generate_key/1</seealso>
+ </p>
</desc>
</func>
- <func>
+
+ <func>
<name>hash(Type, Data) -> Digest</name>
<fsummary></fsummary>
<type>
- <v>Type = md4 | md5 | ripemd160 | sha | sha224 | sha256 | sha384 | sha512</v>
+ <v>Type = md4 | message_digest_algorithms()</v>
<v>Data = iodata()</v>
<v>Digest = binary()</v>
</type>
@@ -288,11 +247,12 @@ Mpint() = <![CDATA[<<ByteLen:32/integer-big, Bytes:ByteLen/binary>>]]>
is not supported by the underlying OpenSSL implementation.</p>
</desc>
</func>
+
<func>
<name>hash_init(Type) -> Context</name>
<fsummary></fsummary>
<type>
- <v>Type = md4 | md5 | ripemd160 | sha | sha224 | sha256 | sha384 | sha512</v>
+ <v>Type = md4 | message_digest_algorithms()</v>
</type>
<desc>
<p>Initializes the context for streaming hash operations. <c>Type</c> determines
@@ -302,6 +262,7 @@ Mpint() = <![CDATA[<<ByteLen:32/integer-big, Bytes:ByteLen/binary>>]]>
is not supported by the underlying OpenSSL implementation.</p>
</desc>
</func>
+
<func>
<name>hash_update(Context, Data) -> NewContext</name>
<fsummary></fsummary>
@@ -329,38 +290,13 @@ Mpint() = <![CDATA[<<ByteLen:32/integer-big, Bytes:ByteLen/binary>>]]>
function used to generate it.</p>
</desc>
</func>
- <func>
- <name>md5_mac(Key, Data) -> Mac</name>
- <fsummary>Compute an <c>MD5 MAC</c>message authentification code</fsummary>
- <type>
- <v>Key = Data = iolist() | binary()</v>
- <v>Mac = binary()</v>
- </type>
- <desc>
- <p>Computes an <c>MD5 MAC</c> message authentification code
- from <c>Key</c> and <c>Data</c>, where the the length of the
- Mac is 128 bits (16 bytes).</p>
- </desc>
- </func>
- <func>
- <name>md5_mac_96(Key, Data) -> Mac</name>
- <fsummary>Compute an <c>MD5 MAC</c>message authentification code</fsummary>
- <type>
- <v>Key = Data = iolist() | binary()</v>
- <v>Mac = binary()</v>
- </type>
- <desc>
- <p>Computes an <c>MD5 MAC</c> message authentification code
- from <c>Key</c> and <c>Data</c>, where the length of the Mac
- is 96 bits (12 bytes).</p>
- </desc>
- </func>
+
<func>
<name>hmac(Type, Key, Data) -> Mac</name>
<name>hmac(Type, Key, Data, MacLength) -> Mac</name>
<fsummary></fsummary>
<type>
- <v>Type = md5 | sha | sha224 | sha256 | sha384 | sha512</v>
+ <v>Type = message_digest_algorithms() </v>
<v>Key = iodata()</v>
<v>Data = iodata()</v>
<v>MacLength = integer()</v>
@@ -372,12 +308,13 @@ Mpint() = <![CDATA[<<ByteLen:32/integer-big, Bytes:ByteLen/binary>>]]>
will limit the size of the resultant <c>Mac</c>.
</desc>
</func>
+
<func>
<name>hmac_init(Type, Key) -> Context</name>
<fsummary></fsummary>
<type>
- <v>Type = md5 | ripemd160 | sha | sha224 | sha256 | sha384 | sha512</v>
- <v>Key = iolist() | binary()</v>
+ <v>Type = message_digest_algorithms()</v>
+ <v>Key = iodata()</v>
<v>Context = binary()</v>
</type>
<desc>
@@ -386,20 +323,26 @@ Mpint() = <![CDATA[<<ByteLen:32/integer-big, Bytes:ByteLen/binary>>]]>
key. The key can be any length.</p>
</desc>
</func>
+
<func>
<name>hmac_update(Context, Data) -> NewContext</name>
<fsummary></fsummary>
<type>
<v>Context = NewContext = binary()</v>
- <v>Data = iolist() | binary()</v>
+ <v>Data = iodata()</v>
</type>
<desc>
<p>Updates the HMAC represented by <c>Context</c> using the given <c>Data</c>. <c>Context</c>
must have been generated using an HMAC init function (such as
<seealso marker="#hmac_init/2">hmac_init</seealso>). <c>Data</c> can be any length. <c>NewContext</c>
- must be passed into the next call to <c>hmac_update</c>.</p>
+ must be passed into the next call to <c>hmac_update</c>
+ or to one of the functions <seealso marker="#hmac_final/1">hmac_final</seealso> and
+ <seealso marker="#hmac_final_n/1">hmac_final_n</seealso>
+ </p>
+
</desc>
</func>
+
<func>
<name>hmac_final(Context) -> Mac</name>
<fsummary></fsummary>
@@ -411,6 +354,7 @@ Mpint() = <![CDATA[<<ByteLen:32/integer-big, Bytes:ByteLen/binary>>]]>
determined by the type of hash function used to generate it.</p>
</desc>
</func>
+
<func>
<name>hmac_final_n(Context, HashLen) -> Mac</name>
<fsummary></fsummary>
@@ -423,705 +367,88 @@ Mpint() = <![CDATA[<<ByteLen:32/integer-big, Bytes:ByteLen/binary>>]]>
zero. <c>Mac</c> will be a binary with at most <c>HashLen</c> bytes. Note that if HashLen is greater than the actual number of bytes returned from the underlying hash, the returned hash will have fewer than <c>HashLen</c> bytes.</p>
</desc>
</func>
- <func>
- <name>sha_mac(Key, Data) -> Mac</name>
- <name>sha_mac(Key, Data, MacLength) -> Mac</name>
- <fsummary>Compute an <c>MD5 MAC</c>message authentification code</fsummary>
- <type>
- <v>Key = Data = iolist() | binary()</v>
- <v>Mac = binary()</v>
- <v>MacLenength = integer() =&lt; 20 </v>
- </type>
- <desc>
- <p>Computes an <c>SHA MAC</c> message authentification code
- from <c>Key</c> and <c>Data</c>, where the default length of the Mac
- is 160 bits (20 bytes).</p>
- </desc>
- </func>
- <func>
- <name>sha_mac_96(Key, Data) -> Mac</name>
- <fsummary>Compute an <c>SHA MAC</c>message authentification code</fsummary>
- <type>
- <v>Key = Data = iolist() | binary()</v>
- <v>Mac = binary()</v>
- </type>
- <desc>
- <p>Computes an <c>SHA MAC</c> message authentification code
- from <c>Key</c> and <c>Data</c>, where the length of the Mac
- is 96 bits (12 bytes).</p>
- </desc>
- </func>
- <func>
- <name>des_cbc_encrypt(Key, IVec, Text) -> Cipher</name>
- <fsummary>Encrypt <c>Text</c>according to DES in CBC mode</fsummary>
- <type>
- <v>Key = Text = iolist() | binary()</v>
- <v>IVec = Cipher = binary()</v>
- </type>
- <desc>
- <p>Encrypts <c>Text</c> according to DES in CBC
- mode. <c>Text</c> must be a multiple of 64 bits (8
- bytes). <c>Key</c> is the DES key, and <c>IVec</c> is an
- arbitrary initializing vector. The lengths of <c>Key</c> and
- <c>IVec</c> must be 64 bits (8 bytes).</p>
- </desc>
- </func>
- <func>
- <name>des_cbc_decrypt(Key, IVec, Cipher) -> Text</name>
- <fsummary>Decrypt <c>Cipher</c>according to DES in CBC mode</fsummary>
- <type>
- <v>Key = Cipher = iolist() | binary()</v>
- <v>IVec = Text = binary()</v>
- </type>
- <desc>
- <p>Decrypts <c>Cipher</c> according to DES in CBC mode.
- <c>Key</c> is the DES key, and <c>IVec</c> is an arbitrary
- initializing vector. <c>Key</c> and <c>IVec</c> must have
- the same values as those used when encrypting. <c>Cipher</c>
- must be a multiple of 64 bits (8 bytes). The lengths of
- <c>Key</c> and <c>IVec</c> must be 64 bits (8 bytes).</p>
- </desc>
- </func>
- <func>
- <name>des_cbc_ivec(Data) -> IVec</name>
- <fsummary>Get <c>IVec</c> to be used in next iteration of
- <c>des_cbc_[ecrypt|decrypt]</c></fsummary>
- <type>
- <v>Data = iolist() | binary()</v>
- <v>IVec = binary()</v>
- </type>
- <desc>
- <p>Returns the <c>IVec</c> to be used in a next iteration of
- <c>des_cbc_[encrypt|decrypt]</c>. <c>Data</c> is the encrypted
- data from the previous iteration step.</p>
- </desc>
- </func>
- <func>
- <name>des_cfb_encrypt(Key, IVec, Text) -> Cipher</name>
- <fsummary>Encrypt <c>Text</c>according to DES in CFB mode</fsummary>
- <type>
- <v>Key = Text = iolist() | binary()</v>
- <v>IVec = Cipher = binary()</v>
- </type>
- <desc>
- <p>Encrypts <c>Text</c> according to DES in 8-bit CFB
- mode. <c>Key</c> is the DES key, and <c>IVec</c> is an
- arbitrary initializing vector. The lengths of <c>Key</c> and
- <c>IVec</c> must be 64 bits (8 bytes).</p>
- </desc>
- </func>
- <func>
- <name>des_cfb_decrypt(Key, IVec, Cipher) -> Text</name>
- <fsummary>Decrypt <c>Cipher</c>according to DES in CFB mode</fsummary>
- <type>
- <v>Key = Cipher = iolist() | binary()</v>
- <v>IVec = Text = binary()</v>
- </type>
- <desc>
- <p>Decrypts <c>Cipher</c> according to DES in 8-bit CFB mode.
- <c>Key</c> is the DES key, and <c>IVec</c> is an arbitrary
- initializing vector. <c>Key</c> and <c>IVec</c> must have
- the same values as those used when encrypting. The lengths of
- <c>Key</c> and <c>IVec</c> must be 64 bits (8 bytes).</p>
- </desc>
- </func>
- <func>
- <name>des_cfb_ivec(IVec, Data) -> NextIVec</name>
- <fsummary>Get <c>IVec</c> to be used in next iteration of
- <c>des_cfb_[ecrypt|decrypt]</c></fsummary>
- <type>
- <v>IVec = iolist() | binary()</v>
- <v>Data = iolist() | binary()</v>
- <v>NextIVec = binary()</v>
- </type>
- <desc>
- <p>Returns the <c>IVec</c> to be used in a next iteration of
- <c>des_cfb_[encrypt|decrypt]</c>. <c>IVec</c> is the vector
- used in the previous iteration step. <c>Data</c> is the encrypted
- data from the previous iteration step.</p>
- </desc>
- </func>
- <func>
- <name>des3_cbc_encrypt(Key1, Key2, Key3, IVec, Text) -> Cipher</name>
- <fsummary>Encrypt <c>Text</c>according to DES3 in CBC mode</fsummary>
- <type>
- <v>Key1 =Key2 = Key3 Text = iolist() | binary()</v>
- <v>IVec = Cipher = binary()</v>
- </type>
- <desc>
- <p>Encrypts <c>Text</c> according to DES3 in CBC
- mode. <c>Text</c> must be a multiple of 64 bits (8
- bytes). <c>Key1</c>, <c>Key2</c>, <c>Key3</c>, are the DES
- keys, and <c>IVec</c> is an arbitrary initializing
- vector. The lengths of each of <c>Key1</c>, <c>Key2</c>,
- <c>Key3</c> and <c>IVec</c> must be 64 bits (8 bytes).</p>
- </desc>
- </func>
- <func>
- <name>des3_cbc_decrypt(Key1, Key2, Key3, IVec, Cipher) -> Text</name>
- <fsummary>Decrypt <c>Cipher</c>according to DES3 in CBC mode</fsummary>
- <type>
- <v>Key1 = Key2 = Key3 = Cipher = iolist() | binary()</v>
- <v>IVec = Text = binary()</v>
- </type>
- <desc>
- <p>Decrypts <c>Cipher</c> according to DES3 in CBC mode.
- <c>Key1</c>, <c>Key2</c>, <c>Key3</c> are the DES key, and
- <c>IVec</c> is an arbitrary initializing vector.
- <c>Key1</c>, <c>Key2</c>, <c>Key3</c> and <c>IVec</c> must
- and <c>IVec</c> must have the same values as those used when
- encrypting. <c>Cipher</c> must be a multiple of 64 bits (8
- bytes). The lengths of <c>Key1</c>, <c>Key2</c>,
- <c>Key3</c>, and <c>IVec</c> must be 64 bits (8 bytes).</p>
- </desc>
- </func>
- <func>
- <name>des3_cfb_encrypt(Key1, Key2, Key3, IVec, Text) -> Cipher</name>
- <fsummary>Encrypt <c>Text</c>according to DES3 in CFB mode</fsummary>
- <type>
- <v>Key1 =Key2 = Key3 Text = iolist() | binary()</v>
- <v>IVec = Cipher = binary()</v>
- </type>
- <desc>
- <p>Encrypts <c>Text</c> according to DES3 in 8-bit CFB
- mode. <c>Key1</c>, <c>Key2</c>, <c>Key3</c>, are the DES
- keys, and <c>IVec</c> is an arbitrary initializing
- vector. The lengths of each of <c>Key1</c>, <c>Key2</c>,
- <c>Key3</c> and <c>IVec</c> must be 64 bits (8 bytes).</p>
- <p>May throw exception <c>notsup</c> for old OpenSSL
- versions (0.9.7) that does not support this encryption mode.</p>
- </desc>
- </func>
- <func>
- <name>des3_cfb_decrypt(Key1, Key2, Key3, IVec, Cipher) -> Text</name>
- <fsummary>Decrypt <c>Cipher</c>according to DES3 in CFB mode</fsummary>
- <type>
- <v>Key1 = Key2 = Key3 = Cipher = iolist() | binary()</v>
- <v>IVec = Text = binary()</v>
- </type>
- <desc>
- <p>Decrypts <c>Cipher</c> according to DES3 in 8-bit CFB mode.
- <c>Key1</c>, <c>Key2</c>, <c>Key3</c> are the DES key, and
- <c>IVec</c> is an arbitrary initializing vector.
- <c>Key1</c>, <c>Key2</c>, <c>Key3</c> and <c>IVec</c> must
- and <c>IVec</c> must have the same values as those used when
- encrypting. The lengths of <c>Key1</c>, <c>Key2</c>,
- <c>Key3</c>, and <c>IVec</c> must be 64 bits (8 bytes).</p>
- <p>May throw exception <c>notsup</c> for old OpenSSL
- versions (0.9.7) that does not support this encryption mode.</p>
- </desc>
- </func>
-
- <func>
- <name>des_ecb_encrypt(Key, Text) -> Cipher</name>
- <fsummary>Encrypt <c>Text</c>according to DES in ECB mode</fsummary>
- <type>
- <v>Key = Text = iolist() | binary()</v>
- <v>Cipher = binary()</v>
- </type>
- <desc>
- <p>Encrypts <c>Text</c> according to DES in ECB mode.
- <c>Key</c> is the DES key. The lengths of <c>Key</c> and
- <c>Text</c> must be 64 bits (8 bytes).</p>
- </desc>
- </func>
- <func>
- <name>des_ecb_decrypt(Key, Cipher) -> Text</name>
- <fsummary>Decrypt <c>Cipher</c>according to DES in ECB mode</fsummary>
- <type>
- <v>Key = Cipher = iolist() | binary()</v>
- <v>Text = binary()</v>
- </type>
- <desc>
- <p>Decrypts <c>Cipher</c> according to DES in ECB mode.
- <c>Key</c> is the DES key. The lengths of <c>Key</c> and
- <c>Cipher</c> must be 64 bits (8 bytes).</p>
- </desc>
- </func>
-
- <func>
- <name>blowfish_ecb_encrypt(Key, Text) -> Cipher</name>
- <fsummary>Encrypt the first 64 bits of <c>Text</c> using Blowfish in ECB mode</fsummary>
- <type>
- <v>Key = Text = iolist() | binary()</v>
- <v>Cipher = binary()</v>
- </type>
- <desc>
- <p>Encrypts the first 64 bits of <c>Text</c> using Blowfish in ECB mode. <c>Key</c> is the Blowfish key. The length of <c>Text</c> must be at least 64 bits (8 bytes).</p>
- </desc>
- </func>
- <func>
- <name>blowfish_ecb_decrypt(Key, Text) -> Cipher</name>
- <fsummary>Decrypt the first 64 bits of <c>Text</c> using Blowfish in ECB mode</fsummary>
- <type>
- <v>Key = Text = iolist() | binary()</v>
- <v>Cipher = binary()</v>
- </type>
- <desc>
- <p>Decrypts the first 64 bits of <c>Text</c> using Blowfish in ECB mode. <c>Key</c> is the Blowfish key. The length of <c>Text</c> must be at least 64 bits (8 bytes).</p>
- </desc>
- </func>
-
- <func>
- <name>blowfish_cbc_encrypt(Key, IVec, Text) -> Cipher</name>
- <fsummary>Encrypt <c>Text</c> using Blowfish in CBC mode</fsummary>
- <type>
- <v>Key = Text = iolist() | binary()</v>
- <v>IVec = Cipher = binary()</v>
- </type>
- <desc>
- <p>Encrypts <c>Text</c> using Blowfish in CBC mode. <c>Key</c> is the Blowfish key, and <c>IVec</c> is an
- arbitrary initializing vector. The length of <c>IVec</c>
- must be 64 bits (8 bytes). The length of <c>Text</c> must be a multiple of 64 bits (8 bytes).</p>
- </desc>
- </func>
- <func>
- <name>blowfish_cbc_decrypt(Key, IVec, Text) -> Cipher</name>
- <fsummary>Decrypt <c>Text</c> using Blowfish in CBC mode</fsummary>
- <type>
- <v>Key = Text = iolist() | binary()</v>
- <v>IVec = Cipher = binary()</v>
- </type>
- <desc>
- <p>Decrypts <c>Text</c> using Blowfish in CBC mode. <c>Key</c> is the Blowfish key, and <c>IVec</c> is an
- arbitrary initializing vector. The length of <c>IVec</c>
- must be 64 bits (8 bytes). The length of <c>Text</c> must be a multiple 64 bits (8 bytes).</p>
- </desc>
- </func>
-
- <func>
- <name>blowfish_cfb64_encrypt(Key, IVec, Text) -> Cipher</name>
- <fsummary>Encrypt <c>Text</c>using Blowfish in CFB mode with 64
- bit feedback</fsummary>
- <type>
- <v>Key = Text = iolist() | binary()</v>
- <v>IVec = Cipher = binary()</v>
- </type>
- <desc>
- <p>Encrypts <c>Text</c> using Blowfish in CFB mode with 64 bit
- feedback. <c>Key</c> is the Blowfish key, and <c>IVec</c> is an
- arbitrary initializing vector. The length of <c>IVec</c>
- must be 64 bits (8 bytes).</p>
- </desc>
- </func>
- <func>
- <name>blowfish_cfb64_decrypt(Key, IVec, Text) -> Cipher</name>
- <fsummary>Decrypt <c>Text</c>using Blowfish in CFB mode with 64
- bit feedback</fsummary>
- <type>
- <v>Key = Text = iolist() | binary()</v>
- <v>IVec = Cipher = binary()</v>
- </type>
- <desc>
- <p>Decrypts <c>Text</c> using Blowfish in CFB mode with 64 bit
- feedback. <c>Key</c> is the Blowfish key, and <c>IVec</c> is an
- arbitrary initializing vector. The length of <c>IVec</c>
- must be 64 bits (8 bytes).</p>
- </desc>
- </func>
<func>
- <name>blowfish_ofb64_encrypt(Key, IVec, Text) -> Cipher</name>
- <fsummary>Encrypt <c>Text</c>using Blowfish in OFB mode with 64
- bit feedback</fsummary>
+ <name>info_lib() -> [{Name,VerNum,VerStr}]</name>
+ <fsummary>Provides information about the libraries used by crypto.</fsummary>
<type>
- <v>Key = Text = iolist() | binary()</v>
- <v>IVec = Cipher = binary()</v>
+ <v>Name = binary()</v>
+ <v>VerNum = integer()</v>
+ <v>VerStr = binary()</v>
</type>
<desc>
- <p>Encrypts <c>Text</c> using Blowfish in OFB mode with 64 bit
- feedback. <c>Key</c> is the Blowfish key, and <c>IVec</c> is an
- arbitrary initializing vector. The length of <c>IVec</c>
- must be 64 bits (8 bytes).</p>
+ <p>Provides the name and version of the libraries used by crypto.</p>
+ <p><c>Name</c> is the name of the library. <c>VerNum</c> is
+ the numeric version according to the library's own versioning
+ scheme. <c>VerStr</c> contains a text variant of the version.</p>
+ <pre>
+> <input>info_lib().</input>
+[{&lt;&lt;"OpenSSL"&gt;&gt;,9469983,&lt;&lt;"OpenSSL 0.9.8a 11 Oct 2005"&gt;&gt;}]
+ </pre>
+ <note><p>
+ From OTP R16 the <em>numeric version</em> represents the version of the OpenSSL
+ <em>header files</em> (<c>openssl/opensslv.h</c>) used when crypto was compiled.
+ The text variant represents the OpenSSL library used at runtime.
+ In earlier OTP versions both numeric and text was taken from the library.
+ </p></note>
</desc>
</func>
<func>
- <name>aes_cfb_128_encrypt(Key, IVec, Text) -> Cipher</name>
- <fsummary>Encrypt <c>Text</c>according to AES in Cipher Feedback mode</fsummary>
- <type>
- <v>Key = Text = iolist() | binary()</v>
- <v>IVec = Cipher = binary()</v>
- </type>
- <desc>
- <p>Encrypts <c>Text</c> according to AES in Cipher Feedback
- mode (CFB). <c>Key</c> is the
- AES key, and <c>IVec</c> is an arbitrary initializing vector.
- The lengths of <c>Key</c> and <c>IVec</c> must be 128 bits
- (16 bytes).</p>
- </desc>
- </func>
- <func>
- <name>aes_cfb_128_decrypt(Key, IVec, Cipher) -> Text</name>
- <fsummary>Decrypt <c>Cipher</c>according to AES in Cipher Feedback mode</fsummary>
- <type>
- <v>Key = Cipher = iolist() | binary()</v>
- <v>IVec = Text = binary()</v>
- </type>
- <desc>
- <p>Decrypts <c>Cipher</c> according to AES in Cipher Feedback Mode (CFB).
- <c>Key</c> is the AES key, and <c>IVec</c> is an arbitrary
- initializing vector. <c>Key</c> and <c>IVec</c> must have
- the same values as those used when encrypting. The lengths of
- <c>Key</c> and <c>IVec</c> must be 128 bits (16 bytes).</p>
- </desc>
- </func>
- <func>
- <name>aes_cbc_128_encrypt(Key, IVec, Text) -> Cipher</name>
- <fsummary>Encrypt <c>Text</c>according to AES in Cipher Block Chaining mode</fsummary>
- <type>
- <v>Key = Text = iolist() | binary()</v>
- <v>IVec = Cipher = binary()</v>
- </type>
- <desc>
- <p>Encrypts <c>Text</c> according to AES in Cipher Block Chaining
- mode (CBC). <c>Text</c>
- must be a multiple of 128 bits (16 bytes). <c>Key</c> is the
- AES key, and <c>IVec</c> is an arbitrary initializing vector.
- The lengths of <c>Key</c> and <c>IVec</c> must be 128 bits
- (16 bytes).</p>
- </desc>
- </func>
- <func>
- <name>aes_cbc_128_decrypt(Key, IVec, Cipher) -> Text</name>
- <fsummary>Decrypt <c>Cipher</c>according to AES in Cipher Block Chaining mode</fsummary>
- <type>
- <v>Key = Cipher = iolist() | binary()</v>
- <v>IVec = Text = binary()</v>
- </type>
- <desc>
- <p>Decrypts <c>Cipher</c> according to AES in Cipher Block
- Chaining mode (CBC).
- <c>Key</c> is the AES key, and <c>IVec</c> is an arbitrary
- initializing vector. <c>Key</c> and <c>IVec</c> must have
- the same values as those used when encrypting. <c>Cipher</c>
- must be a multiple of 128 bits (16 bytes). The lengths of
- <c>Key</c> and <c>IVec</c> must be 128 bits (16 bytes).</p>
- </desc>
- </func>
- <func>
- <name>aes_cbc_ivec(Data) -> IVec</name>
- <fsummary>Get <c>IVec</c> to be used in next iteration of
- <c>aes_cbc_*_[ecrypt|decrypt]</c></fsummary>
- <type>
- <v>Data = iolist() | binary()</v>
- <v>IVec = binary()</v>
- </type>
- <desc>
- <p>Returns the <c>IVec</c> to be used in a next iteration of
- <c>aes_cbc_*_[encrypt|decrypt]</c>. <c>Data</c> is the encrypted
- data from the previous iteration step.</p>
- </desc>
- </func>
- <func>
- <name>aes_ctr_encrypt(Key, IVec, Text) -> Cipher</name>
- <fsummary>Encrypt <c>Text</c>according to AES in Counter mode</fsummary>
- <type>
- <v>Key = Text = iolist() | binary()</v>
- <v>IVec = Cipher = binary()</v>
- </type>
- <desc>
- <p>Encrypts <c>Text</c> according to AES in Counter mode (CTR). <c>Text</c>
- can be any number of bytes. <c>Key</c> is the AES key and must be either
- 128, 192 or 256 bits long. <c>IVec</c> is an arbitrary initializing vector of 128 bits
- (16 bytes).</p>
- </desc>
- </func>
- <func>
- <name>aes_ctr_decrypt(Key, IVec, Cipher) -> Text</name>
- <fsummary>Decrypt <c>Cipher</c>according to AES in Counter mode</fsummary>
- <type>
- <v>Key = Cipher = iolist() | binary()</v>
- <v>IVec = Text = binary()</v>
- </type>
- <desc>
- <p>Decrypts <c>Cipher</c> according to AES in Counter mode (CTR). <c>Cipher</c>
- can be any number of bytes. <c>Key</c> is the AES key and must be either
- 128, 192 or 256 bits long. <c>IVec</c> is an arbitrary initializing vector of 128 bits
- (16 bytes).</p>
- </desc>
- </func>
- <func>
- <name>aes_ctr_stream_init(Key, IVec) -> State</name>
- <fsummary></fsummary>
- <type>
- <v>State = { K, I, E, C }</v>
- <v>Key = K = iolist()</v>
- <v>IVec = I = E = binary()</v>
- <v>C = integer()</v>
- </type>
- <desc>
- <p>Initializes the state for use in streaming AES encryption using Counter mode (CTR).
- <c>Key</c> is the AES key and must be either 128, 192, or 256 bts long. <c>IVec</c> is
- an arbitrary initializing vector of 128 bits (16 bytes). This state is for use with
- <seealso marker="#aes_ctr_stream_encrypt/2">aes_ctr_stream_encrypt</seealso> and
- <seealso marker="#aes_ctr_stream_decrypt/2">aes_ctr_stream_decrypt</seealso>.</p>
- </desc>
- </func>
- <func>
- <name>aes_ctr_stream_encrypt(State, Text) -> { NewState, Cipher}</name>
- <fsummary></fsummary>
- <type>
- <v>Text = iolist() | binary()</v>
- <v>Cipher = binary()</v>
- </type>
- <desc>
- <p>Encrypts <c>Text</c> according to AES in Counter mode (CTR). This function can be
- used to encrypt a stream of text using a series of calls instead of requiring all
- text to be in memory. <c>Text</c> can be any number of bytes. State is initialized using
- <seealso marker="#aes_ctr_stream_init/2">aes_ctr_stream_init</seealso>. <c>NewState</c> is the new streaming
- encryption state that must be passed to the next call to <c>aes_ctr_stream_encrypt</c>.
- <c>Cipher</c> is the encrypted cipher text.</p>
- </desc>
- </func>
- <func>
- <name>aes_ctr_stream_decrypt(State, Cipher) -> { NewState, Text }</name>
- <fsummary></fsummary>
- <type>
- <v>Cipher = iolist() | binary()</v>
- <v>Text = binary()</v>
- </type>
- <desc>
- <p>Decrypts <c>Cipher</c> according to AES in Counter mode (CTR). This function can be
- used to decrypt a stream of ciphertext using a series of calls instead of requiring all
- ciphertext to be in memory. <c>Cipher</c> can be any number of bytes. State is initialized using
- <seealso marker="#aes_ctr_stream_init/2">aes_ctr_stream_init</seealso>. <c>NewState</c> is the new streaming
- encryption state that must be passed to the next call to <c>aes_ctr_stream_encrypt</c>.
- <c>Text</c> is the decrypted data.</p>
- </desc>
- </func>
- <func>
- <name>erlint(Mpint) -> N</name>
- <name>mpint(N) -> Mpint</name>
- <fsummary>Convert between binary multi-precision integer and erlang big integer</fsummary>
- <type>
- <v>Mpint = binary()</v>
- <v>N = integer()</v>
- </type>
- <desc>
- <p>Convert a binary multi-precision integer <c>Mpint</c> to and from
- an erlang big integer. A multi-precision integer is a binary
- with the following form:
- <c><![CDATA[<<ByteLen:32/integer, Bytes:ByteLen/binary>>]]></c> where both
- <c>ByteLen</c> and <c>Bytes</c> are big-endian. Mpints are used in
- some of the functions in <c>crypto</c> and are not translated
- in the API for performance reasons.</p>
- </desc>
- </func>
- <func>
- <name>rand_bytes(N) -> binary()</name>
- <fsummary>Generate a binary of random bytes</fsummary>
- <type>
- <v>N = integer()</v>
- </type>
- <desc>
- <p>Generates N bytes randomly uniform 0..255, and returns the
- result in a binary. Uses the <c>crypto</c> library pseudo-random
- number generator.</p>
- </desc>
- </func>
- <func>
- <name>strong_rand_bytes(N) -> binary()</name>
- <fsummary>Generate a binary of random bytes</fsummary>
- <type>
- <v>N = integer()</v>
- </type>
- <desc>
- <p>Generates N bytes randomly uniform 0..255, and returns the
- result in a binary. Uses a cryptographically secure prng seeded and
- periodically mixed with operating system provided entropy. By default
- this is the <c>RAND_bytes</c> method from OpenSSL.</p>
- <p>May throw exception <c>low_entropy</c> in case the random generator
- failed due to lack of secure "randomness".</p>
- </desc>
- </func>
- <func>
- <name>rand_uniform(Lo, Hi) -> N</name>
- <fsummary>Generate a random number</fsummary>
- <type>
- <v>Lo, Hi, N = Mpint | integer()</v>
- <v>Mpint = binary()</v>
- </type>
- <desc>
- <p>Generate a random number <c><![CDATA[N, Lo =< N < Hi.]]></c> Uses the
- <c>crypto</c> library pseudo-random number generator. The
- arguments (and result) can be either erlang integers or binary
- multi-precision integers. <c>Hi</c> must be larger than <c>Lo</c>.</p>
- </desc>
- </func>
- <func>
- <name>strong_rand_mpint(N, Top, Bottom) -> Mpint</name>
- <fsummary>Generate an N bit random number</fsummary>
- <type>
- <v>N = non_neg_integer()</v>
- <v>Top = -1 | 0 | 1</v>
- <v>Bottom = 0 | 1</v>
- <v>Mpint = binary()</v>
- </type>
- <desc>
- <p>Generate an N bit random number using OpenSSL's
- cryptographically strong pseudo random number generator
- <c>BN_rand</c>.</p>
- <p>The parameter <c>Top</c> places constraints on the most
- significant bits of the generated number. If <c>Top</c> is 1, then the
- two most significant bits will be set to 1, if <c>Top</c> is 0, the
- most significant bit will be 1, and if <c>Top</c> is -1 then no
- constraints are applied and thus the generated number may be less than
- N bits long.</p>
- <p>If <c>Bottom</c> is 1, then the generated number is
- constrained to be odd.</p>
- <p>May throw exception <c>low_entropy</c> in case the random generator
- failed due to lack of secure "randomness".</p>
- </desc>
- </func>
- <func>
- <name>mod_exp(N, P, M) -> Result</name>
- <fsummary>Perform N ^ P mod M</fsummary>
- <type>
- <v>N, P, M, Result = Mpint</v>
- <v>Mpint = binary()</v>
- </type>
- <desc>
- <p>This function performs the exponentiation <c>N ^ P mod M</c>,
- using the <c>crypto</c> library.</p>
- </desc>
- </func>
- <func>
- <name>mod_exp_prime(N, P, M) -> Result</name>
+ <name>mod_pow(N, P, M) -> Result</name>
<fsummary>Computes the function: N^P mod M</fsummary>
<type>
- <v>N, P, M = binary()</v>
+ <v>N, P, M = binary() | integer()</v>
<v>Result = binary() | error</v>
</type>
<desc>
<p>Computes the function <c>N^P mod M</c>.</p>
</desc>
</func>
- <func>
- <name>rsa_sign(DataOrDigest, Key) -> Signature</name>
- <name>rsa_sign(DigestType, DataOrDigest, Key) -> Signature</name>
- <fsummary>Sign the data using rsa with the given key.</fsummary>
- <type>
- <v>DataOrDigest = Data | {digest,Digest}</v>
- <v>Data = Mpint</v>
- <v>Digest = binary()</v>
- <v>Key = [E, N, D] | [E, N, D, P1, P2, E1, E2, C]</v>
- <v>E, N, D = Mpint</v>
- <d>Where <c>E</c> is the public exponent, <c>N</c> is public modulus and
- <c>D</c> is the private exponent.</d>
- <v>P1, P2, E1, E2, C = Mpint</v>
- <d>The longer key format contains redundant information that will make
- the calculation faster. <c>P1,P2</c> are first and second prime factors.
- <c>E1,E2</c> are first and second exponents. <c>C</c> is the CRT coefficient.
- Terminology is taken from RFC 3447.</d>
- <v>DigestType = md5 | sha | sha224 | sha256 | sha384 | sha512</v>
- <d>The default <c>DigestType</c> is sha.</d>
- <v>Mpint = binary()</v>
- <v>Signature = binary()</v>
- </type>
- <desc>
- <p>Creates a RSA signature with the private key <c>Key</c>
- of a digest. The digest is either calculated as a
- <c>DigestType</c> digest of <c>Data</c> or a precalculated
- binary <c>Digest</c>.</p>
- </desc>
- </func>
<func>
- <name>rsa_verify(DataOrDigest, Signature, Key) -> Verified</name>
- <name>rsa_verify(DigestType, DataOrDigest, Signature, Key) -> Verified </name>
- <fsummary>Verify the digest and signature using rsa with given public key.</fsummary>
- <type>
- <v>Verified = boolean()</v>
- <v>DataOrDigest = Data | {digest|Digest}</v>
- <v>Data, Signature = Mpint</v>
- <v>Digest = binary()</v>
- <v>Key = [E, N]</v>
- <v>E, N = Mpint</v>
- <d>Where <c>E</c> is the public exponent and <c>N</c> is public modulus.</d>
- <v>DigestType = md5 | sha | sha224 | sha256 | sha384 | sha512</v>
- <d>The default <c>DigestType</c> is sha.</d>
- <v>Mpint = binary()</v>
- </type>
- <desc>
- <p>Verifies that a digest matches the RSA signature using the
- signer's public key <c>Key</c>.
- The digest is either calculated as a <c>DigestType</c>
- digest of <c>Data</c> or a precalculated binary <c>Digest</c>.</p>
- <p>May throw exception <c>notsup</c> in case the chosen <c>DigestType</c>
- is not supported by the underlying OpenSSL implementation.</p>
- </desc>
- </func>
-
- <func>
- <name>rsa_public_encrypt(PlainText, PublicKey, Padding) -> ChipherText</name>
- <fsummary>Encrypts Msg using the public Key.</fsummary>
- <type>
- <v>PlainText = binary()</v>
- <v>PublicKey = [E, N]</v>
- <v>E, N = Mpint</v>
- <d>Where <c>E</c> is the public exponent and <c>N</c> is public modulus.</d>
- <v>Padding = rsa_pkcs1_padding | rsa_pkcs1_oaep_padding | rsa_no_padding</v>
- <v>ChipherText = binary()</v>
- </type>
- <desc>
- <p>Encrypts the <c>PlainText</c> (usually a session key) using the <c>PublicKey</c>
- and returns the cipher. The <c>Padding</c> decides what padding mode is used,
- <c>rsa_pkcs1_padding</c> is PKCS #1 v1.5 currently the most
- used mode and <c>rsa_pkcs1_oaep_padding</c> is EME-OAEP as
- defined in PKCS #1 v2.0 with SHA-1, MGF1 and an empty encoding
- parameter. This mode is recommended for all new applications.
- The size of the <c>Msg</c> must be less
- than <c>byte_size(N)-11</c> if
- <c>rsa_pkcs1_padding</c> is used, <c>byte_size(N)-41</c> if
- <c>rsa_pkcs1_oaep_padding</c> is used and <c>byte_size(N)</c> if <c>rsa_no_padding</c>
- is used.
- Where byte_size(N) is the size part of an <c>Mpint-1</c>.
- </p>
- </desc>
+ <name>next_iv(Type, Data) -> </name>
+ <fsummary></fsummary>
+ <type>
+ <v>Type = des_cbc | aes_cbc</v>
+ <v>Data = iodata()</v>
+ </type>
+ <desc>
+ <p>Returns the initialization vector to be used in the next
+ iteration of encrypt/decrypt of type <c>Type</c>. Data is the
+ encrypted data from the previous iteration step.</p>
+ </desc>
</func>
<func>
- <name>rsa_private_decrypt(ChipherText, PrivateKey, Padding) -> PlainText</name>
+ <name>private_decrypt(Type, ChipherText, PrivateKey, Padding) -> PlainText</name>
<fsummary>Decrypts ChipherText using the private Key.</fsummary>
<type>
+ <v>Type = rsa</v>
<v>ChipherText = binary()</v>
- <v>PrivateKey = [E, N, D] | [E, N, D, P1, P2, E1, E2, C]</v>
- <v>E, N, D = Mpint</v>
- <d>Where <c>E</c> is the public exponent, <c>N</c> is public modulus and
- <c>D</c> is the private exponent.</d>
- <v>P1, P2, E1, E2, C = Mpint</v>
- <d>The longer key format contains redundant information that will make
- the calculation faster. <c>P1,P2</c> are first and second prime factors.
- <c>E1,E2</c> are first and second exponents. <c>C</c> is the CRT coefficient.
- Terminology is taken from RFC 3447.</d>
+ <v>PrivateKey = rsa_private()</v>
<v>Padding = rsa_pkcs1_padding | rsa_pkcs1_oaep_padding | rsa_no_padding</v>
<v>PlainText = binary()</v>
</type>
<desc>
- <p>Decrypts the <c>ChipherText</c> (usually a session key encrypted with
- <seealso marker="#rsa_public_encrypt/3">rsa_public_encrypt/3</seealso>)
+ <p>Decrypts the <c>ChipherText</c> (usually a session key encrypted with
+ <seealso marker="#public_encrypt/3">public_encrypt/3</seealso>)
using the <c>PrivateKey</c> and returns the
message. The <c>Padding</c> is the padding mode that was
- used to encrypt the data,
- see <seealso marker="#rsa_public_encrypt/3">rsa_public_encrypt/3</seealso>.
+ used to encrypt the data,
+ see <seealso marker="#public_encrypt/3">public_encrypt/3</seealso>.
+ See also <seealso marker="public_key:public_key#decrypt_private/2">public_key:decrypt_private/[2,3]</seealso>
</p>
</desc>
</func>
+
<func>
- <name>rsa_private_encrypt(PlainText, PrivateKey, Padding) -> ChipherText</name>
+ <name>private_encrypt(Type, PlainText, PrivateKey, Padding) -> ChipherText</name>
<fsummary>Encrypts Msg using the private Key.</fsummary>
<type>
+ <v>Type = rsa</v>
<v>PlainText = binary()</v>
- <v>PrivateKey = [E, N, D] | [E, N, D, P1, P2, E1, E2, C]</v>
- <v>E, N, D = Mpint</v>
- <d>Where <c>E</c> is the public exponent, <c>N</c> is public modulus and
- <c>D</c> is the private exponent.</d>
- <v>P1, P2, E1, E2, C = Mpint</v>
- <d>The longer key format contains redundant information that will make
- the calculation faster. <c>P1,P2</c> are first and second prime factors.
- <c>E1,E2</c> are first and second exponents. <c>C</c> is the CRT coefficient.
- Terminology is taken from RFC 3447.</d>
+ <v>PrivateKey = rsa_private()</v>
<v>Padding = rsa_pkcs1_padding | rsa_no_padding</v>
<v>ChipherText = binary()</v>
</type>
@@ -1131,316 +458,289 @@ Mpint() = <![CDATA[<<ByteLen:32/integer-big, Bytes:ByteLen/binary>>]]>
<c>rsa_pkcs1_padding</c> is PKCS #1 v1.5 currently the most
used mode.
The size of the <c>Msg</c> must be less than <c>byte_size(N)-11</c> if
- <c>rsa_pkcs1_padding</c> is used, and <c>byte_size(N)</c> if <c>rsa_no_padding</c>
- is used. Where byte_size(N) is the size part of an <c>Mpint-1</c>.
+ <c>rsa_pkcs1_padding</c> is used, and <c>byte_size(N)</c> if <c>rsa_no_padding</c>
+ is used.
+ See also <seealso marker="public_key:public_key#encrypt_private/2">public_key:encrypt_private/[2,3]</seealso>
</p>
</desc>
</func>
-
<func>
- <name>rsa_public_decrypt(ChipherText, PublicKey, Padding) -> PlainText</name>
+ <name>public_decrypt(Type, ChipherText, PublicKey, Padding) -> PlainText</name>
<fsummary>Decrypts ChipherText using the public Key.</fsummary>
<type>
+ <v>Type = rsa</v>
<v>ChipherText = binary()</v>
- <v>PublicKey = [E, N]</v>
- <v>E, N = Mpint</v>
- <d>Where <c>E</c> is the public exponent and <c>N</c> is public modulus</d>
+ <v>PublicKey = rsa_public() </v>
<v>Padding = rsa_pkcs1_padding | rsa_no_padding</v>
<v>PlainText = binary()</v>
</type>
<desc>
- <p>Decrypts the <c>ChipherText</c> (encrypted with
- <seealso marker="#rsa_private_encrypt/3">rsa_private_encrypt/3</seealso>)
+ <p>Decrypts the <c>ChipherText</c> (encrypted with
+ <seealso marker="#private_encrypt/3">private_encrypt/3</seealso>)
using the <c>PrivateKey</c> and returns the
message. The <c>Padding</c> is the padding mode that was
- used to encrypt the data,
- see <seealso marker="#rsa_private_encrypt/3">rsa_private_encrypt/3</seealso>.
+ used to encrypt the data,
+ see <seealso marker="#private_encrypt/3">private_encrypt/3</seealso>.
+ See also <seealso marker="public_key:public_key#decrypt_public/2">public_key:decrypt_public/[2,3]</seealso>
</p>
</desc>
</func>
-
+
<func>
- <name>dss_sign(DataOrDigest, Key) -> Signature</name>
- <name>dss_sign(DigestType, DataOrDigest, Key) -> Signature</name>
- <fsummary>Sign the data using dsa with given private key.</fsummary>
+ <name>public_encrypt(Type, PlainText, PublicKey, Padding) -> ChipherText</name>
+ <fsummary>Encrypts Msg using the public Key.</fsummary>
<type>
- <v>DigestType = sha</v>
- <v>DataOrDigest = Mpint | {digest,Digest}</v>
- <v>Key = [P, Q, G, X]</v>
- <v>P, Q, G, X = Mpint</v>
- <d> Where <c>P</c>, <c>Q</c> and <c>G</c> are the dss
- parameters and <c>X</c> is the private key.</d>
- <v>Digest = binary() with length 20 bytes</v>
- <v>Signature = binary()</v>
+ <v>Type = rsa</v>
+ <v>PlainText = binary()</v>
+ <v>PublicKey = rsa_public()</v>
+ <v>Padding = rsa_pkcs1_padding | rsa_pkcs1_oaep_padding | rsa_no_padding</v>
+ <v>ChipherText = binary()</v>
</type>
<desc>
- <p>Creates a DSS signature with the private key <c>Key</c> of
- a digest. The digest is either calculated as a SHA1
- digest of <c>Data</c> or a precalculated binary <c>Digest</c>.</p>
- <p>A deprecated feature is having <c>DigestType = 'none'</c>
- in which case <c>DataOrDigest</c> is a precalculated SHA1
- digest.</p>
+ <p>Encrypts the <c>PlainText</c> (usually a session key) using the <c>PublicKey</c>
+ and returns the <c>CipherText</c>. The <c>Padding</c> decides what padding mode is used,
+ <c>rsa_pkcs1_padding</c> is PKCS #1 v1.5 currently the most
+ used mode and <c>rsa_pkcs1_oaep_padding</c> is EME-OAEP as
+ defined in PKCS #1 v2.0 with SHA-1, MGF1 and an empty encoding
+ parameter. This mode is recommended for all new applications.
+ The size of the <c>Msg</c> must be less
+ than <c>byte_size(N)-11</c> if
+ <c>rsa_pkcs1_padding</c> is used, <c>byte_size(N)-41</c> if
+ <c>rsa_pkcs1_oaep_padding</c> is used and <c>byte_size(N)</c> if <c>rsa_no_padding</c>
+ is used.
+ See also <seealso marker="public_key:public_key#encrypt_public/2">public_key:encrypt_public/[2,3]</seealso>
+ </p>
</desc>
</func>
<func>
- <name>dss_verify(DataOrDigest, Signature, Key) -> Verified</name>
- <name>dss_verify(DigestType, DataOrDigest, Signature, Key) -> Verified</name>
- <fsummary>Verify the data and signature using dsa with given public key.</fsummary>
+ <name>rand_bytes(N) -> binary()</name>
+ <fsummary>Generate a binary of random bytes</fsummary>
<type>
- <v>Verified = boolean()</v>
- <v>DigestType = sha</v>
- <v>DataOrDigest = Mpint | {digest,Digest}</v>
- <v>Data = Mpint | ShaDigest</v>
- <v>Signature = Mpint</v>
- <v>Key = [P, Q, G, Y]</v>
- <v>P, Q, G, Y = Mpint</v>
- <d> Where <c>P</c>, <c>Q</c> and <c>G</c> are the dss
- parameters and <c>Y</c> is the public key.</d>
- <v>Digest = binary() with length 20 bytes</v>
+ <v>N = integer()</v>
</type>
<desc>
- <p>Verifies that a digest matches the DSS signature using the
- public key <c>Key</c>. The digest is either calculated as a SHA1
- digest of <c>Data</c> or is a precalculated binary <c>Digest</c>.</p>
- <p>A deprecated feature is having <c>DigestType = 'none'</c>
- in which case <c>DataOrDigest</c> is a precalculated SHA1
- digest binary.</p>
+ <p>Generates N bytes randomly uniform 0..255, and returns the
+ result in a binary. Uses the <c>crypto</c> library pseudo-random
+ number generator.</p>
</desc>
</func>
- <func>
- <name>rc2_cbc_encrypt(Key, IVec, Text) -> Cipher</name>
- <fsummary>Encrypt <c>Text</c>according to RC2 in CBC mode</fsummary>
+ <func>
+ <name>rand_uniform(Lo, Hi) -> N</name>
+ <fsummary>Generate a random number</fsummary>
<type>
- <v>Key = Text = iolist() | binary()</v>
- <v>Ivec = Cipher = binary()</v>
+ <v>Lo, Hi, N = integer()</v>
</type>
<desc>
- <p>Encrypts <c>Text</c> according to RC2 in CBC mode.</p>
+ <p>Generate a random number <c><![CDATA[N, Lo =< N < Hi.]]></c> Uses the
+ <c>crypto</c> library pseudo-random number generator.
+ <c>Hi</c> must be larger than <c>Lo</c>.</p>
</desc>
</func>
<func>
- <name>rc2_cbc_decrypt(Key, IVec, Cipher) -> Text</name>
- <fsummary>Decrypts <c>Cipher</c>according to RC2 in CBC mode</fsummary>
+ <name>sign(Algorithm, DigestType, Msg, Key) -> binary()</name>
+ <fsummary> Create digital signature.</fsummary>
<type>
- <v>Key = Text = iolist() | binary()</v>
- <v>Ivec = Cipher = binary()</v>
+ <v>Algorithm = rsa | dss | ecdsa </v>
+ <v>Msg = binary() | {digest,binary()}</v>
+ <d>The msg is either the binary "plain text" data to be
+ signed or it is the hashed value of "plain text" i.e. the
+ digest.</d>
+ <v>DigestType = digest_type()</v>
+ <v>Key = rsa_private_key() | dsa_private_key() | ec_private_key()</v>
</type>
<desc>
- <p>Decrypts <c>Cipher</c> according to RC2 in CBC mode.</p>
+ <p> Creates a digital signature.</p>
+ See also <seealso marker="public_key:public_key#sign/3">public_key:sign/3</seealso>
</desc>
</func>
-
+
<func>
- <name>rc4_encrypt(Key, Data) -> Result</name>
- <fsummary>Encrypt data using RC4</fsummary>
+ <name>start() -> ok</name>
+ <fsummary> Equivalent to application:start(crypto). </fsummary>
+ <desc>
+ <p> Equivalent to application:start(crypto).</p>
+ </desc>
+ </func>
+ <func>
+ <name>stop() -> ok</name>
+ <fsummary> Equivalent to application:stop(crypto).</fsummary>
+ <desc>
+ <p> Equivalent to application:stop(crypto).</p>
+ </desc>
+ </func>
+
+ <func>
+ <name>strong_rand_bytes(N) -> binary()</name>
+ <fsummary>Generate a binary of random bytes</fsummary>
<type>
- <v>Key, Data = iolist() | binary()</v>
- <v>Result = binary()</v>
+ <v>N = integer()</v>
</type>
<desc>
- <p>Encrypts the data with RC4 symmetric stream encryption.
- Since it is symmetric, the same function is used for
- decryption.</p>
+ <p>Generates N bytes randomly uniform 0..255, and returns the
+ result in a binary. Uses a cryptographically secure prng seeded and
+ periodically mixed with operating system provided entropy. By default
+ this is the <c>RAND_bytes</c> method from OpenSSL.</p>
+ <p>May throw exception <c>low_entropy</c> in case the random generator
+ failed due to lack of secure "randomness".</p>
</desc>
</func>
-
<func>
- <name>dh_generate_key(DHParams) -> {PublicKey,PrivateKey} </name>
- <name>dh_generate_key(PrivateKey, DHParams) -> {PublicKey,PrivateKey} </name>
- <fsummary>Generates a Diffie-Hellman public key</fsummary>
+ <name>stream_init(Type, Key) -> State</name>
+ <fsummary></fsummary>
<type>
- <v>DHParameters = [P, G]</v>
- <v>P, G = Mpint</v>
- <d> Where <c>P</c> is the shared prime number and <c>G</c> is the shared generator.</d>
- <v>PublicKey, PrivateKey = Mpint()</v>
+ <v>Type rc4 </v>
+ <v>State = opaque() </v>
+ <v>Key = iodata()</v>
+ <v>IVec = binary()</v>
</type>
<desc>
- <p>Generates a Diffie-Hellman <c>PublicKey</c> and <c>PrivateKey</c> (if not given).
- </p>
+ <p>Initializes the state for use in RC4 stream encryption
+ <seealso marker="#stream_encrypt/2">stream_encrypt</seealso> and
+ <seealso marker="#stream_decrypt/2">stream_decrypt</seealso></p>
</desc>
</func>
- <func>
- <name>dh_compute_key(OthersPublicKey, MyPrivateKey, DHParams) -> SharedSecret</name>
- <fsummary>Computes the shared secret</fsummary>
+ <func>
+ <name>stream_init(Type, Key, IVec) -> State</name>
+ <fsummary></fsummary>
<type>
- <v>DHParameters = [P, G]</v>
- <v>P, G = Mpint</v>
- <d> Where <c>P</c> is the shared prime number and <c>G</c> is the shared generator.</d>
- <v>OthersPublicKey, MyPrivateKey = Mpint()</v>
- <v>SharedSecret = binary()</v>
+ <v>Type aes_ctr </v>
+ <v>State = opaque() </v>
+ <v>Key = iodata()</v>
+ <v>IVec = binary()</v>
</type>
<desc>
- <p>Computes the shared secret from the private key and the other party's public key.
- </p>
+ <p>Initializes the state for use in streaming AES encryption using Counter mode (CTR).
+ <c>Key</c> is the AES key and must be either 128, 192, or 256 bts long. <c>IVec</c> is
+ an arbitrary initializing vector of 128 bits (16 bytes). This state is for use with
+ <seealso marker="#stream_encrypt/2">stream_encrypt</seealso> and
+ <seealso marker="#stream_decrypt/2">stream_decrypt</seealso>.</p>
</desc>
</func>
-
+
<func>
- <name>srp_generate_key(Generator, Prime, Version) -> {PublicKey, PrivateKey} </name>
- <name>srp_generate_key(Generator, Prime, Version, Private) -> {PublicKey, PrivateKey} </name>
- <name>srp_generate_key(Verifier, Generator, Prime, Version) -> {PublicKey, PrivateKey} </name>
- <name>srp_generate_key(Verifier, Generator, Prime, Version, Private) -> {PublicKey, PrivateKey} </name>
- <fsummary>Generates SRP public keys</fsummary>
+ <name>stream_encrypt(State, PlainText) -> { NewState, CipherText}</name>
+ <fsummary></fsummary>
<type>
- <v>Verifier = binary()</v>
- <d>Parameter v from <url href="http://srp.stanford.edu/design.html">SRP design</url>
- </d>
- <v>Generator = binary() </v>
- <d>Parameter g from <url href="http://srp.stanford.edu/design.html">SRP design</url>
- </d>
- <v>Prime = binary() </v>
- <d>Parameter N from <url href="http://srp.stanford.edu/design.html">SRP design</url>
- </d>
- <v>Version = '3' | '6' | '6a' </v>
- <d>SRP version, TLS SRP cipher suites uses '6a'.</d>
- <v>PublicKey = binary()</v>
- <d> Parameter A or B from <url href="http://srp.stanford.edu/design.html">SRP design</url></d>
- <v>Private = PrivateKey = binary() - generated if not supplied</v>
- <d>Parameter a or b from <url href="http://srp.stanford.edu/design.html">SRP design</url></d>
+ <v>Text = iodata()</v>
+ <v>CipherText = binary()</v>
</type>
<desc>
- <p>Generates SRP public keys for the client side (first argument is Generator)
- or for the server side (first argument is Verifier).</p>
+ <p>Encrypts <c>PlainText</c> according to the stream cipher <c>Type</c> specified in stream_init/3.
+ <c>Text</c> can be any number of bytes. The initial <c>State</c> is created using
+ <seealso marker="#stream_init/2">stream_init</seealso>.
+ <c>NewState</c> must be passed into the next call to <c>stream_encrypt</c>.</p>
</desc>
</func>
<func>
- <name>srp_compute_key(DerivedKey, Prime, Generator,
- ClientPublic, ClientPrivate, ServerPublic, Version) -> SessionKey</name>
- <name>srp_compute_key(DerivedKey, Prime, Generator,
- ClientPublic, ClientPrivate, ServerPublic, Version, Scrambler) -> SessionKey</name>
- <name>srp_compute_key(Verifier, Prime,
- ClientPublic, ServerPublic, ServerPrivate, Version, Scrambler)-> SessionKey</name>
- <name>srp_compute_key(Verifier, Prime,
- ClientPublic, ServerPublic, ServerPrivate, Version) -> SessionKey</name>
-
- <fsummary>Computes SRP session key</fsummary>
+ <name>stream_decrypt(State, CipherText) -> { NewState, PlainText }</name>
+ <fsummary></fsummary>
<type>
- <v>DerivedKey = binary()</v>
- <d>Parameter x from <url href="http://srp.stanford.edu/design.html">SRP design</url>
- </d>
- <v>Verifier = binary()</v>
- <d>Parameter v from <url href="http://srp.stanford.edu/design.html">SRP design</url>
- </d>
- <v>Prime = binary() </v>
- <d>Parameter N from <url href="http://srp.stanford.edu/design.html">SRP design</url>
- </d>
- <v>Generator = binary() </v>
- <d>Parameter g from <url href="http://srp.stanford.edu/design.html">SRP design</url>
- </d>
- <v>ClientPublic = binary() </v>
- <d>Parameter A from <url href="http://srp.stanford.edu/design.html">SRP design</url>
- </d>
- <v>ClientPrivate = binary() </v>
- <d>Parameter a from <url href="http://srp.stanford.edu/design.html">SRP design</url>
- </d>
- <v>ServerPublic = binary() </v>
- <d>Parameter B from <url href="http://srp.stanford.edu/design.html">SRP design</url>
- </d>
- <v>ServerPrivate = binary() </v>
- <d>Parameter b from <url href="http://srp.stanford.edu/design.html">SRP design</url>
- </d>
- <v>Version = '3' | '6' | '6a' </v>
- <d>SRP version, TLS SRP cipher suites uses '6a'.</d>
- <v>SessionKey = binary()</v>
- <d>Result K from <url href="http://srp.stanford.edu/design.html">SRP design</url>
- </d>
+ <v>CipherText = iodata()</v>
+ <v>PlainText = binary()</v>
</type>
<desc>
- <p>
- Computes the SRP session key (shared secret) for the client side (first argument is DerivedKey)
- or for the server side (first argument is Verifier). Also used
- as premaster secret by TLS-SRP ciher suites.
- </p>
+ <p>Decrypts <c>CipherText</c> according to the stream cipher <c>Type</c> specified in stream_init/3.
+ <c>PlainText</c> can be any number of bytes. The initial <c>State</c> is created using
+ <seealso marker="#stream_init/2">stream_init</seealso>.
+ <c>NewState</c> must be passed into the next call to <c>stream_encrypt</c>.</p>
</desc>
</func>
-
- <func>
- <name>exor(Data1, Data2) -> Result</name>
- <fsummary>XOR data</fsummary>
+
+ <func>
+ <name>verify(Algorithm, DigestType, Msg, Signature, Key) -> boolean()</name>
+ <fsummary>Verifies a digital signature.</fsummary>
<type>
- <v>Data1, Data2 = iolist() | binary()</v>
- <v>Result = binary()</v>
+ <v> Algorithm = rsa | dss | ecdsa </v>
+ <v>Msg = binary() | {digest,binary()}</v>
+ <d>The msg is either the binary "plain text" data
+ or it is the hashed value of "plain text" i.e. the digest.</d>
+ <v>DigestType = digest_type()</v>
+ <v>Signature = binary()</v>
+ <v>Key = rsa_public_key() | dsa_public_key() | ec_public_key()</v>
</type>
<desc>
- <p>Performs bit-wise XOR (exclusive or) on the data supplied.</p>
+ <p>Verifies a digital signature</p>
+ See also <seealso marker="public_key:public_key#sign/3">public_key:verify/3</seealso>
</desc>
</func>
- </funcs>
- <section>
- <title>DES in CBC mode</title>
- <p>The Data Encryption Standard (DES) defines an algorithm for
- encrypting and decrypting an 8 byte quantity using an 8 byte key
- (actually only 56 bits of the key is used).
- </p>
- <p>When it comes to encrypting and decrypting blocks that are
- multiples of 8 bytes various modes are defined (NIST SP
- 800-38A). One of those modes is the Cipher Block Chaining (CBC)
- mode, where the encryption of an 8 byte segment depend not only
- of the contents of the segment itself, but also on the result of
- encrypting the previous segment: the encryption of the previous
- segment becomes the initializing vector of the encryption of the
- current segment.
- </p>
- <p>Thus the encryption of every segment depends on the encryption
- key (which is secret) and the encryption of the previous
- segment, except the first segment which has to be provided with
- an initial initializing vector. That vector could be chosen at
- random, or be a counter of some kind. It does not have to be
- secret.
- </p>
- <p>The following example is drawn from the old FIPS 81 standard
- (replaced by NIST SP 800-38A), where both the plain text and the
- resulting cipher text is settled. The following code fragment
- returns `true'.
- </p>
- <pre><![CDATA[
-
- Key = <<16#01,16#23,16#45,16#67,16#89,16#ab,16#cd,16#ef>>,
- IVec = <<16#12,16#34,16#56,16#78,16#90,16#ab,16#cd,16#ef>>,
- P = "Now is the time for all ",
- C = crypto:des_cbc_encrypt(Key, IVec, P),
- % Which is the same as
- P1 = "Now is t", P2 = "he time ", P3 = "for all ",
- C1 = crypto:des_cbc_encrypt(Key, IVec, P1),
- C2 = crypto:des_cbc_encrypt(Key, C1, P2),
- C3 = crypto:des_cbc_encrypt(Key, C2, P3),
-
- C = <<C1/binary, C2/binary, C3/binary>>,
- C = <<16#e5,16#c7,16#cd,16#de,16#87,16#2b,16#f2,16#7c,
- 16#43,16#e9,16#34,16#00,16#8c,16#38,16#9c,16#0f,
- 16#68,16#37,16#88,16#49,16#9a,16#7c,16#05,16#f6>>,
- <<"Now is the time for all ">> ==
- crypto:des_cbc_decrypt(Key, IVec, C).
- ]]></pre>
- <p>The following is true for the DES CBC mode. For all
- decompositions <c>P1 ++ P2 = P</c> of a plain text message
- <c>P</c> (where the length of all quantities are multiples of 8
- bytes), the encryption <c>C</c> of <c>P</c> is equal to <c>C1 ++
- C2</c>, where <c>C1</c> is obtained by encrypting <c>P1</c> with
- <c>Key</c> and the initializing vector <c>IVec</c>, and where
- <c>C2</c> is obtained by encrypting <c>P2</c> with <c>Key</c>
- and the initializing vector <c>last8(C1)</c>,
- where <c>last(Binary)</c> denotes the last 8 bytes of the
- binary <c>Binary</c>.
- </p>
- <p>Similarly, for all decompositions <c>C1 ++ C2 = C</c> of a
- cipher text message <c>C</c> (where the length of all quantities
- are multiples of 8 bytes), the decryption <c>P</c> of <c>C</c>
- is equal to <c>P1 ++ P2</c>, where <c>P1</c> is obtained by
- decrypting <c>C1</c> with <c>Key</c> and the initializing vector
- <c>IVec</c>, and where <c>P2</c> is obtained by decrypting
- <c>C2</c> with <c>Key</c> and the initializing vector
- <c>last8(C1)</c>, where <c>last8(Binary)</c> is as above.
- </p>
- <p>For DES3 (which uses three 64 bit keys) the situation is the
- same.
- </p>
- </section>
+ </funcs>
+
+ <!-- Maybe put this in the users guide -->
+ <!-- <section> -->
+ <!-- <title>DES in CBC mode</title> -->
+ <!-- <p>The Data Encryption Standard (DES) defines an algorithm for -->
+ <!-- encrypting and decrypting an 8 byte quantity using an 8 byte key -->
+ <!-- (actually only 56 bits of the key is used). -->
+ <!-- </p> -->
+ <!-- <p>When it comes to encrypting and decrypting blocks that are -->
+ <!-- multiples of 8 bytes various modes are defined (NIST SP -->
+ <!-- 800-38A). One of those modes is the Cipher Block Chaining (CBC) -->
+ <!-- mode, where the encryption of an 8 byte segment depend not only -->
+ <!-- of the contents of the segment itself, but also on the result of -->
+ <!-- encrypting the previous segment: the encryption of the previous -->
+ <!-- segment becomes the initializing vector of the encryption of the -->
+ <!-- current segment. -->
+ <!-- </p> -->
+ <!-- <p>Thus the encryption of every segment depends on the encryption -->
+ <!-- key (which is secret) and the encryption of the previous -->
+ <!-- segment, except the first segment which has to be provided with -->
+ <!-- an initial initializing vector. That vector could be chosen at -->
+ <!-- random, or be a counter of some kind. It does not have to be -->
+ <!-- secret. -->
+ <!-- </p> -->
+ <!-- <p>The following example is drawn from the old FIPS 81 standard -->
+ <!-- (replaced by NIST SP 800-38A), where both the plain text and the -->
+ <!-- resulting cipher text is settled. The following code fragment -->
+ <!-- returns `true'. -->
+ <!-- </p> -->
+ <!-- <pre><![CDATA[ -->
+
+ <!-- Key = <<16#01,16#23,16#45,16#67,16#89,16#ab,16#cd,16#ef>>, -->
+ <!-- IVec = <<16#12,16#34,16#56,16#78,16#90,16#ab,16#cd,16#ef>>, -->
+ <!-- P = "Now is the time for all ", -->
+ <!-- C = crypto:des_cbc_encrypt(Key, IVec, P), -->
+ <!-- % Which is the same as -->
+ <!-- P1 = "Now is t", P2 = "he time ", P3 = "for all ", -->
+ <!-- C1 = crypto:des_cbc_encrypt(Key, IVec, P1), -->
+ <!-- C2 = crypto:des_cbc_encrypt(Key, C1, P2), -->
+ <!-- C3 = crypto:des_cbc_encrypt(Key, C2, P3), -->
+
+ <!-- C = <<C1/binary, C2/binary, C3/binary>>, -->
+ <!-- C = <<16#e5,16#c7,16#cd,16#de,16#87,16#2b,16#f2,16#7c, -->
+ <!-- 16#43,16#e9,16#34,16#00,16#8c,16#38,16#9c,16#0f, -->
+ <!-- 16#68,16#37,16#88,16#49,16#9a,16#7c,16#05,16#f6>>, -->
+ <!-- <<"Now is the time for all ">> == -->
+ <!-- crypto:des_cbc_decrypt(Key, IVec, C). -->
+ <!-- ]]></pre> -->
+ <!-- <p>The following is true for the DES CBC mode. For all -->
+ <!-- decompositions <c>P1 ++ P2 = P</c> of a plain text message -->
+ <!-- <c>P</c> (where the length of all quantities are multiples of 8 -->
+ <!-- bytes), the encryption <c>C</c> of <c>P</c> is equal to <c>C1 ++ -->
+ <!-- C2</c>, where <c>C1</c> is obtained by encrypting <c>P1</c> with -->
+ <!-- <c>Key</c> and the initializing vector <c>IVec</c>, and where -->
+ <!-- <c>C2</c> is obtained by encrypting <c>P2</c> with <c>Key</c> -->
+ <!-- and the initializing vector <c>last8(C1)</c>, -->
+ <!-- where <c>last(Binary)</c> denotes the last 8 bytes of the -->
+ <!-- binary <c>Binary</c>. -->
+ <!-- </p> -->
+ <!-- <p>Similarly, for all decompositions <c>C1 ++ C2 = C</c> of a -->
+ <!-- cipher text message <c>C</c> (where the length of all quantities -->
+ <!-- are multiples of 8 bytes), the decryption <c>P</c> of <c>C</c> -->
+ <!-- is equal to <c>P1 ++ P2</c>, where <c>P1</c> is obtained by -->
+ <!-- decrypting <c>C1</c> with <c>Key</c> and the initializing vector -->
+ <!-- <c>IVec</c>, and where <c>P2</c> is obtained by decrypting -->
+ <!-- <c>C2</c> with <c>Key</c> and the initializing vector -->
+ <!-- <c>last8(C1)</c>, where <c>last8(Binary)</c> is as above. -->
+ <!-- </p> -->
+ <!-- <p>For DES3 (which uses three 64 bit keys) the situation is the -->
+ <!-- same. -->
+ <!-- </p> -->
+ <!-- </section> -->
</erlref>
diff --git a/lib/crypto/doc/src/crypto_app.xml b/lib/crypto/doc/src/crypto_app.xml
index 8371db1ff2..6d26076c04 100644
--- a/lib/crypto/doc/src/crypto_app.xml
+++ b/lib/crypto/doc/src/crypto_app.xml
@@ -1,4 +1,4 @@
-<?xml version="1.0" encoding="latin1" ?>
+<?xml version="1.0" encoding="iso-8859-1" ?>
<!DOCTYPE appref SYSTEM "appref.dtd">
<appref>
@@ -24,81 +24,28 @@
</legalnotice>
<title>crypto</title>
- <prepared>Peter H&ouml;gfeldt</prepared>
- <responsible>Peter H&ouml;gfeldt</responsible>
- <docno></docno>
- <approved>Peter H&ouml;gfeldt</approved>
- <checked>Peter H&ouml;gfeldt</checked>
- <date>2003-06-01</date>
- <rev>B</rev>
<file>crypto_app.sgml</file>
</header>
<app>crypto</app>
<appsummary>The Crypto Application</appsummary>
<description>
- <p>The purpose of the Crypto application is to provide message
- digest and DES encryption for SMNPv3. It provides computation of
- message digests MD5 and SHA, and CBC-DES encryption and
- decryption.</p>
- <p></p>
+ <p>The purpose of the Crypto application is to provide an Erlang API
+ to cryptographic functions, see <seealso marker="crypto">crypto(3)</seealso>.
+ Note that the API is on a fairly low level and there are some
+ corresponding API functions available in <seealso marker="public_key:public_key">public_key(3)</seealso>,
+ on a higher abstraction level, that uses the crypto application in its implementation.
+ </p>
</description>
<section>
- <title>Configuration</title>
- <p>The following environment configuration parameters are defined
- for the Crypto application. Refer to application(3) for more
- information about configuration parameters.
- </p>
- <taglist>
- <tag><c><![CDATA[debug = true | false <optional>]]></c></tag>
- <item>
- <p>Causes debug information to be written to standard
- error or standard output. Default is <c>false</c>.
- </p>
- </item>
- </taglist>
- </section>
+ <title>DEPENDENCIES</title>
- <section>
- <title>OpenSSL libraries</title>
- <p>The current implementation of the Erlang Crypto application is
- based on the <em>OpenSSL</em> package version 0.9.8 or higher.
- There are source and binary releases on the web.
- </p>
+ <p>The current crypto implementation uses nifs to interface OpenSSLs crypto library
+ and requires <em>OpenSSL</em> package version 0.9.8 or higher.</p>
<p>Source releases of OpenSSL can be downloaded from the <url href="http://www.openssl.org">OpenSSL</url> project home page,
- or mirror sites listed there.
- </p>
- <p>The same URL also contains links to some compiled binaries and
- libraries of OpenSSL (see the <c>Related/Binaries</c> menu) of
- which the <url href="http://www.shininglightpro.com/search.php?searchname=Win32+OpenSSL">Shining Light Productions Win32 and OpenSSL</url> pages are of
- interest for the Win32 user.
- </p>
- <p>For some Unix flavours there are binary packages available
- on the net.
- </p>
- <p>If you cannot find a suitable binary OpenSSL package, you
- have to fetch an OpenSSL source release and compile it.
- </p>
- <p>You then have to compile and install the library
- <c>libcrypto.so</c> (Unix), or the library <c>libeay32.dll</c>
- (Win32).
- </p>
- <p>For Unix The <c>crypto_drv</c> dynamic driver is delivered linked
- to OpenSSL libraries in <c>/usr/local/lib</c>, but the default
- dynamic linking will also accept libraries in <c>/lib</c> and
- <c>/usr/lib</c>.
- </p>
- <p>If that is not applicable to the particular Unix operating
- system used, the example <c>Makefile</c> in the Crypto
- <c>priv/obj</c> directory, should be used as a basis for
- relinking the final version of the port program.
- </p>
- <p>For <c>Win32</c> it is only required that the library can be
- found from the <c>PATH</c> environment variable, or that they
- reside in the appropriate <c>SYSTEM32</c> directory; hence no
- particular relinking is need. Hence no example <c>Makefile</c>
- for Win32 is provided.</p>
- </section>
+ or mirror sites listed there.
+ </p>
+ </section>
<section>
<title>SEE ALSO</title>
diff --git a/lib/crypto/src/crypto.erl b/lib/crypto/src/crypto.erl
index 1d0a9943c3..f4e157198c 100644
--- a/lib/crypto/src/crypto.erl
+++ b/lib/crypto/src/crypto.erl
@@ -21,104 +21,220 @@
-module(crypto).
--export([start/0, stop/0, info/0, info_lib/0, algorithms/0, version/0]).
+-export([start/0, stop/0, info_lib/0, algorithms/0, version/0]).
-export([hash/2, hash_init/1, hash_update/2, hash_final/1]).
+-export([sign/4, verify/5]).
+-export([generate_key/2, generate_key/3, compute_key/4]).
+-export([hmac/3, hmac/4, hmac_init/2, hmac_update/2, hmac_final/1, hmac_final_n/2]).
+-export([exor/2, strong_rand_bytes/1, mod_pow/3]).
+-export([rand_bytes/1, rand_bytes/3, rand_uniform/2]).
+-export([block_encrypt/3, block_decrypt/3, block_encrypt/4, block_decrypt/4]).
+-export([next_iv/2, next_iv/3]).
+-export([stream_init/2, stream_init/3, stream_encrypt/2, stream_decrypt/2]).
+-export([public_encrypt/4, private_decrypt/4]).
+-export([private_encrypt/4, public_decrypt/4]).
+
+-export([dh_generate_parameters/2, dh_check/1]). %% Testing see
+
+%% DEPRECATED
+%% Replaced by hash_*
-export([md4/1, md4_init/0, md4_update/2, md4_final/1]).
-export([md5/1, md5_init/0, md5_update/2, md5_final/1]).
-export([sha/1, sha_init/0, sha_update/2, sha_final/1]).
--export([sha224/1, sha224_init/0, sha224_update/2, sha224_final/1]).
--export([sha256/1, sha256_init/0, sha256_update/2, sha256_final/1]).
--export([sha384/1, sha384_init/0, sha384_update/2, sha384_final/1]).
--export([sha512/1, sha512_init/0, sha512_update/2, sha512_final/1]).
+-deprecated({md4, 1, next_major_release}).
+-deprecated({md5, 1, next_major_release}).
+-deprecated({sha, 1, next_major_release}).
+-deprecated({md4_init, 0, next_major_release}).
+-deprecated({md5_init, 0, next_major_release}).
+-deprecated({sha_init, 0, next_major_release}).
+-deprecated({md4_update, 2, next_major_release}).
+-deprecated({md5_update, 2, next_major_release}).
+-deprecated({sha_update, 2, next_major_release}).
+-deprecated({md4_final, 1, next_major_release}).
+-deprecated({md5_final, 1, next_major_release}).
+-deprecated({sha_final, 1, next_major_release}).
+
+%% Replaced by hmac_*
-export([md5_mac/2, md5_mac_96/2, sha_mac/2, sha_mac/3, sha_mac_96/2]).
--export([sha224_mac/2, sha224_mac/3]).
--export([sha256_mac/2, sha256_mac/3]).
--export([sha384_mac/2, sha384_mac/3]).
--export([sha512_mac/2, sha512_mac/3]).
--export([hmac/3, hmac/4, hmac_init/2, hmac_update/2, hmac_final/1, hmac_final_n/2]).
+-deprecated({md5_mac, 2, next_major_release}).
+-deprecated({md5_mac_96, 2, next_major_release}).
+-deprecated({sha_mac, 2, next_major_release}).
+-deprecated({sha_mac, 3, next_major_release}).
+-deprecated({sha_mac_96, 2, next_major_release}).
+
+%% Replaced by sign/verify
+-export([dss_verify/3, dss_verify/4, rsa_verify/3, rsa_verify/4]).
+-export([dss_sign/2, dss_sign/3, rsa_sign/2, rsa_sign/3]).
+-deprecated({dss_verify, 3, next_major_release}).
+-deprecated({dss_verify, 4, next_major_release}).
+-deprecated({rsa_verify, 3, next_major_release}).
+-deprecated({rsa_verify, 4, next_major_release}).
+-deprecated({dss_sign, 2, next_major_release}).
+-deprecated({dss_sign, 3, next_major_release}).
+-deprecated({rsa_sign, 2, next_major_release}).
+-deprecated({rsa_sign, 3, next_major_release}).
+
+%% Replaced by generate_key
+-export([dh_generate_key/1, dh_generate_key/2, dh_compute_key/3]).
+-deprecated({dh_generate_key, 1, next_major_release}).
+-deprecated({dh_generate_key, 2, next_major_release}).
+-deprecated({dh_compute_key, 3, next_major_release}).
+
+%% Replaced by mod_exp_prim and no longer needed
+-export([mod_exp/3, mpint/1, erlint/1, strong_rand_mpint/3]).
+-deprecated({mod_exp, 3, next_major_release}).
+-deprecated({mpint, 1, next_major_release}).
+-deprecated({erlint, 1, next_major_release}).
+-deprecated({strong_rand_mpint, 3, next_major_release}).
+
+%% Replaced by block_*
-export([des_cbc_encrypt/3, des_cbc_decrypt/3, des_cbc_ivec/1]).
+-export([des3_cbc_encrypt/5, des3_cbc_decrypt/5]).
-export([des_ecb_encrypt/2, des_ecb_decrypt/2]).
+-export([des_ede3_cbc_encrypt/5, des_ede3_cbc_decrypt/5]).
-export([des_cfb_encrypt/3, des_cfb_decrypt/3, des_cfb_ivec/2]).
--export([des3_cbc_encrypt/5, des3_cbc_decrypt/5]).
-export([des3_cfb_encrypt/5, des3_cfb_decrypt/5]).
+-deprecated({des_cbc_encrypt, 3, next_major_release}).
+-deprecated({des_cbc_decrypt, 3, next_major_release}).
+-deprecated({des_cbc_ivec, 1, next_major_release}).
+-deprecated({des3_cbc_encrypt, 5, next_major_release}).
+-deprecated({des3_cbc_decrypt, 5, next_major_release}).
+-deprecated({des_ecb_encrypt, 2, next_major_release}).
+-deprecated({des_ecb_decrypt, 2, next_major_release}).
+-deprecated({des_ede3_cbc_encrypt, 5, next_major_release}).
+-deprecated({des_ede3_cbc_decrypt, 5, next_major_release}).
+-deprecated({des_cfb_encrypt, 3, next_major_release}).
+-deprecated({des_cfb_decrypt, 3, next_major_release}).
+-deprecated({des_cfb_ivec, 2, next_major_release}).
+-deprecated({des3_cfb_encrypt, 5, next_major_release}).
+-deprecated({des3_cfb_decrypt, 5, next_major_release}).
-export([blowfish_ecb_encrypt/2, blowfish_ecb_decrypt/2]).
-export([blowfish_cbc_encrypt/3, blowfish_cbc_decrypt/3]).
-export([blowfish_cfb64_encrypt/3, blowfish_cfb64_decrypt/3]).
-export([blowfish_ofb64_encrypt/3]).
--export([des_ede3_cbc_encrypt/5, des_ede3_cbc_decrypt/5]).
+-deprecated({blowfish_ecb_encrypt, 2, next_major_release}).
+-deprecated({blowfish_ecb_decrypt, 2, next_major_release}).
+-deprecated({blowfish_cbc_encrypt, 3, next_major_release}).
+-deprecated({blowfish_cbc_decrypt, 3, next_major_release}).
+-deprecated({blowfish_cfb64_encrypt, 3, next_major_release}).
+-deprecated({blowfish_cfb64_decrypt, 3, next_major_release}).
+-deprecated({blowfish_ofb64_encrypt, 3, next_major_release}).
-export([aes_cfb_128_encrypt/3, aes_cfb_128_decrypt/3]).
--export([exor/2]).
--export([rc4_encrypt/2, rc4_set_key/1, rc4_encrypt_with_state/2]).
--export([rc2_cbc_encrypt/3, rc2_cbc_decrypt/3, rc2_40_cbc_encrypt/3, rc2_40_cbc_decrypt/3]).
--export([dss_verify/3, dss_verify/4, rsa_verify/3, rsa_verify/4]).
--export([dss_sign/2, dss_sign/3, rsa_sign/2, rsa_sign/3]).
--export([rsa_public_encrypt/3, rsa_private_decrypt/3]).
--export([rsa_private_encrypt/3, rsa_public_decrypt/3]).
--export([dh_generate_key/1, dh_generate_key/2, dh_compute_key/3]).
--export([rand_bytes/1, rand_bytes/3, rand_uniform/2]).
--export([strong_rand_bytes/1, strong_rand_mpint/3]).
--export([mod_exp/3, mod_exp_prime/3, mpint/1, erlint/1]).
--export([srp_generate_key/4, srp_generate_key/3,
- srp_generate_key/5, srp_compute_key/6, srp_compute_key/7, srp_compute_key/8]).
-
-%% -export([idea_cbc_encrypt/3, idea_cbc_decrypt/3]).
-export([aes_cbc_128_encrypt/3, aes_cbc_128_decrypt/3]).
-export([aes_cbc_256_encrypt/3, aes_cbc_256_decrypt/3]).
-export([aes_cbc_ivec/1]).
--export([aes_ctr_encrypt/3, aes_ctr_decrypt/3]).
+-deprecated({aes_cfb_128_encrypt, 3, next_major_release}).
+-deprecated({aes_cfb_128_decrypt, 3, next_major_release}).
+-deprecated({aes_cbc_128_encrypt, 3, next_major_release}).
+-deprecated({aes_cbc_128_decrypt, 3, next_major_release}).
+-deprecated({aes_cbc_256_encrypt, 3, next_major_release}).
+-deprecated({aes_cbc_256_decrypt, 3, next_major_release}).
+-deprecated({aes_cbc_ivec, 1, next_major_release}).
+-export([rc2_cbc_encrypt/3, rc2_cbc_decrypt/3]).
+-export([rc2_40_cbc_encrypt/3, rc2_40_cbc_decrypt/3]).
+-deprecated({rc2_cbc_encrypt, 3, next_major_release}).
+-deprecated({rc2_cbc_decrypt, 3, next_major_release}).
+%% allready replaced by above!
+-deprecated({rc2_40_cbc_encrypt, 3, next_major_release}).
+-deprecated({rc2_40_cbc_decrypt, 3, next_major_release}).
+
+%% Replaced by stream_*
-export([aes_ctr_stream_init/2, aes_ctr_stream_encrypt/2, aes_ctr_stream_decrypt/2]).
-
--export([dh_generate_parameters/2, dh_check/1]). %% Testing see below
-
-
--define(FUNC_LIST, [md4, md4_init, md4_update, md4_final,
+-export([rc4_set_key/1, rc4_encrypt_with_state/2]).
+-deprecated({aes_ctr_stream_init, 2, next_major_release}).
+-deprecated({aes_ctr_stream_encrypt, 2, next_major_release}).
+-deprecated({aes_ctr_stream_decrypt, 2, next_major_release}).
+-deprecated({rc4_set_key, 1, next_major_release}).
+-deprecated({rc4_encrypt_with_state, 2, next_major_release}).
+
+%% Not needed special case of stream_*
+-export([aes_ctr_encrypt/3, aes_ctr_decrypt/3, rc4_encrypt/2]).
+-deprecated({aes_ctr_encrypt, 3, next_major_release}).
+-deprecated({aes_ctr_decrypt, 3, next_major_release}).
+-deprecated({rc4_encrypt, 2, next_major_release}).
+
+%% Replace by public/private_encrypt/decrypt
+-export([rsa_public_encrypt/3, rsa_private_decrypt/3]).
+-export([rsa_private_encrypt/3, rsa_public_decrypt/3]).
+-deprecated({rsa_public_encrypt, 3, next_major_release}).
+-deprecated({rsa_private_decrypt, 3, next_major_release}).
+-deprecated({rsa_public_decrypt, 3, next_major_release}).
+-deprecated({rsa_private_encrypt, 3, next_major_release}).
+
+%% Replaced by crypto:module_info()
+-export([info/0]).
+-deprecated({info, 0, next_major_release}).
+
+-define(FUNC_LIST, [hash, hash_init, hash_update, hash_final,
+ hmac, hmac_init, hmac_update, hmac_final, hmac_final_n,
+ %% deprecated
+ md4, md4_init, md4_update, md4_final,
md5, md5_init, md5_update, md5_final,
sha, sha_init, sha_update, sha_final,
- sha224, sha224_init, sha224_update, sha224_final,
- sha256, sha256_init, sha256_update, sha256_final,
- sha384, sha384_init, sha384_update, sha384_final,
- sha512, sha512_init, sha512_update, sha512_final,
md5_mac, md5_mac_96,
sha_mac, sha_mac_96,
- sha224_mac, sha256_mac, sha384_mac, sha512_mac,
+ %%
+ block_encrypt, block_decrypt,
+ %% deprecated
des_cbc_encrypt, des_cbc_decrypt,
des_cfb_encrypt, des_cfb_decrypt,
des_ecb_encrypt, des_ecb_decrypt,
des3_cbc_encrypt, des3_cbc_decrypt,
des3_cfb_encrypt, des3_cfb_decrypt,
aes_cfb_128_encrypt, aes_cfb_128_decrypt,
+ rc2_cbc_encrypt, rc2_cbc_decrypt,
+ rc2_40_cbc_encrypt, rc2_40_cbc_decrypt,
+ aes_cbc_128_encrypt, aes_cbc_128_decrypt,
+ aes_cbc_256_encrypt, aes_cbc_256_decrypt,
+ blowfish_cbc_encrypt, blowfish_cbc_decrypt,
+ blowfish_cfb64_encrypt, blowfish_cfb64_decrypt,
+ blowfish_ecb_encrypt, blowfish_ecb_decrypt, blowfish_ofb64_encrypt,
+ %%
rand_bytes,
strong_rand_bytes,
- strong_rand_mpint,
rand_uniform,
- mod_exp, mod_exp_prime,
+ mod_pow,
+ exor,
+ %% deprecated
+ mod_exp,strong_rand_mpint,erlint, mpint,
+ %%
+ sign, verify, generate_key, compute_key,
+ %% deprecated
dss_verify,dss_sign,
rsa_verify,rsa_sign,
rsa_public_encrypt,rsa_private_decrypt,
rsa_private_encrypt,rsa_public_decrypt,
dh_generate_key, dh_compute_key,
- aes_cbc_128_encrypt, aes_cbc_128_decrypt,
- exor,
+ %%
+ stream_init, stream_encrypt, stream_decrypt,
+ %% deprecated
rc4_encrypt, rc4_set_key, rc4_encrypt_with_state,
- rc2_40_cbc_encrypt, rc2_40_cbc_decrypt,
- %% idea_cbc_encrypt, idea_cbc_decrypt,
- aes_cbc_256_encrypt, aes_cbc_256_decrypt,
aes_ctr_encrypt, aes_ctr_decrypt,
aes_ctr_stream_init, aes_ctr_stream_encrypt, aes_ctr_stream_decrypt,
- aes_cbc_ivec, blowfish_cbc_encrypt, blowfish_cbc_decrypt,
- blowfish_cfb64_encrypt, blowfish_cfb64_decrypt,
- blowfish_ecb_encrypt, blowfish_ecb_decrypt, blowfish_ofb64_encrypt,
- des_cbc_ivec, des_cfb_ivec, erlint, mpint,
- hash, hash_init, hash_update, hash_final,
- hmac, hmac_init, hmac_update, hmac_final, hmac_final_n, info,
- rc2_cbc_encrypt, rc2_cbc_decrypt,
- srp_generate_key, srp_compute_key,
+ %%
+ next_iv,
+ %% deprecated
+ aes_cbc_ivec,
+ des_cbc_ivec, des_cfb_ivec,
+ info,
+ %%
info_lib, algorithms]).
+-type mpint() :: binary().
-type rsa_digest_type() :: 'md5' | 'sha' | 'sha224' | 'sha256' | 'sha384' | 'sha512'.
-type dss_digest_type() :: 'none' | 'sha'.
+%%-type ecdsa_digest_type() :: 'md5' | 'sha' | 'sha256' | 'sha384' | 'sha512'.
-type data_or_digest() :: binary() | {digest, binary()}.
-type crypto_integer() :: binary() | integer().
+-type ec_key_res() :: any(). %% nif resource
+-type ec_named_curve() :: atom().
+-type ec_point() :: crypto_integer().
+-type ec_basis() :: {tpbasis, K :: non_neg_integer()} | {ppbasis, K1 :: non_neg_integer(), K2 :: non_neg_integer(), K3 :: non_neg_integer()} | onbasis.
+-type ec_field() :: {prime_field, Prime :: integer()} | {characteristic_two_field, M :: integer(), Basis :: ec_basis()}.
+-type ec_prime() :: {A :: crypto_integer(), B :: crypto_integer(), Seed :: binary() | none}.
+-type ec_curve_spec() :: {Field :: ec_field(), Prime :: ec_prime(), Point :: crypto_integer(), Order :: integer(), CoFactor :: none | integer()}.
+-type ec_curve() :: ec_named_curve() | ec_curve_spec().
+-type ec_key() :: {Curve :: ec_curve(), PrivKey :: binary() | undefined, PubKey :: ec_point() | undefined}.
-define(nif_stub,nif_stub_error(?LINE)).
@@ -565,6 +681,110 @@ sha512_mac(Key, Data, MacSz) ->
sha512_mac_nif(_Key,_Data,_MacSz) -> ?nif_stub.
+
+%% Ecrypt/decrypt %%%
+
+-spec block_encrypt(des_cbc | des_cfb | des3_cbc | des3_cbf | des_ede3 | blowfish_cbc |
+ blowfish_cfb64 | aes_cbc128 | aes_cfb128 | aes_cbc256 | rc2_cbc,
+ Key::iodata(), Ivec::binary(), Data::iodata()) -> binary().
+
+block_encrypt(des_cbc, Key, Ivec, Data) ->
+ des_cbc_encrypt(Key, Ivec, Data);
+block_encrypt(des_cfb, Key, Ivec, Data) ->
+ des_cfb_encrypt(Key, Ivec, Data);
+block_encrypt(des3_cbc, [Key1, Key2, Key3], Ivec, Data) ->
+ des3_cbc_encrypt(Key1, Key2, Key3, Ivec, Data);
+block_encrypt(des3_cbf, [Key1, Key2, Key3], Ivec, Data) ->
+ des3_cfb_encrypt(Key1, Key2, Key3, Ivec, Data);
+block_encrypt(des_ede3, [Key1, Key2, Key3], Ivec, Data) ->
+ des_ede3_cbc_encrypt(Key1, Key2, Key3, Ivec, Data);
+block_encrypt(blowfish_cbc, Key, Ivec, Data) ->
+ blowfish_cbc_encrypt(Key, Ivec, Data);
+block_encrypt(blowfish_cfb64, Key, Ivec, Data) ->
+ blowfish_cfb64_encrypt(Key, Ivec, Data);
+block_encrypt(blowfish_ofb64, Key, Ivec, Data) ->
+ blowfish_ofb64_encrypt(Key, Ivec, Data);
+block_encrypt(aes_cbc128, Key, Ivec, Data) ->
+ aes_cbc_128_encrypt(Key, Ivec, Data);
+block_encrypt(aes_cbc256, Key, Ivec, Data) ->
+ aes_cbc_256_encrypt(Key, Ivec, Data);
+block_encrypt(aes_cfb128, Key, Ivec, Data) ->
+ aes_cfb_128_encrypt(Key, Ivec, Data);
+block_encrypt(rc2_cbc, Key, Ivec, Data) ->
+ rc2_cbc_encrypt(Key, Ivec, Data).
+
+-spec block_decrypt(des_cbc | des_cfb | des3_cbc | des3_cbf | des_ede3 | blowfish_cbc |
+ blowfish_cfb64 | blowfish_ofb64 | aes_cbc128 | aes_cbc256 | aes_cfb128 | rc2_cbc,
+ Key::iodata(), Ivec::binary(), Data::iodata()) -> binary().
+
+block_decrypt(des_cbc, Key, Ivec, Data) ->
+ des_cbc_decrypt(Key, Ivec, Data);
+block_decrypt(des_cfb, Key, Ivec, Data) ->
+ des_cfb_decrypt(Key, Ivec, Data);
+block_decrypt(des3_cbc, [Key1, Key2, Key3], Ivec, Data) ->
+ des3_cbc_decrypt(Key1, Key2, Key3, Ivec, Data);
+block_decrypt(des3_cbf, [Key1, Key2, Key3], Ivec, Data) ->
+ des3_cfb_decrypt(Key1, Key2, Key3, Ivec, Data);
+block_decrypt(des_ede3, [Key1, Key2, Key3], Ivec, Data) ->
+ des_ede3_cbc_decrypt(Key1, Key2, Key3, Ivec, Data);
+block_decrypt(blowfish_cbc, Key, Ivec, Data) ->
+ blowfish_cbc_decrypt(Key, Ivec, Data);
+block_decrypt(blowfish_cfb64, Key, Ivec, Data) ->
+ blowfish_cfb64_decrypt(Key, Ivec, Data);
+block_decrypt(blowfish_ofb, Key, Ivec, Data) ->
+ blowfish_ofb64_decrypt(Key, Ivec, Data);
+block_decrypt(aes_cbc128, Key, Ivec, Data) ->
+ aes_cbc_128_decrypt(Key, Ivec, Data);
+block_decrypt(aes_cbc256, Key, Ivec, Data) ->
+ aes_cbc_256_decrypt(Key, Ivec, Data);
+block_decrypt(aes_cfb128, Key, Ivec, Data) ->
+ aes_cfb_128_decrypt(Key, Ivec, Data);
+block_decrypt(rc2_cbc, Key, Ivec, Data) ->
+ rc2_cbc_decrypt(Key, Ivec, Data).
+
+-spec block_encrypt(des_ecb | blowfish_ecb, Key::iodata(), Data::iodata()) -> binary().
+
+block_encrypt(des_ecb, Key, Data) ->
+ des_ecb_encrypt(Key, Data);
+block_encrypt(blowfish_ecb, Key, Data) ->
+ blowfish_ecb_encrypt(Key, Data).
+
+-spec block_decrypt(des_ecb | blowfish_ecb, Key::iodata(), Data::iodata()) -> binary().
+
+block_decrypt(des_ecb, Key, Data) ->
+ des_ecb_decrypt(Key, Data);
+block_decrypt(blowfish_ecb, Key, Data) ->
+ blowfish_ecb_decrypt(Key, Data).
+
+-spec next_iv(des_cbc | aes_cbc, Data::iodata()) -> binary().
+
+next_iv(des_cbc, Data) ->
+ des_cbc_ivec(Data);
+next_iv(aes_cbc, Data) ->
+ aes_cbc_ivec(Data).
+
+-spec next_iv(des_cbf, Ivec::binary(), Data::iodata()) -> binary().
+
+next_iv(des_cbf, Ivec, Data) ->
+ des_cfb_ivec(Ivec, Data).
+
+stream_init(aes_ctr, Key, Ivec) ->
+ {aes_ctr, aes_ctr_stream_init(Key, Ivec)}.
+stream_init(rc4, Key) ->
+ {rc4, rc4_set_key(Key)}.
+stream_encrypt({aes_ctr, State}, Data) ->
+ {State, Cipher} = aes_ctr_stream_encrypt(State, Data),
+ {{aes_ctr, State}, Cipher};
+stream_encrypt({rc4, State0}, Data) ->
+ {State, Cipher} = rc4_encrypt_with_state(State0, Data),
+ {{rc4, State}, Cipher}.
+stream_decrypt({aes_ctr, State0}, Data) ->
+ {State, Text} = aes_ctr_stream_decrypt(State0, Data),
+ {{aes_ctr, State}, Text};
+stream_decrypt({rc4, State0}, Data) ->
+ {State, Text} = rc4_encrypt_with_state (State0, Data),
+ {{rc4, State}, Text}.
+
%%
%% CRYPTO FUNCTIONS
%%
@@ -713,8 +933,12 @@ blowfish_cfb64_decrypt(Key, IVec, Data) ->
bf_cfb64_crypt(_Key, _IVec, _Data, _IsEncrypt) -> ?nif_stub.
+blowfish_ofb64_decrypt(Key, Ivec, Data) ->
+ blowfish_ofb64_encrypt(Key, Ivec, Data).
+
blowfish_ofb64_encrypt(_Key, _IVec, _Data) -> ?nif_stub.
+
%%
%% AES in cipher feedback mode (CFB)
%%
@@ -798,9 +1022,9 @@ mod_exp(Base, Exponent, Modulo)
mod_exp(Base, Exponent, Modulo) ->
mod_exp_nif(mpint_to_bin(Base),mpint_to_bin(Exponent),mpint_to_bin(Modulo), 4).
--spec mod_exp_prime(binary(), binary(), binary()) -> binary() | error.
-mod_exp_prime(Base, Exponent, Prime) ->
- case mod_exp_nif(Base, Exponent, Prime, 0) of
+-spec mod_pow(binary()|integer(), binary()|integer(), binary()|integer()) -> binary() | error.
+mod_pow(Base, Exponent, Prime) ->
+ case mod_exp_nif(ensure_int_as_bin(Base), ensure_int_as_bin(Exponent), ensure_int_as_bin(Prime), 0) of
<<0>> -> error;
R -> R
end.
@@ -819,19 +1043,40 @@ mod_exp_nif(_Base,_Exp,_Mod,_bin_hdr) -> ?nif_stub.
%% Key = [P,Q,G,Y] P,Q,G=DSSParams Y=PublicKey
dss_verify(Data,Signature,Key) ->
- dss_verify(sha, Data, Signature, Key).
-dss_verify(_Type,_Data,_Signature,_Key) -> ?nif_stub.
+ dss_verify(sha, Data, Signature, Key).
+
+dss_verify(Type,Data,Signature,Key) when is_binary(Data), Type=/=none ->
+ verify(dss,Type,mpint_to_bin(Data),mpint_to_bin(Signature),map_mpint_to_bin(Key));
+dss_verify(Type,Digest,Signature,Key) ->
+ verify(dss,Type,Digest,mpint_to_bin(Signature),map_mpint_to_bin(Key)).
% Key = [E,N] E=PublicExponent N=PublicModulus
rsa_verify(Data,Signature,Key) ->
- rsa_verify_nif(sha, Data,Signature,Key).
-rsa_verify(Type, DataOrDigest, Signature, Key) ->
- case rsa_verify_nif(Type, DataOrDigest, Signature, Key) of
+ rsa_verify(sha, Data,Signature,Key).
+rsa_verify(Type, Data, Signature, Key) when is_binary(Data) ->
+ verify(rsa, Type, mpint_to_bin(Data), mpint_to_bin(Signature), map_mpint_to_bin(Key));
+rsa_verify(Type, Digest, Signature, Key) ->
+ verify(rsa, Type, Digest, mpint_to_bin(Signature), map_mpint_to_bin(Key)).
+
+
+verify(dss, Type, Data, Signature, Key) ->
+ dss_verify_nif(Type, Data, Signature, map_ensure_int_as_bin(Key));
+
+verify(rsa, Type, DataOrDigest, Signature, Key) ->
+ case rsa_verify_nif(Type, DataOrDigest, Signature, map_ensure_int_as_bin(Key)) of
notsup -> erlang:error(notsup);
Bool -> Bool
+ end;
+verify(ecdsa, Type, DataOrDigest, Signature, [Key, Curve]) ->
+ case ecdsa_verify_nif(Type, DataOrDigest, Signature, term_to_ec_key({Curve, undefined, Key})) of
+ notsup -> erlang:error(notsup);
+ Bool -> Bool
end.
+
+dss_verify_nif(_Type, _Data, _Signature, _Key) -> ?nif_stub.
rsa_verify_nif(_Type, _Data, _Signature, _Key) -> ?nif_stub.
+ecdsa_verify_nif(_Type, _DataOrDigest, _Signature, _Key) -> ?nif_stub.
%%
@@ -845,24 +1090,103 @@ rsa_verify_nif(_Type, _Data, _Signature, _Key) -> ?nif_stub.
dss_sign(DataOrDigest,Key) ->
dss_sign(sha,DataOrDigest,Key).
-dss_sign(Type, DataOrDigest, Key) ->
- case dss_sign_nif(Type,DataOrDigest,Key) of
- error -> erlang:error(badkey, [DataOrDigest, Key]);
- Sign -> Sign
- end.
+dss_sign(Type, Data, Key) when is_binary(Data), Type=/=none ->
+ sign(dss, Type, mpint_to_bin(Data), map_mpint_to_bin(Key));
+dss_sign(Type, Digest, Key) ->
+ sign(dss, Type, Digest, map_mpint_to_bin(Key)).
-dss_sign_nif(_Type,_Data,_Key) -> ?nif_stub.
%% Key = [E,N,D] E=PublicExponent N=PublicModulus D=PrivateExponent
rsa_sign(DataOrDigest,Key) ->
rsa_sign(sha, DataOrDigest, Key).
-rsa_sign(Type, DataOrDigest, Key) ->
- case rsa_sign_nif(Type,DataOrDigest,Key) of
+
+rsa_sign(Type, Data, Key) when is_binary(Data) ->
+ sign(rsa, Type, mpint_to_bin(Data), map_mpint_to_bin(Key));
+rsa_sign(Type, Digest, Key) ->
+ sign(rsa, Type, Digest, map_mpint_to_bin(Key)).
+
+map_mpint_to_bin(List) ->
+ lists:map(fun(E) -> mpint_to_bin(E) end, List ).
+
+map_ensure_int_as_bin([H|_]=List) when is_integer(H) ->
+ lists:map(fun(E) -> int_to_bin(E) end, List);
+map_ensure_int_as_bin(List) ->
+ List.
+
+ensure_int_as_bin(Int) when is_integer(Int) ->
+ int_to_bin(Int);
+ensure_int_as_bin(Bin) ->
+ Bin.
+
+map_to_norm_bin([H|_]=List) when is_integer(H) ->
+ lists:map(fun(E) -> int_to_bin(E) end, List);
+map_to_norm_bin(List) ->
+ lists:map(fun(E) -> mpint_to_bin(E) end, List).
+
+
+sign(rsa, Type, DataOrDigest, Key) ->
+ case rsa_sign_nif(Type, DataOrDigest, map_ensure_int_as_bin(Key)) of
+ error -> erlang:error(badkey, [Type,DataOrDigest,Key]);
+ Sign -> Sign
+ end;
+sign(dss, Type, DataOrDigest, Key) ->
+ case dss_sign_nif(Type, DataOrDigest, map_ensure_int_as_bin(Key)) of
+ error -> erlang:error(badkey, [DataOrDigest, Key]);
+ Sign -> Sign
+ end;
+sign(ecdsa, Type, DataOrDigest, [Key, Curve]) ->
+ case ecdsa_sign_nif(Type, DataOrDigest, term_to_ec_key({Curve, Key, undefined})) of
error -> erlang:error(badkey, [Type,DataOrDigest,Key]);
Sign -> Sign
end.
rsa_sign_nif(_Type,_Data,_Key) -> ?nif_stub.
+dss_sign_nif(_Type,_Data,_Key) -> ?nif_stub.
+ecdsa_sign_nif(_Type, _DataOrDigest, _Key) -> ?nif_stub.
+
+
+
+
+-spec public_encrypt(rsa, binary(), [binary()], rsa_padding()) ->
+ binary().
+-spec public_decrypt(rsa, binary(), [integer() | binary()], rsa_padding()) ->
+ binary().
+-spec private_encrypt(rsa, binary(), [integer() | binary()], rsa_padding()) ->
+ binary().
+-spec private_decrypt(rsa, binary(), [integer() | binary()], rsa_padding()) ->
+ binary().
+
+public_encrypt(rsa, BinMesg, Key, Padding) ->
+ case rsa_public_crypt(BinMesg, map_ensure_int_as_bin(Key), Padding, true) of
+ error ->
+ erlang:error(encrypt_failed, [BinMesg,Key, Padding]);
+ Sign -> Sign
+ end.
+
+%% Binary, Key = [E,N,D]
+private_decrypt(rsa, BinMesg, Key, Padding) ->
+ case rsa_private_crypt(BinMesg, map_ensure_int_as_bin(Key), Padding, false) of
+ error ->
+ erlang:error(decrypt_failed, [BinMesg,Key, Padding]);
+ Sign -> Sign
+ end.
+
+
+%% Binary, Key = [E,N,D]
+private_encrypt(rsa, BinMesg, Key, Padding) ->
+ case rsa_private_crypt(BinMesg, map_ensure_int_as_bin(Key), Padding, true) of
+ error ->
+ erlang:error(encrypt_failed, [BinMesg,Key, Padding]);
+ Sign -> Sign
+ end.
+
+%% Binary, Key = [E,N]
+public_decrypt(rsa, BinMesg, Key, Padding) ->
+ case rsa_public_crypt(BinMesg, map_ensure_int_as_bin(Key), Padding, false) of
+ error ->
+ erlang:error(decrypt_failed, [BinMesg,Key, Padding]);
+ Sign -> Sign
+ end.
%%
@@ -872,16 +1196,16 @@ rsa_sign_nif(_Type,_Data,_Key) -> ?nif_stub.
-spec rsa_public_encrypt(binary(), [binary()], rsa_padding()) ->
binary().
--spec rsa_public_decrypt(binary(), [binary()], rsa_padding()) ->
+-spec rsa_public_decrypt(binary(), [integer() | mpint()], rsa_padding()) ->
binary().
--spec rsa_private_encrypt(binary(), [binary()], rsa_padding()) ->
+-spec rsa_private_encrypt(binary(), [integer() | mpint()], rsa_padding()) ->
binary().
--spec rsa_private_decrypt(binary(), [binary()], rsa_padding()) ->
+-spec rsa_private_decrypt(binary(), [integer() | mpint()], rsa_padding()) ->
binary().
%% Binary, Key = [E,N]
rsa_public_encrypt(BinMesg, Key, Padding) ->
- case rsa_public_crypt(BinMesg, Key, Padding, true) of
+ case rsa_public_crypt(BinMesg, map_to_norm_bin(Key), Padding, true) of
error ->
erlang:error(encrypt_failed, [BinMesg,Key, Padding]);
Sign -> Sign
@@ -891,7 +1215,7 @@ rsa_public_crypt(_BinMsg, _Key, _Padding, _IsEncrypt) -> ?nif_stub.
%% Binary, Key = [E,N,D]
rsa_private_decrypt(BinMesg, Key, Padding) ->
- case rsa_private_crypt(BinMesg, Key, Padding, false) of
+ case rsa_private_crypt(BinMesg, map_to_norm_bin(Key), Padding, false) of
error ->
erlang:error(decrypt_failed, [BinMesg,Key, Padding]);
Sign -> Sign
@@ -902,7 +1226,7 @@ rsa_private_crypt(_BinMsg, _Key, _Padding, _IsEncrypt) -> ?nif_stub.
%% Binary, Key = [E,N,D]
rsa_private_encrypt(BinMesg, Key, Padding) ->
- case rsa_private_crypt(BinMesg, Key, Padding, true) of
+ case rsa_private_crypt(BinMesg, map_to_norm_bin(Key), Padding, true) of
error ->
erlang:error(encrypt_failed, [BinMesg,Key, Padding]);
Sign -> Sign
@@ -910,7 +1234,7 @@ rsa_private_encrypt(BinMesg, Key, Padding) ->
%% Binary, Key = [E,N]
rsa_public_decrypt(BinMesg, Key, Padding) ->
- case rsa_public_crypt(BinMesg, Key, Padding, false) of
+ case rsa_public_crypt(BinMesg, map_to_norm_bin(Key), Padding, false) of
error ->
erlang:error(decrypt_failed, [BinMesg,Key, Padding]);
Sign -> Sign
@@ -1052,120 +1376,142 @@ dh_check([_Prime,_Gen]) -> ?nif_stub.
{binary(),binary()}.
dh_generate_key(DHParameters) ->
- dh_generate_key(undefined, DHParameters).
+ dh_generate_key_nif(undefined, map_mpint_to_bin(DHParameters), 4).
dh_generate_key(PrivateKey, DHParameters) ->
- case dh_generate_key_nif(PrivateKey, DHParameters) of
- error -> erlang:error(generation_failed, [PrivateKey,DHParameters]);
- Res -> Res
- end.
+ dh_generate_key_nif(mpint_to_bin(PrivateKey), map_mpint_to_bin(DHParameters), 4).
-dh_generate_key_nif(_PrivateKey, _DHParameters) -> ?nif_stub.
+dh_generate_key_nif(_PrivateKey, _DHParameters, _Mpint) -> ?nif_stub.
%% DHParameters = [P (Prime)= mpint(), G(Generator) = mpint()]
-%% MyPrivKey, OthersPublicKey = mpint()
+%% MyPrivKey, OthersPublicKey = mpint()
-spec dh_compute_key(binary(), binary(), [binary()]) -> binary().
dh_compute_key(OthersPublicKey, MyPrivateKey, DHParameters) ->
- case dh_compute_key_nif(OthersPublicKey,MyPrivateKey,DHParameters) of
- error -> erlang:error(computation_failed, [OthersPublicKey,MyPrivateKey,DHParameters]);
- Ret -> Ret
- end.
+ compute_key(dh, mpint_to_bin(OthersPublicKey), mpint_to_bin(MyPrivateKey),
+ map_mpint_to_bin(DHParameters)).
+
dh_compute_key_nif(_OthersPublicKey, _MyPrivateKey, _DHParameters) -> ?nif_stub.
+generate_key(Type, Params) ->
+ generate_key(Type, Params, undefined).
+
+generate_key(dh, DHParameters, PrivateKey) ->
+ dh_generate_key_nif(PrivateKey, map_ensure_int_as_bin(DHParameters), 0);
+
+generate_key(srp, {host, [Verifier, Generator, Prime, Version]}, PrivArg)
+ when is_binary(Verifier), is_binary(Generator), is_binary(Prime), is_atom(Version) ->
+ Private = case PrivArg of
+ undefined -> random_bytes(32);
+ _ -> PrivArg
+ end,
+ host_srp_gen_key(Private, Verifier, Generator, Prime, Version);
+
+generate_key(srp, {user, [Generator, Prime, Version]}, PrivateArg)
+ when is_binary(Generator), is_binary(Prime), is_atom(Version) ->
+ Private = case PrivateArg of
+ undefined -> random_bytes(32);
+ _ -> PrivateArg
+ end,
+ user_srp_gen_key(Private, Generator, Prime);
-%%% SRP
--spec srp_generate_key(binary(), binary(), atom() | binary(), atom() | binary() ) -> {Public::binary(), Private::binary()}.
-srp_generate_key(Verifier, Generator, Prime, Version) when is_binary(Verifier),
- is_binary(Generator),
- is_binary(Prime),
- is_atom(Version) ->
- Private = random_bytes(32),
- server_srp_gen_key(Private, Verifier, Generator, Prime, Version);
-
-srp_generate_key(Generator, Prime, Version, Private) when is_binary(Generator),
- is_binary(Prime),
- is_atom(Version),
- is_binary(Private) ->
- client_srp_gen_key(Private, Generator, Prime).
-
--spec srp_generate_key(binary(), binary(), binary(), atom(), binary()) -> {Public::binary(), Private::binary()}.
-srp_generate_key(Verifier, Generator, Prime, Version, Private) when is_binary(Verifier),
- is_binary(Generator),
- is_binary(Prime),
- is_atom(Version),
- is_binary(Private)
- ->
- server_srp_gen_key(Private, Verifier, Generator, Prime, Version).
-
--spec srp_generate_key(binary(), binary(), atom()) -> {Public::binary(), Private::binary()}.
-srp_generate_key(Generator, Prime, Version) when is_binary(Generator),
- is_binary(Prime),
- is_atom(Version) ->
- Private = random_bytes(32),
- client_srp_gen_key(Private, Generator, Prime).
-
--spec srp_compute_key(binary(), binary(), binary(), binary(), binary(), atom()| binary(), atom() | binary() ) -> binary().
-srp_compute_key(DerivedKey, Prime, Generator, ClientPublic, ClientPrivate, ServerPublic, Version) when
- is_binary(Prime),
+generate_key(ecdh, Curve, undefined) ->
+ ec_key_to_term(ec_key_generate(Curve)).
+
+
+ec_key_generate(_Key) -> ?nif_stub.
+
+
+compute_key(dh, OthersPublicKey, MyPrivateKey, DHParameters) ->
+ case dh_compute_key_nif(OthersPublicKey,MyPrivateKey, map_ensure_int_as_bin(DHParameters)) of
+ error -> erlang:error(computation_failed,
+ [OthersPublicKey,MyPrivateKey,DHParameters]);
+ Ret -> Ret
+ end;
+
+compute_key(srp, HostPublic, {UserPublic, UserPrivate},
+ {user, [DerivedKey, Prime, Generator, Version | ScramblerArg]}) when
+ is_binary(Prime),
is_binary(Generator),
- is_binary(ClientPublic),
- is_binary(ClientPrivate),
- is_binary(ServerPublic),
+ is_binary(UserPublic),
+ is_binary(UserPrivate),
+ is_binary(HostPublic),
is_atom(Version) ->
Multiplier = srp_multiplier(Version, Generator, Prime),
- Scrambler = srp_scrambler(Version, ClientPublic, ServerPublic, Prime),
- srp_client_secret_nif(ClientPrivate, Scrambler, ServerPublic, Multiplier,
- Generator, DerivedKey, Prime);
-
-srp_compute_key(Verifier, Prime, ClientPublic, ServerPublic, ServerPrivate, Version, Scrambler) when
+ Scrambler = case ScramblerArg of
+ [] -> srp_scrambler(Version, UserPublic, HostPublic, Prime);
+ [S] -> S
+ end,
+ srp_user_secret_nif(UserPrivate, Scrambler, HostPublic, Multiplier,
+ Generator, DerivedKey, Prime);
+
+compute_key(srp, UserPublic, {HostPublic, HostPrivate},
+ {host,[Verifier, Prime, Version | ScramblerArg]}) when
is_binary(Verifier),
- is_binary(Prime),
- is_binary(ClientPublic),
- is_binary(ServerPublic),
- is_binary(ServerPrivate),
- is_atom(Version),
- is_binary(Scrambler) ->
- srp_server_secret_nif(Verifier, ServerPrivate, Scrambler, ClientPublic, Prime).
-
--spec srp_compute_key(binary(), binary(), binary(), binary(), binary(), binary(), atom(), binary()) -> binary().
-srp_compute_key(DerivedKey, Prime, Generator, ClientPublic, ClientPrivate,
- ServerPublic, Version, Scrambler) when is_binary(DerivedKey),
- is_binary(Prime),
- is_binary(Generator),
- is_binary(ClientPublic),
- is_binary(ClientPrivate),
- is_binary(ServerPublic),
- is_atom(Version),
- is_binary(Scrambler) ->
- Multiplier = srp_multiplier(Version, Generator, Prime),
- srp_client_secret_nif(ClientPrivate, Scrambler, ServerPublic, Multiplier,
- Generator, DerivedKey, Prime).
-
--spec srp_compute_key(binary(), binary(), binary(), binary(), binary(), atom()) -> binary().
-srp_compute_key(Verifier, Prime, ClientPublic, ServerPublic, ServerPrivate, Version) when
- is_binary(Verifier),
- is_binary(Prime),
- is_binary(ClientPublic),
- is_binary(ServerPublic),
- is_binary(ServerPrivate),
+ is_binary(Prime),
+ is_binary(UserPublic),
+ is_binary(HostPublic),
+ is_binary(HostPrivate),
is_atom(Version) ->
- Scrambler = srp_scrambler(Version, ClientPublic, ServerPublic, Prime),
- srp_server_secret_nif(Verifier, ServerPrivate, Scrambler, ClientPublic, Prime).
+ Scrambler = case ScramblerArg of
+ [] -> srp_scrambler(Version, UserPublic, HostPublic, Prime);
+ [S] -> S
+ end,
+ srp_host_secret_nif(Verifier, HostPrivate, Scrambler, UserPublic, Prime);
+
+compute_key(ecdh, Others, My, Curve) ->
+ ecdh_compute_key_nif(Others, term_to_ec_key({Curve,My,undefined})).
+
+ecdh_compute_key_nif(_Others, _My) -> ?nif_stub.
+
%%
+%% EC
+%%
+ec_key_to_term(Key) ->
+ case ec_key_to_term_nif(Key) of
+ {PrivKey, PubKey} ->
+ {bin_to_int(PrivKey), PubKey};
+ _ ->
+ erlang:error(conversion_failed)
+ end.
+
+ec_key_to_term_nif(_Key) -> ?nif_stub.
+
+term_to_nif_prime({prime_field, Prime}) ->
+ {prime_field, int_to_bin(Prime)};
+term_to_nif_prime(PrimeField) ->
+ PrimeField.
+term_to_nif_curve({A, B, Seed}) ->
+ {ensure_int_as_bin(A), ensure_int_as_bin(B), Seed}.
+term_to_nif_curve_parameters({PrimeField, Curve, BasePoint, Order, CoFactor}) ->
+ {term_to_nif_prime(PrimeField), term_to_nif_curve(Curve), ensure_int_as_bin(BasePoint), int_to_bin(Order), int_to_bin(CoFactor)};
+term_to_nif_curve_parameters(Curve) when is_atom(Curve) ->
+ %% named curve
+ Curve.
+
+-spec term_to_ec_key(ec_key()) -> ec_key_res().
+term_to_ec_key({Curve, undefined, PubKey}) ->
+ term_to_ec_key_nif(term_to_nif_curve_parameters(Curve), undefined, PubKey);
+term_to_ec_key({Curve, PrivKey, PubKey}) ->
+ term_to_ec_key_nif(term_to_nif_curve_parameters(Curve), int_to_bin(PrivKey), PubKey).
+
+term_to_ec_key_nif(_Curve, _PrivKey, _PubKey) -> ?nif_stub.
+
+
+
%% LOCAL FUNCTIONS
%%
-client_srp_gen_key(Private, Generator, Prime) ->
- case mod_exp_prime(Generator, Private, Prime) of
+user_srp_gen_key(Private, Generator, Prime) ->
+ case mod_pow(Generator, Private, Prime) of
error ->
error;
Public ->
{Public, Private}
end.
-server_srp_gen_key(Private, Verifier, Generator, Prime, Version) ->
+host_srp_gen_key(Private, Verifier, Generator, Prime, Version) ->
Multiplier = srp_multiplier(Version, Generator, Prime),
case srp_value_B_nif(Multiplier, Verifier, Generator, Private, Prime) of
error ->
@@ -1185,17 +1531,17 @@ srp_multiplier('6', _, _) ->
srp_multiplier('3', _, _) ->
<<1/integer>>.
-srp_scrambler(Version, ClientPublic, ServerPublic, Prime) when Version == '6'; Version == '6a'->
+srp_scrambler(Version, UserPublic, HostPublic, Prime) when Version == '6'; Version == '6a'->
%% SHA1(PAD(A) | PAD(B)) from http://srp.stanford.edu/design.html
PadLength = erlang:byte_size(Prime),
C0 = sha_init(),
- C1 = sha_update(C0, srp_pad_to(PadLength, ClientPublic)),
- C2 = sha_update(C1, srp_pad_to(PadLength, ServerPublic)),
+ C1 = sha_update(C0, srp_pad_to(PadLength, UserPublic)),
+ C2 = sha_update(C1, srp_pad_to(PadLength, HostPublic)),
sha_final(C2);
-srp_scrambler('3', _, ServerPublic, _Prime) ->
+srp_scrambler('3', _, HostPublic, _Prime) ->
%% The parameter u is a 32-bit unsigned integer which takes its value
%% from the first 32 bits of the SHA1 hash of B, MSB first.
- <<U:32/bits, _/binary>> = sha(ServerPublic),
+ <<U:32/bits, _/binary>> = sha(HostPublic),
U.
srp_pad_length(Width, Length) ->
@@ -1207,9 +1553,9 @@ srp_pad_to(Width, Binary) ->
N -> << 0:(N*8), Binary/binary>>
end.
-srp_server_secret_nif(_Verifier, _B, _U, _A, _Prime) -> ?nif_stub.
+srp_host_secret_nif(_Verifier, _B, _U, _A, _Prime) -> ?nif_stub.
-srp_client_secret_nif(_A, _U, _B, _Multiplier, _Generator, _Exponent, _Prime) -> ?nif_stub.
+srp_user_secret_nif(_A, _U, _B, _Multiplier, _Generator, _Exponent, _Prime) -> ?nif_stub.
srp_value_B_nif(_Multiplier, _Verifier, _Generator, _Exponent, _Prime) -> ?nif_stub.
@@ -1253,10 +1599,12 @@ int_to_bin_neg(X,Ds) ->
int_to_bin_neg(X bsr 8, [(X band 255)|Ds]).
-bin_to_int(Bin) ->
+bin_to_int(Bin) when is_binary(Bin) ->
Bits = bit_size(Bin),
<<Integer:Bits/integer>> = Bin,
- Integer.
+ Integer;
+bin_to_int(undefined) ->
+ undefined.
%% int from integer in a binary with 32bit length
erlint(<<MPIntSize:32/integer,MPIntValue/binary>>) ->
diff --git a/lib/crypto/test/crypto_SUITE.erl b/lib/crypto/test/crypto_SUITE.erl
index 08ecad3233..eddb6b83f9 100644
--- a/lib/crypto/test/crypto_SUITE.erl
+++ b/lib/crypto/test/crypto_SUITE.erl
@@ -76,6 +76,7 @@
rsa_encrypt_decrypt/1,
dh/1,
srp3/1, srp6/1, srp6a/1,
+ ec/1,
exor_test/1,
rc4_test/1,
rc4_stream_test/1,
@@ -105,7 +106,7 @@ groups() ->
rand_uniform_test, strong_rand_test,
rsa_verify_test, dsa_verify_test, rsa_sign_test,
rsa_sign_hash_test, dsa_sign_test, dsa_sign_hash_test,
- rsa_encrypt_decrypt, dh, srp3, srp6, srp6a, exor_test,
+ rsa_encrypt_decrypt, dh, srp3, srp6, srp6a, ec, exor_test,
rc4_test, rc4_stream_test, mod_exp_test, blowfish_cfb64,
smp]}].
@@ -190,8 +191,8 @@ ldd_program() ->
Ldd when is_list(Ldd) -> Ldd
end.
-%%
-%%
+
+
info(doc) ->
["Call the info function."];
info(suite) ->
@@ -207,10 +208,10 @@ info(Config) when is_list(Config) ->
?line [] = Info -- Exports,
?line NotInInfo = Exports -- Info,
io:format("NotInInfo = ~p\n", [NotInInfo]),
- BlackList = lists:sort([des_ede3_cbc_decrypt, des_ede3_cbc_encrypt,
- dh_check, dh_generate_parameters,
- module_info, start, stop, version]),
- ?line BlackList = NotInInfo,
+ %% BlackList = lists:sort([des_ede3_cbc_decrypt, des_ede3_cbc_encrypt,
+ %% dh_check, dh_generate_parameters,
+ %% module_info, start, stop, version]),
+ %% ?line BlackList = NotInInfo,
?line InfoLib = crypto:info_lib(),
?line [_|_] = InfoLib,
@@ -221,10 +222,10 @@ info(Config) when is_list(Config) ->
Me(T,Me);
([],_) ->
ok
- end,
+ end,
?line F(InfoLib,F),
?line crypto:stop()
- end.
+ end.
%%
%%
@@ -359,7 +360,7 @@ hmac_update_sha(Config) when is_list(Config) ->
?line Ctx2 = crypto:hmac_update(Ctx, Data),
?line Ctx3 = crypto:hmac_update(Ctx2, Data2),
?line Mac = crypto:hmac_final(Ctx3),
- ?line Exp = crypto:sha_mac(Key, lists:flatten([Data, Data2])),
+ ?line Exp = crypto:hmac(sha, Key, lists:flatten([Data, Data2])),
?line m(Exp, Mac).
hmac_update_sha256(doc) ->
@@ -381,7 +382,7 @@ hmac_update_sha256_do() ->
?line Ctx2 = crypto:hmac_update(Ctx, Data),
?line Ctx3 = crypto:hmac_update(Ctx2, Data2),
?line Mac = crypto:hmac_final(Ctx3),
- ?line Exp = crypto:sha256_mac(Key, lists:flatten([Data, Data2])),
+ ?line Exp = crypto:hmac(sha256, Key, lists:flatten([Data, Data2])),
?line m(Exp, Mac).
hmac_update_sha512(doc) ->
@@ -403,7 +404,7 @@ hmac_update_sha512_do() ->
?line Ctx2 = crypto:hmac_update(Ctx, Data),
?line Ctx3 = crypto:hmac_update(Ctx2, Data2),
?line Mac = crypto:hmac_final(Ctx3),
- ?line Exp = crypto:sha512_mac(Key, lists:flatten([Data, Data2])),
+ ?line Exp = crypto:hmac(sha512, Key, lists:flatten([Data, Data2])),
?line m(Exp, Mac).
hmac_update_md5(doc) ->
@@ -618,68 +619,64 @@ hmac_rfc4231_sha512(suite) ->
hmac_rfc4231_sha512(Config) when is_list(Config) ->
if_supported(sha512, fun() -> hmac_rfc4231_sha512_do() end).
-hmac_rfc4231_case(Hash, HashFun, case1, Exp) ->
+hmac_rfc4231_case(Hash, case1, Exp) ->
%% Test 1
Key = binary:copy(<<16#0b>>, 20),
Data = <<"Hi There">>,
- hmac_rfc4231_case(Hash, HashFun, Key, Data, Exp);
+ hmac_rfc4231_case(Hash, Key, Data, Exp);
-hmac_rfc4231_case(Hash, HashFun, case2, Exp) ->
+hmac_rfc4231_case(Hash, case2, Exp) ->
%% Test 2
Key = <<"Jefe">>,
Data = <<"what do ya want for nothing?">>,
- hmac_rfc4231_case(Hash, HashFun, Key, Data, Exp);
+ hmac_rfc4231_case(Hash, Key, Data, Exp);
-hmac_rfc4231_case(Hash, HashFun, case3, Exp) ->
+hmac_rfc4231_case(Hash, case3, Exp) ->
%% Test 3
Key = binary:copy(<<16#aa>>, 20),
Data = binary:copy(<<16#dd>>, 50),
- hmac_rfc4231_case(Hash, HashFun, Key, Data, Exp);
+ hmac_rfc4231_case(Hash, Key, Data, Exp);
-hmac_rfc4231_case(Hash, HashFun, case4, Exp) ->
+hmac_rfc4231_case(Hash, case4, Exp) ->
%% Test 4
Key = list_to_binary(lists:seq(1, 16#19)),
Data = binary:copy(<<16#cd>>, 50),
- hmac_rfc4231_case(Hash, HashFun, Key, Data, Exp);
+ hmac_rfc4231_case(Hash, Key, Data, Exp);
-hmac_rfc4231_case(Hash, HashFun, case5, Exp) ->
+hmac_rfc4231_case(Hash, case5, Exp) ->
%% Test 5
Key = binary:copy(<<16#0c>>, 20),
Data = <<"Test With Truncation">>,
- hmac_rfc4231_case(Hash, HashFun, Key, Data, 16, Exp);
+ hmac_rfc4231_case(Hash, Key, Data, 16, Exp);
-hmac_rfc4231_case(Hash, HashFun, case6, Exp) ->
+hmac_rfc4231_case(Hash, case6, Exp) ->
%% Test 6
Key = binary:copy(<<16#aa>>, 131),
Data = <<"Test Using Larger Than Block-Size Key - Hash Key First">>,
- hmac_rfc4231_case(Hash, HashFun, Key, Data, Exp);
+ hmac_rfc4231_case(Hash, Key, Data, Exp);
-hmac_rfc4231_case(Hash, HashFun, case7, Exp) ->
+hmac_rfc4231_case(Hash, case7, Exp) ->
%% Test Case 7
Key = binary:copy(<<16#aa>>, 131),
Data = <<"This is a test using a larger than block-size key and a larger t",
"han block-size data. The key needs to be hashed before being use",
"d by the HMAC algorithm.">>,
- hmac_rfc4231_case(Hash, HashFun, Key, Data, Exp).
+ hmac_rfc4231_case(Hash, Key, Data, Exp).
-hmac_rfc4231_case(Hash, HashFun, Key, Data, Exp) ->
+hmac_rfc4231_case(Hash, Key, Data, Exp) ->
?line Ctx = crypto:hmac_init(Hash, Key),
?line Ctx2 = crypto:hmac_update(Ctx, Data),
?line Mac1 = crypto:hmac_final(Ctx2),
- ?line Mac2 = crypto:HashFun(Key, Data),
?line Mac3 = crypto:hmac(Hash, Key, Data),
?line m(Exp, Mac1),
- ?line m(Exp, Mac2),
?line m(Exp, Mac3).
-hmac_rfc4231_case(Hash, HashFun, Key, Data, Trunc, Exp) ->
+hmac_rfc4231_case(Hash, Key, Data, Trunc, Exp) ->
?line Ctx = crypto:hmac_init(Hash, Key),
?line Ctx2 = crypto:hmac_update(Ctx, Data),
?line Mac1 = crypto:hmac_final_n(Ctx2, Trunc),
- ?line Mac2 = crypto:HashFun(Key, Data, Trunc),
?line Mac3 = crypto:hmac(Hash, Key, Data, Trunc),
?line m(Exp, Mac1),
- ?line m(Exp, Mac2),
?line m(Exp, Mac3).
hmac_rfc4231_sha224_do() ->
@@ -696,7 +693,7 @@ hmac_rfc4231_sha224_do() ->
"d499f112f2d2b7273fa6870e"),
Case7 = hexstr2bin("3a854166ac5d9f023f54d517d0b39dbd"
"946770db9c2b95c9f6f565d1"),
- hmac_rfc4231_cases_do(sha224, sha224_mac, [Case1, Case2, Case3, Case4, Case5, Case6, Case7]).
+ hmac_rfc4231_cases_do(sha224, [Case1, Case2, Case3, Case4, Case5, Case6, Case7]).
hmac_rfc4231_sha256_do() ->
Case1 = hexstr2bin("b0344c61d8db38535ca8afceaf0bf12b"
@@ -712,7 +709,7 @@ hmac_rfc4231_sha256_do() ->
"8e0bc6213728c5140546040f0ee37f54"),
Case7 = hexstr2bin("9b09ffa71b942fcb27635fbcd5b0e944"
"bfdc63644f0713938a7f51535c3a35e2"),
- hmac_rfc4231_cases_do(sha256, sha256_mac, [Case1, Case2, Case3, Case4, Case5, Case6, Case7]).
+ hmac_rfc4231_cases_do(sha256, [Case1, Case2, Case3, Case4, Case5, Case6, Case7]).
hmac_rfc4231_sha384_do() ->
Case1 = hexstr2bin("afd03944d84895626b0825f4ab46907f"
@@ -734,7 +731,7 @@ hmac_rfc4231_sha384_do() ->
Case7 = hexstr2bin("6617178e941f020d351e2f254e8fd32c"
"602420feb0b8fb9adccebb82461e99c5"
"a678cc31e799176d3860e6110c46523e"),
- hmac_rfc4231_cases_do(sha384, sha384_mac, [Case1, Case2, Case3, Case4, Case5, Case6, Case7]).
+ hmac_rfc4231_cases_do(sha384, [Case1, Case2, Case3, Case4, Case5, Case6, Case7]).
hmac_rfc4231_sha512_do() ->
Case1 = hexstr2bin("87aa7cdea5ef619d4ff0b4241a1d6cb0"
@@ -762,16 +759,16 @@ hmac_rfc4231_sha512_do() ->
"debd71f8867289865df5a32d20cdc944"
"b6022cac3c4982b10d5eeb55c3e4de15"
"134676fb6de0446065c97440fa8c6a58"),
- hmac_rfc4231_cases_do(sha512, sha512_mac, [Case1, Case2, Case3, Case4, Case5, Case6, Case7]).
+ hmac_rfc4231_cases_do(sha512, [Case1, Case2, Case3, Case4, Case5, Case6, Case7]).
-hmac_rfc4231_cases_do(Hash, HashFun, CasesData) ->
- hmac_rfc4231_cases_do(Hash, HashFun, [case1, case2, case3, case4, case5, case6, case7], CasesData).
+hmac_rfc4231_cases_do(Hash, CasesData) ->
+ hmac_rfc4231_cases_do(Hash, [case1, case2, case3, case4, case5, case6, case7], CasesData).
-hmac_rfc4231_cases_do(_Hash, _HashFun, _, []) ->
+hmac_rfc4231_cases_do(_Hash, _, []) ->
ok;
-hmac_rfc4231_cases_do(Hash, HashFun, [C|Cases], [D|CasesData]) ->
- hmac_rfc4231_case(Hash, HashFun, C, D),
- hmac_rfc4231_cases_do(Hash, HashFun, Cases, CasesData).
+hmac_rfc4231_cases_do(Hash, [C|Cases], [D|CasesData]) ->
+ hmac_rfc4231_case(Hash, C, D),
+ hmac_rfc4231_cases_do(Hash, Cases, CasesData).
hmac_update_md5_io(doc) ->
["Generate an MD5 HMAC using hmac_init, hmac_update, and hmac_final. "
@@ -858,10 +855,10 @@ sha256(Config) when is_list(Config) ->
if_supported(sha256, fun() -> sha256_do() end).
sha256_do() ->
- ?line m(crypto:sha256("abc"),
+ ?line m(crypto:hash(sha256, "abc"),
hexstr2bin("BA7816BF8F01CFEA4141"
"40DE5DAE2223B00361A396177A9CB410FF61F20015AD")),
- ?line m(crypto:sha256("abcdbcdecdefdefgefghfghighijhijkijkljklmklm"
+ ?line m(crypto:hash(sha256, "abcdbcdecdefdefgefghfghighijhijkijkljklmklm"
"nlmnomnopnopq"),
hexstr2bin("248D6A61D20638B8"
"E5C026930C3E6039A33CE45964FF2167F6ECEDD419DB06C1")).
@@ -877,10 +874,10 @@ sha256_update(Config) when is_list(Config) ->
if_supported(sha256, fun() -> sha256_update_do() end).
sha256_update_do() ->
- ?line Ctx = crypto:sha256_init(),
- ?line Ctx1 = crypto:sha256_update(Ctx, "abcdbcdecdefdefgefghfghighi"),
- ?line Ctx2 = crypto:sha256_update(Ctx1, "jhijkijkljklmklmnlmnomnopnopq"),
- ?line m(crypto:sha256_final(Ctx2),
+ ?line Ctx = crypto:hash_init(sha256),
+ ?line Ctx1 = crypto:hash_update(Ctx, "abcdbcdecdefdefgefghfghighi"),
+ ?line Ctx2 = crypto:hash_update(Ctx1, "jhijkijkljklmklmnlmnomnopnopq"),
+ ?line m(crypto:hash_final(Ctx2),
hexstr2bin("248D6A61D20638B8"
"E5C026930C3E6039A33CE45964FF2167F6ECEDD419DB06C1")).
@@ -896,11 +893,11 @@ sha512(Config) when is_list(Config) ->
if_supported(sha512, fun() -> sha512_do() end).
sha512_do() ->
- ?line m(crypto:sha512("abc"),
+ ?line m(crypto:hash(sha512, "abc"),
hexstr2bin("DDAF35A193617ABACC417349AE20413112E6FA4E89A97EA2"
"0A9EEEE64B55D39A2192992A274FC1A836BA3C23A3FEEBBD"
"454D4423643CE80E2A9AC94FA54CA49F")),
- ?line m(crypto:sha512("abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmn"
+ ?line m(crypto:hash(sha512, "abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmn"
"hijklmnoijklmnopjklmnopqklmnopqrlmnopqrsmnopqrstnopqrstu"),
hexstr2bin("8E959B75DAE313DA8CF4F72814FC143F8F7779C6EB9F7FA1"
"7299AEADB6889018501D289E4900F7E4331B99DEC4B5433A"
@@ -917,10 +914,10 @@ sha512_update(Config) when is_list(Config) ->
if_supported(sha512, fun() -> sha512_update_do() end).
sha512_update_do() ->
- ?line Ctx = crypto:sha512_init(),
- ?line Ctx1 = crypto:sha512_update(Ctx, "abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmn"),
- ?line Ctx2 = crypto:sha512_update(Ctx1, "hijklmnoijklmnopjklmnopqklmnopqrlmnopqrsmnopqrstnopqrstu"),
- ?line m(crypto:sha512_final(Ctx2),
+ ?line Ctx = crypto:hash_init(sha512),
+ ?line Ctx1 = crypto:hash_update(Ctx, "abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmn"),
+ ?line Ctx2 = crypto:hash_update(Ctx1, "hijklmnoijklmnopjklmnopqklmnopqrlmnopqrsmnopqrstnopqrstu"),
+ ?line m(crypto:hash_final(Ctx2),
hexstr2bin("8E959B75DAE313DA8CF4F72814FC143F8F7779C6EB9F7FA1"
"7299AEADB6889018501D289E4900F7E4331B99DEC4B5433A"
"C7D329EEB6DD26545E96E55B874BE909")).
@@ -1629,8 +1626,11 @@ dsa_verify_test(Config) when is_list(Config) ->
BadArg = (catch my_dss_verify(sized_binary(Msg), <<SizeErr:32, SigBlob/binary>>,
ValidKey)),
- ?line m(element(1,element(2,BadArg)), badarg),
-
+ badarg = case element(1,element(2,BadArg)) of
+ badarg -> badarg;
+ function_clause -> badarg;
+ X -> X
+ end,
InValidKey = [crypto:mpint(P_p),
crypto:mpint(Q_p),
crypto:mpint(G_p),
@@ -1663,20 +1663,29 @@ rsa_sign_test(Config) when is_list(Config) ->
Msg = <<"7896345786348756234 Hejsan Svejsan, erlang crypto debugger"
"09812312908312378623487263487623412039812 huagasd">>,
- PrivKey = [crypto:mpint(PubEx), crypto:mpint(Mod), crypto:mpint(PrivEx)],
- PubKey = [crypto:mpint(PubEx), crypto:mpint(Mod)],
- ?line Sig1 = crypto:rsa_sign(sized_binary(Msg), PrivKey),
- ?line m(crypto:rsa_verify(sized_binary(Msg), sized_binary(Sig1),PubKey), true),
+ PrivKey = [PubEx, Mod, PrivEx],
+ PubKey = [PubEx, Mod],
+ PubKeyMpint = map_int_to_mpint(PubKey),
+ Sig1 = crypto:rsa_sign(sized_binary(Msg), map_int_to_mpint(PrivKey)),
+ Sig1 = crypto:sign(rsa, sha, Msg, PrivKey),
+ true = crypto:rsa_verify(sized_binary(Msg), sized_binary(Sig1), PubKeyMpint),
+ true = crypto:verify(rsa, sha, Msg, Sig1, PubKey),
- ?line Sig2 = crypto:rsa_sign(md5, sized_binary(Msg), PrivKey),
- ?line m(crypto:rsa_verify(md5, sized_binary(Msg), sized_binary(Sig2),PubKey), true),
+ Sig2 = crypto:rsa_sign(md5, sized_binary(Msg), map_int_to_mpint(PrivKey)),
+ Sig2 = crypto:sign(rsa, md5, Msg, PrivKey),
+ true = crypto:rsa_verify(md5, sized_binary(Msg), sized_binary(Sig2), PubKeyMpint),
+ true = crypto:verify(rsa, md5, Msg, Sig2, PubKey),
- ?line m(Sig1 =:= Sig2, false),
- ?line m(crypto:rsa_verify(md5, sized_binary(Msg), sized_binary(Sig1),PubKey), false),
- ?line m(crypto:rsa_verify(sha, sized_binary(Msg), sized_binary(Sig1),PubKey), true),
-
+ false = (Sig1 =:= Sig2),
+ false = crypto:rsa_verify(md5, sized_binary(Msg), sized_binary(Sig1), PubKeyMpint),
+ false = crypto:verify(rsa, md5, Msg, Sig1, PubKey),
+ true = crypto:rsa_verify(sha, sized_binary(Msg), sized_binary(Sig1), PubKeyMpint),
+ true = crypto:verify(rsa, sha, Msg, Sig1, PubKey),
+
ok.
-
+map_int_to_mpint(List) ->
+ lists:map(fun(E) -> crypto:mpint(E) end, List).
+
rsa_sign_hash_test(doc) ->
"rsa_sign_hash testing";
rsa_sign_hash_test(suite) ->
@@ -1774,46 +1783,65 @@ rsa_encrypt_decrypt(Config) when is_list(Config) ->
PrivEx = 7531712708607620783801185371644749935066152052780368689827275932079815492940396744378735701395659435842364793962992309884847527234216715366607660219930945,
Mod = 7919488123861148172698919999061127847747888703039837999377650217570191053151807772962118671509138346758471459464133273114654252861270845708312601272799123,
- PrivKey = [crypto:mpint(PubEx), crypto:mpint(Mod), crypto:mpint(PrivEx)],
- PubKey = [crypto:mpint(PubEx), crypto:mpint(Mod)],
+ PrivKey = [PubEx, Mod, PrivEx],
+ PubKey = [PubEx, Mod],
Msg = <<"7896345786348 Asldi">>,
- ?line PKCS1 = crypto:rsa_public_encrypt(Msg, PubKey, rsa_pkcs1_padding),
- ?line PKCS1Dec = crypto:rsa_private_decrypt(PKCS1, PrivKey, rsa_pkcs1_padding),
+ ?line PKCS1 = rsa_public_encrypt(Msg, PubKey, rsa_pkcs1_padding),
+ ?line PKCS1Dec = rsa_private_decrypt(PKCS1, PrivKey, rsa_pkcs1_padding),
io:format("PKCS1Dec ~p~n",[PKCS1Dec]),
?line Msg = PKCS1Dec,
- ?line OAEP = crypto:rsa_public_encrypt(Msg, PubKey, rsa_pkcs1_oaep_padding),
- ?line Msg = crypto:rsa_private_decrypt(OAEP, PrivKey, rsa_pkcs1_oaep_padding),
+ ?line OAEP = rsa_public_encrypt(Msg, PubKey, rsa_pkcs1_oaep_padding),
+ ?line Msg = rsa_private_decrypt(OAEP, PrivKey, rsa_pkcs1_oaep_padding),
<<Msg2Len:32,_/binary>> = crypto:mpint(Mod),
Msg2 = list_to_binary(lists:duplicate(Msg2Len-1, $X)),
- ?line NoPad = crypto:rsa_public_encrypt(Msg2, PubKey, rsa_no_padding),
- ?line NoPadDec = crypto:rsa_private_decrypt(NoPad, PrivKey, rsa_no_padding),
+ ?line NoPad = rsa_public_encrypt(Msg2, PubKey, rsa_no_padding),
+ ?line NoPadDec = rsa_private_decrypt(NoPad, PrivKey, rsa_no_padding),
?line NoPadDec = Msg2,
- ShouldBeError = (catch crypto:rsa_public_encrypt(Msg, PubKey, rsa_no_padding)),
+ ShouldBeError = (catch rsa_public_encrypt(Msg, PubKey, rsa_no_padding)),
?line {'EXIT', {encrypt_failed,_}} = ShouldBeError,
-%% ?line SSL = crypto:rsa_public_encrypt(Msg, PubKey, rsa_sslv23_padding),
-%% ?line Msg = crypto:rsa_private_decrypt(SSL, PrivKey, rsa_sslv23_padding),
+%% ?line SSL = rsa_public_encrypt(Msg, PubKey, rsa_sslv23_padding),
+%% ?line Msg = rsa_private_decrypt(SSL, PrivKey, rsa_sslv23_padding),
- ?line PKCS1_2 = crypto:rsa_private_encrypt(Msg, PrivKey, rsa_pkcs1_padding),
- ?line PKCS1_2Dec = crypto:rsa_public_decrypt(PKCS1_2, PubKey, rsa_pkcs1_padding),
+ ?line PKCS1_2 = rsa_private_encrypt(Msg, PrivKey, rsa_pkcs1_padding),
+ ?line PKCS1_2Dec = rsa_public_decrypt(PKCS1_2, PubKey, rsa_pkcs1_padding),
io:format("PKCS2Dec ~p~n",[PKCS1_2Dec]),
?line Msg = PKCS1_2Dec,
- ?line PKCS1_3 = crypto:rsa_private_encrypt(Msg2, PrivKey, rsa_no_padding),
- ?line PKCS1_3Dec = crypto:rsa_public_decrypt(PKCS1_3, PubKey, rsa_no_padding),
+ ?line PKCS1_3 = rsa_private_encrypt(Msg2, PrivKey, rsa_no_padding),
+ ?line PKCS1_3Dec = rsa_public_decrypt(PKCS1_3, PubKey, rsa_no_padding),
io:format("PKCS2Dec ~p~n",[PKCS1_3Dec]),
?line Msg2 = PKCS1_3Dec,
?line {'EXIT', {encrypt_failed,_}} =
- (catch crypto:rsa_private_encrypt(Msg, PrivKey, rsa_no_padding)),
+ (catch rsa_private_encrypt(Msg, PrivKey, rsa_no_padding)),
ok.
+rsa_public_encrypt(Msg, Key, Pad) ->
+ C1 = crypto:rsa_public_encrypt(Msg, Key, Pad),
+ C2 = crypto:rsa_public_encrypt(Msg, lists:map(fun(E) -> crypto:mpint(E) end, Key), Pad),
+ {C1,C2}.
+
+rsa_public_decrypt(Msg, Key, Pad) ->
+ R = crypto:rsa_public_decrypt(Msg, Key, Pad),
+ R = crypto:rsa_public_decrypt(Msg, lists:map(fun(E) -> crypto:mpint(E) end, Key), Pad).
+
+rsa_private_encrypt(Msg, Key, Pad) ->
+ R = crypto:rsa_private_encrypt(Msg, Key, Pad),
+ R = crypto:rsa_private_encrypt(Msg, lists:map(fun(E) -> crypto:mpint(E) end, Key), Pad).
+
+rsa_private_decrypt({C1,C2}, Key, Pad) ->
+ R = crypto:rsa_private_decrypt(C1, Key, Pad),
+ R = crypto:rsa_private_decrypt(C2, Key, Pad),
+ R = crypto:rsa_private_decrypt(C1, lists:map(fun(E) -> crypto:mpint(E) end, Key), Pad),
+ R = crypto:rsa_private_decrypt(C2, lists:map(fun(E) -> crypto:mpint(E) end, Key), Pad).
+
dh(doc) ->
["Test dh (Diffie-Hellman) functions."];
@@ -1832,13 +1860,16 @@ dh(Config) when is_list(Config) ->
{param, DHPs} ->
timer:sleep(100),
io:format("DHP ~p~n", [DHPs]),
- ?line {Pub1,Priv1} = crypto:dh_generate_key(DHPs),
+ DHPs_mpint = lists:map(fun(E) -> sized_binary(E) end, DHPs),
+ ?line {Pub1,Priv1} = crypto:generate_key(dh, DHPs),
io:format("Key1:~n~p~n~p~n~n", [Pub1,Priv1]),
- ?line {Pub2,Priv2} = crypto:dh_generate_key(DHPs),
+ ?line {Pub2,Priv2} = crypto:dh_generate_key(DHPs_mpint),
io:format("Key2:~n~p~n~p~n~n", [Pub2,Priv2]),
- ?line A = crypto:dh_compute_key(Pub1, Priv2, DHPs),
+ ?line A = crypto:compute_key(dh, Pub1, unsized_binary(Priv2), DHPs),
+ ?line A = crypto:dh_compute_key(sized_binary(Pub1), Priv2, DHPs_mpint),
timer:sleep(100), %% Get another thread see if that triggers problem
- ?line B = crypto:dh_compute_key(Pub2, Priv1, DHPs),
+ ?line B = crypto:compute_key(dh, unsized_binary(Pub2), Priv1, DHPs),
+ ?line B = crypto:dh_compute_key(Pub2, sized_binary(Priv1), DHPs_mpint),
io:format("A ~p~n",[A]),
io:format("B ~p~n",[B]),
?line A = B
@@ -1847,6 +1878,64 @@ dh(Config) when is_list(Config) ->
exit(Pid, kill)
end.
+
+ec(doc) ->
+ ["Test ec (Ecliptic Curve) functions."];
+ec(suite) -> [];
+ec(Config) when is_list(Config) ->
+ if_supported(ec, fun() -> ec_do() end).
+
+ec_do() ->
+ %% test for a name curve
+ {D2_priv, D2_pub} = crypto:generate_key(ecdh, sect113r2),
+ PrivECDH = [D2_priv, sect113r2],
+ PubECDH = [D2_pub, sect113r2],
+ %%TODO: find a published test case for a EC key
+
+ %% test for a full specified curve and public key,
+ %% taken from csca-germany_013_self_signed_cer.pem
+ PubKey = <<16#04, 16#4a, 16#94, 16#49, 16#81, 16#77, 16#9d, 16#df,
+ 16#1d, 16#a5, 16#e7, 16#c5, 16#27, 16#e2, 16#7d, 16#24,
+ 16#71, 16#a9, 16#28, 16#eb, 16#4d, 16#7b, 16#67, 16#75,
+ 16#ae, 16#09, 16#0a, 16#51, 16#45, 16#19, 16#9b, 16#d4,
+ 16#7e, 16#a0, 16#81, 16#e5, 16#5e, 16#d4, 16#a4, 16#3f,
+ 16#60, 16#7c, 16#6a, 16#50, 16#ee, 16#36, 16#41, 16#8a,
+ 16#87, 16#ff, 16#cd, 16#a6, 16#10, 16#39, 16#ca, 16#95,
+ 16#76, 16#7d, 16#ae, 16#ca, 16#c3, 16#44, 16#3f, 16#e3, 16#2c>>,
+ <<P:264/integer>> = <<16#00, 16#a9, 16#fb, 16#57, 16#db, 16#a1, 16#ee, 16#a9,
+ 16#bc, 16#3e, 16#66, 16#0a, 16#90, 16#9d, 16#83, 16#8d,
+ 16#72, 16#6e, 16#3b, 16#f6, 16#23, 16#d5, 16#26, 16#20,
+ 16#28, 16#20, 16#13, 16#48, 16#1d, 16#1f, 16#6e, 16#53, 16#77>>,
+ <<A:256/integer>> = <<16#7d, 16#5a, 16#09, 16#75, 16#fc, 16#2c, 16#30, 16#57,
+ 16#ee, 16#f6, 16#75, 16#30, 16#41, 16#7a, 16#ff, 16#e7,
+ 16#fb, 16#80, 16#55, 16#c1, 16#26, 16#dc, 16#5c, 16#6c,
+ 16#e9, 16#4a, 16#4b, 16#44, 16#f3, 16#30, 16#b5, 16#d9>>,
+ <<B:256/integer>> = <<16#26, 16#dc, 16#5c, 16#6c, 16#e9, 16#4a, 16#4b, 16#44,
+ 16#f3, 16#30, 16#b5, 16#d9, 16#bb, 16#d7, 16#7c, 16#bf,
+ 16#95, 16#84, 16#16, 16#29, 16#5c, 16#f7, 16#e1, 16#ce,
+ 16#6b, 16#cc, 16#dc, 16#18, 16#ff, 16#8c, 16#07, 16#b6>>,
+ BasePoint = <<16#04, 16#8b, 16#d2, 16#ae, 16#b9, 16#cb, 16#7e, 16#57,
+ 16#cb, 16#2c, 16#4b, 16#48, 16#2f, 16#fc, 16#81, 16#b7,
+ 16#af, 16#b9, 16#de, 16#27, 16#e1, 16#e3, 16#bd, 16#23,
+ 16#c2, 16#3a, 16#44, 16#53, 16#bd, 16#9a, 16#ce, 16#32,
+ 16#62, 16#54, 16#7e, 16#f8, 16#35, 16#c3, 16#da, 16#c4,
+ 16#fd, 16#97, 16#f8, 16#46, 16#1a, 16#14, 16#61, 16#1d,
+ 16#c9, 16#c2, 16#77, 16#45, 16#13, 16#2d, 16#ed, 16#8e,
+ 16#54, 16#5c, 16#1d, 16#54, 16#c7, 16#2f, 16#04, 16#69, 16#97>>,
+ <<Order:264/integer>> = <<16#00, 16#a9, 16#fb, 16#57, 16#db, 16#a1, 16#ee, 16#a9,
+ 16#bc, 16#3e, 16#66, 16#0a, 16#90, 16#9d, 16#83, 16#8d,
+ 16#71, 16#8c, 16#39, 16#7a, 16#a3, 16#b5, 16#61, 16#a6,
+ 16#f7, 16#90, 16#1e, 16#0e, 16#82, 16#97, 16#48, 16#56, 16#a7>>,
+ CoFactor = 1,
+ Curve = {{prime_field,P},{A,B,none},BasePoint, Order,CoFactor},
+
+ Msg = <<99,234,6,64,190,237,201,99,80,248,58,40,70,45,149,218,5,246,242,63>>,
+ Sign = crypto:sign(ecdsa, sha, Msg, PrivECDH),
+ ?line true = crypto:verify(ecdsa, sha, Msg, Sign, PubECDH),
+ ?line false = crypto:verify(ecdsa, sha, Msg, <<10,20>>, PubECDH),
+
+ ok.
+
srp3(doc) ->
["SRP-3 test vectors generated by http://srp.stanford.edu/demo/demo.html"];
srp3(suite) -> [];
@@ -1890,15 +1979,15 @@ srp3(Config) when is_list(Config) ->
"9176A9192615DC0277AE7C12F1F6A7F6563FCA11675D809AF578BDE5"
"2B51E05D440B63099A017A0B45044801"),
UserPassHash = crypto:sha([Salt, crypto:sha([Username, <<$:>>, Password])]),
- Verifier = crypto:mod_exp_prime(Generator, UserPassHash, Prime),
- ClientPublic = crypto:mod_exp_prime(Generator, ClientPrivate, Prime),
+ Verifier = crypto:mod_pow(Generator, UserPassHash, Prime),
+ ClientPublic = crypto:mod_pow(Generator, ClientPrivate, Prime),
- {ClientPublic, ClientPrivate} = crypto:srp_generate_key(Generator, Prime, Version, ClientPrivate),
- {ServerPublic, ServerPrivate} = crypto:srp_generate_key(Verifier, Generator, Prime, Version, ServerPrivate),
- SessionKey = crypto:srp_compute_key(UserPassHash, Prime, Generator, ClientPublic,
- ClientPrivate, ServerPublic, Version, Scrambler),
- SessionKey = crypto:srp_compute_key(Verifier, Prime, ClientPublic,
- ServerPublic, ServerPrivate, Version, Scrambler).
+ {ClientPublic, ClientPrivate} = crypto:generate_key(srp, {user, [Generator, Prime, Version]}, ClientPrivate),
+ {ServerPublic, ServerPrivate} = crypto:generate_key(srp, {host, [Verifier, Generator, Prime, Version]}, ServerPrivate),
+ SessionKey = crypto:compute_key(srp, ServerPublic, {ClientPublic, ClientPrivate},
+ {user, [UserPassHash, Prime, Generator, Version, Scrambler]}),
+ SessionKey = crypto:compute_key(srp, ClientPublic, {ServerPublic, ServerPrivate},
+ {host, [Verifier, Prime, Version, Scrambler]}).
srp6(doc) ->
["SRP-6 test vectors generated by http://srp.stanford.edu/demo/demo.html"];
@@ -1941,15 +2030,15 @@ srp6(Config) when is_list(Config) ->
"72E992AAD89095A84B6A5FADA152369AB1E350A03693BEF044DF3EDF"
"0C34741F4696C30E9F675D09F58ACBEB"),
UserPassHash = crypto:sha([Salt, crypto:sha([Username, <<$:>>, Password])]),
- Verifier = crypto:mod_exp_prime(Generator, UserPassHash, Prime),
- ClientPublic = crypto:mod_exp_prime(Generator, ClientPrivate, Prime),
+ Verifier = crypto:mod_pow(Generator, UserPassHash, Prime),
+ ClientPublic = crypto:mod_pow(Generator, ClientPrivate, Prime),
- {ClientPublic, ClientPrivate} = crypto:srp_generate_key(Generator, Prime, Version, ClientPrivate),
- {ServerPublic, ServerPrivate} = crypto:srp_generate_key(Verifier, Generator, Prime, Version, ServerPrivate),
- SessionKey = crypto:srp_compute_key(UserPassHash, Prime, Generator, ClientPublic,
- ClientPrivate, ServerPublic, Version, Scrambler),
- SessionKey = crypto:srp_compute_key(Verifier, Prime, ClientPublic,
- ServerPublic, ServerPrivate, Version, Scrambler).
+ {ClientPublic, ClientPrivate} = crypto:generate_key(srp, {user, [Generator, Prime, Version]}, ClientPrivate),
+ {ServerPublic, ServerPrivate} = crypto:generate_key(srp, {host, [Verifier, Generator, Prime, Version]}, ServerPrivate),
+ SessionKey = crypto:compute_key(srp, ServerPublic, {ClientPublic, ClientPrivate},
+ {user, [UserPassHash, Prime, Generator, Version, Scrambler]}),
+ SessionKey = crypto:compute_key(srp, ClientPublic, {ServerPublic, ServerPrivate},
+ {host, [Verifier, Prime, Version, Scrambler]}).
srp6a(doc) ->
["SRP-6a test vectors from RFC5054."];
@@ -1992,15 +2081,15 @@ srp6a(Config) when is_list(Config) ->
"3499B200210DCC1F10EB33943CD67FC88A2F39A4BE5BEC4EC0A3212D"
"C346D7E474B29EDE8A469FFECA686E5A"),
UserPassHash = crypto:sha([Salt, crypto:sha([Username, <<$:>>, Password])]),
- Verifier = crypto:mod_exp_prime(Generator, UserPassHash, Prime),
+ Verifier = crypto:mod_pow(Generator, UserPassHash, Prime),
- {ClientPublic, ClientPrivate} = crypto:srp_generate_key(Generator, Prime, Version, ClientPrivate),
- {ServerPublic, ServerPrivate} = crypto:srp_generate_key(Verifier, Generator, Prime, Version, ServerPrivate),
+ {ClientPublic, ClientPrivate} = crypto:generate_key(srp, {user, [Generator, Prime, Version]}, ClientPrivate),
+ {ServerPublic, ServerPrivate} = crypto:generate_key(srp, {host, [Verifier, Generator, Prime, Version]}, ServerPrivate),
- SessionKey = crypto:srp_compute_key(UserPassHash, Prime, Generator, ClientPublic,
- ClientPrivate, ServerPublic, Version, Scrambler),
- SessionKey = crypto:srp_compute_key(Verifier, Prime, ClientPublic,
- ServerPublic, ServerPrivate, Version, Scrambler).
+ SessionKey = crypto:compute_key(srp, ServerPublic, {ClientPublic, ClientPrivate},
+ {user, [UserPassHash, Prime, Generator, Version, Scrambler]}),
+ SessionKey = crypto:compute_key(srp, ClientPublic, {ServerPublic, ServerPrivate},
+ {host, [Verifier, Prime, Version, Scrambler]}).
%%
%%
@@ -2195,6 +2284,9 @@ sized_binary(Binary) when is_binary(Binary) ->
sized_binary(List) ->
sized_binary(list_to_binary(List)).
+unsized_binary(<<Sz:32/integer, Binary:Sz/binary>>) ->
+ Binary.
+
xor_bytes(Bin1, Bin2) when is_binary(Bin1), is_binary(Bin2) ->
L1 = binary_to_list(Bin1),
L2 = binary_to_list(Bin2),
diff --git a/lib/dialyzer/src/dialyzer_gui.erl b/lib/dialyzer/src/dialyzer_gui.erl
index ac9844c22c..97e5752577 100644
--- a/lib/dialyzer/src/dialyzer_gui.erl
+++ b/lib/dialyzer/src/dialyzer_gui.erl
@@ -2,7 +2,7 @@
%%------------------------------------------------------------------------
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2006-2012. All Rights Reserved.
+%% Copyright Ericsson AB 2006-2013. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -1331,7 +1331,8 @@ build_analysis_record(#gui_state{mode = Mode, menu = Menu, options = Options,
#analysis{defines = Options#options.defines,
include_dirs = Options#options.include_dirs,
plt = InitPlt,
- start_from = StartFrom}.
+ start_from = StartFrom,
+ solvers = Options#options.solvers}.
get_anal_files(#gui_state{chosen_box = ChosenBox}, StartFrom) ->
Files = gs:read(ChosenBox, items),
diff --git a/lib/dialyzer/src/dialyzer_gui_wx.erl b/lib/dialyzer/src/dialyzer_gui_wx.erl
index c6f7c56227..08f31c1e13 100644
--- a/lib/dialyzer/src/dialyzer_gui_wx.erl
+++ b/lib/dialyzer/src/dialyzer_gui_wx.erl
@@ -2,7 +2,7 @@
%%------------------------------------------------------------------------
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2009-2012. All Rights Reserved.
+%% Copyright Ericsson AB 2009-2013. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -810,7 +810,8 @@ build_analysis_record(#gui_state{mode = Mode, menu = Menu, options = Options,
#analysis{defines = Options#options.defines,
include_dirs = Options#options.include_dirs,
plt = InitPlt,
- start_from = StartFrom}.
+ start_from = StartFrom,
+ solvers = Options#options.solvers}.
get_anal_files(#gui_state{files_to_analyze = Files}, StartFrom) ->
FilteredMods =
diff --git a/lib/erl_interface/src/connect/ei_connect.c b/lib/erl_interface/src/connect/ei_connect.c
index 3ab86bb340..8f1f231b82 100644
--- a/lib/erl_interface/src/connect/ei_connect.c
+++ b/lib/erl_interface/src/connect/ei_connect.c
@@ -830,7 +830,8 @@ int ei_accept_tmo(ei_cnode* ec, int lfd, ErlConnect *conp, unsigned ms)
error:
EI_TRACE_ERR0("ei_accept","<- ACCEPT failed");
- closesocket(fd);
+ if (fd>=0)
+ closesocket(fd);
return ERL_ERROR;
} /* ei_accept */
diff --git a/lib/et/doc/src/et_desc.xmlsrc b/lib/et/doc/src/et_desc.xmlsrc
index c02517ae01..36274f6316 100644
--- a/lib/et/doc/src/et_desc.xmlsrc
+++ b/lib/et/doc/src/et_desc.xmlsrc
@@ -150,7 +150,7 @@
NewEvent = #event{}]]></code>
<p>The interface of the filter function is the same as the the
- filter functions for the good old <c>lists:zf/2</c>. If the filter
+ filter functions for the good old <c>lists:filtermap/2</c>. If the filter
returns <c>false</c> it means that the trace data should silently
be dropped. <c>true</c> means that the trace data data already is
an <c>Event Record</c> and that it should be kept as it is.
diff --git a/lib/ic/java_src/com/ericsson/otp/ic/Environment.java b/lib/ic/java_src/com/ericsson/otp/ic/Environment.java
index fff854a5f8..4b321fbce7 100644
--- a/lib/ic/java_src/com/ericsson/otp/ic/Environment.java
+++ b/lib/ic/java_src/com/ericsson/otp/ic/Environment.java
@@ -135,8 +135,8 @@ public class Environment {
if (connection == null)
connection = self.connect(peer);
- clientP = new com.ericsson.otp.erlang.OtpErlangPid(self); /* This is not perfect */
- send_ref = new com.ericsson.otp.erlang.OtpErlangRef(self);
+ clientP = self.createPid(); /* This is not perfect */
+ send_ref = self.createRef();
}
diff --git a/lib/ic/src/icparse.yrl b/lib/ic/src/icparse.yrl
index d0dd6cde4c..b0286d57f4 100644
--- a/lib/ic/src/icparse.yrl
+++ b/lib/ic/src/icparse.yrl
@@ -230,6 +230,9 @@ Terminals
Rootsymbol '<specification>'.
+Expect 9.
+
+
%%------------------------------------------------------------
%% Clauses
%%
diff --git a/lib/jinterface/test/jinterface_SUITE.erl b/lib/jinterface/test/jinterface_SUITE.erl
index b438da12d0..de8d611efc 100644
--- a/lib/jinterface/test/jinterface_SUITE.erl
+++ b/lib/jinterface/test/jinterface_SUITE.erl
@@ -180,7 +180,7 @@ init_per_testcase(Case, _Config)
Case =:= kill_mbox_from_erlang ->
{skip, "Not yet implemented"};
init_per_testcase(_Case,Config) ->
- Dog = ?t:timetrap({seconds,10}),
+ Dog = ?t:timetrap({seconds,30}),
[{watch_dog,Dog}|Config].
end_per_testcase(_Case,Config) ->
@@ -188,6 +188,7 @@ end_per_testcase(_Case,Config) ->
undefined -> ok;
Pid -> exit(Pid,kill)
end,
+ jitu:kill_all_jnodes(),
?t:timetrap_cancel(?config(watch_dog,Config)),
ok.
diff --git a/lib/jinterface/test/jitu.erl b/lib/jinterface/test/jitu.erl
index 0e1af0ff22..a029c063bc 100644
--- a/lib/jinterface/test/jitu.erl
+++ b/lib/jinterface/test/jitu.erl
@@ -27,7 +27,10 @@
java/4,
java/5,
init_all/1,
- finish_all/1]).
+ finish_all/1,
+ kill_all_jnodes/0]).
+
+-include("ct.hrl").
%%
%% Lots of stuff here are originating from java_client_erl_server_SUITE.erl
@@ -51,10 +54,33 @@ java(Java, Dir, Class, Args, Props) ->
init_all(Config) when is_list(Config) ->
case find_executable(["java"]) of
false -> {skip,"Found no Java VM"};
- Path -> [{java,Path}|Config]
+ Path ->
+ Pid = spawn(fun() ->
+ ets:new(jitu_tab,[set,named_table,public]),
+ receive stop -> ets:delete(jitu_tab) end
+ end),
+ [{java,Path},{tab_proc,Pid}|Config]
end.
-finish_all(Config) -> Config.
+finish_all(Config) ->
+ kill_all_jnodes(),
+ ?config(tab_proc,Config) ! stop,
+ Config.
+
+kill_all_jnodes() ->
+ Jnodes = ets:tab2list(jitu_tab),
+ [begin
+% ct:pal("Killing OsPid=~w started with ~p",[OsPid,_Cmd]),
+ kill_os_process(os:type(),integer_to_list(OsPid))
+ end || {OsPid,_Cmd} <- Jnodes],
+ ets:delete_all_objects(jitu_tab),
+ ok.
+
+kill_os_process({win32,_},OsPid) ->
+ os:cmd("taskkill /PID " ++ OsPid);
+kill_os_process(_,OsPid) ->
+ os:cmd("kill " ++ OsPid).
+
%%
%% Internal stuff...
@@ -110,6 +136,12 @@ cmd(Cmd) ->
io:format("cmd: ~s~n", [Cmd]),
case catch open_port({spawn,Cmd}, PortOpts) of
Port when is_port(Port) ->
+ case erlang:port_info(Port,os_pid) of
+ {os_pid,OsPid} ->
+ ets:insert(jitu_tab,{OsPid,Cmd});
+ _ ->
+ ok
+ end,
Result = cmd_loop(Port, []),
io:format("cmd res: ~w~n", [Result]),
case Result of
diff --git a/lib/jinterface/test/nc_SUITE.erl b/lib/jinterface/test/nc_SUITE.erl
index 63c78ebdaa..f1493a3cc9 100644
--- a/lib/jinterface/test/nc_SUITE.erl
+++ b/lib/jinterface/test/nc_SUITE.erl
@@ -105,12 +105,13 @@ end_per_suite(Config) ->
init_per_testcase(Case, Config) ->
T = case atom_to_list(Case) of
"unicode"++_ -> 240;
- _ -> 30
+ _ -> 120
end,
WatchDog = test_server:timetrap(test_server:seconds(T)),
[{watchdog, WatchDog}| Config].
end_per_testcase(_Case, Config) ->
+ jitu:kill_all_jnodes(),
WatchDog = ?config(watchdog, Config),
test_server:timetrap_cancel(WatchDog).
@@ -695,15 +696,18 @@ run_server(Server, Config, Action, ExtraArgs) ->
true = register(Name, self()),
JName = make_name(),
spawn_link(fun () ->
+ %% Setting max memory to 256. This is due to
+ %% echo_server sometimes failing with
+ %% OutOfMemoryException one some test machines.
ok = jitu:java(?config(java, Config),
?config(data_dir, Config),
atom_to_list(Server),
[JName,
erlang:get_cookie(),
node(),
- Name]++ExtraArgs
- ),
- %,"-DOtpConnection.trace=3"),
+ Name]++ExtraArgs,
+ " -Xmx256m"),
+ %% " -Xmx256m -DOtpConnection.trace=3"),
Name ! {done, JName}
end),
receive
diff --git a/lib/kernel/doc/src/inet.xml b/lib/kernel/doc/src/inet.xml
index 541500a300..7cd98914d1 100644
--- a/lib/kernel/doc/src/inet.xml
+++ b/lib/kernel/doc/src/inet.xml
@@ -559,7 +559,7 @@ fe80::204:acff:fe17:bf38
<c>[Byte1,Byte2|Binary]</c>.</p>
</item>
- <tag><c>{high_msgq_watermark, Size}</c> (TCP/IP sockets)</tag>
+ <tag><c>{high_msgq_watermark, Size}</c></tag>
<item>
<p>The socket message queue will be set into a busy
state when the amount of data queued on the message
@@ -674,7 +674,7 @@ fe80::204:acff:fe17:bf38
the flushing time-out in seconds.</p>
</item>
- <tag><c>{low_msgq_watermark, Size}</c> (TCP/IP sockets)</tag>
+ <tag><c>{low_msgq_watermark, Size}</c></tag>
<item>
<p>If the socket message queue is in a busy state, the
socket message queue will be set in a not busy state when
diff --git a/lib/kernel/src/gen_sctp.erl b/lib/kernel/src/gen_sctp.erl
index 74ad192802..acc116df84 100644
--- a/lib/kernel/src/gen_sctp.erl
+++ b/lib/kernel/src/gen_sctp.erl
@@ -39,7 +39,9 @@
{active, true | false | once} |
{buffer, non_neg_integer()} |
{dontroute, boolean()} |
+ {high_msgq_watermark, pos_integer()} |
{linger, {boolean(), non_neg_integer()}} |
+ {low_msgq_watermark, pos_integer()} |
{mode, list | binary} | list | binary |
{priority, non_neg_integer()} |
{recbuf, non_neg_integer()} |
@@ -68,7 +70,9 @@
active |
buffer |
dontroute |
+ high_msgq_watermark |
linger |
+ low_msgq_watermark |
mode |
priority |
recbuf |
diff --git a/lib/kernel/src/gen_udp.erl b/lib/kernel/src/gen_udp.erl
index c5a1173575..fb5737f82e 100644
--- a/lib/kernel/src/gen_udp.erl
+++ b/lib/kernel/src/gen_udp.erl
@@ -34,6 +34,8 @@
{dontroute, boolean()} |
{drop_membership, {inet:ip_address(), inet:ip_address()}} |
{header, non_neg_integer()} |
+ {high_msgq_watermark, pos_integer()} |
+ {low_msgq_watermark, pos_integer()} |
{mode, list | binary} | list | binary |
{multicast_if, inet:ip_address()} |
{multicast_loop, boolean()} |
@@ -56,6 +58,8 @@
deliver |
dontroute |
header |
+ high_msgq_watermark |
+ low_msgq_watermark |
mode |
multicast_if |
multicast_loop |
diff --git a/lib/kernel/src/inet.erl b/lib/kernel/src/inet.erl
index 9670271b2e..aada1252ad 100644
--- a/lib/kernel/src/inet.erl
+++ b/lib/kernel/src/inet.erl
@@ -712,7 +712,8 @@ udp_options() ->
[tos, priority, reuseaddr, sndbuf, recbuf, header, active, buffer, mode,
deliver, ipv6_v6only,
broadcast, dontroute, multicast_if, multicast_ttl, multicast_loop,
- add_membership, drop_membership, read_packets,raw].
+ add_membership, drop_membership, read_packets,raw,
+ high_msgq_watermark, low_msgq_watermark].
udp_options(Opts, Family) ->
@@ -766,7 +767,7 @@ udp_add(Name, Val, R, Opts, As) ->
sctp_options() ->
[ % The following are generic inet options supported for SCTP sockets:
mode, active, buffer, tos, priority, dontroute, reuseaddr, linger, sndbuf,
- recbuf, ipv6_v6only,
+ recbuf, ipv6_v6only, high_msgq_watermark, low_msgq_watermark,
% Other options are SCTP-specific (though they may be similar to their
% TCP and UDP counter-parts):
diff --git a/lib/kernel/src/inet_int.hrl b/lib/kernel/src/inet_int.hrl
index 000119bc74..a01c733d81 100644
--- a/lib/kernel/src/inet_int.hrl
+++ b/lib/kernel/src/inet_int.hrl
@@ -141,8 +141,8 @@
-define(INET_LOPT_READ_PACKETS, 33).
-define(INET_OPT_RAW, 34).
-define(INET_LOPT_TCP_SEND_TIMEOUT_CLOSE, 35).
--define(INET_LOPT_TCP_MSGQ_HIWTRMRK, 36).
--define(INET_LOPT_TCP_MSGQ_LOWTRMRK, 37).
+-define(INET_LOPT_MSGQ_HIWTRMRK, 36).
+-define(INET_LOPT_MSGQ_LOWTRMRK, 37).
% Specific SCTP options: separate range:
-define(SCTP_OPT_RTOINFO, 100).
-define(SCTP_OPT_ASSOCINFO, 101).
diff --git a/lib/kernel/test/inet_sockopt_SUITE.erl b/lib/kernel/test/inet_sockopt_SUITE.erl
index 75496ce745..185751fead 100644
--- a/lib/kernel/test/inet_sockopt_SUITE.erl
+++ b/lib/kernel/test/inet_sockopt_SUITE.erl
@@ -772,8 +772,10 @@ all_listen_options() ->
{mode,list,binary,true,true},
{deliver,term,port,true,true},
{exit_on_close, true, false, true, true},
- %{high_watermark,4096,8192,true,true},
- %{low_watermark,2048,4096,true,true},
+ {high_watermark,4096,8192,true,true},
+ {low_watermark,2048,4096,true,true},
+ {high_msgq_watermark,4096,8192,true,true},
+ {low_msgq_watermark,2048,4096,true,true},
{send_timeout,infinity,1000,true,true},
{send_timeout_close,false,true,true,true},
{delay_send,false,true,true,true},
@@ -797,6 +799,8 @@ all_connect_options() ->
{exit_on_close, true, false, true, true},
{high_watermark,4096,8192,false,true},
{low_watermark,2048,4096,false,true},
+ {high_msgq_watermark,4096,8192,true,true},
+ {low_msgq_watermark,2048,4096,true,true},
{send_timeout,infinity,1000,true,true},
{send_timeout_close,false,true,true,true},
{delay_send,false,true,true,true},
diff --git a/lib/megaco/.gitignore b/lib/megaco/.gitignore
index 1c5979cd62..3e64dc20f5 100644
--- a/lib/megaco/.gitignore
+++ b/lib/megaco/.gitignore
@@ -1,3 +1,38 @@
+# Files generated by configure.
+/configure
+/config.log
+/config.status
+
+# Files generated when building/running tests
+/test/*.log
+/test/*.beam
+
+# Generated documentation. (ie. not doc/src)
+/doc/[^s]*
+
+# Library links
+/priv/lib/*.so
+
+# Generated text src
+/src/text/megaco_text_mini_parser.erl
+/src/text/megaco_text_parser_*.erl
+
+# Generated binary src and stuff...
+# /src/binary/megaco_per_media_gateway_control_*.erl
+# /src/binary/megaco_per_media_gateway_control_*.asn1db
+/src/binary/megaco_*_media_gateway_control_*.hrl
+/src/binary/megaco_*_media_gateway_control_*.erl
+/src/binary/megaco_*_media_gateway_control_*.asn1db
+
+# Generated binary src and stuff...
+/src/flex/megaco_flex_scanner_drv.c
+/src/flex/megaco_flex_scanner_drv.flex
+/src/flex/megaco_flex_scanner_drv_mt.c
+/src/flex/megaco_flex_scanner_drv_mt.flex
+
+# Generated examples stuff...
examples/meas/Makefile
examples/meas/meas.sh.skel
examples/meas/mstone1.sh.skel
+
+
diff --git a/lib/megaco/doc/src/Makefile b/lib/megaco/doc/src/Makefile
index f35413a4fd..ea2284e89b 100644
--- a/lib/megaco/doc/src/Makefile
+++ b/lib/megaco/doc/src/Makefile
@@ -1,7 +1,7 @@
#
# %CopyrightBegin%
#
-# Copyright Ericsson AB 2000-2012. All Rights Reserved.
+# Copyright Ericsson AB 2000-2013. All Rights Reserved.
#
# The contents of this file are subject to the Erlang Public License,
# Version 1.1, (the "License"); you may not use this file except in
@@ -123,9 +123,6 @@ imgs: $(IMG_FILES:%=$(HTMLDIR)/%)
man: $(MAN3_FILES)
$(INDEX_TARGET): $(INDEX_SRC) $(APP_FILE)
- sed -e 's/%VSN%/$(VSN)/' $< > $@
-
-$(INDEX_TARGET): $(INDEX_SRC) $(APP_FILE)
sed -e 's/%VSN%/$(VSN)/' \
-e 's/%ERLANG_SITE%/www\.erlang\.se\//' \
-e 's/%UP_ONE_LEVEL%/..\/..\/..\/doc\/index.html/' \
diff --git a/lib/megaco/doc/src/notes.xml b/lib/megaco/doc/src/notes.xml
index bb30ce4c2a..91905b76f7 100644
--- a/lib/megaco/doc/src/notes.xml
+++ b/lib/megaco/doc/src/notes.xml
@@ -36,24 +36,138 @@
section is the version number of Megaco.</p>
+ <section><title>Megaco 3.17</title>
+
+ <p>Version 3.17 supports code replacement in runtime from/to
+ version 3.16.0.3 and and 3.16.0.2. </p>
+
+ <section>
+ <title>Improvements and new features</title>
+
+ <p>-</p>
+
+<!--
+ <list type="bulleted">
+ <item>
+ <p>Allow whitespaces in installation path. </p>
+ <p>It is now possible to give configure and make an
+ installation/release path with whitespaces in it. </p>
+ <p>Own Id: OTP-10107</p>
+ </item>
+
+ </list>
+-->
+
+ </section>
+
+ <section>
+ <title>Fixed bugs and malfunctions</title>
+
+ <!--
+ <p>-</p>
+ -->
+
+ <list type="bulleted">
+ <item>
+ <p>Buffer overrun error while flex scanner processing
+ property parm groups. </p>
+ <p>This error occured only for large messages if a
+ buffer realloc was needed while processing the
+ property parm groups. </p>
+ <p>Own Id: OTP-10998</p>
+ <p>Aux Id: Seq 12263</p>
+ </item>
+
+ </list>
+
+ </section>
+
+ <section>
+ <title>Incompatibilities</title>
+ <p>-</p>
+
+<!--
+ <list type="bulleted">
+ <item>
+ <p>A number of binary encoding alternatives has been removed.
+ The binary encoding option <c>driver</c> has been removed
+ since this (the use of the asn1 linked in driver) is
+ now default and there is now way to <em>not</em> use it.
+ See <seealso marker="megaco_encode#binary_config">configuration of binary encoding</seealso> for more info. </p>
+ </item>
+
+ </list>
+-->
+
+ </section>
+
+ </section> <!-- 3.17 -->
+
+
<section><title>Megaco 3.16.0.3</title>
- <section><title>Improvements and New Features</title>
- <list>
+ <p>Version 3.16.0.2 supports code replacement in runtime from/to
+ version 3.16.0.1, 3.16, 3.15.1.1, 3.15.1 and 3.15.</p>
+
+ <section>
+ <title>Improvements and new features</title>
+
+<!--
+ <p>-</p>
+-->
+
+ <list type="bulleted">
<item>
- <p>Where necessary a comment stating encoding has been
- added to Erlang files. The comment is meant to be removed
- in Erlang/OTP R17B when UTF-8 becomes the default
- encoding. </p>
- <p>
- Own Id: OTP-10630</p>
+ <p>Where necessary, a comment stating encoding has been
+ added to Erlang files. The comment is meant to be removed
+ in Erlang/OTP R17B when UTF-8 becomes the default encoding. </p>
+ <p>Own Id: OTP-10630</p>
</item>
+
+ </list>
+
+ </section>
+
+ <section>
+ <title>Fixed bugs and malfunctions</title>
+
+ <p>-</p>
+
+ <!--
+ <list type="bulleted">
+ <item>
+ <p>Fixing miscellaneous things detected by dialyzer. </p>
+ <p>Own Id: OTP-9075</p>
+ </item>
+
</list>
+ -->
+
</section>
-</section>
+ <section>
+ <title>Incompatibilities</title>
+<!--
+ <p>-</p>
+-->
+
+ <list type="bulleted">
+ <item>
+ <p>A number of binary encoding alternatives has been removed.
+ The binary encoding option <c>driver</c> has been removed
+ since this (the use of the asn1 linked in driver) is
+ now default and there is now way to <em>not</em> use it.
+ See <seealso marker="megaco_encode#binary_config">configuration of binary encoding</seealso> for more info. </p>
+ </item>
+
+ </list>
-<section><title>Megaco 3.16.0.2</title>
+ </section>
+
+ </section> <!-- 3.16.0.3 -->
+
+
+ <section><title>Megaco 3.16.0.2</title>
<p>Version 3.16.0.2 supports code replacement in runtime from/to
version 3.16.0.1, 3.16, 3.15.1.1, 3.15.1 and 3.15.</p>
@@ -657,653 +771,6 @@
</section> <!-- 3.13 -->
- <section>
- <title>Megaco 3.12</title>
-
-<!--
- <p>Version 3.12 supports code replacement in runtime from/to
- version 3.11.3.</p>
--->
-
- <section>
- <title>Improvements and new features</title>
-<!--
- <p>-</p>
--->
-
- <list type="bulleted">
- <item>
- <p>Improve handling of async transaction reply. </p>
- <p>For asynchronous requests, issued using
- <seealso marker="megaco#cast">megaco:cast/3</seealso>,
- the reply will be delivered using the
- <seealso marker="megaco_user#trans_reply">handle_trans_reply/4,5</seealso>
- callback function. </p>
- <p>If a receiver of a request, issued using
- <seealso marker="megaco#cast">megaco:cast/3</seealso>,
- does not reply in time, megaco re-sends the request.
- If the receiver of the request sends the reply at the same
- time as megaco re-sends, it may also send a reply to the
- resent request (thinking the first reply got lost). These
- two replies may arrive more or less at the same time,
- causing confusion. </p>
- <p>In order to improve this situation, a number of
- improvements have been done: </p>
- <list type="bulleted">
- <item>
- <p>When the first reply arrives, a timer, request-keep-alive,
- is started. This timer is used to decide when to stop
- accepting replies as legitimate. </p>
- <p>The timeout time for the timer is specified by the
- config option <em>request_keep_alive_timout</em>,
- which can be set per
- <seealso marker="megaco#ui_request_keep_alive_timeout">user</seealso>
- or per
- <seealso marker="megaco#ci_request_keep_alive_timeout">connection</seealso>. </p>
- </item>
- <item>
- <p>We also keep track of how many replies has been received
- (we do this as long as the request-keep-alive timer is
- running). </p>
- </item>
- <item>
- <p>Each reply that arrives while the request-keep-alive timer
- is running (including the first) will be delivered using the
- <seealso marker="megaco_user#trans_reply">handle_trans_reply/4,5</seealso>
- callback function, but with the UserReply augmented to
- include a serial number indicating which reply number this
- is.
- The <em>first</em> reply to arrive,
- will be numbered <em>one (1)</em>. </p>
- </item>
- <item>
- <p>Replies arriving after the timer has expired will be delivered
- in the same way as before, using the
- <seealso marker="megaco_user#unexpected_trans">handle_unexpected_trans/3,4</seealso>
- callback function. </p>
- </item>
- <item>
- <p>Note that if the timer was <em>not</em> configured,
- megaco will act exactly as before! </p>
- </item>
- </list>
- <p>Own Id: OTP-8183</p>
- <p>Aux Id: Seq 11393</p>
- </item>
-
- </list>
-
- </section>
-
- <section>
- <title>Fixed bugs and malfunctions</title>
-<!--
- <p>-</p>
--->
-
- <list type="bulleted">
- <item>
- <p>If the megaco app received a transaction reply, for a request
- issued using the
- <seealso marker="megaco#call">call/3</seealso> function, from
- the wrong remote entity (wrong MId)), megaco would still deliver
- the reply (<seealso marker="megaco#call">call/3</seealso>
- returnes) as if from the correct remote entity (right MId). </p>
- <p>This has been changed so that the function now returns with
- an error reason. </p>
- <p>See <seealso marker="megaco#call">call/3</seealso> for more
- info. </p>
- <p>*** POTENTIAL INCOMPATIBILITY ***</p>
- <p>Own Id: OTP-8212</p>
- <p>Aux Id: Seq 11305</p>
- </item>
-
- </list>
-
- </section>
-
- </section> <!-- 3.12 -->
-
-
- <section>
- <title>Megaco 3.11.3</title>
-
-<!--
- <p>Version 3.11.3 supports code replacement in runtime from/to
- version 3.11.2, 3.11.1 and 3.11.</p>
--->
-
- <section>
- <title>Improvements and new features</title>
-<!--
- <p>-</p>
--->
-
- <list type="bulleted">
- <item>
- <p>Replacing obsolete guard tests.</p>
- <p>Own Id: OTP-8164</p>
- <!-- <p>Aux Id: Seq 11332</p> -->
- </item>
-
- <item>
- <p>Added the config option
- <seealso marker="megaco#ui_call_proxy_gc_timeout">call_proxy_gc_timeout</seealso>
- to be able to control the way unexpected replies (when requests issued
- via calls to <seealso marker="megaco#call">call/3</seealso>)
- are handled. </p>
- <p>See
- <seealso marker="megaco#user_info">user_info/2</seealso>,
- <seealso marker="megaco#conn_info">conn_info/2</seealso> and
- <seealso marker="megaco#call">call/3</seealso> for more info. </p>
- <p>Own Id: OTP-8167</p>
- <p>Aux Id: Seq 11393</p>
- </item>
-
- <item>
- <p>Make flex scanner c89 compiler compliant.</p>
- <p>Akira Kitada</p>
- <p>Own Id: OTP-8191</p>
- <!-- <p>Aux Id: Seq 11332</p> -->
- </item>
-
- </list>
-
- </section>
-
- <section>
- <title>Fixed bugs and malfunctions</title>
- <p>-</p>
-
-<!--
- <list type="bulleted">
- <item>
- <p>Replacing obsolete guard tests.</p>
- <p>Own Id: OTP-8164</p>
- <p>Aux Id: Seq 11332</p>
- </item>
-
- </list>
--->
-
- </section>
-
- <section>
- <title>Incompatibilities</title>
- <p>-</p>
-
-<!--
- <list type="bulleted">
- <item>
- <p>For those implementing their own codec's, the new megaco_encoder
- behaviour will require three more functions. See above for more
- info. </p>
- <p>Own Id: OTP-7168</p>
- <p>Aux Id: Seq 10867</p>
- </item>
-
- </list>
--->
-
- </section>
- </section> <!-- 3.11.3 -->
-
-
- <section>
- <title>Megaco 3.11.2</title>
-
- <p>Version 3.11.2 supports code replacement in runtime from/to
- version 3.11.1 and 3.11.</p>
-
- <section>
- <title>Improvements and new features</title>
-<!--
- <p>-</p>
--->
-
- <list type="bulleted">
- <item>
- <p>Megaco was unnecessarily strict when parsing the SDP
- attribute <c>maxptime</c> (leading or trailing spaces
- cased the value parse to fail). </p>
- <p>This has been improved so that leading and trailing
- spaces are stripped before parsing the value.
- The same has been done for the attribute <c>ptime</c>.</p>
- <p>Own Id: OTP-8123</p>
- <p>Aux Id: Seq 11364</p>
- </item>
-
- </list>
-
- </section>
-
- <section>
- <title>Fixed bugs and malfunctions</title>
- <p>-</p>
-
-<!--
- <list type="bulleted">
- <item>
- <p>[text] The <em>unquoted</em> string BOTH was interpreted as the
- <c>'BothToken'</c> token. This was a version 3 (prev3a, prev3b,
- prev3c and v3) only. </p>
- <p>Own Id: OTP-8114</p>
- <p>Aux Id: Seq 11353</p>
- </item>
-
- <item>
- <p>The reply proxy could crash if the timeout time calculation
- results in a negative number. This will result in a function
- clause with resulting error report.</p>
- <p>Own Id: OTP-8081</p>
- <p>Aux Id: Seq 11332</p>
- </item>
-
- </list>
--->
-
- </section>
-
- <section>
- <title>Incompatibilities</title>
- <p>-</p>
-
-<!--
- <list type="bulleted">
- <item>
- <p>For those implementing their own codec's, the new megaco_encoder
- behaviour will require three more functions. See above for more
- info. </p>
- <p>Own Id: OTP-7168</p>
- <p>Aux Id: Seq 10867</p>
- </item>
-
- </list>
--->
-
- </section>
- </section> <!-- 3.11.2 -->
-
-
- <section>
- <title>Megaco 3.11.1</title>
-
- <p>Version 3.11.1 supports code replacement in runtime from/to
- version 3.11.</p>
-
- <section>
- <title>Improvements and new features</title>
- <p>-</p>
-
-<!--
- <list type="bulleted">
- <item>
- <p>In order to better utilize multi-core procs, the
- <c>flex</c> (text) scanner has been improved. </p>
- <p>The <c>flex</c> (text) scanner has been made reentrant,
- <em>if</em> the flex utility supports this. Note that the version
- of <c>flex</c> supplied with some OS/distros (Solaris 10,
- FreeBSD and OpenBSD to mention a few) may not support this, in which
- case the flex scanner will be non-reentrant, just as before. </p>
- <p>Own Id: OTP-7302</p>
- </item>
-
- </list>
--->
-
- </section>
-
- <section>
- <title>Fixed bugs and malfunctions</title>
-<!--
- <p>-</p>
--->
-
- <list type="bulleted">
- <item>
- <p>[text] The <em>unquoted</em> string BOTH was interpreted as the
- <c>'BothToken'</c> token. This was a version 3 (prev3a, prev3b,
- prev3c and v3) only. </p>
- <p>Own Id: OTP-8114</p>
- <p>Aux Id: Seq 11353</p>
- </item>
-
- <item>
- <p>The reply proxy could crash if the timeout time calculation
- results in a negative number. This will result in a function
- clause with resulting error report.</p>
- <p>Own Id: OTP-8081</p>
- <p>Aux Id: Seq 11332</p>
- </item>
-
- </list>
-
- </section>
-
- <section>
- <title>Incompatibilities</title>
- <p>-</p>
-
-<!--
- <list type="bulleted">
- <item>
- <p>For those implementing their own codec's, the new megaco_encoder
- behaviour will require three more functions. See above for more
- info. </p>
- <p>Own Id: OTP-7168</p>
- <p>Aux Id: Seq 10867</p>
- </item>
-
- </list>
--->
-
- </section>
- </section> <!-- 3.11.1 -->
-
-
- <section>
- <title>Megaco 3.11</title>
-
-<!--
- <p>Version 3.11 supports code replacement in runtime from/to
- version 3.10.1 and 3.10.0.1.</p>
--->
-
- <section>
- <title>Improvements and new features</title>
-<!--
- <p>-</p>
--->
-
- <list type="bulleted">
- <item>
- <p>In order to better utilize multi-core procs, the
- <c>flex</c> (text) scanner has been improved. </p>
- <p>The <c>flex</c> (text) scanner has been made reentrant,
- <em>if</em> the flex utility supports this. Note that the version
- of <c>flex</c> supplied with some OS/distros (Solaris 10,
- FreeBSD and OpenBSD to mention a few) may not support this, in which
- case the flex scanner will be non-reentrant, just as before. </p>
- <p>Own Id: OTP-7302</p>
- </item>
-
- </list>
- </section>
-
- <section>
- <title>Fixed bugs and malfunctions</title>
- <p>-</p>
-
-<!--
- <list type="bulleted">
- <item>
- <p>The (plain) text scanner could incorrectly identify
- character strings (any 17 char long string with the
- char t in the middle) as a TimeStampToken.</p>
- <p>Own Id: OTP-7249</p>
- <p>Aux Id: Seq 10917</p>
- </item>
-
- </list>
--->
-
- </section>
-
- <section>
- <title>Incompatibilities</title>
- <p>-</p>
-
-<!--
- <list type="bulleted">
- <item>
- <p>For those implementing their own codec's, the new megaco_encoder
- behaviour will require three more functions. See above for more
- info. </p>
- <p>Own Id: OTP-7168</p>
- <p>Aux Id: Seq 10867</p>
- </item>
-
- </list>
--->
-
- </section>
- </section> <!-- 3.11 -->
-
-
- <section>
- <title>Megaco 3.10.1</title>
-
- <p>Version 3.10.1 supports code replacement in runtime from/to
- version 3.10.0.1, 3.10 and 3.9.4.</p>
-
- <section>
- <title>Improvements and new features</title>
- <p>-</p>
-
-<!--
- <list type="bulleted">
- <item>
- <p>Updated file headers.</p>
- <p>Own Id: OTP-7851</p>
- <p>Aux Id: Seq 11140</p>
- </item>
-
- </list>
--->
- </section>
-
- <section>
- <title>Fixed bugs and malfunctions</title>
-<!--
- <p>-</p>
--->
-
- <list type="bulleted">
- <item>
- <p>Unexpected
- <seealso marker="megaco_user#unexpected_trans">handle_unexpected_reply</seealso>
- callbacks. </p>
- <p>The <seealso marker="megaco_user">megaco_user</seealso> callback
- function
- <seealso marker="megaco_user#unexpected_trans">handle_unexpected_reply</seealso>
- could during high load be called with unexpected values for the Trans
- argument, such as an <c>TransactionReply</c> where
- <c>transactionResult</c> had the value <c>{error, timeout}</c>.
- This was a result of a race condition and has now been fixed. </p>
- <p>Own Id: OTP-7926</p>
- <p>Aux Id: Seq 11255</p>
- </item>
-
- <item>
- <p>[text] PropertyParm values cannot be quoted. </p>
- <p>It was not possible to encode a PropertyParm value as a quoted string
- (unless it *had* to (has at least one RestChar)). The megaco text codec's
- now also accepts quoted strings as PropertyParm values. </p>
- <p>Own Id: OTP-7936</p>
- <p>Aux Id: Seq 11258</p>
- </item>
-
- </list>
-
- </section>
-
- <section>
- <title>Incompatibilities</title>
- <p>-</p>
-
-<!--
- <list type="bulleted">
- <item>
- <p>If the transport module calls the
- <seealso marker="megaco#process_received_message">process_received_message/5</seealso>
- or
- <seealso marker="megaco#receive_message">receive_message/5</seealso>
- function(s) for the initial message, then the
- <seealso marker="megaco_user#connect">handle_connect/3</seealso>
- function will now be called and not the
- <seealso marker="megaco_user#connect">handle_connect/2</seealso>
- function. </p>
- <p>Own Id: OTP-7713</p>
- <p>Aux Id: Seq 11140</p>
- </item>
-
- </list>
--->
-
- </section>
- </section> <!-- 3.10.1 -->
-
-
- <section>
- <title>Megaco 3.10.0.1</title>
-
- <p>Version 3.10.0.1 supports code replacement in runtime from/to
- version 3.10 and 3.9.4 except
- when using any of the drivers (flex for text or asn1 for binary).</p>
-
- <section>
- <title>Improvements and new features</title>
-<!--
- <p>-</p>
--->
-
- <list type="bulleted">
- <item>
- <p>Updated file headers.</p>
- <p>Own Id: OTP-7851</p>
- <!-- <p>Aux Id: Seq 11140</p> -->
- </item>
-
- </list>
- </section>
-
- <section>
- <title>Fixed bugs and malfunctions</title>
- <p>-</p>
-
-<!--
- <list type="bulleted">
- <item>
- <p>Memory leak in the flex scanner. There was a memory
- leak in the flex scanner function handling
- Property Parameters. </p>
- <p>Own Id: OTP-7700</p>
- <p>Aux Id: Seq 11126</p>
- </item>
-
- </list>
--->
-
- </section>
-
- <section>
- <title>Incompatibilities</title>
- <p>-</p>
-
-<!--
- <list type="bulleted">
- <item>
- <p>If the transport module calls the
- <seealso marker="megaco#process_received_message">process_received_message/5</seealso>
- or
- <seealso marker="megaco#receive_message">receive_message/5</seealso>
- function(s) for the initial message, then the
- <seealso marker="megaco_user#connect">handle_connect/3</seealso>
- function will now be called and not the
- <seealso marker="megaco_user#connect">handle_connect/2</seealso>
- function. </p>
- <p>Own Id: OTP-7713</p>
- <p>Aux Id: Seq 11140</p>
- </item>
-
- </list>
--->
-
- </section>
- </section> <!-- 3.10.0.1 -->
-
-
- <section>
- <title>Megaco 3.10</title>
-
- <p>Version 3.10 supports code replacement in runtime from/to
- version 3.9.4, 3.9.3, 3.9.2, 3.9.1.1, 3.9.1, 3.9, 3.8.2, 3.8.1 and 3.8 except
- when using any of the drivers (flex for text or asn1 for binary).</p>
-
- <section>
- <title>Improvements and new features</title>
-<!--
- <p>-</p>
--->
-
- <list type="bulleted">
- <item>
- <p>Added new API function
- <seealso marker="megaco#connect">megaco:connect/5</seealso> and
- the corresponding new <c>megaco_user</c> callback function
- <seealso marker="megaco_user#connect">handle_connect/3</seealso>.
- The purpose of this is to be able to pass information to the
- <seealso marker="megaco_user#connect">handle_connect/3</seealso>
- function by calling the
- <seealso marker="megaco#connect">megaco:connect/5</seealso>
- function. </p>
- <p>Own Id: OTP-7713</p>
- <p>Aux Id: Seq 11140</p>
- </item>
-
- <item>
- <p>Update file headers with new copyright notice. </p>
- <p>Own Id: OTP-7743</p>
- </item>
-
- </list>
- </section>
-
- <section>
- <title>Fixed bugs and malfunctions</title>
- <p>-</p>
-
-<!--
- <list type="bulleted">
- <item>
- <p>Memory leak in the flex scanner. There was a memory
- leak in the flex scanner function handling
- Property Parameters. </p>
- <p>Own Id: OTP-7700</p>
- <p>Aux Id: Seq 11126</p>
- </item>
-
- </list>
--->
-
- </section>
-
- <section>
- <title>Incompatibilities</title>
-<!--
- <p>-</p>
--->
-
- <list type="bulleted">
- <item>
- <p>If the transport module calls the
- <seealso marker="megaco#process_received_message">process_received_message/5</seealso>
- or
- <seealso marker="megaco#receive_message">receive_message/5</seealso>
- function(s) for the initial message, then the
- <seealso marker="megaco_user#connect">handle_connect/3</seealso>
- function will now be called and not the
- <seealso marker="megaco_user#connect">handle_connect/2</seealso>
- function. </p>
- <p>Own Id: OTP-7713</p>
- <p>Aux Id: Seq 11140</p>
- </item>
-
- </list>
-
- </section>
- </section> <!-- 3.10 -->
-
<!-- section>
<title>Release notes history</title>
<p>For information about older versions see
diff --git a/lib/megaco/src/app/megaco.appup.src b/lib/megaco/src/app/megaco.appup.src
index a7b38eb107..b3659366a4 100644
--- a/lib/megaco/src/app/megaco.appup.src
+++ b/lib/megaco/src/app/megaco.appup.src
@@ -2,7 +2,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2001-2012. All Rights Reserved.
+%% Copyright Ericsson AB 2001-2013. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -18,186 +18,170 @@
%% %CopyrightEnd%
%%
-%%
-%% 3.4.3
-%% |
-%% v
-%% 3.4.4
-%% / \
-%% | |
-%% v v
-%% 3.5 3.4.5
-%% | |
-%% v v
-%% 3.5.1 <- 3.4.6
-%% |
-%% v
-%% 3.5.2
-%% |
-%% v
-%% 3.5.3
-%% |
-%% v
-%% 3.6
-%% |
-%% v
-%% 3.6.0.1
-%% |
-%% v
-%% 3.6.1
-%% |
-%% v
-%% 3.6.2
-%% / \
-%% | |
-%% v |
-%% 3.7 3.6.3
-%% | |
-%% v v
-%% 3.7.1 <- 3.6.4
-%% | |
-%% v v
-%% 3.7.2 <- 3.6.5
-%% | |
-%% v v
-%% 3.7.3 <- 3.6.6
-%% | |
-%% v v
-%% 3.7.4 <- 3.6.7
-%% | |
-%% v v
-%% 3.7.5 <- 3.6.9
-%% |
-%% v
-%% 3.8
-%% |
-%% v
-%% 3.8.1
-%% |
-%% v
-%% 3.8.2
-%% |
-%% v
-%% 3.9
-%% |
-%% v
-%% 3.9.1
-%% |
-%% v
-%% 3.9.1.1
-%% |
-%% v
-%% 3.9.2
-%% |
-%% v
-%% 3.9.3
-%% |
-%% v
-%% 3.9.4
-%% |
-%% v
-%% 3.10
-%% |
-%% v
-%% 3.10.0.1
-%% |
-%% v
-%% 3.10.1
-%% |
-%% v
-%% 3.11
-%% |
-%% v
-%% 3.11.1
-%% |
-%% v
-%% 3.11.2
-%% |
-%% v
-%% 3.11.3
-%% |
-%% v
-%% 3.12
-%% |
-%% v
-%% 3.13
-%% |
-%% v
-%% 3.14
-%% |
-%% v
-%% 3.14.1
-%% |
-%% v
-%% 3.14.1.1
-%% |
-%% v
-%% 3.15
-%% |
-%% v
-%% 3.15.1
-%% |
-%% v
-%% 3.15.1.1
-%% |
-%% v
-%% 3.16
-%% |
-%% v
-%% 3.16.0.1
-%% |
-%% v
-%% 3.16.0.2
+%%
+%% 3.4.3
+%% |
+%% v
+%% 3.4.4
+%% / \
+%% | |
+%% v v
+%% 3.5 3.4.5
+%% | |
+%% v v
+%% 3.5.1 <- 3.4.6
+%% |
+%% v
+%% 3.5.2
+%% |
+%% v
+%% 3.5.3
+%% |
+%% v
+%% 3.6
+%% |
+%% v
+%% 3.6.0.1
+%% |
+%% v
+%% 3.6.1
+%% |
+%% v
+%% 3.6.2
+%% / \
+%% | |
+%% v v
+%% 3.7 3.6.3
+%% | |
+%% v v
+%% 3.7.1 <- 3.6.4
+%% | |
+%% v v
+%% 3.7.2 <- 3.6.5
+%% | |
+%% v v
+%% 3.7.3 <- 3.6.6
+%% | |
+%% v v
+%% 3.7.4 <- 3.6.7
+%% | |
+%% v v
+%% 3.7.5 <- 3.6.9
+%% |
+%% v
+%% 3.8
+%% |
+%% v
+%% 3.8.1
+%% |
+%% v
+%% 3.8.2
+%% |
+%% v
+%% 3.9
+%% |
+%% v
+%% 3.9.1
+%% |
+%% v
+%% 3.9.1.1
+%% |
+%% v
+%% 3.9.2
+%% |
+%% v
+%% 3.9.3
+%% |
+%% v
+%% 3.9.4
+%% |
+%% v
+%% 3.10
+%% |
+%% v
+%% 3.10.0.1
+%% |
+%% v
+%% 3.10.1
+%% |
+%% v
+%% 3.11
+%% |
+%% v
+%% 3.11.1
+%% |
+%% v
+%% 3.11.2
+%% |
+%% v
+%% 3.11.3
+%% / \
+%% | \
+%% v \
+%% 3.12 \
+%% | \
+%% v \
+%% 3.13 \
+%% | \
+%% v \
+%% 3.14 \
+%% | \
+%% v \
+%% 3.14.1 \
+%% | \
+%% v \
+%% 3.14.1.1 \
+%% / \ \
+%% / \ \
+%% | \ \
+%% v \ \
+%% 3.15 \ \
+%% | \ \
+%% v \ \
+%% 3.15.1 \ \
+%% | \ \
+%% v \ \
+%% 3.15.1.1 \ \
+%% / \ \ |
+%% / \ \ |
+%% / \ \ |
+%% | \ \ |
+%% v \ \ |
+%% 3.16 \ \ |
+%% | \ \ |
+%% v \ \ |
+%% 3.16.0.1 \ | |
+%% | \ | |
+%% v \ | |
+%% 3.16.0.2 \ | |
+%% | \ \ | |
+%% | \ \ | |
+%% | \ \ | |
+%% v \ | | |
+%% 3.16.0.3 \ | | |
+%% | \ | | |
+%% | | | | |
+%% | | | | |
+%% | | | | |
+%% v v v v v
+%% 3.17 <- 3.16.1 <- 3.15.2 <- 3.14.2 <- 3.11.4
%%
%%
+
{"%VSN%",
[
- {"3.16.0.1",
- [
- ]
- },
- {"3.16",
- [
- ]
- },
- {"3.15.1.1",
- [
- {restart_application, megaco}
- ]
- },
- {"3.15.1",
- [
- {restart_application, megaco}
- ]
- },
- {"3.15",
+ {"3.16.0.3",
[
- {restart_application, megaco}
+ {update, megaco_flex_scanner_handler, {advanced, upgrade_from_pre_3_17},
+ soft_purge, soft_purge, []}
]
}
],
[
- {"3.16.0.1",
- [
- ]
- },
- {"3.16",
- [
- ]
- },
- {"3.15.1.1",
- [
- {restart_application, megaco}
- ]
- },
- {"3.15.1",
- [
- {restart_application, megaco}
- ]
- },
- {"3.15",
+ {"3.16.0.3",
[
- {restart_application, megaco}
+ {update, megaco_flex_scanner_handler, {advanced, downgrade_to_pre_3_17},
+ soft_purge, soft_purge, []}
]
}
]
diff --git a/lib/megaco/src/flex/megaco_flex_scanner_drv.flex.src b/lib/megaco/src/flex/megaco_flex_scanner_drv.flex.src
index 3914a81b8c..90d5c2aae6 100644
--- a/lib/megaco/src/flex/megaco_flex_scanner_drv.flex.src
+++ b/lib/megaco/src/flex/megaco_flex_scanner_drv.flex.src
@@ -1,8 +1,8 @@
/*
* %CopyrightBegin%
- *
+ *
* Copyright Ericsson AB 2001-2013. All Rights Reserved.
- *
+ *
* The contents of this file are subject to the Erlang Public License,
* Version 1.1, (the "License"); you may not use this file except in
* compliance with the License. You should have received a copy of the
@@ -95,6 +95,13 @@ typedef struct {
int token_counter;
} MfsErlDrvData;
+/* IBL = In Buffer Length - the raw (un-decoded) message buffer length */
+#define TERM_SPEC_SIZE_INITIAL(IBL) (1024 + 2*(IBL))
+
+/* CTSS = Current term spec size - the current term spec length */
+/* S = Size - how many positions we need */
+#define TERM_SPEC_SIZE_NEXT(CTSS,S) ((CTSS) + 1024 + (S))
+
#if !defined(MEGACO_REENTRANT_FLEX_SCANNER)
static MfsErlDrvData mfs_drv_data;
#endif
@@ -737,7 +744,7 @@ v LOAD_TOKEN(mfs_VersionToken);
#endif
-/* #define MFS_DEBUG true */ /* temporary */
+// #define MFS_DEBUG true
#if defined(MFS_DEBUG)
# define DBG( proto ) printf proto
# define DBG_BUF(func, bufName, buf, bufSz) mfs_dbg_buf_print(func, bufName, buf, bufSz)
@@ -842,15 +849,20 @@ static void mfs_ensure_term_spec(MfsErlDrvData* dataP, int size)
"\n term_spec_size: %d\n",
dataP->term_spec_index, dataP->term_spec_size) );
- dataP->term_spec_size = (dataP->term_spec_size * 2) + size;
+ dataP->term_spec_size = TERM_SPEC_SIZE_NEXT(dataP->term_spec_size, size);
DBG( ("mfs_ensure_term_spec -> "
- "term_spec is at 0x%X, new term_spec_size is %d\n",
- (unsigned int) dataP->term_spec, dataP->term_spec_size) );
+ "term_spec is at 0x%X, new term_spec_size is %d (%lu)\n",
+ (unsigned int) dataP->term_spec,
+ dataP->term_spec_size,
+ dataP->term_spec_size * sizeof(ErlDrvTermData)) );
tmp = REALLOC(dataP->term_spec,
dataP->term_spec_size * sizeof(ErlDrvTermData));
+ DBG( ("mfs_ensure_term_spec -> "
+ "realloc result: 0x%X\n", (unsigned int) tmp) );
+
if (tmp == NULL) {
/*
* Ouch, we did'nt get any new memory.
@@ -942,6 +954,9 @@ static void mfs_octet_load_token(ErlDrvTermData TokenTag, int is_empty)
ASSIGN_TERM_SPEC(dataP, ERL_DRV_TUPLE);
ASSIGN_TERM_SPEC(dataP, 3);
+
+ DBG( ("mfs_octet_load_token -> done\n") );
+
}
#if defined(MEGACO_REENTRANT_FLEX_SCANNER)
@@ -1241,7 +1256,7 @@ static void mfs_load_property_groups(MfsErlDrvData* dataP)
} // if ((yytext[i] != SP)...
} // while ...
- mfs_ensure_term_spec(dataP, 4); // 2 + 2 just in case
+ mfs_ensure_term_spec(dataP, 6); // 3 + 3 just in case
/* Make sure we actually have some groups */
@@ -1727,7 +1742,7 @@ static ErlDrvSSizeT mfs_control(ErlDrvData handle,
dataP->text_buf = tmp;
dataP->text_ptr = tmp;
- dataP->term_spec_size = 1000 + buf_len; /* OTP-4237 */
+ dataP->term_spec_size = TERM_SPEC_SIZE_INITIAL(buf_len);
DBG( ("mfs_control -> allocate term-spec buffer: "
"\n term_spec_size: %d\n", dataP->term_spec_size) );
diff --git a/lib/megaco/src/flex/megaco_flex_scanner_handler.erl b/lib/megaco/src/flex/megaco_flex_scanner_handler.erl
index 420202134e..ad28e25c39 100644
--- a/lib/megaco/src/flex/megaco_flex_scanner_handler.erl
+++ b/lib/megaco/src/flex/megaco_flex_scanner_handler.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2001-2010. All Rights Reserved.
+%% Copyright Ericsson AB 2001-2013. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -181,11 +181,11 @@ terminate(_Reason, _S) ->
%% Returns: {ok, NewState}
%%----------------------------------------------------------------------
-code_change({down, _Vsn}, #state{conf = Conf} = State, downgrade_to_pre_3_13_1) ->
+code_change({down, _Vsn}, #state{conf = Conf} = State, downgrade_to_pre_3_17) ->
NewPorts = bump_flex_scanner(Conf),
{ok, State#state{conf = {flex, NewPorts}}};
-code_change(_Vsn, #state{conf = Conf} = State, upgrade_from_pre_3_13_1) ->
+code_change(_Vsn, #state{conf = Conf} = State, upgrade_from_pre_3_17) ->
NewPorts = bump_flex_scanner(Conf),
{ok, State#state{conf = {flex, NewPorts}}};
diff --git a/lib/megaco/test/megaco_appup_test.erl b/lib/megaco/test/megaco_appup_test.erl
index 40eebcae86..fce6cf3cba 100644
--- a/lib/megaco/test/megaco_appup_test.erl
+++ b/lib/megaco/test/megaco_appup_test.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2002-2011. All Rights Reserved.
+%% Copyright Ericsson AB 2002-2013. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -309,6 +309,9 @@ instruction_module(Instr) ->
%% Check that the modules handled in an instruction set for version X
%% is a subset of the instruction set for version X-1.
check_module_subset(Instructions) ->
+ %% io:format("check_module_subset -> "
+ %% "~n Instructions: ~p"
+ %% "~n", [Instructions]),
do_check_module_subset(modules_of(Instructions)).
do_check_module_subset([]) ->
@@ -316,6 +319,11 @@ do_check_module_subset([]) ->
do_check_module_subset([_]) ->
ok;
do_check_module_subset([{_V1, Mods1}|T]) ->
+ %% io:format("do_check_module_subset -> "
+ %% "~n V1: ~p"
+ %% "~n Mods1: ~p"
+ %% "~n T: ~p"
+ %% "~n", [_V1, Mods1, T]),
{V2, Mods2} = hd(T),
%% Check that the modules in V1 is a subset of V2
case do_check_module_subset2(Mods1, Mods2) of
@@ -347,8 +355,21 @@ modules_of(Instructions) ->
modules_of([], Acc) ->
lists:reverse(Acc);
modules_of([{V,Instructions}|T], Acc) ->
- Mods = modules_of2(Instructions, []),
- modules_of(T, [{V, Mods}|Acc]).
+ %% io:format("modules_of -> "
+ %% "~n V: ~p"
+ %% "~n Instructions: ~p"
+ %% "~n", [V, Instructions]),
+ case modules_of2(Instructions, []) of
+ Mods when is_list(Mods) ->
+ %% io:format("modules_of -> "
+ %% "~n Mods: ~p"
+ %% "~n", [Mods]),
+ modules_of(T, [{V, Mods}|Acc]);
+ skip ->
+ %% io:format("modules_of -> skip"
+ %% "~n", []),
+ modules_of(T, Acc)
+ end.
modules_of2([], Acc) ->
lists:reverse(Acc);
@@ -356,6 +377,8 @@ modules_of2([Instr|Instructions], Acc) ->
case module_of(Instr) of
{value, Mod} ->
modules_of2(Instructions, [Mod|Acc]);
+ skip ->
+ skip;
false ->
modules_of2(Instructions, Acc)
end.
@@ -368,6 +391,8 @@ module_of({load_module, Module, _Pre, _Post, _Depend}) ->
{value, Module};
module_of({update, Module, _Change, _Pre, _Post, _Depend}) ->
{value, Module};
+module_of({restart_application, _App}) ->
+ skip;
module_of(_) ->
false.
diff --git a/lib/megaco/test/megaco_codec_flex_lib.erl b/lib/megaco/test/megaco_codec_flex_lib.erl
index 93bc5d4bbc..3e70454faf 100644
--- a/lib/megaco/test/megaco_codec_flex_lib.erl
+++ b/lib/megaco/test/megaco_codec_flex_lib.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2007-2010. All Rights Reserved.
+%% Copyright Ericsson AB 2007-2013. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -49,8 +49,14 @@
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
init(Config) when is_list(Config) ->
+ %% io:format("~w:init -> entry with"
+ %% "~n Config: ~p"
+ %% "~n", [?MODULE, Config]),
Flag = process_flag(trap_exit, true),
Res = (catch start()),
+ %% io:format("~w:init -> start result"
+ %% "~n Res: ~p"
+ %% "~n", [?MODULE, Res]),
process_flag(trap_exit, Flag),
case Res of
{error, Reason} ->
diff --git a/lib/megaco/test/megaco_codec_prev3a_test.erl b/lib/megaco/test/megaco_codec_prev3a_test.erl
index b2316eb509..9c4ed385a6 100644
--- a/lib/megaco/test/megaco_codec_prev3a_test.erl
+++ b/lib/megaco/test/megaco_codec_prev3a_test.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2005-2012. All Rights Reserved.
+%% Copyright Ericsson AB 2005-2013. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -223,23 +223,9 @@ display_text_messages() ->
%% ----
-
-expand(RootCase) ->
- expand([RootCase], []).
-
-expand([], Acc) ->
- lists:flatten(lists:reverse(Acc));
-expand([Case|Cases], Acc) ->
- case (catch apply(?MODULE,Case,[suite])) of
- [] ->
- expand(Cases, [Case|Acc]);
- C when is_list(C) ->
- expand(Cases, [expand(C, [])|Acc]);
- _ ->
- expand(Cases, [Case|Acc])
- end.
-
-
+tickets() ->
+ %% io:format("~w:tickets -> entry~n", [?MODULE]),
+ megaco_test_lib:tickets(?MODULE).
%% ----
@@ -268,26 +254,34 @@ end_per_testcase(Case, Config) ->
%% Top test case
all() ->
- [{group, text}, {group, binary}, {group, erl_dist},
+ [{group, text},
+ {group, binary},
+ {group, erl_dist},
{group, tickets}].
groups() ->
[{text, [],
- [{group, pretty}, {group, flex_pretty},
- {group, compact}, {group, flex_compact}]},
+ [{group, pretty},
+ {group, flex_pretty},
+ {group, compact},
+ {group, flex_compact}]},
{binary, [],
- [{group, bin}, {group, ber}, {group, per}]},
+ [{group, bin},
+ {group, ber},
+ {group, per}]},
{erl_dist, [], [{group, erl_dist_m}]},
{pretty, [], [pretty_test_msgs]},
{compact, [], [compact_test_msgs]},
{flex_pretty, [], flex_pretty_cases()},
{flex_compact, [], flex_compact_cases()},
- {bin, [], [bin_test_msgs]}, {ber, [], [ber_test_msgs]},
+ {bin, [], [bin_test_msgs]},
+ {ber, [], [ber_test_msgs]},
{per, [], [per_test_msgs]},
{erl_dist_m, [], [erl_dist_m_test_msgs]},
{tickets, [],
[{group, compact_tickets},
- {group, flex_compact_tickets}, {group, pretty_tickets},
+ {group, flex_compact_tickets},
+ {group, pretty_tickets},
{group, flex_pretty_tickets}]},
{compact_tickets, [],
[compact_otp4011_msg1, compact_otp4011_msg2,
@@ -311,8 +305,7 @@ groups() ->
compact_otp5993_msg01, compact_otp5993_msg02,
compact_otp5993_msg03, compact_otp6017_msg01,
compact_otp6017_msg02, compact_otp6017_msg03]},
- {flex_compact_tickets, [],
- flex_compact_tickets_cases()},
+ {flex_compact_tickets, [], flex_compact_tickets_cases()},
{pretty_tickets, [],
[pretty_otp4632_msg1, pretty_otp4632_msg2,
pretty_otp4632_msg3, pretty_otp4632_msg4,
@@ -360,64 +353,61 @@ end_per_group(_GroupName, Config) ->
Config.
flex_pretty_cases() ->
- [flex_pretty_test_msgs].
+ [
+ flex_pretty_test_msgs
+ ].
flex_compact_cases() ->
- [flex_compact_test_msgs, flex_compact_dm_timers1,
- flex_compact_dm_timers2, flex_compact_dm_timers3,
- flex_compact_dm_timers4, flex_compact_dm_timers5,
- flex_compact_dm_timers6, flex_compact_dm_timers7,
- flex_compact_dm_timers8].
-
-%% Support for per_bin was added to ASN.1 as of version
-%% 1.3.2 (R8). And later merged into 1.3.1.3 (R7). These
-%% releases are identical (as far as I know).
-%%
+ [
+ flex_compact_test_msgs,
+ flex_compact_dm_timers1,
+ flex_compact_dm_timers2,
+ flex_compact_dm_timers3,
+ flex_compact_dm_timers4,
+ flex_compact_dm_timers5,
+ flex_compact_dm_timers6,
+ flex_compact_dm_timers7,
+ flex_compact_dm_timers8
+ ].
+
flex_compact_tickets_cases() ->
- [flex_compact_otp7431_msg01, flex_compact_otp7431_msg02,
- flex_compact_otp7431_msg03, flex_compact_otp7431_msg04,
- flex_compact_otp7431_msg05, flex_compact_otp7431_msg06,
- flex_compact_otp7431_msg07].
+ [
+ flex_compact_otp7431_msg01,
+ flex_compact_otp7431_msg02,
+ flex_compact_otp7431_msg03,
+ flex_compact_otp7431_msg04,
+ flex_compact_otp7431_msg05,
+ flex_compact_otp7431_msg06,
+ flex_compact_otp7431_msg07
+ ].
flex_pretty_tickets_cases() ->
- [flex_pretty_otp5042_msg1, flex_pretty_otp5085_msg1,
- flex_pretty_otp5085_msg2, flex_pretty_otp5085_msg3,
- flex_pretty_otp5085_msg4, flex_pretty_otp5085_msg5,
- flex_pretty_otp5085_msg6, flex_pretty_otp5085_msg7,
- flex_pretty_otp5085_msg8, flex_pretty_otp5600_msg1,
- flex_pretty_otp5600_msg2, flex_pretty_otp5601_msg1,
- flex_pretty_otp5793_msg01, flex_pretty_otp7431_msg01,
- flex_pretty_otp7431_msg02, flex_pretty_otp7431_msg03,
- flex_pretty_otp7431_msg04, flex_pretty_otp7431_msg05,
- flex_pretty_otp7431_msg06, flex_pretty_otp7431_msg07].
-
-%% ----
+ [
+ flex_pretty_otp5042_msg1,
+ flex_pretty_otp5085_msg1,
+ flex_pretty_otp5085_msg2,
+ flex_pretty_otp5085_msg3,
+ flex_pretty_otp5085_msg4,
+ flex_pretty_otp5085_msg5,
+ flex_pretty_otp5085_msg6,
+ flex_pretty_otp5085_msg7,
+ flex_pretty_otp5085_msg8,
+ flex_pretty_otp5600_msg1,
+ flex_pretty_otp5600_msg2,
+ flex_pretty_otp5601_msg1,
+ flex_pretty_otp5793_msg01,
+ flex_pretty_otp7431_msg01,
+ flex_pretty_otp7431_msg02,
+ flex_pretty_otp7431_msg03,
+ flex_pretty_otp7431_msg04,
+ flex_pretty_otp7431_msg05,
+ flex_pretty_otp7431_msg06,
+ flex_pretty_otp7431_msg07
+ ].
-tickets() ->
- Flag = process_flag(trap_exit, true),
- Cases = expand(tickets),
- Fun = fun(Case) ->
- C = init_per_testcase(Case, [{tc_timeout,
- timer:minutes(10)}]),
- io:format("Eval ~w~n", [Case]),
- Result =
- case (catch apply(?MODULE, Case, [C])) of
- {'EXIT', Reason} ->
- io:format("~n~p exited:~n ~p~n",
- [Case, Reason]),
- {error, {Case, Reason}};
- Res ->
- Res
- end,
- end_per_testcase(Case, C),
- Result
- end,
- process_flag(trap_exit, Flag),
- lists:map(Fun, Cases).
-
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
pretty_test_msgs(suite) ->
diff --git a/lib/megaco/test/megaco_codec_prev3b_test.erl b/lib/megaco/test/megaco_codec_prev3b_test.erl
index fa24f49372..36df434e80 100644
--- a/lib/megaco/test/megaco_codec_prev3b_test.erl
+++ b/lib/megaco/test/megaco_codec_prev3b_test.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2005-2012. All Rights Reserved.
+%% Copyright Ericsson AB 2005-2013. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -241,21 +241,9 @@ generate_text_messages() ->
%% ----
-
-expand(RootCase) ->
- expand([RootCase], []).
-
-expand([], Acc) ->
- lists:flatten(lists:reverse(Acc));
-expand([Case|Cases], Acc) ->
- case (catch apply(?MODULE,Case,[suite])) of
- [] ->
- expand(Cases, [Case|Acc]);
- C when is_list(C) ->
- expand(Cases, [expand(C, [])|Acc]);
- _ ->
- expand(Cases, [Case|Acc])
- end.
+tickets() ->
+ %% io:format("~w:tickets -> entry~n", [?MODULE]),
+ megaco_test_lib:tickets(?MODULE).
%% ----
@@ -284,26 +272,36 @@ end_per_testcase(Case, Config) ->
%% Top test case
all() ->
- [{group, text}, {group, binary}, {group, erl_dist},
- {group, tickets}].
+ [
+ {group, text},
+ {group, binary},
+ {group, erl_dist},
+ {group, tickets}
+ ].
groups() ->
[{text, [],
- [{group, pretty}, {group, flex_pretty},
- {group, compact}, {group, flex_compact}]},
+ [{group, pretty},
+ {group, flex_pretty},
+ {group, compact},
+ {group, flex_compact}]},
{binary, [],
- [{group, bin}, {group, ber}, {group, per}]},
+ [{group, bin},
+ {group, ber},
+ {group, per}]},
{erl_dist, [], [{group, erl_dist_m}]},
{pretty, [], [pretty_test_msgs]},
{compact, [], [compact_test_msgs]},
{flex_pretty, [], flex_pretty_cases()},
{flex_compact, [], flex_compact_cases()},
- {bin, [], [bin_test_msgs]}, {ber, [], [ber_test_msgs]},
+ {bin, [], [bin_test_msgs]},
+ {ber, [], [ber_test_msgs]},
{per, [], [per_test_msgs]},
{erl_dist_m, [], [erl_dist_m_test_msgs]},
{tickets, [],
[{group, compact_tickets},
- {group, flex_compact_tickets}, {group, pretty_tickets},
+ {group, flex_compact_tickets},
+ {group, pretty_tickets},
{group, flex_pretty_tickets}]},
{compact_tickets, [],
[compact_otp4011_msg1, compact_otp4011_msg2,
@@ -328,8 +326,7 @@ groups() ->
compact_otp5993_msg02, compact_otp5993_msg03,
compact_otp6017_msg01, compact_otp6017_msg02,
compact_otp6017_msg03]},
- {flex_compact_tickets, [],
- flex_compact_tickets_cases()},
+ {flex_compact_tickets, [], flex_compact_tickets_cases()},
{pretty_tickets, [],
[pretty_otp4632_msg1, pretty_otp4632_msg2,
pretty_otp4632_msg3, pretty_otp4632_msg4,
@@ -379,63 +376,61 @@ end_per_group(_GroupName, Config) ->
Config.
flex_pretty_cases() ->
- [flex_pretty_test_msgs].
+ [
+ flex_pretty_test_msgs
+ ].
flex_compact_cases() ->
- [flex_compact_test_msgs, flex_compact_dm_timers1,
- flex_compact_dm_timers2, flex_compact_dm_timers3,
- flex_compact_dm_timers4, flex_compact_dm_timers5,
- flex_compact_dm_timers6, flex_compact_dm_timers7,
- flex_compact_dm_timers8].
-
-%% Support for per_bin was added to ASN.1 as of version
-%% 1.3.2 (R8). And later merged into 1.3.1.3 (R7). These
-%% releases are identical (as far as I know).
-%%
+ [
+ flex_compact_test_msgs,
+ flex_compact_dm_timers1,
+ flex_compact_dm_timers2,
+ flex_compact_dm_timers3,
+ flex_compact_dm_timers4,
+ flex_compact_dm_timers5,
+ flex_compact_dm_timers6,
+ flex_compact_dm_timers7,
+ flex_compact_dm_timers8
+ ].
flex_compact_tickets_cases() ->
- [flex_compact_otp7431_msg01, flex_compact_otp7431_msg02,
- flex_compact_otp7431_msg03, flex_compact_otp7431_msg04,
- flex_compact_otp7431_msg05, flex_compact_otp7431_msg06,
- flex_compact_otp7431_msg07].
+ [
+ flex_compact_otp7431_msg01,
+ flex_compact_otp7431_msg02,
+ flex_compact_otp7431_msg03,
+ flex_compact_otp7431_msg04,
+ flex_compact_otp7431_msg05,
+ flex_compact_otp7431_msg06,
+ flex_compact_otp7431_msg07
+ ].
flex_pretty_tickets_cases() ->
- [flex_pretty_otp5042_msg1, flex_pretty_otp5085_msg1,
- flex_pretty_otp5085_msg2, flex_pretty_otp5085_msg3,
- flex_pretty_otp5085_msg4, flex_pretty_otp5085_msg5,
- flex_pretty_otp5085_msg6, flex_pretty_otp5085_msg7,
- flex_pretty_otp5085_msg8, flex_pretty_otp5600_msg1,
- flex_pretty_otp5600_msg2, flex_pretty_otp5601_msg1,
- flex_pretty_otp5793_msg01, flex_pretty_otp5803_msg01,
- flex_pretty_otp5803_msg02, flex_pretty_otp5805_msg01,
- flex_pretty_otp5836_msg01, flex_pretty_otp7431_msg01,
- flex_pretty_otp7431_msg02, flex_pretty_otp7431_msg03,
- flex_pretty_otp7431_msg04, flex_pretty_otp7431_msg05,
- flex_pretty_otp7431_msg06, flex_pretty_otp7431_msg07].
-
-%% ----
-
-tickets() ->
- Flag = process_flag(trap_exit, true),
- Cases = expand(tickets),
- Fun = fun(Case) ->
- C = init_per_testcase(Case, [{tc_timeout,
- timer:minutes(10)}]),
- io:format("Eval ~w~n", [Case]),
- Result =
- case (catch apply(?MODULE, Case, [C])) of
- {'EXIT', Reason} ->
- io:format("~n~p exited:~n ~p~n",
- [Case, Reason]),
- {error, {Case, Reason}};
- Res ->
- Res
- end,
- end_per_testcase(Case, C),
- Result
- end,
- process_flag(trap_exit, Flag),
- lists:map(Fun, Cases).
+ [
+ flex_pretty_otp5042_msg1,
+ flex_pretty_otp5085_msg1,
+ flex_pretty_otp5085_msg2,
+ flex_pretty_otp5085_msg3,
+ flex_pretty_otp5085_msg4,
+ flex_pretty_otp5085_msg5,
+ flex_pretty_otp5085_msg6,
+ flex_pretty_otp5085_msg7,
+ flex_pretty_otp5085_msg8,
+ flex_pretty_otp5600_msg1,
+ flex_pretty_otp5600_msg2,
+ flex_pretty_otp5601_msg1,
+ flex_pretty_otp5793_msg01,
+ flex_pretty_otp5803_msg01,
+ flex_pretty_otp5803_msg02,
+ flex_pretty_otp5805_msg01,
+ flex_pretty_otp5836_msg01,
+ flex_pretty_otp7431_msg01,
+ flex_pretty_otp7431_msg02,
+ flex_pretty_otp7431_msg03,
+ flex_pretty_otp7431_msg04,
+ flex_pretty_otp7431_msg05,
+ flex_pretty_otp7431_msg06,
+ flex_pretty_otp7431_msg07
+ ].
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
diff --git a/lib/megaco/test/megaco_codec_prev3c_test.erl b/lib/megaco/test/megaco_codec_prev3c_test.erl
index 7f6d098ed8..3f715cbb7e 100644
--- a/lib/megaco/test/megaco_codec_prev3c_test.erl
+++ b/lib/megaco/test/megaco_codec_prev3c_test.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2006-2012. All Rights Reserved.
+%% Copyright Ericsson AB 2006-2013. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -247,21 +247,9 @@ generate_text_messages() ->
%% ----
-
-expand(RootCase) ->
- expand([RootCase], []).
-
-expand([], Acc) ->
- lists:flatten(lists:reverse(Acc));
-expand([Case|Cases], Acc) ->
- case (catch apply(?MODULE,Case,[suite])) of
- [] ->
- expand(Cases, [Case|Acc]);
- C when is_list(C) ->
- expand(Cases, [expand(C, [])|Acc]);
- _ ->
- expand(Cases, [Case|Acc])
- end.
+tickets() ->
+ %% io:format("~w:tickets -> entry~n", [?MODULE]),
+ megaco_test_lib:tickets(?MODULE).
%% ----
@@ -289,26 +277,36 @@ end_per_testcase(Case, Config) ->
%% Top test case
all() ->
- [{group, text}, {group, binary}, {group, erl_dist},
- {group, tickets}].
+ [
+ {group, text},
+ {group, binary},
+ {group, erl_dist},
+ {group, tickets}
+ ].
groups() ->
[{text, [],
- [{group, pretty}, {group, flex_pretty},
- {group, compact}, {group, flex_compact}]},
+ [{group, pretty},
+ {group, flex_pretty},
+ {group, compact},
+ {group, flex_compact}]},
{binary, [],
- [{group, bin}, {group, ber}, {group, per}]},
+ [{group, bin},
+ {group, ber},
+ {group, per}]},
{erl_dist, [], [{group, erl_dist_m}]},
{pretty, [], [pretty_test_msgs]},
{compact, [], [compact_test_msgs]},
{flex_pretty, [], flex_pretty_cases()},
{flex_compact, [], flex_compact_cases()},
- {bin, [], [bin_test_msgs]}, {ber, [], [ber_test_msgs]},
+ {bin, [], [bin_test_msgs]},
+ {ber, [], [ber_test_msgs]},
{per, [], [per_test_msgs]},
{erl_dist_m, [], [erl_dist_m_test_msgs]},
{tickets, [],
[{group, compact_tickets},
- {group, flex_compact_tickets}, {group, pretty_tickets},
+ {group, flex_compact_tickets},
+ {group, pretty_tickets},
{group, flex_pretty_tickets}]},
{compact_tickets, [],
[compact_otp4011_msg1, compact_otp4011_msg2,
@@ -332,8 +330,7 @@ groups() ->
compact_otp5993_msg01, compact_otp5993_msg02,
compact_otp5993_msg03, compact_otp6017_msg01,
compact_otp6017_msg02, compact_otp6017_msg03]},
- {flex_compact_tickets, [],
- flex_compact_tickets_cases()},
+ {flex_compact_tickets, [], flex_compact_tickets_cases()},
{pretty_tickets, [],
[pretty_otp4632_msg1, pretty_otp4632_msg2,
pretty_otp4632_msg3, pretty_otp4632_msg4,
@@ -383,63 +380,62 @@ end_per_group(_GroupName, Config) ->
Config.
flex_pretty_cases() ->
- [flex_pretty_test_msgs].
+ [
+ flex_pretty_test_msgs
+ ].
flex_compact_cases() ->
- [flex_compact_test_msgs, flex_compact_dm_timers1,
- flex_compact_dm_timers2, flex_compact_dm_timers3,
- flex_compact_dm_timers4, flex_compact_dm_timers5,
- flex_compact_dm_timers6, flex_compact_dm_timers7,
- flex_compact_dm_timers8].
-
-%% Support for per_bin was added to ASN.1 as of version
-%% 1.3.2 (R8). And later merged into 1.3.1.3 (R7). These
-%% releases are identical (as far as I know).
-%%
-
+ [
+ flex_compact_test_msgs,
+ flex_compact_dm_timers1,
+ flex_compact_dm_timers2,
+ flex_compact_dm_timers3,
+ flex_compact_dm_timers4,
+ flex_compact_dm_timers5,
+ flex_compact_dm_timers6,
+ flex_compact_dm_timers7,
+ flex_compact_dm_timers8
+ ].
+
flex_compact_tickets_cases() ->
- [flex_compact_otp4299_msg1, flex_compact_otp7431_msg01,
- flex_compact_otp7431_msg02, flex_compact_otp7431_msg03,
- flex_compact_otp7431_msg04, flex_compact_otp7431_msg05,
- flex_compact_otp7431_msg06, flex_compact_otp7431_msg07].
+ [
+ flex_compact_otp4299_msg1,
+ flex_compact_otp7431_msg01,
+ flex_compact_otp7431_msg02,
+ flex_compact_otp7431_msg03,
+ flex_compact_otp7431_msg04,
+ flex_compact_otp7431_msg05,
+ flex_compact_otp7431_msg06,
+ flex_compact_otp7431_msg07
+ ].
flex_pretty_tickets_cases() ->
- [flex_pretty_otp5042_msg1, flex_pretty_otp5085_msg1,
- flex_pretty_otp5085_msg2, flex_pretty_otp5085_msg3,
- flex_pretty_otp5085_msg4, flex_pretty_otp5085_msg5,
- flex_pretty_otp5085_msg6, flex_pretty_otp5085_msg7,
- flex_pretty_otp5085_msg8, flex_pretty_otp5600_msg1,
- flex_pretty_otp5600_msg2, flex_pretty_otp5601_msg1,
- flex_pretty_otp5793_msg01, flex_pretty_otp5803_msg01,
- flex_pretty_otp5803_msg02, flex_pretty_otp5805_msg01,
- flex_pretty_otp5836_msg01, flex_pretty_otp7431_msg01,
- flex_pretty_otp7431_msg02, flex_pretty_otp7431_msg03,
- flex_pretty_otp7431_msg04, flex_pretty_otp7431_msg05,
- flex_pretty_otp7431_msg06, flex_pretty_otp7431_msg07].
-
-%% ----
-
-tickets() ->
- Flag = process_flag(trap_exit, true),
- Cases = expand(tickets),
- Fun = fun(Case) ->
- C = init_per_testcase(Case, [{tc_timeout,
- timer:minutes(10)}]),
- io:format("Eval ~w~n", [Case]),
- Result =
- case (catch apply(?MODULE, Case, [C])) of
- {'EXIT', Reason} ->
- io:format("~n~p exited:~n ~p~n",
- [Case, Reason]),
- {error, {Case, Reason}};
- Res ->
- Res
- end,
- end_per_testcase(Case, C),
- Result
- end,
- process_flag(trap_exit, Flag),
- lists:map(Fun, Cases).
+ [
+ flex_pretty_otp5042_msg1,
+ flex_pretty_otp5085_msg1,
+ flex_pretty_otp5085_msg2,
+ flex_pretty_otp5085_msg3,
+ flex_pretty_otp5085_msg4,
+ flex_pretty_otp5085_msg5,
+ flex_pretty_otp5085_msg6,
+ flex_pretty_otp5085_msg7,
+ flex_pretty_otp5085_msg8,
+ flex_pretty_otp5600_msg1,
+ flex_pretty_otp5600_msg2,
+ flex_pretty_otp5601_msg1,
+ flex_pretty_otp5793_msg01,
+ flex_pretty_otp5803_msg01,
+ flex_pretty_otp5803_msg02,
+ flex_pretty_otp5805_msg01,
+ flex_pretty_otp5836_msg01,
+ flex_pretty_otp7431_msg01,
+ flex_pretty_otp7431_msg02,
+ flex_pretty_otp7431_msg03,
+ flex_pretty_otp7431_msg04,
+ flex_pretty_otp7431_msg05,
+ flex_pretty_otp7431_msg06,
+ flex_pretty_otp7431_msg07
+ ].
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
diff --git a/lib/megaco/test/megaco_codec_v1_test.erl b/lib/megaco/test/megaco_codec_v1_test.erl
index 3be0da3ae4..d1a1d31da0 100644
--- a/lib/megaco/test/megaco_codec_v1_test.erl
+++ b/lib/megaco/test/megaco_codec_v1_test.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2003-2012. All Rights Reserved.
+%% Copyright Ericsson AB 2003-2013. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -416,20 +416,9 @@ decode_text_messages(Codec, Config, [Msg|Msgs], Acc) ->
%% ----
-expand(RootCase) ->
- expand([RootCase], []).
-
-expand([], Acc) ->
- lists:flatten(lists:reverse(Acc));
-expand([Case|Cases], Acc) ->
- case (catch apply(?MODULE,Case,[suite])) of
- [] ->
- expand(Cases, [Case|Acc]);
- C when is_list(C) ->
- expand(Cases, [expand(C, [])|Acc]);
- _ ->
- expand(Cases, [Case|Acc])
- end.
+tickets() ->
+ %% io:format("~w:tickets -> entry~n", [?MODULE]),
+ megaco_test_lib:tickets(?MODULE).
%% ----
@@ -594,61 +583,56 @@ end_per_group(_GroupName, Config) ->
Config.
flex_pretty_cases() ->
- [flex_pretty_test_msgs].
+ [
+ flex_pretty_test_msgs
+ ].
flex_compact_cases() ->
- [flex_compact_test_msgs, flex_compact_dm_timers1,
- flex_compact_dm_timers2, flex_compact_dm_timers3,
- flex_compact_dm_timers4, flex_compact_dm_timers5,
- flex_compact_dm_timers6].
-
-%% Support for per_bin was added to ASN.1 as of version
-%% 1.3.2 (R8). And later merged into 1.3.1.3 (R7). These
-%% releases are identical (as far as I know).
-%%
+ [
+ flex_compact_test_msgs,
+ flex_compact_dm_timers1,
+ flex_compact_dm_timers2,
+ flex_compact_dm_timers3,
+ flex_compact_dm_timers4,
+ flex_compact_dm_timers5,
+ flex_compact_dm_timers6
+ ].
flex_compact_tickets_cases() ->
- [flex_compact_otp7431_msg01a,
- flex_compact_otp7431_msg01b, flex_compact_otp7431_msg02,
- flex_compact_otp7431_msg03, flex_compact_otp7431_msg04,
- flex_compact_otp7431_msg05, flex_compact_otp7431_msg06,
- flex_compact_otp7431_msg07].
+ [
+ flex_compact_otp7431_msg01a,
+ flex_compact_otp7431_msg01b,
+ flex_compact_otp7431_msg02,
+ flex_compact_otp7431_msg03,
+ flex_compact_otp7431_msg04,
+ flex_compact_otp7431_msg05,
+ flex_compact_otp7431_msg06,
+ flex_compact_otp7431_msg07
+ ].
flex_pretty_tickets_cases() ->
- [flex_pretty_otp5042_msg1, flex_pretty_otp5085_msg1,
- flex_pretty_otp5085_msg2, flex_pretty_otp5085_msg3,
- flex_pretty_otp5085_msg4, flex_pretty_otp5085_msg5,
- flex_pretty_otp5085_msg6, flex_pretty_otp5085_msg7,
- flex_pretty_otp5600_msg1, flex_pretty_otp5600_msg2,
- flex_pretty_otp5601_msg1, flex_pretty_otp5793_msg01,
- flex_pretty_otp7431_msg01, flex_pretty_otp7431_msg02,
- flex_pretty_otp7431_msg03, flex_pretty_otp7431_msg04,
- flex_pretty_otp7431_msg05, flex_pretty_otp7431_msg06,
- flex_pretty_otp7431_msg07].
-
-%% ----
+ [
+ flex_pretty_otp5042_msg1,
+ flex_pretty_otp5085_msg1,
+ flex_pretty_otp5085_msg2,
+ flex_pretty_otp5085_msg3,
+ flex_pretty_otp5085_msg4,
+ flex_pretty_otp5085_msg5,
+ flex_pretty_otp5085_msg6,
+ flex_pretty_otp5085_msg7,
+ flex_pretty_otp5600_msg1,
+ flex_pretty_otp5600_msg2,
+ flex_pretty_otp5601_msg1,
+ flex_pretty_otp5793_msg01,
+ flex_pretty_otp7431_msg01,
+ flex_pretty_otp7431_msg02,
+ flex_pretty_otp7431_msg03,
+ flex_pretty_otp7431_msg04,
+ flex_pretty_otp7431_msg05,
+ flex_pretty_otp7431_msg06,
+ flex_pretty_otp7431_msg07
+ ].
-tickets() ->
- Flag = process_flag(trap_exit, true),
- Cases = expand(tickets),
- Fun = fun(Case) ->
- C = init_per_testcase(Case, [{tc_timeout,
- timer:minutes(10)}]),
- io:format("Eval ~w~n", [Case]),
- Result =
- case (catch apply(?MODULE, Case, [C])) of
- {'EXIT', Reason} ->
- io:format("~n~p exited:~n ~p~n",
- [Case, Reason]),
- {error, {Case, Reason}};
- Res ->
- Res
- end,
- end_per_testcase(Case, C),
- Result
- end,
- process_flag(trap_exit, Flag),
- lists:map(Fun, Cases).
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
diff --git a/lib/megaco/test/megaco_codec_v2_test.erl b/lib/megaco/test/megaco_codec_v2_test.erl
index 1f522504d6..d1fb22cbee 100644
--- a/lib/megaco/test/megaco_codec_v2_test.erl
+++ b/lib/megaco/test/megaco_codec_v2_test.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2003-2012. All Rights Reserved.
+%% Copyright Ericsson AB 2003-2013. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -37,7 +37,8 @@
-export([t/0, t/1]).
--export([all/0,groups/0,init_per_group/2,end_per_group/2,
+-export([all/0,
+ groups/0, init_per_group/2, end_per_group/2,
pretty_test_msgs/1,
@@ -138,7 +139,11 @@
flex_compact_otp7534_msg01/1,
flex_compact_otp7573_msg01/1,
flex_compact_otp7576_msg01/1,
-
+ flex_compact_otp10998_msg01/1,
+ flex_compact_otp10998_msg02/1,
+ flex_compact_otp10998_msg03/1,
+ flex_compact_otp10998_msg04/1,
+
pretty_otp4632_msg1/1,
pretty_otp4632_msg2/1,
pretty_otp4632_msg3/1,
@@ -392,22 +397,10 @@ decode_text_messages(Codec, Config, [Msg|Msgs], Acc) ->
%% ----
-expand(RootCase) ->
- expand([RootCase], []).
-
-expand([], Acc) ->
- lists:flatten(lists:reverse(Acc));
-expand([Case|Cases], Acc) ->
- case (catch apply(?MODULE,Case,[suite])) of
- [] ->
- expand(Cases, [Case|Acc]);
- C when is_list(C) ->
- expand(Cases, [expand(C, [])|Acc]);
- _ ->
- expand(Cases, [Case|Acc])
- end.
+tickets() ->
+ %% io:format("~w:tickets -> entry~n", [?MODULE]),
+ megaco_test_lib:tickets(?MODULE).
-
%% ----
@@ -435,79 +428,86 @@ end_per_testcase(Case, Config) ->
%% Top test case
all() ->
-[{group, text}, {group, binary}, {group, erl_dist},
- {group, tickets}].
+ [{group, text},
+ {group, binary},
+ {group, erl_dist},
+ {group, tickets}].
groups() ->
[{text, [],
- [{group, pretty}, {group, flex_pretty},
- {group, compact}, {group, flex_compact}]},
- {binary, [],
- [{group, bin}, {group, ber}, {group, per}]},
- {erl_dist, [], [{group, erl_dist_m}]},
- {pretty, [], [pretty_test_msgs]},
- {compact, [], [compact_test_msgs]},
- {flex_pretty, [], flex_pretty_cases()},
- {flex_compact, [], flex_compact_cases()},
- {bin, [], [bin_test_msgs]}, {ber, [], [ber_test_msgs]},
- {per, [], [per_test_msgs]},
- {erl_dist_m, [], [erl_dist_m_test_msgs]},
- {tickets, [],
- [{group, compact_tickets}, {group, pretty_tickets},
- {group, flex_compact_tickets},
- {group, flex_pretty_tickets}]},
- {compact_tickets, [],
- [compact_otp4011_msg1, compact_otp4011_msg2,
- compact_otp4011_msg3, compact_otp4013_msg1,
- compact_otp4085_msg1, compact_otp4085_msg2,
- compact_otp4280_msg1, compact_otp4299_msg1,
- compact_otp4299_msg2, compact_otp4359_msg1,
- compact_otp4920_msg0, compact_otp4920_msg1,
- compact_otp4920_msg2, compact_otp4920_msg3,
- compact_otp4920_msg4, compact_otp4920_msg5,
- compact_otp4920_msg6, compact_otp4920_msg7,
- compact_otp4920_msg8, compact_otp4920_msg9,
- compact_otp4920_msg10, compact_otp4920_msg11,
- compact_otp4920_msg12, compact_otp4920_msg20,
- compact_otp4920_msg21, compact_otp4920_msg22,
- compact_otp4920_msg23, compact_otp4920_msg24,
- compact_otp4920_msg25, compact_otp5186_msg01,
- compact_otp5186_msg02, compact_otp5186_msg03,
- compact_otp5186_msg04, compact_otp5186_msg05,
- compact_otp5186_msg06, compact_otp5290_msg01,
- compact_otp5290_msg02, compact_otp5793_msg01,
- compact_otp5993_msg01, compact_otp5993_msg02,
- compact_otp5993_msg03, compact_otp6017_msg01,
- compact_otp6017_msg02, compact_otp6017_msg03,
- compact_otp7138_msg01, compact_otp7138_msg02,
- compact_otp7457_msg01, compact_otp7457_msg02,
- compact_otp7457_msg03, compact_otp7534_msg01,
- compact_otp7576_msg01, compact_otp7671_msg01]},
- {flex_compact_tickets, [],
- flex_compact_tickets_cases()},
- {pretty_tickets, [],
- [pretty_otp4632_msg1, pretty_otp4632_msg2,
- pretty_otp4632_msg3, pretty_otp4632_msg4,
- pretty_otp4710_msg1, pretty_otp4710_msg2,
- pretty_otp4945_msg1, pretty_otp4945_msg2,
- pretty_otp4945_msg3, pretty_otp4945_msg4,
- pretty_otp4945_msg5, pretty_otp4945_msg6,
- pretty_otp4949_msg1, pretty_otp4949_msg2,
- pretty_otp4949_msg3, pretty_otp5042_msg1,
- pretty_otp5068_msg1, pretty_otp5085_msg1,
- pretty_otp5085_msg2, pretty_otp5085_msg3,
- pretty_otp5085_msg4, pretty_otp5085_msg5,
- pretty_otp5085_msg6, pretty_otp5085_msg7,
- pretty_otp5600_msg1, pretty_otp5600_msg2,
- pretty_otp5601_msg1, pretty_otp5793_msg01,
- pretty_otp5882_msg01, pretty_otp6490_msg01,
- pretty_otp6490_msg02, pretty_otp6490_msg03,
- pretty_otp6490_msg04, pretty_otp6490_msg05,
- pretty_otp6490_msg06, pretty_otp7249_msg01,
- pretty_otp7671_msg01, pretty_otp7671_msg02,
- pretty_otp7671_msg03, pretty_otp7671_msg04,
- pretty_otp7671_msg05]},
- {flex_pretty_tickets, [], flex_pretty_tickets_cases()}].
+ [{group, pretty},
+ {group, flex_pretty},
+ {group, compact},
+ {group, flex_compact}]},
+ {binary, [],
+ [{group, bin},
+ {group, ber},
+ {group, per}]},
+ {erl_dist, [], [{group, erl_dist_m}]},
+ {pretty, [], [pretty_test_msgs]},
+ {compact, [], [compact_test_msgs]},
+ {flex_pretty, [], flex_pretty_cases()},
+ {flex_compact, [], flex_compact_cases()},
+ {bin, [], [bin_test_msgs]},
+ {ber, [], [ber_test_msgs]},
+ {per, [], [per_test_msgs]},
+ {erl_dist_m, [], [erl_dist_m_test_msgs]},
+ {tickets, [],
+ [{group, compact_tickets},
+ {group, pretty_tickets},
+ {group, flex_compact_tickets},
+ {group, flex_pretty_tickets}]},
+ {compact_tickets, [],
+ [compact_otp4011_msg1, compact_otp4011_msg2,
+ compact_otp4011_msg3, compact_otp4013_msg1,
+ compact_otp4085_msg1, compact_otp4085_msg2,
+ compact_otp4280_msg1, compact_otp4299_msg1,
+ compact_otp4299_msg2, compact_otp4359_msg1,
+ compact_otp4920_msg0, compact_otp4920_msg1,
+ compact_otp4920_msg2, compact_otp4920_msg3,
+ compact_otp4920_msg4, compact_otp4920_msg5,
+ compact_otp4920_msg6, compact_otp4920_msg7,
+ compact_otp4920_msg8, compact_otp4920_msg9,
+ compact_otp4920_msg10, compact_otp4920_msg11,
+ compact_otp4920_msg12, compact_otp4920_msg20,
+ compact_otp4920_msg21, compact_otp4920_msg22,
+ compact_otp4920_msg23, compact_otp4920_msg24,
+ compact_otp4920_msg25, compact_otp5186_msg01,
+ compact_otp5186_msg02, compact_otp5186_msg03,
+ compact_otp5186_msg04, compact_otp5186_msg05,
+ compact_otp5186_msg06, compact_otp5290_msg01,
+ compact_otp5290_msg02, compact_otp5793_msg01,
+ compact_otp5993_msg01, compact_otp5993_msg02,
+ compact_otp5993_msg03, compact_otp6017_msg01,
+ compact_otp6017_msg02, compact_otp6017_msg03,
+ compact_otp7138_msg01, compact_otp7138_msg02,
+ compact_otp7457_msg01, compact_otp7457_msg02,
+ compact_otp7457_msg03, compact_otp7534_msg01,
+ compact_otp7576_msg01, compact_otp7671_msg01]},
+ {flex_compact_tickets, [], flex_compact_tickets_cases()},
+ {pretty_tickets, [],
+ [pretty_otp4632_msg1, pretty_otp4632_msg2,
+ pretty_otp4632_msg3, pretty_otp4632_msg4,
+ pretty_otp4710_msg1, pretty_otp4710_msg2,
+ pretty_otp4945_msg1, pretty_otp4945_msg2,
+ pretty_otp4945_msg3, pretty_otp4945_msg4,
+ pretty_otp4945_msg5, pretty_otp4945_msg6,
+ pretty_otp4949_msg1, pretty_otp4949_msg2,
+ pretty_otp4949_msg3, pretty_otp5042_msg1,
+ pretty_otp5068_msg1, pretty_otp5085_msg1,
+ pretty_otp5085_msg2, pretty_otp5085_msg3,
+ pretty_otp5085_msg4, pretty_otp5085_msg5,
+ pretty_otp5085_msg6, pretty_otp5085_msg7,
+ pretty_otp5600_msg1, pretty_otp5600_msg2,
+ pretty_otp5601_msg1, pretty_otp5793_msg01,
+ pretty_otp5882_msg01, pretty_otp6490_msg01,
+ pretty_otp6490_msg02, pretty_otp6490_msg03,
+ pretty_otp6490_msg04, pretty_otp6490_msg05,
+ pretty_otp6490_msg06, pretty_otp7249_msg01,
+ pretty_otp7671_msg01, pretty_otp7671_msg02,
+ pretty_otp7671_msg03, pretty_otp7671_msg04,
+ pretty_otp7671_msg05]},
+ {flex_pretty_tickets, [], flex_pretty_tickets_cases()}].
init_per_group(flex_pretty_tickets, Config) ->
flex_pretty_init(Config);
@@ -533,92 +533,72 @@ end_per_group(_GroupName, Config) ->
-
-
-
-
-
-
-
flex_pretty_cases() ->
-[flex_pretty_test_msgs].
+ [
+ flex_pretty_test_msgs
+ ].
flex_compact_cases() ->
-[flex_compact_test_msgs, flex_compact_dm_timers1,
- flex_compact_dm_timers2, flex_compact_dm_timers3,
- flex_compact_dm_timers4, flex_compact_dm_timers5,
- flex_compact_dm_timers6, flex_compact_dm_timers7,
- flex_compact_dm_timers8].
-
-
-
-
-
-
-
-
-
-
-%% Support for per_bin was added to ASN.1 as of version
-%% 1.3.2 (R8). And later merged into 1.3.1.3 (R7). These
-%% releases are identical (as far as I know).
-%%
-
-
-
-
-
-
-
-flex_compact_tickets_cases() ->
-[flex_compact_otp7138_msg01, flex_compact_otp7138_msg02,
- flex_compact_otp7431_msg01, flex_compact_otp7431_msg02,
- flex_compact_otp7431_msg03, flex_compact_otp7431_msg04,
- flex_compact_otp7431_msg05, flex_compact_otp7431_msg06,
- flex_compact_otp7431_msg07, flex_compact_otp7138_msg02,
- flex_compact_otp7457_msg01, flex_compact_otp7457_msg02,
- flex_compact_otp7457_msg03, flex_compact_otp7534_msg01,
- flex_compact_otp7573_msg01, flex_compact_otp7576_msg01].
+ [
+ flex_compact_test_msgs,
+ flex_compact_dm_timers1,
+ flex_compact_dm_timers2,
+ flex_compact_dm_timers3,
+ flex_compact_dm_timers4,
+ flex_compact_dm_timers5,
+ flex_compact_dm_timers6,
+ flex_compact_dm_timers7,
+ flex_compact_dm_timers8
+ ].
+flex_compact_tickets_cases() ->
+ [
+ flex_compact_otp7138_msg01,
+ flex_compact_otp7138_msg02,
+ flex_compact_otp7431_msg01,
+ flex_compact_otp7431_msg02,
+ flex_compact_otp7431_msg03,
+ flex_compact_otp7431_msg04,
+ flex_compact_otp7431_msg05,
+ flex_compact_otp7431_msg06,
+ flex_compact_otp7431_msg07,
+ flex_compact_otp7138_msg02,
+ flex_compact_otp7457_msg01,
+ flex_compact_otp7457_msg02,
+ flex_compact_otp7457_msg03,
+ flex_compact_otp7534_msg01,
+ flex_compact_otp7573_msg01,
+ flex_compact_otp7576_msg01,
+ flex_compact_otp10998_msg01,
+ flex_compact_otp10998_msg02,
+ flex_compact_otp10998_msg03,
+ flex_compact_otp10998_msg04
+ ].
flex_pretty_tickets_cases() ->
-[flex_pretty_otp5042_msg1, flex_pretty_otp5085_msg1,
- flex_pretty_otp5085_msg2, flex_pretty_otp5085_msg3,
- flex_pretty_otp5085_msg4, flex_pretty_otp5085_msg5,
- flex_pretty_otp5085_msg6, flex_pretty_otp5085_msg7,
- flex_pretty_otp5600_msg1, flex_pretty_otp5600_msg2,
- flex_pretty_otp5601_msg1, flex_pretty_otp5793_msg01,
- flex_pretty_otp7431_msg01, flex_pretty_otp7431_msg02,
- flex_pretty_otp7431_msg03, flex_pretty_otp7431_msg04,
- flex_pretty_otp7431_msg05, flex_pretty_otp7431_msg06,
- flex_pretty_otp7431_msg07].
-
-%% ----
-
-tickets() ->
- Flag = process_flag(trap_exit, true),
- Cases = expand(tickets),
- Fun = fun(Case) ->
- C = init_per_testcase(Case, [{tc_timeout,
- timer:minutes(10)}]),
- io:format("Eval ~w~n", [Case]),
- Result =
- case (catch apply(?MODULE, Case, [C])) of
- {'EXIT', Reason} ->
- io:format("~n~p exited:~n ~p~n",
- [Case, Reason]),
- {error, {Case, Reason}};
- Res ->
- Res
- end,
- end_per_testcase(Case, C),
- Result
- end,
- process_flag(trap_exit, Flag),
- lists:map(Fun, Cases).
-
+ [
+ flex_pretty_otp5042_msg1,
+ flex_pretty_otp5085_msg1,
+ flex_pretty_otp5085_msg2,
+ flex_pretty_otp5085_msg3,
+ flex_pretty_otp5085_msg4,
+ flex_pretty_otp5085_msg5,
+ flex_pretty_otp5085_msg6,
+ flex_pretty_otp5085_msg7,
+ flex_pretty_otp5600_msg1,
+ flex_pretty_otp5600_msg2,
+ flex_pretty_otp5601_msg1,
+ flex_pretty_otp5793_msg01,
+ flex_pretty_otp7431_msg01,
+ flex_pretty_otp7431_msg02,
+ flex_pretty_otp7431_msg03,
+ flex_pretty_otp7431_msg04,
+ flex_pretty_otp7431_msg05,
+ flex_pretty_otp7431_msg06,
+ flex_pretty_otp7431_msg07
+ ].
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
@@ -3138,14 +3118,792 @@ otp7573(Codec, EC, BinMsg) ->
flex_compact_otp7576_msg01(suite) ->
[];
flex_compact_otp7576_msg01(Config) when is_list(Config) ->
-%% put(dbg, true),
-%% put(severity, trc),
+ %% put(dbg, true),
+ %% put(severity, trc),
d("flex_compact_otp7576_msg01 -> entry", []),
Msg = compact_otp7576_msg01(),
Conf = flex_scanner_conf(Config),
compact_otp7576([Conf], Msg).
+%% killer_42_original
+flex_compact_otp10998_msg01() ->
+ <<"!/2 stofmg0
+P=25165898{C=34227581{AV=r01/03/01/38/22{M{TS{eri_terminfo/dev_state=norm,eri_terminfo/dev_type=cee1,eri_terminfo/law_conv=on,SI=IV},O{MO=SR,RV=OFF,semper/act=on,tdmc/ec=off,semper/termstatus=0x00},L{
+v=0
+c=TN RFC2543 -
+m=audio - TDM -
+}}}},C=34227613{AV=r01/03/01/38/12{M{TS{eri_terminfo/dev_state=norm,eri_terminfo/dev_type=cee1,eri_terminfo/law_conv=on,SI=IV},O{MO=SR,RV=OFF,semper/act=on,tdmc/ec=off,semper/termstatus=0x00},L{
+v=0
+c=TN RFC2543 -
+m=audio - TDM -
+}}}},C=34227744{AV=r01/03/01/38/11{M{TS{eri_terminfo/dev_state=norm,eri_terminfo/dev_type=cee1,eri_terminfo/law_conv=on,SI=IV},O{MO=SR,RV=OFF,semper/act=on,tdmc/ec=off,semper/termstatus=0x00},L{
+v=0
+c=TN RFC2543 -
+m=audio - TDM -
+}}}},C=34227755{AV=r01/03/01/38/2{M{TS{eri_terminfo/dev_state=norm,eri_terminfo/dev_type=cee1,eri_terminfo/law_conv=on,SI=IV},O{MO=SR,RV=OFF,semper/act=on,tdmc/ec=off,semper/termstatus=0x00},L{
+v=0
+c=TN RFC2543 -
+m=audio - TDM -
+}}}},C=34227768{AV=r01/03/01/38/14{M{TS{eri_terminfo/dev_state=norm,eri_terminfo/dev_type=cee1,eri_terminfo/law_conv=on,SI=IV},O{MO=SR,RV=OFF,semper/act=on,tdmc/ec=off,semper/termstatus=0x00},L{
+v=0
+c=TN RFC2543 -
+m=audio - TDM -
+}}}},C=34227774{AV=r01/03/01/38/15{M{TS{eri_terminfo/dev_state=norm,eri_terminfo/dev_type=cee1,eri_terminfo/law_conv=on,SI=IV},O{MO=SR,RV=OFF,semper/act=on,tdmc/ec=off,semper/termstatus=0x00},L{
+v=0
+c=TN RFC2543 -
+m=audio - TDM -
+}}}},C=34227775{AV=r01/03/01/38/16{M{TS{eri_terminfo/dev_state=norm,eri_terminfo/dev_type=cee1,eri_terminfo/law_conv=on,SI=IV},O{MO=SR,RV=OFF,semper/act=on,tdmc/ec=off,semper/termstatus=0x00},L{
+v=0
+c=TN RFC2543 -
+m=audio - TDM -
+}}}},C=34323119{AV=r01/03/01/38/9{M{TS{eri_terminfo/dev_state=norm,eri_terminfo/dev_type=cee1,eri_terminfo/law_conv=on,SI=IV},O{MO=SR,RV=OFF,semper/act=on,tdmc/ec=off,semper/termstatus=0x00},L{
+v=0
+c=TN RFC2543 -
+m=audio - TDM -
+}}}},C=34323122{AV=r01/03/01/38/7{M{TS{eri_terminfo/dev_state=norm,eri_terminfo/dev_type=cee1,eri_terminfo/law_conv=on,SI=IV},O{MO=SR,RV=OFF,semper/act=on,tdmc/ec=off,semper/termstatus=0x00},L{
+v=0
+c=TN RFC2543 -
+m=audio - TDM -
+}}}},C=34323156{AV=r01/03/01/38/8{M{TS{eri_terminfo/dev_state=norm,eri_terminfo/dev_type=cee1,eri_terminfo/law_conv=on,SI=IV},O{MO=SR,RV=OFF,semper/act=on,tdmc/ec=off,semper/termstatus=0x00},L{
+v=0
+c=TN RFC2543 -
+m=audio - TDM -
+}}}},C=34323260{AV=r01/03/01/38/13{M{TS{eri_terminfo/dev_state=norm,eri_terminfo/dev_type=cee1,eri_terminfo/law_conv=on,SI=IV},O{MO=SR,RV=OFF,semper/act=on,tdmc/ec=off,semper/termstatus=0x00},L{
+v=0
+c=TN RFC2543 -
+m=audio - TDM -
+}}}},C=34323272{AV=r01/03/01/38/30{M{TS{eri_terminfo/dev_state=norm,eri_terminfo/dev_type=cee1,eri_terminfo/law_conv=on,SI=IV},O{MO=SR,RV=OFF,semper/act=on,tdmc/ec=off,semper/termstatus=0x00},L{
+v=0
+c=TN RFC2543 -
+m=audio - TDM -
+}}}},C=34323273{AV=r01/03/01/38/29{M{TS{eri_terminfo/dev_state=norm,eri_terminfo/dev_type=cee1,eri_terminfo/law_conv=on,SI=IV},O{MO=SR,RV=OFF,semper/act=on,tdmc/ec=off,semper/termstatus=0x00},L{
+v=0
+c=TN RFC2543 -
+m=audio - TDM -
+}}}},C=34323275{AV=r01/03/01/38/25{M{TS{eri_terminfo/dev_state=norm,eri_terminfo/dev_type=cee1,eri_terminfo/law_conv=on,SI=IV},O{MO=SR,RV=OFF,semper/act=on,tdmc/ec=off,semper/termstatus=0x00},L{
+v=0
+c=TN RFC2543 -
+m=audio - TDM -
+}}}},C=34323276{AV=r01/03/01/38/28{M{TS{eri_terminfo/dev_state=norm,eri_terminfo/dev_type=cee1,eri_terminfo/law_conv=on,SI=IV},O{MO=SR,RV=OFF,semper/act=on,tdmc/ec=off,semper/termstatus=0x00},L{
+v=0
+c=TN RFC2543 -
+m=audio - TDM -
+}}}},C=34323279{AV=r01/03/01/38/26{M{TS{eri_terminfo/dev_state=norm,eri_terminfo/dev_type=cee1,eri_terminfo/law_conv=on,SI=IV},O{MO=SR,RV=OFF,semper/act=on,tdmc/ec=off,semper/termstatus=0x00},L{
+v=0
+c=TN RFC2543 -
+m=audio - TDM -
+}}}},C=34323280{AV=r01/03/01/38/24{M{TS{eri_terminfo/dev_state=norm,eri_terminfo/dev_type=cee1,eri_terminfo/law_conv=on,SI=IV},O{MO=SR,RV=OFF,semper/act=on,tdmc/ec=off,semper/termstatus=0x00},L{
+v=0
+c=TN RFC2543 -
+m=audio - TDM -
+}}}},C=34323281{AV=r01/03/01/38/27{M{TS{eri_terminfo/dev_state=norm,eri_terminfo/dev_type=cee1,eri_terminfo/law_conv=on,SI=IV},O{MO=SR,RV=OFF,semper/act=on,tdmc/ec=off,semper/termstatus=0x00},L{
+v=0
+c=TN RFC2543 -
+m=audio - TDM -
+}}}},C=34323284{AV=r01/03/01/38/23{M{TS{eri_terminfo/dev_state=norm,eri_terminfo/dev_type=cee1,eri_terminfo/law_conv=on,SI=IV},O{MO=SR,RV=OFF,semper/act=on,tdmc/ec=off,semper/termstatus=0x00},L{
+v=0
+c=TN RFC2543 -
+m=audio - TDM -
+}}}},C=34129764{AV=r01/03/01/55/31{M{TS{eri_terminfo/dev_state=norm,eri_terminfo/dev_type=cee1,eri_terminfo/law_conv=on,SI=IV},O{MO=SR,RV=OFF,semper/act=on,tdmc/ec=off,semper/termstatus=0x00},L{
+v=0
+c=TN RFC2543 -
+m=audio - TDM -
+}}}},C=34227463{AV=r01/03/01/55/26{M{TS{eri_terminfo/dev_state=norm,eri_terminfo/dev_type=cee1,eri_terminfo/law_conv=on,SI=IV},O{MO=SR,RV=OFF,semper/act=on,tdmc/ec=off,semper/termstatus=0x00},L{
+v=0
+c=TN RFC2543 -
+m=audio - TDM -
+}}}},C=34227472{AV=r01/03/01/55/22{M{TS{eri_terminfo/dev_state=norm,eri_terminfo/dev_type=cee1,eri_terminfo/law_conv=on,SI=IV},O{MO=SR,RV=OFF,semper/act=on,tdmc/ec=off,semper/termstatus=0x00},L{
+v=0
+c=TN RFC2543 -
+m=audio - TDM -
+}}}},C=34227484{AV=r01/03/01/55/16{M{TS{eri_terminfo/dev_state=norm,eri_terminfo/dev_type=cee1,eri_terminfo/law_conv=on,SI=IV},O{MO=SR,RV=OFF,semper/act=on,tdmc/ec=off,semper/termstatus=0x00},L{
+v=0
+c=TN RFC2543 -
+m=audio - TDM -
+}}}},C=34227555{AV=r01/03/01/55/5{M{TS{eri_terminfo/dev_state=norm,eri_terminfo/dev_type=cee1,eri_terminfo/law_conv=on,SI=IV},O{MO=SR,RV=OFF,semper/act=on,tdmc/ec=off,semper/termstatus=0x00},L{
+v=0
+c=TN RFC2543 -
+m=audio - TDM -
+}}}},C=34227556{AV=r01/03/01/55/14{M{TS{eri_terminfo/dev_state=norm,eri_terminfo/dev_type=cee1,eri_terminfo/law_conv=on,SI=IV},O{MO=SR,RV=OFF,semper/act=on,tdmc/ec=off,semper/termstatus=0x00},L{
+v=0
+c=TN RFC2543 -
+m=audio - TDM -
+}}}},C=34227557{AV=r01/03/01/55/10{M{TS{eri_terminfo/dev_state=norm,eri_terminfo/dev_type=cee1,eri_terminfo/law_conv=on,SI=IV},O{MO=SR,RV=OFF,semper/act=on,tdmc/ec=off,semper/termstatus=0x00},L{
+v=0
+c=TN RFC2543 -
+m=audio - TDM -
+}}}},C=34227563{AV=r01/03/01/55/7{M{TS{eri_terminfo/dev_state=norm,eri_terminfo/dev_type=cee1,eri_terminfo/law_conv=on,SI=IV},O{MO=SR,RV=OFF,semper/act=on,tdmc/ec=off,semper/termstatus=0x00},L{
+v=0
+c=TN RFC2543 -
+m=audio - TDM -
+}}}},C=34227565{AV=r01/03/01/55/13{M{TS{eri_terminfo/dev_state=norm,eri_terminfo/dev_type=cee1,eri_terminfo/law_conv=on,SI=IV},O{MO=SR,RV=OFF,semper/act=on,tdmc/ec=off,semper/termstatus=0x00},L{
+v=0
+c=TN RFC2543 -
+m=audio - TDM -
+}}}},C=34227602{AV=r01/03/01/55/21{M{TS{eri_terminfo/dev_state=norm,eri_terminfo/dev_type=cee1,eri_terminfo/law_conv=on,SI=IV},O{MO=SR,RV=OFF,semper/act=on,tdmc/ec=off,semper/termstatus=0x00},L{
+v=0
+c=TN RFC2543 -
+m=audio - TDM -
+}}}},C=34227616{AV=r01/03/01/55/1{M{TS{eri_terminfo/dev_state=norm,eri_terminfo/dev_type=cee1,eri_terminfo/law_conv=on,SI=IV},O{MO=SR,RV=OFF,semper/act=on,tdmc/ec=off,semper/termstatus=0x00},L{
+v=0
+c=TN RFC2543 -
+m=audio - TDM -
+}}}},C=34227704{AV=r01/03/01/55/19{M{TS{eri_terminfo/dev_state=norm,eri_terminfo/dev_type=cee1,eri_terminfo/law_conv=on,SI=IV},O{MO=SR,RV=OFF,semper/act=on,tdmc/ec=off,semper/termstatus=0x00},L{
+v=0
+c=TN RFC2543 -
+m=audio - TDM -
+}}}},C=34227705{AV=r01/03/01/55/18{M{TS{eri_terminfo/dev_state=norm,eri_terminfo/dev_type=cee1,eri_terminfo/law_conv=on,SI=IV},O{MO=SR,RV=OFF,semper/act=on,tdmc/ec=off,semper/termstatus=0x00},L{
+v=0
+c=TN RFC2543 -
+m=audio - TDM -
+}}}},C=34227715{AV=r01/03/01/55/20{M{TS{eri_terminfo/dev_state=norm,eri_terminfo/dev_type=cee1,eri_terminfo/law_conv=on,SI=IV},O{MO=SR,RV=OFF,semper/act=on,tdmc/ec=off,semper/termstatus=0x00},L{
+v=0
+c=TN RFC2543 -
+m=audio - TDM -
+}}}},C=34322656{AV=r01/03/01/55/30{M{TS{eri_terminfo/dev_state=norm,eri_terminfo/dev_type=cee1,eri_terminfo/law_conv=on,SI=IV},O{MO=SR,RV=OFF,semper/act=on,tdmc/ec=off,semper/termstatus=0x00},L{
+v=0
+c=TN RFC2543 -
+m=audio - TDM -
+}}}},C=34322804{AV=r01/03/01/55/24{M{TS{eri_terminfo/dev_state=norm,eri_terminfo/dev_type=cee1,eri_terminfo/law_conv=on,SI=IV},O{MO=SR,RV=OFF,semper/act=on,tdmc/ec=off,semper/termstatus=0x00},L{
+v=0
+c=TN RFC2543 -
+m=audio - TDM -
+}}}},C=34322812{AV=r01/03/01/55/15{M{TS{eri_terminfo/dev_state=norm,eri_terminfo/dev_type=cee1,eri_terminfo/law_conv=on,SI=IV},O{MO=SR,RV=OFF,semper/act=on,tdmc/ec=off,semper/termstatus=0x00},L{
+v=0
+c=TN RFC2543 -
+m=audio - TDM -
+}}}},C=34322825{AV=r01/03/01/55/4{M{TS{eri_terminfo/dev_state=norm,eri_terminfo/dev_type=cee1,eri_terminfo/law_conv=on,SI=IV},O{MO=SR,RV=OFF,semper/act=on,tdmc/ec=off,semper/termstatus=0x00},L{
+v=0
+c=TN RFC2543 -
+m=audio - TDM -
+}}}},C=34322836{AV=r01/03/01/55/17{M{TS{eri_terminfo/dev_state=norm,eri_terminfo/dev_type=cee1,eri_terminfo/law_conv=on,SI=IV},O{MO=SR,RV=OFF,semper/act=on,tdmc/ec=off,semper/termstatus=0x00},L{
+v=0
+c=TN RFC2543 -
+m=audio - TDM -
+}}}},C=34323007{AV=r01/03/01/55/6{M{TS{eri_terminfo/dev_state=norm,eri_terminfo/dev_type=cee1,eri_terminfo/law_conv=on,SI=IV},O{MO=SR,RV=OFF,semper/act=on,tdmc/ec=off,semper/termstatus=0x00},L{
+v=0
+c=TN RFC2543 -
+m=audio - TDM -
+}}}},C=34323008{AV=r01/03/01/55/2{M{TS{eri_terminfo/dev_state=norm,eri_terminfo/dev_type=cee1,eri_terminfo/law_conv=on,SI=IV},O{MO=SR,RV=OFF,semper/act=on,tdmc/ec=off,semper/termstatus=0x00},L{
+v=0
+c=TN RFC2543 -
+m=audio - TDM -
+}}}},C=34323071{AV=r01/03/01/55/28{M{TS{eri_terminfo/dev_state=norm,eri_terminfo/dev_type=cee1,eri_terminfo/law_conv=on,SI=IV},O{MO=SR,RV=OFF,semper/act=on,tdmc/ec=off,semper/termstatus=0x00},L{
+v=0
+c=TN RFC2543 -
+m=audio - TDM -
+}}}},C=34323075{AV=r01/03/01/55/29{M{TS{eri_terminfo/dev_state=norm,eri_terminfo/dev_type=cee1,eri_terminfo/law_conv=on,SI=IV},O{MO=SR,RV=OFF,semper/act=on,tdmc/ec=off,semper/termstatus=0x00},L{
+v=0
+c=TN RFC2543 -
+m=audio - TDM -
+}}}}}">>.
+
+
+%% size36_27_11_bad.txt
+flex_compact_otp10998_msg02() ->
+ <<"!/2 stofmg0
+P=25167656{C=34205358{AV=r01/03/01/27/22{M{TS{eri_terminfo/dev_state=link,eri_terminfo/dev_type=cee1,eri_terminfo/law_conv=on,SI=OS},O{MO=SR,RV=OFF,semper/act=on,tdmc/ec=off,semper/termstatus=0x01},L{
+v=0
+c=TN RFC2543 -
+m=audio - TDM -
+}}}},C=34205359{AV=r01/03/01/27/13{M{TS{eri_terminfo/dev_state=link,eri_terminfo/dev_type=cee1,eri_terminfo/law_conv=on,SI=OS},O{MO=SR,RV=OFF,semper/act=on,tdmc/ec=off,semper/termstatus=0x01},L{
+v=0
+c=TN RFC2543 -
+m=audio - TDM -
+}}}},C=34205360{AV=r01/03/01/27/23{M{TS{eri_terminfo/dev_state=link,eri_terminfo/dev_type=cee1,eri_terminfo/law_conv=on,SI=OS},O{MO=SR,RV=OFF,semper/act=on,tdmc/ec=off,semper/termstatus=0x01},L{
+v=0
+c=TN RFC2543 -
+m=audio - TDM -
+}}}},C=34227786{AV=r01/03/01/27/8{M{TS{eri_terminfo/dev_state=link,eri_terminfo/dev_type=cee1,eri_terminfo/law_conv=on,SI=OS},O{MO=SR,RV=OFF,semper/act=on,tdmc/ec=off,semper/termstatus=0x01},L{
+v=0
+c=TN RFC2543 -
+m=audio - TDM -
+}}}},C=34230890{AV=r01/03/01/27/15{M{TS{eri_terminfo/dev_state=link,eri_terminfo/dev_type=cee1,eri_terminfo/law_conv=on,SI=OS},O{MO=SR,RV=OFF,semper/act=on,tdmc/ec=off,semper/termstatus=0x01},L{
+v=0
+c=TN RFC2543 -
+m=audio - TDM -
+}}}},C=34230903{AV=r01/03/01/27/24{M{TS{eri_terminfo/dev_state=link,eri_terminfo/dev_type=cee1,eri_terminfo/law_conv=on,SI=OS},O{MO=SR,RV=OFF,semper/act=on,tdmc/ec=off,semper/termstatus=0x01},L{
+v=0
+c=TN RFC2543 -
+m=audio - TDM -
+}}}},C=34230904{AV=r01/03/01/27/14{M{TS{eri_terminfo/dev_state=link,eri_terminfo/dev_type=cee1,eri_terminfo/law_conv=on,SI=OS},O{MO=SR,RV=OFF,semper/act=on,tdmc/ec=off,semper/termstatus=0x01},L{
+v=0
+c=TN RFC2543 -
+m=audio - TDM -
+}}}},C=34230905{AV=r01/03/01/27/12{M{TS{eri_terminfo/dev_state=link,eri_terminfo/dev_type=cee1,eri_terminfo/law_conv=on,SI=OS},O{MO=SR,RV=OFF,semper/act=on,tdmc/ec=off,semper/termstatus=0x01},L{
+v=0
+c=TN RFC2543 -
+m=audio - TDM -
+}}}},C=34230913{AV=r01/03/01/27/4{M{TS{eri_terminfo/dev_state=link,eri_terminfo/dev_type=cee1,eri_terminfo/law_conv=on,SI=OS},O{MO=SR,RV=OFF,semper/act=on,tdmc/ec=off,semper/termstatus=0x01},L{
+v=0
+c=TN RFC2543 -
+m=audio - TDM -
+}}}},C=34316801{AV=r01/03/01/27/9{M{TS{eri_terminfo/dev_state=link,eri_terminfo/dev_type=cee1,eri_terminfo/law_conv=on,SI=OS},O{MO=SR,RV=OFF,semper/act=on,tdmc/ec=off,semper/termstatus=0x01},L{
+v=0
+c=TN RFC2543 -
+m=audio - TDM -
+}}}},C=34316805{AV=r01/03/01/27/19{M{TS{eri_terminfo/dev_state=link,eri_terminfo/dev_type=cee1,eri_terminfo/law_conv=on,SI=OS},O{MO=SR,RV=OFF,semper/act=on,tdmc/ec=off,semper/termstatus=0x01},L{
+v=0
+c=TN RFC2543 -
+m=audio - TDM -
+}}}},C=34316814{AV=r01/03/01/27/5{M{TS{eri_terminfo/dev_state=link,eri_terminfo/dev_type=cee1,eri_terminfo/law_conv=on,SI=OS},O{MO=SR,RV=OFF,semper/act=on,tdmc/ec=off,semper/termstatus=0x01},L{
+v=0
+c=TN RFC2543 -
+m=audio - TDM -
+}}}},C=34316829{AV=r01/03/01/27/7{M{TS{eri_terminfo/dev_state=link,eri_terminfo/dev_type=cee1,eri_terminfo/law_conv=on,SI=OS},O{MO=SR,RV=OFF,semper/act=on,tdmc/ec=off,semper/termstatus=0x01},L{
+v=0
+c=TN RFC2543 -
+m=audio - TDM -
+}}}},C=34323013{AV=r01/03/01/27/6{M{TS{eri_terminfo/dev_state=link,eri_terminfo/dev_type=cee1,eri_terminfo/law_conv=on,SI=OS},O{MO=SR,RV=OFF,semper/act=on,tdmc/ec=off,semper/termstatus=0x01},L{
+v=0
+c=TN RFC2543 -
+m=audio - TDM -
+}}}},C=34107499{AV=r01/03/01/11/14{M{TS{eri_terminfo/dev_state=link,eri_terminfo/dev_type=cee1,eri_terminfo/law_conv=on,SI=OS},O{MO=SR,RV=OFF,semper/act=on,tdmc/ec=off,semper/termstatus=0x01},L{
+v=0
+c=TN RFC2543 -
+m=audio - TDM -
+}}}},C=34107500{AV=r01/03/01/11/4{M{TS{eri_terminfo/dev_state=link,eri_terminfo/dev_type=cee1,eri_terminfo/law_conv=on,SI=OS},O{MO=SR,RV=OFF,semper/act=on,tdmc/ec=off,semper/termstatus=0x01},L{
+v=0
+c=TN RFC2543 -
+m=audio - TDM -
+}}}},C=34107505{AV=r01/03/01/11/8{M{TS{eri_terminfo/dev_state=link,eri_terminfo/dev_type=cee1,eri_terminfo/law_conv=on,SI=OS},O{MO=SR,RV=OFF,semper/act=on,tdmc/ec=off,semper/termstatus=0x01},L{
+v=0
+c=TN RFC2543 -
+m=audio - TDM -
+}}}},C=34316766{AV=r01/03/01/11/3{M{TS{eri_terminfo/dev_state=link,eri_terminfo/dev_type=cee1,eri_terminfo/law_conv=on,SI=OS},O{MO=SR,RV=OFF,semper/act=on,tdmc/ec=off,semper/termstatus=0x01},L{
+v=0
+c=TN RFC2543 -
+m=audio - TDM -
+}}}},C=34316768{AV=r01/03/01/11/10{M{TS{eri_terminfo/dev_state=link,eri_terminfo/dev_type=cee1,eri_terminfo/law_conv=on,SI=OS},O{MO=SR,RV=OFF,semper/act=on,tdmc/ec=off,semper/termstatus=0x01},L{
+v=0
+c=TN RFC2543 -
+m=audio - TDM -
+}}}},C=34316786{AV=r01/03/01/11/12{M{TS{eri_terminfo/dev_state=link,eri_terminfo/dev_type=cee1,eri_terminfo/law_conv=on,SI=OS},O{MO=SR,RV=OFF,semper/act=on,tdmc/ec=off,semper/termstatus=0x01},L{
+v=0
+c=TN RFC2543 -
+m=audio - TDM -
+}}}},C=34316787{AV=r01/03/01/11/1{M{TS{eri_terminfo/dev_state=link,eri_terminfo/dev_type=cee1,eri_terminfo/law_conv=on,SI=OS},O{MO=SR,RV=OFF,semper/act=on,tdmc/ec=off,semper/termstatus=0x01},L{
+v=0
+c=TN RFC2543 -
+m=audio - TDM -
+}}}},C=34316793{AV=r01/03/01/11/22{M{TS{eri_terminfo/dev_state=link,eri_terminfo/dev_type=cee1,eri_terminfo/law_conv=on,SI=OS},O{MO=SR,RV=OFF,semper/act=on,tdmc/ec=off,semper/termstatus=0x01},L{
+v=0
+c=TN RFC2543 -
+m=audio - TDM -
+}}}},C=34316794{AV=r01/03/01/11/24{M{TS{eri_terminfo/dev_state=link,eri_terminfo/dev_type=cee1,eri_terminfo/law_conv=on,SI=OS},O{MO=SR,RV=OFF,semper/act=on,tdmc/ec=off,semper/termstatus=0x01},L{
+v=0
+c=TN RFC2543 -
+m=audio - TDM -
+}}}},C=34316795{AV=r01/03/01/11/31{M{TS{eri_terminfo/dev_state=link,eri_terminfo/dev_type=cee1,eri_terminfo/law_conv=on,SI=OS},O{MO=SR,RV=OFF,semper/act=on,tdmc/ec=off,semper/termstatus=0x01},L{
+v=0
+c=TN RFC2543 -
+m=audio - TDM -
+}}}},C=34316797{AV=r01/03/01/11/18{M{TS{eri_terminfo/dev_state=link,eri_terminfo/dev_type=cee1,eri_terminfo/law_conv=on,SI=OS},O{MO=SR,RV=OFF,semper/act=on,tdmc/ec=off,semper/termstatus=0x01},L{
+v=0
+c=TN RFC2543 -
+m=audio - TDM -
+}}}},C=34316804{AV=r01/03/01/11/15{M{TS{eri_terminfo/dev_state=link,eri_terminfo/dev_type=cee1,eri_terminfo/law_conv=on,SI=OS},O{MO=SR,RV=OFF,semper/act=on,tdmc/ec=off,semper/termstatus=0x01},L{
+v=0
+c=TN RFC2543 -
+m=audio - TDM -
+}}}},C=34316807{AV=r01/03/01/11/6{M{TS{eri_terminfo/dev_state=link,eri_terminfo/dev_type=cee1,eri_terminfo/law_conv=on,SI=OS},O{MO=SR,RV=OFF,semper/act=on,tdmc/ec=off,semper/termstatus=0x01},L{
+v=0
+c=TN RFC2543 -
+m=audio - TDM -
+}}}},C=34316815{AV=r01/03/01/11/16{M{TS{eri_terminfo/dev_state=link,eri_terminfo/dev_type=cee1,eri_terminfo/law_conv=on,SI=OS},O{MO=SR,RV=OFF,semper/act=on,tdmc/ec=off,semper/termstatus=0x01},L{
+v=0
+c=TN RFC2543 -
+m=audio - TDM -
+}}}},C=34316819{AV=r01/03/01/11/28{M{TS{eri_terminfo/dev_state=link,eri_terminfo/dev_type=cee1,eri_terminfo/law_conv=on,SI=OS},O{MO=SR,RV=OFF,semper/act=on,tdmc/ec=off,semper/termstatus=0x01},L{
+v=0
+c=TN RFC2543 -
+m=audio - TDM -
+}}}},C=34316824{AV=r01/03/01/11/17{M{TS{eri_terminfo/dev_state=link,eri_terminfo/dev_type=cee1,eri_terminfo/law_conv=on,SI=OS},O{MO=SR,RV=OFF,semper/act=on,tdmc/ec=off,semper/termstatus=0x01},L{
+v=0
+c=TN RFC2543 -
+m=audio - TDM -
+}}}},C=34316826{AV=r01/03/01/11/25{M{TS{eri_terminfo/dev_state=link,eri_terminfo/dev_type=cee1,eri_terminfo/law_conv=on,SI=OS},O{MO=SR,RV=OFF,semper/act=on,tdmc/ec=off,semper/termstatus=0x01},L{
+v=0
+c=TN RFC2543 -
+m=audio - TDM -
+}}}},C=34316827{AV=r01/03/01/11/9{M{TS{eri_terminfo/dev_state=link,eri_terminfo/dev_type=cee1,eri_terminfo/law_conv=on,SI=OS},O{MO=SR,RV=OFF,semper/act=on,tdmc/ec=off,semper/termstatus=0x01},L{
+v=0
+c=TN RFC2543 -
+m=audio - TDM -
+}}}},C=34316828{AV=r01/03/01/11/21{M{TS{eri_terminfo/dev_state=link,eri_terminfo/dev_type=cee1,eri_terminfo/law_conv=on,SI=OS},O{MO=SR,RV=OFF,semper/act=on,tdmc/ec=off,semper/termstatus=0x01},L{
+v=0
+c=TN RFC2543 -
+m=audio - TDM -
+}}}},C=34316830{AV=r01/03/01/11/2{M{TS{eri_terminfo/dev_state=link,eri_terminfo/dev_type=cee1,eri_terminfo/law_conv=on,SI=OS},O{MO=SR,RV=OFF,semper/act=on,tdmc/ec=off,semper/termstatus=0x01},L{
+v=0
+c=TN RFC2543 -
+m=audio - TDM -
+}}}},C=34316832{AV=r01/03/01/11/11{M{TS{eri_terminfo/dev_state=link,eri_terminfo/dev_type=cee1,eri_terminfo/law_conv=on,SI=OS},O{MO=SR,RV=OFF,semper/act=on,tdmc/ec=off,semper/termstatus=0x01},L{
+v=0
+c=TN RFC2543 -
+m=audio - TDM -
+}}}},C=34316850{AV=r01/03/01/11/5{M{TS{eri_terminfo/dev_state=link,eri_terminfo/dev_type=cee1,eri_terminfo/law_conv=on,SI=OS},O{MO=SR,RV=OFF,semper/act=on,tdmc/ec=off,semper/termstatus=0x01},L{
+v=0
+c=TN RFC2543 -
+m=audio - TDM -
+}}}}}">>.
+
+
+%% size41_38_55_good.txt
+flex_compact_otp10998_msg03() ->
+ <<"!/2 stofmg0
+P=25166035{C=34227581{AV=r01/03/01/38/22{M{TS{eri_terminfo/dev_state=link,eri_terminfo/dev_type=cee1,eri_terminfo/law_conv=on,SI=OS},O{MO=SR,RV=OFF,semper/act=on,tdmc/ec=off,semper/termstatus=0x01},L{
+v=0
+c=TN RFC2543 -
+m=audio - TDM -
+}}}},C=34227613{AV=r01/03/01/38/12{M{TS{eri_terminfo/dev_state=link,eri_terminfo/dev_type=cee1,eri_terminfo/law_conv=on,SI=OS},O{MO=SR,RV=OFF,semper/act=on,tdmc/ec=off,semper/termstatus=0x01},L{
+v=0
+c=TN RFC2543 -
+m=audio - TDM -
+}}}},C=34227744{AV=r01/03/01/38/11{M{TS{eri_terminfo/dev_state=link,eri_terminfo/dev_type=cee1,eri_terminfo/law_conv=on,SI=OS},O{MO=SR,RV=OFF,semper/act=on,tdmc/ec=off,semper/termstatus=0x01},L{
+v=0
+c=TN RFC2543 -
+m=audio - TDM -
+}}}},C=34227755{AV=r01/03/01/38/2{M{TS{eri_terminfo/dev_state=link,eri_terminfo/dev_type=cee1,eri_terminfo/law_conv=on,SI=OS},O{MO=SR,RV=OFF,semper/act=on,tdmc/ec=off,semper/termstatus=0x01},L{
+v=0
+c=TN RFC2543 -
+m=audio - TDM -
+}}}},C=34227768{AV=r01/03/01/38/14{M{TS{eri_terminfo/dev_state=link,eri_terminfo/dev_type=cee1,eri_terminfo/law_conv=on,SI=OS},O{MO=SR,RV=OFF,semper/act=on,tdmc/ec=off,semper/termstatus=0x01},L{
+v=0
+c=TN RFC2543 -
+m=audio - TDM -
+}}}},C=34227774{AV=r01/03/01/38/15{M{TS{eri_terminfo/dev_state=link,eri_terminfo/dev_type=cee1,eri_terminfo/law_conv=on,SI=OS},O{MO=SR,RV=OFF,semper/act=on,tdmc/ec=off,semper/termstatus=0x01},L{
+v=0
+c=TN RFC2543 -
+m=audio - TDM -
+}}}},C=34227775{AV=r01/03/01/38/16{M{TS{eri_terminfo/dev_state=link,eri_terminfo/dev_type=cee1,eri_terminfo/law_conv=on,SI=OS},O{MO=SR,RV=OFF,semper/act=on,tdmc/ec=off,semper/termstatus=0x01},L{
+v=0
+c=TN RFC2543 -
+m=audio - TDM -
+}}}},C=34323122{AV=r01/03/01/38/7{M{TS{eri_terminfo/dev_state=link,eri_terminfo/dev_type=cee1,eri_terminfo/law_conv=on,SI=OS},O{MO=SR,RV=OFF,semper/act=on,tdmc/ec=off,semper/termstatus=0x01},L{
+v=0
+c=TN RFC2543 -
+m=audio - TDM -
+}}}},C=34323156{AV=r01/03/01/38/8{M{TS{eri_terminfo/dev_state=link,eri_terminfo/dev_type=cee1,eri_terminfo/law_conv=on,SI=OS},O{MO=SR,RV=OFF,semper/act=on,tdmc/ec=off,semper/termstatus=0x01},L{
+v=0
+c=TN RFC2543 -
+m=audio - TDM -
+}}}},C=34323260{AV=r01/03/01/38/13{M{TS{eri_terminfo/dev_state=link,eri_terminfo/dev_type=cee1,eri_terminfo/law_conv=on,SI=OS},O{MO=SR,RV=OFF,semper/act=on,tdmc/ec=off,semper/termstatus=0x01},L{
+v=0
+c=TN RFC2543 -
+m=audio - TDM -
+}}}},C=34323272{AV=r01/03/01/38/30{M{TS{eri_terminfo/dev_state=link,eri_terminfo/dev_type=cee1,eri_terminfo/law_conv=on,SI=OS},O{MO=SR,RV=OFF,semper/act=on,tdmc/ec=off,semper/termstatus=0x01},L{
+v=0
+c=TN RFC2543 -
+m=audio - TDM -
+}}}},C=34323273{AV=r01/03/01/38/29{M{TS{eri_terminfo/dev_state=link,eri_terminfo/dev_type=cee1,eri_terminfo/law_conv=on,SI=OS},O{MO=SR,RV=OFF,semper/act=on,tdmc/ec=off,semper/termstatus=0x01},L{
+v=0
+c=TN RFC2543 -
+m=audio - TDM -
+}}}},C=34323275{AV=r01/03/01/38/25{M{TS{eri_terminfo/dev_state=link,eri_terminfo/dev_type=cee1,eri_terminfo/law_conv=on,SI=OS},O{MO=SR,RV=OFF,semper/act=on,tdmc/ec=off,semper/termstatus=0x01},L{
+v=0
+c=TN RFC2543 -
+m=audio - TDM -
+}}}},C=34323276{AV=r01/03/01/38/28{M{TS{eri_terminfo/dev_state=link,eri_terminfo/dev_type=cee1,eri_terminfo/law_conv=on,SI=OS},O{MO=SR,RV=OFF,semper/act=on,tdmc/ec=off,semper/termstatus=0x01},L{
+v=0
+c=TN RFC2543 -
+m=audio - TDM -
+}}}},C=34323279{AV=r01/03/01/38/26{M{TS{eri_terminfo/dev_state=link,eri_terminfo/dev_type=cee1,eri_terminfo/law_conv=on,SI=OS},O{MO=SR,RV=OFF,semper/act=on,tdmc/ec=off,semper/termstatus=0x01},L{
+v=0
+c=TN RFC2543 -
+m=audio - TDM -
+}}}},C=34323280{AV=r01/03/01/38/24{M{TS{eri_terminfo/dev_state=link,eri_terminfo/dev_type=cee1,eri_terminfo/law_conv=on,SI=OS},O{MO=SR,RV=OFF,semper/act=on,tdmc/ec=off,semper/termstatus=0x01},L{
+v=0
+c=TN RFC2543 -
+m=audio - TDM -
+}}}},C=34323281{AV=r01/03/01/38/27{M{TS{eri_terminfo/dev_state=link,eri_terminfo/dev_type=cee1,eri_terminfo/law_conv=on,SI=OS},O{MO=SR,RV=OFF,semper/act=on,tdmc/ec=off,semper/termstatus=0x01},L{
+v=0
+c=TN RFC2543 -
+m=audio - TDM -
+}}}},C=34323284{AV=r01/03/01/38/23{M{TS{eri_terminfo/dev_state=link,eri_terminfo/dev_type=cee1,eri_terminfo/law_conv=on,SI=OS},O{MO=SR,RV=OFF,semper/act=on,tdmc/ec=off,semper/termstatus=0x01},L{
+v=0
+c=TN RFC2543 -
+m=audio - TDM -
+}}}},C=34129764{AV=r01/03/01/55/31{M{TS{eri_terminfo/dev_state=link,eri_terminfo/dev_type=cee1,eri_terminfo/law_conv=on,SI=OS},O{MO=SR,RV=OFF,semper/act=on,tdmc/ec=off,semper/termstatus=0x01},L{
+v=0
+c=TN RFC2543 -
+m=audio - TDM -
+}}}},C=34227463{AV=r01/03/01/55/26{M{TS{eri_terminfo/dev_state=link,eri_terminfo/dev_type=cee1,eri_terminfo/law_conv=on,SI=OS},O{MO=SR,RV=OFF,semper/act=on,tdmc/ec=off,semper/termstatus=0x01},L{
+v=0
+c=TN RFC2543 -
+m=audio - TDM -
+}}}},C=34227472{AV=r01/03/01/55/22{M{TS{eri_terminfo/dev_state=link,eri_terminfo/dev_type=cee1,eri_terminfo/law_conv=on,SI=OS},O{MO=SR,RV=OFF,semper/act=on,tdmc/ec=off,semper/termstatus=0x01},L{
+v=0
+c=TN RFC2543 -
+m=audio - TDM -
+}}}},C=34227484{AV=r01/03/01/55/16{M{TS{eri_terminfo/dev_state=link,eri_terminfo/dev_type=cee1,eri_terminfo/law_conv=on,SI=OS},O{MO=SR,RV=OFF,semper/act=on,tdmc/ec=off,semper/termstatus=0x01},L{
+v=0
+c=TN RFC2543 -
+m=audio - TDM -
+}}}},C=34227555{AV=r01/03/01/55/5{M{TS{eri_terminfo/dev_state=link,eri_terminfo/dev_type=cee1,eri_terminfo/law_conv=on,SI=OS},O{MO=SR,RV=OFF,semper/act=on,tdmc/ec=off,semper/termstatus=0x01},L{
+v=0
+c=TN RFC2543 -
+m=audio - TDM -
+}}}},C=34227556{AV=r01/03/01/55/14{M{TS{eri_terminfo/dev_state=link,eri_terminfo/dev_type=cee1,eri_terminfo/law_conv=on,SI=OS},O{MO=SR,RV=OFF,semper/act=on,tdmc/ec=off,semper/termstatus=0x01},L{
+v=0
+c=TN RFC2543 -
+m=audio - TDM -
+}}}},C=34227557{AV=r01/03/01/55/10{M{TS{eri_terminfo/dev_state=link,eri_terminfo/dev_type=cee1,eri_terminfo/law_conv=on,SI=OS},O{MO=SR,RV=OFF,semper/act=on,tdmc/ec=off,semper/termstatus=0x01},L{
+v=0
+c=TN RFC2543 -
+m=audio - TDM -
+}}}},C=34227563{AV=r01/03/01/55/7{M{TS{eri_terminfo/dev_state=link,eri_terminfo/dev_type=cee1,eri_terminfo/law_conv=on,SI=OS},O{MO=SR,RV=OFF,semper/act=on,tdmc/ec=off,semper/termstatus=0x01},L{
+v=0
+c=TN RFC2543 -
+m=audio - TDM -
+}}}},C=34227565{AV=r01/03/01/55/13{M{TS{eri_terminfo/dev_state=link,eri_terminfo/dev_type=cee1,eri_terminfo/law_conv=on,SI=OS},O{MO=SR,RV=OFF,semper/act=on,tdmc/ec=off,semper/termstatus=0x01},L{
+v=0
+c=TN RFC2543 -
+m=audio - TDM -
+}}}},C=34227602{AV=r01/03/01/55/21{M{TS{eri_terminfo/dev_state=link,eri_terminfo/dev_type=cee1,eri_terminfo/law_conv=on,SI=OS},O{MO=SR,RV=OFF,semper/act=on,tdmc/ec=off,semper/termstatus=0x01},L{
+v=0
+c=TN RFC2543 -
+m=audio - TDM -
+}}}},C=34227616{AV=r01/03/01/55/1{M{TS{eri_terminfo/dev_state=link,eri_terminfo/dev_type=cee1,eri_terminfo/law_conv=on,SI=OS},O{MO=SR,RV=OFF,semper/act=on,tdmc/ec=off,semper/termstatus=0x01},L{
+v=0
+c=TN RFC2543 -
+m=audio - TDM -
+}}}},C=34227704{AV=r01/03/01/55/19{M{TS{eri_terminfo/dev_state=link,eri_terminfo/dev_type=cee1,eri_terminfo/law_conv=on,SI=OS},O{MO=SR,RV=OFF,semper/act=on,tdmc/ec=off,semper/termstatus=0x01},L{
+v=0
+c=TN RFC2543 -
+m=audio - TDM -
+}}}},C=34227705{AV=r01/03/01/55/18{M{TS{eri_terminfo/dev_state=link,eri_terminfo/dev_type=cee1,eri_terminfo/law_conv=on,SI=OS},O{MO=SR,RV=OFF,semper/act=on,tdmc/ec=off,semper/termstatus=0x01},L{
+v=0
+c=TN RFC2543 -
+m=audio - TDM -
+}}}},C=34227715{AV=r01/03/01/55/20{M{TS{eri_terminfo/dev_state=link,eri_terminfo/dev_type=cee1,eri_terminfo/law_conv=on,SI=OS},O{MO=SR,RV=OFF,semper/act=on,tdmc/ec=off,semper/termstatus=0x01},L{
+v=0
+c=TN RFC2543 -
+m=audio - TDM -
+}}}},C=34322656{AV=r01/03/01/55/30{M{TS{eri_terminfo/dev_state=link,eri_terminfo/dev_type=cee1,eri_terminfo/law_conv=on,SI=OS},O{MO=SR,RV=OFF,semper/act=on,tdmc/ec=off,semper/termstatus=0x01},L{
+v=0
+c=TN RFC2543 -
+m=audio - TDM -
+}}}},C=34322804{AV=r01/03/01/55/24{M{TS{eri_terminfo/dev_state=link,eri_terminfo/dev_type=cee1,eri_terminfo/law_conv=on,SI=OS},O{MO=SR,RV=OFF,semper/act=on,tdmc/ec=off,semper/termstatus=0x01},L{
+v=0
+c=TN RFC2543 -
+m=audio - TDM -
+}}}},C=34322812{AV=r01/03/01/55/15{M{TS{eri_terminfo/dev_state=link,eri_terminfo/dev_type=cee1,eri_terminfo/law_conv=on,SI=OS},O{MO=SR,RV=OFF,semper/act=on,tdmc/ec=off,semper/termstatus=0x01},L{
+v=0
+c=TN RFC2543 -
+m=audio - TDM -
+}}}},C=34322825{AV=r01/03/01/55/4{M{TS{eri_terminfo/dev_state=link,eri_terminfo/dev_type=cee1,eri_terminfo/law_conv=on,SI=OS},O{MO=SR,RV=OFF,semper/act=on,tdmc/ec=off,semper/termstatus=0x01},L{
+v=0
+c=TN RFC2543 -
+m=audio - TDM -
+}}}},C=34322836{AV=r01/03/01/55/17{M{TS{eri_terminfo/dev_state=link,eri_terminfo/dev_type=cee1,eri_terminfo/law_conv=on,SI=OS},O{MO=SR,RV=OFF,semper/act=on,tdmc/ec=off,semper/termstatus=0x01},L{
+v=0
+c=TN RFC2543 -
+m=audio - TDM -
+}}}},C=34323007{AV=r01/03/01/55/6{M{TS{eri_terminfo/dev_state=link,eri_terminfo/dev_type=cee1,eri_terminfo/law_conv=on,SI=OS},O{MO=SR,RV=OFF,semper/act=on,tdmc/ec=off,semper/termstatus=0x01},L{
+v=0
+c=TN RFC2543 -
+m=audio - TDM -
+}}}},C=34323008{AV=r01/03/01/55/2{M{TS{eri_terminfo/dev_state=link,eri_terminfo/dev_type=cee1,eri_terminfo/law_conv=on,SI=OS},O{MO=SR,RV=OFF,semper/act=on,tdmc/ec=off,semper/termstatus=0x01},L{
+v=0
+c=TN RFC2543 -
+m=audio - TDM -
+}}}},C=34323071{AV=r01/03/01/55/28{M{TS{eri_terminfo/dev_state=link,eri_terminfo/dev_type=cee1,eri_terminfo/law_conv=on,SI=OS},O{MO=SR,RV=OFF,semper/act=on,tdmc/ec=off,semper/termstatus=0x01},L{
+v=0
+c=TN RFC2543 -
+m=audio - TDM -
+}}}},C=34323075{AV=r01/03/01/55/29{M{TS{eri_terminfo/dev_state=link,eri_terminfo/dev_type=cee1,eri_terminfo/law_conv=on,SI=OS},O{MO=SR,RV=OFF,semper/act=on,tdmc/ec=off,semper/termstatus=0x01},L{
+v=0
+c=TN RFC2543 -
+m=audio - TDM -
+}}}}}">>.
+
+
+%% size42_38_55_bad.txt
+flex_compact_otp10998_msg04() ->
+ <<"!/2 stofmg0
+P=33555020{C=34227581{AV=r01/03/01/38/22{M{TS{eri_terminfo/dev_state=link,eri_terminfo/dev_type=cee1,eri_terminfo/law_conv=on,SI=OS},O{MO=SR,RV=OFF,semper/act=on,tdmc/ec=off,semper/termstatus=0x01},L{
+v=0
+c=TN RFC2543 -
+m=audio - TDM -
+}}}},C=34227613{AV=r01/03/01/38/12{M{TS{eri_terminfo/dev_state=link,eri_terminfo/dev_type=cee1,eri_terminfo/law_conv=on,SI=OS},O{MO=SR,RV=OFF,semper/act=on,tdmc/ec=off,semper/termstatus=0x01},L{
+v=0
+c=TN RFC2543 -
+m=audio - TDM -
+}}}},C=34227744{AV=r01/03/01/38/11{M{TS{eri_terminfo/dev_state=link,eri_terminfo/dev_type=cee1,eri_terminfo/law_conv=on,SI=OS},O{MO=SR,RV=OFF,semper/act=on,tdmc/ec=off,semper/termstatus=0x01},L{
+v=0
+c=TN RFC2543 -
+m=audio - TDM -
+}}}},C=34227755{AV=r01/03/01/38/2{M{TS{eri_terminfo/dev_state=link,eri_terminfo/dev_type=cee1,eri_terminfo/law_conv=on,SI=OS},O{MO=SR,RV=OFF,semper/act=on,tdmc/ec=off,semper/termstatus=0x01},L{
+v=0
+c=TN RFC2543 -
+m=audio - TDM -
+}}}},C=34227768{AV=r01/03/01/38/14{M{TS{eri_terminfo/dev_state=link,eri_terminfo/dev_type=cee1,eri_terminfo/law_conv=on,SI=OS},O{MO=SR,RV=OFF,semper/act=on,tdmc/ec=off,semper/termstatus=0x01},L{
+v=0
+c=TN RFC2543 -
+m=audio - TDM -
+}}}},C=34227774{AV=r01/03/01/38/15{M{TS{eri_terminfo/dev_state=link,eri_terminfo/dev_type=cee1,eri_terminfo/law_conv=on,SI=OS},O{MO=SR,RV=OFF,semper/act=on,tdmc/ec=off,semper/termstatus=0x01},L{
+v=0
+c=TN RFC2543 -
+m=audio - TDM -
+}}}},C=34227775{AV=r01/03/01/38/16{M{TS{eri_terminfo/dev_state=link,eri_terminfo/dev_type=cee1,eri_terminfo/law_conv=on,SI=OS},O{MO=SR,RV=OFF,semper/act=on,tdmc/ec=off,semper/termstatus=0x01},L{
+v=0
+c=TN RFC2543 -
+m=audio - TDM -
+}}}},C=34323119{AV=r01/03/01/38/9{M{TS{eri_terminfo/dev_state=link,eri_terminfo/dev_type=cee1,eri_terminfo/law_conv=on,SI=OS},O{MO=SR,RV=OFF,semper/act=on,tdmc/ec=off,semper/termstatus=0x01},L{
+v=0
+c=TN RFC2543 -
+m=audio - TDM -
+}}}},C=34323122{AV=r01/03/01/38/7{M{TS{eri_terminfo/dev_state=link,eri_terminfo/dev_type=cee1,eri_terminfo/law_conv=on,SI=OS},O{MO=SR,RV=OFF,semper/act=on,tdmc/ec=off,semper/termstatus=0x01},L{
+v=0
+c=TN RFC2543 -
+m=audio - TDM -
+}}}},C=34323156{AV=r01/03/01/38/8{M{TS{eri_terminfo/dev_state=link,eri_terminfo/dev_type=cee1,eri_terminfo/law_conv=on,SI=OS},O{MO=SR,RV=OFF,semper/act=on,tdmc/ec=off,semper/termstatus=0x01},L{
+v=0
+c=TN RFC2543 -
+m=audio - TDM -
+}}}},C=34323260{AV=r01/03/01/38/13{M{TS{eri_terminfo/dev_state=link,eri_terminfo/dev_type=cee1,eri_terminfo/law_conv=on,SI=OS},O{MO=SR,RV=OFF,semper/act=on,tdmc/ec=off,semper/termstatus=0x01},L{
+v=0
+c=TN RFC2543 -
+m=audio - TDM -
+}}}},C=34323272{AV=r01/03/01/38/30{M{TS{eri_terminfo/dev_state=link,eri_terminfo/dev_type=cee1,eri_terminfo/law_conv=on,SI=OS},O{MO=SR,RV=OFF,semper/act=on,tdmc/ec=off,semper/termstatus=0x01},L{
+v=0
+c=TN RFC2543 -
+m=audio - TDM -
+}}}},C=34323273{AV=r01/03/01/38/29{M{TS{eri_terminfo/dev_state=link,eri_terminfo/dev_type=cee1,eri_terminfo/law_conv=on,SI=OS},O{MO=SR,RV=OFF,semper/act=on,tdmc/ec=off,semper/termstatus=0x01},L{
+v=0
+c=TN RFC2543 -
+m=audio - TDM -
+}}}},C=34323275{AV=r01/03/01/38/25{M{TS{eri_terminfo/dev_state=link,eri_terminfo/dev_type=cee1,eri_terminfo/law_conv=on,SI=OS},O{MO=SR,RV=OFF,semper/act=on,tdmc/ec=off,semper/termstatus=0x01},L{
+v=0
+c=TN RFC2543 -
+m=audio - TDM -
+}}}},C=34323276{AV=r01/03/01/38/28{M{TS{eri_terminfo/dev_state=link,eri_terminfo/dev_type=cee1,eri_terminfo/law_conv=on,SI=OS},O{MO=SR,RV=OFF,semper/act=on,tdmc/ec=off,semper/termstatus=0x01},L{
+v=0
+c=TN RFC2543 -
+m=audio - TDM -
+}}}},C=34323279{AV=r01/03/01/38/26{M{TS{eri_terminfo/dev_state=link,eri_terminfo/dev_type=cee1,eri_terminfo/law_conv=on,SI=OS},O{MO=SR,RV=OFF,semper/act=on,tdmc/ec=off,semper/termstatus=0x01},L{
+v=0
+c=TN RFC2543 -
+m=audio - TDM -
+}}}},C=34323280{AV=r01/03/01/38/24{M{TS{eri_terminfo/dev_state=link,eri_terminfo/dev_type=cee1,eri_terminfo/law_conv=on,SI=OS},O{MO=SR,RV=OFF,semper/act=on,tdmc/ec=off,semper/termstatus=0x01},L{
+v=0
+c=TN RFC2543 -
+m=audio - TDM -
+}}}},C=34323281{AV=r01/03/01/38/27{M{TS{eri_terminfo/dev_state=link,eri_terminfo/dev_type=cee1,eri_terminfo/law_conv=on,SI=OS},O{MO=SR,RV=OFF,semper/act=on,tdmc/ec=off,semper/termstatus=0x01},L{
+v=0
+c=TN RFC2543 -
+m=audio - TDM -
+}}}},C=34323284{AV=r01/03/01/38/23{M{TS{eri_terminfo/dev_state=link,eri_terminfo/dev_type=cee1,eri_terminfo/law_conv=on,SI=OS},O{MO=SR,RV=OFF,semper/act=on,tdmc/ec=off,semper/termstatus=0x01},L{
+v=0
+c=TN RFC2543 -
+m=audio - TDM -
+}}}},C=34129764{AV=r01/03/01/55/31{M{TS{eri_terminfo/dev_state=link,eri_terminfo/dev_type=cee1,eri_terminfo/law_conv=on,SI=OS},O{MO=SR,RV=OFF,semper/act=on,tdmc/ec=off,semper/termstatus=0x01},L{
+v=0
+c=TN RFC2543 -
+m=audio - TDM -
+}}}},C=34227463{AV=r01/03/01/55/26{M{TS{eri_terminfo/dev_state=link,eri_terminfo/dev_type=cee1,eri_terminfo/law_conv=on,SI=OS},O{MO=SR,RV=OFF,semper/act=on,tdmc/ec=off,semper/termstatus=0x01},L{
+v=0
+c=TN RFC2543 -
+m=audio - TDM -
+}}}},C=34227472{AV=r01/03/01/55/22{M{TS{eri_terminfo/dev_state=link,eri_terminfo/dev_type=cee1,eri_terminfo/law_conv=on,SI=OS},O{MO=SR,RV=OFF,semper/act=on,tdmc/ec=off,semper/termstatus=0x01},L{
+v=0
+c=TN RFC2543 -
+m=audio - TDM -
+}}}},C=34227484{AV=r01/03/01/55/16{M{TS{eri_terminfo/dev_state=link,eri_terminfo/dev_type=cee1,eri_terminfo/law_conv=on,SI=OS},O{MO=SR,RV=OFF,semper/act=on,tdmc/ec=off,semper/termstatus=0x01},L{
+v=0
+c=TN RFC2543 -
+m=audio - TDM -
+}}}},C=34227555{AV=r01/03/01/55/5{M{TS{eri_terminfo/dev_state=link,eri_terminfo/dev_type=cee1,eri_terminfo/law_conv=on,SI=OS},O{MO=SR,RV=OFF,semper/act=on,tdmc/ec=off,semper/termstatus=0x01},L{
+v=0
+c=TN RFC2543 -
+m=audio - TDM -
+}}}},C=34227556{AV=r01/03/01/55/14{M{TS{eri_terminfo/dev_state=link,eri_terminfo/dev_type=cee1,eri_terminfo/law_conv=on,SI=OS},O{MO=SR,RV=OFF,semper/act=on,tdmc/ec=off,semper/termstatus=0x01},L{
+v=0
+c=TN RFC2543 -
+m=audio - TDM -
+}}}},C=34227557{AV=r01/03/01/55/10{M{TS{eri_terminfo/dev_state=link,eri_terminfo/dev_type=cee1,eri_terminfo/law_conv=on,SI=OS},O{MO=SR,RV=OFF,semper/act=on,tdmc/ec=off,semper/termstatus=0x01},L{
+v=0
+c=TN RFC2543 -
+m=audio - TDM -
+}}}},C=34227563{AV=r01/03/01/55/7{M{TS{eri_terminfo/dev_state=link,eri_terminfo/dev_type=cee1,eri_terminfo/law_conv=on,SI=OS},O{MO=SR,RV=OFF,semper/act=on,tdmc/ec=off,semper/termstatus=0x01},L{
+v=0
+c=TN RFC2543 -
+m=audio - TDM -
+}}}},C=34227565{AV=r01/03/01/55/13{M{TS{eri_terminfo/dev_state=link,eri_terminfo/dev_type=cee1,eri_terminfo/law_conv=on,SI=OS},O{MO=SR,RV=OFF,semper/act=on,tdmc/ec=off,semper/termstatus=0x01},L{
+v=0
+c=TN RFC2543 -
+m=audio - TDM -
+}}}},C=34227602{AV=r01/03/01/55/21{M{TS{eri_terminfo/dev_state=link,eri_terminfo/dev_type=cee1,eri_terminfo/law_conv=on,SI=OS},O{MO=SR,RV=OFF,semper/act=on,tdmc/ec=off,semper/termstatus=0x01},L{
+v=0
+c=TN RFC2543 -
+m=audio - TDM -
+}}}},C=34227616{AV=r01/03/01/55/1{M{TS{eri_terminfo/dev_state=link,eri_terminfo/dev_type=cee1,eri_terminfo/law_conv=on,SI=OS},O{MO=SR,RV=OFF,semper/act=on,tdmc/ec=off,semper/termstatus=0x01},L{
+v=0
+c=TN RFC2543 -
+m=audio - TDM -
+}}}},C=34227704{AV=r01/03/01/55/19{M{TS{eri_terminfo/dev_state=link,eri_terminfo/dev_type=cee1,eri_terminfo/law_conv=on,SI=OS},O{MO=SR,RV=OFF,semper/act=on,tdmc/ec=off,semper/termstatus=0x01},L{
+v=0
+c=TN RFC2543 -
+m=audio - TDM -
+}}}},C=34227705{AV=r01/03/01/55/18{M{TS{eri_terminfo/dev_state=link,eri_terminfo/dev_type=cee1,eri_terminfo/law_conv=on,SI=OS},O{MO=SR,RV=OFF,semper/act=on,tdmc/ec=off,semper/termstatus=0x01},L{
+v=0
+c=TN RFC2543 -
+m=audio - TDM -
+}}}},C=34227715{AV=r01/03/01/55/20{M{TS{eri_terminfo/dev_state=link,eri_terminfo/dev_type=cee1,eri_terminfo/law_conv=on,SI=OS},O{MO=SR,RV=OFF,semper/act=on,tdmc/ec=off,semper/termstatus=0x01},L{
+v=0
+c=TN RFC2543 -
+m=audio - TDM -
+}}}},C=34322656{AV=r01/03/01/55/30{M{TS{eri_terminfo/dev_state=link,eri_terminfo/dev_type=cee1,eri_terminfo/law_conv=on,SI=OS},O{MO=SR,RV=OFF,semper/act=on,tdmc/ec=off,semper/termstatus=0x01},L{
+v=0
+c=TN RFC2543 -
+m=audio - TDM -
+}}}},C=34322804{AV=r01/03/01/55/24{M{TS{eri_terminfo/dev_state=link,eri_terminfo/dev_type=cee1,eri_terminfo/law_conv=on,SI=OS},O{MO=SR,RV=OFF,semper/act=on,tdmc/ec=off,semper/termstatus=0x01},L{
+v=0
+c=TN RFC2543 -
+m=audio - TDM -
+}}}},C=34322812{AV=r01/03/01/55/15{M{TS{eri_terminfo/dev_state=link,eri_terminfo/dev_type=cee1,eri_terminfo/law_conv=on,SI=OS},O{MO=SR,RV=OFF,semper/act=on,tdmc/ec=off,semper/termstatus=0x01},L{
+v=0
+c=TN RFC2543 -
+m=audio - TDM -
+}}}},C=34322825{AV=r01/03/01/55/4{M{TS{eri_terminfo/dev_state=link,eri_terminfo/dev_type=cee1,eri_terminfo/law_conv=on,SI=OS},O{MO=SR,RV=OFF,semper/act=on,tdmc/ec=off,semper/termstatus=0x01},L{
+v=0
+c=TN RFC2543 -
+m=audio - TDM -
+}}}},C=34322836{AV=r01/03/01/55/17{M{TS{eri_terminfo/dev_state=link,eri_terminfo/dev_type=cee1,eri_terminfo/law_conv=on,SI=OS},O{MO=SR,RV=OFF,semper/act=on,tdmc/ec=off,semper/termstatus=0x01},L{
+v=0
+c=TN RFC2543 -
+m=audio - TDM -
+}}}},C=34323007{AV=r01/03/01/55/6{M{TS{eri_terminfo/dev_state=link,eri_terminfo/dev_type=cee1,eri_terminfo/law_conv=on,SI=OS},O{MO=SR,RV=OFF,semper/act=on,tdmc/ec=off,semper/termstatus=0x01},L{
+v=0
+c=TN RFC2543 -
+m=audio - TDM -
+}}}},C=34323008{AV=r01/03/01/55/2{M{TS{eri_terminfo/dev_state=link,eri_terminfo/dev_type=cee1,eri_terminfo/law_conv=on,SI=OS},O{MO=SR,RV=OFF,semper/act=on,tdmc/ec=off,semper/termstatus=0x01},L{
+v=0
+c=TN RFC2543 -
+m=audio - TDM -
+}}}},C=34323071{AV=r01/03/01/55/28{M{TS{eri_terminfo/dev_state=link,eri_terminfo/dev_type=cee1,eri_terminfo/law_conv=on,SI=OS},O{MO=SR,RV=OFF,semper/act=on,tdmc/ec=off,semper/termstatus=0x01},L{
+v=0
+c=TN RFC2543 -
+m=audio - TDM -
+}}}},C=34323075{AV=r01/03/01/55/29{M{TS{eri_terminfo/dev_state=link,eri_terminfo/dev_type=cee1,eri_terminfo/law_conv=on,SI=OS},O{MO=SR,RV=OFF,semper/act=on,tdmc/ec=off,semper/termstatus=0x01},L{
+v=0
+c=TN RFC2543 -
+m=audio - TDM -
+}}}}}">>.
+
+
+flex_compact_otp10998_num() ->
+ 10.
+
+flex_compact_otp10998_msg01(suite) ->
+ [];
+flex_compact_otp10998_msg01(Config) when is_list(Config) ->
+ %% put(dbg, true),
+ %% put(severity, trc),
+ d("flex_compact_otp10998_msg01 -> entry", []),
+ Msg = flex_compact_otp10998_msg01(),
+ d("flex_compact_otp10998_msg01 -> message created", []),
+ Conf =
+ try flex_scanner_conf(Config) of
+ C ->
+ C
+ catch
+ exit:Error ->
+ e("Failed getting flex config: "
+ "~n Error: ~p", [Error]),
+ exit(Error)
+ end,
+ d("flex_compact_otp10998_msg01 -> flex config generated", []),
+ flex_compact_otp10998([Conf], flex_compact_otp10998_num(), Msg).
+
+flex_compact_otp10998_msg02(suite) ->
+ [];
+flex_compact_otp10998_msg02(Config) when is_list(Config) ->
+ %% put(dbg, true),
+ %% put(severity, trc),
+ d("flex_compact_otp10998_msg02 -> entry", []),
+ Msg = flex_compact_otp10998_msg02(),
+ d("flex_compact_otp10998_msg02 -> message created", []),
+ Conf =
+ try flex_scanner_conf(Config) of
+ C ->
+ C
+ catch
+ exit:Error ->
+ e("Failed getting flex config: "
+ "~n Error: ~p", [Error]),
+ exit(Error)
+ end,
+ d("flex_compact_otp10998_msg02 -> flex config generated", []),
+ flex_compact_otp10998([Conf], flex_compact_otp10998_num(), Msg).
+
+flex_compact_otp10998_msg03(suite) ->
+ [];
+flex_compact_otp10998_msg03(Config) when is_list(Config) ->
+ %% put(dbg, true),
+ %% put(severity, trc),
+ d("flex_compact_otp10998_msg03 -> entry", []),
+ Msg = flex_compact_otp10998_msg03(),
+ d("flex_compact_otp10998_msg03 -> message created", []),
+ Conf =
+ try flex_scanner_conf(Config) of
+ C ->
+ C
+ catch
+ exit:Error ->
+ e("Failed getting flex config: "
+ "~n Error: ~p", [Error]),
+ exit(Error)
+ end,
+ d("flex_compact_otp10998_msg03 -> flex config generated", []),
+ flex_compact_otp10998([Conf], flex_compact_otp10998_num(), Msg).
+
+flex_compact_otp10998_msg04(suite) ->
+ [];
+flex_compact_otp10998_msg04(Config) when is_list(Config) ->
+ %% put(dbg, true),
+ %% put(severity, trc),
+ d("flex_compact_otp10998_msg04 -> entry", []),
+ Msg = flex_compact_otp10998_msg04(),
+ d("flex_compact_otp10998_msg04 -> message created", []),
+ Conf =
+ try flex_scanner_conf(Config) of
+ C ->
+ C
+ catch
+ exit:Error ->
+ e("Failed getting flex config: "
+ "~n Error: ~p", [Error]),
+ exit(Error)
+ end,
+ d("flex_compact_otp10998_msg04 -> flex config generated", []),
+ flex_compact_otp10998([Conf], flex_compact_otp10998_num(), Msg).
+
+flex_compact_otp10998(EC, N, BinMsg) ->
+ Codec = megaco_compact_text_encoder,
+ Decode = fun(No) ->
+ case decode_message(Codec, false, EC, BinMsg) of
+ {ok, _Msg} ->
+ d("flex_compact_otp10998 -> decode ok", []),
+ ok;
+ {error, Reason} ->
+ e("flex_compact_otp10998 -> "
+ "decode ~w failed: ~p", [No, Reason]),
+ throw({error, No, Reason})
+ end
+ end,
+ do_flex_compact_otp10998(N, Decode).
+
+do_flex_compact_otp10998(N, Decode) when N > 0 ->
+ Decode(N),
+ do_flex_compact_otp10998(N-1, Decode);
+do_flex_compact_otp10998(_, _) ->
+ ok.
+
+
+
%% ==============================================================
%%
%% P r e t t y T e s t c a s e s
@@ -6772,7 +7530,14 @@ cre_PkgsItem(Name, Ver) ->
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
flex_init(Config) ->
- megaco_codec_flex_lib:init(Config).
+ %% io:format("~w:flex_init -> entry with: "
+ %% "~n Config: ~p"
+ %% "~n", [?MODULE, Config]),
+ Res = megaco_codec_flex_lib:init(Config),
+ %% io:format("~w:flex_init -> flex init result: "
+ %% "~n Res: ~p"
+ %% "~n", [?MODULE, Res]),
+ Res.
flex_finish(Config) ->
megaco_codec_flex_lib:finish(Config).
diff --git a/lib/megaco/test/megaco_codec_v3_test.erl b/lib/megaco/test/megaco_codec_v3_test.erl
index 9d564a0ae3..84cc863300 100644
--- a/lib/megaco/test/megaco_codec_v3_test.erl
+++ b/lib/megaco/test/megaco_codec_v3_test.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2006-2012. All Rights Reserved.
+%% Copyright Ericsson AB 2006-2013. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -235,21 +235,9 @@ generate_text_messages() ->
%% ----
-
-expand(RootCase) ->
- expand([RootCase], []).
-
-expand([], Acc) ->
- lists:flatten(lists:reverse(Acc));
-expand([Case|Cases], Acc) ->
- case (catch apply(?MODULE,Case,[suite])) of
- [] ->
- expand(Cases, [Case|Acc]);
- C when is_list(C) ->
- expand(Cases, [expand(C, [])|Acc]);
- _ ->
- expand(Cases, [Case|Acc])
- end.
+tickets() ->
+ %% io:format("~w:tickets -> entry~n", [?MODULE]),
+ megaco_test_lib:tickets(?MODULE).
%% ----
@@ -278,26 +266,34 @@ end_per_testcase(Case, Config) ->
%% Top test case
all() ->
- [{group, text}, {group, binary}, {group, erl_dist},
+ [{group, text},
+ {group, binary},
+ {group, erl_dist},
{group, tickets}].
groups() ->
[{text, [],
- [{group, pretty}, {group, flex_pretty},
- {group, compact}, {group, flex_compact}]},
+ [{group, pretty},
+ {group, flex_pretty},
+ {group, compact},
+ {group, flex_compact}]},
{binary, [],
- [{group, bin}, {group, ber}, {group, per}]},
+ [{group, bin},
+ {group, ber},
+ {group, per}]},
{erl_dist, [], [{group, erl_dist_m}]},
{pretty, [], [pretty_test_msgs]},
{compact, [], [compact_test_msgs]},
{flex_pretty, [], flex_pretty_cases()},
{flex_compact, [], flex_compact_cases()},
- {bin, [], [bin_test_msgs]}, {ber, [], [ber_test_msgs]},
+ {bin, [], [bin_test_msgs]},
+ {ber, [], [ber_test_msgs]},
{per, [], [per_test_msgs]},
{erl_dist_m, [], [erl_dist_m_test_msgs]},
{tickets, [],
[{group, compact_tickets},
- {group, flex_compact_tickets}, {group, pretty_tickets},
+ {group, flex_compact_tickets},
+ {group, pretty_tickets},
{group, flex_pretty_tickets}]},
{compact_tickets, [],
[compact_otp4011_msg1, compact_otp4011_msg2,
@@ -321,8 +317,7 @@ groups() ->
compact_otp5993_msg01, compact_otp5993_msg02,
compact_otp5993_msg03, compact_otp6017_msg01,
compact_otp6017_msg02, compact_otp6017_msg03]},
- {flex_compact_tickets, [],
- flex_compact_tickets_cases()},
+ {flex_compact_tickets, [], flex_compact_tickets_cases()},
{pretty_tickets, [],
[pretty_otp4632_msg1, pretty_otp4632_msg2,
pretty_otp4632_msg3, pretty_otp4632_msg4,
@@ -373,69 +368,65 @@ end_per_group(_GroupName, Config) ->
flex_pretty_cases() ->
- [flex_pretty_test_msgs].
+ [
+ flex_pretty_test_msgs
+ ].
flex_compact_cases() ->
- [flex_compact_test_msgs, flex_compact_dm_timers1,
- flex_compact_dm_timers2, flex_compact_dm_timers3,
- flex_compact_dm_timers4, flex_compact_dm_timers5,
- flex_compact_dm_timers6, flex_compact_dm_timers7,
- flex_compact_dm_timers8].
-
-
-
-%% Support for per_bin was added to ASN.1 as of version
-%% 1.3.2 (R8). And later merged into 1.3.1.3 (R7). These
-%% releases are identical (as far as I know).
-%%
-
+ [
+ flex_compact_test_msgs,
+ flex_compact_dm_timers1,
+ flex_compact_dm_timers2,
+ flex_compact_dm_timers3,
+ flex_compact_dm_timers4,
+ flex_compact_dm_timers5,
+ flex_compact_dm_timers6,
+ flex_compact_dm_timers7,
+ flex_compact_dm_timers8
+ ].
flex_compact_tickets_cases() ->
- [flex_compact_otp4299_msg1, flex_compact_otp7431_msg01,
- flex_compact_otp7431_msg02, flex_compact_otp7431_msg03,
- flex_compact_otp7431_msg04, flex_compact_otp7431_msg05,
- flex_compact_otp7431_msg06, flex_compact_otp7431_msg07].
+ [
+ flex_compact_otp4299_msg1,
+ flex_compact_otp7431_msg01,
+ flex_compact_otp7431_msg02,
+ flex_compact_otp7431_msg03,
+ flex_compact_otp7431_msg04,
+ flex_compact_otp7431_msg05,
+ flex_compact_otp7431_msg06,
+ flex_compact_otp7431_msg07
+ ].
flex_pretty_tickets_cases() ->
- [flex_pretty_otp5042_msg1, flex_pretty_otp5085_msg1,
- flex_pretty_otp5085_msg2, flex_pretty_otp5085_msg3,
- flex_pretty_otp5085_msg4, flex_pretty_otp5085_msg5,
- flex_pretty_otp5085_msg6, flex_pretty_otp5085_msg7,
- flex_pretty_otp5085_msg8, flex_pretty_otp5600_msg1,
- flex_pretty_otp5600_msg2, flex_pretty_otp5601_msg1,
- flex_pretty_otp5793_msg01, flex_pretty_otp5803_msg01,
- flex_pretty_otp5803_msg02, flex_pretty_otp5805_msg01,
- flex_pretty_otp5836_msg01, flex_pretty_otp7431_msg01,
- flex_pretty_otp7431_msg02, flex_pretty_otp7431_msg03,
- flex_pretty_otp7431_msg04, flex_pretty_otp7431_msg05,
- flex_pretty_otp7431_msg06, flex_pretty_otp7431_msg07].
-
-%% ----
+ [
+ flex_pretty_otp5042_msg1,
+ flex_pretty_otp5085_msg1,
+ flex_pretty_otp5085_msg2,
+ flex_pretty_otp5085_msg3,
+ flex_pretty_otp5085_msg4,
+ flex_pretty_otp5085_msg5,
+ flex_pretty_otp5085_msg6,
+ flex_pretty_otp5085_msg7,
+ flex_pretty_otp5085_msg8,
+ flex_pretty_otp5600_msg1,
+ flex_pretty_otp5600_msg2,
+ flex_pretty_otp5601_msg1,
+ flex_pretty_otp5793_msg01,
+ flex_pretty_otp5803_msg01,
+ flex_pretty_otp5803_msg02,
+ flex_pretty_otp5805_msg01,
+ flex_pretty_otp5836_msg01,
+ flex_pretty_otp7431_msg01,
+ flex_pretty_otp7431_msg02,
+ flex_pretty_otp7431_msg03,
+ flex_pretty_otp7431_msg04,
+ flex_pretty_otp7431_msg05,
+ flex_pretty_otp7431_msg06,
+ flex_pretty_otp7431_msg07
+ ].
-tickets() ->
- Flag = process_flag(trap_exit, true),
- Cases = expand(tickets),
- Fun = fun(Case) ->
- C = init_per_testcase(Case, [{tc_timeout,
- timer:minutes(10)}]),
- io:format("Eval ~w~n", [Case]),
- Result =
- case (catch apply(?MODULE, Case, [C])) of
- {'EXIT', Reason} ->
- io:format("~n~p exited:~n ~p~n",
- [Case, Reason]),
- {error, {Case, Reason}};
- Res ->
- Res
- end,
- end_per_testcase(Case, C),
- Result
- end,
- process_flag(trap_exit, Flag),
- lists:map(Fun, Cases).
-
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
pretty_test_msgs(suite) ->
diff --git a/lib/megaco/test/megaco_test_lib.erl b/lib/megaco/test/megaco_test_lib.erl
index 282fd91b44..41b49f6d30 100644
--- a/lib/megaco/test/megaco_test_lib.erl
+++ b/lib/megaco/test/megaco_test_lib.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1999-2011. All Rights Reserved.
+%% Copyright Ericsson AB 1999-2013. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -113,72 +113,17 @@ os_based_skip(_) ->
%% {Mod, Fun, ExpectedRes, ActualRes}
%%----------------------------------------------------------------------
-tickets(Case) ->
- Res = lists:flatten(tickets(Case, default_config())),
- %% io:format("Res: ~p~n", [Res]),
+tickets([Mod]) ->
+ tickets(Mod);
+tickets(Mod) when is_atom(Mod) ->
+ %% p("tickets -> entry with"
+ %% "~n Mod: ~p", [Mod]),
+ Res0 = t({Mod, {group, tickets}, Mod:groups()}, default_config()),
+ Res = lists:flatten(Res0),
+ %% p("tickets(~w) -> Res: ~p~n", [Mod, Res]),
display_result(Res),
Res.
-tickets(Cases, Config) when is_list(Cases) ->
- [tickets(Case, Config) || Case <- Cases];
-tickets(Mod, Config) when is_atom(Mod) ->
- Res = tickets(Mod, tickets, Config),
- Res;
-tickets(Bad, _Config) ->
- [{badarg, Bad, ok}].
-
-tickets(Mod, Func, Config) ->
- case (catch Mod:Func(suite)) of
- [] ->
- io:format("Eval: ~p:", [{Mod, Func}]),
- Res = eval(Mod, Func, Config),
- {R, _, _} = Res,
- io:format(" ~p~n", [R]),
- Res;
-
- Cases when is_list(Cases) ->
- io:format("Expand: ~p:~p ... ~n"
- " ~p~n", [Mod, Func, Cases]),
- Map = fun({M,_}) when is_atom(M) ->
- tickets(M, tickets, Config);
- (F) when is_atom(F) ->
- tickets(Mod, F, Config);
- (Case) -> Case
- end,
- lists:map(Map, Cases);
-
-%% {req, _, {conf, Init, Cases, Finish}} ->
-%% case (catch Mod:Init(Config)) of
-%% Conf when is_list(Conf) ->
-%% io:format("Expand: ~p:~p ...~n", [Mod, Func]),
-%% Map = fun({M,_}) when is_atom(M) ->
-%% tickets(M, tickets, Config);
-%% (F) when is_atom(F) ->
-%% tickets(Mod, F, Config);
-%% (Case) -> Case
-%% end,
-%% Res = lists:map(Map, Cases),
-%% (catch Mod:Finish(Conf)),
-%% Res;
-
-%% {'EXIT', {skipped, Reason}} ->
-%% io:format(" => skipping: ~p~n", [Reason]),
-%% [{skipped, {Mod, Func}, Reason}];
-
-%% Error ->
-%% io:format(" => init failed: ~p~n", [Error]),
-%% [{failed, {Mod, Func}, Error}]
-%% end;
-
- {'EXIT', {undef, _}} ->
- io:format("Undefined: ~p~n", [{Mod, Func}]),
- [{nyi, {Mod, Func}, ok}];
-
- Error ->
- io:format("Ignoring: ~p:~p: ~p~n", [Mod, Func, Error]),
- [{failed, {Mod, Func}, Error}]
- end.
-
display_alloc_info() ->
io:format("Allocator memory information:~n", []),
@@ -254,8 +199,12 @@ alloc_instance_mem_info(Key, InstanceInfo) ->
t([Case]) when is_atom(Case) ->
+ %% p("t -> entry with"
+ %% "~n [Case]: [~p]", [Case]),
t(Case);
t(Case) ->
+ %% p("t -> entry with"
+ %% "~n Case: ~p", [Case]),
process_flag(trap_exit, true),
MEM = fun() -> case (catch erlang:memory()) of
{'EXIT', _} ->
@@ -298,9 +247,16 @@ end_group(Mod, Group, Config) ->
%% This is for sub-SUITEs
t({_Mod, {NewMod, all}, _Groups}, _Config) when is_atom(NewMod) ->
+ %% p("t(all) -> entry with"
+ %% "~n NewMod: ~p", [NewMod]),
t(NewMod);
t({Mod, {group, Name} = Group, Groups}, Config)
when is_atom(Mod) andalso is_atom(Name) andalso is_list(Groups) ->
+ %% p("t(group) -> entry with"
+ %% "~n Mod: ~p"
+ %% "~n Name: ~p"
+ %% "~n Groups: ~p"
+ %% "~n Config: ~p", [Mod, Name, Groups, Config]),
case lists:keysearch(Name, 1, Groups) of
{value, {Name, _Props, GroupsAndCases}} ->
try init_group(Mod, Name, Config) of
@@ -317,7 +273,7 @@ t({Mod, {group, Name} = Group, Groups}, Config)
exit:{skipped, SkipReason} ->
io:format(" => skipping group: ~p~n", [SkipReason]),
[{skipped, {Mod, Group}, SkipReason, 0}];
- exit:{undef, _} ->
+ error:undef ->
[t({Mod, Case, Groups}, Config) ||
Case <- GroupsAndCases];
T:E ->
@@ -328,7 +284,11 @@ t({Mod, {group, Name} = Group, Groups}, Config)
end;
t({Mod, Fun, _}, Config)
when is_atom(Mod) andalso is_atom(Fun) ->
- case catch apply(Mod, Fun, [suite]) of
+ %% p("t -> entry with"
+ %% "~n Mod: ~p"
+ %% "~n Fun: ~p"
+ %% "~n Config: ~p", [Mod, Fun, Config]),
+ try apply(Mod, Fun, [suite]) of
[] ->
io:format("Eval: ~p:", [{Mod, Fun}]),
Res = eval(Mod, Fun, Config),
@@ -343,18 +303,24 @@ t({Mod, Fun, _}, Config)
end,
t(lists:map(Map, Cases), Config);
- {'EXIT', {undef, _}} ->
- io:format("Undefined: ~p~n", [{Mod, Fun}]),
- [{nyi, {Mod, Fun}, ok, 0}];
-
Error ->
io:format("Ignoring: ~p: ~p~n", [{Mod, Fun}, Error]),
[{failed, {Mod, Fun}, Error, 0}]
+
+ catch
+ error:undef ->
+ io:format("Undefined: ~p~n", [{Mod, Fun}]),
+ [{nyi, {Mod, Fun}, ok, 0}]
+
+
end;
t(Mod, Config) when is_atom(Mod) ->
+ %% p("t -> entry with"
+ %% "~n Mod: ~p"
+ %% "~n Config: ~p", [Mod, Config]),
%% This is assumed to be a test suite, so we start by calling
%% the top test suite function(s) (all/0 and groups/0).
- case (catch Mod:all()) of
+ try Mod:all() of
Cases when is_list(Cases) ->
%% The list may contain atoms (actual test cases) and
%% group-tuples (a tuple naming a group of test cases).
@@ -372,17 +338,21 @@ t(Mod, Config) when is_atom(Mod) ->
exit:{skipped, SkipReason} ->
io:format(" => skipping suite: ~p~n", [SkipReason]),
[{skipped, {Mod, init_per_suite}, SkipReason, 0}];
- exit:{undef, _} ->
+ error:undef ->
[t({Mod, Case, Groups}, Config) || Case <- Cases];
T:E ->
+ io:format(" => failed suite: ~p~n", [{T,E}]),
[{failed, {Mod, init_per_suite}, {T,E}, 0}]
end;
- {'EXIT', {undef, _}} ->
- io:format("Undefined: ~p~n", [{Mod, all}]),
- [{nyi, {Mod, all}, ok, 0}];
-
+
Crap ->
Crap
+
+ catch
+ error:undef ->
+ io:format("Undefined: ~p~n", [{Mod, all}]),
+ [{nyi, {Mod, all}, ok, 0}]
+
end;
t(Bad, _Config) ->
[{badarg, Bad, ok, 0}].
@@ -409,6 +379,14 @@ eval(Mod, Fun, Config) ->
wait_for_evaluator(Pid, Mod, Fun, Config, Errors) ->
wait_for_evaluator(Pid, Mod, Fun, Config, Errors, 0).
wait_for_evaluator(Pid, Mod, Fun, Config, Errors, AccTime) ->
+ %% p("wait_for_evaluator -> "
+ %% "~n Pid: ~p"
+ %% "~n Mod: ~p"
+ %% "~n Fun: ~p"
+ %% "~n Config: ~p"
+ %% "~n Errors: ~p"
+ %% "~n AccTime: ~p",
+ %% [Pid, Mod, Fun, Config, Errors, AccTime]),
TestCase = {?MODULE, Mod, Fun},
Label = lists:concat(["TEST CASE: ", Fun]),
receive
@@ -446,16 +424,43 @@ wait_for_evaluator(Pid, Mod, Fun, Config, Errors, AccTime) ->
end.
do_eval(ReplyTo, Mod, Fun, Config) ->
+ %% p("do_eval -> "
+ %% "~n ReplyTo: ~p"
+ %% "~n Mod: ~p"
+ %% "~n Fun: ~p"
+ %% "~n Config: ~p", [ReplyTo, Mod, Fun, Config]),
display_system_info("before", Mod, Fun),
- case timer:tc(Mod, Fun, [Config]) of
- {Time, {'EXIT', {skipped, Reason}}} ->
+ T1 = os:timestamp(),
+ try Mod:Fun(Config) of
+ Res ->
+ %% p("do_eval -> done"
+ %% "~n Res: ~p", [Res]),
+ T2 = os:timestamp(),
+ Time = timer:now_diff(T2, T1),
+ display_tc_time(Time),
+ display_system_info("after", Mod, Fun),
+ ReplyTo ! {done, self(), Res, Time}
+ catch
+ error:undef ->
+ %% p("do_eval -> error - undef", []),
+ ReplyTo ! {'EXIT', self(), undef, 0};
+ exit:{skipped, Reason} ->
+ %% p("do_eval -> exit - skipped"
+ %% "~n Reason: ~p", [Reason]),
+ T2 = os:timestamp(),
+ Time = timer:now_diff(T2, T1),
display_tc_time(Time),
display_system_info("after (skipped)", Mod, Fun),
ReplyTo ! {'EXIT', self(), {skipped, Reason}, Time};
- {Time, Other} ->
+ exit:{suite_failed, Reason} ->
+ %% p("do_eval -> exit - suite-failed"
+ %% "~n Reason: ~p", [Reason]),
+ T2 = os:timestamp(),
+ Time = timer:now_diff(T2, T1),
display_tc_time(Time),
- display_system_info("after", Mod, Fun),
- ReplyTo ! {done, self(), Other, Time}
+ display_system_info("after (failed)", Mod, Fun),
+ ReplyTo ! {done, self(), Reason, Time}
+
end,
unlink(ReplyTo),
exit(shutdown).
diff --git a/lib/megaco/vsn.mk b/lib/megaco/vsn.mk
index b61cf2102c..68b12c0286 100644
--- a/lib/megaco/vsn.mk
+++ b/lib/megaco/vsn.mk
@@ -18,6 +18,6 @@
# %CopyrightEnd%
APPLICATION = megaco
-MEGACO_VSN = 3.16.0.3
+MEGACO_VSN = 3.17
PRE_VSN =
APP_VSN = "$(APPLICATION)-$(MEGACO_VSN)$(PRE_VSN)"
diff --git a/lib/mnesia/src/mnesia_index.erl b/lib/mnesia/src/mnesia_index.erl
index f9f3ce2ea4..6f9f575d93 100644
--- a/lib/mnesia/src/mnesia_index.erl
+++ b/lib/mnesia/src/mnesia_index.erl
@@ -301,7 +301,13 @@ make_ram_index(Tab, [Pos | Tail]) ->
add_ram_index(Tab, Pos) when is_integer(Pos) ->
verbose("Creating index for ~w ~n", [Tab]),
- Index = mnesia_monitor:mktab(mnesia_index, [bag, public]),
+ SetOrBag = val({Tab, setorbag}),
+ IndexType = case SetOrBag of
+ set -> duplicate_bag;
+ ordered_set -> duplicate_bag;
+ bag -> bag
+ end,
+ Index = mnesia_monitor:mktab(mnesia_index, [IndexType, public]),
Insert = fun(Rec, _Acc) ->
true = ?ets_insert(Index, {element(Pos, Rec), element(2, Rec)})
end,
@@ -309,7 +315,7 @@ add_ram_index(Tab, Pos) when is_integer(Pos) ->
true = ets:foldl(Insert, true, Tab),
mnesia_lib:db_fixtable(ram_copies, Tab, false),
mnesia_lib:set({Tab, {index, Pos}}, Index),
- add_index_info(Tab, val({Tab, setorbag}), {Pos, {ram, Index}});
+ add_index_info(Tab, SetOrBag, {Pos, {ram, Index}});
add_ram_index(_Tab, snmp) ->
ok.
diff --git a/lib/mnesia/src/mnesia_loader.erl b/lib/mnesia/src/mnesia_loader.erl
index 4ba400fbbf..4afbea1cc2 100644
--- a/lib/mnesia/src/mnesia_loader.erl
+++ b/lib/mnesia/src/mnesia_loader.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1998-2011. All Rights Reserved.
+%% Copyright Ericsson AB 1998-2013. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -487,7 +487,8 @@ finish_copy(Storage,Tab,Cs,SenderPid,DatBin,OrigTabRec) ->
subscr_receiver(TabRef = {_, Tab}, RecName) ->
receive
- {mnesia_table_event, {Op, Val, _Tid}} ->
+ {mnesia_table_event, {Op, Val, _Tid}}
+ when element(1, Val) =:= Tab ->
if
Tab == RecName ->
handle_event(TabRef, Op, Val);
@@ -496,6 +497,15 @@ subscr_receiver(TabRef = {_, Tab}, RecName) ->
end,
subscr_receiver(TabRef, RecName);
+ {mnesia_table_event, {Op, Val, _Tid}} when element(1, Val) =:= schema ->
+ %% clear_table is faked via two schema events
+ %% a schema record delete and a write
+ case Op of
+ delete -> handle_event(TabRef, clear_table, {Tab, all});
+ _ -> ok
+ end,
+ subscr_receiver(TabRef, RecName);
+
{'EXIT', Pid, Reason} ->
handle_exit(Pid, Reason),
subscr_receiver(TabRef, RecName)
diff --git a/lib/mnesia/test/mnesia_evil_coverage_test.erl b/lib/mnesia/test/mnesia_evil_coverage_test.erl
index 64b61288ef..0df245b75d 100644
--- a/lib/mnesia/test/mnesia_evil_coverage_test.erl
+++ b/lib/mnesia/test/mnesia_evil_coverage_test.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1996-2011. All Rights Reserved.
+%% Copyright Ericsson AB 1996-2013. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -39,7 +39,7 @@ all() ->
db_node_lifecycle, evil_delete_db_node, start_and_stop,
checkpoint, table_lifecycle, storage_options,
add_copy_conflict,
- add_copy_when_going_down, replica_management,
+ add_copy_when_going_down, replica_management, clear_table_during_load,
schema_availability, local_content,
{group, table_access_modifications}, replica_location,
{group, table_sync}, user_properties, unsupp_user_props,
@@ -569,7 +569,50 @@ storage_options(Config) when is_list(Config) ->
?verify_mnesia(Nodes, []).
+clear_table_during_load(suite) -> [];
+clear_table_during_load(doc) ->
+ ["Clear table caused during load caused a schema entry in the actual tab"];
+clear_table_during_load(Config) when is_list(Config) ->
+ Nodes = [_, Node2] = ?acquire_nodes(2, Config ++ [{tc_timeout, timer:minutes(2)}]),
+ ?match({atomic,ok}, mnesia:create_table(cleartab, [{ram_copies, Nodes}])),
+ Tester = self(),
+ Bin = <<"Testingasdasd", 0:32000>>,
+ Fill = fun() -> [mnesia:write({cleartab, N, Bin}) || N <- lists:seq(1, 3000)], ok end,
+ ?match({atomic, ok}, mnesia:sync_transaction(Fill)),
+
+ StopAndStart = fun() ->
+ stopped = mnesia:stop(),
+ Tester ! {self(), stopped},
+ receive start_node -> ok end,
+ ok = mnesia:start(),
+ ok = mnesia:wait_for_tables([cleartab], 2000),
+ lists:foreach(fun({cleartab,_,_}) -> ok;
+ (What) -> Tester ! {failed, What},
+ unlink(Tester),
+ exit(foo)
+ end,
+ ets:tab2list(cleartab)),
+ Tester ! {self(), ok},
+ normal
+ end,
+ Test = fun(N) ->
+ Pid = spawn_link(Node2, StopAndStart),
+ receive {Pid, stopped} -> ok end,
+ Pid ! start_node,
+ timer:sleep(N*10),
+ {atomic, ok} = mnesia:clear_table(cleartab),
+ receive
+ {Pid, ok} -> ok;
+ {failed, What} ->
+ io:format("Failed in ~p tries, with ~p~n",[N, What]),
+ exit({error, What});
+ {'EXIT', Pid, Reason} ->
+ exit({died, Reason})
+ end
+ end,
+ [Test(N) || N <- lists:seq(1, 10)],
+ ?verify_mnesia(Nodes, []).
add_copy_conflict(suite) -> [];
@@ -599,7 +642,7 @@ add_copy_conflict(Config) when is_list(Config) ->
mnesia_controller:unblock_controller(),
?match_receive({test, {atomic,ok}}),
-
+ ?match(ok, mnesia:wait_for_tables([a,b], 3000)),
?verify_mnesia(Nodes, []),
?cleanup(1, Config).
@@ -635,7 +678,7 @@ add_copy_when_going_down(Config) ->
end,
_Lock = spawn(fun() -> mnesia:transaction(WriteAndWait) end),
Tester = self(),
- spawn_link(fun() -> Res = rpc:call(Node2,mnesia, add_table_copy,
+ spawn_link(fun() -> Res = rpc:call(Node2, mnesia, add_table_copy,
[a, Node2, ram_copies]),
Tester ! {test, Res}
end),
diff --git a/lib/public_key/asn1/ECPrivateKey.asn1 b/lib/public_key/asn1/ECPrivateKey.asn1
new file mode 100644
index 0000000000..a20fa4009c
--- /dev/null
+++ b/lib/public_key/asn1/ECPrivateKey.asn1
@@ -0,0 +1,24 @@
+ECPrivateKey { iso(1) identified-organization(3) dod(6)
+ internet(1) security(5) mechanisms(5) pkix(7) id-mod(0)
+ id-mod-ecprivateKey(65) }
+
+DEFINITIONS EXPLICIT TAGS ::=
+
+BEGIN
+
+-- EXPORTS ALL;
+
+IMPORTS
+
+-- FROM New PKIX ASN.1 [RFC5912]
+
+EcpkParameters FROM PKIX1Algorithms88;
+
+ECPrivateKey ::= SEQUENCE {
+ version INTEGER,
+ privateKey OCTET STRING,
+ parameters [0] EcpkParameters OPTIONAL,
+ publicKey [1] BIT STRING OPTIONAL
+}
+
+END
diff --git a/lib/public_key/asn1/OTP-PKIX.asn1 b/lib/public_key/asn1/OTP-PKIX.asn1
index a90fe2840c..911a156d6c 100644
--- a/lib/public_key/asn1/OTP-PKIX.asn1
+++ b/lib/public_key/asn1/OTP-PKIX.asn1
@@ -103,15 +103,16 @@ IMPORTS
md5WithRSAEncryption,
sha1WithRSAEncryption,
rsaEncryption, RSAPublicKey,
- dhpublicnumber, DomainParameters, DHPublicKey,
+ dhpublicnumber, DomainParameters, DHPublicKey,
id-keyExchangeAlgorithm, KEA-Parms-Id, --KEA-PublicKey,
- ecdsa-with-SHA1,
+ ecdsa-with-SHA1, ecdsa-with-SHA224,
+ ecdsa-with-SHA256, ecdsa-with-SHA384, ecdsa-with-SHA512,
prime-field, Prime-p,
characteristic-two-field, --Characteristic-two,
gnBasis,
tpBasis, Trinomial,
ppBasis, Pentanomial,
- id-ecPublicKey, EcpkParameters, ECPoint
+ id-ecPublicKey, EcpkParameters, ECParameters, ECPoint
FROM PKIX1Algorithms88 { iso(1) identified-organization(3) dod(6)
internet(1) security(5) mechanisms(5) pkix(7) id-mod(0)
id-mod-pkix1-algorithms(17) }
@@ -321,7 +322,11 @@ SupportedSignatureAlgorithms SIGNATURE-ALGORITHM-CLASS ::= {
sha256-with-rsa-encryption |
sha384-with-rsa-encryption |
sha512-with-rsa-encryption |
- ecdsa-with-sha1 }
+ ecdsa-with-sha1 |
+ ecdsa-with-sha224 |
+ ecdsa-with-sha256 |
+ ecdsa-with-sha384 |
+ ecdsa-with-sha512 }
SupportedPublicKeyAlgorithms PUBLIC-KEY-ALGORITHM-CLASS ::= {
dsa | rsa-encryption | dh | kea | ec-public-key }
@@ -439,6 +444,22 @@ SupportedPublicKeyAlgorithms PUBLIC-KEY-ALGORITHM-CLASS ::= {
ID ecdsa-with-SHA1
TYPE NULL } -- XXX Must be empty and not NULL
+ ecdsa-with-sha224 SIGNATURE-ALGORITHM-CLASS ::= {
+ ID ecdsa-with-SHA224
+ TYPE NULL } -- XXX Must be empty and not NULL
+
+ ecdsa-with-sha256 SIGNATURE-ALGORITHM-CLASS ::= {
+ ID ecdsa-with-SHA256
+ TYPE NULL } -- XXX Must be empty and not NULL
+
+ ecdsa-with-sha384 SIGNATURE-ALGORITHM-CLASS ::= {
+ ID ecdsa-with-SHA384
+ TYPE NULL } -- XXX Must be empty and not NULL
+
+ ecdsa-with-sha512 SIGNATURE-ALGORITHM-CLASS ::= {
+ ID ecdsa-with-SHA512
+ TYPE NULL } -- XXX Must be empty and not NULL
+
FIELD-ID-CLASS ::= CLASS {
&id OBJECT IDENTIFIER UNIQUE,
&Type }
@@ -489,6 +510,7 @@ SupportedPublicKeyAlgorithms PUBLIC-KEY-ALGORITHM-CLASS ::= {
ID ppBasis
TYPE Pentanomial }
+
-- SubjectPublicKeyInfo.algorithm
ec-public-key PUBLIC-KEY-ALGORITHM-CLASS ::= {
diff --git a/lib/public_key/asn1/OTP-PUB-KEY.set.asn b/lib/public_key/asn1/OTP-PUB-KEY.set.asn
index f8fb318c93..e94f428e4b 100644
--- a/lib/public_key/asn1/OTP-PUB-KEY.set.asn
+++ b/lib/public_key/asn1/OTP-PUB-KEY.set.asn
@@ -6,5 +6,6 @@ PKIX1Algorithms88.asn1
PKCS-1.asn1
PKCS-3.asn1
DSS.asn1
+ECPrivateKey.asn1
PKCS-7.asn1
PKCS-10.asn1
diff --git a/lib/public_key/asn1/PKCS-1.asn1 b/lib/public_key/asn1/PKCS-1.asn1
index b5754790e7..117eacd8ad 100644
--- a/lib/public_key/asn1/PKCS-1.asn1
+++ b/lib/public_key/asn1/PKCS-1.asn1
@@ -52,8 +52,40 @@ id-md5 OBJECT IDENTIFIER ::= {
iso(1) member-body(2) us(840) rsadsi(113549) digestAlgorithm(2) 5
}
+id-hmacWithSHA224 OBJECT IDENTIFIER ::= {
+ iso(1) member-body(2) us(840) rsadsi(113549) digestAlgorithm(2) 8
+}
+
+id-hmacWithSHA256 OBJECT IDENTIFIER ::= {
+ iso(1) member-body(2) us(840) rsadsi(113549) digestAlgorithm(2) 9
+}
+
+id-hmacWithSHA384 OBJECT IDENTIFIER ::= {
+ iso(1) member-body(2) us(840) rsadsi(113549) digestAlgorithm(2) 10
+}
+
+id-hmacWithSHA512 OBJECT IDENTIFIER ::= {
+ iso(1) member-body(2) us(840) rsadsi(113549) digestAlgorithm(2) 11
+}
+
id-mgf1 OBJECT IDENTIFIER ::= { pkcs-1 8 }
+id-sha224 OBJECT IDENTIFIER ::= { joint-iso-itu-t(2)
+ country(16) us(840) organization(1) gov(101) csor(3)
+ nistalgorithm(4) hashalgs(2) 4 }
+
+id-sha256 OBJECT IDENTIFIER ::= { joint-iso-itu-t(2)
+ country(16) us(840) organization(1) gov(101) csor(3)
+ nistalgorithm(4) hashalgs(2) 1 }
+
+id-sha384 OBJECT IDENTIFIER ::= { joint-iso-itu-t(2)
+ country(16) us(840) organization(1) gov(101) csor(3)
+ nistalgorithm(4) hashalgs(2) 2 }
+
+id-sha512 OBJECT IDENTIFIER ::= { joint-iso-itu-t(2)
+ country(16) us(840) organization(1) gov(101) csor(3)
+ nistalgorithm(4) hashalgs(2) 3 }
+
RSAPublicKey ::= SEQUENCE {
modulus INTEGER, -- n
diff --git a/lib/public_key/asn1/PKIX1Algorithms88.asn1 b/lib/public_key/asn1/PKIX1Algorithms88.asn1
index 74225747d3..6cc6745af6 100644
--- a/lib/public_key/asn1/PKIX1Algorithms88.asn1
+++ b/lib/public_key/asn1/PKIX1Algorithms88.asn1
@@ -98,6 +98,11 @@
-- OID for ECDSA signatures with SHA-1
ecdsa-with-SHA1 OBJECT IDENTIFIER ::= { id-ecSigType 1 }
+ ecdsa-with-SHA2 OBJECT IDENTIFIER ::= { id-ecSigType 3 }
+ ecdsa-with-SHA224 OBJECT IDENTIFIER ::= { ecdsa-with-SHA2 1 }
+ ecdsa-with-SHA256 OBJECT IDENTIFIER ::= { ecdsa-with-SHA2 2 }
+ ecdsa-with-SHA384 OBJECT IDENTIFIER ::= { ecdsa-with-SHA2 3 }
+ ecdsa-with-SHA512 OBJECT IDENTIFIER ::= { ecdsa-with-SHA2 4 }
-- OID for an elliptic curve signature
-- format for the value of an ECDSA signature value
@@ -199,40 +204,83 @@
-- Named Elliptic Curves in ANSI X9.62.
- ellipticCurve OBJECT IDENTIFIER ::= { ansi-X9-62 curves(3) }
-
- c-TwoCurve OBJECT IDENTIFIER ::= {
- ellipticCurve characteristicTwo(0) }
-
- c2pnb163v1 OBJECT IDENTIFIER ::= { c-TwoCurve 1 }
- c2pnb163v2 OBJECT IDENTIFIER ::= { c-TwoCurve 2 }
- c2pnb163v3 OBJECT IDENTIFIER ::= { c-TwoCurve 3 }
- c2pnb176w1 OBJECT IDENTIFIER ::= { c-TwoCurve 4 }
- c2tnb191v1 OBJECT IDENTIFIER ::= { c-TwoCurve 5 }
- c2tnb191v2 OBJECT IDENTIFIER ::= { c-TwoCurve 6 }
- c2tnb191v3 OBJECT IDENTIFIER ::= { c-TwoCurve 7 }
- c2onb191v4 OBJECT IDENTIFIER ::= { c-TwoCurve 8 }
- c2onb191v5 OBJECT IDENTIFIER ::= { c-TwoCurve 9 }
- c2pnb208w1 OBJECT IDENTIFIER ::= { c-TwoCurve 10 }
- c2tnb239v1 OBJECT IDENTIFIER ::= { c-TwoCurve 11 }
- c2tnb239v2 OBJECT IDENTIFIER ::= { c-TwoCurve 12 }
- c2tnb239v3 OBJECT IDENTIFIER ::= { c-TwoCurve 13 }
- c2onb239v4 OBJECT IDENTIFIER ::= { c-TwoCurve 14 }
- c2onb239v5 OBJECT IDENTIFIER ::= { c-TwoCurve 15 }
- c2pnb272w1 OBJECT IDENTIFIER ::= { c-TwoCurve 16 }
- c2pnb304w1 OBJECT IDENTIFIER ::= { c-TwoCurve 17 }
- c2tnb359v1 OBJECT IDENTIFIER ::= { c-TwoCurve 18 }
- c2pnb368w1 OBJECT IDENTIFIER ::= { c-TwoCurve 19 }
- c2tnb431r1 OBJECT IDENTIFIER ::= { c-TwoCurve 20 }
-
- primeCurve OBJECT IDENTIFIER ::= { ellipticCurve prime(1) }
-
- prime192v1 OBJECT IDENTIFIER ::= { primeCurve 1 }
- prime192v2 OBJECT IDENTIFIER ::= { primeCurve 2 }
- prime192v3 OBJECT IDENTIFIER ::= { primeCurve 3 }
- prime239v1 OBJECT IDENTIFIER ::= { primeCurve 4 }
- prime239v2 OBJECT IDENTIFIER ::= { primeCurve 5 }
- prime239v3 OBJECT IDENTIFIER ::= { primeCurve 6 }
- prime256v1 OBJECT IDENTIFIER ::= { primeCurve 7 }
+ -- ellipticCurve OBJECT IDENTIFIER ::= { ansi-X9-62 curves(3) }
+
+ -- c-TwoCurve OBJECT IDENTIFIER ::= {
+ -- ansi-ellipticCurve characteristicTwo(0) }
+
+ -- c2pnb163v1 OBJECT IDENTIFIER ::= { c-TwoCurve 1 }
+ -- c2pnb163v2 OBJECT IDENTIFIER ::= { c-TwoCurve 2 }
+ -- c2pnb163v3 OBJECT IDENTIFIER ::= { c-TwoCurve 3 }
+ -- c2pnb176w1 OBJECT IDENTIFIER ::= { c-TwoCurve 4 }
+ -- c2tnb191v1 OBJECT IDENTIFIER ::= { c-TwoCurve 5 }
+ -- c2tnb191v2 OBJECT IDENTIFIER ::= { c-TwoCurve 6 }
+ -- c2tnb191v3 OBJECT IDENTIFIER ::= { c-TwoCurve 7 }
+ -- c2onb191v4 OBJECT IDENTIFIER ::= { c-TwoCurve 8 }
+ -- c2onb191v5 OBJECT IDENTIFIER ::= { c-TwoCurve 9 }
+ -- c2pnb208w1 OBJECT IDENTIFIER ::= { c-TwoCurve 10 }
+ -- c2tnb239v1 OBJECT IDENTIFIER ::= { c-TwoCurve 11 }
+ -- c2tnb239v2 OBJECT IDENTIFIER ::= { c-TwoCurve 12 }
+ -- c2tnb239v3 OBJECT IDENTIFIER ::= { c-TwoCurve 13 }
+ -- c2onb239v4 OBJECT IDENTIFIER ::= { c-TwoCurve 14 }
+ -- c2onb239v5 OBJECT IDENTIFIER ::= { c-TwoCurve 15 }
+ -- c2pnb272w1 OBJECT IDENTIFIER ::= { c-TwoCurve 16 }
+ -- c2pnb304w1 OBJECT IDENTIFIER ::= { c-TwoCurve 17 }
+ -- c2tnb359v1 OBJECT IDENTIFIER ::= { c-TwoCurve 18 }
+ -- c2pnb368w1 OBJECT IDENTIFIER ::= { c-TwoCurve 19 }
+ -- c2tnb431r1 OBJECT IDENTIFIER ::= { c-TwoCurve 20 }
+
+ -- primeCurve OBJECT IDENTIFIER ::= { ansi-ellipticCurve prime(1) }
+
+ -- prime192v1 OBJECT IDENTIFIER ::= { primeCurve 1 }
+ -- prime192v2 OBJECT IDENTIFIER ::= { primeCurve 2 }
+ -- prime192v3 OBJECT IDENTIFIER ::= { primeCurve 3 }
+ -- prime239v1 OBJECT IDENTIFIER ::= { primeCurve 4 }
+ -- prime239v2 OBJECT IDENTIFIER ::= { primeCurve 5 }
+ -- prime239v3 OBJECT IDENTIFIER ::= { primeCurve 6 }
+ -- prime256v1 OBJECT IDENTIFIER ::= { primeCurve 7 }
+
+ certicom-arc OBJECT IDENTIFIER ::= {
+ iso(1) identified-organization(3) certicom(132)
+ }
+
+ ellipticCurve OBJECT IDENTIFIER ::= {
+ iso(1) identified-organization(3) certicom(132) curve(0)
+ }
+
+ secp192r1 OBJECT IDENTIFIER ::= { ansi-X9-62 curves(3) prime(1) 1 }
+ secp256r1 OBJECT IDENTIFIER ::= { ansi-X9-62 curves(3) prime(1) 7 }
+
+ sect163k1 OBJECT IDENTIFIER ::= { ellipticCurve 1 }
+ sect163r1 OBJECT IDENTIFIER ::= { ellipticCurve 2 }
+ sect239k1 OBJECT IDENTIFIER ::= { ellipticCurve 3 }
+ sect113r1 OBJECT IDENTIFIER ::= { ellipticCurve 4 }
+ sect113r2 OBJECT IDENTIFIER ::= { ellipticCurve 5 }
+ secp112r1 OBJECT IDENTIFIER ::= { ellipticCurve 6 }
+ secp112r2 OBJECT IDENTIFIER ::= { ellipticCurve 7 }
+ secp160r1 OBJECT IDENTIFIER ::= { ellipticCurve 8 }
+ secp160k1 OBJECT IDENTIFIER ::= { ellipticCurve 9 }
+ secp256k1 OBJECT IDENTIFIER ::= { ellipticCurve 10 }
+ sect163r2 OBJECT IDENTIFIER ::= { ellipticCurve 15 }
+ sect283k1 OBJECT IDENTIFIER ::= { ellipticCurve 16 }
+ sect283r1 OBJECT IDENTIFIER ::= { ellipticCurve 17 }
+ sect131r1 OBJECT IDENTIFIER ::= { ellipticCurve 22 }
+ sect131r2 OBJECT IDENTIFIER ::= { ellipticCurve 23 }
+ sect193r1 OBJECT IDENTIFIER ::= { ellipticCurve 24 }
+ sect193r2 OBJECT IDENTIFIER ::= { ellipticCurve 25 }
+ sect233k1 OBJECT IDENTIFIER ::= { ellipticCurve 26 }
+ sect233r1 OBJECT IDENTIFIER ::= { ellipticCurve 27 }
+ secp128r1 OBJECT IDENTIFIER ::= { ellipticCurve 28 }
+ secp128r2 OBJECT IDENTIFIER ::= { ellipticCurve 29 }
+ secp160r2 OBJECT IDENTIFIER ::= { ellipticCurve 30 }
+ secp192k1 OBJECT IDENTIFIER ::= { ellipticCurve 31 }
+ secp224k1 OBJECT IDENTIFIER ::= { ellipticCurve 32 }
+ secp224r1 OBJECT IDENTIFIER ::= { ellipticCurve 33 }
+ secp384r1 OBJECT IDENTIFIER ::= { ellipticCurve 34 }
+ secp521r1 OBJECT IDENTIFIER ::= { ellipticCurve 35 }
+ sect409k1 OBJECT IDENTIFIER ::= { ellipticCurve 36 }
+ sect409r1 OBJECT IDENTIFIER ::= { ellipticCurve 37 }
+ sect571k1 OBJECT IDENTIFIER ::= { ellipticCurve 38 }
+ sect571r1 OBJECT IDENTIFIER ::= { ellipticCurve 39 }
END
diff --git a/lib/public_key/doc/src/public_key.xml b/lib/public_key/doc/src/public_key.xml
index 84300f6e65..10c95a39ac 100644
--- a/lib/public_key/doc/src/public_key.xml
+++ b/lib/public_key/doc/src/public_key.xml
@@ -84,7 +84,8 @@
<p><code>pki_asn1_type() = 'Certificate' | 'RSAPrivateKey'| 'RSAPublicKey' |
'DSAPrivateKey' | 'DSAPublicKey' | 'DHParameter' | 'SubjectPublicKeyInfo' |
- 'PrivateKeyInfo' | 'CertificationRequest'</code></p>
+ 'PrivateKeyInfo' | 'CertificationRequest' | 'ECPrivateKey'|
+ 'EcpkParameters'</code></p>
<p><code>pem_entry () = {pki_asn1_type(), binary(), %% DER or encrypted DER
not_encrypted | cipher_info()} </code></p>
@@ -99,7 +100,11 @@
<p><code>dsa_public_key() = {integer(), #'Dss-Parms'{}} </code></p>
<p><code>dsa_private_key() = #'DSAPrivateKey'{}</code></p>
+
+ <p><code>ec_public_key() = {#'ECPoint'{}, #'EcpkParameters'{} | {namedCurve, oid()}} </code></p>
+ <p><code>ec_private_key() = #'ECPrivateKey'{}</code></p>
+
<p><code> public_crypt_options() = [{rsa_pad, rsa_padding()}]. </code></p>
<p><code> rsa_padding() = 'rsa_pkcs1_padding' | 'rsa_pkcs1_oaep_padding'
@@ -109,6 +114,8 @@
<p><code> dss_digest_type() = 'sha' </code></p>
+ <p><code> ecdsa_digest_type() = 'sha'| 'sha224' | 'sha256' | 'sha384' | 'sha512' </code></p>
+
<p><code> crl_reason() = unspecified | keyCompromise | cACompromise | affiliationChanged | superseded | cessationOfOperation | certificateHold | privilegeWithdrawn | aACompromise
</code></p>
@@ -147,6 +154,19 @@
<funcs>
<func>
+ <name> compute_key(OthersKey, MyKey)-></name>
+ <name> compute_key(OthersKey, MyKey, Params)-></name>
+ <fsummary> Compute shared secret</fsummary>
+ <type>
+ <v>OthersKey = #'ECPoint'{} | binary(), MyKey = #'ECPrivateKey'{} | binary()</v>
+ <v>Params = #'DHParameter'{}</v>
+ </type>
+ <desc>
+ <p> Compute shared secret </p>
+ </desc>
+ </func>
+
+ <func>
<name>decrypt_private(CipherText, Key) -> binary()</name>
<name>decrypt_private(CipherText, Key, Options) -> binary()</name>
<fsummary>Public key decryption.</fsummary>
@@ -204,6 +224,17 @@
</func>
<func>
+ <name>generate_key(Params) -> {Public::binary(), Private::binary()} | #'ECPrivateKey'{} </name>
+ <fsummary>Generates a new keypair</fsummary>
+ <type>
+ <v> Params = #'DHParameter'{} | {namedCurve, oid()} | #'ECParameters'{} </v>
+ </type>
+ <desc>
+ <p>Generates a new keypair</p>
+ </desc>
+ </func>
+
+ <func>
<name>pem_decode(PemBin) -> [pem_entry()]</name>
<fsummary>Decode PEM binary data and return
entries as ASN.1 DER encoded entities. </fsummary>
@@ -528,8 +559,8 @@ fun(OtpCert :: #'OTPCertificate'{}, Event :: {bad_cert, Reason :: atom()} |
<d>The msg is either the binary "plain text" data to be
signed or it is the hashed value of "plain text" i.e. the
digest.</d>
- <v>DigestType = rsa_digest_type() | dss_digest_type()</v>
- <v>Key = rsa_private_key() | dsa_private_key()</v>
+ <v>DigestType = rsa_digest_type() | dss_digest_type() | ecdsa_digest_type()</v>
+ <v>Key = rsa_private_key() | dsa_private_key() | ec_private_key()</v>
</type>
<desc>
<p> Creates a digital signature.</p>
@@ -592,12 +623,12 @@ fun(OtpCert :: #'OTPCertificate'{}, Event :: {bad_cert, Reason :: atom()} |
<v>Msg = binary() | {digest,binary()}</v>
<d>The msg is either the binary "plain text" data
or it is the hashed value of "plain text" i.e. the digest.</d>
- <v>DigestType = rsa_digest_type() | dss_digest_type()</v>
+ <v>DigestType = rsa_digest_type() | dss_digest_type() | ecdsa_digest_type()</v>
<v>Signature = binary()</v>
- <v>Key = rsa_public_key() | dsa_public_key()</v>
- </type>
- <desc>
- <p>Verifies a digital signature</p>
+ <v>Key = rsa_public_key() | dsa_public_key() | ec_public_key()</v>
+ </type>
+ <desc>
+ <p>Verifies a digital signature</p>
</desc>
</func>
diff --git a/lib/public_key/include/public_key.hrl b/lib/public_key/include/public_key.hrl
index 4d1d510f29..1e882e76ee 100644
--- a/lib/public_key/include/public_key.hrl
+++ b/lib/public_key/include/public_key.hrl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2008-2012. All Rights Reserved.
+%% Copyright Ericsson AB 2008-2013. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -72,6 +72,10 @@
valid_ext
}).
+-record('ECPoint', {
+ point
+ }).
+
-define(unspecified, 0).
-define(keyCompromise, 1).
@@ -89,6 +93,8 @@
-type rsa_private_key() :: #'RSAPrivateKey'{}.
-type dsa_private_key() :: #'DSAPrivateKey'{}.
-type dsa_public_key() :: {integer(), #'Dss-Parms'{}}.
+-type ec_public_key() :: {#'ECPoint'{},{namedCurve, Oid::tuple()} | #'ECParameters'{}}.
+-type ec_private_key() :: #'ECPrivateKey'{}.
-type der_encoded() :: binary().
-type decrypt_der() :: binary().
-type pki_asn1_type() :: 'Certificate' | 'RSAPrivateKey' | 'RSAPublicKey'
diff --git a/lib/public_key/src/pubkey_cert_records.erl b/lib/public_key/src/pubkey_cert_records.erl
index 98004c71a3..0449129809 100644
--- a/lib/public_key/src/pubkey_cert_records.erl
+++ b/lib/public_key/src/pubkey_cert_records.erl
@@ -23,7 +23,8 @@
-include("public_key.hrl").
--export([decode_cert/1, transform/2, supportedPublicKeyAlgorithms/1]).
+-export([decode_cert/1, transform/2, supportedPublicKeyAlgorithms/1,
+ supportedCurvesTypes/1, namedCurves/1]).
%%====================================================================
%% Internal application API
@@ -101,6 +102,77 @@ supportedPublicKeyAlgorithms(?'dhpublicnumber') -> 'DHPublicKey';
supportedPublicKeyAlgorithms(?'id-keyExchangeAlgorithm') -> 'KEA-PublicKey';
supportedPublicKeyAlgorithms(?'id-ecPublicKey') -> 'ECPoint'.
+supportedCurvesTypes(?'characteristic-two-field') -> characteristic_two_field;
+supportedCurvesTypes(?'prime-field') -> prime_field.
+
+namedCurves(?'sect571r1') -> sect571r1;
+namedCurves(?'sect571k1') -> sect571k1;
+namedCurves(?'sect409r1') -> sect409r1;
+namedCurves(?'sect409k1') -> sect409k1;
+namedCurves(?'secp521r1') -> secp521r1;
+namedCurves(?'secp384r1') -> secp384r1;
+namedCurves(?'secp224r1') -> secp224r1;
+namedCurves(?'secp224k1') -> secp224k1;
+namedCurves(?'secp192k1') -> secp192k1;
+namedCurves(?'secp160r2') -> secp160r2;
+namedCurves(?'secp128r2') -> secp128r2;
+namedCurves(?'secp128r1') -> secp128r1;
+namedCurves(?'sect233r1') -> sect233r1;
+namedCurves(?'sect233k1') -> sect233k1;
+namedCurves(?'sect193r2') -> sect193r2;
+namedCurves(?'sect193r1') -> sect193r1;
+namedCurves(?'sect131r2') -> sect131r2;
+namedCurves(?'sect131r1') -> sect131r1;
+namedCurves(?'sect283r1') -> sect283r1;
+namedCurves(?'sect283k1') -> sect283k1;
+namedCurves(?'sect163r2') -> sect163r2;
+namedCurves(?'secp256k1') -> secp256k1;
+namedCurves(?'secp160k1') -> secp160k1;
+namedCurves(?'secp160r1') -> secp160r1;
+namedCurves(?'secp112r2') -> secp112r2;
+namedCurves(?'secp112r1') -> secp112r1;
+namedCurves(?'sect113r2') -> sect113r2;
+namedCurves(?'sect113r1') -> sect113r1;
+namedCurves(?'sect239k1') -> sect239k1;
+namedCurves(?'sect163r1') -> sect163r1;
+namedCurves(?'sect163k1') -> sect163k1;
+namedCurves(?'secp256r1') -> secp256r1;
+namedCurves(?'secp192r1') -> secp192r1;
+
+namedCurves(sect571r1) -> ?'sect571r1';
+namedCurves(sect571k1) -> ?'sect571k1';
+namedCurves(sect409r1) -> ?'sect409r1';
+namedCurves(sect409k1) -> ?'sect409k1';
+namedCurves(secp521r1) -> ?'secp521r1';
+namedCurves(secp384r1) -> ?'secp384r1';
+namedCurves(secp224r1) -> ?'secp224r1';
+namedCurves(secp224k1) -> ?'secp224k1';
+namedCurves(secp192k1) -> ?'secp192k1';
+namedCurves(secp160r2) -> ?'secp160r2';
+namedCurves(secp128r2) -> ?'secp128r2';
+namedCurves(secp128r1) -> ?'secp128r1';
+namedCurves(sect233r1) -> ?'sect233r1';
+namedCurves(sect233k1) -> ?'sect233k1';
+namedCurves(sect193r2) -> ?'sect193r2';
+namedCurves(sect193r1) -> ?'sect193r1';
+namedCurves(sect131r2) -> ?'sect131r2';
+namedCurves(sect131r1) -> ?'sect131r1';
+namedCurves(sect283r1) -> ?'sect283r1';
+namedCurves(sect283k1) -> ?'sect283k1';
+namedCurves(sect163r2) -> ?'sect163r2';
+namedCurves(secp256k1) -> ?'secp256k1';
+namedCurves(secp160k1) -> ?'secp160k1';
+namedCurves(secp160r1) -> ?'secp160r1';
+namedCurves(secp112r2) -> ?'secp112r2';
+namedCurves(secp112r1) -> ?'secp112r1';
+namedCurves(sect113r2) -> ?'sect113r2';
+namedCurves(sect113r1) -> ?'sect113r1';
+namedCurves(sect239k1) -> ?'sect239k1';
+namedCurves(sect163r1) -> ?'sect163r1';
+namedCurves(sect163k1) -> ?'sect163k1';
+namedCurves(secp256r1) -> ?'secp256r1';
+namedCurves(secp192r1) -> ?'secp192r1'.
+
%%--------------------------------------------------------------------
%%% Internal functions
%%--------------------------------------------------------------------
@@ -111,14 +183,24 @@ decode_supportedPublicKey(#'OTPSubjectPublicKeyInfo'{algorithm= PA =
#'PublicKeyAlgorithm'{algorithm=Algo},
subjectPublicKey = {0,SPK0}}) ->
Type = supportedPublicKeyAlgorithms(Algo),
- {ok, SPK} = 'OTP-PUB-KEY':decode(Type, SPK0),
+ SPK = case Type of
+ 'ECPoint' -> #'ECPoint'{point = SPK0};
+ _ -> {ok, SPK1} = 'OTP-PUB-KEY':decode(Type, SPK0),
+ SPK1
+ end,
#'OTPSubjectPublicKeyInfo'{subjectPublicKey = SPK, algorithm=PA}.
encode_supportedPublicKey(#'OTPSubjectPublicKeyInfo'{algorithm= PA =
#'PublicKeyAlgorithm'{algorithm=Algo},
subjectPublicKey = SPK0}) ->
Type = supportedPublicKeyAlgorithms(Algo),
- {ok, SPK} = 'OTP-PUB-KEY':encode(Type, SPK0),
+ SPK = case Type of
+ 'ECPoint' ->
+ SPK0#'ECPoint'.point;
+ _ ->
+ {ok, SPK1} = 'OTP-PUB-KEY':encode(Type, SPK0),
+ SPK1
+ end,
#'OTPSubjectPublicKeyInfo'{subjectPublicKey = {0,SPK}, algorithm=PA}.
%%% Extensions
diff --git a/lib/public_key/src/pubkey_pem.erl b/lib/public_key/src/pubkey_pem.erl
index 6bdc35fb79..746d142ec3 100644
--- a/lib/public_key/src/pubkey_pem.erl
+++ b/lib/public_key/src/pubkey_pem.erl
@@ -202,7 +202,11 @@ pem_start('CertificationRequest') ->
pem_start('ContentInfo') ->
<<"-----BEGIN PKCS7-----">>;
pem_start('CertificateList') ->
- <<"-----BEGIN X509 CRL-----">>.
+ <<"-----BEGIN X509 CRL-----">>;
+pem_start('OTPEcpkParameters') ->
+ <<"-----BEGIN EC PARAMETERS-----">>;
+pem_start('ECPrivateKey') ->
+ <<"-----BEGIN EC PRIVATE KEY-----">>.
pem_end(<<"-----BEGIN CERTIFICATE-----">>) ->
<<"-----END CERTIFICATE-----">>;
@@ -226,6 +230,10 @@ pem_end(<<"-----BEGIN PKCS7-----">>) ->
<<"-----END PKCS7-----">>;
pem_end(<<"-----BEGIN X509 CRL-----">>) ->
<<"-----END X509 CRL-----">>;
+pem_end(<<"-----BEGIN EC PARAMETERS-----">>) ->
+ <<"-----END EC PARAMETERS-----">>;
+pem_end(<<"-----BEGIN EC PRIVATE KEY-----">>) ->
+ <<"-----END EC PRIVATE KEY-----">>;
pem_end(_) ->
undefined.
@@ -250,7 +258,11 @@ asn1_type(<<"-----BEGIN CERTIFICATE REQUEST-----">>) ->
asn1_type(<<"-----BEGIN PKCS7-----">>) ->
'ContentInfo';
asn1_type(<<"-----BEGIN X509 CRL-----">>) ->
- 'CertificateList'.
+ 'CertificateList';
+asn1_type(<<"-----BEGIN EC PARAMETERS-----">>) ->
+ 'OTPEcpkParameters';
+asn1_type(<<"-----BEGIN EC PRIVATE KEY-----">>) ->
+ 'ECPrivateKey'.
pem_decrypt() ->
<<"Proc-Type: 4,ENCRYPTED">>.
diff --git a/lib/public_key/src/public_key.erl b/lib/public_key/src/public_key.erl
index 736c18cdd4..648dba3d5a 100644
--- a/lib/public_key/src/public_key.erl
+++ b/lib/public_key/src/public_key.erl
@@ -35,6 +35,8 @@
encrypt_public/2, encrypt_public/3,
decrypt_public/2, decrypt_public/3,
sign/3, verify/4,
+ generate_key/1,
+ compute_key/2, compute_key/3,
pkix_sign/2, pkix_verify/2,
pkix_sign_types/1,
pkix_is_self_signed/1,
@@ -52,6 +54,7 @@
-type public_crypt_options() :: [{rsa_pad, rsa_padding()}].
-type rsa_digest_type() :: 'md5' | 'sha'| 'sha224' | 'sha256' | 'sha384' | 'sha512'.
-type dss_digest_type() :: 'none' | 'sha'. %% None is for backwards compatibility
+-type ecdsa_digest_type() :: 'sha'| 'sha224' | 'sha256' | 'sha384' | 'sha512'.
-type crl_reason() :: unspecified | keyCompromise | cACompromise | affiliationChanged | superseded
| cessationOfOperation | certificateHold | privilegeWithdrawn | aACompromise.
-type oid() :: tuple().
@@ -94,7 +97,9 @@ pem_entry_decode({'SubjectPublicKeyInfo', Der, _}) ->
der_decode(KeyType, Key0);
'DSAPublicKey' ->
{params, DssParams} = der_decode('DSAParams', Params),
- {der_decode(KeyType, Key0), DssParams}
+ {der_decode(KeyType, Key0), DssParams};
+ 'ECPoint' ->
+ der_decode(KeyType, Key0)
end;
pem_entry_decode({Asn1Type, Der, not_encrypted}) when is_atom(Asn1Type),
is_binary(Der) ->
@@ -251,10 +256,9 @@ decrypt_private(CipherText,
privateExponent = D} = Key,
Options)
when is_binary(CipherText),
- is_integer(N), is_integer(E), is_integer(D),
is_list(Options) ->
Padding = proplists:get_value(rsa_pad, Options, rsa_pkcs1_padding),
- crypto:rsa_private_decrypt(CipherText, format_rsa_private_key(Key), Padding).
+ crypto:private_decrypt(rsa, CipherText, format_rsa_private_key(Key), Padding).
%%--------------------------------------------------------------------
-spec decrypt_public(CipherText :: binary(), rsa_public_key() | rsa_private_key()) ->
@@ -318,30 +322,41 @@ encrypt_private(PlainText,
Options)
when is_binary(PlainText),
is_integer(N), is_integer(E), is_integer(D),
- is_list(Options) ->
+ is_list(Options) ->
Padding = proplists:get_value(rsa_pad, Options, rsa_pkcs1_padding),
- crypto:rsa_private_encrypt(PlainText, format_rsa_private_key(Key), Padding).
+ crypto:private_encrypt(rsa, PlainText, format_rsa_private_key(Key), Padding).
+%%--------------------------------------------------------------------
+-spec generate_key(#'DHParameter'{} | {namedCurve, Name ::atom()} |
+ #'ECParameters'{}) -> {Public::binary(), Private::binary()} |
+ #'ECPrivateKey'{}.
+%% Description: Generates a new keypair
+%%--------------------------------------------------------------------
+generate_key(#'DHParameter'{prime = P, base = G}) ->
+ crypto:generate_key(dh, [P, G]);
+generate_key({namedCurve, _} = Params) ->
+ ec_generate_key(Params);
+generate_key(#'ECParameters'{} = Params) ->
+ ec_generate_key(Params).
-format_rsa_private_key(#'RSAPrivateKey'{modulus = N, publicExponent = E,
- privateExponent = D,
- prime1 = P1, prime2 = P2,
- exponent1 = E1, exponent2 = E2,
- coefficient = C})
- when is_integer(P1), is_integer(P2),
- is_integer(E1), is_integer(E2), is_integer(C) ->
- [crypto:mpint(K) || K <- [E, N, D, P1, P2, E1, E2, C]];
+%%--------------------------------------------------------------------
+-spec compute_key(#'ECPoint'{} , #'ECPrivateKey'{}) -> binary().
+-spec compute_key(OthersKey ::binary(), MyKey::binary(), #'DHParameter'{}) -> binary().
+%% Description: Compute shared secret
+%%--------------------------------------------------------------------
+compute_key(#'ECPoint'{point = Point}, #'ECPrivateKey'{privateKey = PrivKey,
+ parameters = Param}) ->
+ ECCurve = ec_curve_spec(Param),
+ crypto:compute_key(ecdh, Point, list2int(PrivKey), ECCurve).
-format_rsa_private_key(#'RSAPrivateKey'{modulus = N, publicExponent = E,
- privateExponent = D}) ->
- [crypto:mpint(K) || K <- [E, N, D]].
+compute_key(PubKey, PrivKey, #'DHParameter'{prime = P, base = G}) ->
+ crypto:compute_key(dh, PubKey, PrivKey, [P, G]).
%%--------------------------------------------------------------------
-
-spec pkix_sign_types(SignatureAlg::oid()) ->
%% Relevant dsa digest type is subpart of rsa digest type
{ DigestType :: rsa_digest_type(),
- SignatureType :: rsa | dsa
+ SignatureType :: rsa | dsa | ecdsa
}.
%% Description:
%%--------------------------------------------------------------------
@@ -362,68 +377,60 @@ pkix_sign_types(?md5WithRSAEncryption) ->
pkix_sign_types(?'id-dsa-with-sha1') ->
{sha, dsa};
pkix_sign_types(?'id-dsaWithSHA1') ->
- {sha, dsa}.
+ {sha, dsa};
+pkix_sign_types(?'ecdsa-with-SHA1') ->
+ {sha, ecdsa};
+pkix_sign_types(?'ecdsa-with-SHA256') ->
+ {sha256, ecdsa};
+pkix_sign_types(?'ecdsa-with-SHA384') ->
+ {sha384, ecdsa};
+pkix_sign_types(?'ecdsa-with-SHA512') ->
+ {sha512, ecdsa}.
%%--------------------------------------------------------------------
--spec sign(binary() | {digest, binary()}, rsa_digest_type() | dss_digest_type(),
+-spec sign(binary() | {digest, binary()}, rsa_digest_type() | dss_digest_type() | ecdsa_digest_type(),
rsa_private_key() |
- dsa_private_key()) -> Signature :: binary().
+ dsa_private_key() | ec_private_key()) -> Signature :: binary().
%% Description: Create digital signature.
%%--------------------------------------------------------------------
-sign({digest,_}=Digest, DigestType, Key = #'RSAPrivateKey'{}) ->
- crypto:rsa_sign(DigestType, Digest, format_rsa_private_key(Key));
+sign(DigestOrPlainText, DigestType, Key = #'RSAPrivateKey'{}) ->
+ crypto:sign(rsa, DigestType, DigestOrPlainText, format_rsa_private_key(Key));
-sign(PlainText, DigestType, Key = #'RSAPrivateKey'{}) ->
- crypto:rsa_sign(DigestType, sized_binary(PlainText), format_rsa_private_key(Key));
+sign(DigestOrPlainText, sha, #'DSAPrivateKey'{p = P, q = Q, g = G, x = X}) ->
+ crypto:sign(dss, sha, DigestOrPlainText, [P, Q, G, X]);
-sign({digest,_}=Digest, sha, #'DSAPrivateKey'{p = P, q = Q, g = G, x = X}) ->
- crypto:dss_sign(Digest,
- [crypto:mpint(P), crypto:mpint(Q),
- crypto:mpint(G), crypto:mpint(X)]);
-
-sign(PlainText, sha, #'DSAPrivateKey'{p = P, q = Q, g = G, x = X}) ->
- crypto:dss_sign(sized_binary(PlainText),
- [crypto:mpint(P), crypto:mpint(Q),
- crypto:mpint(G), crypto:mpint(X)]);
+sign(DigestOrPlainText, DigestType, #'ECPrivateKey'{privateKey = PrivKey,
+ parameters = Param}) ->
+ ECCurve = ec_curve_spec(Param),
+ crypto:sign(ecdsa, DigestType, DigestOrPlainText, [list2int(PrivKey), ECCurve]);
%% Backwards compatible
sign(Digest, none, #'DSAPrivateKey'{} = Key) ->
sign({digest,Digest}, sha, Key).
%%--------------------------------------------------------------------
--spec verify(binary() | {digest, binary()}, rsa_digest_type() | dss_digest_type(),
+-spec verify(binary() | {digest, binary()}, rsa_digest_type() | dss_digest_type() | ecdsa_digest_type(),
Signature :: binary(), rsa_public_key()
- | dsa_public_key()) -> boolean().
+ | dsa_public_key() | ec_public_key()) -> boolean().
%% Description: Verifies a digital signature.
%%--------------------------------------------------------------------
-verify({digest,_}=Digest, DigestType, Signature,
+verify(DigestOrPlainText, DigestType, Signature,
#'RSAPublicKey'{modulus = Mod, publicExponent = Exp}) ->
- crypto:rsa_verify(DigestType, Digest,
- sized_binary(Signature),
- [crypto:mpint(Exp), crypto:mpint(Mod)]);
+ crypto:verify(rsa, DigestType, DigestOrPlainText, Signature,
+ [Exp, Mod]);
-verify(PlainText, DigestType, Signature,
- #'RSAPublicKey'{modulus = Mod, publicExponent = Exp}) ->
- crypto:rsa_verify(DigestType,
- sized_binary(PlainText),
- sized_binary(Signature),
- [crypto:mpint(Exp), crypto:mpint(Mod)]);
+verify(DigestOrPlaintext, DigestType, Signature, {#'ECPoint'{point = Point}, Param}) ->
+ ECCurve = ec_curve_spec(Param),
+ crypto:verify(ecdsa, DigestType, DigestOrPlaintext, Signature, [Point, ECCurve]);
-verify({digest,_}=Digest, sha, Signature, {Key, #'Dss-Parms'{p = P, q = Q, g = G}})
- when is_integer(Key), is_binary(Signature) ->
- crypto:dss_verify(Digest, sized_binary(Signature),
- [crypto:mpint(P), crypto:mpint(Q),
- crypto:mpint(G), crypto:mpint(Key)]);
%% Backwards compatibility
verify(Digest, none, Signature, {_, #'Dss-Parms'{}} = Key ) ->
verify({digest,Digest}, sha, Signature, Key);
-verify(PlainText, sha, Signature, {Key, #'Dss-Parms'{p = P, q = Q, g = G}})
- when is_integer(Key), is_binary(PlainText), is_binary(Signature) ->
- crypto:dss_verify(sized_binary(PlainText),
- sized_binary(Signature),
- [crypto:mpint(P), crypto:mpint(Q),
- crypto:mpint(G), crypto:mpint(Key)]).
+verify(DigestOrPlainText, sha = DigestType, Signature, {Key, #'Dss-Parms'{p = P, q = Q, g = G}})
+ when is_integer(Key), is_binary(Signature) ->
+ crypto:verify(dss, DigestType, DigestOrPlainText, Signature, [P, Q, G, Key]).
+
%%--------------------------------------------------------------------
-spec pkix_sign(#'OTPTBSCertificate'{},
rsa_private_key() | dsa_private_key()) -> Der::binary().
@@ -446,7 +453,7 @@ pkix_sign(#'OTPTBSCertificate'{signature =
%%--------------------------------------------------------------------
-spec pkix_verify(Cert::binary(), rsa_public_key()|
- dsa_public_key()) -> boolean().
+ dsa_public_key() | ec_public_key()) -> boolean().
%%
%% Description: Verify pkix x.509 certificate signature.
%%--------------------------------------------------------------------
@@ -458,7 +465,12 @@ pkix_verify(DerCert, {Key, #'Dss-Parms'{}} = DSAKey)
pkix_verify(DerCert, #'RSAPublicKey'{} = RSAKey)
when is_binary(DerCert) ->
{DigestType, PlainText, Signature} = pubkey_cert:verify_data(DerCert),
- verify(PlainText, DigestType, Signature, RSAKey).
+ verify(PlainText, DigestType, Signature, RSAKey);
+
+pkix_verify(DerCert, Key = {#'ECPoint'{}, _})
+ when is_binary(DerCert) ->
+ {DigestType, PlainText, Signature} = pubkey_cert:verify_data(DerCert),
+ verify(PlainText, DigestType, Signature, Key).
%%--------------------------------------------------------------------
-spec pkix_is_issuer(Cert :: der_encoded()| #'OTPCertificate'{} | #'CertificateList'{},
@@ -640,13 +652,11 @@ do_pem_entry_decode({Asn1Type,_, _} = PemEntry, Password) ->
encrypt_public(PlainText, N, E, Options)->
Padding = proplists:get_value(rsa_pad, Options, rsa_pkcs1_padding),
- crypto:rsa_public_encrypt(PlainText, [crypto:mpint(E),crypto:mpint(N)],
- Padding).
+ crypto:public_encrypt(rsa, PlainText, [E,N], Padding).
-decrypt_public(CipherText, N,E, Options) ->
+decrypt_public(CipherText, N,E, Options) ->
Padding = proplists:get_value(rsa_pad, Options, rsa_pkcs1_padding),
- crypto:rsa_public_decrypt(CipherText,[crypto:mpint(E), crypto:mpint(N)],
- Padding).
+ crypto:public_decrypt(rsa, CipherText,[E, N], Padding).
path_validation([], #path_validation_state{working_public_key_algorithm
= Algorithm,
@@ -732,10 +742,6 @@ validate(Cert, #path_validation_state{working_issuer_name = Issuer,
pubkey_cert:prepare_for_next_cert(OtpCert, ValidationState).
-sized_binary(Binary) ->
- Size = size(Binary),
- <<?UINT32(Size), Binary/binary>>.
-
otp_cert(Der) when is_binary(Der) ->
pkix_decode_cert(Der, otp);
otp_cert(#'OTPCertificate'{} =Cert) ->
@@ -842,3 +848,46 @@ combine(CRL, DeltaCRLs) ->
end,
lists:foldl(Fun, hd(Deltas), tl(Deltas))
end.
+
+format_rsa_private_key(#'RSAPrivateKey'{modulus = N, publicExponent = E,
+ privateExponent = D,
+ prime1 = P1, prime2 = P2,
+ exponent1 = E1, exponent2 = E2,
+ coefficient = C})
+ when is_integer(N), is_integer(E), is_integer(D),
+ is_integer(P1), is_integer(P2),
+ is_integer(E1), is_integer(E2), is_integer(C) ->
+ [E, N, D, P1, P2, E1, E2, C];
+
+format_rsa_private_key(#'RSAPrivateKey'{modulus = N, publicExponent = E,
+ privateExponent = D}) when is_integer(N),
+ is_integer(E),
+ is_integer(D) ->
+ [E, N, D].
+
+ec_generate_key(Params) ->
+ Curve = ec_curve_spec(Params),
+ Term = crypto:generate_key(ecdh, Curve),
+ ec_key(Term, Params).
+
+ec_curve_spec( #'ECParameters'{fieldID = FieldId, curve = PCurve, base = Base, order = Order, cofactor = CoFactor }) ->
+ Field = {pubkey_cert_records:supportedCurvesTypes(FieldId#'FieldID'.fieldType),
+ FieldId#'FieldID'.parameters},
+ Curve = {erlang:list_to_binary(PCurve#'Curve'.a), erlang:list_to_binary(PCurve#'Curve'.b), none},
+ {Field, Curve, erlang:list_to_binary(Base), Order, CoFactor};
+ec_curve_spec({namedCurve, OID}) ->
+ pubkey_cert_records:namedCurves(OID).
+
+ec_key({PrivateKey, PubKey}, Params) ->
+ #'ECPrivateKey'{version = 1,
+ privateKey = int2list(PrivateKey),
+ parameters = Params,
+ publicKey = {0, PubKey}}.
+
+list2int(L) ->
+ S = length(L) * 8,
+ <<R:S/integer>> = erlang:iolist_to_binary(L),
+ R.
+int2list(I) ->
+ L = (length(integer_to_list(I, 16)) + 1) div 2,
+ binary_to_list(<<I:(L*8)>>).
diff --git a/lib/public_key/test/erl_make_certs.erl b/lib/public_key/test/erl_make_certs.erl
index 897cf2f350..14efbcc7e0 100644
--- a/lib/public_key/test/erl_make_certs.erl
+++ b/lib/public_key/test/erl_make_certs.erl
@@ -45,7 +45,7 @@
%% {dnQualifer, DnQ}
%% issuer = {Issuer, IssuerKey} true (i.e. a ca cert is created)
%% (obs IssuerKey migth be {Key, Password}
-%% key = KeyFile|KeyBin|rsa|dsa Subject PublicKey rsa or dsa generates key
+%% key = KeyFile|KeyBin|rsa|dsa|ec Subject PublicKey rsa, dsa or ec generates key
%%
%%
%% (OBS: The generated keys are for testing only)
@@ -91,6 +91,16 @@ gen_dsa(LSize,NSize) when is_integer(LSize), is_integer(NSize) ->
{Key, encode_key(Key)}.
%%--------------------------------------------------------------------
+%% @doc Creates a ec key (OBS: for testing only)
+%% the sizes are in bytes
+%% @spec (::integer()) -> {::atom(), ::binary(), ::opaque()}
+%% @end
+%%--------------------------------------------------------------------
+gen_ec(Curve) when is_atom(Curve) ->
+ Key = gen_ec2(Curve),
+ {Key, encode_key(Key)}.
+
+%%--------------------------------------------------------------------
%% @doc Verifies cert signatures
%% @spec (::binary(), ::tuple()) -> ::boolean()
%% @end
@@ -102,7 +112,10 @@ verify_signature(DerEncodedCert, DerKey, _KeyParams) ->
public_key:pkix_verify(DerEncodedCert,
#'RSAPublicKey'{modulus=Mod, publicExponent=Exp});
#'DSAPrivateKey'{p=P, q=Q, g=G, y=Y} ->
- public_key:pkix_verify(DerEncodedCert, {Y, #'Dss-Parms'{p=P, q=Q, g=G}})
+ public_key:pkix_verify(DerEncodedCert, {Y, #'Dss-Parms'{p=P, q=Q, g=G}});
+ #'ECPrivateKey'{version = _Version, privateKey = _PrivKey,
+ parameters = _Params, publicKey = _PubKey} ->
+ public_key:pkix_verify(DerEncodedCert, Key)
end.
%%%%%%%%%%%%%%%%%%%%%%%%% Implementation %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
@@ -112,6 +125,7 @@ get_key(Opts) ->
undefined -> make_key(rsa, Opts);
rsa -> make_key(rsa, Opts);
dsa -> make_key(dsa, Opts);
+ ec -> make_key(ec, Opts);
Key ->
Password = proplists:get_value(password, Opts, no_passwd),
decode_key(Key, Password)
@@ -129,6 +143,8 @@ decode_key(#'RSAPrivateKey'{} = Key,_) ->
Key;
decode_key(#'DSAPrivateKey'{} = Key,_) ->
Key;
+decode_key(#'ECPrivateKey'{} = Key,_) ->
+ Key;
decode_key(PemEntry = {_,_,_}, Pw) ->
public_key:pem_entry_decode(PemEntry, Pw);
decode_key(PemBin, Pw) ->
@@ -140,7 +156,10 @@ encode_key(Key = #'RSAPrivateKey'{}) ->
{'RSAPrivateKey', Der, not_encrypted};
encode_key(Key = #'DSAPrivateKey'{}) ->
{ok, Der} = 'OTP-PUB-KEY':encode('DSAPrivateKey', Key),
- {'DSAPrivateKey', Der, not_encrypted}.
+ {'DSAPrivateKey', Der, not_encrypted};
+encode_key(Key = #'ECPrivateKey'{}) ->
+ {ok, Der} = 'OTP-PUB-KEY':encode('ECPrivateKey', Key),
+ {'ECPrivateKey', Der, not_encrypted}.
make_tbs(SubjectKey, Opts) ->
Version = list_to_atom("v"++integer_to_list(proplists:get_value(version, Opts, 3))),
@@ -282,7 +301,14 @@ publickey(#'RSAPrivateKey'{modulus=N, publicExponent=E}) ->
publickey(#'DSAPrivateKey'{p=P, q=Q, g=G, y=Y}) ->
Algo = #'PublicKeyAlgorithm'{algorithm= ?'id-dsa',
parameters={params, #'Dss-Parms'{p=P, q=Q, g=G}}},
- #'OTPSubjectPublicKeyInfo'{algorithm = Algo, subjectPublicKey = Y}.
+ #'OTPSubjectPublicKeyInfo'{algorithm = Algo, subjectPublicKey = Y};
+publickey(#'ECPrivateKey'{version = _Version,
+ privateKey = _PrivKey,
+ parameters = Params,
+ publicKey = {0, PubKey}}) ->
+ Algo = #'PublicKeyAlgorithm'{algorithm= ?'id-ecPublicKey', parameters=Params},
+ #'OTPSubjectPublicKeyInfo'{algorithm = Algo,
+ subjectPublicKey = #'ECPoint'{point = PubKey}}.
validity(Opts) ->
DefFrom0 = calendar:gregorian_days_to_date(calendar:date_to_gregorian_days(date())-1),
@@ -303,13 +329,24 @@ sign_algorithm(#'RSAPrivateKey'{}, Opts) ->
end,
{Type, 'NULL'};
sign_algorithm(#'DSAPrivateKey'{p=P, q=Q, g=G}, _Opts) ->
- {?'id-dsa-with-sha1', {params,#'Dss-Parms'{p=P, q=Q, g=G}}}.
+ {?'id-dsa-with-sha1', {params,#'Dss-Parms'{p=P, q=Q, g=G}}};
+sign_algorithm(#'ECPrivateKey'{}, Opts) ->
+ Type = case proplists:get_value(digest, Opts, sha1) of
+ sha1 -> ?'ecdsa-with-SHA1';
+ sha512 -> ?'ecdsa-with-SHA512';
+ sha384 -> ?'ecdsa-with-SHA384';
+ sha256 -> ?'ecdsa-with-SHA256'
+ end,
+ {Type, 'NULL'}.
make_key(rsa, _Opts) ->
%% (OBS: for testing only)
gen_rsa2(64);
make_key(dsa, _Opts) ->
- gen_dsa2(128, 20). %% Bytes i.e. {1024, 160}
+ gen_dsa2(128, 20); %% Bytes i.e. {1024, 160}
+make_key(ec, _Opts) ->
+ %% (OBS: for testing only)
+ gen_ec2(secp256k1).
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%% RSA key generation (OBS: for testing only)
@@ -368,6 +405,24 @@ gen_dsa2(LSize, NSize) ->
#'DSAPrivateKey'{version=0, p=P, q=Q, g=G, y=Y, x=X}
end.
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%% EC key generation (OBS: for testing only)
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+int2list(I) ->
+ L = (length(integer_to_list(I, 16)) + 1) div 2,
+ binary_to_list(<<I:(L*8)>>).
+
+gen_ec2(CurveId) ->
+ Key = crypto:ec_key_new(CurveId),
+ crypto:ec_key_generate(Key),
+ {_Curve, PrivKey, PubKey} = crypto:ec_key_to_term(Key),
+
+ #'ECPrivateKey'{version = 1,
+ privateKey = int2list(PrivKey),
+ parameters = {namedCurve, pubkey_cert_records:namedCurves(CurveId)},
+ publicKey = {0, PubKey}}.
+
%% See fips_186-3.pdf
dsa_search(T, P0, Q, Iter) when Iter > 0 ->
P = 2*T*Q*P0 + 1,
diff --git a/lib/public_key/test/pkits_SUITE.erl b/lib/public_key/test/pkits_SUITE.erl
index d901adaadd..8cdf0aaae3 100644
--- a/lib/public_key/test/pkits_SUITE.erl
+++ b/lib/public_key/test/pkits_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2008-2012. All Rights Reserved.
+%% Copyright Ericsson AB 2008-2013. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -758,11 +758,10 @@ warning(Format, Args, File0, Line) ->
io:format("~s(~p): Warning "++Format, [File,Line|Args]).
crypto_support_check(Config) ->
- try crypto:sha256(<<"Test">>) of
- _ ->
- Config
- catch error:notsup ->
- crypto:stop(),
+ case proplists:get_bool(sha256, crypto:algorithms()) of
+ true ->
+ Config;
+ false ->
{skip, "To old version of openssl"}
end.
diff --git a/lib/public_key/test/public_key_SUITE.erl b/lib/public_key/test/public_key_SUITE.erl
index 0de80edeac..5a64140c67 100644
--- a/lib/public_key/test/public_key_SUITE.erl
+++ b/lib/public_key/test/public_key_SUITE.erl
@@ -551,7 +551,7 @@ dsa_sign_verify(Config) when is_list(Config) ->
false = public_key:verify(Msg, sha, <<1:8, DSASign/binary>>,
{DSAPublicKey, DSAParams}),
- Digest = crypto:sha(Msg),
+ Digest = crypto:hash(sha,Msg),
DigestSign = public_key:sign(Digest, none, DSAPrivateKey),
true = public_key:verify(Digest, none, DigestSign, {DSAPublicKey, DSAParams}),
<<_:8, RestDigest/binary>> = Digest,
diff --git a/lib/reltool/src/reltool_utils.erl b/lib/reltool/src/reltool_utils.erl
index edccb889b1..9af8f6bae8 100644
--- a/lib/reltool/src/reltool_utils.erl
+++ b/lib/reltool/src/reltool_utils.erl
@@ -572,7 +572,7 @@ copy_file(From, To) ->
FromMode = FromInfo#file_info.mode,
ToMode = ToInfo#file_info.mode,
ToMode2 = FromMode bor ToMode,
- FileInfo = FromInfo#file_info{mode = ToMode2},
+ FileInfo = ToInfo#file_info{mode = ToMode2},
write_file_info(To, FileInfo),
ok;
{error, Reason} ->
diff --git a/lib/ssl/doc/src/ssl.xml b/lib/ssl/doc/src/ssl.xml
index d5615fecfc..1645eb15f3 100644
--- a/lib/ssl/doc/src/ssl.xml
+++ b/lib/ssl/doc/src/ssl.xml
@@ -37,17 +37,21 @@
<list type="bulleted">
<item>ssl requires the crypto and public_key applications.</item>
<item>Supported SSL/TLS-versions are SSL-3.0, TLS-1.0,
- TLS-1.1 and TLS-1.2 (no support for elliptic curve cipher suites yet).</item>
+ TLS-1.1 and TLS-1.2.</item>
<item>For security reasons sslv2 is not supported.</item>
<item>Ephemeral Diffie-Hellman cipher suites are supported
but not Diffie Hellman Certificates cipher suites.</item>
+ <item>Elliptic Curve cipher suites are supported if crypto
+ supports it and named curves are used.
+ </item>
<item>Export cipher suites are not supported as the
U.S. lifted its export restrictions in early 2000.</item>
<item>IDEA cipher suites are not supported as they have
become deprecated by the latest TLS spec so there is not any
real motivation to implement them.</item>
- <item>CRL and policy certificate
- extensions are not supported yet. </item>
+ <item>CRL and policy certificate extensions are not supported
+ yet. However CRL verification is supported by public_key, only not integrated
+ in ssl yet. </item>
</list>
</section>
@@ -75,7 +79,7 @@
{fail_if_no_peer_cert, boolean()}
{depth, integer()} |
{cert, der_encoded()}| {certfile, path()} |
- {key, {'RSAPrivateKey'| 'DSAPrivateKey' | 'PrivateKeyInfo', der_encoded()}} |
+ {key, {'RSAPrivateKey'| 'DSAPrivateKey' | 'ECPrivateKey' |'PrivateKeyInfo', der_encoded()}} |
{keyfile, path()} | {password, string()} |
{cacerts, [der_encoded()]} | {cacertfile, path()} |
|{dh, der_encoded()} | {dhfile, path()} | {ciphers, ciphers()} |
@@ -125,6 +129,7 @@
<p><c>key_exchange() = rsa | dhe_dss | dhe_rsa | dh_anon
| psk | dhe_psk | rsa_psk | srp_anon | srp_dss | srp_rsa
+ | ecdh_anon | ecdh_ecdsa | ecdhe_ecdsa | ecdh_rsa | ecdhe_rsa
</c></p>
<p><c>cipher() = rc4_128 | des_cbc | '3des_ede_cbc'
@@ -157,7 +162,7 @@
<tag>{certfile, path()}</tag>
<item>Path to a file containing the user's certificate.</item>
- <tag>{key, {'RSAPrivateKey'| 'DSAPrivateKey' | 'PrivateKeyInfo', der_encoded()}}</tag>
+ <tag>{key, {'RSAPrivateKey'| 'DSAPrivateKey' | 'ECPrivateKey' |'PrivateKeyInfo', der_encoded()}}</tag>
<item> The DER encoded users private key. If this option
is supplied it will override the keyfile option.</item>
diff --git a/lib/ssl/src/ssl.erl b/lib/ssl/src/ssl.erl
index 70f3b4f050..f52862729a 100644
--- a/lib/ssl/src/ssl.erl
+++ b/lib/ssl/src/ssl.erl
@@ -364,11 +364,11 @@ cipher_suites() ->
cipher_suites(erlang) ->
Version = ssl_record:highest_protocol_version([]),
- [suite_definition(S) || S <- ssl_cipher:suites(Version)];
+ [suite_definition(S) || S <- cipher_suites(Version, [])];
cipher_suites(openssl) ->
Version = ssl_record:highest_protocol_version([]),
- [ssl_cipher:openssl_suite_name(S) || S <- ssl_cipher:suites(Version)];
+ [ssl_cipher:openssl_suite_name(S) || S <- cipher_suites(Version, [])];
cipher_suites(all) ->
Version = ssl_record:highest_protocol_version([]),
@@ -739,6 +739,7 @@ validate_option(key, {KeyType, Value}) when is_binary(Value),
KeyType == dsa; %% Backwards compatibility
KeyType == 'RSAPrivateKey';
KeyType == 'DSAPrivateKey';
+ KeyType == 'ECPrivateKey';
KeyType == 'PrivateKeyInfo' ->
{KeyType, Value};
@@ -947,21 +948,22 @@ emulated_options([], Inet,Emulated) ->
{Inet, Emulated}.
cipher_suites(Version, []) ->
- ssl_cipher:suites(Version);
+ ssl_cipher:filter_suites(ssl_cipher:suites(Version));
cipher_suites(Version, [{_,_,_,_}| _] = Ciphers0) -> %% Backwards compatibility
Ciphers = [{KeyExchange, Cipher, Hash} || {KeyExchange, Cipher, Hash, _} <- Ciphers0],
- cipher_suites(Version, Ciphers);
+ ssl_cipher:filter_suites(cipher_suites(Version, Ciphers));
cipher_suites(Version, [{_,_,_}| _] = Ciphers0) ->
Ciphers = [ssl_cipher:suite(C) || C <- Ciphers0],
- cipher_suites(Version, Ciphers);
+ ssl_cipher:filter_suites(cipher_suites(Version, Ciphers));
cipher_suites(Version, [Cipher0 | _] = Ciphers0) when is_binary(Cipher0) ->
- Supported = ssl_cipher:suites(Version)
+ Supported0 = ssl_cipher:suites(Version)
++ ssl_cipher:anonymous_suites()
++ ssl_cipher:psk_suites(Version)
++ ssl_cipher:srp_suites(),
- case [Cipher || Cipher <- Ciphers0, lists:member(Cipher, Supported)] of
+ Supported1 = ssl_cipher:filter_suites(Supported0),
+ case [Cipher || Cipher <- Ciphers0, lists:member(Cipher, Supported1)] of
[] ->
- Supported;
+ Supported1;
Ciphers ->
Ciphers
end;
diff --git a/lib/ssl/src/ssl_certificate.erl b/lib/ssl/src/ssl_certificate.erl
index 01a7cd93b5..9e1c3a09bf 100644
--- a/lib/ssl/src/ssl_certificate.erl
+++ b/lib/ssl/src/ssl_certificate.erl
@@ -37,7 +37,8 @@
is_valid_extkey_usage/2,
is_valid_key_usage/2,
select_extension/2,
- extensions_list/1
+ extensions_list/1,
+ public_key_type/1
]).
%%====================================================================
@@ -166,6 +167,18 @@ extensions_list(Extensions) ->
Extensions.
%%--------------------------------------------------------------------
+-spec public_key_type(term()) -> rsa | dsa | ec.
+%%
+%% Description:
+%%--------------------------------------------------------------------
+public_key_type(?'rsaEncryption') ->
+ rsa;
+public_key_type(?'id-dsa') ->
+ dsa;
+public_key_type(?'id-ecPublicKey') ->
+ ec.
+
+%%--------------------------------------------------------------------
%%% Internal functions
%%--------------------------------------------------------------------
certificate_chain(OtpCert, _Cert, CertDbHandle, CertsDbRef, Chain) ->
diff --git a/lib/ssl/src/ssl_certificate_db.erl b/lib/ssl/src/ssl_certificate_db.erl
index ff36b5ee26..cdff73336e 100644
--- a/lib/ssl/src/ssl_certificate_db.erl
+++ b/lib/ssl/src/ssl_certificate_db.erl
@@ -100,7 +100,7 @@ add_trusted_certs(_Pid, {der, DerList}, [CerDb, _,_]) ->
{ok, NewRef};
add_trusted_certs(_Pid, File, [CertsDb, RefDb, PemChache] = Db) ->
- MD5 = crypto:md5(File),
+ MD5 = crypto:hash(md5, File),
case lookup_cached_pem(Db, MD5) of
[{_Content, Ref}] ->
ref_count(Ref, RefDb, 1),
diff --git a/lib/ssl/src/ssl_cipher.erl b/lib/ssl/src/ssl_cipher.erl
index 173c53709b..dc413d6dfc 100644
--- a/lib/ssl/src/ssl_cipher.erl
+++ b/lib/ssl/src/ssl_cipher.erl
@@ -35,7 +35,7 @@
-export([security_parameters/3, suite_definition/1,
decipher/5, cipher/5,
suite/1, suites/1, anonymous_suites/0, psk_suites/1, srp_suites/0,
- openssl_suite/1, openssl_suite_name/1, filter/2,
+ openssl_suite/1, openssl_suite_name/1, filter/2, filter_suites/1,
hash_algorithm/1, sign_algorithm/1]).
-compile(inline).
@@ -73,25 +73,25 @@ cipher(?NULL, CipherState, <<>>, Fragment, _Version) ->
{GenStreamCipherList, CipherState};
cipher(?RC4, CipherState, Mac, Fragment, _Version) ->
State0 = case CipherState#cipher_state.state of
- undefined -> crypto:rc4_set_key(CipherState#cipher_state.key);
+ undefined -> crypto:stream_init(rc4, CipherState#cipher_state.key);
S -> S
end,
GenStreamCipherList = [Fragment, Mac],
- {State1, T} = crypto:rc4_encrypt_with_state(State0, GenStreamCipherList),
+ {State1, T} = crypto:stream_encrypt(State0, GenStreamCipherList),
{T, CipherState#cipher_state{state = State1}};
cipher(?DES, CipherState, Mac, Fragment, Version) ->
block_cipher(fun(Key, IV, T) ->
- crypto:des_cbc_encrypt(Key, IV, T)
+ crypto:block_encrypt(des_cbc, Key, IV, T)
end, block_size(des_cbc), CipherState, Mac, Fragment, Version);
cipher(?'3DES', CipherState, Mac, Fragment, Version) ->
block_cipher(fun(<<K1:8/binary, K2:8/binary, K3:8/binary>>, IV, T) ->
- crypto:des3_cbc_encrypt(K1, K2, K3, IV, T)
+ crypto:block_encrypt(des3_cbc, [K1, K2, K3], IV, T)
end, block_size(des_cbc), CipherState, Mac, Fragment, Version);
cipher(?AES, CipherState, Mac, Fragment, Version) ->
block_cipher(fun(Key, IV, T) when byte_size(Key) =:= 16 ->
- crypto:aes_cbc_128_encrypt(Key, IV, T);
+ crypto:block_encrypt(aes_cbc128, Key, IV, T);
(Key, IV, T) when byte_size(Key) =:= 32 ->
- crypto:aes_cbc_256_encrypt(Key, IV, T)
+ crypto:block_encrypt(aes_cbc256, Key, IV, T)
end, block_size(aes_128_cbc), CipherState, Mac, Fragment, Version).
build_cipher_block(BlockSz, Mac, Fragment) ->
@@ -127,10 +127,10 @@ decipher(?NULL, _HashSz, CipherState, Fragment, _) ->
{Fragment, <<>>, CipherState};
decipher(?RC4, HashSz, CipherState, Fragment, _) ->
State0 = case CipherState#cipher_state.state of
- undefined -> crypto:rc4_set_key(CipherState#cipher_state.key);
+ undefined -> crypto:stream_init(rc4, CipherState#cipher_state.key);
S -> S
end,
- try crypto:rc4_encrypt_with_state(State0, Fragment) of
+ try crypto:stream_decrypt(State0, Fragment) of
{State, Text} ->
GSC = generic_stream_cipher_from_bin(Text, HashSz),
#generic_stream_cipher{content = Content, mac = Mac} = GSC,
@@ -147,17 +147,17 @@ decipher(?RC4, HashSz, CipherState, Fragment, _) ->
decipher(?DES, HashSz, CipherState, Fragment, Version) ->
block_decipher(fun(Key, IV, T) ->
- crypto:des_cbc_decrypt(Key, IV, T)
+ crypto:block_decrypt(des_cbc, Key, IV, T)
end, CipherState, HashSz, Fragment, Version);
decipher(?'3DES', HashSz, CipherState, Fragment, Version) ->
block_decipher(fun(<<K1:8/binary, K2:8/binary, K3:8/binary>>, IV, T) ->
- crypto:des3_cbc_decrypt(K1, K2, K3, IV, T)
+ crypto:block_decrypt(des3_cbc, [K1, K2, K3], IV, T)
end, CipherState, HashSz, Fragment, Version);
decipher(?AES, HashSz, CipherState, Fragment, Version) ->
block_decipher(fun(Key, IV, T) when byte_size(Key) =:= 16 ->
- crypto:aes_cbc_128_decrypt(Key, IV, T);
+ crypto:block_decrypt(aes_cbc128, Key, IV, T);
(Key, IV, T) when byte_size(Key) =:= 32 ->
- crypto:aes_cbc_256_decrypt(Key, IV, T)
+ crypto:block_decrypt(aes_cbc256, Key, IV, T)
end, CipherState, HashSz, Fragment, Version).
block_decipher(Fun, #cipher_state{key=Key, iv=IV} = CipherState0,
@@ -212,10 +212,14 @@ anonymous_suites() ->
?TLS_DH_anon_WITH_AES_128_CBC_SHA,
?TLS_DH_anon_WITH_AES_256_CBC_SHA,
?TLS_DH_anon_WITH_AES_128_CBC_SHA256,
- ?TLS_DH_anon_WITH_AES_256_CBC_SHA256].
+ ?TLS_DH_anon_WITH_AES_256_CBC_SHA256,
+ ?TLS_ECDH_anon_WITH_RC4_128_SHA,
+ ?TLS_ECDH_anon_WITH_3DES_EDE_CBC_SHA,
+ ?TLS_ECDH_anon_WITH_AES_128_CBC_SHA,
+ ?TLS_ECDH_anon_WITH_AES_256_CBC_SHA].
%%--------------------------------------------------------------------
--spec psk_suites(tls_version()) -> [cipher_suite()].
+-spec psk_suites(tls_version() | integer()) -> [cipher_suite()].
%%
%% Description: Returns a list of the PSK cipher suites, only supported
%% if explicitly set by user.
@@ -274,6 +278,11 @@ srp_suites() ->
%% TLS v1.1 suites
suite_definition(?TLS_NULL_WITH_NULL_NULL) ->
{null, null, null, null};
+%% RFC 5746 - Not a real cipher suite used to signal empty "renegotiation_info" extension
+%% to avoid handshake failure from old servers that do not ignore
+%% hello extension data as they should.
+suite_definition(?TLS_EMPTY_RENEGOTIATION_INFO_SCSV) ->
+ {null, null, null, null};
%% suite_definition(?TLS_RSA_WITH_NULL_MD5) ->
%% {rsa, null, md5, default_prf};
%% suite_definition(?TLS_RSA_WITH_NULL_SHA) ->
@@ -423,8 +432,81 @@ suite_definition(?TLS_SRP_SHA_WITH_AES_256_CBC_SHA) ->
suite_definition(?TLS_SRP_SHA_RSA_WITH_AES_256_CBC_SHA) ->
{srp_rsa, aes_256_cbc, sha, default_prf};
suite_definition(?TLS_SRP_SHA_DSS_WITH_AES_256_CBC_SHA) ->
- {srp_dss, aes_256_cbc, sha, default_prf}.
-
+ {srp_dss, aes_256_cbc, sha, default_prf};
+
+%% RFC 4492 EC TLS suites
+suite_definition(?TLS_ECDH_ECDSA_WITH_NULL_SHA) ->
+ {ecdh_ecdsa, null, sha, default_prf};
+suite_definition(?TLS_ECDH_ECDSA_WITH_RC4_128_SHA) ->
+ {ecdh_ecdsa, rc4_128, sha, default_prf};
+suite_definition(?TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA) ->
+ {ecdh_ecdsa, '3des_ede_cbc', sha, default_prf};
+suite_definition(?TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA) ->
+ {ecdh_ecdsa, aes_128_cbc, sha, default_prf};
+suite_definition(?TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA) ->
+ {ecdh_ecdsa, aes_256_cbc, sha, default_prf};
+
+suite_definition(?TLS_ECDHE_ECDSA_WITH_NULL_SHA) ->
+ {ecdhe_ecdsa, null, sha, default_prf};
+suite_definition(?TLS_ECDHE_ECDSA_WITH_RC4_128_SHA) ->
+ {ecdhe_ecdsa, rc4_128, sha, default_prf};
+suite_definition(?TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA) ->
+ {ecdhe_ecdsa, '3des_ede_cbc', sha, default_prf};
+suite_definition(?TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA) ->
+ {ecdhe_ecdsa, aes_128_cbc, sha, default_prf};
+suite_definition(?TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA) ->
+ {ecdhe_ecdsa, aes_256_cbc, sha, default_prf};
+
+suite_definition(?TLS_ECDH_RSA_WITH_NULL_SHA) ->
+ {ecdh_rsa, null, sha, default_prf};
+suite_definition(?TLS_ECDH_RSA_WITH_RC4_128_SHA) ->
+ {ecdh_rsa, rc4_128, sha, default_prf};
+suite_definition(?TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA) ->
+ {ecdh_rsa, '3des_ede_cbc', sha, default_prf};
+suite_definition(?TLS_ECDH_RSA_WITH_AES_128_CBC_SHA) ->
+ {ecdh_rsa, aes_128_cbc, sha, default_prf};
+suite_definition(?TLS_ECDH_RSA_WITH_AES_256_CBC_SHA) ->
+ {ecdh_rsa, aes_256_cbc, sha, default_prf};
+
+suite_definition(?TLS_ECDHE_RSA_WITH_NULL_SHA) ->
+ {ecdhe_rsa, null, sha, default_prf};
+suite_definition(?TLS_ECDHE_RSA_WITH_RC4_128_SHA) ->
+ {ecdhe_rsa, rc4_128, sha, default_prf};
+suite_definition(?TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA) ->
+ {ecdhe_rsa, '3des_ede_cbc', sha, default_prf};
+suite_definition(?TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA) ->
+ {ecdhe_rsa, aes_128_cbc, sha, default_prf};
+suite_definition(?TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA) ->
+ {ecdhe_rsa, aes_256_cbc, sha, default_prf};
+
+suite_definition(?TLS_ECDH_anon_WITH_NULL_SHA) ->
+ {ecdh_anon, null, sha, default_prf};
+suite_definition(?TLS_ECDH_anon_WITH_RC4_128_SHA) ->
+ {ecdh_anon, rc4_128, sha, default_prf};
+suite_definition(?TLS_ECDH_anon_WITH_3DES_EDE_CBC_SHA) ->
+ {ecdh_anon, '3des_ede_cbc', sha, default_prf};
+suite_definition(?TLS_ECDH_anon_WITH_AES_128_CBC_SHA) ->
+ {ecdh_anon, aes_128_cbc, sha, default_prf};
+suite_definition(?TLS_ECDH_anon_WITH_AES_256_CBC_SHA) ->
+ {ecdh_anon, aes_256_cbc, sha, default_prf};
+
+%% RFC 5289 EC TLS suites
+suite_definition(?TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256) ->
+ {ecdhe_ecdsa, aes_128_cbc, sha256, sha256};
+suite_definition(?TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384) ->
+ {ecdhe_ecdsa, aes_256_cbc, sha384, sha384};
+suite_definition(?TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA256) ->
+ {ecdh_ecdsa, aes_128_cbc, sha256, sha256};
+suite_definition(?TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA384) ->
+ {ecdh_ecdsa, aes_256_cbc, sha384, sha384};
+suite_definition(?TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256) ->
+ {ecdhe_rsa, aes_128_cbc, sha256, sha256};
+suite_definition(?TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384) ->
+ {ecdhe_rsa, aes_256_cbc, sha384, sha384};
+suite_definition(?TLS_ECDH_RSA_WITH_AES_128_CBC_SHA256) ->
+ {ecdh_rsa, aes_128_cbc, sha256, sha256};
+suite_definition(?TLS_ECDH_RSA_WITH_AES_256_CBC_SHA384) ->
+ {ecdh_rsa, aes_256_cbc, sha384, sha384}.
%%--------------------------------------------------------------------
-spec suite(erl_cipher_suite()) -> cipher_suite().
@@ -573,7 +655,81 @@ suite({srp_anon, aes_256_cbc, sha}) ->
suite({srp_rsa, aes_256_cbc, sha}) ->
?TLS_SRP_SHA_RSA_WITH_AES_256_CBC_SHA;
suite({srp_dss, aes_256_cbc, sha}) ->
- ?TLS_SRP_SHA_DSS_WITH_AES_256_CBC_SHA.
+ ?TLS_SRP_SHA_DSS_WITH_AES_256_CBC_SHA;
+
+%%% RFC 4492 EC TLS suites
+suite({ecdh_ecdsa, null, sha}) ->
+ ?TLS_ECDH_ECDSA_WITH_NULL_SHA;
+suite({ecdh_ecdsa, rc4_128, sha}) ->
+ ?TLS_ECDH_ECDSA_WITH_RC4_128_SHA;
+suite({ecdh_ecdsa, '3des_ede_cbc', sha}) ->
+ ?TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA;
+suite({ecdh_ecdsa, aes_128_cbc, sha}) ->
+ ?TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA;
+suite({ecdh_ecdsa, aes_256_cbc, sha}) ->
+ ?TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA;
+
+suite({ecdhe_ecdsa, null, sha}) ->
+ ?TLS_ECDHE_ECDSA_WITH_NULL_SHA;
+suite({ecdhe_ecdsa, rc4_128, sha}) ->
+ ?TLS_ECDHE_ECDSA_WITH_RC4_128_SHA;
+suite({ecdhe_ecdsa, '3des_ede_cbc', sha}) ->
+ ?TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA;
+suite({ecdhe_ecdsa, aes_128_cbc, sha}) ->
+ ?TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA;
+suite({ecdhe_ecdsa, aes_256_cbc, sha}) ->
+ ?TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA;
+
+suite({ecdh_rsa, null, sha}) ->
+ ?TLS_ECDH_RSA_WITH_NULL_SHA;
+suite({ecdh_rsa, rc4_128, sha}) ->
+ ?TLS_ECDH_RSA_WITH_RC4_128_SHA;
+suite({ecdh_rsa, '3des_ede_cbc', sha}) ->
+ ?TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA;
+suite({ecdh_rsa, aes_128_cbc, sha}) ->
+ ?TLS_ECDH_RSA_WITH_AES_128_CBC_SHA;
+suite({ecdh_rsa, aes_256_cbc, sha}) ->
+ ?TLS_ECDH_RSA_WITH_AES_256_CBC_SHA;
+
+suite({ecdhe_rsa, null, sha}) ->
+ ?TLS_ECDHE_RSA_WITH_NULL_SHA;
+suite({ecdhe_rsa, rc4_128, sha}) ->
+ ?TLS_ECDHE_RSA_WITH_RC4_128_SHA;
+suite({ecdhe_rsa, '3des_ede_cbc', sha}) ->
+ ?TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA;
+suite({ecdhe_rsa, aes_128_cbc, sha}) ->
+ ?TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA;
+suite({ecdhe_rsa, aes_256_cbc, sha}) ->
+ ?TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA;
+
+suite({ecdh_anon, null, sha}) ->
+ ?TLS_ECDH_anon_WITH_NULL_SHA;
+suite({ecdh_anon, rc4_128, sha}) ->
+ ?TLS_ECDH_anon_WITH_RC4_128_SHA;
+suite({ecdh_anon, '3des_ede_cbc', sha}) ->
+ ?TLS_ECDH_anon_WITH_3DES_EDE_CBC_SHA;
+suite({ecdh_anon, aes_128_cbc, sha}) ->
+ ?TLS_ECDH_anon_WITH_AES_128_CBC_SHA;
+suite({ecdh_anon, aes_256_cbc, sha}) ->
+ ?TLS_ECDH_anon_WITH_AES_256_CBC_SHA;
+
+%%% RFC 5289 EC TLS suites
+suite({ecdhe_ecdsa, aes_128_cbc, sha256}) ->
+ ?TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256;
+suite({ecdhe_ecdsa, aes_256_cbc, sha384}) ->
+ ?TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384;
+suite({ecdh_ecdsa, aes_128_cbc, sha256}) ->
+ ?TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA256;
+suite({ecdh_ecdsa, aes_256_cbc, sha384}) ->
+ ?TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA384;
+suite({ecdhe_rsa, aes_128_cbc, sha256}) ->
+ ?TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256;
+suite({ecdhe_rsa, aes_256_cbc, sha384}) ->
+ ?TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384;
+suite({ecdh_rsa, aes_128_cbc, sha256}) ->
+ ?TLS_ECDH_RSA_WITH_AES_128_CBC_SHA256;
+suite({ecdh_rsa, aes_256_cbc, sha384}) ->
+ ?TLS_ECDH_RSA_WITH_AES_256_CBC_SHA384.
%%--------------------------------------------------------------------
-spec openssl_suite(openssl_cipher_suite()) -> cipher_suite().
@@ -633,8 +789,62 @@ openssl_suite("SRP-RSA-3DES-EDE-CBC-SHA") ->
openssl_suite("SRP-DSS-AES-128-CBC-SHA") ->
?TLS_SRP_SHA_DSS_WITH_AES_128_CBC_SHA;
openssl_suite("SRP-RSA-AES-128-CBC-SHA") ->
- ?TLS_SRP_SHA_RSA_WITH_AES_128_CBC_SHA.
+ ?TLS_SRP_SHA_RSA_WITH_AES_128_CBC_SHA;
+%% RFC 4492 EC TLS suites
+openssl_suite("ECDH-ECDSA-RC4-SHA") ->
+ ?TLS_ECDH_ECDSA_WITH_RC4_128_SHA;
+openssl_suite("ECDH-ECDSA-DES-CBC3-SHA") ->
+ ?TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA;
+openssl_suite("ECDH-ECDSA-AES128-SHA") ->
+ ?TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA;
+openssl_suite("ECDH-ECDSA-AES256-SHA") ->
+ ?TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA;
+
+openssl_suite("ECDHE-ECDSA-RC4-SHA") ->
+ ?TLS_ECDHE_ECDSA_WITH_RC4_128_SHA;
+openssl_suite("ECDHE-ECDSA-DES-CBC3-SHA") ->
+ ?TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA;
+openssl_suite("ECDHE-ECDSA-AES128-SHA") ->
+ ?TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA;
+openssl_suite("ECDHE-ECDSA-AES256-SHA") ->
+ ?TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA;
+
+openssl_suite("ECDHE-RSA-RC4-SHA") ->
+ ?TLS_ECDHE_RSA_WITH_RC4_128_SHA;
+openssl_suite("ECDHE-RSA-DES-CBC3-SHA") ->
+ ?TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA;
+openssl_suite("ECDHE-RSA-AES128-SHA") ->
+ ?TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA;
+openssl_suite("ECDHE-RSA-AES256-SHA") ->
+ ?TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA;
+
+openssl_suite("ECDH-RSA-RC4-SHA") ->
+ ?TLS_ECDH_RSA_WITH_RC4_128_SHA;
+openssl_suite("ECDH-RSA-DES-CBC3-SHA") ->
+ ?TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA;
+openssl_suite("ECDH-RSA-AES128-SHA") ->
+ ?TLS_ECDH_RSA_WITH_AES_128_CBC_SHA;
+openssl_suite("ECDH-RSA-AES256-SHA") ->
+ ?TLS_ECDH_RSA_WITH_AES_256_CBC_SHA;
+
+%% RFC 5289 EC TLS suites
+openssl_suite("ECDHE-ECDSA-AES128-SHA256") ->
+ ?TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256;
+openssl_suite("ECDHE-ECDSA-AES256-SHA384") ->
+ ?TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384;
+openssl_suite("ECDH-ECDSA-AES128-SHA256") ->
+ ?TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA256;
+openssl_suite("ECDH-ECDSA-AES256-SHA384") ->
+ ?TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA384;
+openssl_suite("ECDHE-RSA-AES128-SHA256") ->
+ ?TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256;
+openssl_suite("ECDHE-RSA-AES256-SHA384") ->
+ ?TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384;
+openssl_suite("ECDH-RSA-AES128-SHA256") ->
+ ?TLS_ECDH_RSA_WITH_AES_128_CBC_SHA256;
+openssl_suite("ECDH-RSA-AES256-SHA384") ->
+ ?TLS_ECDH_RSA_WITH_AES_256_CBC_SHA384.
%%--------------------------------------------------------------------
-spec openssl_suite_name(cipher_suite()) -> openssl_cipher_suite().
@@ -716,6 +926,61 @@ openssl_suite_name(?TLS_SRP_SHA_RSA_WITH_AES_256_CBC_SHA) ->
openssl_suite_name(?TLS_SRP_SHA_DSS_WITH_AES_256_CBC_SHA) ->
"SRP-DSS-AES-256-CBC-SHA";
+%% RFC 4492 EC TLS suites
+openssl_suite_name(?TLS_ECDH_ECDSA_WITH_RC4_128_SHA) ->
+ "ECDH-ECDSA-RC4-SHA";
+openssl_suite_name(?TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA) ->
+ "ECDH-ECDSA-DES-CBC3-SHA";
+openssl_suite_name(?TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA) ->
+ "ECDH-ECDSA-AES128-SHA";
+openssl_suite_name(?TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA) ->
+ "ECDH-ECDSA-AES256-SHA";
+
+openssl_suite_name(?TLS_ECDHE_ECDSA_WITH_RC4_128_SHA) ->
+ "ECDHE-ECDSA-RC4-SHA";
+openssl_suite_name(?TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA) ->
+ "ECDHE-ECDSA-DES-CBC3-SHA";
+openssl_suite_name(?TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA) ->
+ "ECDHE-ECDSA-AES128-SHA";
+openssl_suite_name(?TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA) ->
+ "ECDHE-ECDSA-AES256-SHA";
+
+openssl_suite_name(?TLS_ECDH_RSA_WITH_RC4_128_SHA) ->
+ "ECDH-RSA-RC4-SHA";
+openssl_suite_name(?TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA) ->
+ "ECDH-RSA-DES-CBC3-SHA";
+openssl_suite_name(?TLS_ECDH_RSA_WITH_AES_128_CBC_SHA) ->
+ "ECDH-RSA-AES128-SHA";
+openssl_suite_name(?TLS_ECDH_RSA_WITH_AES_256_CBC_SHA) ->
+ "ECDH-RSA-AES256-SHA";
+
+openssl_suite_name(?TLS_ECDHE_RSA_WITH_RC4_128_SHA) ->
+ "ECDHE-RSA-RC4-SHA";
+openssl_suite_name(?TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA) ->
+ "ECDHE-RSA-DES-CBC3-SHA";
+openssl_suite_name(?TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA) ->
+ "ECDHE-RSA-AES128-SHA";
+openssl_suite_name(?TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA) ->
+ "ECDHE-RSA-AES256-SHA";
+
+%% RFC 5289 EC TLS suites
+openssl_suite_name(?TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256) ->
+ "ECDHE-ECDSA-AES128-SHA256";
+openssl_suite_name(?TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384) ->
+ "ECDHE-ECDSA-AES256-SHA384";
+openssl_suite_name(?TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA256) ->
+ "ECDH-ECDSA-AES128-SHA256";
+openssl_suite_name(?TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA384) ->
+ "ECDH-ECDSA-AES256-SHA384";
+openssl_suite_name(?TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256) ->
+ "ECDHE-RSA-AES128-SHA256";
+openssl_suite_name(?TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384) ->
+ "ECDHE-RSA-AES256-SHA384";
+openssl_suite_name(?TLS_ECDH_RSA_WITH_AES_128_CBC_SHA256) ->
+ "ECDH-RSA-AES128-SHA256";
+openssl_suite_name(?TLS_ECDH_RSA_WITH_AES_256_CBC_SHA384) ->
+ "ECDH-RSA-AES256-SHA384";
+
%% No oppenssl name
openssl_suite_name(Cipher) ->
suite_definition(Cipher).
@@ -730,14 +995,85 @@ filter(undefined, Ciphers) ->
filter(DerCert, Ciphers) ->
OtpCert = public_key:pkix_decode_cert(DerCert, otp),
SigAlg = OtpCert#'OTPCertificate'.signatureAlgorithm,
+ PubKeyInfo = OtpCert#'OTPCertificate'.tbsCertificate#'OTPTBSCertificate'.subjectPublicKeyInfo,
+ PubKeyAlg = PubKeyInfo#'OTPSubjectPublicKeyInfo'.algorithm,
+
+ Ciphers1 =
+ case ssl_certificate:public_key_type(PubKeyAlg#'PublicKeyAlgorithm'.algorithm) of
+ rsa ->
+ filter_keyuse(OtpCert, ((Ciphers -- dsa_signed_suites()) -- ec_keyed_suites()) -- ecdh_suites(),
+ rsa_suites(), dhe_rsa_suites() ++ ecdhe_rsa_suites());
+ dsa ->
+ (Ciphers -- rsa_keyed_suites()) -- ec_keyed_suites();
+ ec ->
+ filter_keyuse(OtpCert, (Ciphers -- rsa_keyed_suites()) -- dsa_signed_suites(),
+ [], ecdhe_ecdsa_suites())
+ end,
case public_key:pkix_sign_types(SigAlg#'SignatureAlgorithm'.algorithm) of
{_, rsa} ->
- filter_rsa(OtpCert, Ciphers -- dsa_signed_suites());
+ Ciphers1 -- ecdsa_signed_suites();
{_, dsa} ->
- Ciphers -- rsa_signed_suites()
+ Ciphers1;
+ {_, ecdsa} ->
+ Ciphers1 -- rsa_signed_suites()
end.
%%--------------------------------------------------------------------
+-spec filter_suites([cipher_suite()]) -> [cipher_suite()].
+%%
+%% Description: filter suites for algorithms
+%%-------------------------------------------------------------------
+filter_suites(Suites = [{_,_,_}|_]) ->
+ Algos = crypto:algorithms(),
+ lists:filter(fun({KeyExchange, Cipher, Hash}) ->
+ is_acceptable_keyexchange(KeyExchange, Algos) andalso
+ is_acceptable_cipher(Cipher, Algos) andalso
+ is_acceptable_hash(Hash, Algos)
+ end, Suites);
+
+filter_suites(Suites = [{_,_,_,_}|_]) ->
+ Algos = crypto:algorithms(),
+ lists:filter(fun({KeyExchange, Cipher, Hash, Prf}) ->
+ is_acceptable_keyexchange(KeyExchange, Algos) andalso
+ is_acceptable_cipher(Cipher, Algos) andalso
+ is_acceptable_hash(Hash, Algos) andalso
+ is_acceptable_prf(Prf, Algos)
+ end, Suites);
+
+filter_suites(Suites) ->
+ Algos = crypto:algorithms(),
+ lists:filter(fun(Suite) ->
+ {KeyExchange, Cipher, Hash, Prf} = ssl_cipher:suite_definition(Suite),
+ is_acceptable_keyexchange(KeyExchange, Algos) andalso
+ is_acceptable_cipher(Cipher, Algos) andalso
+ is_acceptable_hash(Hash, Algos) andalso
+ is_acceptable_prf(Prf, Algos)
+ end, Suites).
+
+is_acceptable_keyexchange(KeyExchange, Algos)
+ when KeyExchange == ecdh_ecdsa;
+ KeyExchange == ecdhe_ecdsa;
+ KeyExchange == ecdh_rsa;
+ KeyExchange == ecdhe_rsa;
+ KeyExchange == ecdh_anon ->
+ proplists:get_bool(ec, Algos);
+is_acceptable_keyexchange(_, _) ->
+ true.
+
+is_acceptable_cipher(_, _) ->
+ true.
+
+is_acceptable_hash(null, _Algos) ->
+ true;
+is_acceptable_hash(Hash, Algos) ->
+ proplists:get_bool(Hash, Algos).
+
+is_acceptable_prf(default_prf, _) ->
+ true;
+is_acceptable_prf(Prf, Algos) ->
+ proplists:get_bool(Prf, Algos).
+
+%%--------------------------------------------------------------------
%%% Internal functions
%%--------------------------------------------------------------------
@@ -950,7 +1286,13 @@ next_iv(Bin, IV) ->
rsa_signed_suites() ->
dhe_rsa_suites() ++ rsa_suites() ++
- psk_rsa_suites() ++ srp_rsa_suites().
+ psk_rsa_suites() ++ srp_rsa_suites() ++
+ ecdh_rsa_suites().
+
+rsa_keyed_suites() ->
+ dhe_rsa_suites() ++ rsa_suites() ++
+ psk_rsa_suites() ++ srp_rsa_suites() ++
+ ecdhe_rsa_suites().
dhe_rsa_suites() ->
[?TLS_DHE_RSA_WITH_AES_256_CBC_SHA256,
@@ -982,7 +1324,25 @@ rsa_suites() ->
?TLS_RSA_WITH_RC4_128_SHA,
?TLS_RSA_WITH_RC4_128_MD5,
?TLS_RSA_WITH_DES_CBC_SHA].
-
+
+ecdh_rsa_suites() ->
+ [?TLS_ECDH_RSA_WITH_NULL_SHA,
+ ?TLS_ECDH_RSA_WITH_RC4_128_SHA,
+ ?TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA,
+ ?TLS_ECDH_RSA_WITH_AES_128_CBC_SHA,
+ ?TLS_ECDH_RSA_WITH_AES_256_CBC_SHA,
+ ?TLS_ECDH_RSA_WITH_AES_128_CBC_SHA256,
+ ?TLS_ECDH_RSA_WITH_AES_256_CBC_SHA384].
+
+ecdhe_rsa_suites() ->
+ [?TLS_ECDHE_RSA_WITH_NULL_SHA,
+ ?TLS_ECDHE_RSA_WITH_RC4_128_SHA,
+ ?TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA,
+ ?TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA,
+ ?TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA,
+ ?TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256,
+ ?TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384].
+
dsa_signed_suites() ->
dhe_dss_suites() ++ srp_dss_suites().
@@ -999,24 +1359,52 @@ srp_dss_suites() ->
?TLS_SRP_SHA_DSS_WITH_AES_128_CBC_SHA,
?TLS_SRP_SHA_DSS_WITH_AES_256_CBC_SHA].
-filter_rsa(OtpCert, RsaCiphers) ->
+ec_keyed_suites() ->
+ ecdh_ecdsa_suites() ++ ecdhe_ecdsa_suites()
+ ++ ecdh_rsa_suites().
+
+ecdsa_signed_suites() ->
+ ecdh_ecdsa_suites() ++ ecdhe_ecdsa_suites().
+
+ecdh_suites() ->
+ ecdh_rsa_suites() ++ ecdh_ecdsa_suites().
+
+ecdh_ecdsa_suites() ->
+ [?TLS_ECDH_ECDSA_WITH_NULL_SHA,
+ ?TLS_ECDH_ECDSA_WITH_RC4_128_SHA,
+ ?TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA,
+ ?TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA,
+ ?TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA,
+ ?TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA256,
+ ?TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA384].
+
+ecdhe_ecdsa_suites() ->
+ [?TLS_ECDHE_ECDSA_WITH_NULL_SHA,
+ ?TLS_ECDHE_ECDSA_WITH_RC4_128_SHA,
+ ?TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA,
+ ?TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA,
+ ?TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA,
+ ?TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256,
+ ?TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384].
+
+filter_keyuse(OtpCert, Ciphers, Suites, SignSuites) ->
TBSCert = OtpCert#'OTPCertificate'.tbsCertificate,
TBSExtensions = TBSCert#'OTPTBSCertificate'.extensions,
Extensions = ssl_certificate:extensions_list(TBSExtensions),
case ssl_certificate:select_extension(?'id-ce-keyUsage', Extensions) of
undefined ->
- RsaCiphers;
+ Ciphers;
#'Extension'{extnValue = KeyUse} ->
- Result = filter_rsa_suites(keyEncipherment,
- KeyUse, RsaCiphers, rsa_suites()),
- filter_rsa_suites(digitalSignature,
- KeyUse, Result, dhe_rsa_suites())
+ Result = filter_keyuse_suites(keyEncipherment,
+ KeyUse, Ciphers, Suites),
+ filter_keyuse_suites(digitalSignature,
+ KeyUse, Result, SignSuites)
end.
-filter_rsa_suites(Use, KeyUse, CipherSuits, RsaSuites) ->
+filter_keyuse_suites(Use, KeyUse, CipherSuits, Suites) ->
case ssl_certificate:is_valid_key_usage(KeyUse, Use) of
true ->
CipherSuits;
false ->
- CipherSuits -- RsaSuites
+ CipherSuits -- Suites
end.
diff --git a/lib/ssl/src/ssl_cipher.hrl b/lib/ssl/src/ssl_cipher.hrl
index 90d3704efd..c7c71ee1a7 100644
--- a/lib/ssl/src/ssl_cipher.hrl
+++ b/lib/ssl/src/ssl_cipher.hrl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2007-2012. All Rights Reserved.
+%% Copyright Ericsson AB 2007-2013. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -28,9 +28,9 @@
-type cipher() :: null |rc4_128 | idea_cbc | des40_cbc | des_cbc | '3des_ede_cbc'
| aes_128_cbc | aes_256_cbc.
--type hash() :: null | sha | md5 | sha256 | sha384 | sha512.
+-type hash() :: null | sha | md5 | ssh224 | sha256 | sha384 | sha512.
-type erl_cipher_suite() :: {key_algo(), cipher(), hash()}.
--type int_cipher_suite() :: {key_algo(), cipher(), hash(), hash()}.
+-type int_cipher_suite() :: {key_algo(), cipher(), hash(), hash() | default_prf}.
-type cipher_suite() :: binary().
-type cipher_enum() :: integer().
-type openssl_cipher_suite() :: string().
@@ -219,6 +219,120 @@
%% TLS_DH_anon_WITH_AES_256_CBC_SHA256 = { 0x00,0x6D };
-define(TLS_DH_anon_WITH_AES_256_CBC_SHA256, <<?BYTE(16#00), ?BYTE(16#6D)>>).
+%% RFC 4492 EC TLS suites
+
+%% ECDH_ECDSA
+
+%% TLS_ECDH_ECDSA_WITH_NULL_SHA = { 0xC0, 0x01 }
+-define(TLS_ECDH_ECDSA_WITH_NULL_SHA, <<?BYTE(16#C0), ?BYTE(16#01)>>).
+
+%% TLS_ECDH_ECDSA_WITH_RC4_128_SHA = { 0xC0, 0x02 }
+-define(TLS_ECDH_ECDSA_WITH_RC4_128_SHA, <<?BYTE(16#C0), ?BYTE(16#02)>>).
+
+%% TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA = { 0xC0, 0x03 }
+-define(TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA, <<?BYTE(16#C0), ?BYTE(16#03)>>).
+
+%% TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA = { 0xC0, 0x04 }
+-define(TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA, <<?BYTE(16#C0), ?BYTE(16#04)>>).
+
+%% TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA = { 0xC0, 0x05 }
+-define(TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA, <<?BYTE(16#C0), ?BYTE(16#05)>>).
+
+%% ECDHE_ECDSA
+
+%% TLS_ECDHE_ECDSA_WITH_NULL_SHA = { 0xC0, 0x06 }
+-define(TLS_ECDHE_ECDSA_WITH_NULL_SHA, <<?BYTE(16#C0), ?BYTE(16#06)>>).
+
+%% TLS_ECDHE_ECDSA_WITH_RC4_128_SHA = { 0xC0, 0x07 }
+-define(TLS_ECDHE_ECDSA_WITH_RC4_128_SHA, <<?BYTE(16#C0), ?BYTE(16#07)>>).
+
+%% TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA = { 0xC0, 0x08 }
+-define(TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA, <<?BYTE(16#C0), ?BYTE(16#08)>>).
+
+%% TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA = { 0xC0, 0x09 }
+-define(TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA, <<?BYTE(16#C0), ?BYTE(16#09)>>).
+
+%% TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA = { 0xC0, 0x0A }
+-define(TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA, <<?BYTE(16#C0), ?BYTE(16#0A)>>).
+
+%% ECDH_RSA
+
+%% TLS_ECDH_RSA_WITH_NULL_SHA = { 0xC0, 0x0B }
+-define(TLS_ECDH_RSA_WITH_NULL_SHA, <<?BYTE(16#C0), ?BYTE(16#0B)>>).
+
+%% TLS_ECDH_RSA_WITH_RC4_128_SHA = { 0xC0, 0x0C }
+-define(TLS_ECDH_RSA_WITH_RC4_128_SHA, <<?BYTE(16#C0), ?BYTE(16#0C)>>).
+
+%% TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA = { 0xC0, 0x0D }
+-define(TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA, <<?BYTE(16#C0), ?BYTE(16#0D)>>).
+
+%% TLS_ECDH_RSA_WITH_AES_128_CBC_SHA = { 0xC0, 0x0E }
+-define(TLS_ECDH_RSA_WITH_AES_128_CBC_SHA, <<?BYTE(16#C0), ?BYTE(16#0E)>>).
+
+%% TLS_ECDH_RSA_WITH_AES_256_CBC_SHA = { 0xC0, 0x0F }
+-define(TLS_ECDH_RSA_WITH_AES_256_CBC_SHA, <<?BYTE(16#C0), ?BYTE(16#0F)>>).
+
+%% ECDHE_RSA
+
+%% TLS_ECDHE_RSA_WITH_NULL_SHA = { 0xC0, 0x10 }
+-define(TLS_ECDHE_RSA_WITH_NULL_SHA, <<?BYTE(16#C0), ?BYTE(16#10)>>).
+
+%% TLS_ECDHE_RSA_WITH_RC4_128_SHA = { 0xC0, 0x11 }
+-define(TLS_ECDHE_RSA_WITH_RC4_128_SHA, <<?BYTE(16#C0), ?BYTE(16#11)>>).
+
+%% TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA = { 0xC0, 0x12 }
+-define(TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA, <<?BYTE(16#C0), ?BYTE(16#12)>>).
+
+%% TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA = { 0xC0, 0x13 }
+-define(TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA, <<?BYTE(16#C0), ?BYTE(16#13)>>).
+
+%% TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA = { 0xC0, 0x14 }
+-define(TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA, <<?BYTE(16#C0), ?BYTE(16#14)>>).
+
+%% ECDH_anon
+
+%% TLS_ECDH_anon_WITH_NULL_SHA = { 0xC0, 0x15 }
+-define(TLS_ECDH_anon_WITH_NULL_SHA, <<?BYTE(16#C0), ?BYTE(16#15)>>).
+
+%% TLS_ECDH_anon_WITH_RC4_128_SHA = { 0xC0, 0x16 }
+-define(TLS_ECDH_anon_WITH_RC4_128_SHA, <<?BYTE(16#C0), ?BYTE(16#16)>>).
+
+%% TLS_ECDH_anon_WITH_3DES_EDE_CBC_SHA = { 0xC0, 0x17 }
+-define(TLS_ECDH_anon_WITH_3DES_EDE_CBC_SHA, <<?BYTE(16#C0), ?BYTE(16#17)>>).
+
+%% TLS_ECDH_anon_WITH_AES_128_CBC_SHA = { 0xC0, 0x18 }
+-define(TLS_ECDH_anon_WITH_AES_128_CBC_SHA, <<?BYTE(16#C0), ?BYTE(16#18)>>).
+
+%% TLS_ECDH_anon_WITH_AES_256_CBC_SHA = { 0xC0, 0x19 }
+-define(TLS_ECDH_anon_WITH_AES_256_CBC_SHA, <<?BYTE(16#C0), ?BYTE(16#19)>>).
+
+
+%% RFC 5289 EC TLS suites
+
+%% TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256 = {0xC0,0x23};
+-define(TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256, <<?BYTE(16#C0), ?BYTE(16#23)>>).
+
+%% TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384 = {0xC0,0x24};
+-define(TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384, <<?BYTE(16#C0), ?BYTE(16#24)>>).
+
+%% TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA256 = {0xC0,0x25};
+-define(TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA256, <<?BYTE(16#C0), ?BYTE(16#25)>>).
+
+%% TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA384 = {0xC0,0x26};
+-define(TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA384, <<?BYTE(16#C0), ?BYTE(16#26)>>).
+
+%% TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256 = {0xC0,0x27};
+-define(TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256, <<?BYTE(16#C0), ?BYTE(16#27)>>).
+
+%% TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384 = {0xC0,0x28};
+-define(TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384, <<?BYTE(16#C0), ?BYTE(16#28)>>).
+
+%% TLS_ECDH_RSA_WITH_AES_128_CBC_SHA256 = {0xC0,0x29};
+-define(TLS_ECDH_RSA_WITH_AES_128_CBC_SHA256, <<?BYTE(16#C0), ?BYTE(16#29)>>).
+
+%% TLS_ECDH_RSA_WITH_AES_256_CBC_SHA384 = {0xC0,0x2A};
+-define(TLS_ECDH_RSA_WITH_AES_256_CBC_SHA384, <<?BYTE(16#C0), ?BYTE(16#2A)>>).
+
%%% Kerberos Cipher Suites
%% TLS_KRB5_WITH_DES_CBC_SHA = { 0x00,0x1E };
diff --git a/lib/ssl/src/ssl_connection.erl b/lib/ssl/src/ssl_connection.erl
index 1843377582..54eed03d3c 100644
--- a/lib/ssl/src/ssl_connection.erl
+++ b/lib/ssl/src/ssl_connection.erl
@@ -98,7 +98,8 @@
terminated = false, %
allow_renegotiate = true,
expecting_next_protocol_negotiation = false :: boolean(),
- next_protocol = undefined :: undefined | binary()
+ next_protocol = undefined :: undefined | binary(),
+ client_ecc % {Curves, PointFmt}
}).
-define(DEFAULT_DIFFIE_HELLMAN_PARAMS,
@@ -416,11 +417,14 @@ hello(Hello = #client_hello{client_version = ClientVersion},
ssl_options = SslOpts}) ->
case ssl_handshake:hello(Hello, SslOpts, {Port, Session0, Cache, CacheCb,
ConnectionStates0, Cert}, Renegotiation) of
- {Version, {Type, Session}, ConnectionStates, ProtocolsToAdvertise} ->
- do_server_hello(Type, ProtocolsToAdvertise, State#state{connection_states =
- ConnectionStates,
- negotiated_version = Version,
- session = Session});
+ {Version, {Type, Session}, ConnectionStates, ProtocolsToAdvertise,
+ EcPointFormats, EllipticCurves} ->
+ do_server_hello(Type, ProtocolsToAdvertise,
+ EcPointFormats, EllipticCurves,
+ State#state{connection_states = ConnectionStates,
+ negotiated_version = Version,
+ session = Session,
+ client_ecc = {EllipticCurves, EcPointFormats}});
#alert{} = Alert ->
handle_own_alert(Alert, ClientVersion, hello, State)
end;
@@ -533,7 +537,9 @@ certify(#certificate{} = Cert,
certify(#server_key_exchange{} = KeyExchangeMsg,
#state{role = client, negotiated_version = Version,
key_algorithm = Alg} = State0)
- when Alg == dhe_dss; Alg == dhe_rsa; Alg == dh_anon;
+ when Alg == dhe_dss; Alg == dhe_rsa;
+ Alg == ecdhe_rsa; Alg == ecdhe_ecdsa;
+ Alg == dh_anon; Alg == ecdh_anon;
Alg == psk; Alg == dhe_psk; Alg == rsa_psk;
Alg == srp_dss; Alg == srp_rsa; Alg == srp_anon ->
case handle_server_key(KeyExchangeMsg, State0) of
@@ -669,9 +675,20 @@ certify_client_key_exchange(#encrypted_premaster_secret{premaster_secret= EncPMS
certify_client_key_exchange(#client_diffie_hellman_public{dh_public = ClientPublicDhKey},
#state{negotiated_version = Version,
diffie_hellman_params = #'DHParameter'{prime = P,
- base = G},
+ base = G} = Params,
diffie_hellman_keys = {_, ServerDhPrivateKey}} = State0) ->
- case dh_master_secret(crypto:mpint(P), crypto:mpint(G), ClientPublicDhKey, ServerDhPrivateKey, State0) of
+ case dh_master_secret(Params, ClientPublicDhKey, ServerDhPrivateKey, State0) of
+ #state{} = State1 ->
+ {Record, State} = next_record(State1),
+ next_state(certify, cipher, Record, State);
+ #alert{} = Alert ->
+ handle_own_alert(Alert, Version, certify, State0)
+ end;
+
+certify_client_key_exchange(#client_ec_diffie_hellman_public{dh_public = ClientPublicEcDhPoint},
+ #state{negotiated_version = Version,
+ diffie_hellman_keys = ECDHKey} = State0) ->
+ case ec_dh_master_secret(ECDHKey, #'ECPoint'{point = ClientPublicEcDhPoint}, State0) of
#state{} = State1 ->
{Record, State} = next_record(State1),
next_state(certify, cipher, Record, State);
@@ -696,7 +713,7 @@ certify_client_key_exchange(#client_dhe_psk_identity{
diffie_hellman_params = #'DHParameter'{prime = P,
base = G},
diffie_hellman_keys = {_, ServerDhPrivateKey}} = State0) ->
- case dhe_psk_master_secret(ClientPSKIdentity, crypto:mpint(P), crypto:mpint(G), ClientPublicDhKey, ServerDhPrivateKey, State0) of
+ case dhe_psk_master_secret(ClientPSKIdentity, P, G, ClientPublicDhKey, ServerDhPrivateKey, State0) of
#state{} = State1 ->
{Record, State} = next_record(State1),
next_state(certify, cipher, Record, State);
@@ -1278,6 +1295,7 @@ init_private_key(DbHandle, undefined, KeyFile, Password, _) ->
[PemEntry] = [PemEntry || PemEntry = {PKey, _ , _} <- List,
PKey =:= 'RSAPrivateKey' orelse
PKey =:= 'DSAPrivateKey' orelse
+ PKey =:= 'ECPrivateKey' orelse
PKey =:= 'PrivateKeyInfo'
],
private_key(public_key:pem_entry_decode(PemEntry, Password))
@@ -1291,6 +1309,8 @@ init_private_key(_,{rsa, PrivateKey}, _, _,_) ->
init_private_key('RSAPrivateKey', PrivateKey);
init_private_key(_,{dsa, PrivateKey},_,_,_) ->
init_private_key('DSAPrivateKey', PrivateKey);
+init_private_key(_,{ec, PrivateKey},_,_,_) ->
+ init_private_key('ECPrivateKey', PrivateKey);
init_private_key(_,{Asn1Type, PrivateKey},_,_,_) ->
private_key(init_private_key(Asn1Type, PrivateKey)).
@@ -1306,6 +1326,7 @@ private_key(#'PrivateKeyInfo'{privateKeyAlgorithm =
#'PrivateKeyInfo_privateKeyAlgorithm'{algorithm = ?'id-dsa'},
privateKey = Key}) ->
public_key:der_decode('DSAPrivateKey', iolist_to_binary(Key));
+
private_key(Key) ->
Key.
@@ -1357,7 +1378,15 @@ handle_peer_cert(PeerCert, PublicKeyInfo,
State1 = State0#state{session =
Session#session{peer_certificate = PeerCert},
public_key_info = PublicKeyInfo},
- {Record, State} = next_record(State1),
+ State2 = case PublicKeyInfo of
+ {?'id-ecPublicKey', #'ECPoint'{point = _ECPoint} = PublicKey, PublicKeyParams} ->
+ ECDHKey = public_key:generate_key(PublicKeyParams),
+ State3 = State1#state{diffie_hellman_keys = ECDHKey},
+ ec_dh_master_secret(ECDHKey, PublicKey, State3);
+
+ _ -> State1
+ end,
+ {Record, State} = next_record(State2),
next_state(certify, certify, Record, State).
certify_client(#state{client_certificate_requested = true, role = client,
@@ -1407,15 +1436,18 @@ verify_client_cert(#state{client_certificate_requested = true, role = client,
verify_client_cert(#state{client_certificate_requested = false} = State) ->
State.
-do_server_hello(Type, NextProtocolsToSend, #state{negotiated_version = Version,
- session = #session{session_id = SessId},
- connection_states = ConnectionStates0,
- renegotiation = {Renegotiation, _}}
+do_server_hello(Type, NextProtocolsToSend,
+ EcPointFormats, EllipticCurves,
+ #state{negotiated_version = Version,
+ session = #session{session_id = SessId},
+ connection_states = ConnectionStates0,
+ renegotiation = {Renegotiation, _}}
= State0) when is_atom(Type) ->
ServerHello =
ssl_handshake:server_hello(SessId, Version,
- ConnectionStates0, Renegotiation, NextProtocolsToSend),
+ ConnectionStates0, Renegotiation,
+ NextProtocolsToSend, EcPointFormats, EllipticCurves),
State = server_hello(ServerHello,
State0#state{expecting_next_protocol_negotiation =
NextProtocolsToSend =/= undefined}),
@@ -1547,7 +1579,7 @@ server_hello_done(#state{transport_cb = Transport,
tls_handshake_history = Handshake}.
certify_server(#state{key_algorithm = Algo} = State)
- when Algo == dh_anon; Algo == psk; Algo == dhe_psk ->
+ when Algo == dh_anon; Algo == ecdh_anon; Algo == psk; Algo == dhe_psk; Algo == srp_anon ->
State;
certify_server(#state{transport_cb = Transport,
@@ -1574,7 +1606,7 @@ key_exchange(#state{role = server, key_algorithm = rsa} = State) ->
State;
key_exchange(#state{role = server, key_algorithm = Algo,
hashsign_algorithm = HashSignAlgo,
- diffie_hellman_params = #'DHParameter'{prime = P, base = G} = Params,
+ diffie_hellman_params = #'DHParameter'{} = Params,
private_key = PrivateKey,
connection_states = ConnectionStates0,
negotiated_version = Version,
@@ -1585,13 +1617,13 @@ key_exchange(#state{role = server, key_algorithm = Algo,
when Algo == dhe_dss;
Algo == dhe_rsa;
Algo == dh_anon ->
- Keys = crypto:dh_generate_key([crypto:mpint(P), crypto:mpint(G)]),
+ DHKeys = public_key:generate_key(Params),
ConnectionState =
ssl_record:pending_connection_state(ConnectionStates0, read),
SecParams = ConnectionState#connection_state.security_parameters,
#security_parameters{client_random = ClientRandom,
server_random = ServerRandom} = SecParams,
- Msg = ssl_handshake:key_exchange(server, Version, {dh, Keys, Params,
+ Msg = ssl_handshake:key_exchange(server, Version, {dh, DHKeys, Params,
HashSignAlgo, ClientRandom,
ServerRandom,
PrivateKey}),
@@ -1599,9 +1631,41 @@ key_exchange(#state{role = server, key_algorithm = Algo,
encode_handshake(Msg, Version, ConnectionStates0, Handshake0),
Transport:send(Socket, BinMsg),
State#state{connection_states = ConnectionStates,
- diffie_hellman_keys = Keys,
+ diffie_hellman_keys = DHKeys,
tls_handshake_history = Handshake};
+key_exchange(#state{role = server, private_key = Key, key_algorithm = Algo} = State)
+ when Algo == ecdh_ecdsa; Algo == ecdh_rsa ->
+ State#state{diffie_hellman_keys = Key};
+key_exchange(#state{role = server, key_algorithm = Algo,
+ hashsign_algorithm = HashSignAlgo,
+ private_key = PrivateKey,
+ connection_states = ConnectionStates0,
+ negotiated_version = Version,
+ tls_handshake_history = Handshake0,
+ socket = Socket,
+ transport_cb = Transport
+ } = State)
+ when Algo == ecdhe_ecdsa; Algo == ecdhe_rsa;
+ Algo == ecdh_anon ->
+
+ ECDHKeys = public_key:generate_key(select_curve(State)),
+ ConnectionState =
+ ssl_record:pending_connection_state(ConnectionStates0, read),
+ SecParams = ConnectionState#connection_state.security_parameters,
+ #security_parameters{client_random = ClientRandom,
+ server_random = ServerRandom} = SecParams,
+ Msg = ssl_handshake:key_exchange(server, Version, {ecdh, ECDHKeys,
+ HashSignAlgo, ClientRandom,
+ ServerRandom,
+ PrivateKey}),
+ {BinMsg, ConnectionStates, Handshake1} =
+ encode_handshake(Msg, Version, ConnectionStates0, Handshake0),
+ Transport:send(Socket, BinMsg),
+ State#state{connection_states = ConnectionStates,
+ diffie_hellman_keys = ECDHKeys,
+ tls_handshake_history = Handshake1};
+
key_exchange(#state{role = server, key_algorithm = psk,
ssl_options = #ssl_options{psk_identity = undefined}} = State) ->
State;
@@ -1633,7 +1697,7 @@ key_exchange(#state{role = server, key_algorithm = psk,
key_exchange(#state{role = server, key_algorithm = dhe_psk,
ssl_options = #ssl_options{psk_identity = PskIdentityHint},
hashsign_algorithm = HashSignAlgo,
- diffie_hellman_params = #'DHParameter'{prime = P, base = G} = Params,
+ diffie_hellman_params = #'DHParameter'{} = Params,
private_key = PrivateKey,
connection_states = ConnectionStates0,
negotiated_version = Version,
@@ -1641,13 +1705,13 @@ key_exchange(#state{role = server, key_algorithm = dhe_psk,
socket = Socket,
transport_cb = Transport
} = State) ->
- Keys = crypto:dh_generate_key([crypto:mpint(P), crypto:mpint(G)]),
+ DHKeys = public_key:generate_key(Params),
ConnectionState =
ssl_record:pending_connection_state(ConnectionStates0, read),
SecParams = ConnectionState#connection_state.security_parameters,
#security_parameters{client_random = ClientRandom,
server_random = ServerRandom} = SecParams,
- Msg = ssl_handshake:key_exchange(server, Version, {dhe_psk, PskIdentityHint, Keys, Params,
+ Msg = ssl_handshake:key_exchange(server, Version, {dhe_psk, PskIdentityHint, DHKeys, Params,
HashSignAlgo, ClientRandom,
ServerRandom,
PrivateKey}),
@@ -1655,7 +1719,7 @@ key_exchange(#state{role = server, key_algorithm = dhe_psk,
encode_handshake(Msg, Version, ConnectionStates0, Handshake0),
Transport:send(Socket, BinMsg),
State#state{connection_states = ConnectionStates,
- diffie_hellman_keys = Keys,
+ diffie_hellman_keys = DHKeys,
tls_handshake_history = Handshake};
key_exchange(#state{role = server, key_algorithm = rsa_psk,
@@ -1756,6 +1820,23 @@ key_exchange(#state{role = client,
tls_handshake_history = Handshake};
key_exchange(#state{role = client,
+ connection_states = ConnectionStates0,
+ key_algorithm = Algorithm,
+ negotiated_version = Version,
+ diffie_hellman_keys = Keys,
+ socket = Socket, transport_cb = Transport,
+ tls_handshake_history = Handshake0} = State)
+ when Algorithm == ecdhe_ecdsa; Algorithm == ecdhe_rsa;
+ Algorithm == ecdh_ecdsa; Algorithm == ecdh_rsa;
+ Algorithm == ecdh_anon ->
+ Msg = ssl_handshake:key_exchange(client, Version, {ecdh, Keys}),
+ {BinMsg, ConnectionStates, Handshake} =
+ encode_handshake(Msg, Version, ConnectionStates0, Handshake0),
+ Transport:send(Socket, BinMsg),
+ State#state{connection_states = ConnectionStates,
+ tls_handshake_history = Handshake};
+
+key_exchange(#state{role = client,
ssl_options = SslOpts,
connection_states = ConnectionStates0,
key_algorithm = psk,
@@ -1936,7 +2017,7 @@ handle_server_key(#server_key_exchange{exchange_keys = Keys},
Params = ssl_handshake:decode_server_key(Keys, KeyAlg, Version),
HashSign = connection_hashsign(Params#server_key_params.hashsign, State),
case HashSign of
- {_, anon} ->
+ {_, SignAlgo} when SignAlgo == anon; SignAlgo == ecdh_anon ->
server_master_secret(Params#server_key_params.params, State);
_ ->
verify_server_key(Params, HashSign, State)
@@ -1969,6 +2050,11 @@ server_master_secret(#server_dh_params{dh_p = P, dh_g = G, dh_y = ServerPublicDh
State) ->
dh_master_secret(P, G, ServerPublicDhKey, undefined, State);
+server_master_secret(#server_ecdh_params{curve = ECCurve, public = ECServerPubKey},
+ State) ->
+ ECDHKeys = public_key:generate_key(ECCurve),
+ ec_dh_master_secret(ECDHKeys, #'ECPoint'{point = ECServerPubKey}, State#state{diffie_hellman_keys = ECDHKeys});
+
server_master_secret(#server_psk_params{
hint = IdentityHint},
State) ->
@@ -2000,17 +2086,23 @@ master_from_premaster_secret(PremasterSecret,
Alert
end.
+dh_master_secret(#'DHParameter'{} = Params, OtherPublicDhKey, MyPrivateKey, State) ->
+ PremasterSecret =
+ public_key:compute_key(OtherPublicDhKey, MyPrivateKey, Params),
+ master_from_premaster_secret(PremasterSecret, State).
+
dh_master_secret(Prime, Base, PublicDhKey, undefined, State) ->
- PMpint = mpint_binary(Prime),
- GMpint = mpint_binary(Base),
- Keys = {_, PrivateDhKey} =
- crypto:dh_generate_key([PMpint,GMpint]),
- dh_master_secret(PMpint, GMpint, PublicDhKey, PrivateDhKey, State#state{diffie_hellman_keys = Keys});
+ Keys = {_, PrivateDhKey} = crypto:generate_key(dh, [Prime, Base]),
+ dh_master_secret(Prime, Base, PublicDhKey, PrivateDhKey, State#state{diffie_hellman_keys = Keys});
+
+dh_master_secret(Prime, Base, PublicDhKey, PrivateDhKey, State) ->
+ PremasterSecret =
+ crypto:compute_key(dh, PublicDhKey, PrivateDhKey, [Prime, Base]),
+ master_from_premaster_secret(PremasterSecret, State).
-dh_master_secret(PMpint, GMpint, PublicDhKey, PrivateDhKey, State) ->
+ec_dh_master_secret(ECDHKeys, ECPoint, State) ->
PremasterSecret =
- crypto:dh_compute_key(mpint_binary(PublicDhKey), PrivateDhKey,
- [PMpint, GMpint]),
+ public_key:compute_key(ECPoint, ECDHKeys),
master_from_premaster_secret(PremasterSecret, State).
handle_psk_identity(_PSKIdentity, LookupFun)
@@ -2033,20 +2125,18 @@ server_psk_master_secret(ClientPSKIdentity,
end.
dhe_psk_master_secret(PSKIdentity, Prime, Base, PublicDhKey, undefined, State) ->
- PMpint = mpint_binary(Prime),
- GMpint = mpint_binary(Base),
Keys = {_, PrivateDhKey} =
- crypto:dh_generate_key([PMpint,GMpint]),
- dhe_psk_master_secret(PSKIdentity, PMpint, GMpint, PublicDhKey, PrivateDhKey,
+ crypto:generate_key(dh, [Prime, Base]),
+ dhe_psk_master_secret(PSKIdentity, Prime, Base, PublicDhKey, PrivateDhKey,
State#state{diffie_hellman_keys = Keys});
-dhe_psk_master_secret(PSKIdentity, PMpint, GMpint, PublicDhKey, PrivateDhKey,
+dhe_psk_master_secret(PSKIdentity, Prime, Base, PublicDhKey, PrivateDhKey,
#state{ssl_options = SslOpts} = State) ->
case handle_psk_identity(PSKIdentity, SslOpts#ssl_options.user_lookup_fun) of
{ok, PSK} when is_binary(PSK) ->
DHSecret =
- crypto:dh_compute_key(mpint_binary(PublicDhKey), PrivateDhKey,
- [PMpint, GMpint]),
+ crypto:compute_key(dh, PublicDhKey, PrivateDhKey,
+ [Prime, Base]),
DHLen = erlang:byte_size(DHSecret),
Len = erlang:byte_size(PSK),
PremasterSecret = <<?UINT16(DHLen), DHSecret/binary, ?UINT16(Len), PSK/binary>>,
@@ -2075,7 +2165,7 @@ generate_srp_server_keys(_SrpParams, 10) ->
generate_srp_server_keys(SrpParams =
#srp_user{generator = Generator, prime = Prime,
verifier = Verifier}, N) ->
- case crypto:srp_generate_key(Verifier, Generator, Prime, '6a') of
+ case crypto:generate_key(srp, {host, [Verifier, Generator, Prime, '6a']}) of
error ->
generate_srp_server_keys(SrpParams, N+1);
Keys ->
@@ -2086,7 +2176,7 @@ generate_srp_client_keys(_Generator, _Prime, 10) ->
?ALERT_REC(?FATAL, ?ILLEGAL_PARAMETER);
generate_srp_client_keys(Generator, Prime, N) ->
- case crypto:srp_generate_key(Generator, Prime, '6a') of
+ case crypto:generate_key(srp, {user, [Generator, Prime, '6a']}) of
error ->
generate_srp_client_keys(Generator, Prime, N+1);
Keys ->
@@ -2098,7 +2188,7 @@ handle_srp_identity(Username, {Fun, UserState}) ->
{ok, {SRPParams, Salt, DerivedKey}}
when is_atom(SRPParams), is_binary(Salt), is_binary(DerivedKey) ->
{Generator, Prime} = ssl_srp_primes:get_srp_params(SRPParams),
- Verifier = crypto:mod_exp_prime(Generator, DerivedKey, Prime),
+ Verifier = crypto:mod_pow(Generator, DerivedKey, Prime),
#srp_user{generator = Generator, prime = Prime,
salt = Salt, verifier = Verifier};
#alert{} = Alert ->
@@ -2107,8 +2197,8 @@ handle_srp_identity(Username, {Fun, UserState}) ->
throw(?ALERT_REC(?FATAL, ?ILLEGAL_PARAMETER))
end.
-server_srp_master_secret(Verifier, Prime, ClientPub, State = #state{srp_keys = {ServerPub, ServerPriv}}) ->
- case crypto:srp_compute_key(Verifier, Prime, ClientPub, ServerPub, ServerPriv, '6a') of
+server_srp_master_secret(Verifier, Prime, ClientPub, State = #state{srp_keys = ServerKeys}) ->
+ case crypto:compute_key(srp, ClientPub, ServerKeys, {host, [Verifier, Prime, '6a']}) of
error ->
?ALERT_REC(?FATAL, ?ILLEGAL_PARAMETER);
PremasterSecret ->
@@ -2121,14 +2211,13 @@ client_srp_master_secret(Generator, Prime, Salt, ServerPub, undefined, State) ->
Keys = generate_srp_client_keys(Generator, Prime, 0),
client_srp_master_secret(Generator, Prime, Salt, ServerPub, Keys, State#state{srp_keys = Keys});
-client_srp_master_secret(Generator, Prime, Salt, ServerPub, {ClientPub, ClientPriv},
- #state{ssl_options = SslOpts} = State) ->
+client_srp_master_secret(Generator, Prime, Salt, ServerPub, ClientKeys,
+ #state{ssl_options = SslOpts} = State) ->
case ssl_srp_primes:check_srp_params(Generator, Prime) of
ok ->
{Username, Password} = SslOpts#ssl_options.srp_identity,
DerivedKey = crypto:sha([Salt, crypto:sha([Username, <<$:>>, Password])]),
-
- case crypto:srp_compute_key(DerivedKey, Prime, Generator, ClientPub, ClientPriv, ServerPub, '6a') of
+ case crypto:compute_key(srp, ServerPub, ClientKeys, {user, [DerivedKey, Prime, Generator, '6a']}) of
error ->
?ALERT_REC(?FATAL, ?ILLEGAL_PARAMETER);
PremasterSecret ->
@@ -2798,11 +2887,6 @@ make_premaster_secret({MajVer, MinVer}, rsa) ->
make_premaster_secret(_, _) ->
undefined.
-mpint_binary(Binary) ->
- Size = erlang:byte_size(Binary),
- <<?UINT32(Size), Binary/binary>>.
-
-
ack_connection(#state{renegotiation = {true, Initiater}} = State)
when Initiater == internal;
Initiater == peer ->
@@ -2938,21 +3022,29 @@ default_hashsign(_Version = {Major, Minor}, KeyExchange)
(KeyExchange == rsa orelse
KeyExchange == dhe_rsa orelse
KeyExchange == dh_rsa orelse
+ KeyExchange == ecdhe_rsa orelse
KeyExchange == srp_rsa) ->
{sha, rsa};
default_hashsign(_Version, KeyExchange)
when KeyExchange == rsa;
KeyExchange == dhe_rsa;
KeyExchange == dh_rsa;
+ KeyExchange == ecdhe_rsa;
KeyExchange == srp_rsa ->
{md5sha, rsa};
default_hashsign(_Version, KeyExchange)
+ when KeyExchange == ecdhe_ecdsa;
+ KeyExchange == ecdh_ecdsa;
+ KeyExchange == ecdh_rsa ->
+ {sha, ecdsa};
+default_hashsign(_Version, KeyExchange)
when KeyExchange == dhe_dss;
KeyExchange == dh_dss;
KeyExchange == srp_dss ->
{sha, dsa};
default_hashsign(_Version, KeyExchange)
when KeyExchange == dh_anon;
+ KeyExchange == ecdh_anon;
KeyExchange == psk;
KeyExchange == dhe_psk;
KeyExchange == rsa_psk;
@@ -2987,3 +3079,8 @@ handle_close_alert(Data, StateName, State0) ->
_ ->
ok
end.
+
+select_curve(#state{client_ecc = {[Curve|_], _}}) ->
+ {namedCurve, Curve};
+select_curve(_) ->
+ {namedCurve, ?secp256k1}.
diff --git a/lib/ssl/src/ssl_handshake.erl b/lib/ssl/src/ssl_handshake.erl
index 83c0092de2..e358cbe9bb 100644
--- a/lib/ssl/src/ssl_handshake.erl
+++ b/lib/ssl/src/ssl_handshake.erl
@@ -31,7 +31,7 @@
-include("ssl_srp.hrl").
-include_lib("public_key/include/public_key.hrl").
--export([master_secret/4, client_hello/8, server_hello/5, hello/4,
+-export([master_secret/4, client_hello/8, server_hello/7, hello/4,
hello_request/0, certify/7, certificate/4,
client_certificate_verify/6, certificate_verify/6, verify_signature/5,
certificate_request/3, key_exchange/3, server_key_exchange_hash/2,
@@ -47,6 +47,8 @@
#client_key_exchange{} | #finished{} | #certificate_verify{} |
#hello_request{} | #next_protocol{}.
+-define(NAMED_CURVE_TYPE, 3).
+
%%====================================================================
%% Internal application API
%%====================================================================
@@ -67,6 +69,7 @@ client_hello(Host, Port, ConnectionStates,
SecParams = Pending#connection_state.security_parameters,
Ciphers = available_suites(UserSuites, Version),
SRP = srp_user(SslOpts),
+ {EcPointFormats, EllipticCurves} = default_ecc_extensions(Version),
Id = ssl_session:client_id({Host, Port, SslOpts}, Cache, CacheCb, OwnCert),
@@ -80,6 +83,8 @@ client_hello(Host, Port, ConnectionStates,
renegotiation_info(client, ConnectionStates, Renegotiation),
srp = SRP,
hash_signs = default_hash_signs(),
+ ec_point_formats = EcPointFormats,
+ elliptic_curves = EllipticCurves,
next_protocol_negotiation =
encode_client_protocol_negotiation(SslOpts#ssl_options.next_protocol_selector, Renegotiation)
}.
@@ -96,11 +101,14 @@ encode_protocols_advertised_on_server(Protocols) ->
%%--------------------------------------------------------------------
-spec server_hello(session_id(), tls_version(), #connection_states{},
- boolean(), [binary()] | undefined) -> #server_hello{}.
+ boolean(), [binary()] | undefined,
+ #ec_point_formats{} | undefined,
+ #elliptic_curves{} | undefined) -> #server_hello{}.
%%
%% Description: Creates a server hello message.
%%--------------------------------------------------------------------
-server_hello(SessionId, Version, ConnectionStates, Renegotiation, ProtocolsAdvertisedOnServer) ->
+server_hello(SessionId, Version, ConnectionStates, Renegotiation,
+ ProtocolsAdvertisedOnServer, EcPointFormats, EllipticCurves) ->
Pending = ssl_record:pending_connection_state(ConnectionStates, read),
SecParams = Pending#connection_state.security_parameters,
#server_hello{server_version = Version,
@@ -111,6 +119,8 @@ server_hello(SessionId, Version, ConnectionStates, Renegotiation, ProtocolsAdver
session_id = SessionId,
renegotiation_info =
renegotiation_info(server, ConnectionStates, Renegotiation),
+ ec_point_formats = EcPointFormats,
+ elliptic_curves = EllipticCurves,
next_protocol_negotiation = encode_protocols_advertised_on_server(ProtocolsAdvertisedOnServer)
}.
@@ -129,7 +139,8 @@ hello_request() ->
atom(), #connection_states{}, binary()},
boolean()) ->
{tls_version(), session_id(), #connection_states{}, binary() | undefined}|
- {tls_version(), {resumed | new, #session{}}, #connection_states{}, list(binary()) | undefined} |
+ {tls_version(), {resumed | new, #session{}}, #connection_states{}, [binary()] | undefined,
+ [oid()] | undefined, [oid()] | undefined} |
#alert{}.
%%
%% Description: Handles a recieved hello message
@@ -163,44 +174,27 @@ hello(#server_hello{cipher_suite = CipherSuite, server_version = Version,
?ALERT_REC(?FATAL, ?PROTOCOL_VERSION)
end;
-hello(#client_hello{client_version = ClientVersion, random = Random,
- cipher_suites = CipherSuites,
- renegotiation_info = Info,
- srp = SRP} = Hello,
- #ssl_options{versions = Versions,
- secure_renegotiate = SecureRenegotation} = SslOpts,
+hello(#client_hello{client_version = ClientVersion} = Hello,
+ #ssl_options{versions = Versions} = SslOpts,
{Port, Session0, Cache, CacheCb, ConnectionStates0, Cert}, Renegotiation) ->
-%% TODO: select hash and signature algorithm
+ %% TODO: select hash and signature algorithm
Version = select_version(ClientVersion, Versions),
case ssl_record:is_acceptable_version(Version, Versions) of
true ->
- {Type, #session{cipher_suite = CipherSuite,
- compression_method = Compression} = Session1}
+ %% TODO: need to take supported Curves into Account when selecting the CipherSuite....
+ %% if whe have an ECDSA cert with an unsupported curve, we need to drop ECDSA ciphers
+ {Type, #session{cipher_suite = CipherSuite} = Session1}
= select_session(Hello, Port, Session0, Version,
SslOpts, Cache, CacheCb, Cert),
case CipherSuite of
no_suite ->
?ALERT_REC(?FATAL, ?INSUFFICIENT_SECURITY);
_ ->
- Session = handle_srp_info(SRP, Session1),
- case handle_renegotiation_info(server, Info, ConnectionStates0,
- Renegotiation, SecureRenegotation,
- CipherSuites) of
- {ok, ConnectionStates1} ->
- ConnectionStates =
- hello_pending_connection_states(server,
- Version,
- CipherSuite,
- Random,
- Compression,
- ConnectionStates1),
- case handle_next_protocol_on_server(Hello, Renegotiation, SslOpts) of
- #alert{} = Alert ->
- Alert;
- ProtocolsToAdvertise ->
- {Version, {Type, Session}, ConnectionStates, ProtocolsToAdvertise}
- end;
- #alert{} = Alert ->
+ try handle_hello_extensions(Hello, Version, SslOpts, Session1, ConnectionStates0, Renegotiation) of
+ {Session, ConnectionStates, ProtocolsToAdvertise, ECPointFormats, EllipticCurves} ->
+ {Version, {Type, Session}, ConnectionStates,
+ ProtocolsToAdvertise, ECPointFormats, EllipticCurves}
+ catch throw:Alert ->
Alert
end
end;
@@ -350,9 +344,10 @@ verify_signature(_Version, Hash, _HashAlgo, Signature, {?rsaEncryption, PubKey,
_ -> false
end;
verify_signature(_Version, Hash, {HashAlgo, dsa}, Signature, {?'id-dsa', PublicKey, PublicKeyParams}) ->
+ public_key:verify({digest, Hash}, HashAlgo, Signature, {PublicKey, PublicKeyParams});
+verify_signature(_Version, Hash, {HashAlgo, ecdsa}, Signature, {?'id-ecPublicKey', PublicKey, PublicKeyParams}) ->
public_key:verify({digest, Hash}, HashAlgo, Signature, {PublicKey, PublicKeyParams}).
-
%%--------------------------------------------------------------------
-spec certificate_request(#connection_states{}, db_handle(), certdb_ref()) ->
#certificate_request{}.
@@ -378,6 +373,7 @@ certificate_request(ConnectionStates, CertDbHandle, CertDbRef) ->
{dh, binary()} |
{dh, {binary(), binary()}, #'DHParameter'{}, {HashAlgo::atom(), SignAlgo::atom()},
binary(), binary(), private_key()} |
+ {ecdh, #'ECPrivateKey'{}} |
{psk, binary()} |
{dhe_psk, binary(), binary()} |
{srp, {binary(), binary()}, #srp_user{}, {HashAlgo::atom(), SignAlgo::atom()},
@@ -391,19 +387,25 @@ key_exchange(client, _Version, {premaster_secret, Secret, {_, PublicKey, _}}) ->
encrypted_premaster_secret(Secret, PublicKey),
#client_key_exchange{exchange_keys = EncPremasterSecret};
-key_exchange(client, _Version, {dh, <<?UINT32(Len), PublicKey:Len/binary>>}) ->
+key_exchange(client, _Version, {dh, PublicKey}) ->
#client_key_exchange{
exchange_keys = #client_diffie_hellman_public{
dh_public = PublicKey}
};
+key_exchange(client, _Version, {ecdh, #'ECPrivateKey'{publicKey = {0, ECPublicKey}}}) ->
+ #client_key_exchange{
+ exchange_keys = #client_ec_diffie_hellman_public{
+ dh_public = ECPublicKey}
+ };
+
key_exchange(client, _Version, {psk, Identity}) ->
#client_key_exchange{
exchange_keys = #client_psk_identity{
identity = Identity}
};
-key_exchange(client, _Version, {dhe_psk, Identity, <<?UINT32(Len), PublicKey:Len/binary>>}) ->
+key_exchange(client, _Version, {dhe_psk, Identity, PublicKey}) ->
#client_key_exchange{
exchange_keys = #client_dhe_psk_identity{
identity = Identity,
@@ -415,7 +417,7 @@ key_exchange(client, _Version, {psk_premaster_secret, PskIdentity, Secret, {_, P
encrypted_premaster_secret(Secret, PublicKey),
#client_key_exchange{
exchange_keys = #client_rsa_psk_identity{
- identity = PskIdentity,
+ identity = PskIdentity,
exchange_keys = EncPremasterSecret}};
key_exchange(client, _Version, {srp, PublicKey}) ->
@@ -424,31 +426,34 @@ key_exchange(client, _Version, {srp, PublicKey}) ->
srp_a = PublicKey}
};
-key_exchange(server, Version, {dh, {<<?UINT32(Len), PublicKey:Len/binary>>, _},
- #'DHParameter'{prime = P, base = G},
- HashSign, ClientRandom, ServerRandom, PrivateKey}) ->
- <<?UINT32(_), PBin/binary>> = crypto:mpint(P),
- <<?UINT32(_), GBin/binary>> = crypto:mpint(G),
- ServerDHParams = #server_dh_params{dh_p = PBin,
- dh_g = GBin, dh_y = PublicKey},
+key_exchange(server, Version, {dh, {PublicKey, _},
+ #'DHParameter'{prime = P, base = G},
+ HashSign, ClientRandom, ServerRandom, PrivateKey}) ->
+ ServerDHParams = #server_dh_params{dh_p = int_to_bin(P),
+ dh_g = int_to_bin(G), dh_y = PublicKey},
enc_server_key_exchange(Version, ServerDHParams, HashSign,
ClientRandom, ServerRandom, PrivateKey);
+key_exchange(server, Version, {ecdh, #'ECPrivateKey'{publicKey = {0, ECPublicKey},
+ parameters = ECCurve}, HashSign, ClientRandom, ServerRandom,
+ PrivateKey}) ->
+ ServerECParams = #server_ecdh_params{curve = ECCurve, public = ECPublicKey},
+ enc_server_key_exchange(Version, ServerECParams, HashSign,
+ ClientRandom, ServerRandom, PrivateKey);
+
key_exchange(server, Version, {psk, PskIdentityHint,
HashSign, ClientRandom, ServerRandom, PrivateKey}) ->
ServerPSKParams = #server_psk_params{hint = PskIdentityHint},
enc_server_key_exchange(Version, ServerPSKParams, HashSign,
ClientRandom, ServerRandom, PrivateKey);
-key_exchange(server, Version, {dhe_psk, PskIdentityHint, {<<?UINT32(Len), PublicKey:Len/binary>>, _},
+key_exchange(server, Version, {dhe_psk, PskIdentityHint, {PublicKey, _},
#'DHParameter'{prime = P, base = G},
HashSign, ClientRandom, ServerRandom, PrivateKey}) ->
- <<?UINT32(_), PBin/binary>> = crypto:mpint(P),
- <<?UINT32(_), GBin/binary>> = crypto:mpint(G),
ServerEDHPSKParams = #server_dhe_psk_params{
hint = PskIdentityHint,
- dh_params = #server_dh_params{dh_p = PBin,
- dh_g = GBin, dh_y = PublicKey}
+ dh_params = #server_dh_params{dh_p = int_to_bin(P),
+ dh_g = int_to_bin(G), dh_y = PublicKey}
},
enc_server_key_exchange(Version, ServerEDHPSKParams,
HashSign, ClientRandom, ServerRandom, PrivateKey);
@@ -591,6 +596,7 @@ get_tls_handshake(Version, Data, Buffer) ->
-spec decode_client_key(binary(), key_algo(), tls_version()) ->
#encrypted_premaster_secret{}
| #client_diffie_hellman_public{}
+ | #client_ec_diffie_hellman_public{}
| #client_psk_identity{}
| #client_dhe_psk_identity{}
| #client_rsa_psk_identity{}
@@ -661,8 +667,8 @@ decrypt_premaster_secret(Secret, RSAPrivateKey) ->
%% Description: Calculate server key exchange hash
%%--------------------------------------------------------------------
server_key_exchange_hash(md5sha, Value) ->
- MD5 = crypto:md5(Value),
- SHA = crypto:sha(Value),
+ MD5 = crypto:hash(md5, Value),
+ SHA = crypto:hash(sha, Value),
<<MD5/binary, SHA/binary>>;
server_key_exchange_hash(Hash, Value) ->
@@ -833,10 +839,35 @@ select_next_protocol(Protocols, NextProtocolSelector) ->
Protocol
end.
-handle_srp_info(undefined, Session) ->
- Session;
-handle_srp_info(#srp{username = Username}, Session) ->
- Session#session{srp_username = Username}.
+default_ecc_extensions(Version) ->
+ case proplists:get_bool(ec, crypto:algorithms()) of
+ true ->
+ EcPointFormats = #ec_point_formats{ec_point_format_list = [?ECPOINT_UNCOMPRESSED]},
+ EllipticCurves = #elliptic_curves{elliptic_curve_list = ssl_tls1:ecc_curves(Version)},
+ {EcPointFormats, EllipticCurves};
+ _ ->
+ {undefined, undefined}
+ end.
+
+handle_ecc_extensions(Version, EcPointFormats0, EllipticCurves0) ->
+ case proplists:get_bool(ec, crypto:algorithms()) of
+ true ->
+ EcPointFormats1 = handle_ecc_point_fmt_extension(EcPointFormats0),
+ EllipticCurves1 = handle_ecc_curves_extension(Version, EllipticCurves0),
+ {EcPointFormats1, EllipticCurves1};
+ _ ->
+ {undefined, undefined}
+ end.
+
+handle_ecc_point_fmt_extension(undefined) ->
+ undefined;
+handle_ecc_point_fmt_extension(_) ->
+ #ec_point_formats{ec_point_format_list = [?ECPOINT_UNCOMPRESSED]}.
+
+handle_ecc_curves_extension(Version, undefined) ->
+ undefined;
+handle_ecc_curves_extension(Version, _) ->
+ #elliptic_curves{elliptic_curve_list = ssl_tls1:ecc_curves(Version)}.
handle_renegotiation_info(_, #renegotiation_info{renegotiated_connection = ?byte(0)},
ConnectionStates, false, _, _) ->
@@ -1022,6 +1053,8 @@ dec_hs(_Version, ?CLIENT_HELLO, <<?BYTE(Major), ?BYTE(Minor), Random:32/binary,
RenegotiationInfo = proplists:get_value(renegotiation_info, DecodedExtensions, undefined),
SRP = proplists:get_value(srp, DecodedExtensions, undefined),
HashSigns = proplists:get_value(hash_signs, DecodedExtensions, undefined),
+ EllipticCurves = proplists:get_value(elliptic_curves, DecodedExtensions,
+ undefined),
NextProtocolNegotiation = proplists:get_value(next_protocol_negotiation, DecodedExtensions, undefined),
#client_hello{
@@ -1033,6 +1066,7 @@ dec_hs(_Version, ?CLIENT_HELLO, <<?BYTE(Major), ?BYTE(Minor), Random:32/binary,
renegotiation_info = RenegotiationInfo,
srp = SRP,
hash_signs = HashSigns,
+ elliptic_curves = EllipticCurves,
next_protocol_negotiation = NextProtocolNegotiation
};
@@ -1046,7 +1080,8 @@ dec_hs(_Version, ?SERVER_HELLO, <<?BYTE(Major), ?BYTE(Minor), Random:32/binary,
cipher_suite = Cipher_suite,
compression_method = Comp_method,
renegotiation_info = undefined,
- hash_signs = undefined};
+ hash_signs = undefined,
+ elliptic_curves = undefined};
dec_hs(_Version, ?SERVER_HELLO, <<?BYTE(Major), ?BYTE(Minor), Random:32/binary,
?BYTE(SID_length), Session_ID:SID_length/binary,
@@ -1058,6 +1093,8 @@ dec_hs(_Version, ?SERVER_HELLO, <<?BYTE(Major), ?BYTE(Minor), Random:32/binary,
undefined),
HashSigns = proplists:get_value(hash_signs, HelloExtensions,
undefined),
+ EllipticCurves = proplists:get_value(elliptic_curves, HelloExtensions,
+ undefined),
NextProtocolNegotiation = proplists:get_value(next_protocol_negotiation, HelloExtensions, undefined),
#server_hello{
@@ -1068,6 +1105,7 @@ dec_hs(_Version, ?SERVER_HELLO, <<?BYTE(Major), ?BYTE(Minor), Random:32/binary,
compression_method = Comp_method,
renegotiation_info = RenegotiationInfo,
hash_signs = HashSigns,
+ elliptic_curves = EllipticCurves,
next_protocol_negotiation = NextProtocolNegotiation};
dec_hs(_Version, ?CERTIFICATE, <<?UINT24(ACLen), ASN1Certs:ACLen/binary>>) ->
#certificate{asn1_certificates = certs_to_list(ASN1Certs)};
@@ -1111,6 +1149,11 @@ dec_client_key(<<>>, ?KEY_EXCHANGE_DIFFIE_HELLMAN, _) ->
dec_client_key(<<?UINT16(DH_YLen), DH_Y:DH_YLen/binary>>,
?KEY_EXCHANGE_DIFFIE_HELLMAN, _) ->
#client_diffie_hellman_public{dh_public = DH_Y};
+dec_client_key(<<>>, ?KEY_EXCHANGE_EC_DIFFIE_HELLMAN, _) ->
+ throw(?ALERT_REC(?FATAL, ?UNSUPPORTED_CERTIFICATE));
+dec_client_key(<<?BYTE(DH_YLen), DH_Y:DH_YLen/binary>>,
+ ?KEY_EXCHANGE_EC_DIFFIE_HELLMAN, _) ->
+ #client_ec_diffie_hellman_public{dh_public = DH_Y};
dec_client_key(<<?UINT16(Len), Id:Len/binary>>,
?KEY_EXCHANGE_PSK, _) ->
#client_psk_identity{identity = Id};
@@ -1161,6 +1204,19 @@ dec_server_key(<<?UINT16(PLen), P:PLen/binary,
params_bin = BinMsg,
hashsign = HashSign,
signature = Signature};
+%% ECParameters with named_curve
+%% TODO: explicit curve
+dec_server_key(<<?BYTE(?NAMED_CURVE), ?UINT16(CurveID),
+ ?BYTE(PointLen), ECPoint:PointLen/binary,
+ _/binary>> = KeyStruct,
+ ?KEY_EXCHANGE_EC_DIFFIE_HELLMAN, Version) ->
+ Params = #server_ecdh_params{curve = {namedCurve, ssl_tls1:enum_to_oid(CurveID)},
+ public = ECPoint},
+ {BinMsg, HashSign, Signature} = dec_ske_params(PointLen + 4, KeyStruct, Version),
+ #server_key_params{params = Params,
+ params_bin = BinMsg,
+ hashsign = HashSign,
+ signature = Signature};
dec_server_key(<<?UINT16(Len), PskIdentityHint:Len/binary>> = KeyStruct,
KeyExchange, Version)
when KeyExchange == ?KEY_EXCHANGE_PSK; KeyExchange == ?KEY_EXCHANGE_RSA_PSK ->
@@ -1237,6 +1293,22 @@ dec_hello_extensions(<<?UINT16(?SIGNATURE_ALGORITHMS_EXT), ?UINT16(Len),
dec_hello_extensions(Rest, [{hash_signs,
#hash_sign_algos{hash_sign_algos = HashSignAlgos}} | Acc]);
+dec_hello_extensions(<<?UINT16(?ELLIPTIC_CURVES_EXT), ?UINT16(Len),
+ ExtData:Len/binary, Rest/binary>>, Acc) ->
+ EllipticCurveListLen = Len - 2,
+ <<?UINT16(EllipticCurveListLen), EllipticCurveList/binary>> = ExtData,
+ EllipticCurves = [ssl_tls1:enum_to_oid(X) || <<X:16>> <= EllipticCurveList],
+ dec_hello_extensions(Rest, [{elliptic_curves,
+ #elliptic_curves{elliptic_curve_list = EllipticCurves}} | Acc]);
+
+dec_hello_extensions(<<?UINT16(?EC_POINT_FORMATS_EXT), ?UINT16(Len),
+ ExtData:Len/binary, Rest/binary>>, Acc) ->
+ ECPointFormatListLen = Len - 1,
+ <<?BYTE(ECPointFormatListLen), ECPointFormatList/binary>> = ExtData,
+ ECPointFormats = binary_to_list(ECPointFormatList),
+ dec_hello_extensions(Rest, [{ec_point_formats,
+ #ec_point_formats{ec_point_format_list = ECPointFormats}} | Acc]);
+
%% Ignore data following the ClientHello (i.e.,
%% extensions) if not understood.
@@ -1287,13 +1359,17 @@ enc_hs(#client_hello{client_version = {Major, Minor},
renegotiation_info = RenegotiationInfo,
srp = SRP,
hash_signs = HashSigns,
+ ec_point_formats = EcPointFormats,
+ elliptic_curves = EllipticCurves,
next_protocol_negotiation = NextProtocolNegotiation}, _Version) ->
SIDLength = byte_size(SessionID),
BinCompMethods = list_to_binary(CompMethods),
CmLength = byte_size(BinCompMethods),
BinCipherSuites = list_to_binary(CipherSuites),
CsLength = byte_size(BinCipherSuites),
- Extensions0 = hello_extensions(RenegotiationInfo, SRP, NextProtocolNegotiation),
+ Extensions0 = hello_extensions(RenegotiationInfo, SRP, NextProtocolNegotiation)
+ ++ ec_hello_extensions(lists:map(fun ssl_cipher:suite_definition/1, CipherSuites), EcPointFormats)
+ ++ ec_hello_extensions(lists:map(fun ssl_cipher:suite_definition/1, CipherSuites), EllipticCurves),
Extensions1 = if
Major == 3, Minor >=3 -> Extensions0 ++ hello_extensions(HashSigns);
true -> Extensions0
@@ -1308,16 +1384,21 @@ enc_hs(#client_hello{client_version = {Major, Minor},
enc_hs(#server_hello{server_version = {Major, Minor},
random = Random,
session_id = Session_ID,
- cipher_suite = Cipher_suite,
+ cipher_suite = CipherSuite,
compression_method = Comp_method,
renegotiation_info = RenegotiationInfo,
+ ec_point_formats = EcPointFormats,
+ elliptic_curves = EllipticCurves,
next_protocol_negotiation = NextProtocolNegotiation}, _Version) ->
SID_length = byte_size(Session_ID),
- Extensions = hello_extensions(RenegotiationInfo, NextProtocolNegotiation),
+ CipherSuites = [ssl_cipher:suite_definition(CipherSuite)],
+ Extensions = hello_extensions(RenegotiationInfo, NextProtocolNegotiation)
+ ++ ec_hello_extensions(CipherSuites, EcPointFormats)
+ ++ ec_hello_extensions(CipherSuites, EllipticCurves),
ExtensionsBin = enc_hello_extensions(Extensions),
{?SERVER_HELLO, <<?BYTE(Major), ?BYTE(Minor), Random:32/binary,
?BYTE(SID_length), Session_ID/binary,
- Cipher_suite/binary, ?BYTE(Comp_method), ExtensionsBin/binary>>};
+ CipherSuite/binary, ?BYTE(Comp_method), ExtensionsBin/binary>>};
enc_hs(#certificate{asn1_certificates = ASN1CertList}, _Version) ->
ASN1Certs = certs_from_list(ASN1CertList),
ACLen = erlang:iolist_size(ASN1Certs),
@@ -1370,6 +1451,9 @@ enc_cke(#encrypted_premaster_secret{premaster_secret = PKEPMS}, _) ->
enc_cke(#client_diffie_hellman_public{dh_public = DHPublic}, _) ->
Len = byte_size(DHPublic),
<<?UINT16(Len), DHPublic/binary>>;
+enc_cke(#client_ec_diffie_hellman_public{dh_public = DHPublic}, _) ->
+ Len = byte_size(DHPublic),
+ <<?BYTE(Len), DHPublic/binary>>;
enc_cke(#client_psk_identity{identity = undefined}, _) ->
Id = <<"psk_identity">>,
Len = byte_size(Id),
@@ -1398,6 +1482,11 @@ enc_server_key(#server_dh_params{dh_p = P, dh_g = G, dh_y = Y}) ->
GLen = byte_size(G),
YLen = byte_size(Y),
<<?UINT16(PLen), P/binary, ?UINT16(GLen), G/binary, ?UINT16(YLen), Y/binary>>;
+enc_server_key(#server_ecdh_params{curve = {namedCurve, ECCurve}, public = ECPubKey}) ->
+ %%TODO: support arbitrary keys
+ KLen = size(ECPubKey),
+ <<?BYTE(?NAMED_CURVE_TYPE), ?UINT16((ssl_tls1:oid_to_enum(ECCurve))),
+ ?BYTE(KLen), ECPubKey/binary>>;
enc_server_key(#server_psk_params{hint = PskIdentityHint}) ->
Len = byte_size(PskIdentityHint),
<<?UINT16(Len), PskIdentityHint/binary>>;
@@ -1431,11 +1520,46 @@ enc_sign(_HashSign, Sign, _Version) ->
SignLen = byte_size(Sign),
<<?UINT16(SignLen), Sign/binary>>.
+
+ec_hello_extensions(CipherSuites, #elliptic_curves{} = Info) ->
+ case advertises_ec_ciphers(CipherSuites) of
+ true ->
+ [Info];
+ false ->
+ []
+ end;
+ec_hello_extensions(CipherSuites, #ec_point_formats{} = Info) ->
+ case advertises_ec_ciphers(CipherSuites) of
+ true ->
+ [Info];
+ false ->
+ []
+ end;
+ec_hello_extensions(_, undefined) ->
+ [].
+
hello_extensions(RenegotiationInfo, NextProtocolNegotiation) ->
hello_extensions(RenegotiationInfo) ++ next_protocol_extension(NextProtocolNegotiation).
hello_extensions(RenegotiationInfo, SRP, NextProtocolNegotiation) ->
- hello_extensions(RenegotiationInfo) ++ hello_extensions(SRP) ++ next_protocol_extension(NextProtocolNegotiation).
+ hello_extensions(RenegotiationInfo)
+ ++ hello_extensions(SRP)
+ ++ next_protocol_extension(NextProtocolNegotiation).
+
+advertises_ec_ciphers([]) ->
+ false;
+advertises_ec_ciphers([{ecdh_ecdsa, _,_,_} | _]) ->
+ true;
+advertises_ec_ciphers([{ecdhe_ecdsa, _,_,_} | _]) ->
+ true;
+advertises_ec_ciphers([{ecdh_rsa, _,_,_} | _]) ->
+ true;
+advertises_ec_ciphers([{ecdhe_rsa, _,_,_} | _]) ->
+ true;
+advertises_ec_ciphers([{ecdh_anon, _,_,_} | _]) ->
+ true;
+advertises_ec_ciphers([_| Rest]) ->
+ advertises_ec_ciphers(Rest).
%% Renegotiation info
hello_extensions(#renegotiation_info{renegotiated_connection = undefined}) ->
@@ -1473,12 +1597,22 @@ enc_hello_extensions([#renegotiation_info{renegotiated_connection = Info} | Rest
InfoLen = byte_size(Info),
Len = InfoLen +1,
enc_hello_extensions(Rest, <<?UINT16(?RENEGOTIATION_EXT), ?UINT16(Len), ?BYTE(InfoLen), Info/binary, Acc/binary>>);
-
+enc_hello_extensions([#elliptic_curves{elliptic_curve_list = EllipticCurves} | Rest], Acc) ->
+ EllipticCurveList = << <<(ssl_tls1:oid_to_enum(X)):16>> || X <- EllipticCurves>>,
+ ListLen = byte_size(EllipticCurveList),
+ Len = ListLen + 2,
+ enc_hello_extensions(Rest, <<?UINT16(?ELLIPTIC_CURVES_EXT),
+ ?UINT16(Len), ?UINT16(ListLen), EllipticCurveList/binary, Acc/binary>>);
+enc_hello_extensions([#ec_point_formats{ec_point_format_list = ECPointFormats} | Rest], Acc) ->
+ ECPointFormatList = list_to_binary(ECPointFormats),
+ ListLen = byte_size(ECPointFormatList),
+ Len = ListLen + 1,
+ enc_hello_extensions(Rest, <<?UINT16(?EC_POINT_FORMATS_EXT),
+ ?UINT16(Len), ?BYTE(ListLen), ECPointFormatList/binary, Acc/binary>>);
enc_hello_extensions([#srp{username = UserName} | Rest], Acc) ->
SRPLen = byte_size(UserName),
Len = SRPLen + 2,
enc_hello_extensions(Rest, <<?UINT16(?SRP_EXT), ?UINT16(Len), ?BYTE(SRPLen), UserName/binary, Acc/binary>>);
-
enc_hello_extensions([#hash_sign_algos{hash_sign_algos = HashSignAlgos} | Rest], Acc) ->
SignAlgoList = << <<(ssl_cipher:hash_algorithm(Hash)):8, (ssl_cipher:sign_algorithm(Sign)):8>> ||
{Hash, Sign} <- HashSignAlgos >>,
@@ -1513,9 +1647,15 @@ from_2bytes(<<?UINT16(N), Rest/binary>>, Acc) ->
certificate_types({KeyExchange, _, _, _})
when KeyExchange == rsa;
KeyExchange == dhe_dss;
- KeyExchange == dhe_rsa ->
+ KeyExchange == dhe_rsa;
+ KeyExchange == ecdhe_rsa ->
<<?BYTE(?RSA_SIGN), ?BYTE(?DSS_SIGN)>>;
+certificate_types({KeyExchange, _, _, _})
+ when KeyExchange == dh_ecdsa;
+ KeyExchange == dhe_ecdsa ->
+ <<?BYTE(?ECDSA_SIGN)>>;
+
certificate_types(_) ->
<<?BYTE(?RSA_SIGN)>>.
@@ -1532,9 +1672,6 @@ certificate_authorities(CertDbHandle, CertDbRef) ->
Enc = fun(#'OTPCertificate'{tbsCertificate=TBSCert}) ->
OTPSubj = TBSCert#'OTPTBSCertificate'.subject,
DNEncodedBin = public_key:pkix_encode('Name', OTPSubj, otp),
- %%Subj = public_key:pkix_transform(OTPSubj, encode),
- %% {ok, DNEncoded} = 'OTP-PUB-KEY':encode('Name', Subj),
- %% DNEncodedBin = iolist_to_binary(DNEncoded),
DNEncodedLen = byte_size(DNEncodedBin),
<<?UINT16(DNEncodedLen), DNEncodedBin/binary>>
end,
@@ -1555,7 +1692,9 @@ digitally_signed(_Version, Hash, HashAlgo, #'DSAPrivateKey'{} = Key) ->
public_key:sign({digest, Hash}, HashAlgo, Key);
digitally_signed(_Version, Hash, _HashAlgo, #'RSAPrivateKey'{} = Key) ->
public_key:encrypt_private(Hash, Key,
- [{rsa_pad, rsa_pkcs1_padding}]).
+ [{rsa_pad, rsa_pkcs1_padding}]);
+digitally_signed(_Version, Hash, HashAlgo, Key) ->
+ public_key:sign({digest, Hash}, HashAlgo, Key).
calc_master_secret({3,0}, _PrfAlgo, PremasterSecret, ClientRandom, ServerRandom) ->
ssl_ssl3:master_secret(PremasterSecret, ClientRandom, ServerRandom);
@@ -1588,6 +1727,10 @@ key_exchange_alg(rsa) ->
key_exchange_alg(Alg) when Alg == dhe_rsa; Alg == dhe_dss;
Alg == dh_dss; Alg == dh_rsa; Alg == dh_anon ->
?KEY_EXCHANGE_DIFFIE_HELLMAN;
+key_exchange_alg(Alg) when Alg == ecdhe_rsa; Alg == ecdh_rsa;
+ Alg == ecdhe_ecdsa; Alg == ecdh_ecdsa;
+ Alg == ecdh_anon ->
+ ?KEY_EXCHANGE_EC_DIFFIE_HELLMAN;
key_exchange_alg(psk) ->
?KEY_EXCHANGE_PSK;
key_exchange_alg(dhe_psk) ->
@@ -1612,15 +1755,70 @@ apply_user_fun(Fun, OtpCert, ExtensionOrError, UserState0, SslState) ->
-define(TLSEXT_SIGALG_RSA(MD), {MD, rsa}).
-define(TLSEXT_SIGALG_DSA(MD), {MD, dsa}).
+-define(TLSEXT_SIGALG_ECDSA(MD), {MD, ecdsa}).
--define(TLSEXT_SIGALG(MD), ?TLSEXT_SIGALG_RSA(MD)).
+-define(TLSEXT_SIGALG(MD), ?TLSEXT_SIGALG_ECDSA(MD), ?TLSEXT_SIGALG_RSA(MD)).
default_hash_signs() ->
+ HashSigns = [?TLSEXT_SIGALG(sha512),
+ ?TLSEXT_SIGALG(sha384),
+ ?TLSEXT_SIGALG(sha256),
+ ?TLSEXT_SIGALG(sha224),
+ ?TLSEXT_SIGALG(sha),
+ ?TLSEXT_SIGALG_DSA(sha),
+ ?TLSEXT_SIGALG_RSA(md5)],
+ HasECC = proplists:get_bool(ec, crypto:algorithms()),
#hash_sign_algos{hash_sign_algos =
- [?TLSEXT_SIGALG(sha512),
- ?TLSEXT_SIGALG(sha384),
- ?TLSEXT_SIGALG(sha256),
- ?TLSEXT_SIGALG(sha224),
- ?TLSEXT_SIGALG(sha),
- ?TLSEXT_SIGALG_DSA(sha),
- ?TLSEXT_SIGALG_RSA(md5)]}.
+ lists:filter(fun({_, ecdsa}) -> HasECC;
+ (_) -> true end, HashSigns)}.
+
+handle_hello_extensions(#client_hello{random = Random,
+ cipher_suites = CipherSuites,
+ renegotiation_info = Info,
+ srp = SRP,
+ ec_point_formats = EcPointFormats0,
+ elliptic_curves = EllipticCurves0} = Hello, Version,
+ #ssl_options{secure_renegotiate = SecureRenegotation} = Opts,
+ Session0, ConnectionStates0, Renegotiation) ->
+ Session = handle_srp_extension(SRP, Session0),
+ ConnectionStates = handle_renegotiation_extension(Version, Info, Random, Session, ConnectionStates0,
+ Renegotiation, SecureRenegotation, CipherSuites),
+ ProtocolsToAdvertise = handle_next_protocol_extension(Hello, Renegotiation, Opts),
+ {EcPointFormats, EllipticCurves} = handle_ecc_extensions(Version, EcPointFormats0, EllipticCurves0),
+ %%TODO make extensions compund data structure
+ {Session, ConnectionStates, ProtocolsToAdvertise, EcPointFormats, EllipticCurves}.
+
+
+handle_renegotiation_extension(Version, Info, Random, #session{cipher_suite = CipherSuite,
+ compression_method = Compression},
+ ConnectionStates0, Renegotiation, SecureRenegotation, CipherSuites) ->
+ case handle_renegotiation_info(server, Info, ConnectionStates0,
+ Renegotiation, SecureRenegotation,
+ CipherSuites) of
+ {ok, ConnectionStates1} ->
+ hello_pending_connection_states(server,
+ Version,
+ CipherSuite,
+ Random,
+ Compression,
+ ConnectionStates1);
+ #alert{} = Alert ->
+ throw(Alert)
+ end.
+
+handle_next_protocol_extension(Hello, Renegotiation, SslOpts)->
+ case handle_next_protocol_on_server(Hello, Renegotiation, SslOpts) of
+ #alert{} = Alert ->
+ throw(Alert);
+ ProtocolsToAdvertise ->
+ ProtocolsToAdvertise
+ end.
+
+handle_srp_extension(undefined, Session) ->
+ Session;
+handle_srp_extension(#srp{username = Username}, Session) ->
+ Session#session{srp_username = Username}.
+
+int_to_bin(I) ->
+ L = (length(integer_to_list(I, 16)) + 1) div 2,
+ <<I:(L*8)>>.
diff --git a/lib/ssl/src/ssl_handshake.hrl b/lib/ssl/src/ssl_handshake.hrl
index 1fbb88f5f6..b2387a0ee7 100644
--- a/lib/ssl/src/ssl_handshake.hrl
+++ b/lib/ssl/src/ssl_handshake.hrl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2007-2012. All Rights Reserved.
+%% Copyright Ericsson AB 2007-2013. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -28,9 +28,9 @@
-include_lib("public_key/include/public_key.hrl").
--type algo_oid() :: ?'rsaEncryption' | ?'id-dsa'.
--type public_key_params() :: #'Dss-Parms'{} | term().
--type public_key_info() :: {algo_oid(), #'RSAPublicKey'{} | integer() , public_key_params()}.
+-type oid() :: tuple().
+-type public_key_params() :: #'Dss-Parms'{} | {namedCurve, oid()} | #'ECParameters'{} | term().
+-type public_key_info() :: {oid(), #'RSAPublicKey'{} | integer() | #'ECPoint'{}, public_key_params()}.
-type tls_handshake_history() :: {[binary()], [binary()]}.
-define(NO_PROTOCOL, <<>>).
@@ -102,6 +102,8 @@
renegotiation_info,
srp, % srp username to send
hash_signs, % supported combinations of hashes/signature algos
+ ec_point_formats, % supported ec point formats
+ elliptic_curves, % supported elliptic curver
next_protocol_negotiation = undefined % [binary()]
}).
@@ -113,6 +115,8 @@
compression_method, % compression_method
renegotiation_info,
hash_signs, % supported combinations of hashes/signature algos
+ ec_point_formats, % supported ec point formats
+ elliptic_curves, % supported elliptic curver
next_protocol_negotiation = undefined % [binary()]
}).
@@ -130,6 +134,7 @@
-define(KEY_EXCHANGE_RSA, 0).
-define(KEY_EXCHANGE_DIFFIE_HELLMAN, 1).
+-define(KEY_EXCHANGE_EC_DIFFIE_HELLMAN, 6).
-define(KEY_EXCHANGE_PSK, 2).
-define(KEY_EXCHANGE_DHE_PSK, 3).
-define(KEY_EXCHANGE_RSA_PSK, 4).
@@ -146,6 +151,11 @@
dh_y %% opaque DH_Ys<1..2^16-1>
}).
+-record(server_ecdh_params, {
+ curve,
+ public %% opaque encoded ECpoint
+ }).
+
-record(server_psk_params, {
hint
}).
@@ -195,6 +205,9 @@
-define(DSS_SIGN, 2).
-define(RSA_FIXED_DH, 3).
-define(DSS_FIXED_DH, 4).
+-define(ECDSA_SIGN, 64).
+-define(RSA_FIXED_ECDH, 65).
+-define(ECDSA_FIXED_ECDH, 66).
% opaque DistinguishedName<1..2^16-1>;
@@ -231,6 +244,10 @@
dh_public
}).
+-record(client_ec_diffie_hellman_public, {
+ dh_public
+ }).
+
-record(client_psk_identity, {
identity
}).
@@ -304,6 +321,33 @@
-record(next_protocol, {selected_protocol}).
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%% ECC Extensions RFC 4492 section 4 and 5
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+-define(ELLIPTIC_CURVES_EXT, 10).
+-define(EC_POINT_FORMATS_EXT, 11).
+
+-record(elliptic_curves, {
+ elliptic_curve_list
+ }).
+
+-record(ec_point_formats, {
+ ec_point_format_list
+ }).
+
+-define(ECPOINT_UNCOMPRESSED, 0).
+-define(ECPOINT_ANSIX962_COMPRESSED_PRIME, 1).
+-define(ECPOINT_ANSIX962_COMPRESSED_CHAR2, 2).
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%% ECC RFC 4492 Handshake Messages, Section 5
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+-define(EXPLICIT_PRIME, 1).
+-define(EXPLICIT_CHAR2, 2).
+-define(NAMED_CURVE, 3).
+
-endif. % -ifdef(ssl_handshake).
diff --git a/lib/ssl/src/ssl_internal.hrl b/lib/ssl/src/ssl_internal.hrl
index 96a1c8e1ce..14db4a6067 100644
--- a/lib/ssl/src/ssl_internal.hrl
+++ b/lib/ssl/src/ssl_internal.hrl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2007-2012. All Rights Reserved.
+%% Copyright Ericsson AB 2007-2013. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -37,9 +37,9 @@
-type tls_atom_version() :: sslv3 | tlsv1 | 'tlsv1.1' | 'tlsv1.2'.
-type certdb_ref() :: reference().
-type db_handle() :: term().
--type key_algo() :: null | rsa | dhe_rsa | dhe_dss | dh_anon.
+-type key_algo() :: null | rsa | dhe_rsa | dhe_dss | ecdhe_ecdsa| ecdh_ecdsa | ecdh_rsa| srp_rsa| srp_dss | psk | dhe_psk | rsa_psk | dh_anon | ecdh_anon | srp_anon.
-type der_cert() :: binary().
--type private_key() :: #'RSAPrivateKey'{} | #'DSAPrivateKey'{}.
+-type private_key() :: #'RSAPrivateKey'{} | #'DSAPrivateKey'{} | #'ECPrivateKey'{}.
-type issuer() :: tuple().
-type serialnumber() :: integer().
-type cert_key() :: {reference(), integer(), issuer()}.
diff --git a/lib/ssl/src/ssl_manager.erl b/lib/ssl/src/ssl_manager.erl
index aa9da65bb8..caea528a08 100644
--- a/lib/ssl/src/ssl_manager.erl
+++ b/lib/ssl/src/ssl_manager.erl
@@ -103,7 +103,7 @@ connection_init(Trustedcerts, Role) ->
%% Description: Cach a pem file and return its content.
%%--------------------------------------------------------------------
cache_pem_file(File, DbHandle) ->
- MD5 = crypto:md5(File),
+ MD5 = crypto:hash(md5, File),
case ssl_certificate_db:lookup_cached_pem(DbHandle, MD5) of
[{Content,_}] ->
{ok, Content};
@@ -468,7 +468,7 @@ new_id(Port, Tries, Cache, CacheCb) ->
clean_cert_db(Ref, CertDb, RefDb, PemCache, File) ->
case ssl_certificate_db:ref_count(Ref, RefDb, 0) of
0 ->
- MD5 = crypto:md5(File),
+ MD5 = crypto:hash(md5, File),
case ssl_certificate_db:lookup_cached_pem(PemCache, MD5) of
[{Content, Ref}] ->
ssl_certificate_db:insert(MD5, Content, PemCache);
diff --git a/lib/ssl/src/ssl_record.erl b/lib/ssl/src/ssl_record.erl
index 26aca56739..50b1b2cda9 100644
--- a/lib/ssl/src/ssl_record.erl
+++ b/lib/ssl/src/ssl_record.erl
@@ -712,12 +712,4 @@ mac_hash({3, N} = Version, MacAlg, MacSecret, SeqNo, Type, Length, Fragment)
Length, Fragment).
sufficient_tlsv1_2_crypto_support() ->
- Data = "Sampl",
- Data2 = "e #1",
- Key = <<0,1,2,3,16,17,18,19,32,33,34,35,48,49,50,51,4,5,6,7,20,21,22,23,36,37,38,39,
- 52,53,54,55,8,9,10,11,24,25,26,27,40,41,42,43,56,57,58,59>>,
- try
- crypto:sha256_mac(Key, lists:flatten([Data, Data2])),
- true
- catch _:_ -> false
- end.
+ proplists:get_bool(sha256, crypto:algorithms()).
diff --git a/lib/ssl/src/ssl_ssl3.erl b/lib/ssl/src/ssl_ssl3.erl
index a11c5b8c0c..013c27ebb5 100644
--- a/lib/ssl/src/ssl_ssl3.erl
+++ b/lib/ssl/src/ssl_ssl3.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2007-2012. All Rights Reserved.
+%% Copyright Ericsson AB 2007-2013. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -154,9 +154,9 @@ suites() ->
%%--------------------------------------------------------------------
hash(?MD5, Data) ->
- crypto:md5(Data);
+ crypto:hash(md5, Data);
hash(?SHA, Data) ->
- crypto:sha(Data).
+ crypto:hash(sha, Data).
%%pad_1(?NULL) ->
%% "";
@@ -198,6 +198,6 @@ gen(_Secret, _All, Wanted, Len, _C, _N, Acc) when Wanted =< Len ->
Block;
gen(Secret, All, Wanted, Len, C, N, Acc) ->
Prefix = lists:duplicate(N, C),
- SHA = crypto:sha([Prefix, All]),
- MD5 = crypto:md5([Secret, SHA]),
+ SHA = crypto:hash(sha, [Prefix, All]),
+ MD5 = crypto:hash(md5, [Secret, SHA]),
gen(Secret, All, Wanted, Len + 16, C+1, N+1, [MD5 | Acc]).
diff --git a/lib/ssl/src/ssl_tls1.erl b/lib/ssl/src/ssl_tls1.erl
index 41dc1bf0dc..f8fd9efd07 100644
--- a/lib/ssl/src/ssl_tls1.erl
+++ b/lib/ssl/src/ssl_tls1.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2007-2012. All Rights Reserved.
+%% Copyright Ericsson AB 2007-2013. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -29,7 +29,8 @@
-include("ssl_record.hrl").
-export([master_secret/4, finished/5, certificate_verify/3, mac_hash/7,
- setup_keys/8, suites/1, prf/5]).
+ setup_keys/8, suites/1, prf/5,
+ ecc_curves/1, oid_to_enum/1, enum_to_oid/1]).
%%====================================================================
%% Internal application API
@@ -57,8 +58,8 @@ finished(Role, Version, PrfAlgo, MasterSecret, Handshake)
%% verify_data
%% PRF(master_secret, finished_label, MD5(handshake_messages) +
%% SHA-1(handshake_messages)) [0..11];
- MD5 = crypto:md5(Handshake),
- SHA = crypto:sha(Handshake),
+ MD5 = crypto:hash(md5, Handshake),
+ SHA = crypto:hash(sha, Handshake),
prf(?MD5SHA, MasterSecret, finished_label(Role), [MD5, SHA], 12);
finished(Role, Version, PrfAlgo, MasterSecret, Handshake)
@@ -76,8 +77,8 @@ finished(Role, Version, PrfAlgo, MasterSecret, Handshake)
-spec certificate_verify(md5sha | sha, integer(), [binary()]) -> binary().
certificate_verify(md5sha, _Version, Handshake) ->
- MD5 = crypto:md5(Handshake),
- SHA = crypto:sha(Handshake),
+ MD5 = crypto:hash(md5, Handshake),
+ SHA = crypto:hash(sha, Handshake),
<<MD5/binary, SHA/binary>>;
certificate_verify(HashAlgo, _Version, Handshake) ->
@@ -184,27 +185,56 @@ mac_hash(Method, Mac_write_secret, Seq_num, Type, {Major, Minor},
suites(Minor) when Minor == 1; Minor == 2->
[
+ ?TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA,
+ ?TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA,
?TLS_DHE_RSA_WITH_AES_256_CBC_SHA,
?TLS_DHE_DSS_WITH_AES_256_CBC_SHA,
+ ?TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA,
+ ?TLS_ECDH_RSA_WITH_AES_256_CBC_SHA,
?TLS_RSA_WITH_AES_256_CBC_SHA,
+
+ ?TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA,
+ ?TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA,
?TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA,
?TLS_DHE_DSS_WITH_3DES_EDE_CBC_SHA,
+ ?TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA,
+ ?TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA,
?TLS_RSA_WITH_3DES_EDE_CBC_SHA,
+
+ ?TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA,
+ ?TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA,
?TLS_DHE_RSA_WITH_AES_128_CBC_SHA,
?TLS_DHE_DSS_WITH_AES_128_CBC_SHA,
+ ?TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA,
+ ?TLS_ECDH_RSA_WITH_AES_128_CBC_SHA,
?TLS_RSA_WITH_AES_128_CBC_SHA,
%%?TLS_RSA_WITH_IDEA_CBC_SHA,
+ ?TLS_ECDHE_ECDSA_WITH_RC4_128_SHA,
+ ?TLS_ECDHE_RSA_WITH_RC4_128_SHA,
?TLS_RSA_WITH_RC4_128_SHA,
?TLS_RSA_WITH_RC4_128_MD5,
?TLS_DHE_RSA_WITH_DES_CBC_SHA,
+ ?TLS_ECDH_ECDSA_WITH_RC4_128_SHA,
+ ?TLS_ECDH_RSA_WITH_RC4_128_SHA,
?TLS_RSA_WITH_DES_CBC_SHA
];
suites(Minor) when Minor == 3 ->
[
+ ?TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384,
+ ?TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384,
+ ?TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA384,
+ ?TLS_ECDH_RSA_WITH_AES_256_CBC_SHA384,
+
?TLS_DHE_RSA_WITH_AES_256_CBC_SHA256,
?TLS_DHE_DSS_WITH_AES_256_CBC_SHA256,
?TLS_RSA_WITH_AES_256_CBC_SHA256,
+
+ ?TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256,
+ ?TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256,
+ ?TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA256,
+ ?TLS_ECDH_RSA_WITH_AES_128_CBC_SHA256,
+
?TLS_DHE_RSA_WITH_AES_128_CBC_SHA256,
?TLS_DHE_DSS_WITH_AES_128_CBC_SHA256,
?TLS_RSA_WITH_AES_128_CBC_SHA256
@@ -218,16 +248,8 @@ suites(Minor) when Minor == 3 ->
%%%% HMAC and the Pseudorandom Functions RFC 2246 & 4346 - 5.%%%%
hmac_hash(?NULL, _, _) ->
<<>>;
-hmac_hash(?MD5, Key, Value) ->
- crypto:md5_mac(Key, Value);
-hmac_hash(?SHA, Key, Value) ->
- crypto:sha_mac(Key, Value);
-hmac_hash(?SHA256, Key, Value) ->
- crypto:sha256_mac(Key, Value);
-hmac_hash(?SHA384, Key, Value) ->
- crypto:sha384_mac(Key, Value);
-hmac_hash(?SHA512, Key, Value) ->
- crypto:sha512_mac(Key, Value).
+hmac_hash(Alg, Key, Value) ->
+ crypto:hmac(mac_algo(Alg), Key, Value).
mac_algo(?MD5) -> md5;
mac_algo(?SHA) -> sha;
@@ -303,3 +325,64 @@ finished_label(client) ->
<<"client finished">>;
finished_label(server) ->
<<"server finished">>.
+
+%% list ECC curves in prefered order
+ecc_curves(_Minor) ->
+ [?sect571r1,?sect571k1,?secp521r1,?sect409k1,?sect409r1,
+ ?secp384r1,?sect283k1,?sect283r1,?secp256k1,?secp256r1,
+ ?sect239k1,?sect233k1,?sect233r1,?secp224k1,?secp224r1,
+ ?sect193r1,?sect193r2,?secp192k1,?secp192r1,?sect163k1,
+ ?sect163r1,?sect163r2,?secp160k1,?secp160r1,?secp160r2].
+
+%% ECC curves from draft-ietf-tls-ecc-12.txt (Oct. 17, 2005)
+oid_to_enum(?sect163k1) -> 1;
+oid_to_enum(?sect163r1) -> 2;
+oid_to_enum(?sect163r2) -> 3;
+oid_to_enum(?sect193r1) -> 4;
+oid_to_enum(?sect193r2) -> 5;
+oid_to_enum(?sect233k1) -> 6;
+oid_to_enum(?sect233r1) -> 7;
+oid_to_enum(?sect239k1) -> 8;
+oid_to_enum(?sect283k1) -> 9;
+oid_to_enum(?sect283r1) -> 10;
+oid_to_enum(?sect409k1) -> 11;
+oid_to_enum(?sect409r1) -> 12;
+oid_to_enum(?sect571k1) -> 13;
+oid_to_enum(?sect571r1) -> 14;
+oid_to_enum(?secp160k1) -> 15;
+oid_to_enum(?secp160r1) -> 16;
+oid_to_enum(?secp160r2) -> 17;
+oid_to_enum(?secp192k1) -> 18;
+oid_to_enum(?secp192r1) -> 19;
+oid_to_enum(?secp224k1) -> 20;
+oid_to_enum(?secp224r1) -> 21;
+oid_to_enum(?secp256k1) -> 22;
+oid_to_enum(?secp256r1) -> 23;
+oid_to_enum(?secp384r1) -> 24;
+oid_to_enum(?secp521r1) -> 25.
+
+enum_to_oid(1) -> ?sect163k1;
+enum_to_oid(2) -> ?sect163r1;
+enum_to_oid(3) -> ?sect163r2;
+enum_to_oid(4) -> ?sect193r1;
+enum_to_oid(5) -> ?sect193r2;
+enum_to_oid(6) -> ?sect233k1;
+enum_to_oid(7) -> ?sect233r1;
+enum_to_oid(8) -> ?sect239k1;
+enum_to_oid(9) -> ?sect283k1;
+enum_to_oid(10) -> ?sect283r1;
+enum_to_oid(11) -> ?sect409k1;
+enum_to_oid(12) -> ?sect409r1;
+enum_to_oid(13) -> ?sect571k1;
+enum_to_oid(14) -> ?sect571r1;
+enum_to_oid(15) -> ?secp160k1;
+enum_to_oid(16) -> ?secp160r1;
+enum_to_oid(17) -> ?secp160r2;
+enum_to_oid(18) -> ?secp192k1;
+enum_to_oid(19) -> ?secp192r1;
+enum_to_oid(20) -> ?secp224k1;
+enum_to_oid(21) -> ?secp224r1;
+enum_to_oid(22) -> ?secp256k1;
+enum_to_oid(23) -> ?secp256r1;
+enum_to_oid(24) -> ?secp384r1;
+enum_to_oid(25) -> ?secp521r1.
diff --git a/lib/ssl/test/erl_make_certs.erl b/lib/ssl/test/erl_make_certs.erl
index 71aa985c4f..723ccf4496 100644
--- a/lib/ssl/test/erl_make_certs.erl
+++ b/lib/ssl/test/erl_make_certs.erl
@@ -45,7 +45,7 @@
%% {dnQualifer, DnQ}
%% issuer = {Issuer, IssuerKey} true (i.e. a ca cert is created)
%% (obs IssuerKey migth be {Key, Password}
-%% key = KeyFile|KeyBin|rsa|dsa Subject PublicKey rsa or dsa generates key
+%% key = KeyFile|KeyBin|rsa|dsa|ec Subject PublicKey rsa, dsa or ec generates key
%%
%%
%% (OBS: The generated keys are for testing only)
@@ -91,6 +91,16 @@ gen_dsa(LSize,NSize) when is_integer(LSize), is_integer(NSize) ->
{Key, encode_key(Key)}.
%%--------------------------------------------------------------------
+%% @doc Creates a ec key (OBS: for testing only)
+%% the sizes are in bytes
+%% @spec (::integer()) -> {::atom(), ::binary(), ::opaque()}
+%% @end
+%%--------------------------------------------------------------------
+gen_ec(Curve) when is_atom(Curve) ->
+ Key = gen_ec2(Curve),
+ {Key, encode_key(Key)}.
+
+%%--------------------------------------------------------------------
%% @doc Verifies cert signatures
%% @spec (::binary(), ::tuple()) -> ::boolean()
%% @end
@@ -102,7 +112,10 @@ verify_signature(DerEncodedCert, DerKey, _KeyParams) ->
public_key:pkix_verify(DerEncodedCert,
#'RSAPublicKey'{modulus=Mod, publicExponent=Exp});
#'DSAPrivateKey'{p=P, q=Q, g=G, y=Y} ->
- public_key:pkix_verify(DerEncodedCert, {Y, #'Dss-Parms'{p=P, q=Q, g=G}})
+ public_key:pkix_verify(DerEncodedCert, {Y, #'Dss-Parms'{p=P, q=Q, g=G}});
+ #'ECPrivateKey'{version = _Version, privateKey = _PrivKey,
+ parameters = Params, publicKey = {0, PubKey}} ->
+ public_key:pkix_verify(DerEncodedCert, {#'ECPoint'{point = PubKey}, Params})
end.
%%%%%%%%%%%%%%%%%%%%%%%%% Implementation %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
@@ -112,6 +125,7 @@ get_key(Opts) ->
undefined -> make_key(rsa, Opts);
rsa -> make_key(rsa, Opts);
dsa -> make_key(dsa, Opts);
+ ec -> make_key(ec, Opts);
Key ->
Password = proplists:get_value(password, Opts, no_passwd),
decode_key(Key, Password)
@@ -129,6 +143,8 @@ decode_key(#'RSAPrivateKey'{} = Key,_) ->
Key;
decode_key(#'DSAPrivateKey'{} = Key,_) ->
Key;
+decode_key(#'ECPrivateKey'{} = Key,_) ->
+ Key;
decode_key(PemEntry = {_,_,_}, Pw) ->
public_key:pem_entry_decode(PemEntry, Pw);
decode_key(PemBin, Pw) ->
@@ -140,7 +156,10 @@ encode_key(Key = #'RSAPrivateKey'{}) ->
{'RSAPrivateKey', Der, not_encrypted};
encode_key(Key = #'DSAPrivateKey'{}) ->
{ok, Der} = 'OTP-PUB-KEY':encode('DSAPrivateKey', Key),
- {'DSAPrivateKey', Der, not_encrypted}.
+ {'DSAPrivateKey', Der, not_encrypted};
+encode_key(Key = #'ECPrivateKey'{}) ->
+ {ok, Der} = 'OTP-PUB-KEY':encode('ECPrivateKey', Key),
+ {'ECPrivateKey', Der, not_encrypted}.
make_tbs(SubjectKey, Opts) ->
Version = list_to_atom("v"++integer_to_list(proplists:get_value(version, Opts, 3))),
@@ -277,7 +296,14 @@ publickey(#'RSAPrivateKey'{modulus=N, publicExponent=E}) ->
publickey(#'DSAPrivateKey'{p=P, q=Q, g=G, y=Y}) ->
Algo = #'PublicKeyAlgorithm'{algorithm= ?'id-dsa',
parameters={params, #'Dss-Parms'{p=P, q=Q, g=G}}},
- #'OTPSubjectPublicKeyInfo'{algorithm = Algo, subjectPublicKey = Y}.
+ #'OTPSubjectPublicKeyInfo'{algorithm = Algo, subjectPublicKey = Y};
+publickey(#'ECPrivateKey'{version = _Version,
+ privateKey = _PrivKey,
+ parameters = Params,
+ publicKey = {0, PubKey}}) ->
+ Algo = #'PublicKeyAlgorithm'{algorithm= ?'id-ecPublicKey', parameters=Params},
+ #'OTPSubjectPublicKeyInfo'{algorithm = Algo,
+ subjectPublicKey = #'ECPoint'{point = PubKey}}.
validity(Opts) ->
DefFrom0 = calendar:gregorian_days_to_date(calendar:date_to_gregorian_days(date())-1),
@@ -298,13 +324,24 @@ sign_algorithm(#'RSAPrivateKey'{}, Opts) ->
end,
{Type, 'NULL'};
sign_algorithm(#'DSAPrivateKey'{p=P, q=Q, g=G}, _Opts) ->
- {?'id-dsa-with-sha1', {params,#'Dss-Parms'{p=P, q=Q, g=G}}}.
+ {?'id-dsa-with-sha1', {params,#'Dss-Parms'{p=P, q=Q, g=G}}};
+sign_algorithm(#'ECPrivateKey'{}, Opts) ->
+ Type = case proplists:get_value(digest, Opts, sha1) of
+ sha1 -> ?'ecdsa-with-SHA1';
+ sha512 -> ?'ecdsa-with-SHA512';
+ sha384 -> ?'ecdsa-with-SHA384';
+ sha256 -> ?'ecdsa-with-SHA256'
+ end,
+ {Type, 'NULL'}.
make_key(rsa, _Opts) ->
%% (OBS: for testing only)
gen_rsa2(64);
make_key(dsa, _Opts) ->
- gen_dsa2(128, 20). %% Bytes i.e. {1024, 160}
+ gen_dsa2(128, 20); %% Bytes i.e. {1024, 160}
+make_key(ec, _Opts) ->
+ %% (OBS: for testing only)
+ gen_ec2(secp256k1).
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%% RSA key generation (OBS: for testing only)
@@ -363,6 +400,22 @@ gen_dsa2(LSize, NSize) ->
#'DSAPrivateKey'{version=0, p=P, q=Q, g=G, y=Y, x=X}
end.
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%% EC key generation (OBS: for testing only)
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+int2list(I) ->
+ L = (length(integer_to_list(I, 16)) + 1) div 2,
+ binary_to_list(<<I:(L*8)>>).
+
+gen_ec2(CurveId) ->
+ {PrivKey, PubKey} = crypto:generate_key(ecdh, CurveId),
+
+ #'ECPrivateKey'{version = 1,
+ privateKey = int2list(PrivKey),
+ parameters = {namedCurve, pubkey_cert_records:namedCurves(CurveId)},
+ publicKey = {0, PubKey}}.
+
%% See fips_186-3.pdf
dsa_search(T, P0, Q, Iter) when Iter > 0 ->
P = 2*T*Q*P0 + 1,
diff --git a/lib/ssl/test/ssl_basic_SUITE.erl b/lib/ssl/test/ssl_basic_SUITE.erl
index 5cedde5d27..165a8a5fcc 100644
--- a/lib/ssl/test/ssl_basic_SUITE.erl
+++ b/lib/ssl/test/ssl_basic_SUITE.erl
@@ -69,6 +69,7 @@ groups() ->
{session, [], session_tests()},
{renegotiate, [], renegotiate_tests()},
{ciphers, [], cipher_tests()},
+ {ciphers_ec, [], cipher_tests_ec()},
{error_handling_tests, [], error_handling_tests()}
].
@@ -76,6 +77,7 @@ all_versions_groups ()->
[{group, api},
{group, renegotiate},
{group, ciphers},
+ {group, ciphers_ec},
{group, error_handling_tests}].
@@ -156,10 +158,19 @@ cipher_tests() ->
anonymous_cipher_suites,
psk_cipher_suites,
psk_with_hint_cipher_suites,
+ psk_anon_cipher_suites,
+ psk_anon_with_hint_cipher_suites,
srp_cipher_suites,
+ srp_anon_cipher_suites,
srp_dsa_cipher_suites,
default_reject_anonymous].
+cipher_tests_ec() ->
+ [ciphers_ecdsa_signed_certs,
+ ciphers_ecdsa_signed_certs_openssl_names,
+ ciphers_ecdh_rsa_signed_certs,
+ ciphers_ecdh_rsa_signed_certs_openssl_names].
+
error_handling_tests()->
[controller_dies,
client_closes_socket,
@@ -185,10 +196,12 @@ init_per_suite(Config0) ->
Result =
(catch make_certs:all(?config(data_dir, Config0),
?config(priv_dir, Config0))),
- ct:print("Make certs ~p~n", [Result]),
+ ct:log("Make certs ~p~n", [Result]),
Config1 = ssl_test_lib:make_dsa_cert(Config0),
- Config = ssl_test_lib:cert_options(Config1),
+ Config2 = ssl_test_lib:make_ecdsa_cert(Config1),
+ Config3 = ssl_test_lib:make_ecdh_rsa_cert(Config2),
+ Config = ssl_test_lib:cert_options(Config3),
[{watchdog, Dog} | Config]
catch _:_ ->
{skip, "Crypto did not start"}
@@ -253,7 +266,7 @@ init_per_testcase(empty_protocol_versions, Config) ->
%% ssl_test_lib:make_mix_cert(Config0);
init_per_testcase(_TestCase, Config0) ->
- ct:print("TLS/SSL version ~p~n ", [ssl_record:supported_protocol_versions()]),
+ ct:log("TLS/SSL version ~p~n ", [ssl_record:supported_protocol_versions()]),
Config = lists:keydelete(watchdog, 1, Config0),
Dog = ct:timetrap(?TIMEOUT),
[{watchdog, Dog} | Config].
@@ -316,7 +329,7 @@ connection_info(Config) when is_list(Config) ->
[{ciphers,[{rsa,rc4_128,sha,no_export}]} |
ClientOpts]}]),
- ct:print("Testcase ~p, Client ~p Server ~p ~n",
+ ct:log("Testcase ~p, Client ~p Server ~p ~n",
[self(), Client, Server]),
Version =
@@ -369,7 +382,7 @@ controlling_process(Config) when is_list(Config) ->
ClientMsg]}},
{options, ClientOpts}]),
- ct:print("Testcase ~p, Client ~p Server ~p ~n",
+ ct:log("Testcase ~p, Client ~p Server ~p ~n",
[self(), Client, Server]),
receive
@@ -419,7 +432,7 @@ controller_dies(Config) when is_list(Config) ->
ClientMsg]}},
{options, ClientOpts}]),
- ct:print("Testcase ~p, Client ~p Server ~p ~n", [self(), Client, Server]),
+ ct:log("Testcase ~p, Client ~p Server ~p ~n", [self(), Client, Server]),
ct:sleep(?SLEEP), %% so that they are connected
process_flag(trap_exit, true),
@@ -457,12 +470,12 @@ controller_dies(Config) when is_list(Config) ->
Client3 ! die_nice
end,
- ct:print("Wating on exit ~p~n",[Client3]),
+ ct:log("Wating on exit ~p~n",[Client3]),
receive {'EXIT', Client3, normal} -> ok end,
receive %% Client3 is dead but that doesn't matter, socket should not be closed.
Unexpected ->
- ct:print("Unexpected ~p~n",[Unexpected]),
+ ct:log("Unexpected ~p~n",[Unexpected]),
ct:fail({line, ?LINE-1})
after 1000 ->
ok
@@ -593,7 +606,7 @@ peername(Config) when is_list(Config) ->
ServerMsg = {ok, {ClientIp, ClientPort}},
ClientMsg = {ok, {ServerIp, Port}},
- ct:print("Testcase ~p, Client ~p Server ~p ~n",
+ ct:log("Testcase ~p, Client ~p Server ~p ~n",
[self(), Client, Server]),
ssl_test_lib:check_result(Server, ServerMsg, Client, ClientMsg),
@@ -626,7 +639,7 @@ peercert(Config) when is_list(Config) ->
ServerMsg = {error, no_peercert},
ClientMsg = {ok, BinCert},
- ct:print("Testcase ~p, Client ~p Server ~p ~n",
+ ct:log("Testcase ~p, Client ~p Server ~p ~n",
[self(), Client, Server]),
ssl_test_lib:check_result(Server, ServerMsg, Client, ClientMsg),
@@ -664,7 +677,7 @@ peercert_with_client_cert(Config) when is_list(Config) ->
ServerMsg = {ok, ClientBinCert},
ClientMsg = {ok, ServerBinCert},
- ct:print("Testcase ~p, Client ~p Server ~p ~n",
+ ct:log("Testcase ~p, Client ~p Server ~p ~n",
[self(), Client, Server]),
ssl_test_lib:check_result(Server, ServerMsg, Client, ClientMsg),
@@ -696,7 +709,7 @@ sockname(Config) when is_list(Config) ->
ServerMsg = {ok, {ServerIp, Port}},
ClientMsg = {ok, {ClientIp, ClientPort}},
- ct:print("Testcase ~p, Client ~p Server ~p ~n",
+ ct:log("Testcase ~p, Client ~p Server ~p ~n",
[self(), Client, Server]),
ssl_test_lib:check_result(Server, ServerMsg, Client, ClientMsg),
@@ -769,7 +782,7 @@ socket_options_result(Socket, Options, DefaultValues, NewOptions, NewValues) ->
ssl:setopts(Socket, [{nodelay, true}]),
{ok,[{nodelay, true}]} = ssl:getopts(Socket, [nodelay]),
{ok, All} = ssl:getopts(Socket, []),
- ct:print("All opts ~p~n", [All]),
+ ct:log("All opts ~p~n", [All]),
ok.
@@ -792,7 +805,7 @@ invalid_inet_get_option(Config) when is_list(Config) ->
{mfa, {ssl_test_lib, no_result, []}},
{options, ClientOpts}]),
- ct:print("Testcase ~p, Client ~p Server ~p ~n",
+ ct:log("Testcase ~p, Client ~p Server ~p ~n",
[self(), Client, Server]),
ssl_test_lib:check_result(Server, ok),
@@ -818,7 +831,7 @@ invalid_inet_get_option_not_list(Config) when is_list(Config) ->
{mfa, {ssl_test_lib, no_result, []}},
{options, ClientOpts}]),
- ct:print("Testcase ~p, Client ~p Server ~p ~n",
+ ct:log("Testcase ~p, Client ~p Server ~p ~n",
[self(), Client, Server]),
ssl_test_lib:check_result(Server, ok),
@@ -850,7 +863,7 @@ invalid_inet_get_option_improper_list(Config) when is_list(Config) ->
{mfa, {ssl_test_lib, no_result, []}},
{options, ClientOpts}]),
- ct:print("Testcase ~p, Client ~p Server ~p ~n",
+ ct:log("Testcase ~p, Client ~p Server ~p ~n",
[self(), Client, Server]),
ssl_test_lib:check_result(Server, ok),
@@ -881,7 +894,7 @@ invalid_inet_set_option(Config) when is_list(Config) ->
{mfa, {ssl_test_lib, no_result, []}},
{options, ClientOpts}]),
- ct:print("Testcase ~p, Client ~p Server ~p ~n",
+ ct:log("Testcase ~p, Client ~p Server ~p ~n",
[self(), Client, Server]),
ssl_test_lib:check_result(Server, ok),
@@ -913,7 +926,7 @@ invalid_inet_set_option_not_list(Config) when is_list(Config) ->
{mfa, {ssl_test_lib, no_result, []}},
{options, ClientOpts}]),
- ct:print("Testcase ~p, Client ~p Server ~p ~n",
+ ct:log("Testcase ~p, Client ~p Server ~p ~n",
[self(), Client, Server]),
ssl_test_lib:check_result(Server, ok),
@@ -945,7 +958,7 @@ invalid_inet_set_option_improper_list(Config) when is_list(Config) ->
{mfa, {ssl_test_lib, no_result, []}},
{options, ClientOpts}]),
- ct:print("Testcase ~p, Client ~p Server ~p ~n",
+ ct:log("Testcase ~p, Client ~p Server ~p ~n",
[self(), Client, Server]),
ssl_test_lib:check_result(Server, ok),
@@ -986,7 +999,7 @@ misc_ssl_options(Config) when is_list(Config) ->
{mfa, {ssl_test_lib, send_recv_result_active, []}},
{options, TestOpts ++ ClientOpts}]),
- ct:print("Testcase ~p, Client ~p Server ~p ~n",
+ ct:log("Testcase ~p, Client ~p Server ~p ~n",
[self(), Client, Server]),
ssl_test_lib:check_result(Server, ok, Client, ok),
@@ -999,7 +1012,7 @@ versions() ->
versions(Config) when is_list(Config) ->
[_|_] = Versions = ssl:versions(),
- ct:print("~p~n", [Versions]).
+ ct:log("~p~n", [Versions]).
%%--------------------------------------------------------------------
send_recv() ->
@@ -1021,7 +1034,7 @@ send_recv(Config) when is_list(Config) ->
{mfa, {ssl_test_lib, send_recv_result, []}},
{options, [{active, false} | ClientOpts]}]),
- ct:print("Testcase ~p, Client ~p Server ~p ~n",
+ ct:log("Testcase ~p, Client ~p Server ~p ~n",
[self(), Client, Server]),
ssl_test_lib:check_result(Server, ok, Client, ok),
@@ -1047,7 +1060,7 @@ send_close(Config) when is_list(Config) ->
{ok, SslS} = rpc:call(ClientNode, ssl, connect,
[TcpS,[{active, false}|ClientOpts]]),
- ct:print("Testcase ~p, Client ~p Server ~p ~n",
+ ct:log("Testcase ~p, Client ~p Server ~p ~n",
[self(), self(), Server]),
ok = ssl:send(SslS, "Hello world"),
{ok,<<"Hello world">>} = ssl:recv(SslS, 11),
@@ -1132,7 +1145,7 @@ upgrade(Config) when is_list(Config) ->
{tcp_options, TcpOpts},
{ssl_options, ClientOpts}]),
- ct:print("Testcase ~p, Client ~p Server ~p ~n",
+ ct:log("Testcase ~p, Client ~p Server ~p ~n",
[self(), Client, Server]),
ssl_test_lib:check_result(Server, ok, Client, ok),
@@ -1182,7 +1195,7 @@ upgrade_with_timeout(Config) when is_list(Config) ->
{tcp_options, TcpOpts},
{ssl_options, ClientOpts}]),
- ct:print("Testcase ~p, Client ~p Server ~p ~n",
+ ct:log("Testcase ~p, Client ~p Server ~p ~n",
[self(), Client, Server]),
ssl_test_lib:check_result(Server, ok, Client, ok),
@@ -1208,14 +1221,14 @@ tcp_connect(Config) when is_list(Config) ->
Port = ssl_test_lib:inet_port(Server),
{ok, Socket} = gen_tcp:connect(Hostname, Port, [binary, {packet, 0}]),
- ct:print("Testcase ~p connected to Server ~p ~n", [self(), Server]),
+ ct:log("Testcase ~p connected to Server ~p ~n", [self(), Server]),
gen_tcp:send(Socket, "<SOME GARBLED NON SSL MESSAGE>"),
receive
{tcp_closed, Socket} ->
receive
{Server, {error, Error}} ->
- ct:print("Error ~p", [Error])
+ ct:log("Error ~p", [Error])
end
end.
%%--------------------------------------------------------------------
@@ -1236,7 +1249,7 @@ tcp_connect_big(Config) when is_list(Config) ->
Port = ssl_test_lib:inet_port(Server),
{ok, Socket} = gen_tcp:connect(Hostname, Port, [binary, {packet, 0}]),
- ct:print("Testcase ~p connected to Server ~p ~n", [self(), Server]),
+ ct:log("Testcase ~p connected to Server ~p ~n", [self(), Server]),
Rand = crypto:rand_bytes(?MAX_CIPHER_TEXT_LENGTH+1),
gen_tcp:send(Socket, <<?BYTE(0),
@@ -1248,7 +1261,7 @@ tcp_connect_big(Config) when is_list(Config) ->
{Server, {error, timeout}} ->
ct:fail("hangs");
{Server, {error, Error}} ->
- ct:print("Error ~p", [Error])
+ ct:log("Error ~p", [Error])
end
end.
@@ -1278,7 +1291,7 @@ ipv6(Config) when is_list(Config) ->
{options,
[inet6, {active, false} | ClientOpts]}]),
- ct:print("Testcase ~p, Client ~p Server ~p ~n",
+ ct:log("Testcase ~p, Client ~p Server ~p ~n",
[self(), Client, Server]),
ssl_test_lib:check_result(Server, ok, Client, ok),
@@ -1536,8 +1549,8 @@ ciphers_rsa_signed_certs(Config) when is_list(Config) ->
Version =
ssl_record:protocol_version(ssl_record:highest_protocol_version([])),
- Ciphers = ssl_test_lib:rsa_suites(),
- ct:print("~p erlang cipher suites ~p~n", [Version, Ciphers]),
+ Ciphers = ssl_test_lib:rsa_suites(erlang),
+ ct:log("~p erlang cipher suites ~p~n", [Version, Ciphers]),
run_suites(Ciphers, Version, Config, rsa).
%%-------------------------------------------------------------------
ciphers_rsa_signed_certs_openssl_names() ->
@@ -1547,7 +1560,7 @@ ciphers_rsa_signed_certs_openssl_names(Config) when is_list(Config) ->
Version =
ssl_record:protocol_version(ssl_record:highest_protocol_version([])),
Ciphers = ssl_test_lib:openssl_rsa_suites(),
- ct:print("tls1 openssl cipher suites ~p~n", [Ciphers]),
+ ct:log("tls1 openssl cipher suites ~p~n", [Ciphers]),
run_suites(Ciphers, Version, Config, rsa).
%%-------------------------------------------------------------------
@@ -1559,7 +1572,7 @@ ciphers_dsa_signed_certs(Config) when is_list(Config) ->
ssl_record:protocol_version(ssl_record:highest_protocol_version([])),
Ciphers = ssl_test_lib:dsa_suites(),
- ct:print("~p erlang cipher suites ~p~n", [Version, Ciphers]),
+ ct:log("~p erlang cipher suites ~p~n", [Version, Ciphers]),
run_suites(Ciphers, Version, Config, dsa).
%%-------------------------------------------------------------------
ciphers_dsa_signed_certs_openssl_names() ->
@@ -1570,7 +1583,7 @@ ciphers_dsa_signed_certs_openssl_names(Config) when is_list(Config) ->
ssl_record:protocol_version(ssl_record:highest_protocol_version([])),
Ciphers = ssl_test_lib:openssl_dsa_suites(),
- ct:print("tls1 openssl cipher suites ~p~n", [Ciphers]),
+ ct:log("tls1 openssl cipher suites ~p~n", [Ciphers]),
run_suites(Ciphers, Version, Config, dsa).
%%-------------------------------------------------------------------
anonymous_cipher_suites()->
@@ -1594,6 +1607,20 @@ psk_with_hint_cipher_suites(Config) when is_list(Config) ->
Ciphers = ssl_test_lib:psk_suites(),
run_suites(Ciphers, Version, Config, psk_with_hint).
%%-------------------------------------------------------------------
+psk_anon_cipher_suites() ->
+ [{doc, "Test the anonymous PSK ciphersuites WITHOUT server supplied identity hint"}].
+psk_anon_cipher_suites(Config) when is_list(Config) ->
+ Version = ssl_record:protocol_version(ssl_record:highest_protocol_version([])),
+ Ciphers = ssl_test_lib:psk_anon_suites(),
+ run_suites(Ciphers, Version, Config, psk_anon).
+%%-------------------------------------------------------------------
+psk_anon_with_hint_cipher_suites()->
+ [{doc, "Test the anonymous PSK ciphersuites WITH server supplied identity hint"}].
+psk_anon_with_hint_cipher_suites(Config) when is_list(Config) ->
+ Version = ssl_record:protocol_version(ssl_record:highest_protocol_version([])),
+ Ciphers = ssl_test_lib:psk_anon_suites(),
+ run_suites(Ciphers, Version, Config, psk_anon_with_hint).
+%%-------------------------------------------------------------------
srp_cipher_suites()->
[{doc, "Test the SRP ciphersuites"}].
srp_cipher_suites(Config) when is_list(Config) ->
@@ -1601,6 +1628,13 @@ srp_cipher_suites(Config) when is_list(Config) ->
Ciphers = ssl_test_lib:srp_suites(),
run_suites(Ciphers, Version, Config, srp).
%%-------------------------------------------------------------------
+srp_anon_cipher_suites()->
+ [{doc, "Test the anonymous SRP ciphersuites"}].
+srp_anon_cipher_suites(Config) when is_list(Config) ->
+ Version = ssl_record:protocol_version(ssl_record:highest_protocol_version([])),
+ Ciphers = ssl_test_lib:srp_anon_suites(),
+ run_suites(Ciphers, Version, Config, srp_anon).
+%%-------------------------------------------------------------------
srp_dsa_cipher_suites()->
[{doc, "Test the SRP DSA ciphersuites"}].
srp_dsa_cipher_suites(Config) when is_list(Config) ->
@@ -1632,6 +1666,48 @@ default_reject_anonymous(Config) when is_list(Config) ->
Client, {error, {tls_alert, "insufficient security"}}).
%%--------------------------------------------------------------------
+ciphers_ecdsa_signed_certs() ->
+ [{doc, "Test all ecdsa ssl cipher suites in highest support ssl/tls version"}].
+
+ciphers_ecdsa_signed_certs(Config) when is_list(Config) ->
+ Version =
+ ssl_record:protocol_version(ssl_record:highest_protocol_version([])),
+
+ Ciphers = ssl_test_lib:ecdsa_suites(),
+ ct:log("~p erlang cipher suites ~p~n", [Version, Ciphers]),
+ run_suites(Ciphers, Version, Config, ecdsa).
+%%--------------------------------------------------------------------
+ciphers_ecdsa_signed_certs_openssl_names() ->
+ [{doc, "Test all ecdsa ssl cipher suites in highest support ssl/tls version"}].
+
+ciphers_ecdsa_signed_certs_openssl_names(Config) when is_list(Config) ->
+ Version =
+ ssl_record:protocol_version(ssl_record:highest_protocol_version([])),
+ Ciphers = ssl_test_lib:openssl_ecdsa_suites(),
+ ct:log("tls1 openssl cipher suites ~p~n", [Ciphers]),
+ run_suites(Ciphers, Version, Config, ecdsa).
+%%--------------------------------------------------------------------
+ciphers_ecdh_rsa_signed_certs() ->
+ [{doc, "Test all ecdh_rsa ssl cipher suites in highest support ssl/tls version"}].
+
+ciphers_ecdh_rsa_signed_certs(Config) when is_list(Config) ->
+ Version =
+ ssl_record:protocol_version(ssl_record:highest_protocol_version([])),
+
+ Ciphers = ssl_test_lib:ecdh_rsa_suites(),
+ ct:log("~p erlang cipher suites ~p~n", [Version, Ciphers]),
+ run_suites(Ciphers, Version, Config, ecdh_rsa).
+%%--------------------------------------------------------------------
+ciphers_ecdh_rsa_signed_certs_openssl_names() ->
+ [{doc, "Test all ecdh_rsa ssl cipher suites in highest support ssl/tls version"}].
+
+ciphers_ecdh_rsa_signed_certs_openssl_names(Config) when is_list(Config) ->
+ Version =
+ ssl_record:protocol_version(ssl_record:highest_protocol_version([])),
+ Ciphers = ssl_test_lib:openssl_ecdh_rsa_suites(),
+ ct:log("tls1 openssl cipher suites ~p~n", [Ciphers]),
+ run_suites(Ciphers, Version, Config, ecdh_rsa).
+%%--------------------------------------------------------------------
reuse_session() ->
[{doc,"Test reuse of sessions (short handshake)"}].
reuse_session(Config) when is_list(Config) ->
@@ -1670,7 +1746,7 @@ reuse_session(Config) when is_list(Config) ->
{Client1, SessionInfo} ->
ok;
{Client1, Other} ->
- ct:print("Expected: ~p, Unexpected: ~p~n",
+ ct:log("Expected: ~p, Unexpected: ~p~n",
[SessionInfo, Other]),
ct:fail(session_not_reused)
end,
@@ -1728,7 +1804,7 @@ reuse_session(Config) when is_list(Config) ->
ct:fail(
session_reused_when_session_reuse_disabled_by_server);
{Client4, _Other} ->
- ct:print("OTHER: ~p ~n", [_Other]),
+ ct:log("OTHER: ~p ~n", [_Other]),
ok
end,
@@ -1778,7 +1854,7 @@ reuse_session_expired(Config) when is_list(Config) ->
{Client1, SessionInfo} ->
ok;
{Client1, Other} ->
- ct:print("Expected: ~p, Unexpected: ~p~n",
+ ct:log("Expected: ~p, Unexpected: ~p~n",
[SessionInfo, Other]),
ct:fail(session_not_reused)
end,
@@ -2481,7 +2557,7 @@ connect_twice(Config) when is_list(Config) ->
{options, [{keepalive, true},{active, false}
| ClientOpts]}]),
- ct:print("Testcase ~p, Client ~p Server ~p ~n",
+ ct:log("Testcase ~p, Client ~p Server ~p ~n",
[self(), Client, Server]),
ssl_test_lib:check_result(Server, ok, Client, ok),
@@ -2827,9 +2903,9 @@ result_ok(_Socket) ->
ok.
renegotiate(Socket, Data) ->
- ct:print("Renegotiating ~n", []),
+ ct:log("Renegotiating ~n", []),
Result = ssl:renegotiate(Socket),
- ct:print("Result ~p~n", [Result]),
+ ct:log("Result ~p~n", [Result]),
ssl:send(Socket, Data),
case Result of
ok ->
@@ -2858,7 +2934,7 @@ renegotiate_immediately(Socket) ->
{error, renegotiation_rejected} = ssl:renegotiate(Socket),
ct:sleep(?RENEGOTIATION_DISABLE_TIME +1),
ok = ssl:renegotiate(Socket),
- ct:print("Renegotiated again"),
+ ct:log("Renegotiated again"),
ssl:send(Socket, "Hello world"),
ok.
@@ -2877,7 +2953,7 @@ new_config(PrivDir, ServerOpts0) ->
ServerOpts = proplists:delete(keyfile, ServerOpts2),
{ok, PEM} = file:read_file(NewCaCertFile),
- ct:print("CA file content: ~p~n", [public_key:pem_decode(PEM)]),
+ ct:log("CA file content: ~p~n", [public_key:pem_decode(PEM)]),
[{cacertfile, NewCaCertFile}, {certfile, NewCertFile},
{keyfile, NewKeyFile} | ServerOpts].
@@ -3073,15 +3149,15 @@ get_close(Pid, Where) ->
{'EXIT', Pid, _Reason} ->
receive
{_, {ssl_closed, Socket}} ->
- ct:print("Socket closed ~p~n",[Socket]);
+ ct:log("Socket closed ~p~n",[Socket]);
Unexpected ->
- ct:print("Unexpected ~p~n",[Unexpected]),
+ ct:log("Unexpected ~p~n",[Unexpected]),
ct:fail({line, ?LINE-1})
after 5000 ->
ct:fail({timeout, {line, ?LINE, Where}})
end;
Unexpected ->
- ct:print("Unexpected ~p~n",[Unexpected]),
+ ct:log("Unexpected ~p~n",[Unexpected]),
ct:fail({line, ?LINE-1})
after 5000 ->
ct:fail({timeout, {line, ?LINE, Where}})
@@ -3095,7 +3171,7 @@ run_send_recv_rizzo(Ciphers, Config, Version, Mfa) ->
[] ->
ok;
Error ->
- ct:print("Cipher suite errors: ~p~n", [Error]),
+ ct:log("Cipher suite errors: ~p~n", [Error]),
ct:fail(cipher_suite_failed_see_test_case_log)
end.
@@ -3125,12 +3201,21 @@ rizzo_test(Cipher, Config, Version, Mfa) ->
[{Cipher, Error}]
end.
-client_server_opts({KeyAlgo,_,_}, Config) when KeyAlgo == rsa orelse KeyAlgo == dhe_rsa ->
+client_server_opts({KeyAlgo,_,_}, Config)
+ when KeyAlgo == rsa orelse
+ KeyAlgo == dhe_rsa orelse
+ KeyAlgo == ecdhe_rsa ->
{?config(client_opts, Config),
?config(server_opts, Config)};
client_server_opts({KeyAlgo,_,_}, Config) when KeyAlgo == dss orelse KeyAlgo == dhe_dss ->
{?config(client_dsa_opts, Config),
- ?config(server_dsa_opts, Config)}.
+ ?config(server_dsa_opts, Config)};
+client_server_opts({KeyAlgo,_,_}, Config) when KeyAlgo == ecdh_ecdsa orelse KeyAlgo == ecdhe_ecdsa ->
+ {?config(client_opts, Config),
+ ?config(server_ecdsa_opts, Config)};
+client_server_opts({KeyAlgo,_,_}, Config) when KeyAlgo == ecdh_rsa ->
+ {?config(client_opts, Config),
+ ?config(server_ecdh_rsa_opts, Config)}.
run_suites(Ciphers, Version, Config, Type) ->
{ClientOpts, ServerOpts} =
@@ -3151,12 +3236,27 @@ run_suites(Ciphers, Version, Config, Type) ->
psk_with_hint ->
{?config(client_psk, Config),
?config(server_psk_hint, Config)};
+ psk_anon ->
+ {?config(client_psk, Config),
+ ?config(server_psk_anon, Config)};
+ psk_anon_with_hint ->
+ {?config(client_psk, Config),
+ ?config(server_psk_anon_hint, Config)};
srp ->
{?config(client_srp, Config),
?config(server_srp, Config)};
+ srp_anon ->
+ {?config(client_srp, Config),
+ ?config(server_srp_anon, Config)};
srp_dsa ->
{?config(client_srp_dsa, Config),
- ?config(server_srp_dsa, Config)}
+ ?config(server_srp_dsa, Config)};
+ ecdsa ->
+ {?config(client_opts, Config),
+ ?config(server_ecdsa_opts, Config)};
+ ecdh_rsa ->
+ {?config(client_opts, Config),
+ ?config(server_ecdh_rsa_opts, Config)}
end,
Result = lists:map(fun(Cipher) ->
@@ -3166,7 +3266,7 @@ run_suites(Ciphers, Version, Config, Type) ->
[] ->
ok;
Error ->
- ct:print("Cipher suite errors: ~p~n", [Error]),
+ ct:log("Cipher suite errors: ~p~n", [Error]),
ct:fail(cipher_suite_failed_see_test_case_log)
end.
@@ -3177,7 +3277,7 @@ erlang_cipher_suite(Suite) ->
cipher(CipherSuite, Version, Config, ClientOpts, ServerOpts) ->
%% process_flag(trap_exit, true),
- ct:print("Testing CipherSuite ~p~n", [CipherSuite]),
+ ct:log("Testing CipherSuite ~p~n", [CipherSuite]),
{ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
ErlangCipherSuite = erlang_cipher_suite(CipherSuite),
diff --git a/lib/ssl/test/ssl_certificate_verify_SUITE.erl b/lib/ssl/test/ssl_certificate_verify_SUITE.erl
index 26938bda50..2703d2d79c 100644
--- a/lib/ssl/test/ssl_certificate_verify_SUITE.erl
+++ b/lib/ssl/test/ssl_certificate_verify_SUITE.erl
@@ -86,7 +86,7 @@ init_per_suite(Config0) ->
Result =
(catch make_certs:all(?config(data_dir, Config0),
?config(priv_dir, Config0))),
- ct:print("Make certs ~p~n", [Result]),
+ ct:log("Make certs ~p~n", [Result]),
Config1 = ssl_test_lib:make_dsa_cert(Config0),
Config = ssl_test_lib:cert_options(Config1),
@@ -297,7 +297,7 @@ verify_fun_always_run_client(Config) when is_list(Config) ->
%% this is not a bug it is a circumstance of how tcp works!
receive
{Server, ServerError} ->
- ct:print("Server Error ~p~n", [ServerError])
+ ct:log("Server Error ~p~n", [ServerError])
end,
ssl_test_lib:check_result(Client, {error, {tls_alert, "handshake failure"}}).
@@ -346,7 +346,7 @@ verify_fun_always_run_server(Config) when is_list(Config) ->
%% this is not a bug it is a circumstance of how tcp works!
receive
{Client, ClientError} ->
- ct:print("Client Error ~p~n", [ClientError])
+ ct:log("Client Error ~p~n", [ClientError])
end,
ssl_test_lib:check_result(Server, {error, {tls_alert, "handshake failure"}}).
@@ -413,7 +413,7 @@ cert_expired(Config) when is_list(Config) ->
two_digits_str(Sec)])),
NewValidity = {'Validity', {generalTime, NotBeforeStr}, {generalTime, NotAfterStr}},
- ct:print("Validity: ~p ~n NewValidity: ~p ~n",
+ ct:log("Validity: ~p ~n NewValidity: ~p ~n",
[OTPTbsCert#'OTPTBSCertificate'.validity, NewValidity]),
NewOTPTbsCert = OTPTbsCert#'OTPTBSCertificate'{validity = NewValidity},
@@ -644,7 +644,7 @@ no_authority_key_identifier(Config) when is_list(Config) ->
NewExtensions = delete_authority_key_extension(Extensions, []),
NewOTPTbsCert = OTPTbsCert#'OTPTBSCertificate'{extensions = NewExtensions},
- ct:print("Extensions ~p~n, NewExtensions: ~p~n", [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}]),
@@ -955,10 +955,10 @@ client_msg(Client, ClientMsg) ->
{Client, ClientMsg} ->
ok;
{Client, {error,closed}} ->
- ct:print("client got close"),
+ ct:log("client got close"),
ok;
{Client, {error, Reason}} ->
- ct:print("client got econnaborted: ~p", [Reason]),
+ ct:log("client got econnaborted: ~p", [Reason]),
ok;
Unexpected ->
ct:fail(Unexpected)
@@ -968,10 +968,10 @@ server_msg(Server, ServerMsg) ->
{Server, ServerMsg} ->
ok;
{Server, {error,closed}} ->
- ct:print("server got close"),
+ ct:log("server got close"),
ok;
{Server, {error, Reason}} ->
- ct:print("server got econnaborted: ~p", [Reason]),
+ ct:log("server got econnaborted: ~p", [Reason]),
ok;
Unexpected ->
ct:fail(Unexpected)
diff --git a/lib/ssl/test/ssl_npn_handshake_SUITE.erl b/lib/ssl/test/ssl_npn_handshake_SUITE.erl
index 8c1b22cf5e..7b271c4d5d 100644
--- a/lib/ssl/test/ssl_npn_handshake_SUITE.erl
+++ b/lib/ssl/test/ssl_npn_handshake_SUITE.erl
@@ -74,7 +74,7 @@ init_per_suite(Config) ->
Result =
(catch make_certs:all(?config(data_dir, Config),
?config(priv_dir, Config))),
- ct:print("Make certs ~p~n", [Result]),
+ ct:log("Make certs ~p~n", [Result]),
ssl_test_lib:cert_options(Config)
catch _:_ ->
{skip, "Crypto did not start"}
@@ -311,13 +311,13 @@ run_npn_handshake(Config, ClientExtraOpts, ServerExtraOpts, ExpectedProtocol) ->
assert_npn(Socket, Protocol) ->
- ct:print("Negotiated Protocol ~p, Expecting: ~p ~n",
+ ct:log("Negotiated Protocol ~p, Expecting: ~p ~n",
[ssl:negotiated_next_protocol(Socket), Protocol]),
Protocol = ssl:negotiated_next_protocol(Socket).
assert_npn_and_renegotiate_and_send_data(Socket, Protocol, Data) ->
assert_npn(Socket, Protocol),
- ct:print("Renegotiating ~n", []),
+ ct:log("Renegotiating ~n", []),
ok = ssl:renegotiate(Socket),
ssl:send(Socket, Data),
assert_npn(Socket, Protocol),
@@ -332,7 +332,7 @@ ssl_receive_and_assert_npn(Socket, Protocol, Data) ->
ssl_receive(Socket, Data).
ssl_send(Socket, Data) ->
- ct:print("Connection info: ~p~n",
+ ct:log("Connection info: ~p~n",
[ssl:connection_info(Socket)]),
ssl:send(Socket, Data).
@@ -340,11 +340,11 @@ ssl_receive(Socket, Data) ->
ssl_receive(Socket, Data, []).
ssl_receive(Socket, Data, Buffer) ->
- ct:print("Connection info: ~p~n",
+ ct:log("Connection info: ~p~n",
[ssl:connection_info(Socket)]),
receive
{ssl, Socket, MoreData} ->
- ct:print("Received ~p~n",[MoreData]),
+ ct:log("Received ~p~n",[MoreData]),
NewBuffer = Buffer ++ MoreData,
case NewBuffer of
Data ->
diff --git a/lib/ssl/test/ssl_npn_hello_SUITE.erl b/lib/ssl/test/ssl_npn_hello_SUITE.erl
index 72768bcb55..43fa72ea28 100644
--- a/lib/ssl/test/ssl_npn_hello_SUITE.erl
+++ b/lib/ssl/test/ssl_npn_hello_SUITE.erl
@@ -25,6 +25,8 @@
-compile(export_all).
-include("ssl_handshake.hrl").
-include("ssl_record.hrl").
+-include("ssl_cipher.hrl").
+-include("ssl_internal.hrl").
-include_lib("common_test/include/ct.hrl").
%%--------------------------------------------------------------------
@@ -75,17 +77,19 @@ encode_and_decode_npn_server_hello_test(_Config) ->
{[{DecodedHandshakeMessage, _Raw}], _} =
ssl_handshake:get_tls_handshake(Version, list_to_binary(HandShakeData), <<>>),
NextProtocolNegotiation = DecodedHandshakeMessage#server_hello.next_protocol_negotiation,
- ct:print("~p ~n", [NextProtocolNegotiation]),
+ ct:log("~p ~n", [NextProtocolNegotiation]),
NextProtocolNegotiation = #next_protocol_negotiation{extension_data = <<6, "spdy/2">>}.
%%--------------------------------------------------------------------
create_server_hello_with_no_advertised_protocols_test(_Config) ->
- Hello = ssl_handshake:server_hello(<<>>, {3, 0}, create_connection_states(), false, undefined),
+ Hello = ssl_handshake:server_hello(<<>>, {3, 0}, create_connection_states(), false,
+ undefined, undefined, undefined),
undefined = Hello#server_hello.next_protocol_negotiation.
%%--------------------------------------------------------------------
create_server_hello_with_advertised_protocols_test(_Config) ->
Hello = ssl_handshake:server_hello(<<>>, {3, 0}, create_connection_states(),
- false, [<<"spdy/1">>, <<"http/1.0">>, <<"http/1.1">>]),
+ false, [<<"spdy/1">>, <<"http/1.0">>, <<"http/1.1">>],
+ undefined, undefined),
#next_protocol_negotiation{extension_data = <<6, "spdy/1", 8, "http/1.0", 8, "http/1.1">>} =
Hello#server_hello.next_protocol_negotiation.
%%--------------------------------------------------------------------
@@ -96,7 +100,7 @@ create_client_handshake(Npn) ->
client_version = {1, 2},
random = <<1:256>>,
session_id = <<>>,
- cipher_suites = "",
+ cipher_suites = [?TLS_DHE_DSS_WITH_DES_CBC_SHA],
compression_methods = "",
next_protocol_negotiation = Npn,
renegotiation_info = #renegotiation_info{}
@@ -107,7 +111,7 @@ create_server_handshake(Npn) ->
server_version = {1, 2},
random = <<1:256>>,
session_id = <<>>,
- cipher_suite = <<1,2>>,
+ cipher_suite = ?TLS_DHE_DSS_WITH_DES_CBC_SHA,
compression_method = 1,
next_protocol_negotiation = Npn,
renegotiation_info = #renegotiation_info{}
@@ -119,7 +123,7 @@ create_connection_states() ->
security_parameters = #security_parameters{
server_random = <<1:256>>,
compression_algorithm = 1,
- cipher_suite = <<1, 2>>
+ cipher_suite = ?TLS_DHE_DSS_WITH_DES_CBC_SHA
}
},
diff --git a/lib/ssl/test/ssl_packet_SUITE.erl b/lib/ssl/test/ssl_packet_SUITE.erl
index 4116bb39d1..5a374e234d 100644
--- a/lib/ssl/test/ssl_packet_SUITE.erl
+++ b/lib/ssl/test/ssl_packet_SUITE.erl
@@ -143,7 +143,7 @@ init_per_suite(Config) ->
Result =
(catch make_certs:all(?config(data_dir, Config),
?config(priv_dir, Config))),
- ct:print("Make certs ~p~n", [Result]),
+ ct:log("Make certs ~p~n", [Result]),
ssl_test_lib:cert_options(Config)
catch _:_ ->
{skip, "Crypto did not start"}
@@ -2069,7 +2069,7 @@ client_packet_decode(Socket, [Head | Tail] = Packet) ->
client_packet_decode(Socket, [Head], Tail, Packet).
client_packet_decode(Socket, P1, P2, Packet) ->
- ct:print("Packet: ~p ~n", [Packet]),
+ ct:log("Packet: ~p ~n", [Packet]),
ok = ssl:send(Socket, P1),
ok = ssl:send(Socket, P2),
receive
diff --git a/lib/ssl/test/ssl_payload_SUITE.erl b/lib/ssl/test/ssl_payload_SUITE.erl
index 77ad546420..5f5166391f 100644
--- a/lib/ssl/test/ssl_payload_SUITE.erl
+++ b/lib/ssl/test/ssl_payload_SUITE.erl
@@ -556,33 +556,33 @@ send(Socket, Data, Size, Repeate,F) ->
sender(Socket, Data, Size) ->
ok = send(Socket, Data, Size, 100, fun() -> do_recv(Socket, Data, Size, <<>>, false) end),
- ct:print("Sender recv: ~p~n", [ssl:getopts(Socket, [active])]),
+ ct:log("Sender recv: ~p~n", [ssl:getopts(Socket, [active])]),
ok.
sender_once(Socket, Data, Size) ->
send(Socket, Data, Size, 100,
fun() -> do_active_once(Socket, Data, Size, <<>>, false) end),
- ct:print("Sender active once: ~p~n",
+ ct:log("Sender active once: ~p~n",
[ssl:getopts(Socket, [active])]),
ok.
sender_active(Socket, Data, Size) ->
F = fun() -> do_active(Socket, Data, Size, <<>>, false) end,
send(Socket, Data, Size, 100, F),
- ct:print("Sender active: ~p~n", [ssl:getopts(Socket, [active])]),
+ ct:log("Sender active: ~p~n", [ssl:getopts(Socket, [active])]),
ok.
echoer(Socket, Data, Size) ->
- ct:print("Echoer recv: ~p~n", [ssl:getopts(Socket, [active])]),
+ ct:log("Echoer recv: ~p~n", [ssl:getopts(Socket, [active])]),
echo(fun() -> do_recv(Socket, Data, Size, <<>>, true) end, 100).
echoer_once(Socket, Data, Size) ->
- ct:print("Echoer active once: ~p ~n",
+ ct:log("Echoer active once: ~p ~n",
[ssl:getopts(Socket, [active])]),
echo(fun() -> do_active_once(Socket, Data, Size, <<>>, true) end, 100).
echoer_active(Socket, Data, Size) ->
- ct:print("Echoer active: ~p~n", [ssl:getopts(Socket, [active])]),
+ ct:log("Echoer active: ~p~n", [ssl:getopts(Socket, [active])]),
echo(fun() -> do_active(Socket, Data, Size, <<>>, true) end, 100).
echo(_Fun, 0) -> ok;
diff --git a/lib/ssl/test/ssl_session_cache_SUITE.erl b/lib/ssl/test/ssl_session_cache_SUITE.erl
index fd9a0a594c..6cc6c4bdb2 100644
--- a/lib/ssl/test/ssl_session_cache_SUITE.erl
+++ b/lib/ssl/test/ssl_session_cache_SUITE.erl
@@ -63,7 +63,7 @@ init_per_suite(Config0) ->
Result =
(catch make_certs:all(?config(data_dir, Config0),
?config(priv_dir, Config0))),
- ct:print("Make certs ~p~n", [Result]),
+ ct:log("Make certs ~p~n", [Result]),
Config1 = ssl_test_lib:make_dsa_cert(Config0),
Config = ssl_test_lib:cert_options(Config1),
diff --git a/lib/ssl/test/ssl_test_lib.erl b/lib/ssl/test/ssl_test_lib.erl
index d655d7659e..a8ff5187b6 100644
--- a/lib/ssl/test/ssl_test_lib.erl
+++ b/lib/ssl/test/ssl_test_lib.erl
@@ -59,7 +59,7 @@ run_server(Opts) ->
Options = proplists:get_value(options, Opts),
Pid = proplists:get_value(from, Opts),
Transport = proplists:get_value(transport, Opts, ssl),
- ct:print("ssl:listen(~p, ~p)~n", [Port, Options]),
+ ct:log("ssl:listen(~p, ~p)~n", [Port, Options]),
{ok, ListenSocket} = rpc:call(Node, Transport, listen, [Port, Options]),
Pid ! {listen, up},
send_selected_port(Pid, Port, ListenSocket),
@@ -77,13 +77,13 @@ do_run_server(ListenSocket, AcceptSocket, Opts) ->
Pid = proplists:get_value(from, Opts),
Transport = proplists:get_value(transport, Opts, ssl),
{Module, Function, Args} = proplists:get_value(mfa, Opts),
- ct:print("Server: apply(~p,~p,~p)~n",
+ ct:log("Server: apply(~p,~p,~p)~n",
[Module, Function, [AcceptSocket | Args]]),
case rpc:call(Node, Module, Function, [AcceptSocket | Args]) of
no_result_msg ->
ok;
Msg ->
- ct:print("Server Msg: ~p ~n", [Msg]),
+ ct:log("Server Msg: ~p ~n", [Msg]),
Pid ! {self(), Msg}
end,
receive
@@ -92,10 +92,10 @@ do_run_server(ListenSocket, AcceptSocket, Opts) ->
{listen, MFA} ->
run_server(ListenSocket, [MFA | proplists:delete(mfa, Opts)]);
close ->
- ct:print("Server closing ~p ~n", [self()]),
+ ct:log("Server closing ~p ~n", [self()]),
Result = rpc:call(Node, Transport, close, [AcceptSocket], 500),
Result1 = rpc:call(Node, Transport, close, [ListenSocket], 500),
- ct:print("Result ~p : ~p ~n", [Result, Result1]);
+ ct:log("Result ~p : ~p ~n", [Result, Result1]);
{ssl_closed, _} ->
ok
end.
@@ -115,7 +115,7 @@ connect(#sslsocket{} = ListenSocket, Opts) ->
end;
connect(ListenSocket, Opts) ->
Node = proplists:get_value(node, Opts),
- ct:print("gen_tcp:accept(~p)~n", [ListenSocket]),
+ ct:log("gen_tcp:accept(~p)~n", [ListenSocket]),
{ok, AcceptSocket} = rpc:call(Node, gen_tcp, accept,
[ListenSocket]),
AcceptSocket.
@@ -123,10 +123,10 @@ connect(ListenSocket, Opts) ->
connect(_, _, 0, AcceptSocket, _) ->
AcceptSocket;
connect(ListenSocket, Node, N, _, Timeout) ->
- ct:print("ssl:transport_accept(~p)~n", [ListenSocket]),
+ ct:log("ssl:transport_accept(~p)~n", [ListenSocket]),
{ok, AcceptSocket} = rpc:call(Node, ssl, transport_accept,
[ListenSocket]),
- ct:print("ssl:ssl_accept(~p, ~p)~n", [AcceptSocket, Timeout]),
+ ct:log("ssl:ssl_accept(~p, ~p)~n", [AcceptSocket, Timeout]),
case rpc:call(Node, ssl, ssl_accept, [AcceptSocket, Timeout]) of
ok ->
@@ -161,27 +161,27 @@ run_client(Opts) ->
Pid = proplists:get_value(from, Opts),
Transport = proplists:get_value(transport, Opts, ssl),
Options = proplists:get_value(options, Opts),
- ct:print("ssl:connect(~p, ~p, ~p)~n", [Host, Port, Options]),
+ ct:log("ssl:connect(~p, ~p, ~p)~n", [Host, Port, Options]),
case rpc:call(Node, Transport, connect, [Host, Port, Options]) of
{ok, Socket} ->
Pid ! { connected, Socket },
- ct:print("Client: connected~n", []),
+ ct:log("Client: connected~n", []),
%% In special cases we want to know the client port, it will
%% be indicated by sending {port, 0} in options list!
send_selected_port(Pid, proplists:get_value(port, Options), Socket),
{Module, Function, Args} = proplists:get_value(mfa, Opts),
- ct:print("Client: apply(~p,~p,~p)~n",
+ ct:log("Client: apply(~p,~p,~p)~n",
[Module, Function, [Socket | Args]]),
case rpc:call(Node, Module, Function, [Socket | Args]) of
no_result_msg ->
ok;
Msg ->
- ct:print("Client Msg: ~p ~n", [Msg]),
+ ct:log("Client Msg: ~p ~n", [Msg]),
Pid ! {self(), Msg}
end,
receive
close ->
- ct:print("Client closing~n", []),
+ ct:log("Client closing~n", []),
rpc:call(Node, Transport, close, [Socket]);
{ssl_closed, Socket} ->
ok;
@@ -189,18 +189,18 @@ run_client(Opts) ->
ok
end;
{error, Reason} ->
- ct:print("Client: connection failed: ~p ~n", [Reason]),
+ ct:log("Client: connection failed: ~p ~n", [Reason]),
Pid ! {self(), {error, Reason}}
end.
close(Pid) ->
- ct:print("Close ~p ~n", [Pid]),
+ ct:log("Close ~p ~n", [Pid]),
Monitor = erlang:monitor(process, Pid),
Pid ! close,
receive
{'DOWN', Monitor, process, Pid, Reason} ->
erlang:demonitor(Monitor),
- ct:print("Pid: ~p down due to:~p ~n", [Pid, Reason])
+ ct:log("Pid: ~p down due to:~p ~n", [Pid, Reason])
end.
check_result(Server, ServerMsg, Client, ClientMsg) ->
@@ -339,12 +339,22 @@ cert_options(Config) ->
{psk_identity, "HINT"},
{user_lookup_fun, {fun user_lookup/3, PskSharedSecret}},
{ciphers, psk_suites()}]},
+ {server_psk_anon, [{ssl_imp, new},{reuseaddr, true},
+ {user_lookup_fun, {fun user_lookup/3, PskSharedSecret}},
+ {ciphers, psk_anon_suites()}]},
+ {server_psk_anon_hint, [{ssl_imp, new},{reuseaddr, true},
+ {psk_identity, "HINT"},
+ {user_lookup_fun, {fun user_lookup/3, PskSharedSecret}},
+ {ciphers, psk_anon_suites()}]},
{client_srp, [{ssl_imp, new},{reuseaddr, true},
{srp_identity, {"Test-User", "secret"}}]},
{server_srp, [{ssl_imp, new},{reuseaddr, true},
{certfile, ServerCertFile}, {keyfile, ServerKeyFile},
{user_lookup_fun, {fun user_lookup/3, undefined}},
{ciphers, srp_suites()}]},
+ {server_srp_anon, [{ssl_imp, new},{reuseaddr, true},
+ {user_lookup_fun, {fun user_lookup/3, undefined}},
+ {ciphers, srp_anon_suites()}]},
{server_verification_opts, [{ssl_imp, new},{reuseaddr, true},
{cacertfile, ServerCaCertFile},
{certfile, ServerCertFile}, {keyfile, ServerKeyFile}]},
@@ -394,6 +404,49 @@ make_dsa_cert(Config) ->
{certfile, ClientCertFile}, {keyfile, ClientKeyFile}]}
| Config].
+make_ecdsa_cert(Config) ->
+ case proplists:get_bool(ec, crypto:algorithms()) of
+ true ->
+ {ServerCaCertFile, ServerCertFile, ServerKeyFile} = make_cert_files("server", Config, ec, ec, ""),
+ {ClientCaCertFile, ClientCertFile, ClientKeyFile} = make_cert_files("client", Config, ec, ec, ""),
+ [{server_ecdsa_opts, [{ssl_imp, new},{reuseaddr, true},
+ {cacertfile, ServerCaCertFile},
+ {certfile, ServerCertFile}, {keyfile, ServerKeyFile}]},
+ {server_ecdsa_verify_opts, [{ssl_imp, new},{reuseaddr, true},
+ {cacertfile, ClientCaCertFile},
+ {certfile, ServerCertFile}, {keyfile, ServerKeyFile},
+ {verify, verify_peer}]},
+ {client_ecdsa_opts, [{ssl_imp, new},{reuseaddr, true},
+ {cacertfile, ClientCaCertFile},
+ {certfile, ClientCertFile}, {keyfile, ClientKeyFile}]}
+ | Config];
+ _ ->
+ Config
+ end.
+
+%% RFC 4492, Sect. 2.3. ECDH_RSA
+%%
+%% This key exchange algorithm is the same as ECDH_ECDSA except that the
+%% server's certificate MUST be signed with RSA rather than ECDSA.
+make_ecdh_rsa_cert(Config) ->
+ case proplists:get_bool(ec, crypto:algorithms()) of
+ true ->
+ {ServerCaCertFile, ServerCertFile, ServerKeyFile} = make_cert_files("server", Config, rsa, ec, "rsa_"),
+ {ClientCaCertFile, ClientCertFile, ClientKeyFile} = make_cert_files("client", Config, rsa, ec, "rsa_"),
+ [{server_ecdh_rsa_opts, [{ssl_imp, new},{reuseaddr, true},
+ {cacertfile, ServerCaCertFile},
+ {certfile, ServerCertFile}, {keyfile, ServerKeyFile}]},
+ {server_ecdh_rsa_verify_opts, [{ssl_imp, new},{reuseaddr, true},
+ {cacertfile, ClientCaCertFile},
+ {certfile, ServerCertFile}, {keyfile, ServerKeyFile},
+ {verify, verify_peer}]},
+ {client_ecdh_rsa_opts, [{ssl_imp, new},{reuseaddr, true},
+ {cacertfile, ClientCaCertFile},
+ {certfile, ClientCertFile}, {keyfile, ClientKeyFile}]}
+ | Config];
+ _ ->
+ Config
+ end.
make_mix_cert(Config) ->
{ServerCaCertFile, ServerCertFile, ServerKeyFile} = make_cert_files("server", Config, dsa,
@@ -445,33 +498,33 @@ run_upgrade_server(Opts) ->
SslOptions = proplists:get_value(ssl_options, Opts),
Pid = proplists:get_value(from, Opts),
- ct:print("gen_tcp:listen(~p, ~p)~n", [Port, TcpOptions]),
+ ct:log("gen_tcp:listen(~p, ~p)~n", [Port, TcpOptions]),
{ok, ListenSocket} = rpc:call(Node, gen_tcp, listen, [Port, TcpOptions]),
Pid ! {listen, up},
send_selected_port(Pid, Port, ListenSocket),
- ct:print("gen_tcp:accept(~p)~n", [ListenSocket]),
+ ct:log("gen_tcp:accept(~p)~n", [ListenSocket]),
{ok, AcceptSocket} = rpc:call(Node, gen_tcp, accept, [ListenSocket]),
try
{ok, SslAcceptSocket} = case TimeOut of
infinity ->
- ct:print("ssl:ssl_accept(~p, ~p)~n",
+ ct:log("ssl:ssl_accept(~p, ~p)~n",
[AcceptSocket, SslOptions]),
rpc:call(Node, ssl, ssl_accept,
[AcceptSocket, SslOptions]);
_ ->
- ct:print("ssl:ssl_accept(~p, ~p, ~p)~n",
+ ct:log("ssl:ssl_accept(~p, ~p, ~p)~n",
[AcceptSocket, SslOptions, TimeOut]),
rpc:call(Node, ssl, ssl_accept,
[AcceptSocket, SslOptions, TimeOut])
end,
{Module, Function, Args} = proplists:get_value(mfa, Opts),
Msg = rpc:call(Node, Module, Function, [SslAcceptSocket | Args]),
- ct:print("Upgrade Server Msg: ~p ~n", [Msg]),
+ ct:log("Upgrade Server Msg: ~p ~n", [Msg]),
Pid ! {self(), Msg},
receive
close ->
- ct:print("Upgrade Server closing~n", []),
+ ct:log("Upgrade Server closing~n", []),
rpc:call(Node, ssl, close, [SslAcceptSocket])
end
catch error:{badmatch, Error} ->
@@ -489,24 +542,24 @@ run_upgrade_client(Opts) ->
TcpOptions = proplists:get_value(tcp_options, Opts),
SslOptions = proplists:get_value(ssl_options, Opts),
- ct:print("gen_tcp:connect(~p, ~p, ~p)~n",
+ ct:log("gen_tcp:connect(~p, ~p, ~p)~n",
[Host, Port, TcpOptions]),
{ok, Socket} = rpc:call(Node, gen_tcp, connect, [Host, Port, TcpOptions]),
send_selected_port(Pid, Port, Socket),
- ct:print("ssl:connect(~p, ~p)~n", [Socket, SslOptions]),
+ ct:log("ssl:connect(~p, ~p)~n", [Socket, SslOptions]),
{ok, SslSocket} = rpc:call(Node, ssl, connect, [Socket, SslOptions]),
{Module, Function, Args} = proplists:get_value(mfa, Opts),
- ct:print("apply(~p, ~p, ~p)~n",
+ ct:log("apply(~p, ~p, ~p)~n",
[Module, Function, [SslSocket | Args]]),
Msg = rpc:call(Node, Module, Function, [SslSocket | Args]),
- ct:print("Upgrade Client Msg: ~p ~n", [Msg]),
+ ct:log("Upgrade Client Msg: ~p ~n", [Msg]),
Pid ! {self(), Msg},
receive
close ->
- ct:print("Upgrade Client closing~n", []),
+ ct:log("Upgrade Client closing~n", []),
rpc:call(Node, ssl, close, [SslSocket])
end.
@@ -525,20 +578,20 @@ run_upgrade_server_error(Opts) ->
SslOptions = proplists:get_value(ssl_options, Opts),
Pid = proplists:get_value(from, Opts),
- ct:print("gen_tcp:listen(~p, ~p)~n", [Port, TcpOptions]),
+ ct:log("gen_tcp:listen(~p, ~p)~n", [Port, TcpOptions]),
{ok, ListenSocket} = rpc:call(Node, gen_tcp, listen, [Port, TcpOptions]),
Pid ! {listen, up},
send_selected_port(Pid, Port, ListenSocket),
- ct:print("gen_tcp:accept(~p)~n", [ListenSocket]),
+ ct:log("gen_tcp:accept(~p)~n", [ListenSocket]),
{ok, AcceptSocket} = rpc:call(Node, gen_tcp, accept, [ListenSocket]),
Error = case TimeOut of
infinity ->
- ct:print("ssl:ssl_accept(~p, ~p)~n",
+ ct:log("ssl:ssl_accept(~p, ~p)~n",
[AcceptSocket, SslOptions]),
rpc:call(Node, ssl, ssl_accept,
[AcceptSocket, SslOptions]);
_ ->
- ct:print("ssl:ssl_accept(~p, ~p, ~p)~n",
+ ct:log("ssl:ssl_accept(~p, ~p, ~p)~n",
[AcceptSocket, SslOptions, TimeOut]),
rpc:call(Node, ssl, ssl_accept,
[AcceptSocket, SslOptions, TimeOut])
@@ -558,26 +611,26 @@ run_server_error(Opts) ->
Options = proplists:get_value(options, Opts),
Pid = proplists:get_value(from, Opts),
Transport = proplists:get_value(transport, Opts, ssl),
- ct:print("ssl:listen(~p, ~p)~n", [Port, Options]),
+ ct:log("ssl:listen(~p, ~p)~n", [Port, Options]),
case rpc:call(Node, Transport, listen, [Port, Options]) of
{ok, #sslsocket{} = ListenSocket} ->
%% To make sure error_client will
%% get {error, closed} and not {error, connection_refused}
Pid ! {listen, up},
send_selected_port(Pid, Port, ListenSocket),
- ct:print("ssl:transport_accept(~p)~n", [ListenSocket]),
+ ct:log("ssl:transport_accept(~p)~n", [ListenSocket]),
case rpc:call(Node, Transport, transport_accept, [ListenSocket]) of
{error, _} = Error ->
Pid ! {self(), Error};
{ok, AcceptSocket} ->
- ct:print("ssl:ssl_accept(~p)~n", [AcceptSocket]),
+ ct:log("ssl:ssl_accept(~p)~n", [AcceptSocket]),
Error = rpc:call(Node, ssl, ssl_accept, [AcceptSocket]),
Pid ! {self(), Error}
end;
{ok, ListenSocket} ->
Pid ! {listen, up},
send_selected_port(Pid, Port, ListenSocket),
- ct:print("~p:accept(~p)~n", [Transport, ListenSocket]),
+ ct:log("~p:accept(~p)~n", [Transport, ListenSocket]),
case rpc:call(Node, Transport, accept, [ListenSocket]) of
{error, _} = Error ->
Pid ! {self(), Error}
@@ -599,7 +652,7 @@ run_client_error(Opts) ->
Pid = proplists:get_value(from, Opts),
Transport = proplists:get_value(transport, Opts, ssl),
Options = proplists:get_value(options, Opts),
- ct:print("ssl:connect(~p, ~p, ~p)~n", [Host, Port, Options]),
+ ct:log("ssl:connect(~p, ~p, ~p)~n", [Host, Port, Options]),
Error = rpc:call(Node, Transport, connect, [Host, Port, Options]),
Pid ! {self(), Error}.
@@ -656,11 +709,16 @@ send_selected_port(Pid, 0, Socket) ->
send_selected_port(_,_,_) ->
ok.
-rsa_suites() ->
- lists:filter(fun({dhe_dss, _, _}) ->
- false;
+rsa_suites(CounterPart) ->
+ ECC = is_sane_ecc(CounterPart),
+ lists:filter(fun({rsa, _, _}) ->
+ true;
+ ({dhe_rsa, _, _}) ->
+ true;
+ ({ecdhe_rsa, _, _}) when ECC == true ->
+ true;
(_) ->
- true
+ false
end,
ssl:cipher_suites()).
@@ -680,17 +738,32 @@ dsa_suites() ->
end,
ssl:cipher_suites()).
+ecdsa_suites() ->
+ lists:filter(fun({ecdhe_ecdsa, _, _}) ->
+ true;
+ (_) ->
+ false
+ end,
+ ssl:cipher_suites()).
+
+ecdh_rsa_suites() ->
+ lists:filter(fun({ecdh_rsa, _, _}) ->
+ true;
+ (_) ->
+ false
+ end,
+ ssl:cipher_suites()).
openssl_rsa_suites() ->
Ciphers = ssl:cipher_suites(openssl),
lists:filter(fun(Str) ->
- case re:run(Str,"DSS",[]) of
+ case re:run(Str,"DSS|ECDH-RSA|ECDSA",[]) of
nomatch ->
true;
_ ->
false
end
- end, Ciphers).
+ end, Ciphers).
openssl_dsa_suites() ->
Ciphers = ssl:cipher_suites(openssl),
@@ -703,14 +776,58 @@ openssl_dsa_suites() ->
end
end, Ciphers).
+openssl_ecdsa_suites() ->
+ Ciphers = ssl:cipher_suites(openssl),
+ lists:filter(fun(Str) ->
+ case re:run(Str,"ECDHE-ECDSA",[]) of
+ nomatch ->
+ false;
+ _ ->
+ true
+ end
+ end, Ciphers).
+
+openssl_ecdh_rsa_suites() ->
+ Ciphers = ssl:cipher_suites(openssl),
+ lists:filter(fun(Str) ->
+ case re:run(Str,"ECDH-RSA",[]) of
+ nomatch ->
+ false;
+ _ ->
+ true
+ end
+ end, Ciphers).
+
anonymous_suites() ->
- [{dh_anon, rc4_128, md5},
- {dh_anon, des_cbc, sha},
- {dh_anon, '3des_ede_cbc', sha},
- {dh_anon, aes_128_cbc, sha},
- {dh_anon, aes_256_cbc, sha}].
+ Suites =
+ [{dh_anon, rc4_128, md5},
+ {dh_anon, des_cbc, sha},
+ {dh_anon, '3des_ede_cbc', sha},
+ {dh_anon, aes_128_cbc, sha},
+ {dh_anon, aes_256_cbc, sha},
+ {ecdh_anon,rc4_128,sha},
+ {ecdh_anon,'3des_ede_cbc',sha},
+ {ecdh_anon,aes_128_cbc,sha},
+ {ecdh_anon,aes_256_cbc,sha}],
+ ssl_cipher:filter_suites(Suites).
psk_suites() ->
+ Suites =
+ [{psk, rc4_128, sha},
+ {psk, '3des_ede_cbc', sha},
+ {psk, aes_128_cbc, sha},
+ {psk, aes_256_cbc, sha},
+ {dhe_psk, rc4_128, sha},
+ {dhe_psk, '3des_ede_cbc', sha},
+ {dhe_psk, aes_128_cbc, sha},
+ {dhe_psk, aes_256_cbc, sha},
+ {rsa_psk, rc4_128, sha},
+ {rsa_psk, '3des_ede_cbc', sha},
+ {rsa_psk, aes_128_cbc, sha},
+ {rsa_psk, aes_256_cbc, sha}],
+ ssl_cipher:filter_suites(Suites).
+
+psk_anon_suites() ->
[{psk, rc4_128, sha},
{psk, '3des_ede_cbc', sha},
{psk, aes_128_cbc, sha},
@@ -718,24 +835,29 @@ psk_suites() ->
{dhe_psk, rc4_128, sha},
{dhe_psk, '3des_ede_cbc', sha},
{dhe_psk, aes_128_cbc, sha},
- {dhe_psk, aes_256_cbc, sha},
- {rsa_psk, rc4_128, sha},
- {rsa_psk, '3des_ede_cbc', sha},
- {rsa_psk, aes_128_cbc, sha},
- {rsa_psk, aes_256_cbc, sha}].
+ {dhe_psk, aes_256_cbc, sha}].
srp_suites() ->
+ Suites =
+ [{srp_anon, '3des_ede_cbc', sha},
+ {srp_rsa, '3des_ede_cbc', sha},
+ {srp_anon, aes_128_cbc, sha},
+ {srp_rsa, aes_128_cbc, sha},
+ {srp_anon, aes_256_cbc, sha},
+ {srp_rsa, aes_256_cbc, sha}],
+ ssl_cipher:filter_suites(Suites).
+
+srp_anon_suites() ->
[{srp_anon, '3des_ede_cbc', sha},
- {srp_rsa, '3des_ede_cbc', sha},
{srp_anon, aes_128_cbc, sha},
- {srp_rsa, aes_128_cbc, sha},
- {srp_anon, aes_256_cbc, sha},
- {srp_rsa, aes_256_cbc, sha}].
+ {srp_anon, aes_256_cbc, sha}].
srp_dss_suites() ->
- [{srp_dss, '3des_ede_cbc', sha},
- {srp_dss, aes_128_cbc, sha},
- {srp_dss, aes_256_cbc, sha}].
+ Suites =
+ [{srp_dss, '3des_ede_cbc', sha},
+ {srp_dss, aes_128_cbc, sha},
+ {srp_dss, aes_256_cbc, sha}],
+ ssl_cipher:filter_suites(Suites).
pem_to_der(File) ->
{ok, PemBin} = file:read_file(File),
@@ -747,7 +869,7 @@ der_to_pem(File, Entries) ->
cipher_result(Socket, Result) ->
Result = ssl:connection_info(Socket),
- ct:print("Successfull connect: ~p~n", [Result]),
+ ct:log("Successfull connect: ~p~n", [Result]),
%% Importante to send two packets here
%% to properly test "cipher state" handling
ssl:send(Socket, "Hello\n"),
@@ -817,15 +939,9 @@ init_tls_version(Version) ->
ssl:start().
sufficient_crypto_support('tlsv1.2') ->
- Data = "Sampl",
- Data2 = "e #1",
- Key = <<0,1,2,3,16,17,18,19,32,33,34,35,48,49,50,51,4,5,6,7,20,21,22,23,36,37,38,39,
- 52,53,54,55,8,9,10,11,24,25,26,27,40,41,42,43,56,57,58,59>>,
- try
- crypto:sha256_mac(Key, lists:flatten([Data, Data2])),
- true
- catch _:_ -> false
- end;
+ proplists:get_bool(sha256, crypto:algorithms());
+sufficient_crypto_support(ciphers_ec) ->
+ proplists:get_bool(ec, crypto:algorithms());
sufficient_crypto_support(_) ->
true.
@@ -858,3 +974,35 @@ send_recv_result_active_once(Socket) ->
{ssl, Socket, "Hello world"} ->
ok
end.
+
+is_sane_ecc(openssl) ->
+ case os:cmd("openssl version") of
+ "OpenSSL 1.0.0a" ++ _ -> % Known bug in openssl
+ %% manifests as SSL_CHECK_SERVERHELLO_TLSEXT:tls invalid ecpointformat list
+ false;
+ "OpenSSL 1.0.0" ++ _ -> % Known bug in openssl
+ %% manifests as SSL_CHECK_SERVERHELLO_TLSEXT:tls invalid ecpointformat list
+ false;
+ "OpenSSL 0.9.8" ++ _ -> % Does not support ECC
+ false;
+ "OpenSSL 0.9.7" ++ _ -> % Does not support ECC
+ false;
+ _ ->
+ true
+ end;
+is_sane_ecc(_) ->
+ true.
+
+cipher_restriction(Config0) ->
+ case is_sane_ecc(openssl) of
+ false ->
+ Opts = proplists:get_value(server_opts, Config0),
+ Config1 = proplists:delete(server_opts, Config0),
+ VerOpts = proplists:get_value(server_verification_opts, Config1),
+ Config = proplists:delete(server_verification_opts, Config1),
+ Restricted0 = ssl:cipher_suites() -- ecdsa_suites(),
+ Restricted = Restricted0 -- ecdh_rsa_suites(),
+ [{server_opts, [{ciphers, Restricted} | Opts]}, {server_verification_opts, [{ciphers, Restricted} | VerOpts] } | Config];
+ true ->
+ Config0
+ end.
diff --git a/lib/ssl/test/ssl_to_openssl_SUITE.erl b/lib/ssl/test/ssl_to_openssl_SUITE.erl
index a3d382f837..075b4b1ec4 100644
--- a/lib/ssl/test/ssl_to_openssl_SUITE.erl
+++ b/lib/ssl/test/ssl_to_openssl_SUITE.erl
@@ -104,10 +104,11 @@ init_per_suite(Config0) ->
Result =
(catch make_certs:all(?config(data_dir, Config0),
?config(priv_dir, Config0))),
- ct:print("Make certs ~p~n", [Result]),
+ ct:log("Make certs ~p~n", [Result]),
Config1 = ssl_test_lib:make_dsa_cert(Config0),
Config = ssl_test_lib:cert_options(Config1),
- [{watchdog, Dog} | Config]
+ NewConfig = [{watchdog, Dog} | Config],
+ ssl_test_lib:cipher_restriction(NewConfig)
catch _:_ ->
{skip, "Crypto did not start"}
end
@@ -200,7 +201,7 @@ basic_erlang_client_openssl_server(Config) when is_list(Config) ->
Cmd = "openssl s_server -accept " ++ integer_to_list(Port) ++
" -cert " ++ CertFile ++ " -key " ++ KeyFile,
- ct:print("openssl cmd: ~p~n", [Cmd]),
+ ct:log("openssl cmd: ~p~n", [Cmd]),
OpensslPort = open_port({spawn, Cmd}, [stderr_to_stdout]),
@@ -212,7 +213,7 @@ basic_erlang_client_openssl_server(Config) when is_list(Config) ->
{mfa, {?MODULE,
erlang_ssl_receive, [Data]}},
{options, ClientOpts}]),
- port_command(OpensslPort, Data),
+ true = port_command(OpensslPort, Data),
ssl_test_lib:check_result(Client, ok),
@@ -241,10 +242,10 @@ basic_erlang_server_openssl_client(Config) when is_list(Config) ->
Cmd = "openssl s_client -port " ++ integer_to_list(Port) ++
" -host localhost",
- ct:print("openssl cmd: ~p~n", [Cmd]),
+ ct:log("openssl cmd: ~p~n", [Cmd]),
OpenSslPort = open_port({spawn, Cmd}, [stderr_to_stdout]),
- port_command(OpenSslPort, Data),
+ true = port_command(OpenSslPort, Data),
ssl_test_lib:check_result(Server, ok),
@@ -272,7 +273,7 @@ erlang_client_openssl_server(Config) when is_list(Config) ->
Cmd = "openssl s_server -accept " ++ integer_to_list(Port) ++ version_flag(Version) ++
" -cert " ++ CertFile ++ " -key " ++ KeyFile,
- ct:print("openssl cmd: ~p~n", [Cmd]),
+ ct:log("openssl cmd: ~p~n", [Cmd]),
OpensslPort = open_port({spawn, Cmd}, [stderr_to_stdout]),
@@ -284,7 +285,7 @@ erlang_client_openssl_server(Config) when is_list(Config) ->
{mfa, {?MODULE,
erlang_ssl_receive, [Data]}},
{options, ClientOpts}]),
- port_command(OpensslPort, Data),
+ true = port_command(OpensslPort, Data),
ssl_test_lib:check_result(Client, ok),
@@ -314,10 +315,10 @@ erlang_server_openssl_client(Config) when is_list(Config) ->
Cmd = "openssl s_client -port " ++ integer_to_list(Port) ++ version_flag(Version) ++
" -host localhost",
- ct:print("openssl cmd: ~p~n", [Cmd]),
+ ct:log("openssl cmd: ~p~n", [Cmd]),
OpenSslPort = open_port({spawn, Cmd}, [stderr_to_stdout]),
- port_command(OpenSslPort, Data),
+ true = port_command(OpenSslPort, Data),
ssl_test_lib:check_result(Server, ok),
@@ -349,7 +350,7 @@ erlang_client_openssl_server_dsa_cert(Config) when is_list(Config) ->
" -cert " ++ CertFile ++ " -CAfile " ++ CaCertFile
++ " -key " ++ KeyFile ++ " -Verify 2 -msg",
- ct:print("openssl cmd: ~p~n", [Cmd]),
+ ct:log("openssl cmd: ~p~n", [Cmd]),
OpensslPort = open_port({spawn, Cmd}, [stderr_to_stdout]),
@@ -362,7 +363,7 @@ erlang_client_openssl_server_dsa_cert(Config) when is_list(Config) ->
erlang_ssl_receive, [Data]}},
{options, ClientOpts}]),
- port_command(OpensslPort, Data),
+ true = port_command(OpensslPort, Data),
ssl_test_lib:check_result(Client, ok),
@@ -396,10 +397,10 @@ erlang_server_openssl_client_dsa_cert(Config) when is_list(Config) ->
" -host localhost " ++ " -cert " ++ CertFile ++ " -CAfile " ++ CaCertFile
++ " -key " ++ KeyFile ++ " -msg",
- ct:print("openssl cmd: ~p~n", [Cmd]),
+ ct:log("openssl cmd: ~p~n", [Cmd]),
OpenSslPort = open_port({spawn, Cmd}, [stderr_to_stdout]),
- port_command(OpenSslPort, Data),
+ true = port_command(OpenSslPort, Data),
ssl_test_lib:check_result(Server, ok),
@@ -431,11 +432,11 @@ erlang_server_openssl_client_reuse_session(Config) when is_list(Config) ->
Cmd = "openssl s_client -port " ++ integer_to_list(Port) ++ version_flag(Version) ++
" -host localhost -reconnect",
- ct:print("openssl cmd: ~p~n", [Cmd]),
+ ct:log("openssl cmd: ~p~n", [Cmd]),
OpenSslPort = open_port({spawn, Cmd}, [stderr_to_stdout]),
- port_command(OpenSslPort, Data),
+ true = port_command(OpenSslPort, Data),
ssl_test_lib:check_result(Server, ok),
@@ -467,7 +468,7 @@ erlang_client_openssl_server_renegotiate(Config) when is_list(Config) ->
Cmd = "openssl s_server -accept " ++ integer_to_list(Port) ++ version_flag(Version) ++
" -cert " ++ CertFile ++ " -key " ++ KeyFile ++ " -msg",
- ct:print("openssl cmd: ~p~n", [Cmd]),
+ ct:log("openssl cmd: ~p~n", [Cmd]),
OpensslPort = open_port({spawn, Cmd}, [stderr_to_stdout]),
@@ -480,9 +481,9 @@ erlang_client_openssl_server_renegotiate(Config) when is_list(Config) ->
delayed_send, [[ErlData, OpenSslData]]}},
{options, ClientOpts}]),
- port_command(OpensslPort, ?OPENSSL_RENEGOTIATE),
+ true = port_command(OpensslPort, ?OPENSSL_RENEGOTIATE),
ct:sleep(?SLEEP),
- port_command(OpensslPort, OpenSslData),
+ true = port_command(OpensslPort, OpenSslData),
ssl_test_lib:check_result(Client, ok),
@@ -516,7 +517,7 @@ erlang_client_openssl_server_nowrap_seqnum(Config) when is_list(Config) ->
Cmd = "openssl s_server -accept " ++ integer_to_list(Port) ++ version_flag(Version) ++
" -cert " ++ CertFile ++ " -key " ++ KeyFile ++ " -msg",
- ct:print("openssl cmd: ~p~n", [Cmd]),
+ ct:log("openssl cmd: ~p~n", [Cmd]),
OpensslPort = open_port({spawn, Cmd}, [stderr_to_stdout]),
@@ -562,11 +563,11 @@ erlang_server_openssl_client_nowrap_seqnum(Config) when is_list(Config) ->
Cmd = "openssl s_client -port " ++ integer_to_list(Port) ++ version_flag(Version) ++
" -host localhost -msg",
- ct:print("openssl cmd: ~p~n", [Cmd]),
+ ct:log("openssl cmd: ~p~n", [Cmd]),
OpenSslPort = open_port({spawn, Cmd}, [stderr_to_stdout]),
- port_command(OpenSslPort, Data),
+ true = port_command(OpenSslPort, Data),
ssl_test_lib:check_result(Server, ok),
@@ -597,7 +598,7 @@ erlang_client_openssl_server_no_server_ca_cert(Config) when is_list(Config) ->
Cmd = "openssl s_server -accept " ++ integer_to_list(Port) ++ version_flag(Version) ++
" -cert " ++ CertFile ++ " -key " ++ KeyFile ++ " -msg",
- ct:print("openssl cmd: ~p~n", [Cmd]),
+ ct:log("openssl cmd: ~p~n", [Cmd]),
OpensslPort = open_port({spawn, Cmd}, [stderr_to_stdout]),
@@ -610,7 +611,7 @@ erlang_client_openssl_server_no_server_ca_cert(Config) when is_list(Config) ->
erlang_ssl_receive, [Data]}},
{options, ClientOpts}]),
- port_command(OpensslPort, Data),
+ true = port_command(OpensslPort, Data),
ssl_test_lib:check_result(Client, ok),
@@ -640,7 +641,7 @@ erlang_client_openssl_server_client_cert(Config) when is_list(Config) ->
" -cert " ++ CertFile ++ " -CAfile " ++ CaCertFile
++ " -key " ++ KeyFile ++ " -Verify 2",
- ct:print("openssl cmd: ~p~n", [Cmd]),
+ ct:log("openssl cmd: ~p~n", [Cmd]),
OpensslPort = open_port({spawn, Cmd}, [stderr_to_stdout]),
@@ -652,7 +653,7 @@ erlang_client_openssl_server_client_cert(Config) when is_list(Config) ->
{mfa, {?MODULE,
erlang_ssl_receive, [Data]}},
{options, ClientOpts}]),
- port_command(OpensslPort, Data),
+ true = port_command(OpensslPort, Data),
ssl_test_lib:check_result(Client, ok),
@@ -691,10 +692,10 @@ erlang_server_openssl_client_client_cert(Config) when is_list(Config) ->
++ " -key " ++ KeyFile ++ " -port " ++ integer_to_list(Port) ++ version_flag(Version) ++
" -host localhost",
- ct:print("openssl cmd: ~p~n", [Cmd]),
+ ct:log("openssl cmd: ~p~n", [Cmd]),
OpenSslPort = open_port({spawn, Cmd}, [stderr_to_stdout]),
- port_command(OpenSslPort, Data),
+ true = port_command(OpenSslPort, Data),
ssl_test_lib:check_result(Server, ok),
@@ -749,7 +750,7 @@ ciphers_rsa_signed_certs(Config) when is_list(Config) ->
Version =
ssl_record:protocol_version(ssl_record:highest_protocol_version([])),
- Ciphers = ssl_test_lib:rsa_suites(),
+ Ciphers = ssl_test_lib:rsa_suites(openssl),
run_suites(Ciphers, Version, Config, rsa).
%%--------------------------------------------------------------------
@@ -779,7 +780,7 @@ erlang_client_bad_openssl_server(Config) when is_list(Config) ->
Cmd = "openssl s_server -accept " ++ integer_to_list(Port) ++ version_flag(Version) ++
" -cert " ++ CertFile ++ " -key " ++ KeyFile ++ "",
- ct:print("openssl cmd: ~p~n", [Cmd]),
+ ct:log("openssl cmd: ~p~n", [Cmd]),
OpensslPort = open_port({spawn, Cmd}, [stderr_to_stdout]),
@@ -793,7 +794,7 @@ erlang_client_bad_openssl_server(Config) when is_list(Config) ->
[{versions, [Version]} | ClientOpts]}]),
%% Send garbage
- port_command(OpensslPort, ?OPENSSL_GARBAGE),
+ true = port_command(OpensslPort, ?OPENSSL_GARBAGE),
ct:sleep(?SLEEP),
@@ -835,7 +836,7 @@ expired_session(Config) when is_list(Config) ->
Cmd = "openssl s_server -accept " ++ integer_to_list(Port) ++
" -cert " ++ CertFile ++ " -key " ++ KeyFile ++ "",
- ct:print("openssl cmd: ~p~n", [Cmd]),
+ ct:log("openssl cmd: ~p~n", [Cmd]),
OpensslPort = open_port({spawn, Cmd}, [stderr_to_stdout]),
@@ -893,10 +894,10 @@ ssl2_erlang_server_openssl_client(Config) when is_list(Config) ->
Cmd = "openssl s_client -port " ++ integer_to_list(Port) ++
" -host localhost -ssl2 -msg",
- ct:print("openssl cmd: ~p~n", [Cmd]),
+ ct:log("openssl cmd: ~p~n", [Cmd]),
OpenSslPort = open_port({spawn, Cmd}, [stderr_to_stdout]),
- port_command(OpenSslPort, Data),
+ true = port_command(OpenSslPort, Data),
receive
{'EXIT', OpenSslPort, _} ->
ok
@@ -912,7 +913,7 @@ erlang_client_openssl_server_npn() ->
erlang_client_openssl_server_npn(Config) when is_list(Config) ->
Data = "From openssl to erlang",
start_erlang_client_and_openssl_server_for_npn_negotiation(Config, Data, fun(Client, OpensslPort) ->
- port_command(OpensslPort, Data),
+ true = port_command(OpensslPort, Data),
ssl_test_lib:check_result(Client, ok)
end),
@@ -925,9 +926,9 @@ erlang_client_openssl_server_npn_renegotiate() ->
erlang_client_openssl_server_npn_renegotiate(Config) when is_list(Config) ->
Data = "From openssl to erlang",
start_erlang_client_and_openssl_server_for_npn_negotiation(Config, Data, fun(Client, OpensslPort) ->
- port_command(OpensslPort, ?OPENSSL_RENEGOTIATE),
+ true = port_command(OpensslPort, ?OPENSSL_RENEGOTIATE),
ct:sleep(?SLEEP),
- port_command(OpensslPort, Data),
+ true = port_command(OpensslPort, Data),
ssl_test_lib:check_result(Client, ok)
end),
ok.
@@ -939,7 +940,7 @@ erlang_server_openssl_client_npn(Config) when is_list(Config) ->
Data = "From openssl to erlang",
start_erlang_server_and_openssl_client_for_npn_negotiation(Config, Data, fun(Server, OpensslPort) ->
- port_command(OpensslPort, Data),
+ true = port_command(OpensslPort, Data),
ssl_test_lib:check_result(Server, ok)
end),
ok.
@@ -951,9 +952,9 @@ erlang_server_openssl_client_npn_renegotiate() ->
erlang_server_openssl_client_npn_renegotiate(Config) when is_list(Config) ->
Data = "From openssl to erlang",
start_erlang_server_and_openssl_client_for_npn_negotiation(Config, Data, fun(Server, OpensslPort) ->
- port_command(OpensslPort, ?OPENSSL_RENEGOTIATE),
+ true = port_command(OpensslPort, ?OPENSSL_RENEGOTIATE),
ct:sleep(?SLEEP),
- port_command(OpensslPort, Data),
+ true = port_command(OpensslPort, Data),
ssl_test_lib:check_result(Server, ok)
end),
ok.
@@ -962,7 +963,7 @@ erlang_client_openssl_server_npn_only_server(Config) when is_list(Config) ->
Data = "From openssl to erlang",
start_erlang_client_and_openssl_server_with_opts(Config, [],
"-nextprotoneg spdy/2", Data, fun(Server, OpensslPort) ->
- port_command(OpensslPort, Data),
+ true = port_command(OpensslPort, Data),
ssl_test_lib:check_result(Server, ok)
end),
ok.
@@ -975,7 +976,7 @@ erlang_client_openssl_server_npn_only_client(Config) when is_list(Config) ->
[{client_preferred_next_protocols,
{client, [<<"spdy/2">>], <<"http/1.1">>}}], "",
Data, fun(Server, OpensslPort) ->
- port_command(OpensslPort, Data),
+ true = port_command(OpensslPort, Data),
ssl_test_lib:check_result(Server, ok)
end),
ok.
@@ -985,7 +986,7 @@ erlang_server_openssl_client_npn_only_server(Config) when is_list(Config) ->
Data = "From openssl to erlang",
start_erlang_server_and_openssl_client_with_opts(Config, [{next_protocols_advertised, [<<"spdy/2">>]}], "",
Data, fun(Server, OpensslPort) ->
- port_command(OpensslPort, Data),
+ true = port_command(OpensslPort, Data),
ssl_test_lib:check_result(Server, ok)
end),
ok.
@@ -994,7 +995,7 @@ erlang_server_openssl_client_npn_only_client(Config) when is_list(Config) ->
Data = "From openssl to erlang",
start_erlang_server_and_openssl_client_with_opts(Config, [], "-nextprotoneg spdy/2",
Data, fun(Server, OpensslPort) ->
- port_command(OpensslPort, Data),
+ true = port_command(OpensslPort, Data),
ssl_test_lib:check_result(Server, ok)
end),
ok.
@@ -1020,13 +1021,13 @@ run_suites(Ciphers, Version, Config, Type) ->
[] ->
ok;
Error ->
- ct:print("Cipher suite errors: ~p~n", [Error]),
+ ct:log("Cipher suite errors: ~p~n", [Error]),
ct:fail(cipher_suite_failed_see_test_case_log)
end.
cipher(CipherSuite, Version, Config, ClientOpts, ServerOpts) ->
process_flag(trap_exit, true),
- ct:print("Testing CipherSuite ~p~n", [CipherSuite]),
+ ct:log("Testing CipherSuite ~p~n", [CipherSuite]),
{ClientNode, _ServerNode, Hostname} = ssl_test_lib:run_where(Config),
Port = ssl_test_lib:inet_port(node()),
@@ -1036,7 +1037,7 @@ cipher(CipherSuite, Version, Config, ClientOpts, ServerOpts) ->
Cmd = "openssl s_server -accept " ++ integer_to_list(Port) ++ version_flag(Version) ++
" -cert " ++ CertFile ++ " -key " ++ KeyFile ++ "",
- ct:print("openssl cmd: ~p~n", [Cmd]),
+ ct:log("openssl cmd: ~p~n", [Cmd]),
OpenSslPort = open_port({spawn, Cmd}, [stderr_to_stdout]),
@@ -1052,19 +1053,19 @@ cipher(CipherSuite, Version, Config, ClientOpts, ServerOpts) ->
[{ciphers,[CipherSuite]} |
ClientOpts]}]),
- port_command(OpenSslPort, "Hello\n"),
+ true = port_command(OpenSslPort, "Hello\n"),
receive
{Port, {data, _}} when is_port(Port) ->
ok
after 500 ->
- ct:print("Time out on openssl port, check that"
+ ct:log("Time out on openssl port, check that"
" the messages Hello and world are received"
" during close of port" , []),
ok
end,
- port_command(OpenSslPort, " world\n"),
+ true = port_command(OpenSslPort, " world\n"),
Result = ssl_test_lib:wait_for_result(Client, ok),
@@ -1100,7 +1101,7 @@ start_erlang_client_and_openssl_server_with_opts(Config, ErlangClientOpts, Opens
integer_to_list(Port) ++ version_flag(Version) ++
" -cert " ++ CertFile ++ " -key " ++ KeyFile,
- ct:print("openssl cmd: ~p~n", [Cmd]),
+ ct:log("openssl cmd: ~p~n", [Cmd]),
OpensslPort = open_port({spawn, Cmd}, [stderr_to_stdout]),
@@ -1139,7 +1140,7 @@ start_erlang_client_and_openssl_server_for_npn_negotiation(Config, Data, Callbac
Cmd = "openssl s_server -msg -nextprotoneg http/1.1,spdy/2 -accept " ++ integer_to_list(Port) ++ version_flag(Version) ++
" -cert " ++ CertFile ++ " -key " ++ KeyFile,
- ct:print("openssl cmd: ~p~n", [Cmd]),
+ ct:log("openssl cmd: ~p~n", [Cmd]),
OpensslPort = open_port({spawn, Cmd}, [stderr_to_stdout]),
@@ -1177,7 +1178,7 @@ start_erlang_server_and_openssl_client_for_npn_negotiation(Config, Data, Callbac
Cmd = "openssl s_client -nextprotoneg http/1.0,spdy/2 -msg -port " ++ integer_to_list(Port) ++ version_flag(Version) ++
" -host localhost",
- ct:print("openssl cmd: ~p~n", [Cmd]),
+ ct:log("openssl cmd: ~p~n", [Cmd]),
OpenSslPort = open_port({spawn, Cmd}, [stderr_to_stdout]),
@@ -1206,7 +1207,7 @@ start_erlang_server_and_openssl_client_with_opts(Config, ErlangServerOpts, OpenS
Cmd = "openssl s_client " ++ OpenSSLClientOpts ++ " -msg -port " ++ integer_to_list(Port) ++ version_flag(Version) ++
" -host localhost",
- ct:print("openssl cmd: ~p~n", [Cmd]),
+ ct:log("openssl cmd: ~p~n", [Cmd]),
OpenSslPort = open_port({spawn, Cmd}, [stderr_to_stdout]),
@@ -1225,7 +1226,7 @@ erlang_ssl_receive_and_assert_npn(Socket, Protocol, Data) ->
ok.
erlang_ssl_receive(Socket, Data) ->
- ct:print("Connection info: ~p~n",
+ ct:log("Connection info: ~p~n",
[ssl:connection_info(Socket)]),
receive
{ssl, Socket, Data} ->
@@ -1247,7 +1248,7 @@ erlang_ssl_receive(Socket, Data) ->
connection_info(Socket, Version) ->
case ssl:connection_info(Socket) of
{ok, {Version, _} = Info} ->
- ct:print("Connection info: ~p~n", [Info]),
+ ct:log("Connection info: ~p~n", [Info]),
ok;
{ok, {OtherVersion, _}} ->
{wrong_version, OtherVersion}
@@ -1269,28 +1270,28 @@ close_port(Port) ->
close_loop(Port, Time, SentClose) ->
receive
{Port, {data,Debug}} when is_port(Port) ->
- io:format("openssl ~s~n",[Debug]),
+ ct:log("openssl ~s~n",[Debug]),
close_loop(Port, Time, SentClose);
{ssl,_,Msg} ->
- io:format("ssl Msg ~s~n",[Msg]),
+ ct:log("ssl Msg ~s~n",[Msg]),
close_loop(Port, Time, SentClose);
{Port, closed} ->
- io:format("Port Closed~n",[]),
+ ct:log("Port Closed~n",[]),
ok;
{'EXIT', Port, Reason} ->
- io:format("Port Closed ~p~n",[Reason]),
+ ct:log("Port Closed ~p~n",[Reason]),
ok;
Msg ->
- io:format("Port Msg ~p~n",[Msg]),
+ ct:log("Port Msg ~p~n",[Msg]),
close_loop(Port, Time, SentClose)
after Time ->
case SentClose of
false ->
- io:format("Closing port ~n",[]),
+ ct:log("Closing port ~n",[]),
catch erlang:port_close(Port),
close_loop(Port, Time, true);
true ->
- io:format("Timeout~n",[])
+ ct:log("Timeout~n",[])
end
end.
@@ -1305,7 +1306,7 @@ server_sent_garbage(Socket) ->
wait_for_openssl_server() ->
receive
{Port, {data, Debug}} when is_port(Port) ->
- io:format("openssl ~s~n",[Debug]),
+ ct:log("openssl ~s~n",[Debug]),
%% openssl has started make sure
%% it will be in accept. Parsing
%% output is too error prone. (Even
diff --git a/lib/stdlib/doc/src/lists.xml b/lib/stdlib/doc/src/lists.xml
index b6c0fa4e05..1aff78f4fc 100644
--- a/lib/stdlib/doc/src/lists.xml
+++ b/lib/stdlib/doc/src/lists.xml
@@ -152,6 +152,31 @@
</desc>
</func>
<func>
+ <name name="filtermap" arity="2"/>
+ <fsummary>Filter and map elements which satisfy a function</fsummary>
+ <desc>
+ <p>Calls <c><anno>Fun</anno>(<anno>Elem</anno>)</c> on successive elements <c>Elem</c>
+ of <c><anno>List1</anno></c>. <c><anno>Fun</anno>/2</c> must return either a boolean
+ or a tuple <c>{true, <anno>Value</anno>}</c>. The function returns the list of elements
+ for which <c><anno>Fun</anno></c> returns a new value, where a value of <c>true</c>
+ is synonymous with <c>{true, <anno>Elem</anno>}</c>.</p>
+ <p>That is, <c>filtermap</c> behaves as if it had been defined as follows:</p>
+ <code type="none">
+filtermap(Fun, List1) ->
+ lists:foldr(fun(Elem, Acc) ->
+ case Fun(Elem) of
+ false -> Acc;
+ true -> [Elem|Acc];
+ {true,Value} -> [Value|Acc]
+ end,
+ end, [], List1).</code>
+ <p>Example:</p>
+ <pre>
+> <input>lists:filtermap(fun(X) -> case X rem 2 of 0 -> {true, X div 2}; _ -> false end end, [1,2,3,4,5]).</input>
+[1,2]</pre>
+ </desc>
+ </func>
+ <func>
<name name="flatlength" arity="1"/>
<fsummary>Length of flattened deep list</fsummary>
<desc>
diff --git a/lib/stdlib/src/epp.erl b/lib/stdlib/src/epp.erl
index e31cd63f69..d1d060ebc8 100644
--- a/lib/stdlib/src/epp.erl
+++ b/lib/stdlib/src/epp.erl
@@ -601,7 +601,7 @@ enter_file2(NewF, Pname, From, St0, AtLocation) ->
%% file will depend on the order of file inclusions in the parent files
Path = [filename:dirname(Pname) | tl(St0#epp.path)],
_ = set_encoding(NewF),
- #epp{file=NewF,location=Loc,name=Pname,delta=0,
+ #epp{file=NewF,location=Loc,name=Pname,name2=Pname,delta=0,
sstk=[St0|St0#epp.sstk],path=Path,macs=Ms}.
enter_file_reply(From, Name, Location, AtLocation) ->
diff --git a/lib/stdlib/src/erl_pp.erl b/lib/stdlib/src/erl_pp.erl
index 7c7566e4ec..c0596e5ba6 100644
--- a/lib/stdlib/src/erl_pp.erl
+++ b/lib/stdlib/src/erl_pp.erl
@@ -35,7 +35,7 @@
| fun((Expr :: erl_parse:abstract_expr(),
CurrentIndentation :: integer(),
CurrentPrecedence :: non_neg_integer(),
- HookFunction :: hook_function()) ->
+ Options :: options()) ->
io_lib:chars())).
-type(option() :: {hook, hook_function()}
@@ -225,7 +225,7 @@ lattribute(module, {M,Vs}, _Opts, _State) ->
lattribute(module, M, _Opts, _State) ->
attr("module", [{var,0,pname(M)}]);
lattribute(export, Falist, _Opts, _State) ->
- call({var,0,"-export"}, [falist(Falist)], 0, none);
+ call({var,0,"-export"}, [falist(Falist)], 0, options(none));
lattribute(import, Name, _Opts, _State) when is_list(Name) ->
attr("import", [{var,0,pname(Name)}]);
lattribute(import, {From,Falist}, _Opts, _State) ->
@@ -240,10 +240,10 @@ lattribute(Name, Arg, #options{encoding = Encoding}, _State) ->
typeattr(Tag, {TypeName,Type,Args}, _Opts) ->
{first,leaf("-"++atom_to_list(Tag)++" "),
- typed(call({atom,0,TypeName}, Args, 0, none), Type)}.
+ typed(call({atom,0,TypeName}, Args, 0, options(none)), Type)}.
ltype({ann_type,_Line,[V,T]}) ->
- typed(lexpr(V, none), T);
+ typed(lexpr(V, options(none)), T);
ltype({paren_type,_Line,[T]}) ->
[$(,ltype(T),$)];
ltype({type,_Line,union,Ts}) ->
@@ -253,7 +253,7 @@ ltype({type,_Line,list,[T]}) ->
ltype({type,_Line,nonempty_list,[T]}) ->
{seq,$[,$],[$,],[ltype(T),leaf("...")]};
ltype({type,Line,nil,[]}) ->
- lexpr({nil,Line}, 0, none);
+ lexpr({nil,Line}, 0, options(none));
ltype({type,Line,tuple,any}) ->
simple_type({atom,Line,tuple}, []);
ltype({type,_Line,tuple,Ts}) ->
@@ -261,7 +261,7 @@ ltype({type,_Line,tuple,Ts}) ->
ltype({type,_Line,record,[{atom,_,N}|Fs]}) ->
record_type(N, Fs);
ltype({type,_Line,range,[_I1,_I2]=Es}) ->
- expr_list(Es, '..', fun lexpr/2, none);
+ expr_list(Es, '..', fun lexpr/2, options(none));
ltype({type,_Line,binary,[I1,I2]}) ->
binary_type(I1, I2); % except binary()
ltype({type,_Line,'fun',[]}) ->
@@ -277,14 +277,14 @@ ltype({remote_type,Line,[M,F,Ts]}) ->
ltype({atom,_,T}) ->
leaf(write(T));
ltype(E) ->
- lexpr(E, 0, none).
+ lexpr(E, 0, options(none)).
binary_type(I1, I2) ->
B = [[] || {integer,_,0} <- [I1]] =:= [],
U = [[] || {integer,_,0} <- [I2]] =:= [],
P = max_prec(),
- E1 = [[leaf("_:"),lexpr(I1, P, none)] || B],
- E2 = [[leaf("_:_*"),lexpr(I2, P, none)] || U],
+ E1 = [[leaf("_:"),lexpr(I1, P, options(none))] || B],
+ E2 = [[leaf("_:_*"),lexpr(I2, P, options(none))] || U],
{seq,'<<','>>',[$,],E1++E2}.
record_type(Name, Fields) ->
@@ -294,7 +294,7 @@ field_types(Fs) ->
tuple_type(Fs, fun field_type/1).
field_type({type,_Line,field_type,[Name,Type]}) ->
- typed(lexpr(Name, none), Type).
+ typed(lexpr(Name, options(none)), Type).
typed(B, {type,_,union,Ts}) ->
%% Special layout for :: followed by union.
@@ -330,7 +330,8 @@ sig_type(FunType) ->
fun_type([], FunType).
guard_type(Before, Gs) ->
- Gl = {list,[{step,'when',expr_list(Gs, [$,], fun constraint/2, none)}]},
+ Opts = options(none),
+ Gl = {list,[{step,'when',expr_list(Gs, [$,], fun constraint/2, Opts)}]},
{list,[{step,Before,Gl}]}.
constraint({type,_Line,constraint,[Tag,As]}, _Opts) ->
@@ -345,7 +346,7 @@ type_args({type,_line,product,Ts}) ->
targs(Ts).
simple_type(Tag, Types) ->
- {first,lexpr(Tag, 0, none),targs(Types)}.
+ {first,lexpr(Tag, 0, options(none)),targs(Types)}.
targs(Ts) ->
{seq,$(,$),[$,],ltypes(Ts)}.
@@ -357,7 +358,7 @@ ltypes(Ts, F) ->
[F(T) || T <- Ts].
attr(Name, Args) ->
- call({var,0,format("-~s", [Name])}, Args, 0, none).
+ call({var,0,format("-~s", [Name])}, Args, 0, options(none)).
pname(['' | As]) ->
[$. | pname(As)];
@@ -632,11 +633,11 @@ bit_elem_types([T | Rest]) ->
[bit_elem_type(T), $-|bit_elem_types(Rest)].
bit_elem_type({A,B}) ->
- [lexpr(erl_parse:abstract(A), none),
+ [lexpr(erl_parse:abstract(A), options(none)),
$:,
- lexpr(erl_parse:abstract(B), none)];
+ lexpr(erl_parse:abstract(B), options(none))];
bit_elem_type(T) ->
- lexpr(erl_parse:abstract(T), none).
+ lexpr(erl_parse:abstract(T), options(none)).
%% end of BITS
diff --git a/lib/stdlib/src/lists.erl b/lib/stdlib/src/lists.erl
index 961c060019..0c033acd88 100644
--- a/lib/stdlib/src/lists.erl
+++ b/lib/stdlib/src/lists.erl
@@ -36,7 +36,7 @@
-export([merge/3, rmerge/3, sort/2, umerge/3, rumerge/3, usort/2]).
-export([all/2,any/2,map/2,flatmap/2,foldl/3,foldr/3,filter/2,
- partition/2,zf/2,
+ partition/2,zf/2,filtermap/2,
mapfoldl/3,mapfoldr/3,foreach/2,takewhile/2,dropwhile/2,splitwith/2,
split/2]).
@@ -1291,18 +1291,28 @@ partition(Pred, [H | T], As, Bs) ->
partition(Pred, [], As, Bs) when is_function(Pred, 1) ->
{reverse(As), reverse(Bs)}.
--spec zf(fun((T) -> boolean() | {'true', X}), [T]) -> [(T | X)].
+-spec filtermap(Fun, List1) -> List2 when
+ Fun :: fun((Elem) -> boolean() | {'true', Value}),
+ List1 :: [Elem],
+ List2 :: [Elem | Value],
+ Elem :: term(),
+ Value :: term().
-zf(F, [Hd|Tail]) ->
+filtermap(F, [Hd|Tail]) ->
case F(Hd) of
true ->
- [Hd|zf(F, Tail)];
+ [Hd|filtermap(F, Tail)];
{true,Val} ->
- [Val|zf(F, Tail)];
+ [Val|filtermap(F, Tail)];
false ->
- zf(F, Tail)
+ filtermap(F, Tail)
end;
-zf(F, []) when is_function(F, 1) -> [].
+filtermap(F, []) when is_function(F, 1) -> [].
+
+-spec zf(fun((T) -> boolean() | {'true', X}), [T]) -> [(T | X)].
+
+zf(F, L) ->
+ filtermap(F, L).
-spec foreach(Fun, List) -> ok when
Fun :: fun((Elem :: T) -> term()),
diff --git a/lib/stdlib/src/otp_internal.erl b/lib/stdlib/src/otp_internal.erl
index a4f4035c79..f2849e50ec 100644
--- a/lib/stdlib/src/otp_internal.erl
+++ b/lib/stdlib/src/otp_internal.erl
@@ -66,6 +66,139 @@ obsolete_1(rpc, safe_multi_server_call, A) when A =:= 2; A =:= 3 ->
{deprecated, {rpc, multi_server_call, A}};
+%% *** CRYPTO add in R16B01 ***
+
+obsolete_1(crypto, md4, 1) ->
+ {deprecated, {crypto, hash, 2}};
+obsolete_1(crypto, md5, 1) ->
+ {deprecated, {crypto, hash, 2}};
+obsolete_1(crypto, sha, 1) ->
+ {deprecated, {crypto, hash, 2}};
+
+obsolete_1(crypto, md4_init, 1) ->
+ {deprecated, {crypto, hash_init, 2}};
+obsolete_1(crypto, md5_init, 1) ->
+ {deprecated, {crypto, hash_init, 2}};
+obsolete_1(crypto, sha_init, 1) ->
+ {deprecated, {crypto, hash_init, 2}};
+
+obsolete_1(crypto, md4_update, 2) ->
+ {deprecated, {crypto, hash_update, 3}};
+obsolete_1(crypto, md5_update, 2) ->
+ {deprecated, {crypto, hash_update, 3}};
+obsolete_1(crypto, sah_update, 2) ->
+ {deprecated, {crypto, hash_update, 3}};
+
+obsolete_1(crypto, md4_final, 1) ->
+ {deprecated, {crypto, hash_final, 2}};
+obsolete_1(crypto, md5_final, 1) ->
+ {deprecated, {crypto, hash_final, 2}};
+obsolete_1(crypto, sha_final, 1) ->
+ {deprecated, {crypto, hash_final, 2}};
+
+obsolete_1(crypto, md5_mac, 2) ->
+ {deprecated, {crypto, hmac, 3}};
+obsolete_1(crypto, sha_mac, 2) ->
+ {deprecated, {crypto, hmac, 3}};
+
+obsolete_1(crypto, sha_mac_96, 2) ->
+ {deprecated, {crypto, hmac_n, 3}};
+obsolete_1(crypto, md5_mac_96, 2) ->
+ {deprecated, {crypto, hmac_n, 3}};
+
+obsolete_1(crypto, rsa_sign, 3) ->
+ {deprecated, {crypto, sign, 4}};
+obsolete_1(crypto, rsa_verify, 3) ->
+ {deprecated, {crypto, verify, 4}};
+
+obsolete_1(crypto, dss_sign, 2) ->
+ {deprecated, {crypto, sign, 4}};
+obsolete_1(crypto, dss_sign, 3) ->
+ {deprecated, {crypto, sign, 4}};
+
+obsolete_1(crypto, dss_verify, 3) ->
+ {deprecated, {crypto, verify, 4}};
+obsolete_1(crypto, dss_verify, 4) ->
+ {deprecated, {crypto, verify, 4}};
+
+obsolete_1(crypto, mod_exp, 3) ->
+ {deprecated, {crypto, mod_pow, 3}};
+
+obsolete_1(crypto, dh_compute_key, 3) ->
+ {deprecated, {crypto, compute_key, 4}};
+obsolete_1(crypto, dh_generate_key, 1) ->
+ {deprecated, {crypto, generate_key, 3}};
+obsolete_1(crypto, dh_generate_key, 2) ->
+ {deprecated, {crypto, generate_key, 3}};
+
+obsolete_1(crypto, des_cbc_encrypt, 3) ->
+ {deprecated, {crypto, block_encrypt, 4}};
+obsolete_1(crypto, des3_cbc_encrypt, 5) ->
+ {deprecated, {crypto, block_encrypt, 4}};
+obsolete_1(crypto, des_ecb_encrypt, 3) ->
+ {deprecated, {crypto, block_encrypt, 4}};
+obsolete_1(crypto, des_ede3_cbc_encrypt, 5) ->
+ {deprecated, {crypto, block_encrypt, 4}};
+obsolete_1(crypto, des_cfb_encrypt, 3) ->
+ {deprecated, {crypto, block_encrypt, 4}};
+obsolete_1(crypto, des3_cfb_encrypt, 5) ->
+ {deprecated, {crypto, block_encrypt, 4}};
+obsolete_1(crypto, blowfish_ecb_encrypt, 2) ->
+ {deprecated, {crypto, block_encrypt, 3}};
+obsolete_1(crypto, blowfish_cbc_encrypt, 3) ->
+ {deprecated, {crypto, block_encrypt, 4}};
+obsolete_1(crypto, blowfish_cfb64_encrypt, 3) ->
+ {deprecated, {crypto, block_encrypt, 4}};
+obsolete_1(crypto, blowfish_ofb64_encrypt, 3) ->
+ {deprecated, {crypto, block_encrypt, 4}};
+obsolete_1(crypto, aes_cfb_128_encrypt, 3) ->
+ {deprecated, {crypto, block_encrypt, 4}};
+obsolete_1(crypto, aes_cbc_256_encrypt, 3) ->
+ {deprecated, {crypto, block_encrypt, 4}};
+obsolete_1(crypto,rc2_cbc_encrypt, 3) ->
+ {deprecated, {crypto, block_encrypt, 4}};
+obsolete_1(crypto,rc2_40_cbc_encrypt, 3) ->
+ {deprecated, {crypto, block_encrypt, 4}};
+
+obsolete_1(crypto, des_cbc_decrypt, 3) ->
+ {deprecated, {crypto, block_decrypt, 4}};
+obsolete_1(crypto, des3_cbc_decrypt, 5) ->
+ {deprecated, {crypto, block_decrypt, 4}};
+obsolete_1(crypto, des_ecb_decrypt, 3) ->
+ {deprecated, {crypto, block_decrypt, 4}};
+obsolete_1(crypto, des_ede3_cbc_decrypt, 5) ->
+ {deprecated, {crypto, block_decrypt, 4}};
+obsolete_1(crypto, des_cfb_decrypt, 3) ->
+ {deprecated, {crypto, block_decrypt, 4}};
+obsolete_1(crypto, des3_cfb_decrypt, 5) ->
+ {deprecated, {crypto, block_decrypt, 4}};
+obsolete_1(crypto, blowfish_ecb_decrypt, 2) ->
+ {deprecated, {crypto, block_decrypt, 3}};
+obsolete_1(crypto, blowfish_cbc_decrypt, 3) ->
+ {deprecated, {crypto, block_decrypt, 4}};
+obsolete_1(crypto, blowfish_cfb64_decrypt, 3) ->
+ {deprecated, {crypto, block_decrypt, 4}};
+obsolete_1(crypto, blowfish_ofb64_decrypt, 3) ->
+ {deprecated, {crypto, block_decrypt, 4}};
+obsolete_1(crypto, aes_cfb_128_decrypt, 3) ->
+ {deprecated, {crypto, block_decrypt, 4}};
+obsolete_1(crypto, aes_cbc_256_decrypt, 3) ->
+ {deprecated, {crypto, block_decrypt, 4}};
+obsolete_1(crypto,rc2_cbc_decrypt, 3) ->
+ {deprecated, {crypto, block_decrypt, 4}};
+obsolete_1(crypto,rc2_40_cbc_decrypt, 3) ->
+ {deprecated, {crypto, block_decrypt, 4}};
+
+obsolete_1(crypto,info, 0) ->
+ {deprecated, {crypto, module_info, 0}};
+
+obsolete_1(crypto, strong_rand_mpint, 3) ->
+ {deprecated, "needed only by deprecated functions"};
+obsolete_1(crypto, erlint, 3) ->
+ {deprecated, "needed only by deprecated functions"};
+obsolete_1(crypto, mpint, 3) ->
+ {deprecated, "needed only by deprecated functions"};
+
%% *** SNMP ***
obsolete_1(snmp, N, A) ->
diff --git a/lib/stdlib/test/epp_SUITE.erl b/lib/stdlib/test/epp_SUITE.erl
index b2f1aa955a..0cbdf76270 100644
--- a/lib/stdlib/test/epp_SUITE.erl
+++ b/lib/stdlib/test/epp_SUITE.erl
@@ -104,6 +104,8 @@ include_local(suite) ->
include_local(Config) when is_list(Config) ->
?line DataDir = ?config(data_dir, Config),
?line File = filename:join(DataDir, "include_local.erl"),
+ FooHrl = filename:join([DataDir,"include","foo.hrl"]),
+ BarHrl = filename:join([DataDir,"include","bar.hrl"]),
%% include_local.erl includes include/foo.hrl which
%% includes bar.hrl (also in include/) without requiring
%% any additional include path, and overriding any file
@@ -111,6 +113,8 @@ include_local(Config) when is_list(Config) ->
?line {ok, List} = epp:parse_file(File, [DataDir], []),
?line {value, {attribute,_,a,{true,true}}} =
lists:keysearch(a,3,List),
+ [{File,1},{FooHrl,1},{BarHrl,1},{FooHrl,5},{File,5}] =
+ [ FileLine || {attribute,_,file,FileLine} <- List ],
ok.
%%% Here is a little reimplementation of epp:parse_file, which times out
diff --git a/lib/stdlib/test/erl_pp_SUITE.erl b/lib/stdlib/test/erl_pp_SUITE.erl
index 9c0a43abcc..ff3470349e 100644
--- a/lib/stdlib/test/erl_pp_SUITE.erl
+++ b/lib/stdlib/test/erl_pp_SUITE.erl
@@ -49,7 +49,7 @@
otp_6321/1, otp_6911/1, otp_6914/1, otp_8150/1, otp_8238/1,
otp_8473/1, otp_8522/1, otp_8567/1, otp_8664/1, otp_9147/1,
- otp_10302/1, otp_10820/1]).
+ otp_10302/1, otp_10820/1, otp_11100/1]).
%% Internal export.
-export([ehook/6]).
@@ -81,7 +81,7 @@ groups() ->
{tickets, [],
[otp_6321, otp_6911, otp_6914, otp_8150, otp_8238,
otp_8473, otp_8522, otp_8567, otp_8664, otp_9147,
- otp_10302, otp_10820]}].
+ otp_10302, otp_10820, otp_11100]}].
init_per_suite(Config) ->
Config.
@@ -1103,6 +1103,45 @@ file_attr_is_string("-file(\"" ++ _) -> true;
file_attr_is_string([_ | L]) ->
file_attr_is_string(L).
+otp_11100(doc) ->
+ "OTP-11100. Fix printing of invalid forms.";
+otp_11100(suite) -> [];
+otp_11100(Config) when is_list(Config) ->
+ %% There are a few places where the added code ("options(none)")
+ %% doesn't make a difference (pp:bit_elem_type/1 is an example).
+
+ %% Cannot trigger the use of the hook function with export/import.
+ "-export([{fy,a}/b]).\n" =
+ pf({attribute,1,export,[{{fy,a},b}]}),
+ "-type foo() :: integer(INVALID-FORM:{foo,bar}:).\n" =
+ pf({attribute,1,type,{foo,{type,1,integer,[{foo,bar}]},[]}}),
+ pf({attribute,1,type,
+ {a,{type,1,range,[{integer,1,1},{foo,bar}]},[]}}),
+ "-type foo(INVALID-FORM:{foo,bar}:) :: A.\n" =
+ pf({attribute,1,type,{foo,{var,1,'A'},[{foo,bar}]}}),
+ "-type foo() :: (INVALID-FORM:{foo,bar}: :: []).\n" =
+ pf({attribute,1,type,
+ {foo,{paren_type,1,
+ [{ann_type,1,[{foo,bar},{type,1,nil,[]}]}]},
+ []}}),
+ "-type foo() :: <<_:INVALID-FORM:{foo,bar}:>>.\n" =
+ pf({attribute,1,type,
+ {foo,{type,1,binary,[{foo,bar},{integer,1,0}]},[]}}),
+ "-type foo() :: <<_:10, _:_*INVALID-FORM:{foo,bar}:>>.\n" =
+ pf({attribute,1,type,
+ {foo,{type,1,binary,[{integer,1,10},{foo,bar}]},[]}}),
+ "-type foo() :: #r{INVALID-FORM:{foo,bar}: :: integer()}.\n" =
+ pf({attribute,1,type,
+ {foo,{type,1,record,
+ [{atom,1,r},
+ {type,1,field_type,
+ [{foo,bar},{type,1,integer,[]}]}]},
+ []}}),
+ ok.
+
+pf(Form) ->
+ lists:flatten(erl_pp:form(Form,none)).
+
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
compile(Config, Tests) ->
diff --git a/lib/stdlib/test/ets_SUITE.erl b/lib/stdlib/test/ets_SUITE.erl
index af5d5a8f21..bd69019892 100644
--- a/lib/stdlib/test/ets_SUITE.erl
+++ b/lib/stdlib/test/ets_SUITE.erl
@@ -75,6 +75,7 @@
-export([otp_9932/1]).
-export([otp_9423/1]).
-export([otp_10182/1]).
+-export([memory_check_summary/1]).
-export([init_per_testcase/2, end_per_testcase/2]).
%% Convenience for manual testing
@@ -149,7 +150,9 @@ all() ->
give_away, setopts, bad_table, types,
otp_10182,
otp_9932,
- otp_9423].
+ otp_9423,
+
+ memory_check_summary]. % MUST BE LAST
groups() ->
[{new, [],
@@ -185,7 +188,8 @@ init_per_suite(Config) ->
end_per_suite(_Config) ->
stop_spawn_logger(),
- catch erts_debug:set_internal_state(available_internal_state, false).
+ catch erts_debug:set_internal_state(available_internal_state, false),
+ ok.
init_per_group(_GroupName, Config) ->
Config.
@@ -193,6 +197,26 @@ init_per_group(_GroupName, Config) ->
end_per_group(_GroupName, Config) ->
Config.
+%% Test that we did not have "too many" failed verify_etsmem()'s
+%% in the test suite.
+%% verify_etsmem() may give a low number of false positives
+%% as concurrent activities, such as lingering processes
+%% from earlier test suites, may do unrelated ets (de)allocations.
+memory_check_summary(_Config) ->
+ case whereis(ets_test_spawn_logger) of
+ undefined ->
+ ?t:fail("No spawn logger exist");
+ _ ->
+ ets_test_spawn_logger ! {self(), get_failed_memchecks},
+ receive {get_failed_memchecks, FailedMemchecks} -> ok end,
+ io:format("Failed memchecks: ~p\n",[FailedMemchecks]),
+ if FailedMemchecks > 3 ->
+ ct:fail("Too many failed (~p) memchecks", [FailedMemchecks]);
+ true ->
+ ok
+ end
+ end.
+
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
@@ -5635,7 +5659,8 @@ verify_etsmem({MemInfo,AllTabs}) ->
io:format("Actual: ~p", [MemInfo2]),
io:format("Changed tables before: ~p\n",[AllTabs -- AllTabs2]),
io:format("Changed tables after: ~p\n", [AllTabs2 -- AllTabs]),
- ?t:fail()
+ ets_test_spawn_logger ! failed_memcheck,
+ {comment, "Failed memory check"}
end.
@@ -5657,10 +5682,10 @@ stop_loopers(Loopers) ->
looper(Fun, State) ->
looper(Fun, Fun(State)).
-spawn_logger(Procs) ->
+spawn_logger(Procs, FailedMemchecks) ->
receive
{new_test_proc, Proc} ->
- spawn_logger([Proc|Procs]);
+ spawn_logger([Proc|Procs], FailedMemchecks);
{sync_test_procs, Kill, From} ->
lists:foreach(fun (Proc) when From == Proc ->
ok;
@@ -5683,7 +5708,14 @@ spawn_logger(Procs) ->
end
end, Procs),
From ! test_procs_synced,
- spawn_logger([From])
+ spawn_logger([From], FailedMemchecks);
+
+ failed_memcheck ->
+ spawn_logger(Procs, FailedMemchecks+1);
+
+ {Pid, get_failed_memchecks} ->
+ Pid ! {get_failed_memchecks, FailedMemchecks},
+ spawn_logger(Procs, FailedMemchecks)
end.
pid_status(Pid) ->
@@ -5699,7 +5731,7 @@ start_spawn_logger() ->
case whereis(ets_test_spawn_logger) of
Pid when is_pid(Pid) -> true;
_ -> register(ets_test_spawn_logger,
- spawn_opt(fun () -> spawn_logger([]) end,
+ spawn_opt(fun () -> spawn_logger([], 0) end,
[{priority, max}]))
end.
@@ -5710,8 +5742,7 @@ start_spawn_logger() ->
stop_spawn_logger() ->
Mon = erlang:monitor(process, ets_test_spawn_logger),
(catch exit(whereis(ets_test_spawn_logger), kill)),
- receive {'DOWN', Mon, _, _, _} -> ok end,
- ok.
+ receive {'DOWN', Mon, _, _, _} -> ok end.
wait_for_test_procs() ->
wait_for_test_procs(false).
@@ -5811,7 +5842,7 @@ spawn_monitor_with_pid(Pid, Fun, N) ->
end) of
Pid ->
{Pid, erlang:monitor(process, Pid)};
- Other ->
+ _Other ->
spawn_monitor_with_pid(Pid,Fun,N-1)
end.
@@ -6117,11 +6148,18 @@ repeat_for_opts(F, OptGenList) ->
repeat_for_opts(F, OptGenList, []).
repeat_for_opts(F, [], Acc) ->
- lists:map(fun(Opts) ->
- OptList = lists:filter(fun(E) -> E =/= void end, Opts),
- io:format("Calling with options ~p\n",[OptList]),
- F(OptList)
- end, Acc);
+ lists:foldl(fun(Opts, RV_Acc) ->
+ OptList = lists:filter(fun(E) -> E =/= void end, Opts),
+ io:format("Calling with options ~p\n",[OptList]),
+ RV = F(OptList),
+ case RV_Acc of
+ {comment,_} -> RV_Acc;
+ _ -> case RV of
+ {comment,_} -> RV;
+ _ -> [RV | RV_Acc]
+ end
+ end
+ end, [], Acc);
repeat_for_opts(F, [OptList | Tail], []) when is_list(OptList) ->
repeat_for_opts(F, Tail, [[Opt] || Opt <- OptList]);
repeat_for_opts(F, [OptList | Tail], AccList) when is_list(OptList) ->
diff --git a/lib/stdlib/test/gen_server_SUITE.erl b/lib/stdlib/test/gen_server_SUITE.erl
index 3b6a3f38bc..a360a0809b 100644
--- a/lib/stdlib/test/gen_server_SUITE.erl
+++ b/lib/stdlib/test/gen_server_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1996-2012. All Rights Reserved.
+%% Copyright Ericsson AB 1996-2013. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -1082,13 +1082,23 @@ replace_state(Config) when is_list(Config) ->
%% Test that the time for a huge message queue is not
%% significantly slower than with an empty message queue.
call_with_huge_message_queue(Config) when is_list(Config) ->
+ case test_server:is_native(gen) of
+ true ->
+ {skip,
+ "gen is native - huge message queue optimization "
+ "is not implemented"};
+ false ->
+ do_call_with_huge_message_queue()
+ end.
+
+do_call_with_huge_message_queue() ->
?line Pid = spawn_link(fun echo_loop/0),
- ?line {Time,ok} = tc(fun() -> calls(10, Pid) end),
+ ?line {Time,ok} = tc(fun() -> calls(10000, Pid) end),
?line [self() ! {msg,N} || N <- lists:seq(1, 500000)],
erlang:garbage_collect(),
- ?line {NewTime,ok} = tc(fun() -> calls(10, Pid) end),
+ ?line {NewTime,ok} = tc(fun() -> calls(10000, Pid) end),
io:format("Time for empty message queue: ~p", [Time]),
io:format("Time for huge message queue: ~p", [NewTime]),
diff --git a/lib/stdlib/test/lists_SUITE.erl b/lib/stdlib/test/lists_SUITE.erl
index b56f0b39d8..cd7210f8ec 100644
--- a/lib/stdlib/test/lists_SUITE.erl
+++ b/lib/stdlib/test/lists_SUITE.erl
@@ -2532,8 +2532,8 @@ otp_5939(Config) when is_list(Config) ->
?line [] = lists:filter(Pred, []),
?line {'EXIT', _} = (catch lists:partition(func, [])),
?line {[],[]} = lists:partition(Pred, []),
- ?line {'EXIT', _} = (catch lists:zf(func, [])),
- ?line [] = lists:zf(Fun1, []),
+ ?line {'EXIT', _} = (catch lists:filtermap(func, [])),
+ ?line [] = lists:filtermap(Fun1, []),
?line {'EXIT', _} = (catch lists:foreach(func, [])),
?line ok = lists:foreach(Fun1, []),
?line {'EXIT', _} = (catch lists:mapfoldl(func, [], [])),
diff --git a/lib/stdlib/test/zip_SUITE.erl b/lib/stdlib/test/zip_SUITE.erl
index 7233c061ef..a57641ef62 100644
--- a/lib/stdlib/test/zip_SUITE.erl
+++ b/lib/stdlib/test/zip_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2006-2011. All Rights Reserved.
+%% Copyright Ericsson AB 2006-2013. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -109,13 +109,32 @@ borderline_test(Size, TempDir) ->
ok.
unzip_list(Archive, Name) ->
- case os:find_executable("unzip") of
- Unzip when is_list(Unzip) ->
+ case unix_unzip_exists() of
+ true ->
unzip_list1(Archive, Name);
_ ->
ok
end.
+%% Used to do os:find_executable() to check if unzip exists, but on
+%% some hosts that would give an unzip program which did not take the
+%% "-Z" option.
+%% Here we check that "unzip -Z" (which should display usage) and
+%% check that it exists with status 0.
+unix_unzip_exists() ->
+ case os:type() of
+ {unix,_} ->
+ Port = open_port({spawn,"unzip -Z > /dev/null"}, [exit_status]),
+ receive
+ {Port,{exit_status,0}} ->
+ true;
+ {Port,{exit_status,_Fail}} ->
+ false
+ end;
+ _ ->
+ false
+ end.
+
unzip_list1(Archive, Name) ->
Expect = Name ++ "\n",
cmd_expect("unzip -Z -1 " ++ Archive, Expect).
diff --git a/lib/test_server/src/test_server_ctrl.erl b/lib/test_server/src/test_server_ctrl.erl
index 21c10adccb..ffa21d054c 100644
--- a/lib/test_server/src/test_server_ctrl.erl
+++ b/lib/test_server/src/test_server_ctrl.erl
@@ -1183,7 +1183,7 @@ init_tester(Mod, Func, Args, Dir, Name, {_,_,MinLev}=Levels,
"<td>~.3fs</td><td><b>~ts</b></td><td>~w Ok, ~w Failed~ts of ~w</td></tr>\n"
"</tfoot>\n",
[Time,SuccessStr,OkN,FailedN,SkipStr,OkN+FailedN+SkippedN]),
- test_server_io:stop().
+ test_server_io:stop([major,html,unexpected_io]).
report_severe_error(Reason) ->
test_server_sup:framework_call(report, [severe_error,Reason]).
@@ -1588,7 +1588,7 @@ do_test_cases(TopCases, SkipCases,
print(major, "=started ~s",
[lists:flatten(timestamp_get(""))]),
- put(test_server_html_footer, Footer),
+ test_server_io:set_footer(Footer),
run_test_cases(TestSpec, Config, TimetrapData)
end;
diff --git a/lib/test_server/src/test_server_io.erl b/lib/test_server/src/test_server_io.erl
index a979deffc3..73d4468bda 100644
--- a/lib/test_server/src/test_server_io.erl
+++ b/lib/test_server/src/test_server_io.erl
@@ -29,7 +29,7 @@
%%
-module(test_server_io).
--export([start_link/0,stop/0,get_gl/1,set_fd/2,
+-export([start_link/0,stop/1,get_gl/1,set_fd/2,
start_transaction/0,end_transaction/0,
print_buffered/1,print/3,print_unexpected/1,
set_footer/1,set_job_name/1,set_gl_props/1]).
@@ -55,10 +55,10 @@ start_link() ->
Other
end.
-stop() ->
+stop(FilesToClose) ->
OldGL = group_leader(),
group_leader(self(), self()),
- req(stop),
+ req({stop,FilesToClose}),
group_leader(OldGL, self()),
ok.
@@ -213,12 +213,21 @@ handle_call({set_job_name,Name}, _From, St) ->
handle_call({set_gl_props,Props}, _From, #st{shared_gl=Shared}=St) ->
test_server_gl:set_props(Shared, Props),
{reply,ok,St#st{gl_props=Props}};
-handle_call(stop, From, #st{shared_gl=SGL,gls=Gls0}=St0) ->
+handle_call({stop,FdTags}, From, #st{fds=Fds,shared_gl=SGL,gls=Gls0}=St0) ->
St = St0#st{gls=gb_sets:insert(SGL, Gls0),stopping=From},
gc(St),
%% Give the users of the surviving group leaders some
%% time to finish.
erlang:send_after(2000, self(), stop_group_leaders),
+ %% close open log files
+ lists:foreach(fun(Tag) ->
+ case gb_trees:lookup(Tag, Fds) of
+ none ->
+ ok;
+ {value,Fd} ->
+ file:close(Fd)
+ end
+ end, FdTags),
{noreply,St}.
handle_info({'EXIT',Pid,normal}, #st{gls=Gls0,stopping=From}=St) ->