aboutsummaryrefslogtreecommitdiffstats
path: root/lib
diff options
context:
space:
mode:
Diffstat (limited to 'lib')
-rw-r--r--lib/common_test/doc/src/ct_run.xml12
-rw-r--r--lib/common_test/doc/src/run_test_chapter.xml31
-rw-r--r--lib/common_test/src/ct.erl3
-rw-r--r--lib/common_test/src/ct_framework.erl70
-rw-r--r--lib/common_test/src/ct_repeat.erl38
-rw-r--r--lib/common_test/src/ct_run.erl14
-rw-r--r--lib/common_test/test/Makefile1
-rw-r--r--lib/common_test/test/ct_repeat_testrun_SUITE.erl378
-rw-r--r--lib/common_test/test/ct_repeat_testrun_SUITE_data/a_test/r1_SUITE.erl75
-rw-r--r--lib/common_test/test/ct_repeat_testrun_SUITE_data/b_test/r2_SUITE.erl75
-rw-r--r--lib/common_test/test/ct_test_support.erl70
-rw-r--r--lib/compiler/src/compile.erl3
-rw-r--r--lib/compiler/src/v3_core.erl51
-rw-r--r--lib/compiler/test/bs_bincomp_SUITE.erl3
-rw-r--r--lib/crypto/c_src/crypto.c275
-rwxr-xr-xlib/crypto/doc/src/crypto.xml102
-rw-r--r--lib/crypto/src/crypto.erl244
-rw-r--r--lib/crypto/test/crypto_SUITE.erl731
-rw-r--r--lib/dialyzer/src/dialyzer_analysis_callgraph.erl4
-rw-r--r--lib/odbc/c_src/odbcserver.c2
-rw-r--r--lib/odbc/test/odbc_query_SUITE.erl22
-rw-r--r--lib/odbc/test/oracle.erl27
-rw-r--r--lib/odbc/test/postgres.erl39
-rw-r--r--lib/reltool/src/reltool_server.erl39
-rw-r--r--lib/reltool/test/reltool_server_SUITE.erl53
-rw-r--r--lib/snmp/include/.gitignore4
-rw-r--r--lib/snmp/priv/mibs/.gitignore1
-rw-r--r--lib/snmp/test/snmp_test_data/.gitignore2
-rw-r--r--lib/ssl/doc/src/ssl.xml72
-rw-r--r--lib/ssl/src/Makefile3
-rw-r--r--lib/ssl/src/ssl.app.src1
-rw-r--r--lib/ssl/src/ssl.erl40
-rw-r--r--lib/ssl/src/ssl_alert.erl4
-rw-r--r--lib/ssl/src/ssl_alert.hrl2
-rw-r--r--lib/ssl/src/ssl_cipher.erl292
-rw-r--r--lib/ssl/src/ssl_cipher.hrl105
-rw-r--r--lib/ssl/src/ssl_connection.erl463
-rw-r--r--lib/ssl/src/ssl_handshake.erl218
-rw-r--r--lib/ssl/src/ssl_handshake.hrl51
-rw-r--r--lib/ssl/src/ssl_internal.hrl3
-rw-r--r--lib/ssl/src/ssl_srp.hrl31
-rw-r--r--lib/ssl/src/ssl_srp_primes.erl506
-rw-r--r--lib/ssl/src/ssl_srp_primes.hrl1
-rw-r--r--lib/ssl/test/ssl_basic_SUITE.erl47
-rw-r--r--lib/ssl/test/ssl_test_lib.erl64
-rw-r--r--lib/stdlib/doc/src/erl_parse.xml19
-rw-r--r--lib/stdlib/doc/src/sys.xml85
-rw-r--r--lib/stdlib/src/erl_parse.yrl1
-rw-r--r--lib/stdlib/src/erl_scan.erl1
-rw-r--r--lib/stdlib/src/gen_event.erl18
-rw-r--r--lib/stdlib/src/gen_fsm.erl11
-rw-r--r--lib/stdlib/src/gen_server.erl7
-rw-r--r--lib/stdlib/src/sys.erl32
-rw-r--r--lib/stdlib/test/erl_scan_SUITE.erl28
-rw-r--r--lib/stdlib/test/gen_event_SUITE.erl47
-rw-r--r--lib/stdlib/test/gen_fsm_SUITE.erl38
-rw-r--r--lib/stdlib/test/gen_server_SUITE.erl48
-rw-r--r--lib/stdlib/test/io_proto_SUITE.erl18
-rw-r--r--lib/tools/emacs/erlang-start.el3
59 files changed, 3999 insertions, 629 deletions
diff --git a/lib/common_test/doc/src/ct_run.xml b/lib/common_test/doc/src/ct_run.xml
index d871908952..c87c765ae7 100644
--- a/lib/common_test/doc/src/ct_run.xml
+++ b/lib/common_test/doc/src/ct_run.xml
@@ -113,9 +113,9 @@
[-muliply_timetraps Multiplier]
[-scale_timetraps]
[-create_priv_dir auto_per_run | auto_per_tc | manual_per_tc]
- [-repeat N [-force_stop]] |
- [-duration HHMMSS [-force_stop]] |
- [-until [YYMoMoDD]HHMMSS [-force_stop]]
+ [-repeat N] |
+ [-duration HHMMSS [-force_stop [skip_rest]]] |
+ [-until [YYMoMoDD]HHMMSS [-force_stop [skip_rest]]]
[-basic_html]
[-ct_hooks CTHModule1 CTHOpts1 and CTHModule2 CTHOpts2 and ..
CTHModuleN CTHOptsN]
@@ -149,9 +149,9 @@
[-muliply_timetraps Multiplier]
[-scale_timetraps]
[-create_priv_dir auto_per_run | auto_per_tc | manual_per_tc]
- [-repeat N [-force_stop]] |
- [-duration HHMMSS [-force_stop]] |
- [-until [YYMoMoDD]HHMMSS [-force_stop]]
+ [-repeat N] |
+ [-duration HHMMSS [-force_stop [skip_rest]]] |
+ [-until [YYMoMoDD]HHMMSS [-force_stop [skip_rest]]]
[-basic_html]
[-ct_hooks CTHModule1 CTHOpts1 and CTHModule2 CTHOpts2 and ..
CTHModuleN CTHOptsN]
diff --git a/lib/common_test/doc/src/run_test_chapter.xml b/lib/common_test/doc/src/run_test_chapter.xml
index 35f89153d3..afaed29626 100644
--- a/lib/common_test/doc/src/run_test_chapter.xml
+++ b/lib/common_test/doc/src/run_test_chapter.xml
@@ -174,7 +174,7 @@
<item><c><![CDATA[-repeat <n>]]></c>, tells Common Test to repeat the tests n times (see below).</item>
<item><c><![CDATA[-duration <time>]]></c>, tells Common Test to repeat the tests for duration of time (see below).</item>
<item><c><![CDATA[-until <stop_time>]]></c>, tells Common Test to repeat the tests until stop_time (see below).</item>
- <item><c>-force_stop</c>, on timeout, the test run will be aborted when current test job is finished (see below).</item>
+ <item><c>-force_stop [skip_rest]</c>, on timeout, the test run will be aborted when current test job is finished. If <c>skip_rest</c> is provided the rest of the test cases in the current test job will be skipped (see below).</item>
<item><c><![CDATA[-decrypt_key <key>]]></c>, provides a decryption key for
<seealso marker="config_file_chapter#encrypted_config_files">encrypted configuration files</seealso>.</item>
<item><c><![CDATA[-decrypt_file <key_file>]]></c>, points out a file containing a decryption key for
@@ -1273,6 +1273,7 @@
<item><c>-duration DurTime ({duration,DurTime})</c>, where <c>DurTime</c> is the duration, see below.</item>
<item><c>-until StopTime ({until,StopTime})</c>, where <c>StopTime</c> is finish time, see below.</item>
<item><c>-force_stop ({force_stop,true})</c></item>
+ <item><c>-force_stop skip_rest ({force_stop,skip_rest})</c></item>
</list>
<p>The duration time, <c>DurTime</c>, is specified as <c>HHMMSS</c>. Example:
<c>-duration 012030</c> or <c>{duration,"012030"}</c>, means the tests will
@@ -1283,12 +1284,16 @@
Example: <c>-until 071001120000</c> or <c>{until,"071001120000"}</c>, which means the tests
will be executed and (if time allows) repeated, until 12 o'clock on the 1st of Oct 2007.</p>
- <p>When timeout occurs, Common Test will never abort the test run immediately, since
+ <p>When timeout occurs, Common Test will never abort the ongoing test case, since
this might leave the system under test in an undefined, and possibly bad, state.
- Instead Common Test will finish the current test job, or the complete test
- run, before stopping. The latter is the default behaviour. The <c>force_stop</c>
- flag/option tells Common Test to stop as soon as the current test job is finished.
- Note that since Common Test always finishes off the current test job or test session,
+ Instead Common Test will by default finish the current test
+ run before stopping. If the <c>force_stop</c> flag is
+ given, Common Test will stop as soon as the current test job
+ is finished, and if the <c>force_stop</c> flag is given with
+ <c>skip_rest</c> Common Test will only complete the current
+ test case and skip the rest of the tests in the test job.
+ Note that since Common Test always finishes off at least the
+ current test case,
the time specified with <c>duration</c> or <c>until</c> is never definitive!</p>
<p>Log files from every single repeated test run is saved in normal Common Test fashion (see above).
@@ -1312,6 +1317,18 @@
<p>Example 2:</p>
<pre>
+ $ ct_run -dir $TEST_ROOT/to1 $TEST_ROOT/to2 -duration 001000 -forces_stop skip_rest</pre>
+ <p>Here the same test run as in Example 1, but with the
+ <c>force_stop</c> flag set to <c>skip_rest</c>. If the timeout
+ occurs while executing tests in directory to1, the rest of the
+ test cases in to1 will be skipped and then the test will be
+ aborted without running the tests in to2 another time. If the
+ timeout occurs while executing tests in directory to2, then the
+ rest of the test cases in to2 will be skipped and then the test
+ will be aborted.</p>
+
+ <p>Example 3:</p>
+ <pre>
$ date
Fri Sep 28 15:00:00 MEST 2007
@@ -1321,7 +1338,7 @@
Common Test will finish the entire test run before stopping (i.e. the to1 and to2 test
will always both be executed in the same test run).</p>
- <p>Example 3:</p>
+ <p>Example 4:</p>
<pre>
$ ct_run -dir $TEST_ROOT/to1 $TEST_ROOT/to2 -repeat 5</pre>
<p>Here the test run, including both the to1 and the to2 test, will be repeated 5 times.</p>
diff --git a/lib/common_test/src/ct.erl b/lib/common_test/src/ct.erl
index 04a95a53fa..e6732f7fc7 100644
--- a/lib/common_test/src/ct.erl
+++ b/lib/common_test/src/ct.erl
@@ -153,7 +153,7 @@ run(TestDirs) ->
%%% {auto_compile,Bool} | {create_priv_dir,CreatePrivDir} |
%%% {multiply_timetraps,M} | {scale_timetraps,Bool} |
%%% {repeat,N} | {duration,DurTime} | {until,StopTime} |
-%%% {force_stop,Bool} | {decrypt,DecryptKeyOrFile} |
+%%% {force_stop,ForceStop} | {decrypt,DecryptKeyOrFile} |
%%% {refresh_logs,LogDir} | {logopts,LogOpts} |
%%% {verbosity,VLevels} | {basic_html,Bool} |
%%% {ct_hooks, CTHs} | {enable_builtin_hooks,Bool} |
@@ -184,6 +184,7 @@ run(TestDirs) ->
%%% N = integer()
%%% DurTime = string(HHMMSS)
%%% StopTime = string(YYMoMoDDHHMMSS) | string(HHMMSS)
+%%% ForceStop = skip_rest | Bool
%%% DecryptKeyOrFile = {key,DecryptKey} | {file,DecryptFile}
%%% DecryptKey = string()
%%% DecryptFile = string()
diff --git a/lib/common_test/src/ct_framework.erl b/lib/common_test/src/ct_framework.erl
index 5fe4eaf511..b92fe1555f 100644
--- a/lib/common_test/src/ct_framework.erl
+++ b/lib/common_test/src/ct_framework.erl
@@ -64,38 +64,46 @@ init_tc(Mod,Func,Config) ->
ok
end,
- case ct_util:get_testdata(curr_tc) of
- {Suite,{suite0_failed,{require,Reason}}} ->
- {skip,{require_failed_in_suite0,Reason}};
- {Suite,{suite0_failed,_}=Failure} ->
- {skip,Failure};
+ case Func=/=end_per_suite
+ andalso Func=/=end_per_group
+ andalso ct_util:get_testdata(skip_rest) of
+ true ->
+ {skip,"Repeated test stopped by force_stop option"};
_ ->
- ct_util:update_testdata(curr_tc,
- fun(undefined) ->
- [{Suite,Func}];
- (Running) ->
- [{Suite,Func}|Running]
- end, [create]),
- case ct_util:read_suite_data({seq,Suite,Func}) of
- undefined ->
- init_tc1(Mod,Suite,Func,Config);
- Seq when is_atom(Seq) ->
- case ct_util:read_suite_data({seq,Suite,Seq}) of
- [Func|TCs] -> % this is the 1st case in Seq
- %% make sure no cases in this seq are
- %% marked as failed from an earlier execution
- %% in the same suite
- lists:foreach(
- fun(TC) ->
- ct_util:save_suite_data({seq,Suite,TC},
- Seq)
- end, TCs);
- _ ->
- ok
- end,
- init_tc1(Mod,Suite,Func,Config);
- {failed,Seq,BadFunc} ->
- {skip,{sequence_failed,Seq,BadFunc}}
+ case ct_util:get_testdata(curr_tc) of
+ {Suite,{suite0_failed,{require,Reason}}} ->
+ {skip,{require_failed_in_suite0,Reason}};
+ {Suite,{suite0_failed,_}=Failure} ->
+ {skip,Failure};
+ _ ->
+ ct_util:update_testdata(curr_tc,
+ fun(undefined) ->
+ [{Suite,Func}];
+ (Running) ->
+ [{Suite,Func}|Running]
+ end, [create]),
+ case ct_util:read_suite_data({seq,Suite,Func}) of
+ undefined ->
+ init_tc1(Mod,Suite,Func,Config);
+ Seq when is_atom(Seq) ->
+ case ct_util:read_suite_data({seq,Suite,Seq}) of
+ [Func|TCs] -> % this is the 1st case in Seq
+ %% make sure no cases in this seq are
+ %% marked as failed from an earlier execution
+ %% in the same suite
+ lists:foreach(
+ fun(TC) ->
+ ct_util:save_suite_data(
+ {seq,Suite,TC},
+ Seq)
+ end, TCs);
+ _ ->
+ ok
+ end,
+ init_tc1(Mod,Suite,Func,Config);
+ {failed,Seq,BadFunc} ->
+ {skip,{sequence_failed,Seq,BadFunc}}
+ end
end
end.
diff --git a/lib/common_test/src/ct_repeat.erl b/lib/common_test/src/ct_repeat.erl
index a47309c6ee..f4d9949776 100644
--- a/lib/common_test/src/ct_repeat.erl
+++ b/lib/common_test/src/ct_repeat.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
@@ -23,7 +23,7 @@
%%% start flags (or equivalent ct:run_test/1 options) are supported:
%%% -until <StopTime>, StopTime = YYMoMoDDHHMMSS | HHMMSS
%%% -duration <DurTime>, DurTime = HHMMSS
-%%% -force_stop
+%%% -force_stop [skip_rest]
%%% -repeat <N>, N = integer()</p>
-module(ct_repeat).
@@ -62,12 +62,15 @@ loop_test(If,Args) when is_list(Args) ->
io:format("\nCommon Test: "
"Will repeat tests for ~s.\n\n",[ts(Secs)]),
TPid =
- case lists:keymember(force_stop,1,Args) of
- true ->
+ case proplists:get_value(force_stop,Args) of
+ False when False==false; False==undefined ->
+ undefined;
+ ForceStop ->
CtrlPid = self(),
- spawn(fun() -> stop_after(CtrlPid,Secs) end);
- false ->
- undefined
+ spawn(
+ fun() ->
+ stop_after(CtrlPid,Secs,ForceStop)
+ end)
end,
Args1 = [{loop_info,[{stop_time,Secs,StopTime,1}]} | Args],
loop(If,stop_time,0,Secs,StopTime,Args1,TPid,[])
@@ -212,7 +215,7 @@ get_stop_time(until,[Y1,Y2,Mo1,Mo2,D1,D2,H1,H2,Mi1,Mi2,S1,S2]) ->
list_to_integer([S1,S2])},
calendar:datetime_to_gregorian_seconds({Date,Time});
-get_stop_time(until,Time) ->
+get_stop_time(until,Time=[_,_,_,_,_,_]) ->
get_stop_time(until,"000000"++Time);
get_stop_time(duration,[H1,H2,Mi1,Mi2,S1,S2]) ->
@@ -227,10 +230,17 @@ cancel(Pid) ->
%% After Secs, abort will make the test_server finish the current
%% job, then empty the job queue and stop.
-stop_after(_CtrlPid,Secs) ->
+stop_after(_CtrlPid,Secs,ForceStop) ->
timer:sleep(Secs*1000),
+ case ForceStop of
+ SkipRest when SkipRest==skip_rest; SkipRest==["skip_rest"] ->
+ ct_util:set_testdata({skip_rest,true});
+ _ ->
+ ok
+ end,
test_server_ctrl:abort().
+
%% Callback from ct_run to print loop info to system log.
log_loop_info(Args) ->
case lists:keysearch(loop_info,1,Args) of
@@ -259,11 +269,11 @@ log_loop_info(Args) ->
io_lib:format("Test time remaining: ~w secs (~w%)\n",
[Secs,trunc((Secs/Secs0)*100)]),
LogStr4 =
- case lists:keymember(force_stop,1,Args) of
- true ->
- io_lib:format("force_stop is enabled",[]);
- _ ->
- ""
+ case proplists:get_value(force_stop,Args) of
+ False when False==false; False==undefined ->
+ "";
+ ForceStop ->
+ io_lib:format("force_stop is set to: ~w",[ForceStop])
end,
ct_logs:log("Test loop info",LogStr1++LogStr2++LogStr3++LogStr4,[])
end.
diff --git a/lib/common_test/src/ct_run.erl b/lib/common_test/src/ct_run.erl
index 49f00429ae..57cfab532e 100644
--- a/lib/common_test/src/ct_run.erl
+++ b/lib/common_test/src/ct_run.erl
@@ -771,9 +771,9 @@ script_usage() ->
"\n\t[-scale_timetraps]"
"\n\t[-create_priv_dir auto_per_run | auto_per_tc | manual_per_tc]"
"\n\t[-basic_html]"
- "\n\t[-repeat N [-force_stop]] |"
- "\n\t[-duration HHMMSS [-force_stop]] |"
- "\n\t[-until [YYMoMoDD]HHMMSS [-force_stop]]\n\n"),
+ "\n\t[-repeat N] |"
+ "\n\t[-duration HHMMSS [-force_stop [skip_rest]]] |"
+ "\n\t[-until [YYMoMoDD]HHMMSS [-force_stop [skip_rest]]]\n\n"),
io:format("Run tests using test specification:\n\n"
"\tct_run -spec TestSpec1 TestSpec2 .. TestSpecN"
"\n\t[-config ConfigFile1 ConfigFile2 .. ConfigFileN]"
@@ -795,9 +795,9 @@ script_usage() ->
"\n\t[-scale_timetraps]"
"\n\t[-create_priv_dir auto_per_run | auto_per_tc | manual_per_tc]"
"\n\t[-basic_html]"
- "\n\t[-repeat N [-force_stop]] |"
- "\n\t[-duration HHMMSS [-force_stop]] |"
- "\n\t[-until [YYMoMoDD]HHMMSS [-force_stop]]\n\n"),
+ "\n\t[-repeat N] |"
+ "\n\t[-duration HHMMSS [-force_stop [skip_rest]]] |"
+ "\n\t[-until [YYMoMoDD]HHMMSS [-force_stop [skip_rest]]]\n\n"),
io:format("Refresh the HTML index files:\n\n"
"\tct_run -refresh_logs [LogDir]"
"[-logdir LogDir] "
@@ -2933,6 +2933,8 @@ opts2args(EnvStartOpts) ->
[];
({create_priv_dir,PD}) when is_atom(PD) ->
[{create_priv_dir,[atom_to_list(PD)]}];
+ ({force_stop,skip_rest}) ->
+ [{force_stop,["skip_rest"]}];
({force_stop,true}) ->
[{force_stop,[]}];
({force_stop,false}) ->
diff --git a/lib/common_test/test/Makefile b/lib/common_test/test/Makefile
index a9ebd8f1d3..94569fa87f 100644
--- a/lib/common_test/test/Makefile
+++ b/lib/common_test/test/Makefile
@@ -38,6 +38,7 @@ MODULES= \
ct_groups_spec_SUITE \
ct_sequence_1_SUITE \
ct_repeat_1_SUITE \
+ ct_repeat_testrun_SUITE \
ct_testspec_1_SUITE \
ct_testspec_2_SUITE \
ct_testspec_3_SUITE \
diff --git a/lib/common_test/test/ct_repeat_testrun_SUITE.erl b/lib/common_test/test/ct_repeat_testrun_SUITE.erl
new file mode 100644
index 0000000000..7ec384c932
--- /dev/null
+++ b/lib/common_test/test/ct_repeat_testrun_SUITE.erl
@@ -0,0 +1,378 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 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
+%% Erlang Public License along with this software. If not, it can be
+%% retrieved online at http://www.erlang.org/.
+%%
+%% Software distributed under the License is distributed on an "AS IS"
+%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+%% the License for the specific language governing rights and limitations
+%% under the License.
+%%
+%% %CopyrightEnd%
+%%
+
+%%%-------------------------------------------------------------------
+%%% File: ct_repeat_test_SUITE
+%%%
+%%% Description:
+%%% Test different options for repeating test runs:
+%%% -repeat N
+%%% -duration T [-force_stop [skip_rest]]
+%%% -until T [-force_stop [skip_rest]]
+%%%
+%%%-------------------------------------------------------------------
+-module(ct_repeat_testrun_SUITE).
+
+-compile(export_all).
+
+-include_lib("common_test/include/ct.hrl").
+-include_lib("common_test/include/ct_event.hrl").
+
+-define(eh, ct_test_support_eh).
+-define(skip_reason, "Repeated test stopped by force_stop option").
+-define(skipped, {skipped, ?skip_reason}).
+
+
+%% Timers used in this test.
+%% Each test suite consists of
+%%
+%% [tc1,tc2,{group,g,[tc1,tc2]},tc2]
+%%
+%% In r1_SUITE tc1 has a sleep of 10 sec - all other test cases just
+%% return ok.
+%%
+%% => One complete test run of two suites r1_SUITE + r2_SUITE is at
+%% least 20 seconds (10 sec for each r1_SUITE:tc1)
+%%
+-define(t1,30). % time shall expire during second run of r1_SUITE
+-define(t2,6). % time shall expire during first run of tc1
+-define(t3,16). % time shall expire during second run of tc1
+
+
+%%--------------------------------------------------------------------
+%% TEST SERVER CALLBACK FUNCTIONS
+%%--------------------------------------------------------------------
+
+%%--------------------------------------------------------------------
+%% Description: Since Common Test starts another Test Server
+%% instance, the tests need to be performed on a separate node (or
+%% there will be clashes with logging processes etc).
+%%--------------------------------------------------------------------
+init_per_suite(Config0) ->
+ Config = ct_test_support:init_per_suite(Config0),
+ DataDir = ?config(data_dir, Config),
+ Suite1 = filename:join([DataDir,"a_test","r1_SUITE"]),
+ Suite2 = filename:join([DataDir,"b_test","r2_SUITE"]),
+ Opts0 = ct_test_support:get_opts(Config),
+ Opts1 = Opts0 ++ [{suite,Suite1},{testcase,tc2},{label,timing1}],
+ Opts2 = Opts0 ++ [{suite,Suite2},{testcase,tc2},{label,timing2}],
+
+ %% Make sure both suites are compiled
+ {1,0,{0,0}} = ct_test_support:run(ct,run_test,[Opts1],Config),
+ {1,0,{0,0}} = ct_test_support:run(ct,run_test,[Opts2],Config),
+
+ %% Time the shortest testcase to use for offset
+ {T0,{1,0,{0,0}}} = timer:tc(ct_test_support,run,[ct,run_test,[Opts1],Config]),
+
+ %% -2 is to ensure we hit inside the target test case and not after
+% T = round(T0/1000000)-2,
+ T=0,
+ [{offset,T}|Config].
+
+end_per_suite(Config) ->
+ ct_test_support:end_per_suite(Config).
+
+init_per_testcase(TestCase, Config) ->
+ ct_test_support:init_per_testcase(TestCase, Config).
+
+end_per_testcase(TestCase, Config) ->
+ ct_test_support:end_per_testcase(TestCase, Config).
+
+suite() -> [{ct_hooks,[ts_install_cth]}].
+
+all() ->
+ [
+ repeat_n,
+ duration,
+ duration_force_stop,
+ duration_force_stop_skip_rest,
+ duration_force_stop_skip_rest_group,
+ until,
+ until_force_stop,
+ until_force_stop_skip_rest,
+ until_force_stop_skip_rest_group
+ ].
+
+%%--------------------------------------------------------------------
+%% TEST CASES
+%%--------------------------------------------------------------------
+
+%%%-----------------------------------------------------------------
+%%%
+repeat_n(Config) when is_list(Config) ->
+ DataDir = ?config(data_dir, Config),
+ Dirs = filelib:wildcard(filename:join(DataDir,"*")),
+ {Opts,ERPid} = setup([{dir,Dirs},
+ {label,repeat_n},
+ {repeat,2}],
+ Config),
+ ok = execute(repeat_n, Opts, ERPid, Config).
+
+duration(Config) when is_list(Config) ->
+ DataDir = ?config(data_dir, Config),
+ Dirs = filelib:wildcard(filename:join(DataDir,"*")),
+ {Opts,ERPid} = setup([{dir,Dirs},
+ {label,duration},
+ {duration,duration_str(?t1,2,Config)}],
+ Config),
+ ok = execute(duration, Opts, ERPid, Config).
+
+duration_force_stop(Config) when is_list(Config) ->
+ DataDir = ?config(data_dir, Config),
+ Dirs = filelib:wildcard(filename:join(DataDir,"*")),
+ {Opts,ERPid} = setup([{dir,Dirs},
+ {label,duration_force_stop},
+ {duration,duration_str(?t1,2,Config)},
+ {force_stop,true}],
+ Config),
+ ok = execute(duration_force_stop, Opts, ERPid, Config).
+
+duration_force_stop_skip_rest(Config) when is_list(Config) ->
+ DataDir = ?config(data_dir, Config),
+ Dirs = filelib:wildcard(filename:join(DataDir,"*")),
+ {Opts,ERPid} = setup([{dir,Dirs},
+ {label,duration_force_stop_skip_rest},
+ {duration,duration_str(?t2,1,Config)},
+ {force_stop,skip_rest}],
+ Config),
+ ok = execute(duration_force_stop_skip_rest, Opts, ERPid, Config).
+
+duration_force_stop_skip_rest_group(Config) when is_list(Config) ->
+ DataDir = ?config(data_dir, Config),
+ Dirs = filelib:wildcard(filename:join(DataDir,"*")),
+ {Opts,ERPid} = setup([{dir,Dirs},
+ {label,duration_force_stop_skip_rest_group},
+ {duration,duration_str(?t3,1,Config)},
+ {force_stop,skip_rest}],
+ Config),
+ ok = execute(duration_force_stop_skip_rest_group, Opts, ERPid, Config).
+
+until(Config) when is_list(Config) ->
+ DataDir = ?config(data_dir, Config),
+ Dirs = filelib:wildcard(filename:join(DataDir,"*")),
+ {Opts,ERPid} = setup([{dir,Dirs},
+ {label,until}],
+ Config),
+ ExecuteFun =
+ fun() ->
+ [_,_] = ct_test_support:run_ct_run_test(
+ Opts++[{until,until_str(?t1,2,Config)}],Config),
+ 0 = ct_test_support:run_ct_script_start(
+ Opts++[{until,until_str(?t1,2,Config)}],Config)
+ end,
+ ok = execute(ExecuteFun, until, Opts, ERPid, Config).
+
+until_force_stop(Config) when is_list(Config) ->
+ DataDir = ?config(data_dir, Config),
+ Dirs = filelib:wildcard(filename:join(DataDir,"*")),
+ {Opts,ERPid} = setup([{dir,Dirs},
+ {label,until_force_stop},
+ {force_stop,true}],
+ Config),
+ ExecuteFun =
+ fun() ->
+ [_,_] = ct_test_support:run_ct_run_test(
+ Opts++[{until,until_str(?t1,2,Config)}],Config),
+ 0 = ct_test_support:run_ct_script_start(
+ Opts++[{until,until_str(?t1,2,Config)}],Config)
+ end,
+ ok = execute(ExecuteFun, until_force_stop, Opts, ERPid, Config).
+
+until_force_stop_skip_rest(Config) when is_list(Config) ->
+ DataDir = ?config(data_dir, Config),
+ Dirs = filelib:wildcard(filename:join(DataDir,"*")),
+ {Opts,ERPid} = setup([{dir,Dirs},
+ {label,until_force_stop_skip_rest},
+ {force_stop,skip_rest}],
+ Config),
+ ExecuteFun =
+ fun() ->
+ [_] = ct_test_support:run_ct_run_test(
+ Opts++[{until,until_str(?t2,1,Config)}],Config),
+ 1 = ct_test_support:run_ct_script_start(
+ Opts++[{until,until_str(?t2,1,Config)}],Config)
+ end,
+ ok = execute(ExecuteFun, until_force_stop_skip_rest,
+ Opts, ERPid, Config).
+
+until_force_stop_skip_rest_group(Config) when is_list(Config) ->
+ DataDir = ?config(data_dir, Config),
+ Dirs = filelib:wildcard(filename:join(DataDir,"*")),
+ {Opts,ERPid} = setup([{dir,Dirs},
+ {label,until_force_stop_skip_rest_group},
+ {force_stop,skip_rest}],
+ Config),
+ ExecuteFun =
+ fun() ->
+ [_] = ct_test_support:run_ct_run_test(
+ Opts++[{until,until_str(?t3,1,Config)}],Config),
+ 0 = ct_test_support:run_ct_script_start(
+ Opts++[{until,until_str(?t3,1,Config)}],Config)
+ end,
+ ok = execute(ExecuteFun,
+ until_force_stop_skip_rest_group,
+ Opts, ERPid, Config).
+
+
+%%%-----------------------------------------------------------------
+%%% HELP FUNCTIONS
+%%%-----------------------------------------------------------------
+
+setup(Test, Config) ->
+ Opts0 = ct_test_support:get_opts(Config),
+ Level = ?config(trace_level, Config),
+ EvHArgs = [{cbm,ct_test_support},{trace_level,Level}],
+ Opts = Opts0 ++ [{event_handler,{?eh,EvHArgs}}|Test],
+ ERPid = ct_test_support:start_event_receiver(Config),
+ {Opts,ERPid}.
+
+%% Execute test, first with ct:run_test, then with ct:script_start
+execute(Name, Opts, ERPid, Config) ->
+ ExecuteFun = fun() -> ok = ct_test_support:run(Opts, Config) end,
+ execute(ExecuteFun, Name, Opts, ERPid, Config).
+
+execute(ExecuteFun, Name, Opts, ERPid, Config) ->
+ ExecuteFun(),
+ Events = ct_test_support:get_events(ERPid, Config),
+
+ ct_test_support:log_events(Name,
+ reformat(Events, ?eh),
+ ?config(priv_dir, Config),
+ Opts),
+
+ TestEvents = events_to_check(Name),
+ ct_test_support:verify_events(TestEvents, Events, Config).
+
+reformat(Events, EH) ->
+ ct_test_support:reformat(Events, EH).
+
+%% N is the expected number of repeats
+until_str(Secs0,N,Config) ->
+ Offset = ?config(offset,Config),
+ Secs = Secs0 + N*Offset,
+ Now = calendar:datetime_to_gregorian_seconds(calendar:local_time()),
+ {{Y,Mo,D},{H,M,S}} = calendar:gregorian_seconds_to_datetime(Now+Secs),
+ lists:flatten(io_lib:format("~2..0w~2..0w~2..0w~2..0w~2..0w~2..0w",
+ [Y rem 100, Mo, D, H, M, S])).
+
+%% N is the expected number of repeats
+duration_str(Secs0,N,Config) ->
+ Offset = ?config(offset,Config),
+ Secs = Secs0 + N*Offset,
+ "0000" ++ lists:flatten(io_lib:format("~2..0w",[Secs])).
+
+%%%-----------------------------------------------------------------
+%%% TEST EVENTS
+%%%-----------------------------------------------------------------
+%% 2 tests (ct:run_test + script_start) is default
+events_to_check(C) when C==repeat_n; C==duration; C==until ->
+ dupl(4, start_logging() ++ all_succ() ++ stop_logging());
+events_to_check(C) when C==duration_force_stop; C==until_force_stop ->
+ dupl(2, start_logging() ++
+ all_succ() ++
+ stop_logging() ++
+ start_logging() ++
+ all_succ(r1_SUITE) ++
+ stop_logging());
+events_to_check(C) when C==duration_force_stop_skip_rest;
+ C==until_force_stop_skip_rest ->
+ dupl(2, start_logging() ++ skip_first_tc1(r1_SUITE) ++ stop_logging());
+events_to_check(C) when C==duration_force_stop_skip_rest_group;
+ C==until_force_stop_skip_rest_group ->
+ dupl(2, start_logging() ++ skip_tc1_in_group(r1_SUITE) ++ stop_logging()).
+
+dupl(N,List) ->
+ lists:flatten(lists:duplicate(N,List)).
+
+start_logging() ->
+ [{?eh,start_logging,{'DEF','RUNDIR'}}].
+stop_logging() ->
+ [{?eh,stop_logging,[]}].
+
+
+all_succ() ->
+ all_succ(r1_SUITE) ++ all_succ(r2_SUITE).
+
+all_succ(Suite) ->
+ [{?eh,tc_start,{Suite,init_per_suite}},
+ {?eh,tc_done,{Suite,init_per_suite,ok}},
+ {?eh,tc_start,{Suite,tc1}},
+ {?eh,tc_done,{Suite,tc1,ok}},
+ {?eh,test_stats,{'_',0,{0,0}}},
+ {?eh,tc_start,{Suite,tc2}},
+ {?eh,tc_done,{Suite,tc2,ok}},
+ {?eh,test_stats,{'_',0,{0,0}}},
+ [{?eh,tc_start,{Suite,{init_per_group,g,[]}}},
+ {?eh,tc_done,{Suite,{init_per_group,g,[]},ok}},
+ {?eh,tc_start,{Suite,tc1}},
+ {?eh,tc_done,{Suite,tc1,ok}},
+ {?eh,test_stats,{'_',0,{0,0}}},
+ {?eh,tc_start,{Suite,tc2}},
+ {?eh,tc_done,{Suite,tc2,ok}},
+ {?eh,test_stats,{'_',0,{0,0}}},
+ {?eh,tc_start,{Suite,{end_per_group,g,[]}}},
+ {?eh,tc_done,{Suite,{end_per_group,g,[]},ok}}],
+ {?eh,tc_start,{Suite,tc2}},
+ {?eh,tc_done,{Suite,tc2,ok}},
+ {?eh,test_stats,{'_',0,{0,0}}},
+ {?eh,tc_start,{Suite,end_per_suite}},
+ {?eh,tc_done,{Suite,end_per_suite,ok}}].
+
+skip_first_tc1(Suite) ->
+ [{?eh,tc_start,{Suite,init_per_suite}},
+ {?eh,tc_done,{Suite,init_per_suite,ok}},
+ {?eh,tc_start,{Suite,tc1}},
+ {?eh,tc_done,{Suite,tc1,ok}},
+ {?eh,test_stats,{'_',0,{0,0}}},
+ {?eh,tc_done,{Suite,tc2,?skipped}},
+ {?eh,test_stats,{'_',0,{1,0}}},
+ {?eh,tc_done,{Suite,{init_per_group,g,[]},?skipped}},
+ {?eh,tc_auto_skip,{Suite,tc1,?skip_reason}},
+ {?eh,test_stats,{'_',0,{1,1}}},
+ {?eh,tc_auto_skip,{Suite,tc2,?skip_reason}},
+ {?eh,test_stats,{'_',0,{1,2}}},
+ {?eh,tc_auto_skip,{Suite,end_per_group,?skip_reason}},
+ {?eh,tc_done,{Suite,tc2,?skipped}},
+ {?eh,test_stats,{'_',0,{2,2}}},
+ {?eh,tc_start,{Suite,end_per_suite}},
+ {?eh,tc_done,{Suite,end_per_suite,ok}}].
+
+
+skip_tc1_in_group(Suite) ->
+ [{?eh,tc_start,{Suite,init_per_suite}},
+ {?eh,tc_done,{Suite,init_per_suite,ok}},
+ {?eh,tc_start,{Suite,tc1}},
+ {?eh,tc_done,{Suite,tc1,ok}},
+ {?eh,test_stats,{'_',0,{0,0}}},
+ {?eh,tc_start,{Suite,tc2}},
+ {?eh,tc_done,{Suite,tc2,ok}},
+ {?eh,test_stats,{'_',0,{0,0}}},
+ [{?eh,tc_start,{Suite,{init_per_group,g,[]}}},
+ {?eh,tc_done,{Suite,{init_per_group,g,[]},ok}},
+ {?eh,tc_start,{Suite,tc1}},
+ {?eh,tc_done,{Suite,tc1,ok}},
+ {?eh,test_stats,{'_',0,{0,0}}},
+ {?eh,tc_done,{Suite,tc2,?skipped}},
+ {?eh,test_stats,{'_',0,{1,0}}},
+ {?eh,tc_start,{Suite,{end_per_group,g,[]}}},
+ {?eh,tc_done,{Suite,{end_per_group,g,[]},ok}}],
+ {?eh,tc_done,{Suite,tc2,?skipped}},
+ {?eh,test_stats,{'_',0,{2,0}}},
+ {?eh,tc_start,{Suite,end_per_suite}},
+ {?eh,tc_done,{Suite,end_per_suite,ok}}].
diff --git a/lib/common_test/test/ct_repeat_testrun_SUITE_data/a_test/r1_SUITE.erl b/lib/common_test/test/ct_repeat_testrun_SUITE_data/a_test/r1_SUITE.erl
new file mode 100644
index 0000000000..3fd5943691
--- /dev/null
+++ b/lib/common_test/test/ct_repeat_testrun_SUITE_data/a_test/r1_SUITE.erl
@@ -0,0 +1,75 @@
+%%--------------------------------------------------------------------
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 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
+%% Erlang Public License along with this software. If not, it can be
+%% retrieved online at http://www.erlang.org/.
+%%
+%% Software distributed under the License is distributed on an "AS IS"
+%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+%% the License for the specific language governing rights and limitations
+%% under the License.
+%%
+%% %CopyrightEnd%
+%%
+%%----------------------------------------------------------------------
+%% File: r1_SUITE.erl
+%%
+%% Description:
+%%
+%%
+%% @author Support
+%% @doc
+%% @end
+%%----------------------------------------------------------------------
+%%----------------------------------------------------------------------
+-module(r1_SUITE).
+-include_lib("common_test/include/ct.hrl").
+
+-compile(export_all).
+
+%% Default timetrap timeout (set in init_per_testcase).
+-define(default_timeout, ?t:seconds(30)).
+
+all() ->
+ testcases() ++ [{group,g}, tc2].
+
+groups() ->
+ [{g,testcases()}].
+
+testcases() ->
+ [tc1,tc2].
+
+init_per_suite(Config) ->
+ Config.
+
+end_per_suite(Config) ->
+ Config.
+
+init_per_group(_, Config) ->
+ Config.
+
+end_per_group(_Group, Config) ->
+ Config.
+
+init_per_testcase(_Case, Config) ->
+ Dog = test_server:timetrap(?default_timeout),
+ [{watchdog, Dog}|Config].
+
+end_per_testcase(_Case, Config) ->
+ Dog=?config(watchdog, Config),
+ test_server:timetrap_cancel(Dog),
+ ok.
+
+%%%-----------------------------------------------------------------
+%%% Test cases
+tc1(_Config) ->
+ timer:sleep(10000),
+ ok.
+
+tc2(_Config) ->
+ ok.
diff --git a/lib/common_test/test/ct_repeat_testrun_SUITE_data/b_test/r2_SUITE.erl b/lib/common_test/test/ct_repeat_testrun_SUITE_data/b_test/r2_SUITE.erl
new file mode 100644
index 0000000000..dc9abc2863
--- /dev/null
+++ b/lib/common_test/test/ct_repeat_testrun_SUITE_data/b_test/r2_SUITE.erl
@@ -0,0 +1,75 @@
+%%--------------------------------------------------------------------
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 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
+%% Erlang Public License along with this software. If not, it can be
+%% retrieved online at http://www.erlang.org/.
+%%
+%% Software distributed under the License is distributed on an "AS IS"
+%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+%% the License for the specific language governing rights and limitations
+%% under the License.
+%%
+%% %CopyrightEnd%
+%%
+%%----------------------------------------------------------------------
+%% File: r2_SUITE.erl
+%%
+%% Description:
+%%
+%%
+%% @author Support
+%% @doc
+%% @end
+%%----------------------------------------------------------------------
+%%----------------------------------------------------------------------
+-module(r2_SUITE).
+-include_lib("common_test/include/ct.hrl").
+
+-compile(export_all).
+
+%% Default timetrap timeout (set in init_per_testcase).
+-define(default_timeout, ?t:seconds(30)).
+
+all() ->
+ testcases() ++ [{group,g}, tc2].
+
+groups() ->
+ [{g,testcases()}].
+
+testcases() ->
+ [tc1,tc2].
+
+init_per_suite(Config) ->
+ Config.
+
+end_per_suite(Config) ->
+ Config.
+
+init_per_group(_, Config) ->
+ Config.
+
+end_per_group(_Group, Config) ->
+ Config.
+
+init_per_testcase(_Case, Config) ->
+ Dog = test_server:timetrap(?default_timeout),
+ [{watchdog, Dog}|Config].
+
+end_per_testcase(_Case, Config) ->
+ Dog=?config(watchdog, Config),
+ test_server:timetrap_cancel(Dog),
+ ok.
+
+%%%-----------------------------------------------------------------
+%%% Test cases
+tc1(_Config) ->
+ %% timer:sleep(3000),
+ ok.
+
+tc2(_Config) ->
+ ok.
diff --git a/lib/common_test/test/ct_test_support.erl b/lib/common_test/test/ct_test_support.erl
index 5e109e98e9..70dd087358 100644
--- a/lib/common_test/test/ct_test_support.erl
+++ b/lib/common_test/test/ct_test_support.erl
@@ -29,7 +29,8 @@
-export([init_per_suite/1, init_per_suite/2, end_per_suite/1,
init_per_testcase/2, end_per_testcase/2,
write_testspec/2, write_testspec/3,
- run/2, run/3, run/4, get_opts/1, wait_for_ct_stop/1]).
+ run/2, run/3, run/4, run_ct_run_test/2, run_ct_script_start/2,
+ get_opts/1, wait_for_ct_stop/1]).
-export([handle_event/2, start_event_receiver/1, get_events/2,
verify_events/3, verify_events/4, reformat/2, log_events/4,
@@ -224,9 +225,15 @@ get_opts(Config) ->
%%%-----------------------------------------------------------------
%%%
run(Opts, Config) when is_list(Opts) ->
+ %% use ct interface
+ CtRunTestResult=run_ct_run_test(Opts,Config),
+ %% use run_test interface (simulated)
+ ExitStatus=run_ct_script_start(Opts,Config),
+ check_result(CtRunTestResult,ExitStatus,Opts).
+
+run_ct_run_test(Opts,Config) ->
CTNode = proplists:get_value(ct_node, Config),
Level = proplists:get_value(trace_level, Config),
- %% use ct interface
test_server:format(Level, "~n[RUN #1] Calling ct:run_test(~p) on ~p~n",
[Opts, CTNode]),
CtRunTestResult = rpc:call(CTNode, ct, run_test, [Opts]),
@@ -242,7 +249,11 @@ run(Opts, Config) when is_list(Opts) ->
timer:sleep(5000),
undefined = rpc:call(CTNode, erlang, whereis, [ct_util_server])
end,
- %% use run_test interface (simulated)
+ CtRunTestResult.
+
+run_ct_script_start(Opts, Config) ->
+ CTNode = proplists:get_value(ct_node, Config),
+ Level = proplists:get_value(trace_level, Config),
Opts1 = [{halt_with,{?MODULE,ct_test_halt}} | Opts],
test_server:format(Level, "Saving start opts on ~p: ~p~n",
[CTNode, Opts1]),
@@ -253,27 +264,38 @@ run(Opts, Config) when is_list(Opts) ->
ExitStatus = rpc:call(CTNode, ct_run, script_start, []),
test_server:format(Level, "[RUN #2] Got exit status value ~p~n",
[ExitStatus]),
- case {CtRunTestResult,ExitStatus} of
- {{_Ok,Failed,{_UserSkipped,_AutoSkipped}},1} when Failed > 0 ->
- ok;
- {{_Ok,0,{_UserSkipped,AutoSkipped}},ExitStatus} when AutoSkipped > 0 ->
- case proplists:get_value(exit_status, Opts1) of
- ignore_config when ExitStatus == 1 ->
- {error,{wrong_exit_status,ExitStatus}};
- _ ->
- ok
- end;
- {{error,_}=Error,ExitStatus} ->
- if ExitStatus /= 2 ->
- {error,{wrong_exit_status,ExitStatus}};
- ExitStatus == 2 ->
- Error
- end;
- {{_Ok,0,{_UserSkipped,_AutoSkipped}},0} ->
- ok;
- Unexpected ->
- {error,{unexpected_return_value,Unexpected}}
- end.
+ ExitStatus.
+
+check_result({_Ok,Failed,{_UserSkipped,_AutoSkipped}},1,_Opts)
+ when Failed > 0 ->
+ ok;
+check_result({_Ok,0,{_UserSkipped,AutoSkipped}},ExitStatus,Opts)
+ when AutoSkipped > 0 ->
+ case proplists:get_value(exit_status, Opts) of
+ ignore_config when ExitStatus == 1 ->
+ {error,{wrong_exit_status,ExitStatus}};
+ _ ->
+ ok
+ end;
+check_result({error,_}=Error,2,_Opts) ->
+ Error;
+check_result({error,_},ExitStatus,_Opts) ->
+ {error,{wrong_exit_status,ExitStatus}};
+check_result({_Ok,0,{_UserSkipped,_AutoSkipped}},0,_Opts) ->
+ ok;
+check_result(CtRunTestResult,ExitStatus,Opts)
+ when is_list(CtRunTestResult) -> % repeated testruns
+ try check_result(sum_testruns(CtRunTestResult,0,0,0,0),ExitStatus,Opts)
+ catch _:_ ->
+ {error,{unexpected_return_value,{CtRunTestResult,ExitStatus}}}
+ end;
+check_result(CtRunTestResult,ExitStatus,_Opts) ->
+ {error,{unexpected_return_value,{CtRunTestResult,ExitStatus}}}.
+
+sum_testruns([{O,F,{US,AS}}|T],Ok,Failed,UserSkipped,AutoSkipped) ->
+ sum_testruns(T,Ok+O,Failed+F,UserSkipped+US,AutoSkipped+AS);
+sum_testruns([],Ok,Failed,UserSkipped,AutoSkipped) ->
+ {Ok,Failed,{UserSkipped,AutoSkipped}}.
run(M, F, A, Config) ->
run({M,F,A}, [], Config).
diff --git a/lib/compiler/src/compile.erl b/lib/compiler/src/compile.erl
index 497af2b52c..745f1d5cf9 100644
--- a/lib/compiler/src/compile.erl
+++ b/lib/compiler/src/compile.erl
@@ -599,7 +599,8 @@ standard_passes() ->
core_passes() ->
%% Optimization and transforms of Core Erlang code.
- [{delay,
+ [{iff,clint0,?pass(core_lint_module)},
+ {delay,
[{unless,no_copt,
[{core_old_inliner,fun test_old_inliner/1,fun core_old_inliner/1},
{iff,doldinline,{listing,"oldinline"}},
diff --git a/lib/compiler/src/v3_core.erl b/lib/compiler/src/v3_core.erl
index 01042cc56f..eea54b30a2 100644
--- a/lib/compiler/src/v3_core.erl
+++ b/lib/compiler/src/v3_core.erl
@@ -1187,9 +1187,9 @@ list_gen_pattern(P0, Line, St) ->
bc_initial_size(E, Q, St0) ->
try
- {ElemSzExpr,ElemSzPre,St1} = bc_elem_size(E, St0),
+ {ElemSzExpr,ElemSzPre,EVs,St1} = bc_elem_size(E, St0),
{V,St2} = new_var(St1),
- {GenSzExpr,GenSzPre,St3} = bc_gen_size(Q, St2),
+ {GenSzExpr,GenSzPre,St3} = bc_gen_size(Q, EVs, St2),
case ElemSzExpr of
#c_literal{val=ElemSz} when ElemSz rem 8 =:= 0 ->
NumBytesExpr = #c_literal{val=ElemSz div 8},
@@ -1214,11 +1214,13 @@ bc_initial_size(E, Q, St0) ->
bc_elem_size({bin,_,El}, St0) ->
case bc_elem_size_1(El, 0, []) of
{Bits,[]} ->
- {#c_literal{val=Bits},[],St0};
+ {#c_literal{val=Bits},[],[],St0};
{Bits,Vars0} ->
[{U,V0}|Pairs] = sort(Vars0),
F = bc_elem_size_combine(Pairs, U, [V0], []),
- bc_mul_pairs(F, #c_literal{val=Bits}, [], St0)
+ Vs = [V || {_,#c_var{name=V}} <- Vars0],
+ {E,Pre,St} = bc_mul_pairs(F, #c_literal{val=Bits}, [], St0),
+ {E,Pre,Vs,St}
end.
bc_elem_size_1([{bin_element,_,_,{integer,_,N},Flags}|Es], Bits, Vars) ->
@@ -1260,11 +1262,11 @@ bc_add_list_1([H|T], Pre, E, St0) ->
bc_add_list_1([], Pre, E, St) ->
{E,reverse(Pre),St}.
-bc_gen_size(Q, St) ->
- bc_gen_size_1(Q, #c_literal{val=1}, [], St).
+bc_gen_size(Q, EVs, St) ->
+ bc_gen_size_1(Q, EVs, #c_literal{val=1}, [], St).
-bc_gen_size_1([{generate,L,El,Gen}|Qs], E0, Pre0, St0) ->
- bc_verify_non_filtering(El),
+bc_gen_size_1([{generate,L,El,Gen}|Qs], EVs, E0, Pre0, St0) ->
+ bc_verify_non_filtering(El, EVs),
case Gen of
{var,_,ListVar} ->
Lanno = lineno_anno(L, St0),
@@ -1275,16 +1277,16 @@ bc_gen_size_1([{generate,L,El,Gen}|Qs], E0, Pre0, St0) ->
name=#c_literal{val=length},
args=[#c_var{name=ListVar}]}},
{E,Pre,St} = bc_gen_size_mul(E0, LenVar, [Set|Pre0], St1),
- bc_gen_size_1(Qs, E, Pre, St);
+ bc_gen_size_1(Qs, EVs, E, Pre, St);
_ ->
%% The only expressions we handle is literal lists.
Len = bc_list_length(Gen, 0),
{E,Pre,St} = bc_gen_size_mul(E0, #c_literal{val=Len}, Pre0, St0),
- bc_gen_size_1(Qs, E, Pre, St)
+ bc_gen_size_1(Qs, EVs, E, Pre, St)
end;
-bc_gen_size_1([{b_generate,_,El,Gen}|Qs], E0, Pre0, St0) ->
- bc_verify_non_filtering(El),
- {MatchSzExpr,Pre1,St1} = bc_elem_size(El, St0),
+bc_gen_size_1([{b_generate,_,El,Gen}|Qs], EVs, E0, Pre0, St0) ->
+ bc_verify_non_filtering(El, EVs),
+ {MatchSzExpr,Pre1,_,St1} = bc_elem_size(El, St0),
Pre2 = reverse(Pre1, Pre0),
{ResVar,St2} = new_var(St1),
{BitSizeExpr,Pre3,St3} = bc_gen_bit_size(Gen, Pre2, St2),
@@ -1292,10 +1294,10 @@ bc_gen_size_1([{b_generate,_,El,Gen}|Qs], E0, Pre0, St0) ->
MatchSzExpr)},
Pre4 = [Div|Pre3],
{E,Pre,St} = bc_gen_size_mul(E0, ResVar, Pre4, St3),
- bc_gen_size_1(Qs, E, Pre, St);
-bc_gen_size_1([], E, Pre, St) ->
+ bc_gen_size_1(Qs, EVs, E, Pre, St);
+bc_gen_size_1([], _, E, Pre, St) ->
{E,reverse(Pre),St};
-bc_gen_size_1(_, _, _, _) ->
+bc_gen_size_1(_, _, _, _, _) ->
throw(impossible).
bc_gen_bit_size({var,L,V}, Pre0, St0) ->
@@ -1312,13 +1314,20 @@ bc_gen_bit_size({bin,_,_}=Bin, Pre, St) ->
bc_gen_bit_size(_, _, _) ->
throw(impossible).
-bc_verify_non_filtering({bin,_,Els}) ->
- foreach(fun({bin_element,_,{var,_,_},_,_}) -> ok;
+bc_verify_non_filtering({bin,_,Els}, EVs) ->
+ foreach(fun({bin_element,_,{var,_,V},_,_}) ->
+ case member(V, EVs) of
+ true -> throw(impossible);
+ false -> ok
+ end;
(_) -> throw(impossible)
end, Els);
-bc_verify_non_filtering({var,_,_}) ->
- ok;
-bc_verify_non_filtering(_) ->
+bc_verify_non_filtering({var,_,V}, EVs) ->
+ case member(V, EVs) of
+ true -> throw(impossible);
+ false -> ok
+ end;
+bc_verify_non_filtering(_, _) ->
throw(impossible).
bc_list_length({string,_,Str}, Len) ->
diff --git a/lib/compiler/test/bs_bincomp_SUITE.erl b/lib/compiler/test/bs_bincomp_SUITE.erl
index d39e340429..451a9b1e3b 100644
--- a/lib/compiler/test/bs_bincomp_SUITE.erl
+++ b/lib/compiler/test/bs_bincomp_SUITE.erl
@@ -282,6 +282,9 @@ sizes(Config) when is_list(Config) ->
?line <<1,2,3,0>> = Fun13(7),
?line <<1,2,3,0,0>> = Fun13(8),
+ <<0:3>> = cs_default(<< <<0:S>> || S <- [0,1,2] >>),
+ <<0:3>> = cs_default(<< <<0:S>> || <<S>> <= <<0,1,2>> >>),
+
?line {'EXIT',_} = (catch << <<C:4>> || <<C:8>> <= {1,2,3} >>),
?line cs_end(),
diff --git a/lib/crypto/c_src/crypto.c b/lib/crypto/c_src/crypto.c
index e77e5fb8f0..fac77308f6 100644
--- a/lib/crypto/c_src/crypto.c
+++ b/lib/crypto/c_src/crypto.c
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 2010-2012. All Rights Reserved.
+ * Copyright Ericsson AB 2010-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
@@ -136,6 +136,7 @@ static void unload(ErlNifEnv* env, void* priv_data);
/* The NIFs: */
static ERL_NIF_TERM info_lib(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
+static ERL_NIF_TERM algorithms(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
static ERL_NIF_TERM md5(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
static ERL_NIF_TERM md5_init(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
static ERL_NIF_TERM md5_update(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
@@ -207,6 +208,9 @@ static ERL_NIF_TERM dh_generate_parameters_nif(ErlNifEnv* env, int argc, const E
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 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[]);
@@ -215,6 +219,7 @@ static ERL_NIF_TERM blowfish_ofb64_encrypt(ErlNifEnv* env, int argc, const ERL_N
/* helpers */
+static void init_algorithms_types(void);
static void init_digest_types(ErlNifEnv* env);
static void hmac_md5(unsigned char *key, int klen,
unsigned char *dbuf, int dlen,
@@ -247,6 +252,7 @@ static int library_refc = 0; /* number of users of this dynamic library */
static ErlNifFunc nif_funcs[] = {
{"info_lib", 0, info_lib},
+ {"algorithms", 0, algorithms},
{"md5", 1, md5},
{"md5_init", 0, md5_init},
{"md5_update", 2, md5_update},
@@ -304,7 +310,7 @@ static ErlNifFunc nif_funcs[] = {
{"rand_bytes", 3, rand_bytes_3},
{"strong_rand_mpint_nif", 3, strong_rand_mpint_nif},
{"rand_uniform_nif", 2, rand_uniform_nif},
- {"mod_exp_nif", 3, mod_exp_nif},
+ {"mod_exp_nif", 4, mod_exp_nif},
{"dss_verify", 4, dss_verify},
{"rsa_verify_nif", 4, rsa_verify_nif},
{"aes_cbc_crypt", 4, aes_cbc_crypt},
@@ -321,6 +327,9 @@ static ErlNifFunc nif_funcs[] = {
{"dh_check", 1, dh_check},
{"dh_generate_key_nif", 2, 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},
{"bf_cfb64_crypt", 4, bf_cfb64_crypt},
{"bf_cbc_crypt", 4, bf_cbc_crypt},
{"bf_ecb_crypt", 3, bf_ecb_crypt},
@@ -458,6 +467,7 @@ static int init(ErlNifEnv* env, ERL_NIF_TERM load_info)
atom_digest = enif_make_atom(env,"digest");
init_digest_types(env);
+ init_algorithms_types();
#ifdef HAVE_DYNAMIC_CRYPTO_LIB
{
@@ -538,6 +548,35 @@ static void unload(ErlNifEnv* env, void* priv_data)
--library_refc;
}
+static int algos_cnt;
+static ERL_NIF_TERM algos[7]; /* increase when extending the list */
+
+static void init_algorithms_types(void)
+{
+ algos_cnt = 0;
+
+ algos[algos_cnt++] = atom_md5;
+ algos[algos_cnt++] = atom_sha;
+ algos[algos_cnt++] = atom_ripemd160;
+#ifdef HAVE_SHA224
+ algos[algos_cnt++] = atom_sha224;
+#endif
+#ifdef HAVE_SHA256
+ algos[algos_cnt++] = atom_sha256;
+#endif
+#ifdef HAVE_SHA384
+ algos[algos_cnt++] = atom_sha384;
+#endif
+#ifdef HAVE_SHA512
+ algos[algos_cnt++] = atom_sha512;
+#endif
+}
+
+static ERL_NIF_TERM algorithms(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
+{
+ return enif_make_list_from_array(env, algos, algos_cnt);
+}
+
static ERL_NIF_TERM info_lib(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
{
/* [{<<"OpenSSL">>,9470143,<<"OpenSSL 0.9.8k 25 Mar 2009">>}] */
@@ -1515,6 +1554,17 @@ static int get_bn_from_mpint(ErlNifEnv* env, ERL_NIF_TERM term, BIGNUM** bnp)
return 1;
}
+static int get_bn_from_bin(ErlNifEnv* env, ERL_NIF_TERM term, BIGNUM** bnp)
+{
+ ErlNifBinary bin;
+ if (!enif_inspect_binary(env,term,&bin)) {
+ return 0;
+ }
+ ERL_VALGRIND_ASSERT_MEM_DEFINED(bin.data, bin.size);
+ *bnp = BN_bin2bn(bin.data, bin.size, NULL);
+ return 1;
+}
+
static ERL_NIF_TERM rand_uniform_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
{/* (Lo,Hi) */
BIGNUM *bn_from = NULL, *bn_to, *bn_rand;
@@ -1543,16 +1593,19 @@ static ERL_NIF_TERM rand_uniform_nif(ErlNifEnv* env, int argc, const ERL_NIF_TER
}
static ERL_NIF_TERM mod_exp_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
-{/* (Base,Exponent,Modulo) */
+{/* (Base,Exponent,Modulo,bin_hdr) */
BIGNUM *bn_base=NULL, *bn_exponent=NULL, *bn_modulo, *bn_result;
BN_CTX *bn_ctx;
unsigned char* ptr;
unsigned dlen;
+ unsigned bin_hdr; /* return type: 0=plain binary, 4: mpint */
+ unsigned extra_byte;
ERL_NIF_TERM ret;
- if (!get_bn_from_mpint(env, argv[0], &bn_base)
- || !get_bn_from_mpint(env, argv[1], &bn_exponent)
- || !get_bn_from_mpint(env, argv[2], &bn_modulo)) {
+ if (!get_bn_from_bin(env, argv[0], &bn_base)
+ || !get_bn_from_bin(env, argv[1], &bn_exponent)
+ || !get_bn_from_bin(env, argv[2], &bn_modulo)
+ || !enif_get_uint(env,argv[3],&bin_hdr) || (bin_hdr & ~4)) {
if (bn_base) BN_free(bn_base);
if (bn_exponent) BN_free(bn_exponent);
@@ -1562,9 +1615,14 @@ static ERL_NIF_TERM mod_exp_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM arg
bn_ctx = BN_CTX_new();
BN_mod_exp(bn_result, bn_base, bn_exponent, bn_modulo, bn_ctx);
dlen = BN_num_bytes(bn_result);
- ptr = enif_make_new_binary(env, dlen+4, &ret);
- put_int32(ptr, dlen);
- BN_bn2bin(bn_result, ptr+4);
+ extra_byte = bin_hdr && BN_is_bit_set(bn_result, dlen*8-1);
+ ptr = enif_make_new_binary(env, bin_hdr+extra_byte+dlen, &ret);
+ if (bin_hdr) {
+ put_int32(ptr, extra_byte+dlen);
+ ptr[4] = 0; /* extra zeroed byte to ensure a positive mpint */
+ ptr += bin_hdr + extra_byte;
+ }
+ BN_bn2bin(bn_result, ptr);
BN_free(bn_result);
BN_CTX_free(bn_ctx);
BN_free(bn_modulo);
@@ -2344,6 +2402,205 @@ static ERL_NIF_TERM dh_compute_key_nif(ErlNifEnv* env, int argc, const ERL_NIF_T
return ret;
}
+static ERL_NIF_TERM srp_value_B_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
+{/* (Multiplier, Verifier, Generator, Exponent, Prime) */
+ BIGNUM *bn_verifier = NULL;
+ BIGNUM *bn_exponent, *bn_generator, *bn_prime, *bn_multiplier, *bn_result;
+ BN_CTX *bn_ctx;
+ unsigned char* ptr;
+ unsigned dlen;
+ ERL_NIF_TERM ret;
+
+ if (!get_bn_from_bin(env, argv[0], &bn_multiplier)
+ || !get_bn_from_bin(env, argv[1], &bn_verifier)
+ || !get_bn_from_bin(env, argv[2], &bn_generator)
+ || !get_bn_from_bin(env, argv[3], &bn_exponent)
+ || !get_bn_from_bin(env, argv[4], &bn_prime)) {
+ if (bn_multiplier) BN_free(bn_multiplier);
+ if (bn_verifier) BN_free(bn_verifier);
+ if (bn_verifier) BN_free(bn_generator);
+ if (bn_verifier) BN_free(bn_exponent);
+ if (bn_verifier) BN_free(bn_prime);
+ return enif_make_badarg(env);
+ }
+
+ bn_result = BN_new();
+ bn_ctx = BN_CTX_new();
+
+ /* B = k*v + g^b % N */
+
+ /* k * v */
+ BN_mod_mul(bn_multiplier, bn_multiplier, bn_verifier, bn_prime, bn_ctx);
+
+ /* g^b % N */
+ BN_mod_exp(bn_result, bn_generator, bn_exponent, bn_prime, bn_ctx);
+
+ /* k*v + g^b % N */
+ BN_mod_add(bn_result, bn_result, bn_multiplier, bn_prime, bn_ctx);
+
+ /* check that B % N != 0, reuse bn_multiplier */
+ BN_nnmod(bn_multiplier, bn_result, bn_prime, bn_ctx);
+ if (BN_is_zero(bn_multiplier)) {
+ ret = atom_error;
+ } else {
+ dlen = BN_num_bytes(bn_result);
+ ptr = enif_make_new_binary(env, dlen, &ret);
+ BN_bn2bin(bn_result, ptr);
+ }
+ BN_free(bn_result);
+ BN_CTX_free(bn_ctx);
+ BN_free(bn_prime);
+ BN_free(bn_generator);
+ BN_free(bn_multiplier);
+ BN_free(bn_exponent);
+ BN_free(bn_verifier);
+ return ret;
+}
+
+static ERL_NIF_TERM srp_client_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
+*/
+ BIGNUM *bn_exponent = NULL, *bn_a = NULL;
+ BIGNUM *bn_u, *bn_multiplier, *bn_exp2, *bn_base,
+ *bn_prime, *bn_generator, *bn_B, *bn_result;
+ BN_CTX *bn_ctx;
+ unsigned char* ptr;
+ unsigned dlen;
+ ERL_NIF_TERM ret;
+
+ if (!get_bn_from_bin(env, argv[0], &bn_a)
+ || !get_bn_from_bin(env, argv[1], &bn_u)
+ || !get_bn_from_bin(env, argv[2], &bn_B)
+ || !get_bn_from_bin(env, argv[3], &bn_multiplier)
+ || !get_bn_from_bin(env, argv[4], &bn_generator)
+ || !get_bn_from_bin(env, argv[5], &bn_exponent)
+ || !get_bn_from_bin(env, argv[6], &bn_prime))
+ {
+ if (bn_exponent) BN_free(bn_exponent);
+ if (bn_a) BN_free(bn_a);
+ if (bn_u) BN_free(bn_u);
+ if (bn_B) BN_free(bn_B);
+ if (bn_multiplier) BN_free(bn_multiplier);
+ if (bn_generator) BN_free(bn_generator);
+ if (bn_prime) BN_free(bn_prime);
+ return enif_make_badarg(env);
+ }
+
+ bn_ctx = BN_CTX_new();
+ bn_result = BN_new();
+
+ /* check that B % N != 0 */
+ BN_nnmod(bn_result, bn_B, bn_prime, bn_ctx);
+ if (BN_is_zero(bn_result)) {
+ BN_free(bn_exponent);
+ BN_free(bn_a);
+ BN_free(bn_generator);
+ BN_free(bn_prime);
+ BN_free(bn_u);
+ BN_free(bn_B);
+ BN_CTX_free(bn_ctx);
+
+ return atom_error;
+ }
+
+ /* (B - (k * g^x)) */
+ bn_base = BN_new();
+ BN_mod_exp(bn_result, bn_generator, bn_exponent, bn_prime, bn_ctx);
+ BN_mod_mul(bn_result, bn_multiplier, bn_result, bn_prime, bn_ctx);
+ BN_mod_sub(bn_base, bn_B, bn_result, bn_prime, bn_ctx);
+
+ /* a + (u * x) */
+ bn_exp2 = BN_new();
+ BN_mod_mul(bn_result, bn_u, bn_exponent, bn_prime, bn_ctx);
+ BN_mod_add(bn_exp2, bn_a, bn_result, bn_prime, bn_ctx);
+
+ /* (B - (k * g^x)) ^ (a + (u * x)) % N */
+ BN_mod_exp(bn_result, bn_base, bn_exp2, bn_prime, bn_ctx);
+
+ dlen = BN_num_bytes(bn_result);
+ ptr = enif_make_new_binary(env, dlen, &ret);
+ BN_bn2bin(bn_result, ptr);
+ BN_free(bn_result);
+ BN_CTX_free(bn_ctx);
+
+ BN_free(bn_multiplier);
+ BN_free(bn_exp2);
+ BN_free(bn_u);
+ BN_free(bn_exponent);
+ BN_free(bn_a);
+ BN_free(bn_B);
+ BN_free(bn_base);
+ BN_free(bn_generator);
+ BN_free(bn_prime);
+ return ret;
+}
+
+static ERL_NIF_TERM srp_server_secret_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
+{/* (Verifier, b, u, A, Prime) */
+/*
+ <premaster secret> = (A * v^u) ^ b % N
+*/
+ BIGNUM *bn_b = NULL, *bn_verifier = NULL;
+ BIGNUM *bn_prime, *bn_A, *bn_u, *bn_base, *bn_result;
+ BN_CTX *bn_ctx;
+ unsigned char* ptr;
+ unsigned dlen;
+ ERL_NIF_TERM ret;
+
+ if (!get_bn_from_bin(env, argv[0], &bn_verifier)
+ || !get_bn_from_bin(env, argv[1], &bn_b)
+ || !get_bn_from_bin(env, argv[2], &bn_u)
+ || !get_bn_from_bin(env, argv[3], &bn_A)
+ || !get_bn_from_bin(env, argv[4], &bn_prime))
+ {
+ if (bn_verifier) BN_free(bn_verifier);
+ if (bn_b) BN_free(bn_b);
+ if (bn_u) BN_free(bn_u);
+ if (bn_A) BN_free(bn_A);
+ if (bn_prime) BN_free(bn_prime);
+ return enif_make_badarg(env);
+ }
+
+ bn_ctx = BN_CTX_new();
+ bn_result = BN_new();
+
+ /* check that A % N != 0 */
+ BN_nnmod(bn_result, bn_A, bn_prime, bn_ctx);
+ if (BN_is_zero(bn_result)) {
+ BN_free(bn_b);
+ BN_free(bn_verifier);
+ BN_free(bn_prime);
+ BN_free(bn_A);
+ BN_CTX_free(bn_ctx);
+
+ return atom_error;
+ }
+
+ /* (A * v^u) */
+ bn_base = BN_new();
+ BN_mod_exp(bn_base, bn_verifier, bn_u, bn_prime, bn_ctx);
+ BN_mod_mul(bn_base, bn_A, bn_base, bn_prime, bn_ctx);
+
+ /* (A * v^u) ^ b % N */
+ BN_mod_exp(bn_result, bn_base, bn_b, bn_prime, bn_ctx);
+
+ dlen = BN_num_bytes(bn_result);
+ ptr = enif_make_new_binary(env, dlen, &ret);
+ BN_bn2bin(bn_result, ptr);
+ BN_free(bn_result);
+ BN_CTX_free(bn_ctx);
+
+ BN_free(bn_u);
+ BN_free(bn_base);
+ BN_free(bn_verifier);
+ BN_free(bn_prime);
+ BN_free(bn_A);
+ BN_free(bn_b);
+ return ret;
+}
+
static ERL_NIF_TERM bf_cfb64_crypt(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
{/* (Key, Ivec, Data, IsEncrypt) */
ErlNifBinary key_bin, ivec_bin, data_bin;
diff --git a/lib/crypto/doc/src/crypto.xml b/lib/crypto/doc/src/crypto.xml
index 6b9b2ef207..f30a058ca4 100755
--- a/lib/crypto/doc/src/crypto.xml
+++ b/lib/crypto/doc/src/crypto.xml
@@ -63,6 +63,11 @@
<item>
<p>dss: Digital Signature Standard (FIPS 186-2)</p>
</item>
+ <item>
+ <p>srp: Secure Remote Password Protocol (RFC 2945)</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>
@@ -99,6 +104,14 @@ Mpint() = <![CDATA[<<ByteLen:32/integer-big, Bytes:ByteLen/binary>>]]>
</desc>
</func>
<func>
+ <name>algorithms() -> [atom()]</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>
@@ -973,7 +986,17 @@ Mpint() = <![CDATA[<<ByteLen:32/integer-big, Bytes:ByteLen/binary>>]]>
using the <c>crypto</c> library.</p>
</desc>
</func>
-
+ <func>
+ <name>mod_exp_prime(N, P, M) -> Result</name>
+ <fsummary>Computes the function: N^P mod M</fsummary>
+ <type>
+ <v>N, P, M = binary()</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>
@@ -1256,8 +1279,85 @@ Mpint() = <![CDATA[<<ByteLen:32/integer-big, Bytes:ByteLen/binary>>]]>
</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>
+ <type>
+ <v>Verifier = binary()</v>
+ <d>Parameter v from <seealso marker="http://srp.stanford.edu/design.html">SRP design</seealso>
+ </d>
+ <v>Generator = binary() </v>
+ <d>Parameter g from <seealso marker="http://srp.stanford.edu/design.html">SRP design</seealso>
+ </d>
+ <v>Prime = binary() </v>
+ <d>Parameter N from <seealso marker="http://srp.stanford.edu/design.html">SRP design</seealso>
+ </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 <seealso marker="http://srp.stanford.edu/design.html">SRP design</seealso></d>
+ <v>PrivateKey = binary() - generated if not supplied</v>
+ <d>Parameter a or b from <seealso marker="http://srp.stanford.edu/design.html">SRP design</seealso></d>
+ </type>
+ <desc>
+ <p>Generates SRP public keys</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>
+ <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>
+ </type>
+ <desc>
+ <p>
+ Computes the SRP session key (shared secret). Also used
+ as premaster secret by TLS-SRP ciher suites.
+ </p>
+ </desc>
+ </func>
+
+ <func>
<name>exor(Data1, Data2) -> Result</name>
<fsummary>XOR data</fsummary>
<type>
diff --git a/lib/crypto/src/crypto.erl b/lib/crypto/src/crypto.erl
index 1328a95e87..1d0a9943c3 100644
--- a/lib/crypto/src/crypto.erl
+++ b/lib/crypto/src/crypto.erl
@@ -21,7 +21,7 @@
-module(crypto).
--export([start/0, stop/0, info/0, info_lib/0, version/0]).
+-export([start/0, stop/0, info/0, info_lib/0, algorithms/0, version/0]).
-export([hash/2, hash_init/1, hash_update/2, hash_final/1]).
-export([md4/1, md4_init/0, md4_update/2, md4_final/1]).
-export([md5/1, md5_init/0, md5_update/2, md5_final/1]).
@@ -57,7 +57,10 @@
-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, mpint/1, erlint/1]).
+-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]).
@@ -88,7 +91,7 @@
strong_rand_bytes,
strong_rand_mpint,
rand_uniform,
- mod_exp,
+ mod_exp, mod_exp_prime,
dss_verify,dss_sign,
rsa_verify,rsa_sign,
rsa_public_encrypt,rsa_private_decrypt,
@@ -109,7 +112,8 @@
hash, hash_init, hash_update, hash_final,
hmac, hmac_init, hmac_update, hmac_final, hmac_final_n, info,
rc2_cbc_encrypt, rc2_cbc_decrypt,
- info_lib]).
+ srp_generate_key, srp_compute_key,
+ info_lib, algorithms]).
-type rsa_digest_type() :: 'md5' | 'sha' | 'sha224' | 'sha256' | 'sha384' | 'sha512'.
-type dss_digest_type() :: 'none' | 'sha'.
@@ -184,6 +188,8 @@ info() ->
info_lib() -> ?nif_stub.
+algorithms() -> ?nif_stub.
+
%% Crypto app version history:
%% (no version): Driver implementation
%% 2.0 : NIF implementation, requires OTP R14
@@ -783,21 +789,24 @@ rand_uniform_pos(_,_) ->
rand_uniform_nif(_From,_To) -> ?nif_stub.
%%
-%% mod_exp - utility for rsa generation
+%% mod_exp - utility for rsa generation and SRP
%%
mod_exp(Base, Exponent, Modulo)
when is_integer(Base), is_integer(Exponent), is_integer(Modulo) ->
- erlint(mod_exp(mpint(Base), mpint(Exponent), mpint(Modulo)));
+ bin_to_int(mod_exp_nif(int_to_bin(Base), int_to_bin(Exponent), int_to_bin(Modulo), 0));
mod_exp(Base, Exponent, Modulo) ->
- case mod_exp_nif(Base,Exponent,Modulo) of
- <<Len:32/integer, MSB, Rest/binary>> when MSB > 127 ->
- <<(Len + 1):32/integer, 0, MSB, Rest/binary>>;
- Whatever ->
- Whatever
+ 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
+ <<0>> -> error;
+ R -> R
end.
-mod_exp_nif(_Base,_Exp,_Mod) -> ?nif_stub.
+
+mod_exp_nif(_Base,_Exp,_Mod,_bin_hdr) -> ?nif_stub.
%%
%% DSS, RSA - verify
@@ -1064,50 +1073,205 @@ dh_compute_key(OthersPublicKey, MyPrivateKey, DHParameters) ->
dh_compute_key_nif(_OthersPublicKey, _MyPrivateKey, _DHParameters) -> ?nif_stub.
+
+%%% 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),
+ is_binary(Generator),
+ is_binary(ClientPublic),
+ is_binary(ClientPrivate),
+ is_binary(ServerPublic),
+ 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
+ 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_atom(Version) ->
+ Scrambler = srp_scrambler(Version, ClientPublic, ServerPublic, Prime),
+ srp_server_secret_nif(Verifier, ServerPrivate, Scrambler, ClientPublic, Prime).
+
%%
%% LOCAL FUNCTIONS
%%
+client_srp_gen_key(Private, Generator, Prime) ->
+ case mod_exp_prime(Generator, Private, Prime) of
+ error ->
+ error;
+ Public ->
+ {Public, Private}
+ end.
+
+server_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 ->
+ error;
+ Public ->
+ {Public, Private}
+ end.
+
+srp_multiplier('6a', Generator, Prime) ->
+ %% k = SHA1(N | PAD(g)) from http://srp.stanford.edu/design.html
+ C0 = sha_init(),
+ C1 = sha_update(C0, Prime),
+ C2 = sha_update(C1, srp_pad_to(erlang:byte_size(Prime), Generator)),
+ sha_final(C2);
+srp_multiplier('6', _, _) ->
+ <<3/integer>>;
+srp_multiplier('3', _, _) ->
+ <<1/integer>>.
+
+srp_scrambler(Version, ClientPublic, ServerPublic, 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)),
+ sha_final(C2);
+srp_scrambler('3', _, ServerPublic, _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.
+
+srp_pad_length(Width, Length) ->
+ (Width - Length rem Width) rem Width.
+
+srp_pad_to(Width, Binary) ->
+ case srp_pad_length(Width, size(Binary)) of
+ 0 -> Binary;
+ N -> << 0:(N*8), Binary/binary>>
+ end.
+
+srp_server_secret_nif(_Verifier, _B, _U, _A, _Prime) -> ?nif_stub.
+
+srp_client_secret_nif(_A, _U, _B, _Multiplier, _Generator, _Exponent, _Prime) -> ?nif_stub.
+
+srp_value_B_nif(_Multiplier, _Verifier, _Generator, _Exponent, _Prime) -> ?nif_stub.
%% large integer in a binary with 32bit length
%% MP representaion (SSH2)
-mpint(X) when X < 0 ->
- case X of
- -1 ->
- <<0,0,0,1,16#ff>>;
- _ ->
- mpint_neg(X,0,[])
- end;
-mpint(X) ->
- case X of
- 0 ->
- <<0,0,0,0>>;
- _ ->
- mpint_pos(X,0,[])
- end.
+mpint(X) when X < 0 -> mpint_neg(X);
+mpint(X) -> mpint_pos(X).
-define(UINT32(X), X:32/unsigned-big-integer).
-mpint_neg(-1,I,Ds=[MSB|_]) ->
- if MSB band 16#80 =/= 16#80 ->
- <<?UINT32((I+1)), (list_to_binary([255|Ds]))/binary>>;
- true ->
- (<<?UINT32(I), (list_to_binary(Ds))/binary>>)
- end;
-mpint_neg(X,I,Ds) ->
- mpint_neg(X bsr 8,I+1,[(X band 255)|Ds]).
+
+mpint_neg(X) ->
+ Bin = int_to_bin_neg(X, []),
+ Sz = byte_size(Bin),
+ <<?UINT32(Sz), Bin/binary>>.
-mpint_pos(0,I,Ds=[MSB|_]) ->
+mpint_pos(X) ->
+ Bin = int_to_bin_pos(X, []),
+ <<MSB,_/binary>> = Bin,
+ Sz = byte_size(Bin),
if MSB band 16#80 == 16#80 ->
- <<?UINT32((I+1)), (list_to_binary([0|Ds]))/binary>>;
+ <<?UINT32((Sz+1)), 0, Bin/binary>>;
true ->
- (<<?UINT32(I), (list_to_binary(Ds))/binary>>)
- end;
-mpint_pos(X,I,Ds) ->
- mpint_pos(X bsr 8,I+1,[(X band 255)|Ds]).
+ <<?UINT32(Sz), Bin/binary>>
+ end.
+
+int_to_bin(X) when X < 0 -> int_to_bin_neg(X, []);
+int_to_bin(X) -> int_to_bin_pos(X, []).
+
+%%int_to_bin_pos(X) when X >= 0 ->
+%% int_to_bin_pos(X, []).
+
+int_to_bin_pos(0,Ds=[_|_]) ->
+ list_to_binary(Ds);
+int_to_bin_pos(X,Ds) ->
+ int_to_bin_pos(X bsr 8, [(X band 255)|Ds]).
+
+int_to_bin_neg(-1, Ds=[MSB|_]) when MSB >= 16#80 ->
+ list_to_binary(Ds);
+int_to_bin_neg(X,Ds) ->
+ int_to_bin_neg(X bsr 8, [(X band 255)|Ds]).
+
+
+bin_to_int(Bin) ->
+ Bits = bit_size(Bin),
+ <<Integer:Bits/integer>> = Bin,
+ Integer.
%% int from integer in a binary with 32bit length
erlint(<<MPIntSize:32/integer,MPIntValue/binary>>) ->
Bits= MPIntSize * 8,
<<Integer:Bits/integer>> = MPIntValue,
Integer.
+
+mpint_to_bin(<<Len:32, Bin:Len/binary>>) ->
+ Bin.
+
+random_bytes(N) ->
+ try strong_rand_bytes(N) of
+ RandBytes ->
+ RandBytes
+ catch
+ error:low_entropy ->
+ rand_bytes(N)
+ end.
diff --git a/lib/crypto/test/crypto_SUITE.erl b/lib/crypto/test/crypto_SUITE.erl
index 6f2df0f07b..08ecad3233 100644
--- a/lib/crypto/test/crypto_SUITE.erl
+++ b/lib/crypto/test/crypto_SUITE.erl
@@ -39,7 +39,10 @@
hmac_update_md5_io/1,
hmac_update_md5_n/1,
hmac_rfc2202/1,
- hmac_rfc4231/1,
+ hmac_rfc4231_sha224/1,
+ hmac_rfc4231_sha256/1,
+ hmac_rfc4231_sha384/1,
+ hmac_rfc4231_sha512/1,
ripemd160/1,
ripemd160_update/1,
sha256/1,
@@ -72,6 +75,7 @@
dsa_sign_hash_test/1,
rsa_encrypt_decrypt/1,
dh/1,
+ srp3/1, srp6/1, srp6a/1,
exor_test/1,
rc4_test/1,
rc4_stream_test/1,
@@ -93,14 +97,15 @@ groups() ->
sha256, sha256_update, sha512, sha512_update,
hmac_update_sha, hmac_update_sha_n, hmac_update_sha256, hmac_update_sha512,
hmac_update_md5_n, hmac_update_md5_io, hmac_update_md5,
- hmac_rfc2202, hmac_rfc4231,
+ hmac_rfc2202, hmac_rfc4231_sha224, hmac_rfc4231_sha256,
+ hmac_rfc4231_sha384, hmac_rfc4231_sha512,
des_cbc, aes_cfb, aes_cbc,
des_cfb, des_cfb_iter, des3_cbc, des3_cfb, rc2_cbc,
aes_cbc_iter, aes_ctr, aes_ctr_stream, des_cbc_iter, des_ecb,
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, exor_test,
+ rsa_encrypt_decrypt, dh, srp3, srp6, srp6a, exor_test,
rc4_test, rc4_stream_test, mod_exp_test, blowfish_cfb64,
smp]}].
@@ -363,8 +368,7 @@ hmac_update_sha256(doc) ->
hmac_update_sha256(suite) ->
[];
hmac_update_sha256(Config) when is_list(Config) ->
- if_098(fun() -> hmac_update_sha256_do() end).
-
+ if_supported(sha256, fun() -> hmac_update_sha256_do() end).
hmac_update_sha256_do() ->
?line Key = hexstr2bin("00010203101112132021222330313233"
@@ -386,7 +390,7 @@ hmac_update_sha512(doc) ->
hmac_update_sha512(suite) ->
[];
hmac_update_sha512(Config) when is_list(Config) ->
- if_098(fun() -> hmac_update_sha512_do() end).
+ if_supported(sha512, fun() -> hmac_update_sha512_do() end).
hmac_update_sha512_do() ->
?line Key = hexstr2bin("00010203101112132021222330313233"
@@ -582,366 +586,192 @@ hmac_rfc2202_sha() ->
?line m(Case7Exp, Case7Mac_1),
?line m(Case7Exp, Case7Mac_2).
-hmac_rfc4231(doc) ->
- ["Generate an HMAC using crypto:shaXXX_mac, hmac, and hmac_init, hmac_update, and hmac_final. "
+hmac_rfc4231_sha224(doc) ->
+ ["Generate an HMAC using crypto:sha224_mac, hmac, and hmac_init, hmac_update, and hmac_final. "
"Testvectors are take from RFC4231." ];
-hmac_rfc4231(suite) ->
+hmac_rfc4231_sha224(suite) ->
[];
-hmac_rfc4231(Config) when is_list(Config) ->
- if_098(fun() -> hmac_rfc4231_do() end).
+hmac_rfc4231_sha224(Config) when is_list(Config) ->
+ if_supported(sha224, fun() -> hmac_rfc4231_sha224_do() end).
-hmac_rfc4231_do() ->
- %% Test Case 1
- Case1Key = binary:copy(<<16#0b>>, 20),
- Case1Data = <<"Hi There">>,
- Case1Exp224 = hexstr2bin("896fb1128abbdf196832107cd49df33f"
- "47b4b1169912ba4f53684b22"),
- Case1Exp256 = hexstr2bin("b0344c61d8db38535ca8afceaf0bf12b"
- "881dc200c9833da726e9376c2e32cff7"),
- Case1Exp384 = hexstr2bin("afd03944d84895626b0825f4ab46907f"
- "15f9dadbe4101ec682aa034c7cebc59c"
- "faea9ea9076ede7f4af152e8b2fa9cb6"),
- Case1Exp512 = hexstr2bin("87aa7cdea5ef619d4ff0b4241a1d6cb0"
- "2379f4e2ce4ec2787ad0b30545e17cde"
- "daa833b7d6b8a702038b274eaea3f4e4"
- "be9d914eeb61f1702e696c203a126854"),
-
- ?line Case1Ctx224 = crypto:hmac_init(sha224, Case1Key),
- ?line Case1Ctx224_2 = crypto:hmac_update(Case1Ctx224, Case1Data),
- ?line Case1Mac224_1 = crypto:hmac_final(Case1Ctx224_2),
- ?line Case1Mac224_2 = crypto:sha224_mac(Case1Key, Case1Data),
- ?line Case1Mac224_3 = crypto:hmac(sha224, Case1Key, Case1Data),
- ?line m(Case1Exp224, Case1Mac224_1),
- ?line m(Case1Exp224, Case1Mac224_2),
- ?line m(Case1Exp224, Case1Mac224_3),
-
- ?line Case1Ctx256 = crypto:hmac_init(sha256, Case1Key),
- ?line Case1Ctx256_2 = crypto:hmac_update(Case1Ctx256, Case1Data),
- ?line Case1Mac256_1 = crypto:hmac_final(Case1Ctx256_2),
- ?line Case1Mac256_2 = crypto:sha256_mac(Case1Key, Case1Data),
- ?line Case1Mac256_3 = crypto:hmac(sha256, Case1Key, Case1Data),
- ?line m(Case1Exp256, Case1Mac256_1),
- ?line m(Case1Exp256, Case1Mac256_2),
- ?line m(Case1Exp256, Case1Mac256_3),
-
- ?line Case1Ctx384 = crypto:hmac_init(sha384, Case1Key),
- ?line Case1Ctx384_2 = crypto:hmac_update(Case1Ctx384, Case1Data),
- ?line Case1Mac384_1 = crypto:hmac_final(Case1Ctx384_2),
- ?line Case1Mac384_2 = crypto:sha384_mac(Case1Key, Case1Data),
- ?line Case1Mac384_3 = crypto:hmac(sha384, Case1Key, Case1Data),
- ?line m(Case1Exp384, Case1Mac384_1),
- ?line m(Case1Exp384, Case1Mac384_2),
- ?line m(Case1Exp384, Case1Mac384_3),
-
- ?line Case1Ctx512 = crypto:hmac_init(sha512, Case1Key),
- ?line Case1Ctx512_2 = crypto:hmac_update(Case1Ctx512, Case1Data),
- ?line Case1Mac512_1 = crypto:hmac_final(Case1Ctx512_2),
- ?line Case1Mac512_2 = crypto:sha512_mac(Case1Key, Case1Data),
- ?line Case1Mac512_3 = crypto:hmac(sha512, Case1Key, Case1Data),
- ?line m(Case1Exp512, Case1Mac512_1),
- ?line m(Case1Exp512, Case1Mac512_2),
- ?line m(Case1Exp512, Case1Mac512_3),
-
- %% Test Case 2
- Case2Key = <<"Jefe">>,
- Case2Data = <<"what do ya want for nothing?">>,
- Case2Exp224 = hexstr2bin("a30e01098bc6dbbf45690f3a7e9e6d0f"
- "8bbea2a39e6148008fd05e44"),
- Case2Exp256 = hexstr2bin("5bdcc146bf60754e6a042426089575c7"
- "5a003f089d2739839dec58b964ec3843"),
- Case2Exp384 = hexstr2bin("af45d2e376484031617f78d2b58a6b1b"
- "9c7ef464f5a01b47e42ec3736322445e"
- "8e2240ca5e69e2c78b3239ecfab21649"),
- Case2Exp512 = hexstr2bin("164b7a7bfcf819e2e395fbe73b56e0a3"
- "87bd64222e831fd610270cd7ea250554"
- "9758bf75c05a994a6d034f65f8f0e6fd"
- "caeab1a34d4a6b4b636e070a38bce737"),
-
- ?line Case2Ctx224 = crypto:hmac_init(sha224, Case2Key),
- ?line Case2Ctx224_2 = crypto:hmac_update(Case2Ctx224, Case2Data),
- ?line Case2Mac224_1 = crypto:hmac_final(Case2Ctx224_2),
- ?line Case2Mac224_2 = crypto:sha224_mac(Case2Key, Case2Data),
- ?line Case2Mac224_3 = crypto:hmac(sha224, Case2Key, Case2Data),
- ?line m(Case2Exp224, Case2Mac224_1),
- ?line m(Case2Exp224, Case2Mac224_2),
- ?line m(Case2Exp224, Case2Mac224_3),
-
- ?line Case2Ctx256 = crypto:hmac_init(sha256, Case2Key),
- ?line Case2Ctx256_2 = crypto:hmac_update(Case2Ctx256, Case2Data),
- ?line Case2Mac256_1 = crypto:hmac_final(Case2Ctx256_2),
- ?line Case2Mac256_2 = crypto:sha256_mac(Case2Key, Case2Data),
- ?line Case2Mac256_3 = crypto:hmac(sha256, Case2Key, Case2Data),
- ?line m(Case2Exp256, Case2Mac256_1),
- ?line m(Case2Exp256, Case2Mac256_2),
- ?line m(Case2Exp256, Case2Mac256_3),
-
- ?line Case2Ctx384 = crypto:hmac_init(sha384, Case2Key),
- ?line Case2Ctx384_2 = crypto:hmac_update(Case2Ctx384, Case2Data),
- ?line Case2Mac384_1 = crypto:hmac_final(Case2Ctx384_2),
- ?line Case2Mac384_2 = crypto:sha384_mac(Case2Key, Case2Data),
- ?line Case2Mac384_3 = crypto:hmac(sha384, Case2Key, Case2Data),
- ?line m(Case2Exp384, Case2Mac384_1),
- ?line m(Case2Exp384, Case2Mac384_2),
- ?line m(Case2Exp384, Case2Mac384_3),
-
- ?line Case2Ctx512 = crypto:hmac_init(sha512, Case2Key),
- ?line Case2Ctx512_2 = crypto:hmac_update(Case2Ctx512, Case2Data),
- ?line Case2Mac512_1 = crypto:hmac_final(Case2Ctx512_2),
- ?line Case2Mac512_2 = crypto:sha512_mac(Case2Key, Case2Data),
- ?line Case2Mac512_3 = crypto:hmac(sha512, Case2Key, Case2Data),
- ?line m(Case2Exp512, Case2Mac512_1),
- ?line m(Case2Exp512, Case2Mac512_2),
- ?line m(Case2Exp512, Case2Mac512_3),
-
- %% Test Case 3
- Case3Key = binary:copy(<<16#aa>>, 20),
- Case3Data = binary:copy(<<16#dd>>, 50),
- Case3Exp224 = hexstr2bin("7fb3cb3588c6c1f6ffa9694d7d6ad264"
- "9365b0c1f65d69d1ec8333ea"),
- Case3Exp256 = hexstr2bin("773ea91e36800e46854db8ebd09181a7"
- "2959098b3ef8c122d9635514ced565fe"),
- Case3Exp384 = hexstr2bin("88062608d3e6ad8a0aa2ace014c8a86f"
- "0aa635d947ac9febe83ef4e55966144b"
- "2a5ab39dc13814b94e3ab6e101a34f27"),
- Case3Exp512 = hexstr2bin("fa73b0089d56a284efb0f0756c890be9"
- "b1b5dbdd8ee81a3655f83e33b2279d39"
- "bf3e848279a722c806b485a47e67c807"
- "b946a337bee8942674278859e13292fb"),
-
- ?line Case3Ctx224 = crypto:hmac_init(sha224, Case3Key),
- ?line Case3Ctx224_2 = crypto:hmac_update(Case3Ctx224, Case3Data),
- ?line Case3Mac224_1 = crypto:hmac_final(Case3Ctx224_2),
- ?line Case3Mac224_2 = crypto:sha224_mac(Case3Key, Case3Data),
- ?line Case3Mac224_3 = crypto:hmac(sha224, Case3Key, Case3Data),
- ?line m(Case3Exp224, Case3Mac224_1),
- ?line m(Case3Exp224, Case3Mac224_2),
- ?line m(Case3Exp224, Case3Mac224_3),
-
- ?line Case3Ctx256 = crypto:hmac_init(sha256, Case3Key),
- ?line Case3Ctx256_2 = crypto:hmac_update(Case3Ctx256, Case3Data),
- ?line Case3Mac256_1 = crypto:hmac_final(Case3Ctx256_2),
- ?line Case3Mac256_2 = crypto:sha256_mac(Case3Key, Case3Data),
- ?line Case3Mac256_3 = crypto:hmac(sha256, Case3Key, Case3Data),
- ?line m(Case3Exp256, Case3Mac256_1),
- ?line m(Case3Exp256, Case3Mac256_2),
- ?line m(Case3Exp256, Case3Mac256_3),
-
- ?line Case3Ctx384 = crypto:hmac_init(sha384, Case3Key),
- ?line Case3Ctx384_2 = crypto:hmac_update(Case3Ctx384, Case3Data),
- ?line Case3Mac384_1 = crypto:hmac_final(Case3Ctx384_2),
- ?line Case3Mac384_2 = crypto:sha384_mac(Case3Key, Case3Data),
- ?line Case3Mac384_3 = crypto:hmac(sha384, Case3Key, Case3Data),
- ?line m(Case3Exp384, Case3Mac384_1),
- ?line m(Case3Exp384, Case3Mac384_2),
- ?line m(Case3Exp384, Case3Mac384_3),
-
- ?line Case3Ctx512 = crypto:hmac_init(sha512, Case3Key),
- ?line Case3Ctx512_2 = crypto:hmac_update(Case3Ctx512, Case3Data),
- ?line Case3Mac512_1 = crypto:hmac_final(Case3Ctx512_2),
- ?line Case3Mac512_2 = crypto:sha512_mac(Case3Key, Case3Data),
- ?line Case3Mac512_3 = crypto:hmac(sha512, Case3Key, Case3Data),
- ?line m(Case3Exp512, Case3Mac512_1),
- ?line m(Case3Exp512, Case3Mac512_2),
- ?line m(Case3Exp512, Case3Mac512_3),
-
- %% Test Case 4
- Case4Key = list_to_binary(lists:seq(1, 16#19)),
- Case4Data = binary:copy(<<16#cd>>, 50),
- Case4Exp224 = hexstr2bin("6c11506874013cac6a2abc1bb382627c"
- "ec6a90d86efc012de7afec5a"),
- Case4Exp256 = hexstr2bin("82558a389a443c0ea4cc819899f2083a"
- "85f0faa3e578f8077a2e3ff46729665b"),
- Case4Exp384 = hexstr2bin("3e8a69b7783c25851933ab6290af6ca7"
- "7a9981480850009cc5577c6e1f573b4e"
- "6801dd23c4a7d679ccf8a386c674cffb"),
- Case4Exp512 = hexstr2bin("b0ba465637458c6990e5a8c5f61d4af7"
- "e576d97ff94b872de76f8050361ee3db"
- "a91ca5c11aa25eb4d679275cc5788063"
- "a5f19741120c4f2de2adebeb10a298dd"),
-
- ?line Case4Ctx224 = crypto:hmac_init(sha224, Case4Key),
- ?line Case4Ctx224_2 = crypto:hmac_update(Case4Ctx224, Case4Data),
- ?line Case4Mac224_1 = crypto:hmac_final(Case4Ctx224_2),
- ?line Case4Mac224_2 = crypto:sha224_mac(Case4Key, Case4Data),
- ?line Case4Mac224_3 = crypto:hmac(sha224, Case4Key, Case4Data),
- ?line m(Case4Exp224, Case4Mac224_1),
- ?line m(Case4Exp224, Case4Mac224_2),
- ?line m(Case4Exp224, Case4Mac224_3),
-
- ?line Case4Ctx256 = crypto:hmac_init(sha256, Case4Key),
- ?line Case4Ctx256_2 = crypto:hmac_update(Case4Ctx256, Case4Data),
- ?line Case4Mac256_1 = crypto:hmac_final(Case4Ctx256_2),
- ?line Case4Mac256_2 = crypto:sha256_mac(Case4Key, Case4Data),
- ?line Case4Mac256_3 = crypto:hmac(sha256, Case4Key, Case4Data),
- ?line m(Case4Exp256, Case4Mac256_1),
- ?line m(Case4Exp256, Case4Mac256_2),
- ?line m(Case4Exp256, Case4Mac256_3),
-
- ?line Case4Ctx384 = crypto:hmac_init(sha384, Case4Key),
- ?line Case4Ctx384_2 = crypto:hmac_update(Case4Ctx384, Case4Data),
- ?line Case4Mac384_1 = crypto:hmac_final(Case4Ctx384_2),
- ?line Case4Mac384_2 = crypto:sha384_mac(Case4Key, Case4Data),
- ?line Case4Mac384_3 = crypto:hmac(sha384, Case4Key, Case4Data),
- ?line m(Case4Exp384, Case4Mac384_1),
- ?line m(Case4Exp384, Case4Mac384_2),
- ?line m(Case4Exp384, Case4Mac384_3),
-
- ?line Case4Ctx512 = crypto:hmac_init(sha512, Case4Key),
- ?line Case4Ctx512_2 = crypto:hmac_update(Case4Ctx512, Case4Data),
- ?line Case4Mac512_1 = crypto:hmac_final(Case4Ctx512_2),
- ?line Case4Mac512_2 = crypto:sha512_mac(Case4Key, Case4Data),
- ?line Case4Mac512_3 = crypto:hmac(sha512, Case4Key, Case4Data),
- ?line m(Case4Exp512, Case4Mac512_1),
- ?line m(Case4Exp512, Case4Mac512_2),
- ?line m(Case4Exp512, Case4Mac512_3),
-
- %% Test Case 5
- Case5Key = binary:copy(<<16#0c>>, 20),
- Case5Data = <<"Test With Truncation">>,
- Case5Exp224 = hexstr2bin("0e2aea68a90c8d37c988bcdb9fca6fa8"),
- Case5Exp256 = hexstr2bin("a3b6167473100ee06e0c796c2955552b"),
- Case5Exp384 = hexstr2bin("3abf34c3503b2a23a46efc619baef897"),
- Case5Exp512 = hexstr2bin("415fad6271580a531d4179bc891d87a6"),
-
- ?line Case5Ctx224 = crypto:hmac_init(sha224, Case5Key),
- ?line Case5Ctx224_2 = crypto:hmac_update(Case5Ctx224, Case5Data),
- ?line Case5Mac224_1 = crypto:hmac_final_n(Case5Ctx224_2, 16),
- ?line Case5Mac224_2 = crypto:sha224_mac(Case5Key, Case5Data, 16),
- ?line Case5Mac224_3 = crypto:hmac(sha224, Case5Key, Case5Data, 16),
- ?line m(Case5Exp224, Case5Mac224_1),
- ?line m(Case5Exp224, Case5Mac224_2),
- ?line m(Case5Exp224, Case5Mac224_3),
-
- ?line Case5Ctx256 = crypto:hmac_init(sha256, Case5Key),
- ?line Case5Ctx256_2 = crypto:hmac_update(Case5Ctx256, Case5Data),
- ?line Case5Mac256_1 = crypto:hmac_final_n(Case5Ctx256_2, 16),
- ?line Case5Mac256_2 = crypto:sha256_mac(Case5Key, Case5Data, 16),
- ?line Case5Mac256_3 = crypto:hmac(sha256, Case5Key, Case5Data, 16),
- ?line m(Case5Exp256, Case5Mac256_1),
- ?line m(Case5Exp256, Case5Mac256_2),
- ?line m(Case5Exp256, Case5Mac256_3),
-
- ?line Case5Ctx384 = crypto:hmac_init(sha384, Case5Key),
- ?line Case5Ctx384_2 = crypto:hmac_update(Case5Ctx384, Case5Data),
- ?line Case5Mac384_1 = crypto:hmac_final_n(Case5Ctx384_2, 16),
- ?line Case5Mac384_2 = crypto:sha384_mac(Case5Key, Case5Data, 16),
- ?line Case5Mac384_3 = crypto:hmac(sha384, Case5Key, Case5Data, 16),
- ?line m(Case5Exp384, Case5Mac384_1),
- ?line m(Case5Exp384, Case5Mac384_2),
- ?line m(Case5Exp384, Case5Mac384_3),
-
- ?line Case5Ctx512 = crypto:hmac_init(sha512, Case5Key),
- ?line Case5Ctx512_2 = crypto:hmac_update(Case5Ctx512, Case5Data),
- ?line Case5Mac512_1 = crypto:hmac_final_n(Case5Ctx512_2, 16),
- ?line Case5Mac512_2 = crypto:sha512_mac(Case5Key, Case5Data, 16),
- ?line Case5Mac512_3 = crypto:hmac(sha512, Case5Key, Case5Data, 16),
- ?line m(Case5Exp512, Case5Mac512_1),
- ?line m(Case5Exp512, Case5Mac512_2),
- ?line m(Case5Exp512, Case5Mac512_3),
-
- %% Test Case 6
- Case6Key = binary:copy(<<16#aa>>, 131),
- Case6Data = <<"Test Using Larger Than Block-Size Key - Hash Key First">>,
- Case6Exp224 = hexstr2bin("95e9a0db962095adaebe9b2d6f0dbce2"
- "d499f112f2d2b7273fa6870e"),
- Case6Exp256 = hexstr2bin("60e431591ee0b67f0d8a26aacbf5b77f"
- "8e0bc6213728c5140546040f0ee37f54"),
- Case6Exp384 = hexstr2bin("4ece084485813e9088d2c63a041bc5b4"
- "4f9ef1012a2b588f3cd11f05033ac4c6"
- "0c2ef6ab4030fe8296248df163f44952"),
- Case6Exp512 = hexstr2bin("80b24263c7c1a3ebb71493c1dd7be8b4"
- "9b46d1f41b4aeec1121b013783f8f352"
- "6b56d037e05f2598bd0fd2215d6a1e52"
- "95e64f73f63f0aec8b915a985d786598"),
-
- ?line Case6Ctx224 = crypto:hmac_init(sha224, Case6Key),
- ?line Case6Ctx224_2 = crypto:hmac_update(Case6Ctx224, Case6Data),
- ?line Case6Mac224_1 = crypto:hmac_final(Case6Ctx224_2),
- ?line Case6Mac224_2 = crypto:sha224_mac(Case6Key, Case6Data),
- ?line Case6Mac224_3 = crypto:hmac(sha224, Case6Key, Case6Data),
- ?line m(Case6Exp224, Case6Mac224_1),
- ?line m(Case6Exp224, Case6Mac224_2),
- ?line m(Case6Exp224, Case6Mac224_3),
-
- ?line Case6Ctx256 = crypto:hmac_init(sha256, Case6Key),
- ?line Case6Ctx256_2 = crypto:hmac_update(Case6Ctx256, Case6Data),
- ?line Case6Mac256_1 = crypto:hmac_final(Case6Ctx256_2),
- ?line Case6Mac256_2 = crypto:sha256_mac(Case6Key, Case6Data),
- ?line Case6Mac256_3 = crypto:hmac(sha256, Case6Key, Case6Data),
- ?line m(Case6Exp256, Case6Mac256_1),
- ?line m(Case6Exp256, Case6Mac256_2),
- ?line m(Case6Exp256, Case6Mac256_3),
-
- ?line Case6Ctx384 = crypto:hmac_init(sha384, Case6Key),
- ?line Case6Ctx384_2 = crypto:hmac_update(Case6Ctx384, Case6Data),
- ?line Case6Mac384_1 = crypto:hmac_final(Case6Ctx384_2),
- ?line Case6Mac384_2 = crypto:sha384_mac(Case6Key, Case6Data),
- ?line Case6Mac384_3 = crypto:hmac(sha384, Case6Key, Case6Data),
- ?line m(Case6Exp384, Case6Mac384_1),
- ?line m(Case6Exp384, Case6Mac384_2),
- ?line m(Case6Exp384, Case6Mac384_3),
-
- ?line Case6Ctx512 = crypto:hmac_init(sha512, Case6Key),
- ?line Case6Ctx512_2 = crypto:hmac_update(Case6Ctx512, Case6Data),
- ?line Case6Mac512_1 = crypto:hmac_final(Case6Ctx512_2),
- ?line Case6Mac512_2 = crypto:sha512_mac(Case6Key, Case6Data),
- ?line Case6Mac512_3 = crypto:hmac(sha512, Case6Key, Case6Data),
- ?line m(Case6Exp512, Case6Mac512_1),
- ?line m(Case6Exp512, Case6Mac512_2),
- ?line m(Case6Exp512, Case6Mac512_3),
-
+hmac_rfc4231_sha256(doc) ->
+ ["Generate an HMAC using crypto:sha256_mac, hmac, and hmac_init, hmac_update, and hmac_final. "
+ "Testvectors are take from RFC4231." ];
+hmac_rfc4231_sha256(suite) ->
+ [];
+hmac_rfc4231_sha256(Config) when is_list(Config) ->
+ if_supported(sha256, fun() -> hmac_rfc4231_sha256_do() end).
+
+hmac_rfc4231_sha384(doc) ->
+ ["Generate an HMAC using crypto:sha384_mac, hmac, and hmac_init, hmac_update, and hmac_final. "
+ "Testvectors are take from RFC4231." ];
+hmac_rfc4231_sha384(suite) ->
+ [];
+hmac_rfc4231_sha384(Config) when is_list(Config) ->
+ if_supported(sha384, fun() -> hmac_rfc4231_sha384_do() end).
+
+hmac_rfc4231_sha512(doc) ->
+ ["Generate an HMAC using crypto:sha512_mac, hmac, and hmac_init, hmac_update, and hmac_final. "
+ "Testvectors are take from RFC4231." ];
+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) ->
+ %% Test 1
+ Key = binary:copy(<<16#0b>>, 20),
+ Data = <<"Hi There">>,
+ hmac_rfc4231_case(Hash, HashFun, Key, Data, Exp);
+
+hmac_rfc4231_case(Hash, HashFun, 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, HashFun, 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, HashFun, 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, HashFun, 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, HashFun, 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, HashFun, case7, Exp) ->
%% Test Case 7
- Case7Key = binary:copy(<<16#aa>>, 131),
- Case7Data = <<"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.">>,
- Case7Exp224 = hexstr2bin("3a854166ac5d9f023f54d517d0b39dbd"
- "946770db9c2b95c9f6f565d1"),
- Case7Exp256 = hexstr2bin("9b09ffa71b942fcb27635fbcd5b0e944"
- "bfdc63644f0713938a7f51535c3a35e2"),
- Case7Exp384 = hexstr2bin("6617178e941f020d351e2f254e8fd32c"
- "602420feb0b8fb9adccebb82461e99c5"
- "a678cc31e799176d3860e6110c46523e"),
- Case7Exp512 = hexstr2bin("e37b6a775dc87dbaa4dfa9f96e5e3ffd"
- "debd71f8867289865df5a32d20cdc944"
- "b6022cac3c4982b10d5eeb55c3e4de15"
- "134676fb6de0446065c97440fa8c6a58"),
-
- ?line Case7Ctx224 = crypto:hmac_init(sha224, Case7Key),
- ?line Case7Ctx224_2 = crypto:hmac_update(Case7Ctx224, Case7Data),
- ?line Case7Mac224_1 = crypto:hmac_final(Case7Ctx224_2),
- ?line Case7Mac224_2 = crypto:sha224_mac(Case7Key, Case7Data),
- ?line Case7Mac224_3 = crypto:hmac(sha224, Case7Key, Case7Data),
- ?line m(Case7Exp224, Case7Mac224_1),
- ?line m(Case7Exp224, Case7Mac224_2),
- ?line m(Case7Exp224, Case7Mac224_3),
-
- ?line Case7Ctx256 = crypto:hmac_init(sha256, Case7Key),
- ?line Case7Ctx256_2 = crypto:hmac_update(Case7Ctx256, Case7Data),
- ?line Case7Mac256_1 = crypto:hmac_final(Case7Ctx256_2),
- ?line Case7Mac256_2 = crypto:sha256_mac(Case7Key, Case7Data),
- ?line Case7Mac256_3 = crypto:hmac(sha256, Case7Key, Case7Data),
- ?line m(Case7Exp256, Case7Mac256_1),
- ?line m(Case7Exp256, Case7Mac256_2),
- ?line m(Case7Exp256, Case7Mac256_3),
-
- ?line Case7Ctx384 = crypto:hmac_init(sha384, Case7Key),
- ?line Case7Ctx384_2 = crypto:hmac_update(Case7Ctx384, Case7Data),
- ?line Case7Mac384_1 = crypto:hmac_final(Case7Ctx384_2),
- ?line Case7Mac384_2 = crypto:sha384_mac(Case7Key, Case7Data),
- ?line Case7Mac384_3 = crypto:hmac(sha384, Case7Key, Case7Data),
- ?line m(Case7Exp384, Case7Mac384_1),
- ?line m(Case7Exp384, Case7Mac384_2),
- ?line m(Case7Exp384, Case7Mac384_3),
-
- ?line Case7Ctx512 = crypto:hmac_init(sha512, Case7Key),
- ?line Case7Ctx512_2 = crypto:hmac_update(Case7Ctx512, Case7Data),
- ?line Case7Mac512_1 = crypto:hmac_final(Case7Ctx512_2),
- ?line Case7Mac512_2 = crypto:sha512_mac(Case7Key, Case7Data),
- ?line Case7Mac512_3 = crypto:hmac(sha512, Case7Key, Case7Data),
- ?line m(Case7Exp512, Case7Mac512_1),
- ?line m(Case7Exp512, Case7Mac512_2),
- ?line m(Case7Exp512, Case7Mac512_3).
+ 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, HashFun, 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) ->
+ ?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() ->
+ Case1 = hexstr2bin("896fb1128abbdf196832107cd49df33f"
+ "47b4b1169912ba4f53684b22"),
+ Case2 = hexstr2bin("a30e01098bc6dbbf45690f3a7e9e6d0f"
+ "8bbea2a39e6148008fd05e44"),
+ Case3 = hexstr2bin("7fb3cb3588c6c1f6ffa9694d7d6ad264"
+ "9365b0c1f65d69d1ec8333ea"),
+ Case4 = hexstr2bin("6c11506874013cac6a2abc1bb382627c"
+ "ec6a90d86efc012de7afec5a"),
+ Case5 = hexstr2bin("0e2aea68a90c8d37c988bcdb9fca6fa8"),
+ Case6 = hexstr2bin("95e9a0db962095adaebe9b2d6f0dbce2"
+ "d499f112f2d2b7273fa6870e"),
+ Case7 = hexstr2bin("3a854166ac5d9f023f54d517d0b39dbd"
+ "946770db9c2b95c9f6f565d1"),
+ hmac_rfc4231_cases_do(sha224, sha224_mac, [Case1, Case2, Case3, Case4, Case5, Case6, Case7]).
+
+hmac_rfc4231_sha256_do() ->
+ Case1 = hexstr2bin("b0344c61d8db38535ca8afceaf0bf12b"
+ "881dc200c9833da726e9376c2e32cff7"),
+ Case2 = hexstr2bin("5bdcc146bf60754e6a042426089575c7"
+ "5a003f089d2739839dec58b964ec3843"),
+ Case3 = hexstr2bin("773ea91e36800e46854db8ebd09181a7"
+ "2959098b3ef8c122d9635514ced565fe"),
+ Case4 = hexstr2bin("82558a389a443c0ea4cc819899f2083a"
+ "85f0faa3e578f8077a2e3ff46729665b"),
+ Case5 = hexstr2bin("a3b6167473100ee06e0c796c2955552b"),
+ Case6 = hexstr2bin("60e431591ee0b67f0d8a26aacbf5b77f"
+ "8e0bc6213728c5140546040f0ee37f54"),
+ Case7 = hexstr2bin("9b09ffa71b942fcb27635fbcd5b0e944"
+ "bfdc63644f0713938a7f51535c3a35e2"),
+ hmac_rfc4231_cases_do(sha256, sha256_mac, [Case1, Case2, Case3, Case4, Case5, Case6, Case7]).
+
+hmac_rfc4231_sha384_do() ->
+ Case1 = hexstr2bin("afd03944d84895626b0825f4ab46907f"
+ "15f9dadbe4101ec682aa034c7cebc59c"
+ "faea9ea9076ede7f4af152e8b2fa9cb6"),
+ Case2 = hexstr2bin("af45d2e376484031617f78d2b58a6b1b"
+ "9c7ef464f5a01b47e42ec3736322445e"
+ "8e2240ca5e69e2c78b3239ecfab21649"),
+ Case3 = hexstr2bin("88062608d3e6ad8a0aa2ace014c8a86f"
+ "0aa635d947ac9febe83ef4e55966144b"
+ "2a5ab39dc13814b94e3ab6e101a34f27"),
+ Case4 = hexstr2bin("3e8a69b7783c25851933ab6290af6ca7"
+ "7a9981480850009cc5577c6e1f573b4e"
+ "6801dd23c4a7d679ccf8a386c674cffb"),
+ Case5 = hexstr2bin("3abf34c3503b2a23a46efc619baef897"),
+ Case6 = hexstr2bin("4ece084485813e9088d2c63a041bc5b4"
+ "4f9ef1012a2b588f3cd11f05033ac4c6"
+ "0c2ef6ab4030fe8296248df163f44952"),
+ Case7 = hexstr2bin("6617178e941f020d351e2f254e8fd32c"
+ "602420feb0b8fb9adccebb82461e99c5"
+ "a678cc31e799176d3860e6110c46523e"),
+ hmac_rfc4231_cases_do(sha384, sha384_mac, [Case1, Case2, Case3, Case4, Case5, Case6, Case7]).
+
+hmac_rfc4231_sha512_do() ->
+ Case1 = hexstr2bin("87aa7cdea5ef619d4ff0b4241a1d6cb0"
+ "2379f4e2ce4ec2787ad0b30545e17cde"
+ "daa833b7d6b8a702038b274eaea3f4e4"
+ "be9d914eeb61f1702e696c203a126854"),
+ Case2 = hexstr2bin("164b7a7bfcf819e2e395fbe73b56e0a3"
+ "87bd64222e831fd610270cd7ea250554"
+ "9758bf75c05a994a6d034f65f8f0e6fd"
+ "caeab1a34d4a6b4b636e070a38bce737"),
+ Case3 = hexstr2bin("fa73b0089d56a284efb0f0756c890be9"
+ "b1b5dbdd8ee81a3655f83e33b2279d39"
+ "bf3e848279a722c806b485a47e67c807"
+ "b946a337bee8942674278859e13292fb"),
+ Case4 = hexstr2bin("b0ba465637458c6990e5a8c5f61d4af7"
+ "e576d97ff94b872de76f8050361ee3db"
+ "a91ca5c11aa25eb4d679275cc5788063"
+ "a5f19741120c4f2de2adebeb10a298dd"),
+ Case5 = hexstr2bin("415fad6271580a531d4179bc891d87a6"),
+ Case6 = hexstr2bin("80b24263c7c1a3ebb71493c1dd7be8b4"
+ "9b46d1f41b4aeec1121b013783f8f352"
+ "6b56d037e05f2598bd0fd2215d6a1e52"
+ "95e64f73f63f0aec8b915a985d786598"),
+ Case7 = hexstr2bin("e37b6a775dc87dbaa4dfa9f96e5e3ffd"
+ "debd71f8867289865df5a32d20cdc944"
+ "b6022cac3c4982b10d5eeb55c3e4de15"
+ "134676fb6de0446065c97440fa8c6a58"),
+ hmac_rfc4231_cases_do(sha512, sha512_mac, [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, _HashFun, _, []) ->
+ 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_update_md5_io(doc) ->
["Generate an MD5 HMAC using hmac_init, hmac_update, and hmac_final. "
@@ -1025,7 +855,7 @@ sha256(doc) ->
sha256(suite) ->
[];
sha256(Config) when is_list(Config) ->
- if_098(fun() -> sha256_do() end).
+ if_supported(sha256, fun() -> sha256_do() end).
sha256_do() ->
?line m(crypto:sha256("abc"),
@@ -1044,7 +874,7 @@ sha256_update(doc) ->
sha256_update(suite) ->
[];
sha256_update(Config) when is_list(Config) ->
- if_098(fun() -> sha256_update_do() end).
+ if_supported(sha256, fun() -> sha256_update_do() end).
sha256_update_do() ->
?line Ctx = crypto:sha256_init(),
@@ -1063,7 +893,7 @@ sha512(doc) ->
sha512(suite) ->
[];
sha512(Config) when is_list(Config) ->
- if_098(fun() -> sha512_do() end).
+ if_supported(sha512, fun() -> sha512_do() end).
sha512_do() ->
?line m(crypto:sha512("abc"),
@@ -1084,7 +914,7 @@ sha512_update(doc) ->
sha512_update(suite) ->
[];
sha512_update(Config) when is_list(Config) ->
- if_098(fun() -> sha512_update_do() end).
+ if_supported(sha512, fun() -> sha512_update_do() end).
sha512_update_do() ->
?line Ctx = crypto:sha512_init(),
@@ -2017,6 +1847,161 @@ dh(Config) when is_list(Config) ->
exit(Pid, kill)
end.
+srp3(doc) ->
+ ["SRP-3 test vectors generated by http://srp.stanford.edu/demo/demo.html"];
+srp3(suite) -> [];
+srp3(Config) when is_list(Config) ->
+ Username = <<"alice">>,
+ Password = <<"password123">>,
+ Salt = hexstr2bin("2857827A19266A1F2BC6"),
+ Prime = hexstr2bin("EEAF0AB9ADB38DD69C33F80AFA8FC5E86072618775FF3C0B9EA2314C"
+ "9C256576D674DF7496EA81D3383B4813D692C6E0E0D5D8E250B98BE4"
+ "8E495C1D6089DAD15DC7D7B46154D6B6CE8EF4AD69B15D4982559B29"
+ "7BCF1885C529F566660E57EC68EDBC3C05726CC02FD4CBF4976EAA9A"
+ "FD5138FE8376435B9FC61D2FC0EB06E3"),
+ Generator = <<2>>,
+ Version = '3',
+ Scrambler = hexstr2bin("02E2476A"),
+
+ %% X = hexstr2bin("96E54AB0CD4C5123EDCFA4A1502918AAD3C9E2A8"),
+ Verifier = hexstr2bin("96EB5F13621D911AA1CA405DE9C64217D4108EEEECAFFE500034FE0E"
+ "C031E42C8714667C161BCE0E7996F7DDE1B63824C130D2D7286C08C0"
+ "49758420735961347112AE102A3F23B3F687F8FEE0DF2BFAF933C608"
+ "D6FE5B5EEE3116FE54016E065BF8E8C9FDBBC08719231AC215149140"
+ "519E8FDD9AA4F410C28A58AF42974D2D"),
+ ClientPrivate = hexstr2bin("6411DE75538BED8170677D577D0608F39112BC95B503C447EB6AC945"
+ "49C75C7B"),
+ ServerPrivate = hexstr2bin("85E44A6F694DBE676145DB245A045CD37C99F05C562C7840A31F270D"
+ "9AADCF8B"),
+ ClientPublic = hexstr2bin("B22B1FFA2244B8CB94F3A9080F419CAEAB0DBA93EA1965B5E84587EE"
+ "55C79E7A118865DC59B9D0353362C2A8261E7C1B0D221A0E233C2AD1"
+ "640DACBB8664CBC9733EAC392DA7800142860380C3FC573C3C064329"
+ "CF54063FD114C7210E9CB3A611EA8002B1844B698F930D95D143899B"
+ "948A090E0C25938E5F84067D1883DC63"),
+ ServerPublic = hexstr2bin("93A8C4D8B7F7395ADCFD4ABA37B015124513D3F37B3E85EB23064BE5"
+ "F53C0AE32FFB9D8C0AA0DCFFA74D632DD67DEBB5C35AAE9812286CC8"
+ "C43CC176ECBC6D3F447594D9554E995B2509127BF88FADDDA4982D03"
+ "8EC3001320712D3B1269308CE70F319B2295FA57674F03A2D993CFB1"
+ "F84C35B7D0C012FA73CD4C8F7D5A71C7"),
+
+ SessionKey = hexstr2bin("C29A986C4D521BBC66428ED11D994CD7431574A6184B83CDCC345092"
+ "791E75748A1D38CAC4BD14760F0D2694B711236419240FF2F172454C"
+ "46ABF4FF39498DAFDD2C82924F7D7BD76CDFCE688C77D93F18A65409"
+ "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),
+
+ {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).
+
+srp6(doc) ->
+ ["SRP-6 test vectors generated by http://srp.stanford.edu/demo/demo.html"];
+srp6(suite) -> [];
+srp6(Config) when is_list(Config) ->
+ Username = <<"alice">>,
+ Password = <<"password123">>,
+ Salt = hexstr2bin("2857827A19266A1F2BC6"),
+ Prime = hexstr2bin("EEAF0AB9ADB38DD69C33F80AFA8FC5E86072618775FF3C0B9EA2314C"
+ "9C256576D674DF7496EA81D3383B4813D692C6E0E0D5D8E250B98BE4"
+ "8E495C1D6089DAD15DC7D7B46154D6B6CE8EF4AD69B15D4982559B29"
+ "7BCF1885C529F566660E57EC68EDBC3C05726CC02FD4CBF4976EAA9A"
+ "FD5138FE8376435B9FC61D2FC0EB06E3"),
+ Generator = <<2>>,
+ Version = '6',
+ Scrambler = hexstr2bin("0A2534C0BF52A0DA9001EEC62CF2A546AB0908A7"),
+ Verifier = hexstr2bin("96EB5F13621D911AA1CA405DE9C64217D4108EEEECAFFE500034FE0E"
+ "C031E42C8714667C161BCE0E7996F7DDE1B63824C130D2D7286C08C0"
+ "49758420735961347112AE102A3F23B3F687F8FEE0DF2BFAF933C608"
+ "D6FE5B5EEE3116FE54016E065BF8E8C9FDBBC08719231AC215149140"
+ "519E8FDD9AA4F410C28A58AF42974D2D"),
+ ClientPrivate = hexstr2bin("6411DE75538BED8170677D577D0608F39112BC95B503C447EB6AC945"
+ "49C75C7B"),
+ ServerPrivate = hexstr2bin("85E44A6F694DBE676145DB245A045CD37C99F05C562C7840A31F270D"
+ "9AADCF8B"),
+ ClientPublic = hexstr2bin("B22B1FFA2244B8CB94F3A9080F419CAEAB0DBA93EA1965B5E84587EE"
+ "55C79E7A118865DC59B9D0353362C2A8261E7C1B0D221A0E233C2AD1"
+ "640DACBB8664CBC9733EAC392DA7800142860380C3FC573C3C064329"
+ "CF54063FD114C7210E9CB3A611EA8002B1844B698F930D95D143899B"
+ "948A090E0C25938E5F84067D1883DC63"),
+ ServerPublic = hexstr2bin("D2D07845CE7ECDB9845DD36B10ACD3598CC29049DE9F467F84CE16B6"
+ "D97A6DC567AF8B0F9FEDF74962400AD5C357951E64E67B641246F264"
+ "C8DE6D9A72E554D6C8D3194548780A0C438A0FCC509CA88A14AA1DEB"
+ "C0F09E4B37A965D1545DB4AD361346F3189B0EA569C06D326C4E4797"
+ "9E381C748293B7C0591BE0BE419E053E"),
+
+ SessionKey = hexstr2bin("19D22C19612874EBF1F2581F8EFCFDC44C6FDA3B87B0A73823D7E962"
+ "554295D4E48D3A336523ADBDDD0EC8FB0F02687109E97E01C17C93CC"
+ "7216F9CD8A4AC39F0429857D8D1023066614BDFCBCB89F59A0FEB81C"
+ "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),
+
+ {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).
+
+srp6a(doc) ->
+ ["SRP-6a test vectors from RFC5054."];
+srp6a(suite) -> [];
+srp6a(Config) when is_list(Config) ->
+ Username = <<"alice">>,
+ Password = <<"password123">>,
+ Salt = hexstr2bin("BEB25379D1A8581EB5A727673A2441EE"),
+ Prime = hexstr2bin("EEAF0AB9ADB38DD69C33F80AFA8FC5E86072618775FF3C0B9EA2314C"
+ "9C256576D674DF7496EA81D3383B4813D692C6E0E0D5D8E250B98BE4"
+ "8E495C1D6089DAD15DC7D7B46154D6B6CE8EF4AD69B15D4982559B29"
+ "7BCF1885C529F566660E57EC68EDBC3C05726CC02FD4CBF4976EAA9A"
+ "FD5138FE8376435B9FC61D2FC0EB06E3"),
+ Generator = <<2>>,
+ Version = '6a',
+ Scrambler = hexstr2bin("CE38B9593487DA98554ED47D70A7AE5F462EF019"),
+ Verifier = hexstr2bin("7E273DE8696FFC4F4E337D05B4B375BEB0DDE1569E8FA00A9886D812"
+ "9BADA1F1822223CA1A605B530E379BA4729FDC59F105B4787E5186F5"
+ "C671085A1447B52A48CF1970B4FB6F8400BBF4CEBFBB168152E08AB5"
+ "EA53D15C1AFF87B2B9DA6E04E058AD51CC72BFC9033B564E26480D78"
+ "E955A5E29E7AB245DB2BE315E2099AFB"),
+ ClientPrivate = hexstr2bin("60975527035CF2AD1989806F0407210BC81EDC04E2762A56AFD529DD"
+ "DA2D4393"),
+ ServerPrivate = hexstr2bin("E487CB59D31AC550471E81F00F6928E01DDA08E974A004F49E61F5D1"
+ "05284D20"),
+ ClientPublic = hexstr2bin("61D5E490F6F1B79547B0704C436F523DD0E560F0C64115BB72557EC4"
+ "4352E8903211C04692272D8B2D1A5358A2CF1B6E0BFCF99F921530EC"
+ "8E39356179EAE45E42BA92AEACED825171E1E8B9AF6D9C03E1327F44"
+ "BE087EF06530E69F66615261EEF54073CA11CF5858F0EDFDFE15EFEA"
+ "B349EF5D76988A3672FAC47B0769447B"),
+ ServerPublic = hexstr2bin("BD0C61512C692C0CB6D041FA01BB152D4916A1E77AF46AE105393011"
+ "BAF38964DC46A0670DD125B95A981652236F99D9B681CBF87837EC99"
+ "6C6DA04453728610D0C6DDB58B318885D7D82C7F8DEB75CE7BD4FBAA"
+ "37089E6F9C6059F388838E7A00030B331EB76840910440B1B27AAEAE"
+ "EB4012B7D7665238A8E3FB004B117B58"),
+
+ SessionKey = hexstr2bin("B0DC82BABCF30674AE450C0287745E7990A3381F63B387AAF271A10D"
+ "233861E359B48220F7C4693C9AE12B0A6F67809F0876E2D013800D6C"
+ "41BB59B6D5979B5C00A172B4A2A5903A0BDCAF8A709585EB2AFAFA8F"
+ "3499B200210DCC1F10EB33943CD67FC88A2F39A4BE5BEC4EC0A3212D"
+ "C346D7E474B29EDE8A469FFECA686E5A"),
+ UserPassHash = crypto:sha([Salt, crypto:sha([Username, <<$:>>, Password])]),
+ Verifier = crypto:mod_exp_prime(Generator, UserPassHash, 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).
+
%%
%%
exor_test(doc) ->
@@ -2120,8 +2105,8 @@ worker_loop(N, Config) ->
aes_cfb, aes_cbc, des_cbc_iter, rand_uniform_test, strong_rand_test,
rsa_verify_test, exor_test, rc4_test, rc4_stream_test, mod_exp_test,
hmac_update_md5, hmac_update_sha, hmac_update_sha256, hmac_update_sha512,
- hmac_rfc2202, hmac_rfc4231,
- aes_ctr_stream },
+ hmac_rfc2202, hmac_rfc4231_sha224, hmac_rfc4231_sha256, hmac_rfc4231_sha384,
+ hmac_rfc4231_sha512, aes_ctr_stream },
F = element(random:uniform(size(Funcs)),Funcs),
%%io:format("worker ~p calling ~p\n",[self(),F]),
@@ -2256,10 +2241,10 @@ openssl_version() ->
undefined
end.
-if_098(Fun) ->
- case openssl_version() of
- V when V < 16#908000 ->
- {skipped,"OpenSSL version too old"};
+if_supported(Algorithm, Fun) ->
+ case proplists:get_bool(Algorithm, crypto:algorithms()) of
+ true ->
+ Fun();
_ ->
- Fun()
+ {skipped, io:format("~s not spupported", [Algorithm])}
end.
diff --git a/lib/dialyzer/src/dialyzer_analysis_callgraph.erl b/lib/dialyzer/src/dialyzer_analysis_callgraph.erl
index 86618a4915..ca6b403ac9 100644
--- a/lib/dialyzer/src/dialyzer_analysis_callgraph.erl
+++ b/lib/dialyzer/src/dialyzer_analysis_callgraph.erl
@@ -261,8 +261,8 @@ compile_and_store(Files, #analysis_state{codeserver = CServer,
dict:new(), NewFiles),
check_for_duplicate_modules(ModDict);
false ->
- Msg = io_lib:format("Could not scan the following file(s): ~p",
- [lists:flatten(Failed)]),
+ Msg = io_lib:format("Could not scan the following file(s):~n~s",
+ [[Reason || {_Filename, Reason} <- Failed]]),
exit({error, Msg})
end,
{T2, _} = statistics(runtime),
diff --git a/lib/odbc/c_src/odbcserver.c b/lib/odbc/c_src/odbcserver.c
index a6b3de6e48..5730e20774 100644
--- a/lib/odbc/c_src/odbcserver.c
+++ b/lib/odbc/c_src/odbcserver.c
@@ -1222,7 +1222,7 @@ static db_result_msg encode_out_params(db_state *state,
(column.type.strlen_or_indptr_array[j]));
break;
case SQL_C_SLONG:
- ei_x_encode_long(&dynamic_buffer(state), ((long*)values)[j]);
+ ei_x_encode_long(&dynamic_buffer(state), ((SQLINTEGER*)values)[j]);
break;
case SQL_C_DOUBLE:
ei_x_encode_double(&dynamic_buffer(state),
diff --git a/lib/odbc/test/odbc_query_SUITE.erl b/lib/odbc/test/odbc_query_SUITE.erl
index 062373afa0..56550bfaa6 100644
--- a/lib/odbc/test/odbc_query_SUITE.erl
+++ b/lib/odbc/test/odbc_query_SUITE.erl
@@ -43,7 +43,7 @@ suite() -> [{ct_hooks,[ts_install_cth]}].
all() ->
case odbc_test_lib:odbc_check() of
ok ->
- [sql_query, next, {group, scrollable_cursors}, select_count,
+ [stored_proc, sql_query, next, {group, scrollable_cursors}, select_count,
select_next, select_relative, select_absolute,
create_table_twice, delete_table_twice, duplicate_key,
not_connection_owner, no_result_set, query_error,
@@ -172,6 +172,26 @@ end_per_testcase(_Case, Config) ->
%%-------------------------------------------------------------------------
%% Test cases starts here.
%%-------------------------------------------------------------------------
+stored_proc(doc)->
+ ["Test stored proc with OUT param"];
+stored_proc(suite) -> [];
+stored_proc(Config) when is_list(Config) ->
+ case ?RDBMS of
+ X when X == oracle; X == postgres->
+ Ref = ?config(connection_ref, Config),
+ {updated, _} =
+ odbc:sql_query(Ref,
+ ?RDBMS:stored_proc_integer_out()),
+ Result = ?RDBMS:query_result(),
+ Result =
+ ?RDBMS:param_query(Ref),
+ {updated, _} =
+ odbc:sql_query(Ref, ?RDBMS:drop_proc()),
+ ok;
+ _ ->
+ {skip, "stored proc not yet supported"}
+ end.
+
sql_query(doc)->
["Test the common cases"];
sql_query(suite) -> [];
diff --git a/lib/odbc/test/oracle.erl b/lib/odbc/test/oracle.erl
index d74863d8c1..95cf7155dc 100644
--- a/lib/odbc/test/oracle.erl
+++ b/lib/odbc/test/oracle.erl
@@ -240,3 +240,30 @@ describe_floating() ->
{ok,[{"F",sql_double},{"R",sql_double},{"D",sql_double}]}.
describe_dec_num() ->
{ok,[{"MYDEC",{sql_decimal,9,3}},{"MYNUM",{sql_decimal,9,2}}]}.
+
+%-------------------------------------------------------------------------
+drop_proc() ->
+ "drop procedure test_proc1;".
+
+stored_proc_integer_out() ->
+ "create or replace PROCEDURE test_proc1(" ++
+ "int_a OUT NUMBER, " ++
+ "int_b OUT NUMBER) " ++
+ "is " ++
+ "begin " ++
+ " int_a := 123; " ++
+ " int_b := 456; " ++
+ "exception " ++
+ "WHEN NO_DATA_FOUND THEN " ++
+ " int_a := 0; " ++
+ " int_b := 0; " ++
+ "end;".
+
+param_query(Ref) ->
+ odbc:param_query(Ref, "call test_proc1(?,?)",
+ [{sql_integer, out, [0]},
+ {sql_integer, out, [0]}]).
+
+
+query_result() ->
+ {executed, 2, [{123, 456}]}.
diff --git a/lib/odbc/test/postgres.erl b/lib/odbc/test/postgres.erl
index d564dbd5ff..0c1761b835 100644
--- a/lib/odbc/test/postgres.erl
+++ b/lib/odbc/test/postgres.erl
@@ -293,3 +293,42 @@ describe_dec_num() ->
describe_timestamp() ->
{ok, [{"field", sql_timestamp}]}.
+
+%-------------------------------------------------------------------------
+drop_proc() ->
+ "drop function test_proc1(OUT integer, OUT integer);".
+
+stored_proc_integer_out() ->
+ "create or replace FUNCTION test_proc1(" ++
+ "OUT int_a INTEGER, " ++
+ "OUT int_b INTEGER) " ++
+ "AS $$ " ++
+ "BEGIN " ++
+ " int_a := 123; " ++
+ " int_b := 456; " ++
+ "END " ++
+ "$$ LANGUAGE plpgsql ".
+
+%% This does not test what you might think it is supposed to test.
+%% Since the stored procedure has got 2 out parameters and no
+%% in parameters it is of arity 0 as called below.
+%%
+%% The port program odbcserver.c will marshal these out parameters
+%% and hand them to ODBC. The ODBC driver for postgres will
+%% apparently not give a hoot about these out parameters and instead
+%% return the result in a regular result select set. The port program
+%% will assume it has the result in the out parameters and marshal
+%% these as they are i.e as it itself had packed them, so they
+%% come back unchanged.
+%%
+%% The real function result goes into the void but the code in odbcserver.c
+%% that marshals out parameters returned from ODBC will be run
+%% so that is what this test tests...
+%%
+param_query(Ref) ->
+ odbc:param_query(Ref, "select * from test_proc1()",
+ [{sql_integer, out, [111]},
+ {sql_integer, out, [444]}]).
+
+query_result() ->
+ {executed, 2, [{111, 444}]}.
diff --git a/lib/reltool/src/reltool_server.erl b/lib/reltool/src/reltool_server.erl
index 5e25f22a6f..97785ca7f8 100644
--- a/lib/reltool/src/reltool_server.erl
+++ b/lib/reltool/src/reltool_server.erl
@@ -973,7 +973,8 @@ refresh_app(#app{name = AppName,
is_escript = IsEscript,
active_dir = ActiveDir,
label = OptLabel,
- mods = Mods} = App,
+ mods = Mods,
+ status = AppStatus} = App,
Force,
Status) ->
if
@@ -993,6 +994,8 @@ refresh_app(#app{name = AppName,
read_app_info(AppFile,
AppFile,
AppName,
+ ActiveDir,
+ AppStatus,
DefaultVsn,
Status),
@@ -1064,9 +1067,11 @@ refresh_app(#app{name = AppName,
missing_app_info(Vsn) ->
#app_info{vsn = Vsn}.
-read_app_info(_AppFileOrBin, _AppFile, erts, DefaultVsn, Status) ->
+read_app_info(_AppFileOrBin, _AppFile, erts, _ActiveDir, _AppStatus, DefaultVsn, Status) ->
{missing_app_info(DefaultVsn), Status};
-read_app_info(AppFileOrBin, AppFile, AppName, DefaultVsn, Status) ->
+read_app_info(_AppFileOrBin, _AppFile, _AppName, undefined, missing, DefaultVsn, Status) ->
+ {missing_app_info(DefaultVsn), Status};
+read_app_info(AppFileOrBin, AppFile, AppName, _ActiveDir, _AppStatus, DefaultVsn, Status) ->
EnoentText = file:format_error(enoent),
case reltool_utils:prim_consult(AppFileOrBin) of
{ok, [{application, AppName, Info}]} ->
@@ -1080,9 +1085,9 @@ read_app_info(AppFileOrBin, AppFile, AppName, DefaultVsn, Status) ->
Status)};
{error, Text} when Text =:= EnoentText ->
{missing_app_info(DefaultVsn),
- reltool_utils:add_warning("~w: Missing app file ~tp.",
- [AppName,AppFile],
- Status)};
+ reltool_utils:add_warning("~w: Missing app file ~tp.",
+ [AppName,AppFile],
+ Status)};
{error, Text} ->
{missing_app_info(DefaultVsn),
reltool_utils:add_warning("~w: Cannot parse app file ~tp (~tp).",
@@ -1773,13 +1778,15 @@ escripts_to_apps([Escript | Escripts], Apps, Status) ->
get_vsn_from_dir(AppName,AppLabel),
AppFileName =
filename:join([Escript, FullName]),
+ Dir = filename:join([Escript, AppName]),
{Info, StatusAcc2} =
read_app_info(GetBin(),
AppFileName,
AppName,
+ Dir,
+ ok,
DefaultVsn,
Status),
- Dir = filename:join([Escript, AppName]),
{[{AppName, app, Dir, Info} | FileAcc],
StatusAcc2};
E when E =:= Ext ->
@@ -1979,20 +1986,27 @@ refresh_apps(ConfigApps, [New | NewApps], Acc, Force, Status) ->
refresh_apps(_ConfigApps, [], Acc, _Force, Status) ->
{lists:reverse(Acc), Status}.
-
ensure_app_info(#app{is_escript = IsEscript, active_dir = Dir, info = Info},
Status)
when IsEscript=/=false ->
%% Escript or application which is inlined in an escript
{Info, Dir, Status};
-ensure_app_info(#app{name = Name, sorted_dirs = []}, _Status) ->
- reltool_utils:throw_error("~w: : Missing application directory.",[Name]);
+ensure_app_info(#app{name = Name, sorted_dirs = []} = App, Status) ->
+ Reason = "~w: Missing application directory.",
+ case App of
+ #app{incl_cond = exclude, status = missing, active_dir = Dir} ->
+ Status2 = reltool_utils:add_warning(Reason, [Name], Status),
+ {missing_app_info(""), Dir, Status2};
+ _ ->
+ reltool_utils:throw_error(Reason, [Name])
+ end;
ensure_app_info(#app{name = Name,
vsn = Vsn,
use_selected_vsn = UseSelectedVsn,
active_dir = ActiveDir,
sorted_dirs = Dirs,
- info = undefined},
+ info = undefined,
+ status = AppStatus},
Status) ->
ReadInfo =
fun(Dir, StatusAcc) ->
@@ -2000,7 +2014,8 @@ ensure_app_info(#app{name = Name,
Ebin = filename:join([Dir, "ebin"]),
DefaultVsn = get_vsn_from_dir(Name,Base),
AppFile = filename:join([Ebin, atom_to_list(Name) ++ ".app"]),
- read_app_info(AppFile, AppFile, Name, DefaultVsn, StatusAcc)
+ read_app_info(AppFile, AppFile, Name, ActiveDir,
+ AppStatus, DefaultVsn, StatusAcc)
end,
{AllInfo, Status2} = lists:mapfoldl(ReadInfo, Status, Dirs),
AllVsns = [I#app_info.vsn || I <- AllInfo],
diff --git a/lib/reltool/test/reltool_server_SUITE.erl b/lib/reltool/test/reltool_server_SUITE.erl
index 23338d9ecd..adea716e99 100644
--- a/lib/reltool/test/reltool_server_SUITE.erl
+++ b/lib/reltool/test/reltool_server_SUITE.erl
@@ -80,6 +80,8 @@ all() ->
otp_9229_dupl_mod_exclude_app,
otp_9229_dupl_mod_exclude_mod,
dupl_mod_in_app_file,
+ include_non_existing_app,
+ exclude_non_existing_app,
get_apps,
get_mod,
get_sys,
@@ -1313,7 +1315,6 @@ otp_9229_dupl_mod_exclude_mod(Config) ->
ok.
-
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%% Test that if a module is duplicated in a .app file, then a warning
%% is produced, but target can still be created.
@@ -1346,6 +1347,56 @@ dupl_mod_in_app_file(Config) ->
ok.
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%% Test that a reasonable error message is returned if an application
+%% is missing
+include_non_existing_app(_Config) ->
+ %% Configure the server
+ Sys =
+ {sys,
+ [
+ {incl_cond,exclude},
+ {app,foobar,[{incl_cond,include}]},
+ {app,kernel,[{incl_cond,include}]},
+ {app,stdlib,[{incl_cond,include}]},
+ {app,sasl,[{incl_cond,include}]}
+ ]},
+
+ %% Generate target file
+ TargetDir = filename:join([?WORK_DIR, "target_include_non_existing_app"]),
+ ?m(ok, reltool_utils:recursive_delete(TargetDir)),
+ ?m(ok, file:make_dir(TargetDir)),
+ ?log("SPEC: ~p\n", [reltool:get_target_spec([{config, Sys}])]),
+ ?m({error,"foobar: Missing application directory."},
+ reltool:get_status([{config, Sys}])),
+
+ ok.
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%% Test that if a missing application is explicitly excluded a warning
+%% should be issued.
+exclude_non_existing_app(_Config) ->
+ %% Configure the server
+ Sys =
+ {sys,
+ [
+ {incl_cond,exclude},
+ {app,foobar,[{incl_cond,exclude}]},
+ {app,kernel,[{incl_cond,include}]},
+ {app,stdlib,[{incl_cond,include}]},
+ {app,sasl,[{incl_cond,include}]}
+ ]},
+
+ %% Generate target file
+ TargetDir = filename:join([?WORK_DIR, "target_exclude_non_existing_app"]),
+ ?m(ok, reltool_utils:recursive_delete(TargetDir)),
+ ?m(ok, file:make_dir(TargetDir)),
+ ?log("SPEC: ~p\n", [reltool:get_target_spec([{config, Sys}])]),
+ ?m({ok,["foobar: Missing application directory."]},
+ reltool:get_status([{config, Sys}])),
+
+ ok.
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%% Test the interface used by the GUI:
%% get_app
%% get_apps
diff --git a/lib/snmp/include/.gitignore b/lib/snmp/include/.gitignore
new file mode 100644
index 0000000000..4db987f64a
--- /dev/null
+++ b/lib/snmp/include/.gitignore
@@ -0,0 +1,4 @@
+*.hrl
+!SNMPv2-TC.hrl
+!snmp_tables.hrl
+!snmp_types.hrl
diff --git a/lib/snmp/priv/mibs/.gitignore b/lib/snmp/priv/mibs/.gitignore
index e69de29bb2..a8a0dcec44 100644
--- a/lib/snmp/priv/mibs/.gitignore
+++ b/lib/snmp/priv/mibs/.gitignore
@@ -0,0 +1 @@
+*.bin
diff --git a/lib/snmp/test/snmp_test_data/.gitignore b/lib/snmp/test/snmp_test_data/.gitignore
new file mode 100644
index 0000000000..c7cffa7f6d
--- /dev/null
+++ b/lib/snmp/test/snmp_test_data/.gitignore
@@ -0,0 +1,2 @@
+*.bin
+*.hrl
diff --git a/lib/ssl/doc/src/ssl.xml b/lib/ssl/doc/src/ssl.xml
index e9858a3220..2501db858a 100644
--- a/lib/ssl/doc/src/ssl.xml
+++ b/lib/ssl/doc/src/ssl.xml
@@ -79,6 +79,7 @@
{keyfile, path()} | {password, string()} |
{cacerts, [der_encoded()]} | {cacertfile, path()} |
|{dh, der_encoded()} | {dhfile, path()} | {ciphers, ciphers()} |
+ {user_lookup_fun, {fun(), term()}}, {psk_identity, string()}, {srp_identity, {string(), string()}} |
{ssl_imp, ssl_imp()} | {reuse_sessions, boolean()} | {reuse_session, fun()}
{next_protocols_advertised, [binary()]} |
{client_preferred_next_protocols, client | server, [binary()]}
@@ -123,6 +124,7 @@
{key_exchange(), cipher(), hash()}</c></p>
<p><c>key_exchange() = rsa | dhe_dss | dhe_rsa | dh_anon
+ | psk | dhe_psk | rsa_psk | srp_anon | srp_dss | srp_rsa
</c></p>
<p><c>cipher() = rc4_128 | des_cbc | '3des_ede_cbc'
@@ -134,6 +136,9 @@
<p><c>prf_random() = client_random | server_random
</c></p>
+ <p><c>srp_param_type() = srp_1024 | srp_1536 | srp_2048 | srp_3072
+ | srp_4096 | srp_6144 | srp_8192</c></p>
+
</section>
<section>
@@ -179,13 +184,16 @@
<tag>{ciphers, ciphers()}</tag>
<item>The cipher suites that should be supported. The function
- <c>cipher_suites/0</c> can be used to find all available
- ciphers. Additionally some anonymous cipher 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}) are supported for testing purposes and will
- only work if explicitly enabled by this option and they are supported/enabled
- by the peer also.
+ <c>cipher_suites/0</c> can be used to find all ciphers that are
+ supported by default. <c>cipher_suites(all)</c> may be called
+ to find all available cipher suites.
+ Pre-Shared Key (<url href="http://www.ietf.org/rfc/rfc4279.txt">RFC 4279</url> and
+ <url href="http://www.ietf.org/rfc/rfc5487.txt">RFC 5487</url>),
+ Secure Remote Password (<url href="http://www.ietf.org/rfc/rfc5054.txt">RFC 5054</url>)
+ and anonymous cipher suites only work if explicitly enabled by
+ this option and they are supported/enabled by the peer also.
+ Note that anonymous cipher suites are supported for testing purposes
+ only and should not be used when security matters.
</item>
<tag>{ssl_imp, new | old}</tag>
@@ -195,10 +203,10 @@
<tag>{secure_renegotiate, boolean()}</tag>
<item>Specifies if to reject renegotiation attempt that does
- not live up to RFC 5746. By default secure_renegotiate is
+ not live up to <url href="http://www.ietf.org/rfc/rfc5746.txt">RFC 5746</url>. By default secure_renegotiate is
set to false i.e. secure renegotiation will be used if possible
but it will fallback to unsecure renegotiation if the peer
- does not support RFC 5746.
+ does not support <url href="http://www.ietf.org/rfc/rfc5746.txt">RFC 5746</url>.
</item>
<tag>{depth, integer()}</tag>
@@ -292,6 +300,32 @@ fun(OtpCert :: #'OTPCertificate'{}, Event :: {bad_cert, Reason :: atom()} |
<c>undefined</c> is specified (this is the default), the process
will never go into hibernation.
</item>
+
+ <tag>{user_lookup_fun, {Lookupfun :: fun(), UserState :: term()}}</tag>
+ <item>
+ <p>The lookup fun should be defined as:</p>
+ <code>
+fun(psk, PSKIdentity, UserState :: term()) ->
+ {ok, SharedSecret :: binary()} | error;
+fun(srp, Username, UserState :: term()) ->
+ {ok, {SRPParams :: srp_param_type(), Salt :: binary(), DerivedKey :: binary()}} | error.
+ </code>
+
+ <p>For Pre-Shared Key (PSK) cipher suites, the lookup fun will
+ be called by the client and server to determine the shared
+ secret. When called by the client, PSKIdentity will be set to the
+ hint presented by the server or undefined. When called by the
+ server, PSKIdentity is the identity presented by the client.
+ </p>
+
+ <p>For Secure Remote Password (SRP), the fun will only be used by the server to obtain
+ parameters that it will use to generate its session keys. <c>DerivedKey</c> should be
+ derived according to <url href="http://tools.ietf.org/html/rfc2945#section-3"> RFC 2945</url> and
+ <url href="http://tools.ietf.org/html/rfc5054#section-2.4"> RFC 5054</url>:
+ <c>crypto:sha([Salt, crypto:sha([Username, &lt;&lt;$:&gt;&gt;, Password])]) </c>
+ </p>
+ </item>
+
</taglist>
</section>
@@ -334,6 +368,14 @@ fun(OtpCert :: #'OTPCertificate'{}, Event :: {bad_cert, Reason :: atom()} |
server does not support Next Protocol Negotiation the
connection will be aborted if no default protocol is supplied.</p>
</item>
+
+ <tag>{psk_identity, string()}</tag>
+ <item>Specifies the identity the client presents to the server. The matching secret is
+ found by calling the user_look_fun.
+ </item>
+ <tag>{srp_identity, {Username :: string(), Password :: string()}</tag>
+ <item>Specifies the Username and Password to use to authenticate to the server.
+ </item>
</taglist>
</section>
@@ -396,6 +438,10 @@ fun(OtpCert :: #'OTPCertificate'{}, Event :: {bad_cert, Reason :: atom()} |
using <c>negotiated_next_protocol/1</c> method.
</item>
+ <tag>{psk_identity, string()}</tag>
+ <item>Specifies the server identity hint the server presents to the client.
+ </item>
+
</taglist>
</section>
@@ -427,13 +473,16 @@ fun(OtpCert :: #'OTPCertificate'{}, Event :: {bad_cert, Reason :: atom()} |
<name>cipher_suites(Type) -> ciphers()</name>
<fsummary> Returns a list of supported cipher suites</fsummary>
<type>
- <v>Type = erlang | openssl</v>
+ <v>Type = erlang | openssl | all</v>
</type>
<desc><p>Returns a list of supported cipher suites.
cipher_suites() is equivalent to cipher_suites(erlang).
Type openssl is provided for backwards compatibility with
- old ssl that used openssl.
+ old ssl that used openssl. cipher_suites(all) returns
+ all available cipher suites. The cipher suites not present
+ in cipher_suites(erlang) but in included in cipher_suites(all)
+ will not be used unless explicitly configured by the user.
</p>
</desc>
</func>
@@ -821,7 +870,6 @@ fun(OtpCert :: #'OTPCertificate'{}, Event :: {bad_cert, Reason :: atom()} |
</desc>
</func>
-
</funcs>
<section>
diff --git a/lib/ssl/src/Makefile b/lib/ssl/src/Makefile
index e61f415c84..d3ba76d34e 100644
--- a/lib/ssl/src/Makefile
+++ b/lib/ssl/src/Makefile
@@ -50,6 +50,7 @@ MODULES= \
ssl_certificate\
ssl_certificate_db\
ssl_cipher \
+ ssl_srp_primes \
ssl_connection \
ssl_connection_sup \
ssl_handshake \
@@ -65,7 +66,7 @@ MODULES= \
INTERNAL_HRL_FILES = \
ssl_alert.hrl ssl_cipher.hrl ssl_handshake.hrl ssl_internal.hrl \
- ssl_record.hrl
+ ssl_record.hrl ssl_srp.hrl ssl_srp_primes.hrl
ERL_FILES= \
$(MODULES:%=%.erl) \
diff --git a/lib/ssl/src/ssl.app.src b/lib/ssl/src/ssl.app.src
index 897a097f73..5c34de905e 100644
--- a/lib/ssl/src/ssl.app.src
+++ b/lib/ssl/src/ssl.app.src
@@ -20,6 +20,7 @@
ssl_connection_sup,
ssl_connection,
ssl_cipher,
+ ssl_srp_primes,
ssl_certificate_db,
ssl_certificate,
ssl_alert
diff --git a/lib/ssl/src/ssl.erl b/lib/ssl/src/ssl.erl
index fc06b5f1b0..70f3b4f050 100644
--- a/lib/ssl/src/ssl.erl
+++ b/lib/ssl/src/ssl.erl
@@ -37,6 +37,7 @@
-include("ssl_record.hrl").
-include("ssl_cipher.hrl").
-include("ssl_handshake.hrl").
+-include("ssl_srp_primes.hrl").
-include_lib("public_key/include/public_key.hrl").
@@ -65,6 +66,9 @@
{cert, Der::binary()} | {certfile, path()} | {key, Der::binary()} |
{keyfile, path()} | {password, string()} | {cacerts, [Der::binary()]} |
{cacertfile, path()} | {dh, Der::binary()} | {dhfile, path()} |
+ {user_lookup_fun, {fun(), InitialUserState::term()}} |
+ {psk_identity, string()} |
+ {srp_identity, {string(), string()}} |
{ciphers, ciphers()} | {ssl_imp, ssl_imp()} | {reuse_sessions, boolean()} |
{reuse_session, fun()} | {hibernate_after, integer()|undefined} |
{next_protocols_advertised, list(binary())} |
@@ -351,7 +355,7 @@ negotiated_next_protocol(#sslsocket{pid = Pid}) ->
ssl_connection:negotiated_next_protocol(Pid).
-spec cipher_suites() -> [erl_cipher_suite()].
--spec cipher_suites(erlang | openssl) -> [erl_cipher_suite()] | [string()].
+-spec cipher_suites(erlang | openssl | all ) -> [erl_cipher_suite()] | [string()].
%% Description: Returns all supported cipher suites.
%%--------------------------------------------------------------------
@@ -364,8 +368,15 @@ cipher_suites(erlang) ->
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 <- ssl_cipher:suites(Version)];
+cipher_suites(all) ->
+ Version = ssl_record:highest_protocol_version([]),
+ Supported = ssl_cipher:suites(Version)
+ ++ ssl_cipher:anonymous_suites()
+ ++ ssl_cipher:psk_suites(Version)
+ ++ ssl_cipher:srp_suites(),
+ [suite_definition(S) || S <- Supported].
%%--------------------------------------------------------------------
-spec getopts(#sslsocket{}, [gen_tcp:option_name()]) ->
{ok, [gen_tcp:option()]} | {error, reason()}.
@@ -635,6 +646,9 @@ handle_options(Opts0, _Role) ->
cacertfile = handle_option(cacertfile, Opts, CaCertDefault),
dh = handle_option(dh, Opts, undefined),
dhfile = handle_option(dhfile, Opts, undefined),
+ user_lookup_fun = handle_option(user_lookup_fun, Opts, undefined),
+ psk_identity = handle_option(psk_identity, Opts, undefined),
+ srp_identity = handle_option(srp_identity, Opts, undefined),
ciphers = handle_option(ciphers, Opts, []),
%% Server side option
reuse_session = handle_option(reuse_session, Opts, ReuseSessionFun),
@@ -654,7 +668,8 @@ handle_options(Opts0, _Role) ->
SslOptions = [versions, verify, verify_fun,
fail_if_no_peer_cert, verify_client_once,
depth, cert, certfile, key, keyfile,
- password, cacerts, cacertfile, dh, dhfile, ciphers,
+ password, cacerts, cacertfile, dh, dhfile,
+ user_lookup_fun, psk_identity, srp_identity, ciphers,
reuse_session, reuse_sessions, ssl_imp,
cb_info, renegotiate_at, secure_renegotiate, hibernate_after,
erl_dist, next_protocols_advertised,
@@ -756,6 +771,20 @@ validate_option(dhfile, Value) when is_binary(Value) ->
Value;
validate_option(dhfile, Value) when is_list(Value), Value =/= "" ->
list_to_binary(Value);
+validate_option(psk_identity, undefined) ->
+ undefined;
+validate_option(psk_identity, Identity)
+ when is_list(Identity), Identity =/= "", length(Identity) =< 65535 ->
+ list_to_binary(Identity);
+validate_option(user_lookup_fun, undefined) ->
+ undefined;
+validate_option(user_lookup_fun, {Fun, _} = Value) when is_function(Fun, 3) ->
+ Value;
+validate_option(srp_identity, undefined) ->
+ undefined;
+validate_option(srp_identity, {Username, Password})
+ when is_list(Username), is_list(Password), Username =/= "", length(Username) =< 255 ->
+ {list_to_binary(Username), list_to_binary(Password)};
validate_option(ciphers, Value) when is_list(Value) ->
Version = ssl_record:highest_protocol_version([]),
try cipher_suites(Version, Value)
@@ -926,7 +955,10 @@ cipher_suites(Version, [{_,_,_}| _] = Ciphers0) ->
Ciphers = [ssl_cipher:suite(C) || C <- Ciphers0],
cipher_suites(Version, Ciphers);
cipher_suites(Version, [Cipher0 | _] = Ciphers0) when is_binary(Cipher0) ->
- Supported = ssl_cipher:suites(Version) ++ ssl_cipher:anonymous_suites(),
+ Supported = 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
[] ->
Supported;
diff --git a/lib/ssl/src/ssl_alert.erl b/lib/ssl/src/ssl_alert.erl
index 94e95d3cd3..1810043dfb 100644
--- a/lib/ssl/src/ssl_alert.erl
+++ b/lib/ssl/src/ssl_alert.erl
@@ -112,4 +112,6 @@ description_txt(?INTERNAL_ERROR) ->
description_txt(?USER_CANCELED) ->
"user canceled";
description_txt(?NO_RENEGOTIATION) ->
- "no renegotiation".
+ "no renegotiation";
+description_txt(?UNKNOWN_PSK_IDENTITY) ->
+ "unknown psk identity".
diff --git a/lib/ssl/src/ssl_alert.hrl b/lib/ssl/src/ssl_alert.hrl
index 92548edab7..2a8a91aefa 100644
--- a/lib/ssl/src/ssl_alert.hrl
+++ b/lib/ssl/src/ssl_alert.hrl
@@ -60,6 +60,7 @@
%% internal_error(80),
%% user_canceled(90),
%% no_renegotiation(100),
+%% unknown_psk_identity(115),
%% (255)
%% } AlertDescription;
@@ -87,6 +88,7 @@
-define(INTERNAL_ERROR, 80).
-define(USER_CANCELED, 90).
-define(NO_RENEGOTIATION, 100).
+-define(UNKNOWN_PSK_IDENTITY, 115).
-define(ALERT_REC(Level,Desc), #alert{level=Level,description=Desc,where={?FILE, ?LINE}}).
diff --git a/lib/ssl/src/ssl_cipher.erl b/lib/ssl/src/ssl_cipher.erl
index d91e2a89a0..173c53709b 100644
--- a/lib/ssl/src/ssl_cipher.erl
+++ b/lib/ssl/src/ssl_cipher.erl
@@ -34,7 +34,7 @@
-export([security_parameters/3, suite_definition/1,
decipher/5, cipher/5,
- suite/1, suites/1, anonymous_suites/0,
+ suite/1, suites/1, anonymous_suites/0, psk_suites/1, srp_suites/0,
openssl_suite/1, openssl_suite_name/1, filter/2,
hash_algorithm/1, sign_algorithm/1]).
@@ -215,6 +215,56 @@ anonymous_suites() ->
?TLS_DH_anon_WITH_AES_256_CBC_SHA256].
%%--------------------------------------------------------------------
+-spec psk_suites(tls_version()) -> [cipher_suite()].
+%%
+%% Description: Returns a list of the PSK cipher suites, only supported
+%% if explicitly set by user.
+%%--------------------------------------------------------------------
+psk_suites({3, N}) ->
+ psk_suites(N);
+
+psk_suites(N)
+ when N >= 3 ->
+ psk_suites(0) ++
+ [?TLS_DHE_PSK_WITH_AES_256_CBC_SHA384,
+ ?TLS_RSA_PSK_WITH_AES_256_CBC_SHA384,
+ ?TLS_PSK_WITH_AES_256_CBC_SHA384,
+ ?TLS_DHE_PSK_WITH_AES_128_CBC_SHA256,
+ ?TLS_RSA_PSK_WITH_AES_128_CBC_SHA256,
+ ?TLS_PSK_WITH_AES_128_CBC_SHA256];
+
+psk_suites(_) ->
+ [?TLS_DHE_PSK_WITH_AES_256_CBC_SHA,
+ ?TLS_RSA_PSK_WITH_AES_256_CBC_SHA,
+ ?TLS_PSK_WITH_AES_256_CBC_SHA,
+ ?TLS_DHE_PSK_WITH_AES_128_CBC_SHA,
+ ?TLS_RSA_PSK_WITH_AES_128_CBC_SHA,
+ ?TLS_PSK_WITH_AES_128_CBC_SHA,
+ ?TLS_DHE_PSK_WITH_3DES_EDE_CBC_SHA,
+ ?TLS_RSA_PSK_WITH_3DES_EDE_CBC_SHA,
+ ?TLS_PSK_WITH_3DES_EDE_CBC_SHA,
+ ?TLS_DHE_PSK_WITH_RC4_128_SHA,
+ ?TLS_RSA_PSK_WITH_RC4_128_SHA,
+ ?TLS_PSK_WITH_RC4_128_SHA].
+
+%%--------------------------------------------------------------------
+-spec srp_suites() -> [cipher_suite()].
+%%
+%% Description: Returns a list of the SRP cipher suites, only supported
+%% if explicitly set by user.
+%%--------------------------------------------------------------------
+srp_suites() ->
+ [?TLS_SRP_SHA_WITH_3DES_EDE_CBC_SHA,
+ ?TLS_SRP_SHA_RSA_WITH_3DES_EDE_CBC_SHA,
+ ?TLS_SRP_SHA_DSS_WITH_3DES_EDE_CBC_SHA,
+ ?TLS_SRP_SHA_WITH_AES_128_CBC_SHA,
+ ?TLS_SRP_SHA_RSA_WITH_AES_128_CBC_SHA,
+ ?TLS_SRP_SHA_DSS_WITH_AES_128_CBC_SHA,
+ ?TLS_SRP_SHA_WITH_AES_256_CBC_SHA,
+ ?TLS_SRP_SHA_RSA_WITH_AES_256_CBC_SHA,
+ ?TLS_SRP_SHA_DSS_WITH_AES_256_CBC_SHA].
+
+%%--------------------------------------------------------------------
-spec suite_definition(cipher_suite()) -> int_cipher_suite().
%%
%% Description: Return erlang cipher suite definition.
@@ -297,7 +347,84 @@ suite_definition(?TLS_DH_anon_WITH_AES_256_CBC_SHA) ->
suite_definition(?TLS_DH_anon_WITH_AES_128_CBC_SHA256) ->
{dh_anon, aes_128_cbc, sha256, default_prf};
suite_definition(?TLS_DH_anon_WITH_AES_256_CBC_SHA256) ->
- {dh_anon, aes_256_cbc, sha256, default_prf}.
+ {dh_anon, aes_256_cbc, sha256, default_prf};
+
+%%% PSK Cipher Suites RFC 4279
+
+suite_definition(?TLS_PSK_WITH_RC4_128_SHA) ->
+ {psk, rc4_128, sha, default_prf};
+suite_definition(?TLS_PSK_WITH_3DES_EDE_CBC_SHA) ->
+ {psk, '3des_ede_cbc', sha, default_prf};
+suite_definition(?TLS_PSK_WITH_AES_128_CBC_SHA) ->
+ {psk, aes_128_cbc, sha, default_prf};
+suite_definition(?TLS_PSK_WITH_AES_256_CBC_SHA) ->
+ {psk, aes_256_cbc, sha, default_prf};
+suite_definition(?TLS_DHE_PSK_WITH_RC4_128_SHA) ->
+ {dhe_psk, rc4_128, sha, default_prf};
+suite_definition(?TLS_DHE_PSK_WITH_3DES_EDE_CBC_SHA) ->
+ {dhe_psk, '3des_ede_cbc', sha, default_prf};
+suite_definition(?TLS_DHE_PSK_WITH_AES_128_CBC_SHA) ->
+ {dhe_psk, aes_128_cbc, sha, default_prf};
+suite_definition(?TLS_DHE_PSK_WITH_AES_256_CBC_SHA) ->
+ {dhe_psk, aes_256_cbc, sha, default_prf};
+suite_definition(?TLS_RSA_PSK_WITH_RC4_128_SHA) ->
+ {rsa_psk, rc4_128, sha, default_prf};
+suite_definition(?TLS_RSA_PSK_WITH_3DES_EDE_CBC_SHA) ->
+ {rsa_psk, '3des_ede_cbc', sha, default_prf};
+suite_definition(?TLS_RSA_PSK_WITH_AES_128_CBC_SHA) ->
+ {rsa_psk, aes_128_cbc, sha, default_prf};
+suite_definition(?TLS_RSA_PSK_WITH_AES_256_CBC_SHA) ->
+ {rsa_psk, aes_256_cbc, sha, default_prf};
+
+%%% TLS 1.2 PSK Cipher Suites RFC 5487
+
+suite_definition(?TLS_PSK_WITH_AES_128_CBC_SHA256) ->
+ {psk, aes_128_cbc, sha256, default_prf};
+suite_definition(?TLS_PSK_WITH_AES_256_CBC_SHA384) ->
+ {psk, aes_256_cbc, sha384, default_prf};
+suite_definition(?TLS_DHE_PSK_WITH_AES_128_CBC_SHA256) ->
+ {dhe_psk, aes_128_cbc, sha256, default_prf};
+suite_definition(?TLS_DHE_PSK_WITH_AES_256_CBC_SHA384) ->
+ {dhe_psk, aes_256_cbc, sha384, default_prf};
+suite_definition(?TLS_RSA_PSK_WITH_AES_128_CBC_SHA256) ->
+ {rsa_psk, aes_128_cbc, sha256, default_prf};
+suite_definition(?TLS_RSA_PSK_WITH_AES_256_CBC_SHA384) ->
+ {rsa_psk, aes_256_cbc, sha384, default_prf};
+
+suite_definition(?TLS_PSK_WITH_NULL_SHA256) ->
+ {psk, null, sha256, default_prf};
+suite_definition(?TLS_PSK_WITH_NULL_SHA384) ->
+ {psk, null, sha384, default_prf};
+suite_definition(?TLS_DHE_PSK_WITH_NULL_SHA256) ->
+ {dhe_psk, null, sha256, default_prf};
+suite_definition(?TLS_DHE_PSK_WITH_NULL_SHA384) ->
+ {dhe_psk, null, sha384, default_prf};
+suite_definition(?TLS_RSA_PSK_WITH_NULL_SHA256) ->
+ {rsa_psk, null, sha256, default_prf};
+suite_definition(?TLS_RSA_PSK_WITH_NULL_SHA384) ->
+ {rsa_psk, null, sha384, default_prf};
+
+%%% SRP Cipher Suites RFC 5054
+
+suite_definition(?TLS_SRP_SHA_WITH_3DES_EDE_CBC_SHA) ->
+ {srp_anon, '3des_ede_cbc', sha, default_prf};
+suite_definition(?TLS_SRP_SHA_RSA_WITH_3DES_EDE_CBC_SHA) ->
+ {srp_rsa, '3des_ede_cbc', sha, default_prf};
+suite_definition(?TLS_SRP_SHA_DSS_WITH_3DES_EDE_CBC_SHA) ->
+ {srp_dss, '3des_ede_cbc', sha, default_prf};
+suite_definition(?TLS_SRP_SHA_WITH_AES_128_CBC_SHA) ->
+ {srp_anon, aes_128_cbc, sha, default_prf};
+suite_definition(?TLS_SRP_SHA_RSA_WITH_AES_128_CBC_SHA) ->
+ {srp_rsa, aes_128_cbc, sha, default_prf};
+suite_definition(?TLS_SRP_SHA_DSS_WITH_AES_128_CBC_SHA) ->
+ {srp_dss, aes_128_cbc, sha, default_prf};
+suite_definition(?TLS_SRP_SHA_WITH_AES_256_CBC_SHA) ->
+ {srp_anon, aes_256_cbc, sha, default_prf};
+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}.
+
%%--------------------------------------------------------------------
-spec suite(erl_cipher_suite()) -> cipher_suite().
@@ -370,7 +497,83 @@ suite({dhe_rsa, aes_256_cbc, sha256}) ->
suite({dh_anon, aes_128_cbc, sha256}) ->
?TLS_DH_anon_WITH_AES_128_CBC_SHA256;
suite({dh_anon, aes_256_cbc, sha256}) ->
- ?TLS_DH_anon_WITH_AES_256_CBC_SHA256.
+ ?TLS_DH_anon_WITH_AES_256_CBC_SHA256;
+
+%%% PSK Cipher Suites RFC 4279
+
+suite({psk, rc4_128,sha}) ->
+ ?TLS_PSK_WITH_RC4_128_SHA;
+suite({psk, '3des_ede_cbc',sha}) ->
+ ?TLS_PSK_WITH_3DES_EDE_CBC_SHA;
+suite({psk, aes_128_cbc,sha}) ->
+ ?TLS_PSK_WITH_AES_128_CBC_SHA;
+suite({psk, aes_256_cbc,sha}) ->
+ ?TLS_PSK_WITH_AES_256_CBC_SHA;
+suite({dhe_psk, rc4_128,sha}) ->
+ ?TLS_DHE_PSK_WITH_RC4_128_SHA;
+suite({dhe_psk, '3des_ede_cbc',sha}) ->
+ ?TLS_DHE_PSK_WITH_3DES_EDE_CBC_SHA;
+suite({dhe_psk, aes_128_cbc,sha}) ->
+ ?TLS_DHE_PSK_WITH_AES_128_CBC_SHA;
+suite({dhe_psk, aes_256_cbc,sha}) ->
+ ?TLS_DHE_PSK_WITH_AES_256_CBC_SHA;
+suite({rsa_psk, rc4_128,sha}) ->
+ ?TLS_RSA_PSK_WITH_RC4_128_SHA;
+suite({rsa_psk, '3des_ede_cbc',sha}) ->
+ ?TLS_RSA_PSK_WITH_3DES_EDE_CBC_SHA;
+suite({rsa_psk, aes_128_cbc,sha}) ->
+ ?TLS_RSA_PSK_WITH_AES_128_CBC_SHA;
+suite({rsa_psk, aes_256_cbc,sha}) ->
+ ?TLS_RSA_PSK_WITH_AES_256_CBC_SHA;
+
+%%% TLS 1.2 PSK Cipher Suites RFC 5487
+
+suite({psk, aes_128_cbc, sha256}) ->
+ ?TLS_PSK_WITH_AES_128_CBC_SHA256;
+suite({psk, aes_256_cbc, sha384}) ->
+ ?TLS_PSK_WITH_AES_256_CBC_SHA384;
+suite({dhe_psk, aes_128_cbc, sha256}) ->
+ ?TLS_DHE_PSK_WITH_AES_128_CBC_SHA256;
+suite({dhe_psk, aes_256_cbc, sha384}) ->
+ ?TLS_DHE_PSK_WITH_AES_256_CBC_SHA384;
+suite({rsa_psk, aes_128_cbc, sha256}) ->
+ ?TLS_RSA_PSK_WITH_AES_128_CBC_SHA256;
+suite({rsa_psk, aes_256_cbc, sha384}) ->
+ ?TLS_RSA_PSK_WITH_AES_256_CBC_SHA384;
+
+suite({psk, null, sha256}) ->
+ ?TLS_PSK_WITH_NULL_SHA256;
+suite({psk, null, sha384}) ->
+ ?TLS_PSK_WITH_NULL_SHA384;
+suite({dhe_psk, null, sha256}) ->
+ ?TLS_DHE_PSK_WITH_NULL_SHA256;
+suite({dhe_psk, null, sha384}) ->
+ ?TLS_DHE_PSK_WITH_NULL_SHA384;
+suite({rsa_psk, null, sha256}) ->
+ ?TLS_RSA_PSK_WITH_NULL_SHA256;
+suite({rsa_psk, null, sha384}) ->
+ ?TLS_RSA_PSK_WITH_NULL_SHA384;
+
+%%% SRP Cipher Suites RFC 5054
+
+suite({srp_anon, '3des_ede_cbc', sha}) ->
+ ?TLS_SRP_SHA_WITH_3DES_EDE_CBC_SHA;
+suite({srp_rsa, '3des_ede_cbc', sha}) ->
+ ?TLS_SRP_SHA_RSA_WITH_3DES_EDE_CBC_SHA;
+suite({srp_dss, '3des_ede_cbc', sha}) ->
+ ?TLS_SRP_SHA_DSS_WITH_3DES_EDE_CBC_SHA;
+suite({srp_anon, aes_128_cbc, sha}) ->
+ ?TLS_SRP_SHA_WITH_AES_128_CBC_SHA;
+suite({srp_rsa, aes_128_cbc, sha}) ->
+ ?TLS_SRP_SHA_RSA_WITH_AES_128_CBC_SHA;
+suite({srp_dss, aes_128_cbc, sha}) ->
+ ?TLS_SRP_SHA_DSS_WITH_AES_128_CBC_SHA;
+suite({srp_anon, aes_256_cbc, sha}) ->
+ ?TLS_SRP_SHA_WITH_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.
%%--------------------------------------------------------------------
-spec openssl_suite(openssl_cipher_suite()) -> cipher_suite().
@@ -415,7 +618,24 @@ openssl_suite("RC4-MD5") ->
openssl_suite("EDH-RSA-DES-CBC-SHA") ->
?TLS_DHE_RSA_WITH_DES_CBC_SHA;
openssl_suite("DES-CBC-SHA") ->
- ?TLS_RSA_WITH_DES_CBC_SHA.
+ ?TLS_RSA_WITH_DES_CBC_SHA;
+
+%%% SRP Cipher Suites RFC 5054
+
+openssl_suite("SRP-DSS-AES-256-CBC-SHA") ->
+ ?TLS_SRP_SHA_DSS_WITH_AES_256_CBC_SHA;
+openssl_suite("SRP-RSA-AES-256-CBC-SHA") ->
+ ?TLS_SRP_SHA_RSA_WITH_AES_256_CBC_SHA;
+openssl_suite("SRP-DSS-3DES-EDE-CBC-SHA") ->
+ ?TLS_SRP_SHA_DSS_WITH_3DES_EDE_CBC_SHA;
+openssl_suite("SRP-RSA-3DES-EDE-CBC-SHA") ->
+ ?TLS_SRP_SHA_RSA_WITH_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.
+
+
%%--------------------------------------------------------------------
-spec openssl_suite_name(cipher_suite()) -> openssl_cipher_suite().
%%
@@ -469,6 +689,33 @@ openssl_suite_name(?TLS_DHE_DSS_WITH_AES_256_CBC_SHA256) ->
"DHE-DSS-AES256-SHA256";
openssl_suite_name(?TLS_DHE_RSA_WITH_AES_256_CBC_SHA256) ->
"DHE-RSA-AES256-SHA256";
+
+%%% PSK Cipher Suites RFC 4279
+
+openssl_suite_name(?TLS_PSK_WITH_AES_256_CBC_SHA) ->
+ "PSK-AES256-CBC-SHA";
+openssl_suite_name(?TLS_PSK_WITH_3DES_EDE_CBC_SHA) ->
+ "PSK-3DES-EDE-CBC-SHA";
+openssl_suite_name(?TLS_PSK_WITH_AES_128_CBC_SHA) ->
+ "PSK-AES128-CBC-SHA";
+openssl_suite_name(?TLS_PSK_WITH_RC4_128_SHA) ->
+ "PSK-RC4-SHA";
+
+%%% SRP Cipher Suites RFC 5054
+
+openssl_suite_name(?TLS_SRP_SHA_RSA_WITH_3DES_EDE_CBC_SHA) ->
+ "SRP-RSA-3DES-EDE-CBC-SHA";
+openssl_suite_name(?TLS_SRP_SHA_DSS_WITH_3DES_EDE_CBC_SHA) ->
+ "SRP-DSS-3DES-EDE-CBC-SHA";
+openssl_suite_name(?TLS_SRP_SHA_RSA_WITH_AES_128_CBC_SHA) ->
+ "SRP-RSA-AES-128-CBC-SHA";
+openssl_suite_name(?TLS_SRP_SHA_DSS_WITH_AES_128_CBC_SHA) ->
+ "SRP-DSS-AES-128-CBC-SHA";
+openssl_suite_name(?TLS_SRP_SHA_RSA_WITH_AES_256_CBC_SHA) ->
+ "SRP-RSA-AES-256-CBC-SHA";
+openssl_suite_name(?TLS_SRP_SHA_DSS_WITH_AES_256_CBC_SHA) ->
+ "SRP-DSS-AES-256-CBC-SHA";
+
%% No oppenssl name
openssl_suite_name(Cipher) ->
suite_definition(Cipher).
@@ -605,14 +852,14 @@ hash_size(md5) ->
16;
hash_size(sha) ->
20;
+hash_size(sha224) ->
+ 28;
hash_size(sha256) ->
- 32.
-%% Currently no supported cipher suites defaults to sha384 or sha512
-%% so these clauses are not needed at the moment.
-%% hash_size(sha384) ->
-%% 48;
-%% hash_size(sha512) ->
-%% 64.
+ 32;
+hash_size(sha384) ->
+ 48;
+hash_size(sha512) ->
+ 64.
%% RFC 5246: 6.2.3.2. CBC Block Cipher
%%
@@ -702,7 +949,8 @@ next_iv(Bin, IV) ->
NextIV.
rsa_signed_suites() ->
- dhe_rsa_suites() ++ rsa_suites().
+ dhe_rsa_suites() ++ rsa_suites() ++
+ psk_rsa_suites() ++ srp_rsa_suites().
dhe_rsa_suites() ->
[?TLS_DHE_RSA_WITH_AES_256_CBC_SHA256,
@@ -712,6 +960,19 @@ dhe_rsa_suites() ->
?TLS_DHE_RSA_WITH_AES_128_CBC_SHA,
?TLS_DHE_RSA_WITH_DES_CBC_SHA].
+psk_rsa_suites() ->
+ [?TLS_RSA_PSK_WITH_AES_256_CBC_SHA384,
+ ?TLS_RSA_PSK_WITH_AES_128_CBC_SHA256,
+ ?TLS_RSA_PSK_WITH_AES_256_CBC_SHA,
+ ?TLS_RSA_PSK_WITH_AES_128_CBC_SHA,
+ ?TLS_RSA_PSK_WITH_3DES_EDE_CBC_SHA,
+ ?TLS_RSA_PSK_WITH_RC4_128_SHA].
+
+srp_rsa_suites() ->
+ [?TLS_SRP_SHA_RSA_WITH_3DES_EDE_CBC_SHA,
+ ?TLS_SRP_SHA_RSA_WITH_AES_128_CBC_SHA,
+ ?TLS_SRP_SHA_RSA_WITH_AES_256_CBC_SHA].
+
rsa_suites() ->
[?TLS_RSA_WITH_AES_256_CBC_SHA256,
?TLS_RSA_WITH_AES_256_CBC_SHA,
@@ -723,7 +984,7 @@ rsa_suites() ->
?TLS_RSA_WITH_DES_CBC_SHA].
dsa_signed_suites() ->
- dhe_dss_suites().
+ dhe_dss_suites() ++ srp_dss_suites().
dhe_dss_suites() ->
[?TLS_DHE_DSS_WITH_AES_256_CBC_SHA256,
@@ -733,6 +994,11 @@ dhe_dss_suites() ->
?TLS_DHE_DSS_WITH_AES_128_CBC_SHA,
?TLS_DHE_DSS_WITH_3DES_EDE_CBC_SHA].
+srp_dss_suites() ->
+ [?TLS_SRP_SHA_DSS_WITH_3DES_EDE_CBC_SHA,
+ ?TLS_SRP_SHA_DSS_WITH_AES_128_CBC_SHA,
+ ?TLS_SRP_SHA_DSS_WITH_AES_256_CBC_SHA].
+
filter_rsa(OtpCert, RsaCiphers) ->
TBSCert = OtpCert#'OTPCertificate'.tbsCertificate,
TBSExtensions = TBSCert#'OTPTBSCertificate'.extensions,
diff --git a/lib/ssl/src/ssl_cipher.hrl b/lib/ssl/src/ssl_cipher.hrl
index 0f439f8ed5..90d3704efd 100644
--- a/lib/ssl/src/ssl_cipher.hrl
+++ b/lib/ssl/src/ssl_cipher.hrl
@@ -250,4 +250,109 @@
%% hello extension data as they should.
-define(TLS_EMPTY_RENEGOTIATION_INFO_SCSV, <<?BYTE(16#00), ?BYTE(16#FF)>>).
+%%% PSK Cipher Suites RFC 4279
+
+%% TLS_PSK_WITH_RC4_128_SHA = { 0x00, 0x8A };
+-define(TLS_PSK_WITH_RC4_128_SHA, <<?BYTE(16#00), ?BYTE(16#8A)>>).
+
+%% TLS_PSK_WITH_3DES_EDE_CBC_SHA = { 0x00, 0x8B };
+-define(TLS_PSK_WITH_3DES_EDE_CBC_SHA, <<?BYTE(16#00), ?BYTE(16#8B)>>).
+
+%% TLS_PSK_WITH_AES_128_CBC_SHA = { 0x00, 0x8C };
+-define(TLS_PSK_WITH_AES_128_CBC_SHA, <<?BYTE(16#00), ?BYTE(16#8C)>>).
+
+%% TLS_PSK_WITH_AES_256_CBC_SHA = { 0x00, 0x8D };
+-define(TLS_PSK_WITH_AES_256_CBC_SHA, <<?BYTE(16#00), ?BYTE(16#8D)>>).
+
+%% TLS_DHE_PSK_WITH_RC4_128_SHA = { 0x00, 0x8E };
+-define(TLS_DHE_PSK_WITH_RC4_128_SHA, <<?BYTE(16#00), ?BYTE(16#8E)>>).
+
+%% TLS_DHE_PSK_WITH_3DES_EDE_CBC_SHA = { 0x00, 0x8F };
+-define(TLS_DHE_PSK_WITH_3DES_EDE_CBC_SHA, <<?BYTE(16#00), ?BYTE(16#8F)>>).
+
+%% TLS_DHE_PSK_WITH_AES_128_CBC_SHA = { 0x00, 0x90 };
+-define(TLS_DHE_PSK_WITH_AES_128_CBC_SHA, <<?BYTE(16#00), ?BYTE(16#90)>>).
+
+%% TLS_DHE_PSK_WITH_AES_256_CBC_SHA = { 0x00, 0x91 };
+-define(TLS_DHE_PSK_WITH_AES_256_CBC_SHA, <<?BYTE(16#00), ?BYTE(16#91)>>).
+
+%% TLS_RSA_PSK_WITH_RC4_128_SHA = { 0x00, 0x92 };
+-define(TLS_RSA_PSK_WITH_RC4_128_SHA, <<?BYTE(16#00), ?BYTE(16#92)>>).
+
+%% TLS_RSA_PSK_WITH_3DES_EDE_CBC_SHA = { 0x00, 0x93 };
+-define(TLS_RSA_PSK_WITH_3DES_EDE_CBC_SHA, <<?BYTE(16#00), ?BYTE(16#93)>>).
+
+%% TLS_RSA_PSK_WITH_AES_128_CBC_SHA = { 0x00, 0x94 };
+-define(TLS_RSA_PSK_WITH_AES_128_CBC_SHA, <<?BYTE(16#00), ?BYTE(16#94)>>).
+
+%% TLS_RSA_PSK_WITH_AES_256_CBC_SHA = { 0x00, 0x95 };
+-define(TLS_RSA_PSK_WITH_AES_256_CBC_SHA, <<?BYTE(16#00), ?BYTE(16#95)>>).
+
+%%% TLS 1.2 PSK Cipher Suites RFC 5487
+
+%% TLS_PSK_WITH_AES_128_CBC_SHA256 = {0x00,0xAE};
+-define(TLS_PSK_WITH_AES_128_CBC_SHA256, <<?BYTE(16#00), ?BYTE(16#AE)>>).
+
+%% TLS_PSK_WITH_AES_256_CBC_SHA384 = {0x00,0xAF};
+-define(TLS_PSK_WITH_AES_256_CBC_SHA384, <<?BYTE(16#00), ?BYTE(16#AF)>>).
+
+%% TLS_PSK_WITH_NULL_SHA256 = {0x00,0xB0};
+-define(TLS_PSK_WITH_NULL_SHA256, <<?BYTE(16#00), ?BYTE(16#B0)>>).
+
+%% TLS_PSK_WITH_NULL_SHA384 = {0x00,0xB1};
+-define(TLS_PSK_WITH_NULL_SHA384, <<?BYTE(16#00), ?BYTE(16#B1)>>).
+
+%% TLS_DHE_PSK_WITH_AES_128_CBC_SHA256 = {0x00,0xB2};
+-define(TLS_DHE_PSK_WITH_AES_128_CBC_SHA256, <<?BYTE(16#00), ?BYTE(16#B2)>>).
+
+%% TLS_DHE_PSK_WITH_AES_256_CBC_SHA384 = {0x00,0xB3};
+-define(TLS_DHE_PSK_WITH_AES_256_CBC_SHA384, <<?BYTE(16#00), ?BYTE(16#B3)>>).
+
+%% TLS_DHE_PSK_WITH_NULL_SHA256 = {0x00,0xB4};
+-define(TLS_DHE_PSK_WITH_NULL_SHA256, <<?BYTE(16#00), ?BYTE(16#B4)>>).
+
+%% TLS_DHE_PSK_WITH_NULL_SHA384 = {0x00,0xB5};
+-define(TLS_DHE_PSK_WITH_NULL_SHA384, <<?BYTE(16#00), ?BYTE(16#B5)>>).
+
+%% TLS_RSA_PSK_WITH_AES_128_CBC_SHA256 = {0x00,0xB6};
+-define(TLS_RSA_PSK_WITH_AES_128_CBC_SHA256, <<?BYTE(16#00), ?BYTE(16#B6)>>).
+
+%% TLS_RSA_PSK_WITH_AES_256_CBC_SHA384 = {0x00,0xB7};
+-define(TLS_RSA_PSK_WITH_AES_256_CBC_SHA384, <<?BYTE(16#00), ?BYTE(16#B7)>>).
+
+%% TLS_RSA_PSK_WITH_NULL_SHA256 = {0x00,0xB8};
+-define(TLS_RSA_PSK_WITH_NULL_SHA256, <<?BYTE(16#00), ?BYTE(16#B8)>>).
+
+%% TLS_RSA_PSK_WITH_NULL_SHA384 = {0x00,0xB9};
+-define(TLS_RSA_PSK_WITH_NULL_SHA384, <<?BYTE(16#00), ?BYTE(16#B9)>>).
+
+%%% SRP Cipher Suites RFC 5054
+
+%% TLS_SRP_SHA_WITH_3DES_EDE_CBC_SHA = { 0xC0,0x1A };
+-define(TLS_SRP_SHA_WITH_3DES_EDE_CBC_SHA, <<?BYTE(16#C0), ?BYTE(16#1A)>>).
+
+%% TLS_SRP_SHA_RSA_WITH_3DES_EDE_CBC_SHA = { 0xC0,0x1B };
+-define(TLS_SRP_SHA_RSA_WITH_3DES_EDE_CBC_SHA, <<?BYTE(16#C0), ?BYTE(16#1B)>>).
+
+%% TLS_SRP_SHA_DSS_WITH_3DES_EDE_CBC_SHA = { 0xC0,0x1C };
+-define(TLS_SRP_SHA_DSS_WITH_3DES_EDE_CBC_SHA, <<?BYTE(16#C0), ?BYTE(16#1C)>>).
+
+%% TLS_SRP_SHA_WITH_AES_128_CBC_SHA = { 0xC0,0x1D };
+-define(TLS_SRP_SHA_WITH_AES_128_CBC_SHA, <<?BYTE(16#C0), ?BYTE(16#1D)>>).
+
+%% TLS_SRP_SHA_RSA_WITH_AES_128_CBC_SHA = { 0xC0,0x1E };
+-define(TLS_SRP_SHA_RSA_WITH_AES_128_CBC_SHA, <<?BYTE(16#C0), ?BYTE(16#1E)>>).
+
+%% TLS_SRP_SHA_DSS_WITH_AES_128_CBC_SHA = { 0xC0,0x1F };
+-define(TLS_SRP_SHA_DSS_WITH_AES_128_CBC_SHA, <<?BYTE(16#C0), ?BYTE(16#1F)>>).
+
+%% TLS_SRP_SHA_WITH_AES_256_CBC_SHA = { 0xC0,0x20 };
+-define(TLS_SRP_SHA_WITH_AES_256_CBC_SHA, <<?BYTE(16#C0), ?BYTE(16#20)>>).
+
+%% TLS_SRP_SHA_RSA_WITH_AES_256_CBC_SHA = { 0xC0,0x21 };
+-define(TLS_SRP_SHA_RSA_WITH_AES_256_CBC_SHA, <<?BYTE(16#C0), ?BYTE(16#21)>>).
+
+%% TLS_SRP_SHA_DSS_WITH_AES_256_CBC_SHA = { 0xC0,0x22 };
+-define(TLS_SRP_SHA_DSS_WITH_AES_256_CBC_SHA, <<?BYTE(16#C0), ?BYTE(16#22)>>).
+
-endif. % -ifdef(ssl_cipher).
diff --git a/lib/ssl/src/ssl_connection.erl b/lib/ssl/src/ssl_connection.erl
index 4f241ecc0a..1843377582 100644
--- a/lib/ssl/src/ssl_connection.erl
+++ b/lib/ssl/src/ssl_connection.erl
@@ -34,6 +34,8 @@
-include("ssl_record.hrl").
-include("ssl_cipher.hrl").
-include("ssl_internal.hrl").
+-include("ssl_srp.hrl").
+-include("ssl_srp_primes.hrl").
-include_lib("public_key/include/public_key.hrl").
%% Internal application API
@@ -80,6 +82,9 @@
private_key, % PKIX: #'RSAPrivateKey'{}
diffie_hellman_params, % PKIX: #'DHParameter'{} relevant for server side
diffie_hellman_keys, % {PublicKey, PrivateKey}
+ psk_identity, % binary() - server psk identity hint
+ srp_params, % #srp_user{}
+ srp_keys, % {PublicKey, PrivateKey}
premaster_secret, %
file_ref_db, % ets()
cert_db_ref, % ref()
@@ -528,7 +533,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 == dh_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
#state{} = State1 ->
{Record, State} = next_record(State1),
@@ -545,6 +552,45 @@ certify(#certificate_request{}, State0) ->
{Record, State} = next_record(State0#state{client_certificate_requested = true}),
next_state(certify, certify, Record, State);
+%% PSK and RSA_PSK might bypass the Server-Key-Exchange
+certify(#server_hello_done{},
+ #state{session = #session{master_secret = undefined},
+ negotiated_version = Version,
+ psk_identity = PSKIdentity,
+ premaster_secret = undefined,
+ role = client,
+ key_algorithm = Alg} = State0)
+ when Alg == psk ->
+ case server_psk_master_secret(PSKIdentity, State0) of
+ #state{} = State ->
+ client_certify_and_key_exchange(State);
+ #alert{} = Alert ->
+ handle_own_alert(Alert, Version, certify, State0)
+ end;
+
+certify(#server_hello_done{},
+ #state{session = #session{master_secret = undefined},
+ ssl_options = SslOpts,
+ negotiated_version = Version,
+ psk_identity = PSKIdentity,
+ premaster_secret = undefined,
+ role = client,
+ key_algorithm = Alg} = State0)
+ when Alg == rsa_psk ->
+ case handle_psk_identity(PSKIdentity, SslOpts#ssl_options.user_lookup_fun) of
+ {ok, PSK} when is_binary(PSK) ->
+ PremasterSecret = make_premaster_secret(Version, rsa),
+ Len = byte_size(PSK),
+ RealPMS = <<?UINT16(48), PremasterSecret/binary, ?UINT16(Len), PSK/binary>>,
+ State1 = State0#state{premaster_secret = PremasterSecret},
+ State = master_from_premaster_secret(RealPMS, State1),
+ client_certify_and_key_exchange(State);
+ #alert{} = Alert ->
+ Alert;
+ _ ->
+ ?ALERT_REC(?FATAL, ?ILLEGAL_PARAMETER)
+ end;
+
%% Master secret was determined with help of server-key exchange msg
certify(#server_hello_done{},
#state{session = #session{master_secret = MasterSecret} = Session,
@@ -631,6 +677,60 @@ certify_client_key_exchange(#client_diffie_hellman_public{dh_public = ClientPubl
next_state(certify, cipher, Record, State);
#alert{} = Alert ->
handle_own_alert(Alert, Version, certify, State0)
+ end;
+
+certify_client_key_exchange(#client_psk_identity{identity = ClientPSKIdentity},
+ #state{negotiated_version = Version} = State0) ->
+ case server_psk_master_secret(ClientPSKIdentity, 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_dhe_psk_identity{
+ identity = ClientPSKIdentity,
+ dh_public = ClientPublicDhKey},
+ #state{negotiated_version = Version,
+ 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
+ #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_rsa_psk_identity{
+ identity = PskIdentity,
+ exchange_keys =
+ #encrypted_premaster_secret{premaster_secret= EncPMS}},
+ #state{negotiated_version = Version,
+ private_key = Key} = State0) ->
+ PremasterSecret = ssl_handshake:decrypt_premaster_secret(EncPMS, Key),
+ case server_rsa_psk_master_secret(PskIdentity, PremasterSecret, 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_srp_public{srp_a = ClientPublicKey},
+ #state{negotiated_version = Version,
+ srp_params =
+ #srp_user{prime = Prime,
+ verifier = Verifier}
+ } = State0) ->
+ case server_srp_master_secret(Verifier, Prime, ClientPublicKey, 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.
%%--------------------------------------------------------------------
@@ -1446,7 +1546,8 @@ server_hello_done(#state{transport_cb = Transport,
State#state{connection_states = ConnectionStates,
tls_handshake_history = Handshake}.
-certify_server(#state{key_algorithm = dh_anon} = State) ->
+certify_server(#state{key_algorithm = Algo} = State)
+ when Algo == dh_anon; Algo == psk; Algo == dhe_psk ->
State;
certify_server(#state{transport_cb = Transport,
@@ -1501,6 +1602,128 @@ key_exchange(#state{role = server, key_algorithm = Algo,
diffie_hellman_keys = Keys,
tls_handshake_history = Handshake};
+key_exchange(#state{role = server, key_algorithm = psk,
+ ssl_options = #ssl_options{psk_identity = undefined}} = State) ->
+ State;
+key_exchange(#state{role = server, key_algorithm = psk,
+ ssl_options = #ssl_options{psk_identity = PskIdentityHint},
+ hashsign_algorithm = HashSignAlgo,
+ private_key = PrivateKey,
+ connection_states = ConnectionStates0,
+ negotiated_version = Version,
+ tls_handshake_history = Handshake0,
+ socket = Socket,
+ transport_cb = Transport
+ } = 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, {psk, PskIdentityHint,
+ HashSignAlgo, ClientRandom,
+ ServerRandom,
+ PrivateKey}),
+ {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 = server, key_algorithm = dhe_psk,
+ ssl_options = #ssl_options{psk_identity = PskIdentityHint},
+ hashsign_algorithm = HashSignAlgo,
+ diffie_hellman_params = #'DHParameter'{prime = P, base = G} = Params,
+ private_key = PrivateKey,
+ connection_states = ConnectionStates0,
+ negotiated_version = Version,
+ tls_handshake_history = Handshake0,
+ socket = Socket,
+ transport_cb = Transport
+ } = State) ->
+ Keys = crypto:dh_generate_key([crypto:mpint(P), crypto:mpint(G)]),
+ 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,
+ HashSignAlgo, ClientRandom,
+ ServerRandom,
+ PrivateKey}),
+ {BinMsg, ConnectionStates, Handshake} =
+ encode_handshake(Msg, Version, ConnectionStates0, Handshake0),
+ Transport:send(Socket, BinMsg),
+ State#state{connection_states = ConnectionStates,
+ diffie_hellman_keys = Keys,
+ tls_handshake_history = Handshake};
+
+key_exchange(#state{role = server, key_algorithm = rsa_psk,
+ ssl_options = #ssl_options{psk_identity = undefined}} = State) ->
+ State;
+key_exchange(#state{role = server, key_algorithm = rsa_psk,
+ ssl_options = #ssl_options{psk_identity = PskIdentityHint},
+ hashsign_algorithm = HashSignAlgo,
+ private_key = PrivateKey,
+ connection_states = ConnectionStates0,
+ negotiated_version = Version,
+ tls_handshake_history = Handshake0,
+ socket = Socket,
+ transport_cb = Transport
+ } = 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, {psk, PskIdentityHint,
+ HashSignAlgo, ClientRandom,
+ ServerRandom,
+ PrivateKey}),
+ {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 = server, key_algorithm = Algo,
+ ssl_options = #ssl_options{user_lookup_fun = LookupFun},
+ hashsign_algorithm = HashSignAlgo,
+ session = #session{srp_username = Username},
+ private_key = PrivateKey,
+ connection_states = ConnectionStates0,
+ negotiated_version = Version,
+ tls_handshake_history = Handshake0,
+ socket = Socket,
+ transport_cb = Transport
+ } = State)
+ when Algo == srp_dss;
+ Algo == srp_rsa;
+ Algo == srp_anon ->
+ SrpParams = handle_srp_identity(Username, LookupFun),
+ Keys = case generate_srp_server_keys(SrpParams, 0) of
+ Alert = #alert{} ->
+ throw(Alert);
+ Keys0 = {_,_} ->
+ Keys0
+ end,
+ 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, {srp, Keys, SrpParams,
+ HashSignAlgo, ClientRandom,
+ ServerRandom,
+ PrivateKey}),
+ {BinMsg, ConnectionStates, Handshake} =
+ encode_handshake(Msg, Version, ConnectionStates0, Handshake0),
+ Transport:send(Socket, BinMsg),
+ State#state{connection_states = ConnectionStates,
+ srp_params = SrpParams,
+ srp_keys = Keys,
+ tls_handshake_history = Handshake};
+
key_exchange(#state{role = client,
connection_states = ConnectionStates0,
key_algorithm = rsa,
@@ -1530,6 +1753,68 @@ key_exchange(#state{role = client,
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,
+ negotiated_version = Version,
+ socket = Socket, transport_cb = Transport,
+ tls_handshake_history = Handshake0} = State) ->
+ Msg = ssl_handshake:key_exchange(client, Version, {psk, SslOpts#ssl_options.psk_identity}),
+ {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 = dhe_psk,
+ negotiated_version = Version,
+ diffie_hellman_keys = {DhPubKey, _},
+ socket = Socket, transport_cb = Transport,
+ tls_handshake_history = Handshake0} = State) ->
+ Msg = ssl_handshake:key_exchange(client, Version, {dhe_psk, SslOpts#ssl_options.psk_identity, DhPubKey}),
+ {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 = rsa_psk,
+ public_key_info = PublicKeyInfo,
+ negotiated_version = Version,
+ premaster_secret = PremasterSecret,
+ socket = Socket, transport_cb = Transport,
+ tls_handshake_history = Handshake0} = State) ->
+ Msg = rsa_psk_key_exchange(Version, SslOpts#ssl_options.psk_identity, PremasterSecret, PublicKeyInfo),
+ {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,
+ connection_states = ConnectionStates0,
+ key_algorithm = Algorithm,
+ negotiated_version = Version,
+ srp_keys = {ClientPubKey, _},
+ socket = Socket, transport_cb = Transport,
+ tls_handshake_history = Handshake0} = State)
+ when Algorithm == srp_dss;
+ Algorithm == srp_rsa;
+ Algorithm == srp_anon ->
+ Msg = ssl_handshake:key_exchange(client, Version, {srp, ClientPubKey}),
+ {BinMsg, ConnectionStates, Handshake} =
+ encode_handshake(Msg, Version, ConnectionStates0, Handshake0),
+ Transport:send(Socket, BinMsg),
+ State#state{connection_states = ConnectionStates,
tls_handshake_history = Handshake}.
rsa_key_exchange(Version, PremasterSecret, PublicKeyInfo = {Algorithm, _, _})
@@ -1548,6 +1833,22 @@ rsa_key_exchange(Version, PremasterSecret, PublicKeyInfo = {Algorithm, _, _})
rsa_key_exchange(_, _, _) ->
throw (?ALERT_REC(?FATAL,?HANDSHAKE_FAILURE)).
+rsa_psk_key_exchange(Version, PskIdentity, PremasterSecret, PublicKeyInfo = {Algorithm, _, _})
+ when Algorithm == ?rsaEncryption;
+ Algorithm == ?md2WithRSAEncryption;
+ Algorithm == ?md5WithRSAEncryption;
+ Algorithm == ?sha1WithRSAEncryption;
+ Algorithm == ?sha224WithRSAEncryption;
+ Algorithm == ?sha256WithRSAEncryption;
+ Algorithm == ?sha384WithRSAEncryption;
+ Algorithm == ?sha512WithRSAEncryption
+ ->
+ ssl_handshake:key_exchange(client, Version,
+ {psk_premaster_secret, PskIdentity, PremasterSecret,
+ PublicKeyInfo});
+rsa_psk_key_exchange(_, _, _, _) ->
+ throw (?ALERT_REC(?FATAL,?HANDSHAKE_FAILURE)).
+
request_client_cert(#state{ssl_options = #ssl_options{verify = verify_peer},
connection_states = ConnectionStates0,
cert_db = CertDbHandle,
@@ -1666,7 +1967,23 @@ verify_server_key(#server_key_params{params = Params,
server_master_secret(#server_dh_params{dh_p = P, dh_g = G, dh_y = ServerPublicDhKey},
State) ->
- dh_master_secret(P, G, ServerPublicDhKey, undefined, State).
+ dh_master_secret(P, G, ServerPublicDhKey, undefined, State);
+
+server_master_secret(#server_psk_params{
+ hint = IdentityHint},
+ State) ->
+ %% store for later use
+ State#state{psk_identity = IdentityHint};
+
+server_master_secret(#server_dhe_psk_params{
+ hint = IdentityHint,
+ dh_params = #server_dh_params{dh_p = P, dh_g = G, dh_y = ServerPublicDhKey}},
+ State) ->
+ dhe_psk_master_secret(IdentityHint, P, G, ServerPublicDhKey, undefined, State);
+
+server_master_secret(#server_srp_params{srp_n = N, srp_g = G, srp_s = S, srp_b = B},
+ State) ->
+ client_srp_master_secret(G, N, S, B, undefined, State).
master_from_premaster_secret(PremasterSecret,
#state{session = Session,
@@ -1696,6 +2013,131 @@ dh_master_secret(PMpint, GMpint, PublicDhKey, PrivateDhKey, State) ->
[PMpint, GMpint]),
master_from_premaster_secret(PremasterSecret, State).
+handle_psk_identity(_PSKIdentity, LookupFun)
+ when LookupFun == undefined ->
+ error;
+handle_psk_identity(PSKIdentity, {Fun, UserState}) ->
+ Fun(psk, PSKIdentity, UserState).
+
+server_psk_master_secret(ClientPSKIdentity,
+ #state{ssl_options = SslOpts} = State) ->
+ case handle_psk_identity(ClientPSKIdentity, SslOpts#ssl_options.user_lookup_fun) of
+ {ok, PSK} when is_binary(PSK) ->
+ Len = byte_size(PSK),
+ PremasterSecret = <<?UINT16(Len), 0:(Len*8), ?UINT16(Len), PSK/binary>>,
+ master_from_premaster_secret(PremasterSecret, State);
+ #alert{} = Alert ->
+ Alert;
+ _ ->
+ ?ALERT_REC(?FATAL, ?ILLEGAL_PARAMETER)
+ 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,
+ State#state{diffie_hellman_keys = Keys});
+
+dhe_psk_master_secret(PSKIdentity, PMpint, GMpint, 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]),
+ DHLen = erlang:byte_size(DHSecret),
+ Len = erlang:byte_size(PSK),
+ PremasterSecret = <<?UINT16(DHLen), DHSecret/binary, ?UINT16(Len), PSK/binary>>,
+ master_from_premaster_secret(PremasterSecret, State);
+ #alert{} = Alert ->
+ Alert;
+ _ ->
+ ?ALERT_REC(?FATAL, ?ILLEGAL_PARAMETER)
+ end.
+
+server_rsa_psk_master_secret(PskIdentity, PremasterSecret,
+ #state{ssl_options = SslOpts} = State) ->
+ case handle_psk_identity(PskIdentity, SslOpts#ssl_options.user_lookup_fun) of
+ {ok, PSK} when is_binary(PSK) ->
+ Len = byte_size(PSK),
+ RealPMS = <<?UINT16(48), PremasterSecret/binary, ?UINT16(Len), PSK/binary>>,
+ master_from_premaster_secret(RealPMS, State);
+ #alert{} = Alert ->
+ Alert;
+ _ ->
+ ?ALERT_REC(?FATAL, ?ILLEGAL_PARAMETER)
+ end.
+
+generate_srp_server_keys(_SrpParams, 10) ->
+ ?ALERT_REC(?FATAL, ?ILLEGAL_PARAMETER);
+generate_srp_server_keys(SrpParams =
+ #srp_user{generator = Generator, prime = Prime,
+ verifier = Verifier}, N) ->
+ case crypto:srp_generate_key(Verifier, Generator, Prime, '6a') of
+ error ->
+ generate_srp_server_keys(SrpParams, N+1);
+ Keys ->
+ Keys
+ end.
+
+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
+ error ->
+ generate_srp_client_keys(Generator, Prime, N+1);
+ Keys ->
+ Keys
+ end.
+
+handle_srp_identity(Username, {Fun, UserState}) ->
+ case Fun(srp, Username, UserState) of
+ {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),
+ #srp_user{generator = Generator, prime = Prime,
+ salt = Salt, verifier = Verifier};
+ #alert{} = Alert ->
+ throw(Alert);
+ _ ->
+ 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
+ error ->
+ ?ALERT_REC(?FATAL, ?ILLEGAL_PARAMETER);
+ PremasterSecret ->
+ master_from_premaster_secret(PremasterSecret, State)
+ end.
+
+client_srp_master_secret(_Generator, _Prime, _Salt, _ServerPub, #alert{} = Alert, _State) ->
+ Alert;
+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) ->
+ 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
+ error ->
+ ?ALERT_REC(?FATAL, ?ILLEGAL_PARAMETER);
+ PremasterSecret ->
+ master_from_premaster_secret(PremasterSecret, State)
+ end;
+ _ ->
+ ?ALERT_REC(?FATAL, ?ILLEGAL_PARAMETER)
+ end.
+
cipher_role(client, Data, Session, #state{connection_states = ConnectionStates0} = State) ->
ConnectionStates = ssl_record:set_server_verify_data(current_both, Data, ConnectionStates0),
next_state_connection(cipher, ack_connection(State#state{session = Session,
@@ -2495,19 +2937,26 @@ default_hashsign(_Version = {Major, Minor}, KeyExchange)
when Major == 3 andalso Minor >= 3 andalso
(KeyExchange == rsa orelse
KeyExchange == dhe_rsa orelse
- KeyExchange == dh_rsa) ->
+ KeyExchange == dh_rsa orelse
+ KeyExchange == srp_rsa) ->
{sha, rsa};
default_hashsign(_Version, KeyExchange)
when KeyExchange == rsa;
KeyExchange == dhe_rsa;
- KeyExchange == dh_rsa ->
+ KeyExchange == dh_rsa;
+ KeyExchange == srp_rsa ->
{md5sha, rsa};
default_hashsign(_Version, KeyExchange)
when KeyExchange == dhe_dss;
- KeyExchange == dh_dss ->
+ KeyExchange == dh_dss;
+ KeyExchange == srp_dss ->
{sha, dsa};
default_hashsign(_Version, KeyExchange)
- when KeyExchange == dh_anon ->
+ when KeyExchange == dh_anon;
+ KeyExchange == psk;
+ KeyExchange == dhe_psk;
+ KeyExchange == rsa_psk;
+ KeyExchange == srp_anon ->
{null, anon}.
start_or_recv_cancel_timer(infinity, _RecvFrom) ->
diff --git a/lib/ssl/src/ssl_handshake.erl b/lib/ssl/src/ssl_handshake.erl
index 889d310ca8..83c0092de2 100644
--- a/lib/ssl/src/ssl_handshake.erl
+++ b/lib/ssl/src/ssl_handshake.erl
@@ -28,6 +28,7 @@
-include("ssl_cipher.hrl").
-include("ssl_alert.hrl").
-include("ssl_internal.hrl").
+-include("ssl_srp.hrl").
-include_lib("public_key/include/public_key.hrl").
-export([master_secret/4, client_hello/8, server_hello/5, hello/4,
@@ -65,6 +66,7 @@ client_hello(Host, Port, ConnectionStates,
Pending = ssl_record:pending_connection_state(ConnectionStates, read),
SecParams = Pending#connection_state.security_parameters,
Ciphers = available_suites(UserSuites, Version),
+ SRP = srp_user(SslOpts),
Id = ssl_session:client_id({Host, Port, SslOpts}, Cache, CacheCb, OwnCert),
@@ -76,6 +78,7 @@ client_hello(Host, Port, ConnectionStates,
renegotiation_info =
renegotiation_info(client, ConnectionStates, Renegotiation),
+ srp = SRP,
hash_signs = default_hash_signs(),
next_protocol_negotiation =
encode_client_protocol_negotiation(SslOpts#ssl_options.next_protocol_selector, Renegotiation)
@@ -162,7 +165,8 @@ hello(#server_hello{cipher_suite = CipherSuite, server_version = Version,
hello(#client_hello{client_version = ClientVersion, random = Random,
cipher_suites = CipherSuites,
- renegotiation_info = Info} = Hello,
+ renegotiation_info = Info,
+ srp = SRP} = Hello,
#ssl_options{versions = Versions,
secure_renegotiate = SecureRenegotation} = SslOpts,
{Port, Session0, Cache, CacheCb, ConnectionStates0, Cert}, Renegotiation) ->
@@ -171,13 +175,14 @@ hello(#client_hello{client_version = ClientVersion, random = Random,
case ssl_record:is_acceptable_version(Version, Versions) of
true ->
{Type, #session{cipher_suite = CipherSuite,
- compression_method = Compression} = Session}
+ compression_method = Compression} = 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
@@ -372,6 +377,10 @@ certificate_request(ConnectionStates, CertDbHandle, CertDbRef) ->
{premaster_secret, binary(), public_key_info()} |
{dh, binary()} |
{dh, {binary(), binary()}, #'DHParameter'{}, {HashAlgo::atom(), SignAlgo::atom()},
+ binary(), binary(), private_key()} |
+ {psk, binary()} |
+ {dhe_psk, binary(), binary()} |
+ {srp, {binary(), binary()}, #srp_user{}, {HashAlgo::atom(), SignAlgo::atom()},
binary(), binary(), private_key()}) ->
#client_key_exchange{} | #server_key_exchange{}.
%%
@@ -388,6 +397,33 @@ key_exchange(client, _Version, {dh, <<?UINT32(Len), PublicKey:Len/binary>>}) ->
dh_public = PublicKey}
};
+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>>}) ->
+ #client_key_exchange{
+ exchange_keys = #client_dhe_psk_identity{
+ identity = Identity,
+ dh_public = PublicKey}
+ };
+
+key_exchange(client, _Version, {psk_premaster_secret, PskIdentity, Secret, {_, PublicKey, _}}) ->
+ EncPremasterSecret =
+ encrypted_premaster_secret(Secret, PublicKey),
+ #client_key_exchange{
+ exchange_keys = #client_rsa_psk_identity{
+ identity = PskIdentity,
+ exchange_keys = EncPremasterSecret}};
+
+key_exchange(client, _Version, {srp, PublicKey}) ->
+ #client_key_exchange{
+ exchange_keys = #client_srp_public{
+ srp_a = PublicKey}
+ };
+
key_exchange(server, Version, {dh, {<<?UINT32(Len), PublicKey:Len/binary>>, _},
#'DHParameter'{prime = P, base = G},
HashSign, ClientRandom, ServerRandom, PrivateKey}) ->
@@ -396,6 +432,34 @@ key_exchange(server, Version, {dh, {<<?UINT32(Len), PublicKey:Len/binary>>, _},
ServerDHParams = #server_dh_params{dh_p = PBin,
dh_g = GBin, dh_y = PublicKey},
enc_server_key_exchange(Version, ServerDHParams, 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>>, _},
+ #'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}
+ },
+ enc_server_key_exchange(Version, ServerEDHPSKParams,
+ HashSign, ClientRandom, ServerRandom, PrivateKey);
+
+key_exchange(server, Version, {srp, {PublicKey, _},
+ #srp_user{generator = Generator, prime = Prime,
+ salt = Salt},
+ HashSign, ClientRandom, ServerRandom, PrivateKey}) ->
+ ServerSRPParams = #server_srp_params{srp_n = Prime, srp_g = Generator,
+ srp_s = Salt, srp_b = PublicKey},
+ enc_server_key_exchange(Version, ServerSRPParams, HashSign,
ClientRandom, ServerRandom, PrivateKey).
enc_server_key_exchange(Version, Params, {HashAlgo, SignAlgo},
@@ -525,7 +589,12 @@ get_tls_handshake(Version, Data, Buffer) ->
%%--------------------------------------------------------------------
-spec decode_client_key(binary(), key_algo(), tls_version()) ->
- #encrypted_premaster_secret{} | #client_diffie_hellman_public{}.
+ #encrypted_premaster_secret{}
+ | #client_diffie_hellman_public{}
+ | #client_psk_identity{}
+ | #client_dhe_psk_identity{}
+ | #client_rsa_psk_identity{}
+ | #client_srp_public{}.
%%
%% Description: Decode client_key data and return appropriate type
%%--------------------------------------------------------------------
@@ -677,6 +746,11 @@ cipher_suites(Suites, false) ->
cipher_suites(Suites, true) ->
Suites.
+srp_user(#ssl_options{srp_identity = {UserName, _}}) ->
+ #srp{username = UserName};
+srp_user(_) ->
+ undefined.
+
renegotiation_info(client, _, false) ->
#renegotiation_info{renegotiated_connection = undefined};
renegotiation_info(server, ConnectionStates, false) ->
@@ -759,6 +833,11 @@ 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}.
+
handle_renegotiation_info(_, #renegotiation_info{renegotiated_connection = ?byte(0)},
ConnectionStates, false, _, _) ->
{ok, ssl_record:set_renegotiation_flag(true, ConnectionStates)};
@@ -941,6 +1020,7 @@ dec_hs(_Version, ?CLIENT_HELLO, <<?BYTE(Major), ?BYTE(Minor), Random:32/binary,
DecodedExtensions = dec_hello_extensions(Extensions),
RenegotiationInfo = proplists:get_value(renegotiation_info, DecodedExtensions, undefined),
+ SRP = proplists:get_value(srp, DecodedExtensions, undefined),
HashSigns = proplists:get_value(hash_signs, DecodedExtensions, undefined),
NextProtocolNegotiation = proplists:get_value(next_protocol_negotiation, DecodedExtensions, undefined),
@@ -951,6 +1031,7 @@ dec_hs(_Version, ?CLIENT_HELLO, <<?BYTE(Major), ?BYTE(Minor), Random:32/binary,
cipher_suites = from_2bytes(CipherSuites),
compression_methods = Comp_methods,
renegotiation_info = RenegotiationInfo,
+ srp = SRP,
hash_signs = HashSigns,
next_protocol_negotiation = NextProtocolNegotiation
};
@@ -1029,7 +1110,23 @@ dec_client_key(<<>>, ?KEY_EXCHANGE_DIFFIE_HELLMAN, _) ->
throw(?ALERT_REC(?FATAL, ?UNSUPPORTED_CERTIFICATE));
dec_client_key(<<?UINT16(DH_YLen), DH_Y:DH_YLen/binary>>,
?KEY_EXCHANGE_DIFFIE_HELLMAN, _) ->
- #client_diffie_hellman_public{dh_public = DH_Y}.
+ #client_diffie_hellman_public{dh_public = DH_Y};
+dec_client_key(<<?UINT16(Len), Id:Len/binary>>,
+ ?KEY_EXCHANGE_PSK, _) ->
+ #client_psk_identity{identity = Id};
+dec_client_key(<<?UINT16(Len), Id:Len/binary,
+ ?UINT16(DH_YLen), DH_Y:DH_YLen/binary>>,
+ ?KEY_EXCHANGE_DHE_PSK, _) ->
+ #client_dhe_psk_identity{identity = Id, dh_public = DH_Y};
+dec_client_key(<<?UINT16(Len), Id:Len/binary, PKEPMS/binary>>,
+ ?KEY_EXCHANGE_RSA_PSK, {3, 0}) ->
+ #client_rsa_psk_identity{identity = Id, exchange_keys = #encrypted_premaster_secret{premaster_secret = PKEPMS}};
+dec_client_key(<<?UINT16(Len), Id:Len/binary, ?UINT16(_), PKEPMS/binary>>,
+ ?KEY_EXCHANGE_RSA_PSK, _) ->
+ #client_rsa_psk_identity{identity = Id, exchange_keys = #encrypted_premaster_secret{premaster_secret = PKEPMS}};
+dec_client_key(<<?UINT16(ALen), A:ALen/binary>>,
+ ?KEY_EXCHANGE_SRP, _) ->
+ #client_srp_public{srp_a = A}.
dec_ske_params(Len, Keys, Version) ->
<<Params:Len/bytes, Signature/binary>> = Keys,
@@ -1064,6 +1161,41 @@ dec_server_key(<<?UINT16(PLen), P:PLen/binary,
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 ->
+ Params = #server_psk_params{
+ hint = PskIdentityHint},
+ {BinMsg, HashSign, Signature} = dec_ske_params(Len + 2, KeyStruct, Version),
+ #server_key_params{params = Params,
+ params_bin = BinMsg,
+ hashsign = HashSign,
+ signature = Signature};
+dec_server_key(<<?UINT16(Len), IdentityHint:Len/binary,
+ ?UINT16(PLen), P:PLen/binary,
+ ?UINT16(GLen), G:GLen/binary,
+ ?UINT16(YLen), Y:YLen/binary, _/binary>> = KeyStruct,
+ ?KEY_EXCHANGE_DHE_PSK, Version) ->
+ DHParams = #server_dh_params{dh_p = P, dh_g = G, dh_y = Y},
+ Params = #server_dhe_psk_params{
+ hint = IdentityHint,
+ dh_params = DHParams},
+ {BinMsg, HashSign, Signature} = dec_ske_params(Len + PLen + GLen + YLen + 8, KeyStruct, Version),
+ #server_key_params{params = Params,
+ params_bin = BinMsg,
+ hashsign = HashSign,
+ signature = Signature};
+dec_server_key(<<?UINT16(NLen), N:NLen/binary,
+ ?UINT16(GLen), G:GLen/binary,
+ ?BYTE(SLen), S:SLen/binary,
+ ?UINT16(BLen), B:BLen/binary, _/binary>> = KeyStruct,
+ ?KEY_EXCHANGE_SRP, Version) ->
+ Params = #server_srp_params{srp_n = N, srp_g = G, srp_s = S, srp_b = B},
+ {BinMsg, HashSign, Signature} = dec_ske_params(NLen + GLen + SLen + BLen + 7, KeyStruct, Version),
+ #server_key_params{params = Params,
+ params_bin = BinMsg,
+ hashsign = HashSign,
+ signature = Signature};
dec_server_key(_, _, _) ->
throw(?ALERT_REC(?FATAL, ?HANDSHAKE_FAILURE)).
@@ -1091,6 +1223,11 @@ dec_hello_extensions(<<?UINT16(?RENEGOTIATION_EXT), ?UINT16(Len), Info:Len/binar
dec_hello_extensions(Rest, [{renegotiation_info,
#renegotiation_info{renegotiated_connection = RenegotiateInfo}} | Acc]);
+dec_hello_extensions(<<?UINT16(?SRP_EXT), ?UINT16(Len), ?BYTE(SRPLen), SRP:SRPLen/binary, Rest/binary>>, Acc)
+ when Len == SRPLen + 2 ->
+ dec_hello_extensions(Rest, [{srp,
+ #srp{username = SRP}} | Acc]);
+
dec_hello_extensions(<<?UINT16(?SIGNATURE_ALGORITHMS_EXT), ?UINT16(Len),
ExtData:Len/binary, Rest/binary>>, Acc) ->
SignAlgoListLen = Len - 2,
@@ -1148,6 +1285,7 @@ enc_hs(#client_hello{client_version = {Major, Minor},
cipher_suites = CipherSuites,
compression_methods = CompMethods,
renegotiation_info = RenegotiationInfo,
+ srp = SRP,
hash_signs = HashSigns,
next_protocol_negotiation = NextProtocolNegotiation}, _Version) ->
SIDLength = byte_size(SessionID),
@@ -1155,7 +1293,7 @@ enc_hs(#client_hello{client_version = {Major, Minor},
CmLength = byte_size(BinCompMethods),
BinCipherSuites = list_to_binary(CipherSuites),
CsLength = byte_size(BinCipherSuites),
- Extensions0 = hello_extensions(RenegotiationInfo, NextProtocolNegotiation),
+ Extensions0 = hello_extensions(RenegotiationInfo, SRP, NextProtocolNegotiation),
Extensions1 = if
Major == 3, Minor >=3 -> Extensions0 ++ hello_extensions(HashSigns);
true -> Extensions0
@@ -1231,13 +1369,56 @@ enc_cke(#encrypted_premaster_secret{premaster_secret = PKEPMS}, _) ->
<<?UINT16(PKEPMSLen), PKEPMS/binary>>;
enc_cke(#client_diffie_hellman_public{dh_public = DHPublic}, _) ->
Len = byte_size(DHPublic),
- <<?UINT16(Len), DHPublic/binary>>.
+ <<?UINT16(Len), DHPublic/binary>>;
+enc_cke(#client_psk_identity{identity = undefined}, _) ->
+ Id = <<"psk_identity">>,
+ Len = byte_size(Id),
+ <<?UINT16(Len), Id/binary>>;
+enc_cke(#client_psk_identity{identity = Id}, _) ->
+ Len = byte_size(Id),
+ <<?UINT16(Len), Id/binary>>;
+enc_cke(Identity = #client_dhe_psk_identity{identity = undefined}, Version) ->
+ enc_cke(Identity#client_dhe_psk_identity{identity = <<"psk_identity">>}, Version);
+enc_cke(#client_dhe_psk_identity{identity = Id, dh_public = DHPublic}, _) ->
+ Len = byte_size(Id),
+ DHLen = byte_size(DHPublic),
+ <<?UINT16(Len), Id/binary, ?UINT16(DHLen), DHPublic/binary>>;
+enc_cke(Identity = #client_rsa_psk_identity{identity = undefined}, Version) ->
+ enc_cke(Identity#client_rsa_psk_identity{identity = <<"psk_identity">>}, Version);
+enc_cke(#client_rsa_psk_identity{identity = Id, exchange_keys = ExchangeKeys}, Version) ->
+ EncPMS = enc_cke(ExchangeKeys, Version),
+ Len = byte_size(Id),
+ <<?UINT16(Len), Id/binary, EncPMS/binary>>;
+enc_cke(#client_srp_public{srp_a = A}, _) ->
+ Len = byte_size(A),
+ <<?UINT16(Len), A/binary>>.
enc_server_key(#server_dh_params{dh_p = P, dh_g = G, dh_y = Y}) ->
PLen = byte_size(P),
GLen = byte_size(G),
YLen = byte_size(Y),
- <<?UINT16(PLen), P/binary, ?UINT16(GLen), G/binary, ?UINT16(YLen), Y/binary>>.
+ <<?UINT16(PLen), P/binary, ?UINT16(GLen), G/binary, ?UINT16(YLen), Y/binary>>;
+enc_server_key(#server_psk_params{hint = PskIdentityHint}) ->
+ Len = byte_size(PskIdentityHint),
+ <<?UINT16(Len), PskIdentityHint/binary>>;
+enc_server_key(Params = #server_dhe_psk_params{hint = undefined}) ->
+ enc_server_key(Params#server_dhe_psk_params{hint = <<>>});
+enc_server_key(#server_dhe_psk_params{
+ hint = PskIdentityHint,
+ dh_params = #server_dh_params{dh_p = P, dh_g = G, dh_y = Y}}) ->
+ Len = byte_size(PskIdentityHint),
+ PLen = byte_size(P),
+ GLen = byte_size(G),
+ YLen = byte_size(Y),
+ <<?UINT16(Len), PskIdentityHint/binary,
+ ?UINT16(PLen), P/binary, ?UINT16(GLen), G/binary, ?UINT16(YLen), Y/binary>>;
+enc_server_key(#server_srp_params{srp_n = N, srp_g = G, srp_s = S, srp_b = B}) ->
+ NLen = byte_size(N),
+ GLen = byte_size(G),
+ SLen = byte_size(S),
+ BLen = byte_size(B),
+ <<?UINT16(NLen), N/binary, ?UINT16(GLen), G/binary,
+ ?BYTE(SLen), S/binary, ?UINT16(BLen), B/binary>>.
enc_sign({_, anon}, _Sign, _Version) ->
<<>>;
@@ -1253,13 +1434,20 @@ enc_sign(_HashSign, Sign, _Version) ->
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).
+
%% Renegotiation info
hello_extensions(#renegotiation_info{renegotiated_connection = undefined}) ->
[];
hello_extensions(#renegotiation_info{} = Info) ->
[Info];
+hello_extensions(#srp{} = Info) ->
+ [Info];
hello_extensions(#hash_sign_algos{} = Info) ->
- [Info].
+ [Info];
+hello_extensions(undefined) ->
+ [].
next_protocol_extension(undefined) ->
[];
@@ -1286,6 +1474,11 @@ enc_hello_extensions([#renegotiation_info{renegotiated_connection = Info} | Rest
Len = InfoLen +1,
enc_hello_extensions(Rest, <<?UINT16(?RENEGOTIATION_EXT), ?UINT16(Len), ?BYTE(InfoLen), Info/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 >>,
@@ -1395,6 +1588,15 @@ 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(psk) ->
+ ?KEY_EXCHANGE_PSK;
+key_exchange_alg(dhe_psk) ->
+ ?KEY_EXCHANGE_DHE_PSK;
+key_exchange_alg(rsa_psk) ->
+ ?KEY_EXCHANGE_RSA_PSK;
+key_exchange_alg(Alg)
+ when Alg == srp_rsa; Alg == srp_dss; Alg == srp_anon ->
+ ?KEY_EXCHANGE_SRP;
key_exchange_alg(_) ->
?NULL.
diff --git a/lib/ssl/src/ssl_handshake.hrl b/lib/ssl/src/ssl_handshake.hrl
index 2414d5b666..1fbb88f5f6 100644
--- a/lib/ssl/src/ssl_handshake.hrl
+++ b/lib/ssl/src/ssl_handshake.hrl
@@ -48,6 +48,7 @@
compression_method,
cipher_suite,
master_secret,
+ srp_username,
is_resumable,
time_stamp
}).
@@ -99,6 +100,7 @@
cipher_suites, % cipher_suites<2..2^16-1>
compression_methods, % compression_methods<1..2^8-1>,
renegotiation_info,
+ srp, % srp username to send
hash_signs, % supported combinations of hashes/signature algos
next_protocol_negotiation = undefined % [binary()]
}).
@@ -128,6 +130,10 @@
-define(KEY_EXCHANGE_RSA, 0).
-define(KEY_EXCHANGE_DIFFIE_HELLMAN, 1).
+-define(KEY_EXCHANGE_PSK, 2).
+-define(KEY_EXCHANGE_DHE_PSK, 3).
+-define(KEY_EXCHANGE_RSA_PSK, 4).
+-define(KEY_EXCHANGE_SRP, 5).
-record(server_rsa_params, {
rsa_modulus, %% opaque RSA_modulus<1..2^16-1>
@@ -139,7 +145,23 @@
dh_g, %% opaque DH_g<1..2^16-1>
dh_y %% opaque DH_Ys<1..2^16-1>
}).
-
+
+-record(server_psk_params, {
+ hint
+ }).
+
+-record(server_dhe_psk_params, {
+ hint,
+ dh_params
+ }).
+
+-record(server_srp_params, {
+ srp_n, %% opaque srp_N<1..2^16-1>
+ srp_g, %% opaque srp_g<1..2^16-1>
+ srp_s, %% opaque srp_s<1..2^8-1>
+ srp_b %% opaque srp_B<1..2^16-1>
+ }).
+
-record(server_key_exchange, {
exchange_keys
}).
@@ -209,6 +231,24 @@
dh_public
}).
+-record(client_psk_identity, {
+ identity
+ }).
+
+-record(client_dhe_psk_identity, {
+ identity,
+ dh_public
+ }).
+
+-record(client_rsa_psk_identity, {
+ identity,
+ exchange_keys
+ }).
+
+-record(client_srp_public, {
+ srp_a
+ }).
+
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%% Certificate verify - RFC 4346 section 7.4.8
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
@@ -235,6 +275,15 @@
}).
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%% SRP RFC 5054 section 2.8.1.
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+-define(SRP_EXT, 12).
+
+-record(srp, {
+ username
+ }).
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%% Signature Algorithms RFC 5746 section 7.4.1.4.1.
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-define(SIGNATURE_ALGORITHMS_EXT, 13).
diff --git a/lib/ssl/src/ssl_internal.hrl b/lib/ssl/src/ssl_internal.hrl
index ed0dc34adf..96a1c8e1ce 100644
--- a/lib/ssl/src/ssl_internal.hrl
+++ b/lib/ssl/src/ssl_internal.hrl
@@ -90,6 +90,9 @@
cacertfile, % file()
dh, % der_encoded()
dhfile, % file()
+ user_lookup_fun, % server option, fun to lookup the user
+ psk_identity, % binary
+ srp_identity, % client option {User, Password}
ciphers, %
%% Local policy for the server if it want's to reuse the session
%% or not. Defaluts to allways returning true.
diff --git a/lib/ssl/src/ssl_srp.hrl b/lib/ssl/src/ssl_srp.hrl
new file mode 100644
index 0000000000..ab2be33ab2
--- /dev/null
+++ b/lib/ssl/src/ssl_srp.hrl
@@ -0,0 +1,31 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2007-2012. 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
+%% Erlang Public License along with this software. If not, it can be
+%% retrieved online at http://www.erlang.org/.
+%%
+%% Software distributed under the License is distributed on an "AS IS"
+%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+%% the License for the specific language governing rights and limitations
+%% under the License.
+%%
+%% %CopyrightEnd%
+%%
+
+%%
+%%----------------------------------------------------------------------
+%% Purpose: Record definition for the TLS SRP protocol
+%% see RFC 5054
+%%----------------------------------------------------------------------
+
+-record(srp_user, {
+ generator :: binary(),
+ prime :: binary(),
+ salt :: binary(),
+ verifier :: binary()
+ }).
diff --git a/lib/ssl/src/ssl_srp_primes.erl b/lib/ssl/src/ssl_srp_primes.erl
new file mode 100644
index 0000000000..ca20a8d673
--- /dev/null
+++ b/lib/ssl/src/ssl_srp_primes.erl
@@ -0,0 +1,506 @@
+-module(ssl_srp_primes).
+
+-export([get_srp_params/1, check_srp_params/2]).
+
+-define(PRIME_1024, <<16#EE, 16#AF, 16#0A, 16#B9, 16#AD, 16#B3, 16#8D,
+ 16#D6, 16#9C, 16#33, 16#F8, 16#0A, 16#FA, 16#8F,
+ 16#C5, 16#E8, 16#60, 16#72, 16#61, 16#87, 16#75,
+ 16#FF, 16#3C, 16#0B, 16#9E, 16#A2, 16#31, 16#4C,
+ 16#9C, 16#25, 16#65, 16#76, 16#D6, 16#74, 16#DF,
+ 16#74, 16#96, 16#EA, 16#81, 16#D3, 16#38, 16#3B,
+ 16#48, 16#13, 16#D6, 16#92, 16#C6, 16#E0, 16#E0,
+ 16#D5, 16#D8, 16#E2, 16#50, 16#B9, 16#8B, 16#E4,
+ 16#8E, 16#49, 16#5C, 16#1D, 16#60, 16#89, 16#DA,
+ 16#D1, 16#5D, 16#C7, 16#D7, 16#B4, 16#61, 16#54,
+ 16#D6, 16#B6, 16#CE, 16#8E, 16#F4, 16#AD, 16#69,
+ 16#B1, 16#5D, 16#49, 16#82, 16#55, 16#9B, 16#29,
+ 16#7B, 16#CF, 16#18, 16#85, 16#C5, 16#29, 16#F5,
+ 16#66, 16#66, 16#0E, 16#57, 16#EC, 16#68, 16#ED,
+ 16#BC, 16#3C, 16#05, 16#72, 16#6C, 16#C0, 16#2F,
+ 16#D4, 16#CB, 16#F4, 16#97, 16#6E, 16#AA, 16#9A,
+ 16#FD, 16#51, 16#38, 16#FE, 16#83, 16#76, 16#43,
+ 16#5B, 16#9F, 16#C6, 16#1D, 16#2F, 16#C0, 16#EB,
+ 16#06, 16#E3>>).
+-define(GENERATOR_1024, <<2>>).
+
+
+-define(PRIME_1536, <<16#9D, 16#EF, 16#3C, 16#AF, 16#B9, 16#39, 16#27,
+ 16#7A, 16#B1, 16#F1, 16#2A, 16#86, 16#17, 16#A4,
+ 16#7B, 16#BB, 16#DB, 16#A5, 16#1D, 16#F4, 16#99,
+ 16#AC, 16#4C, 16#80, 16#BE, 16#EE, 16#A9, 16#61,
+ 16#4B, 16#19, 16#CC, 16#4D, 16#5F, 16#4F, 16#5F,
+ 16#55, 16#6E, 16#27, 16#CB, 16#DE, 16#51, 16#C6,
+ 16#A9, 16#4B, 16#E4, 16#60, 16#7A, 16#29, 16#15,
+ 16#58, 16#90, 16#3B, 16#A0, 16#D0, 16#F8, 16#43,
+ 16#80, 16#B6, 16#55, 16#BB, 16#9A, 16#22, 16#E8,
+ 16#DC, 16#DF, 16#02, 16#8A, 16#7C, 16#EC, 16#67,
+ 16#F0, 16#D0, 16#81, 16#34, 16#B1, 16#C8, 16#B9,
+ 16#79, 16#89, 16#14, 16#9B, 16#60, 16#9E, 16#0B,
+ 16#E3, 16#BA, 16#B6, 16#3D, 16#47, 16#54, 16#83,
+ 16#81, 16#DB, 16#C5, 16#B1, 16#FC, 16#76, 16#4E,
+ 16#3F, 16#4B, 16#53, 16#DD, 16#9D, 16#A1, 16#15,
+ 16#8B, 16#FD, 16#3E, 16#2B, 16#9C, 16#8C, 16#F5,
+ 16#6E, 16#DF, 16#01, 16#95, 16#39, 16#34, 16#96,
+ 16#27, 16#DB, 16#2F, 16#D5, 16#3D, 16#24, 16#B7,
+ 16#C4, 16#86, 16#65, 16#77, 16#2E, 16#43, 16#7D,
+ 16#6C, 16#7F, 16#8C, 16#E4, 16#42, 16#73, 16#4A,
+ 16#F7, 16#CC, 16#B7, 16#AE, 16#83, 16#7C, 16#26,
+ 16#4A, 16#E3, 16#A9, 16#BE, 16#B8, 16#7F, 16#8A,
+ 16#2F, 16#E9, 16#B8, 16#B5, 16#29, 16#2E, 16#5A,
+ 16#02, 16#1F, 16#FF, 16#5E, 16#91, 16#47, 16#9E,
+ 16#8C, 16#E7, 16#A2, 16#8C, 16#24, 16#42, 16#C6,
+ 16#F3, 16#15, 16#18, 16#0F, 16#93, 16#49, 16#9A,
+ 16#23, 16#4D, 16#CF, 16#76, 16#E3, 16#FE, 16#D1,
+ 16#35, 16#F9, 16#BB>>).
+-define(GENERATOR_1536, <<2>>).
+
+-define(PRIME_2048, <<16#AC, 16#6B, 16#DB, 16#41, 16#32, 16#4A, 16#9A,
+ 16#9B, 16#F1, 16#66, 16#DE, 16#5E, 16#13, 16#89,
+ 16#58, 16#2F, 16#AF, 16#72, 16#B6, 16#65, 16#19,
+ 16#87, 16#EE, 16#07, 16#FC, 16#31, 16#92, 16#94,
+ 16#3D, 16#B5, 16#60, 16#50, 16#A3, 16#73, 16#29,
+ 16#CB, 16#B4, 16#A0, 16#99, 16#ED, 16#81, 16#93,
+ 16#E0, 16#75, 16#77, 16#67, 16#A1, 16#3D, 16#D5,
+ 16#23, 16#12, 16#AB, 16#4B, 16#03, 16#31, 16#0D,
+ 16#CD, 16#7F, 16#48, 16#A9, 16#DA, 16#04, 16#FD,
+ 16#50, 16#E8, 16#08, 16#39, 16#69, 16#ED, 16#B7,
+ 16#67, 16#B0, 16#CF, 16#60, 16#95, 16#17, 16#9A,
+ 16#16, 16#3A, 16#B3, 16#66, 16#1A, 16#05, 16#FB,
+ 16#D5, 16#FA, 16#AA, 16#E8, 16#29, 16#18, 16#A9,
+ 16#96, 16#2F, 16#0B, 16#93, 16#B8, 16#55, 16#F9,
+ 16#79, 16#93, 16#EC, 16#97, 16#5E, 16#EA, 16#A8,
+ 16#0D, 16#74, 16#0A, 16#DB, 16#F4, 16#FF, 16#74,
+ 16#73, 16#59, 16#D0, 16#41, 16#D5, 16#C3, 16#3E,
+ 16#A7, 16#1D, 16#28, 16#1E, 16#44, 16#6B, 16#14,
+ 16#77, 16#3B, 16#CA, 16#97, 16#B4, 16#3A, 16#23,
+ 16#FB, 16#80, 16#16, 16#76, 16#BD, 16#20, 16#7A,
+ 16#43, 16#6C, 16#64, 16#81, 16#F1, 16#D2, 16#B9,
+ 16#07, 16#87, 16#17, 16#46, 16#1A, 16#5B, 16#9D,
+ 16#32, 16#E6, 16#88, 16#F8, 16#77, 16#48, 16#54,
+ 16#45, 16#23, 16#B5, 16#24, 16#B0, 16#D5, 16#7D,
+ 16#5E, 16#A7, 16#7A, 16#27, 16#75, 16#D2, 16#EC,
+ 16#FA, 16#03, 16#2C, 16#FB, 16#DB, 16#F5, 16#2F,
+ 16#B3, 16#78, 16#61, 16#60, 16#27, 16#90, 16#04,
+ 16#E5, 16#7A, 16#E6, 16#AF, 16#87, 16#4E, 16#73,
+ 16#03, 16#CE, 16#53, 16#29, 16#9C, 16#CC, 16#04,
+ 16#1C, 16#7B, 16#C3, 16#08, 16#D8, 16#2A, 16#56,
+ 16#98, 16#F3, 16#A8, 16#D0, 16#C3, 16#82, 16#71,
+ 16#AE, 16#35, 16#F8, 16#E9, 16#DB, 16#FB, 16#B6,
+ 16#94, 16#B5, 16#C8, 16#03, 16#D8, 16#9F, 16#7A,
+ 16#E4, 16#35, 16#DE, 16#23, 16#6D, 16#52, 16#5F,
+ 16#54, 16#75, 16#9B, 16#65, 16#E3, 16#72, 16#FC,
+ 16#D6, 16#8E, 16#F2, 16#0F, 16#A7, 16#11, 16#1F,
+ 16#9E, 16#4A, 16#FF, 16#73>>).
+-define(GENERATOR_2048, <<2>>).
+
+-define(PRIME_3072, <<16#FF, 16#FF, 16#FF, 16#FF, 16#FF, 16#FF, 16#FF,
+ 16#FF, 16#C9, 16#0F, 16#DA, 16#A2, 16#21, 16#68,
+ 16#C2, 16#34, 16#C4, 16#C6, 16#62, 16#8B, 16#80,
+ 16#DC, 16#1C, 16#D1, 16#29, 16#02, 16#4E, 16#08,
+ 16#8A, 16#67, 16#CC, 16#74, 16#02, 16#0B, 16#BE,
+ 16#A6, 16#3B, 16#13, 16#9B, 16#22, 16#51, 16#4A,
+ 16#08, 16#79, 16#8E, 16#34, 16#04, 16#DD, 16#EF,
+ 16#95, 16#19, 16#B3, 16#CD, 16#3A, 16#43, 16#1B,
+ 16#30, 16#2B, 16#0A, 16#6D, 16#F2, 16#5F, 16#14,
+ 16#37, 16#4F, 16#E1, 16#35, 16#6D, 16#6D, 16#51,
+ 16#C2, 16#45, 16#E4, 16#85, 16#B5, 16#76, 16#62,
+ 16#5E, 16#7E, 16#C6, 16#F4, 16#4C, 16#42, 16#E9,
+ 16#A6, 16#37, 16#ED, 16#6B, 16#0B, 16#FF, 16#5C,
+ 16#B6, 16#F4, 16#06, 16#B7, 16#ED, 16#EE, 16#38,
+ 16#6B, 16#FB, 16#5A, 16#89, 16#9F, 16#A5, 16#AE,
+ 16#9F, 16#24, 16#11, 16#7C, 16#4B, 16#1F, 16#E6,
+ 16#49, 16#28, 16#66, 16#51, 16#EC, 16#E4, 16#5B,
+ 16#3D, 16#C2, 16#00, 16#7C, 16#B8, 16#A1, 16#63,
+ 16#BF, 16#05, 16#98, 16#DA, 16#48, 16#36, 16#1C,
+ 16#55, 16#D3, 16#9A, 16#69, 16#16, 16#3F, 16#A8,
+ 16#FD, 16#24, 16#CF, 16#5F, 16#83, 16#65, 16#5D,
+ 16#23, 16#DC, 16#A3, 16#AD, 16#96, 16#1C, 16#62,
+ 16#F3, 16#56, 16#20, 16#85, 16#52, 16#BB, 16#9E,
+ 16#D5, 16#29, 16#07, 16#70, 16#96, 16#96, 16#6D,
+ 16#67, 16#0C, 16#35, 16#4E, 16#4A, 16#BC, 16#98,
+ 16#04, 16#F1, 16#74, 16#6C, 16#08, 16#CA, 16#18,
+ 16#21, 16#7C, 16#32, 16#90, 16#5E, 16#46, 16#2E,
+ 16#36, 16#CE, 16#3B, 16#E3, 16#9E, 16#77, 16#2C,
+ 16#18, 16#0E, 16#86, 16#03, 16#9B, 16#27, 16#83,
+ 16#A2, 16#EC, 16#07, 16#A2, 16#8F, 16#B5, 16#C5,
+ 16#5D, 16#F0, 16#6F, 16#4C, 16#52, 16#C9, 16#DE,
+ 16#2B, 16#CB, 16#F6, 16#95, 16#58, 16#17, 16#18,
+ 16#39, 16#95, 16#49, 16#7C, 16#EA, 16#95, 16#6A,
+ 16#E5, 16#15, 16#D2, 16#26, 16#18, 16#98, 16#FA,
+ 16#05, 16#10, 16#15, 16#72, 16#8E, 16#5A, 16#8A,
+ 16#AA, 16#C4, 16#2D, 16#AD, 16#33, 16#17, 16#0D,
+ 16#04, 16#50, 16#7A, 16#33, 16#A8, 16#55, 16#21,
+ 16#AB, 16#DF, 16#1C, 16#BA, 16#64, 16#EC, 16#FB,
+ 16#85, 16#04, 16#58, 16#DB, 16#EF, 16#0A, 16#8A,
+ 16#EA, 16#71, 16#57, 16#5D, 16#06, 16#0C, 16#7D,
+ 16#B3, 16#97, 16#0F, 16#85, 16#A6, 16#E1, 16#E4,
+ 16#C7, 16#AB, 16#F5, 16#AE, 16#8C, 16#DB, 16#09,
+ 16#33, 16#D7, 16#1E, 16#8C, 16#94, 16#E0, 16#4A,
+ 16#25, 16#61, 16#9D, 16#CE, 16#E3, 16#D2, 16#26,
+ 16#1A, 16#D2, 16#EE, 16#6B, 16#F1, 16#2F, 16#FA,
+ 16#06, 16#D9, 16#8A, 16#08, 16#64, 16#D8, 16#76,
+ 16#02, 16#73, 16#3E, 16#C8, 16#6A, 16#64, 16#52,
+ 16#1F, 16#2B, 16#18, 16#17, 16#7B, 16#20, 16#0C,
+ 16#BB, 16#E1, 16#17, 16#57, 16#7A, 16#61, 16#5D,
+ 16#6C, 16#77, 16#09, 16#88, 16#C0, 16#BA, 16#D9,
+ 16#46, 16#E2, 16#08, 16#E2, 16#4F, 16#A0, 16#74,
+ 16#E5, 16#AB, 16#31, 16#43, 16#DB, 16#5B, 16#FC,
+ 16#E0, 16#FD, 16#10, 16#8E, 16#4B, 16#82, 16#D1,
+ 16#20, 16#A9, 16#3A, 16#D2, 16#CA, 16#FF, 16#FF,
+ 16#FF, 16#FF, 16#FF, 16#FF, 16#FF, 16#FF>>).
+-define(GENERATOR_3072, <<5>>).
+
+-define(PRIME_4096, <<16#FF, 16#FF, 16#FF, 16#FF, 16#FF, 16#FF, 16#FF,
+ 16#FF, 16#C9, 16#0F, 16#DA, 16#A2, 16#21, 16#68,
+ 16#C2, 16#34, 16#C4, 16#C6, 16#62, 16#8B, 16#80,
+ 16#DC, 16#1C, 16#D1, 16#29, 16#02, 16#4E, 16#08,
+ 16#8A, 16#67, 16#CC, 16#74, 16#02, 16#0B, 16#BE,
+ 16#A6, 16#3B, 16#13, 16#9B, 16#22, 16#51, 16#4A,
+ 16#08, 16#79, 16#8E, 16#34, 16#04, 16#DD, 16#EF,
+ 16#95, 16#19, 16#B3, 16#CD, 16#3A, 16#43, 16#1B,
+ 16#30, 16#2B, 16#0A, 16#6D, 16#F2, 16#5F, 16#14,
+ 16#37, 16#4F, 16#E1, 16#35, 16#6D, 16#6D, 16#51,
+ 16#C2, 16#45, 16#E4, 16#85, 16#B5, 16#76, 16#62,
+ 16#5E, 16#7E, 16#C6, 16#F4, 16#4C, 16#42, 16#E9,
+ 16#A6, 16#37, 16#ED, 16#6B, 16#0B, 16#FF, 16#5C,
+ 16#B6, 16#F4, 16#06, 16#B7, 16#ED, 16#EE, 16#38,
+ 16#6B, 16#FB, 16#5A, 16#89, 16#9F, 16#A5, 16#AE,
+ 16#9F, 16#24, 16#11, 16#7C, 16#4B, 16#1F, 16#E6,
+ 16#49, 16#28, 16#66, 16#51, 16#EC, 16#E4, 16#5B,
+ 16#3D, 16#C2, 16#00, 16#7C, 16#B8, 16#A1, 16#63,
+ 16#BF, 16#05, 16#98, 16#DA, 16#48, 16#36, 16#1C,
+ 16#55, 16#D3, 16#9A, 16#69, 16#16, 16#3F, 16#A8,
+ 16#FD, 16#24, 16#CF, 16#5F, 16#83, 16#65, 16#5D,
+ 16#23, 16#DC, 16#A3, 16#AD, 16#96, 16#1C, 16#62,
+ 16#F3, 16#56, 16#20, 16#85, 16#52, 16#BB, 16#9E,
+ 16#D5, 16#29, 16#07, 16#70, 16#96, 16#96, 16#6D,
+ 16#67, 16#0C, 16#35, 16#4E, 16#4A, 16#BC, 16#98,
+ 16#04, 16#F1, 16#74, 16#6C, 16#08, 16#CA, 16#18,
+ 16#21, 16#7C, 16#32, 16#90, 16#5E, 16#46, 16#2E,
+ 16#36, 16#CE, 16#3B, 16#E3, 16#9E, 16#77, 16#2C,
+ 16#18, 16#0E, 16#86, 16#03, 16#9B, 16#27, 16#83,
+ 16#A2, 16#EC, 16#07, 16#A2, 16#8F, 16#B5, 16#C5,
+ 16#5D, 16#F0, 16#6F, 16#4C, 16#52, 16#C9, 16#DE,
+ 16#2B, 16#CB, 16#F6, 16#95, 16#58, 16#17, 16#18,
+ 16#39, 16#95, 16#49, 16#7C, 16#EA, 16#95, 16#6A,
+ 16#E5, 16#15, 16#D2, 16#26, 16#18, 16#98, 16#FA,
+ 16#05, 16#10, 16#15, 16#72, 16#8E, 16#5A, 16#8A,
+ 16#AA, 16#C4, 16#2D, 16#AD, 16#33, 16#17, 16#0D,
+ 16#04, 16#50, 16#7A, 16#33, 16#A8, 16#55, 16#21,
+ 16#AB, 16#DF, 16#1C, 16#BA, 16#64, 16#EC, 16#FB,
+ 16#85, 16#04, 16#58, 16#DB, 16#EF, 16#0A, 16#8A,
+ 16#EA, 16#71, 16#57, 16#5D, 16#06, 16#0C, 16#7D,
+ 16#B3, 16#97, 16#0F, 16#85, 16#A6, 16#E1, 16#E4,
+ 16#C7, 16#AB, 16#F5, 16#AE, 16#8C, 16#DB, 16#09,
+ 16#33, 16#D7, 16#1E, 16#8C, 16#94, 16#E0, 16#4A,
+ 16#25, 16#61, 16#9D, 16#CE, 16#E3, 16#D2, 16#26,
+ 16#1A, 16#D2, 16#EE, 16#6B, 16#F1, 16#2F, 16#FA,
+ 16#06, 16#D9, 16#8A, 16#08, 16#64, 16#D8, 16#76,
+ 16#02, 16#73, 16#3E, 16#C8, 16#6A, 16#64, 16#52,
+ 16#1F, 16#2B, 16#18, 16#17, 16#7B, 16#20, 16#0C,
+ 16#BB, 16#E1, 16#17, 16#57, 16#7A, 16#61, 16#5D,
+ 16#6C, 16#77, 16#09, 16#88, 16#C0, 16#BA, 16#D9,
+ 16#46, 16#E2, 16#08, 16#E2, 16#4F, 16#A0, 16#74,
+ 16#E5, 16#AB, 16#31, 16#43, 16#DB, 16#5B, 16#FC,
+ 16#E0, 16#FD, 16#10, 16#8E, 16#4B, 16#82, 16#D1,
+ 16#20, 16#A9, 16#21, 16#08, 16#01, 16#1A, 16#72,
+ 16#3C, 16#12, 16#A7, 16#87, 16#E6, 16#D7, 16#88,
+ 16#71, 16#9A, 16#10, 16#BD, 16#BA, 16#5B, 16#26,
+ 16#99, 16#C3, 16#27, 16#18, 16#6A, 16#F4, 16#E2,
+ 16#3C, 16#1A, 16#94, 16#68, 16#34, 16#B6, 16#15,
+ 16#0B, 16#DA, 16#25, 16#83, 16#E9, 16#CA, 16#2A,
+ 16#D4, 16#4C, 16#E8, 16#DB, 16#BB, 16#C2, 16#DB,
+ 16#04, 16#DE, 16#8E, 16#F9, 16#2E, 16#8E, 16#FC,
+ 16#14, 16#1F, 16#BE, 16#CA, 16#A6, 16#28, 16#7C,
+ 16#59, 16#47, 16#4E, 16#6B, 16#C0, 16#5D, 16#99,
+ 16#B2, 16#96, 16#4F, 16#A0, 16#90, 16#C3, 16#A2,
+ 16#23, 16#3B, 16#A1, 16#86, 16#51, 16#5B, 16#E7,
+ 16#ED, 16#1F, 16#61, 16#29, 16#70, 16#CE, 16#E2,
+ 16#D7, 16#AF, 16#B8, 16#1B, 16#DD, 16#76, 16#21,
+ 16#70, 16#48, 16#1C, 16#D0, 16#06, 16#91, 16#27,
+ 16#D5, 16#B0, 16#5A, 16#A9, 16#93, 16#B4, 16#EA,
+ 16#98, 16#8D, 16#8F, 16#DD, 16#C1, 16#86, 16#FF,
+ 16#B7, 16#DC, 16#90, 16#A6, 16#C0, 16#8F, 16#4D,
+ 16#F4, 16#35, 16#C9, 16#34, 16#06, 16#31, 16#99,
+ 16#FF, 16#FF, 16#FF, 16#FF, 16#FF, 16#FF, 16#FF,
+ 16#FF>>).
+-define(GENERATOR_4096, <<5>>).
+
+-define(PRIME_6144, <<16#FF, 16#FF, 16#FF, 16#FF, 16#FF, 16#FF, 16#FF,
+ 16#FF, 16#C9, 16#0F, 16#DA, 16#A2, 16#21, 16#68,
+ 16#C2, 16#34, 16#C4, 16#C6, 16#62, 16#8B, 16#80,
+ 16#DC, 16#1C, 16#D1, 16#29, 16#02, 16#4E, 16#08,
+ 16#8A, 16#67, 16#CC, 16#74, 16#02, 16#0B, 16#BE,
+ 16#A6, 16#3B, 16#13, 16#9B, 16#22, 16#51, 16#4A,
+ 16#08, 16#79, 16#8E, 16#34, 16#04, 16#DD, 16#EF,
+ 16#95, 16#19, 16#B3, 16#CD, 16#3A, 16#43, 16#1B,
+ 16#30, 16#2B, 16#0A, 16#6D, 16#F2, 16#5F, 16#14,
+ 16#37, 16#4F, 16#E1, 16#35, 16#6D, 16#6D, 16#51,
+ 16#C2, 16#45, 16#E4, 16#85, 16#B5, 16#76, 16#62,
+ 16#5E, 16#7E, 16#C6, 16#F4, 16#4C, 16#42, 16#E9,
+ 16#A6, 16#37, 16#ED, 16#6B, 16#0B, 16#FF, 16#5C,
+ 16#B6, 16#F4, 16#06, 16#B7, 16#ED, 16#EE, 16#38,
+ 16#6B, 16#FB, 16#5A, 16#89, 16#9F, 16#A5, 16#AE,
+ 16#9F, 16#24, 16#11, 16#7C, 16#4B, 16#1F, 16#E6,
+ 16#49, 16#28, 16#66, 16#51, 16#EC, 16#E4, 16#5B,
+ 16#3D, 16#C2, 16#00, 16#7C, 16#B8, 16#A1, 16#63,
+ 16#BF, 16#05, 16#98, 16#DA, 16#48, 16#36, 16#1C,
+ 16#55, 16#D3, 16#9A, 16#69, 16#16, 16#3F, 16#A8,
+ 16#FD, 16#24, 16#CF, 16#5F, 16#83, 16#65, 16#5D,
+ 16#23, 16#DC, 16#A3, 16#AD, 16#96, 16#1C, 16#62,
+ 16#F3, 16#56, 16#20, 16#85, 16#52, 16#BB, 16#9E,
+ 16#D5, 16#29, 16#07, 16#70, 16#96, 16#96, 16#6D,
+ 16#67, 16#0C, 16#35, 16#4E, 16#4A, 16#BC, 16#98,
+ 16#04, 16#F1, 16#74, 16#6C, 16#08, 16#CA, 16#18,
+ 16#21, 16#7C, 16#32, 16#90, 16#5E, 16#46, 16#2E,
+ 16#36, 16#CE, 16#3B, 16#E3, 16#9E, 16#77, 16#2C,
+ 16#18, 16#0E, 16#86, 16#03, 16#9B, 16#27, 16#83,
+ 16#A2, 16#EC, 16#07, 16#A2, 16#8F, 16#B5, 16#C5,
+ 16#5D, 16#F0, 16#6F, 16#4C, 16#52, 16#C9, 16#DE,
+ 16#2B, 16#CB, 16#F6, 16#95, 16#58, 16#17, 16#18,
+ 16#39, 16#95, 16#49, 16#7C, 16#EA, 16#95, 16#6A,
+ 16#E5, 16#15, 16#D2, 16#26, 16#18, 16#98, 16#FA,
+ 16#05, 16#10, 16#15, 16#72, 16#8E, 16#5A, 16#8A,
+ 16#AA, 16#C4, 16#2D, 16#AD, 16#33, 16#17, 16#0D,
+ 16#04, 16#50, 16#7A, 16#33, 16#A8, 16#55, 16#21,
+ 16#AB, 16#DF, 16#1C, 16#BA, 16#64, 16#EC, 16#FB,
+ 16#85, 16#04, 16#58, 16#DB, 16#EF, 16#0A, 16#8A,
+ 16#EA, 16#71, 16#57, 16#5D, 16#06, 16#0C, 16#7D,
+ 16#B3, 16#97, 16#0F, 16#85, 16#A6, 16#E1, 16#E4,
+ 16#C7, 16#AB, 16#F5, 16#AE, 16#8C, 16#DB, 16#09,
+ 16#33, 16#D7, 16#1E, 16#8C, 16#94, 16#E0, 16#4A,
+ 16#25, 16#61, 16#9D, 16#CE, 16#E3, 16#D2, 16#26,
+ 16#1A, 16#D2, 16#EE, 16#6B, 16#F1, 16#2F, 16#FA,
+ 16#06, 16#D9, 16#8A, 16#08, 16#64, 16#D8, 16#76,
+ 16#02, 16#73, 16#3E, 16#C8, 16#6A, 16#64, 16#52,
+ 16#1F, 16#2B, 16#18, 16#17, 16#7B, 16#20, 16#0C,
+ 16#BB, 16#E1, 16#17, 16#57, 16#7A, 16#61, 16#5D,
+ 16#6C, 16#77, 16#09, 16#88, 16#C0, 16#BA, 16#D9,
+ 16#46, 16#E2, 16#08, 16#E2, 16#4F, 16#A0, 16#74,
+ 16#E5, 16#AB, 16#31, 16#43, 16#DB, 16#5B, 16#FC,
+ 16#E0, 16#FD, 16#10, 16#8E, 16#4B, 16#82, 16#D1,
+ 16#20, 16#A9, 16#21, 16#08, 16#01, 16#1A, 16#72,
+ 16#3C, 16#12, 16#A7, 16#87, 16#E6, 16#D7, 16#88,
+ 16#71, 16#9A, 16#10, 16#BD, 16#BA, 16#5B, 16#26,
+ 16#99, 16#C3, 16#27, 16#18, 16#6A, 16#F4, 16#E2,
+ 16#3C, 16#1A, 16#94, 16#68, 16#34, 16#B6, 16#15,
+ 16#0B, 16#DA, 16#25, 16#83, 16#E9, 16#CA, 16#2A,
+ 16#D4, 16#4C, 16#E8, 16#DB, 16#BB, 16#C2, 16#DB,
+ 16#04, 16#DE, 16#8E, 16#F9, 16#2E, 16#8E, 16#FC,
+ 16#14, 16#1F, 16#BE, 16#CA, 16#A6, 16#28, 16#7C,
+ 16#59, 16#47, 16#4E, 16#6B, 16#C0, 16#5D, 16#99,
+ 16#B2, 16#96, 16#4F, 16#A0, 16#90, 16#C3, 16#A2,
+ 16#23, 16#3B, 16#A1, 16#86, 16#51, 16#5B, 16#E7,
+ 16#ED, 16#1F, 16#61, 16#29, 16#70, 16#CE, 16#E2,
+ 16#D7, 16#AF, 16#B8, 16#1B, 16#DD, 16#76, 16#21,
+ 16#70, 16#48, 16#1C, 16#D0, 16#06, 16#91, 16#27,
+ 16#D5, 16#B0, 16#5A, 16#A9, 16#93, 16#B4, 16#EA,
+ 16#98, 16#8D, 16#8F, 16#DD, 16#C1, 16#86, 16#FF,
+ 16#B7, 16#DC, 16#90, 16#A6, 16#C0, 16#8F, 16#4D,
+ 16#F4, 16#35, 16#C9, 16#34, 16#02, 16#84, 16#92,
+ 16#36, 16#C3, 16#FA, 16#B4, 16#D2, 16#7C, 16#70,
+ 16#26, 16#C1, 16#D4, 16#DC, 16#B2, 16#60, 16#26,
+ 16#46, 16#DE, 16#C9, 16#75, 16#1E, 16#76, 16#3D,
+ 16#BA, 16#37, 16#BD, 16#F8, 16#FF, 16#94, 16#06,
+ 16#AD, 16#9E, 16#53, 16#0E, 16#E5, 16#DB, 16#38,
+ 16#2F, 16#41, 16#30, 16#01, 16#AE, 16#B0, 16#6A,
+ 16#53, 16#ED, 16#90, 16#27, 16#D8, 16#31, 16#17,
+ 16#97, 16#27, 16#B0, 16#86, 16#5A, 16#89, 16#18,
+ 16#DA, 16#3E, 16#DB, 16#EB, 16#CF, 16#9B, 16#14,
+ 16#ED, 16#44, 16#CE, 16#6C, 16#BA, 16#CE, 16#D4,
+ 16#BB, 16#1B, 16#DB, 16#7F, 16#14, 16#47, 16#E6,
+ 16#CC, 16#25, 16#4B, 16#33, 16#20, 16#51, 16#51,
+ 16#2B, 16#D7, 16#AF, 16#42, 16#6F, 16#B8, 16#F4,
+ 16#01, 16#37, 16#8C, 16#D2, 16#BF, 16#59, 16#83,
+ 16#CA, 16#01, 16#C6, 16#4B, 16#92, 16#EC, 16#F0,
+ 16#32, 16#EA, 16#15, 16#D1, 16#72, 16#1D, 16#03,
+ 16#F4, 16#82, 16#D7, 16#CE, 16#6E, 16#74, 16#FE,
+ 16#F6, 16#D5, 16#5E, 16#70, 16#2F, 16#46, 16#98,
+ 16#0C, 16#82, 16#B5, 16#A8, 16#40, 16#31, 16#90,
+ 16#0B, 16#1C, 16#9E, 16#59, 16#E7, 16#C9, 16#7F,
+ 16#BE, 16#C7, 16#E8, 16#F3, 16#23, 16#A9, 16#7A,
+ 16#7E, 16#36, 16#CC, 16#88, 16#BE, 16#0F, 16#1D,
+ 16#45, 16#B7, 16#FF, 16#58, 16#5A, 16#C5, 16#4B,
+ 16#D4, 16#07, 16#B2, 16#2B, 16#41, 16#54, 16#AA,
+ 16#CC, 16#8F, 16#6D, 16#7E, 16#BF, 16#48, 16#E1,
+ 16#D8, 16#14, 16#CC, 16#5E, 16#D2, 16#0F, 16#80,
+ 16#37, 16#E0, 16#A7, 16#97, 16#15, 16#EE, 16#F2,
+ 16#9B, 16#E3, 16#28, 16#06, 16#A1, 16#D5, 16#8B,
+ 16#B7, 16#C5, 16#DA, 16#76, 16#F5, 16#50, 16#AA,
+ 16#3D, 16#8A, 16#1F, 16#BF, 16#F0, 16#EB, 16#19,
+ 16#CC, 16#B1, 16#A3, 16#13, 16#D5, 16#5C, 16#DA,
+ 16#56, 16#C9, 16#EC, 16#2E, 16#F2, 16#96, 16#32,
+ 16#38, 16#7F, 16#E8, 16#D7, 16#6E, 16#3C, 16#04,
+ 16#68, 16#04, 16#3E, 16#8F, 16#66, 16#3F, 16#48,
+ 16#60, 16#EE, 16#12, 16#BF, 16#2D, 16#5B, 16#0B,
+ 16#74, 16#74, 16#D6, 16#E6, 16#94, 16#F9, 16#1E,
+ 16#6D, 16#CC, 16#40, 16#24, 16#FF, 16#FF, 16#FF,
+ 16#FF, 16#FF, 16#FF, 16#FF, 16#FF>>).
+-define(GENERATOR_6144, <<5>>).
+
+-define(PRIME_8192, <<16#FF, 16#FF, 16#FF, 16#FF, 16#FF, 16#FF, 16#FF,
+ 16#FF, 16#C9, 16#0F, 16#DA, 16#A2, 16#21, 16#68,
+ 16#C2, 16#34, 16#C4, 16#C6, 16#62, 16#8B, 16#80,
+ 16#DC, 16#1C, 16#D1, 16#29, 16#02, 16#4E, 16#08,
+ 16#8A, 16#67, 16#CC, 16#74, 16#02, 16#0B, 16#BE,
+ 16#A6, 16#3B, 16#13, 16#9B, 16#22, 16#51, 16#4A,
+ 16#08, 16#79, 16#8E, 16#34, 16#04, 16#DD, 16#EF,
+ 16#95, 16#19, 16#B3, 16#CD, 16#3A, 16#43, 16#1B,
+ 16#30, 16#2B, 16#0A, 16#6D, 16#F2, 16#5F, 16#14,
+ 16#37, 16#4F, 16#E1, 16#35, 16#6D, 16#6D, 16#51,
+ 16#C2, 16#45, 16#E4, 16#85, 16#B5, 16#76, 16#62,
+ 16#5E, 16#7E, 16#C6, 16#F4, 16#4C, 16#42, 16#E9,
+ 16#A6, 16#37, 16#ED, 16#6B, 16#0B, 16#FF, 16#5C,
+ 16#B6, 16#F4, 16#06, 16#B7, 16#ED, 16#EE, 16#38,
+ 16#6B, 16#FB, 16#5A, 16#89, 16#9F, 16#A5, 16#AE,
+ 16#9F, 16#24, 16#11, 16#7C, 16#4B, 16#1F, 16#E6,
+ 16#49, 16#28, 16#66, 16#51, 16#EC, 16#E4, 16#5B,
+ 16#3D, 16#C2, 16#00, 16#7C, 16#B8, 16#A1, 16#63,
+ 16#BF, 16#05, 16#98, 16#DA, 16#48, 16#36, 16#1C,
+ 16#55, 16#D3, 16#9A, 16#69, 16#16, 16#3F, 16#A8,
+ 16#FD, 16#24, 16#CF, 16#5F, 16#83, 16#65, 16#5D,
+ 16#23, 16#DC, 16#A3, 16#AD, 16#96, 16#1C, 16#62,
+ 16#F3, 16#56, 16#20, 16#85, 16#52, 16#BB, 16#9E,
+ 16#D5, 16#29, 16#07, 16#70, 16#96, 16#96, 16#6D,
+ 16#67, 16#0C, 16#35, 16#4E, 16#4A, 16#BC, 16#98,
+ 16#04, 16#F1, 16#74, 16#6C, 16#08, 16#CA, 16#18,
+ 16#21, 16#7C, 16#32, 16#90, 16#5E, 16#46, 16#2E,
+ 16#36, 16#CE, 16#3B, 16#E3, 16#9E, 16#77, 16#2C,
+ 16#18, 16#0E, 16#86, 16#03, 16#9B, 16#27, 16#83,
+ 16#A2, 16#EC, 16#07, 16#A2, 16#8F, 16#B5, 16#C5,
+ 16#5D, 16#F0, 16#6F, 16#4C, 16#52, 16#C9, 16#DE,
+ 16#2B, 16#CB, 16#F6, 16#95, 16#58, 16#17, 16#18,
+ 16#39, 16#95, 16#49, 16#7C, 16#EA, 16#95, 16#6A,
+ 16#E5, 16#15, 16#D2, 16#26, 16#18, 16#98, 16#FA,
+ 16#05, 16#10, 16#15, 16#72, 16#8E, 16#5A, 16#8A,
+ 16#AA, 16#C4, 16#2D, 16#AD, 16#33, 16#17, 16#0D,
+ 16#04, 16#50, 16#7A, 16#33, 16#A8, 16#55, 16#21,
+ 16#AB, 16#DF, 16#1C, 16#BA, 16#64, 16#EC, 16#FB,
+ 16#85, 16#04, 16#58, 16#DB, 16#EF, 16#0A, 16#8A,
+ 16#EA, 16#71, 16#57, 16#5D, 16#06, 16#0C, 16#7D,
+ 16#B3, 16#97, 16#0F, 16#85, 16#A6, 16#E1, 16#E4,
+ 16#C7, 16#AB, 16#F5, 16#AE, 16#8C, 16#DB, 16#09,
+ 16#33, 16#D7, 16#1E, 16#8C, 16#94, 16#E0, 16#4A,
+ 16#25, 16#61, 16#9D, 16#CE, 16#E3, 16#D2, 16#26,
+ 16#1A, 16#D2, 16#EE, 16#6B, 16#F1, 16#2F, 16#FA,
+ 16#06, 16#D9, 16#8A, 16#08, 16#64, 16#D8, 16#76,
+ 16#02, 16#73, 16#3E, 16#C8, 16#6A, 16#64, 16#52,
+ 16#1F, 16#2B, 16#18, 16#17, 16#7B, 16#20, 16#0C,
+ 16#BB, 16#E1, 16#17, 16#57, 16#7A, 16#61, 16#5D,
+ 16#6C, 16#77, 16#09, 16#88, 16#C0, 16#BA, 16#D9,
+ 16#46, 16#E2, 16#08, 16#E2, 16#4F, 16#A0, 16#74,
+ 16#E5, 16#AB, 16#31, 16#43, 16#DB, 16#5B, 16#FC,
+ 16#E0, 16#FD, 16#10, 16#8E, 16#4B, 16#82, 16#D1,
+ 16#20, 16#A9, 16#21, 16#08, 16#01, 16#1A, 16#72,
+ 16#3C, 16#12, 16#A7, 16#87, 16#E6, 16#D7, 16#88,
+ 16#71, 16#9A, 16#10, 16#BD, 16#BA, 16#5B, 16#26,
+ 16#99, 16#C3, 16#27, 16#18, 16#6A, 16#F4, 16#E2,
+ 16#3C, 16#1A, 16#94, 16#68, 16#34, 16#B6, 16#15,
+ 16#0B, 16#DA, 16#25, 16#83, 16#E9, 16#CA, 16#2A,
+ 16#D4, 16#4C, 16#E8, 16#DB, 16#BB, 16#C2, 16#DB,
+ 16#04, 16#DE, 16#8E, 16#F9, 16#2E, 16#8E, 16#FC,
+ 16#14, 16#1F, 16#BE, 16#CA, 16#A6, 16#28, 16#7C,
+ 16#59, 16#47, 16#4E, 16#6B, 16#C0, 16#5D, 16#99,
+ 16#B2, 16#96, 16#4F, 16#A0, 16#90, 16#C3, 16#A2,
+ 16#23, 16#3B, 16#A1, 16#86, 16#51, 16#5B, 16#E7,
+ 16#ED, 16#1F, 16#61, 16#29, 16#70, 16#CE, 16#E2,
+ 16#D7, 16#AF, 16#B8, 16#1B, 16#DD, 16#76, 16#21,
+ 16#70, 16#48, 16#1C, 16#D0, 16#06, 16#91, 16#27,
+ 16#D5, 16#B0, 16#5A, 16#A9, 16#93, 16#B4, 16#EA,
+ 16#98, 16#8D, 16#8F, 16#DD, 16#C1, 16#86, 16#FF,
+ 16#B7, 16#DC, 16#90, 16#A6, 16#C0, 16#8F, 16#4D,
+ 16#F4, 16#35, 16#C9, 16#34, 16#02, 16#84, 16#92,
+ 16#36, 16#C3, 16#FA, 16#B4, 16#D2, 16#7C, 16#70,
+ 16#26, 16#C1, 16#D4, 16#DC, 16#B2, 16#60, 16#26,
+ 16#46, 16#DE, 16#C9, 16#75, 16#1E, 16#76, 16#3D,
+ 16#BA, 16#37, 16#BD, 16#F8, 16#FF, 16#94, 16#06,
+ 16#AD, 16#9E, 16#53, 16#0E, 16#E5, 16#DB, 16#38,
+ 16#2F, 16#41, 16#30, 16#01, 16#AE, 16#B0, 16#6A,
+ 16#53, 16#ED, 16#90, 16#27, 16#D8, 16#31, 16#17,
+ 16#97, 16#27, 16#B0, 16#86, 16#5A, 16#89, 16#18,
+ 16#DA, 16#3E, 16#DB, 16#EB, 16#CF, 16#9B, 16#14,
+ 16#ED, 16#44, 16#CE, 16#6C, 16#BA, 16#CE, 16#D4,
+ 16#BB, 16#1B, 16#DB, 16#7F, 16#14, 16#47, 16#E6,
+ 16#CC, 16#25, 16#4B, 16#33, 16#20, 16#51, 16#51,
+ 16#2B, 16#D7, 16#AF, 16#42, 16#6F, 16#B8, 16#F4,
+ 16#01, 16#37, 16#8C, 16#D2, 16#BF, 16#59, 16#83,
+ 16#CA, 16#01, 16#C6, 16#4B, 16#92, 16#EC, 16#F0,
+ 16#32, 16#EA, 16#15, 16#D1, 16#72, 16#1D, 16#03,
+ 16#F4, 16#82, 16#D7, 16#CE, 16#6E, 16#74, 16#FE,
+ 16#F6, 16#D5, 16#5E, 16#70, 16#2F, 16#46, 16#98,
+ 16#0C, 16#82, 16#B5, 16#A8, 16#40, 16#31, 16#90,
+ 16#0B, 16#1C, 16#9E, 16#59, 16#E7, 16#C9, 16#7F,
+ 16#BE, 16#C7, 16#E8, 16#F3, 16#23, 16#A9, 16#7A,
+ 16#7E, 16#36, 16#CC, 16#88, 16#BE, 16#0F, 16#1D,
+ 16#45, 16#B7, 16#FF, 16#58, 16#5A, 16#C5, 16#4B,
+ 16#D4, 16#07, 16#B2, 16#2B, 16#41, 16#54, 16#AA,
+ 16#CC, 16#8F, 16#6D, 16#7E, 16#BF, 16#48, 16#E1,
+ 16#D8, 16#14, 16#CC, 16#5E, 16#D2, 16#0F, 16#80,
+ 16#37, 16#E0, 16#A7, 16#97, 16#15, 16#EE, 16#F2,
+ 16#9B, 16#E3, 16#28, 16#06, 16#A1, 16#D5, 16#8B,
+ 16#B7, 16#C5, 16#DA, 16#76, 16#F5, 16#50, 16#AA,
+ 16#3D, 16#8A, 16#1F, 16#BF, 16#F0, 16#EB, 16#19,
+ 16#CC, 16#B1, 16#A3, 16#13, 16#D5, 16#5C, 16#DA,
+ 16#56, 16#C9, 16#EC, 16#2E, 16#F2, 16#96, 16#32,
+ 16#38, 16#7F, 16#E8, 16#D7, 16#6E, 16#3C, 16#04,
+ 16#68, 16#04, 16#3E, 16#8F, 16#66, 16#3F, 16#48,
+ 16#60, 16#EE, 16#12, 16#BF, 16#2D, 16#5B, 16#0B,
+ 16#74, 16#74, 16#D6, 16#E6, 16#94, 16#F9, 16#1E,
+ 16#6D, 16#BE, 16#11, 16#59, 16#74, 16#A3, 16#92,
+ 16#6F, 16#12, 16#FE, 16#E5, 16#E4, 16#38, 16#77,
+ 16#7C, 16#B6, 16#A9, 16#32, 16#DF, 16#8C, 16#D8,
+ 16#BE, 16#C4, 16#D0, 16#73, 16#B9, 16#31, 16#BA,
+ 16#3B, 16#C8, 16#32, 16#B6, 16#8D, 16#9D, 16#D3,
+ 16#00, 16#74, 16#1F, 16#A7, 16#BF, 16#8A, 16#FC,
+ 16#47, 16#ED, 16#25, 16#76, 16#F6, 16#93, 16#6B,
+ 16#A4, 16#24, 16#66, 16#3A, 16#AB, 16#63, 16#9C,
+ 16#5A, 16#E4, 16#F5, 16#68, 16#34, 16#23, 16#B4,
+ 16#74, 16#2B, 16#F1, 16#C9, 16#78, 16#23, 16#8F,
+ 16#16, 16#CB, 16#E3, 16#9D, 16#65, 16#2D, 16#E3,
+ 16#FD, 16#B8, 16#BE, 16#FC, 16#84, 16#8A, 16#D9,
+ 16#22, 16#22, 16#2E, 16#04, 16#A4, 16#03, 16#7C,
+ 16#07, 16#13, 16#EB, 16#57, 16#A8, 16#1A, 16#23,
+ 16#F0, 16#C7, 16#34, 16#73, 16#FC, 16#64, 16#6C,
+ 16#EA, 16#30, 16#6B, 16#4B, 16#CB, 16#C8, 16#86,
+ 16#2F, 16#83, 16#85, 16#DD, 16#FA, 16#9D, 16#4B,
+ 16#7F, 16#A2, 16#C0, 16#87, 16#E8, 16#79, 16#68,
+ 16#33, 16#03, 16#ED, 16#5B, 16#DD, 16#3A, 16#06,
+ 16#2B, 16#3C, 16#F5, 16#B3, 16#A2, 16#78, 16#A6,
+ 16#6D, 16#2A, 16#13, 16#F8, 16#3F, 16#44, 16#F8,
+ 16#2D, 16#DF, 16#31, 16#0E, 16#E0, 16#74, 16#AB,
+ 16#6A, 16#36, 16#45, 16#97, 16#E8, 16#99, 16#A0,
+ 16#25, 16#5D, 16#C1, 16#64, 16#F3, 16#1C, 16#C5,
+ 16#08, 16#46, 16#85, 16#1D, 16#F9, 16#AB, 16#48,
+ 16#19, 16#5D, 16#ED, 16#7E, 16#A1, 16#B1, 16#D5,
+ 16#10, 16#BD, 16#7E, 16#E7, 16#4D, 16#73, 16#FA,
+ 16#F3, 16#6B, 16#C3, 16#1E, 16#CF, 16#A2, 16#68,
+ 16#35, 16#90, 16#46, 16#F4, 16#EB, 16#87, 16#9F,
+ 16#92, 16#40, 16#09, 16#43, 16#8B, 16#48, 16#1C,
+ 16#6C, 16#D7, 16#88, 16#9A, 16#00, 16#2E, 16#D5,
+ 16#EE, 16#38, 16#2B, 16#C9, 16#19, 16#0D, 16#A6,
+ 16#FC, 16#02, 16#6E, 16#47, 16#95, 16#58, 16#E4,
+ 16#47, 16#56, 16#77, 16#E9, 16#AA, 16#9E, 16#30,
+ 16#50, 16#E2, 16#76, 16#56, 16#94, 16#DF, 16#C8,
+ 16#1F, 16#56, 16#E8, 16#80, 16#B9, 16#6E, 16#71,
+ 16#60, 16#C9, 16#80, 16#DD, 16#98, 16#ED, 16#D3,
+ 16#DF, 16#FF, 16#FF, 16#FF, 16#FF, 16#FF, 16#FF,
+ 16#FF, 16#FF>>).
+-define(GENERATOR_8192, <<19>>).
+
+get_srp_params(srp_1024) -> {?GENERATOR_1024, ?PRIME_1024};
+get_srp_params(srp_1536) -> {?GENERATOR_1536, ?PRIME_1536};
+get_srp_params(srp_2048) -> {?GENERATOR_2048, ?PRIME_2048};
+get_srp_params(srp_3072) -> {?GENERATOR_3072, ?PRIME_3072};
+get_srp_params(srp_4096) -> {?GENERATOR_4096, ?PRIME_4096};
+get_srp_params(srp_6144) -> {?GENERATOR_6144, ?PRIME_6144};
+get_srp_params(srp_8192) -> {?GENERATOR_8192, ?PRIME_8192}.
+
+check_srp_params(?GENERATOR_1024, ?PRIME_1024) -> ok;
+check_srp_params(?GENERATOR_1536, ?PRIME_1536) -> ok;
+check_srp_params(?GENERATOR_2048, ?PRIME_2048) -> ok;
+check_srp_params(?GENERATOR_3072, ?PRIME_3072) -> ok;
+check_srp_params(?GENERATOR_4096, ?PRIME_4096) -> ok;
+check_srp_params(?GENERATOR_6144, ?PRIME_6144) -> ok;
+check_srp_params(?GENERATOR_8192, ?PRIME_8192) -> ok;
+check_srp_params(_Generator, _Prime) ->
+ not_accepted.
diff --git a/lib/ssl/src/ssl_srp_primes.hrl b/lib/ssl/src/ssl_srp_primes.hrl
new file mode 100644
index 0000000000..4bd534efbf
--- /dev/null
+++ b/lib/ssl/src/ssl_srp_primes.hrl
@@ -0,0 +1 @@
+-type srp_parameters() :: srp_1024 | srp_1536 | srp_2048 | srp_3072 | srp_4096 | srp_6144 | srp_8192.
diff --git a/lib/ssl/test/ssl_basic_SUITE.erl b/lib/ssl/test/ssl_basic_SUITE.erl
index 6b8f226a77..5cedde5d27 100644
--- a/lib/ssl/test/ssl_basic_SUITE.erl
+++ b/lib/ssl/test/ssl_basic_SUITE.erl
@@ -154,6 +154,10 @@ cipher_tests() ->
ciphers_dsa_signed_certs,
ciphers_dsa_signed_certs_openssl_names,
anonymous_cipher_suites,
+ psk_cipher_suites,
+ psk_with_hint_cipher_suites,
+ srp_cipher_suites,
+ srp_dsa_cipher_suites,
default_reject_anonymous].
error_handling_tests()->
@@ -1575,7 +1579,34 @@ anonymous_cipher_suites(Config) when is_list(Config) ->
Version = ssl_record:protocol_version(ssl_record:highest_protocol_version([])),
Ciphers = ssl_test_lib:anonymous_suites(),
run_suites(Ciphers, Version, Config, anonymous).
-
+%%-------------------------------------------------------------------
+psk_cipher_suites() ->
+ [{doc, "Test the PSK ciphersuites WITHOUT server supplied identity hint"}].
+psk_cipher_suites(Config) when is_list(Config) ->
+ Version = ssl_record:protocol_version(ssl_record:highest_protocol_version([])),
+ Ciphers = ssl_test_lib:psk_suites(),
+ run_suites(Ciphers, Version, Config, psk).
+%%-------------------------------------------------------------------
+psk_with_hint_cipher_suites()->
+ [{doc, "Test the PSK ciphersuites WITH server supplied identity hint"}].
+psk_with_hint_cipher_suites(Config) when is_list(Config) ->
+ Version = ssl_record:protocol_version(ssl_record:highest_protocol_version([])),
+ Ciphers = ssl_test_lib:psk_suites(),
+ run_suites(Ciphers, Version, Config, psk_with_hint).
+%%-------------------------------------------------------------------
+srp_cipher_suites()->
+ [{doc, "Test the SRP ciphersuites"}].
+srp_cipher_suites(Config) when is_list(Config) ->
+ Version = ssl_record:protocol_version(ssl_record:highest_protocol_version([])),
+ Ciphers = ssl_test_lib:srp_suites(),
+ run_suites(Ciphers, Version, Config, srp).
+%%-------------------------------------------------------------------
+srp_dsa_cipher_suites()->
+ [{doc, "Test the SRP DSA ciphersuites"}].
+srp_dsa_cipher_suites(Config) when is_list(Config) ->
+ Version = ssl_record:protocol_version(ssl_record:highest_protocol_version([])),
+ Ciphers = ssl_test_lib:srp_dss_suites(),
+ run_suites(Ciphers, Version, Config, srp_dsa).
%%--------------------------------------------------------------------
default_reject_anonymous()->
[{doc,"Test that by default anonymous cipher suites are rejected "}].
@@ -3113,7 +3144,19 @@ run_suites(Ciphers, Version, Config, Type) ->
anonymous ->
%% No certs in opts!
{?config(client_opts, Config),
- ?config(server_anon, Config)}
+ ?config(server_anon, Config)};
+ psk ->
+ {?config(client_psk, Config),
+ ?config(server_psk, Config)};
+ psk_with_hint ->
+ {?config(client_psk, Config),
+ ?config(server_psk_hint, Config)};
+ srp ->
+ {?config(client_srp, Config),
+ ?config(server_srp, Config)};
+ srp_dsa ->
+ {?config(client_srp_dsa, Config),
+ ?config(server_srp_dsa, Config)}
end,
Result = lists:map(fun(Cipher) ->
diff --git a/lib/ssl/test/ssl_test_lib.erl b/lib/ssl/test/ssl_test_lib.erl
index 76b302b1cb..d655d7659e 100644
--- a/lib/ssl/test/ssl_test_lib.erl
+++ b/lib/ssl/test/ssl_test_lib.erl
@@ -281,6 +281,13 @@ wait_for_result(Pid, Msg) ->
%% Unexpected
end.
+user_lookup(psk, _Identity, UserState) ->
+ {ok, UserState};
+user_lookup(srp, Username, _UserState) ->
+ Salt = ssl:random_bytes(16),
+ UserPassHash = crypto:sha([Salt, crypto:sha([Username, <<$:>>, <<"secret">>])]),
+ {ok, {srp_1024, Salt, UserPassHash}}.
+
cert_options(Config) ->
ClientCaCertFile = filename:join([?config(priv_dir, Config),
"client", "cacerts.pem"]),
@@ -307,6 +314,7 @@ cert_options(Config) ->
"badcert.pem"]),
BadKeyFile = filename:join([?config(priv_dir, Config),
"badkey.pem"]),
+ PskSharedSecret = <<1,2,3,4,5,6,7,8,9,10,11,12,13,14,15>>,
[{client_opts, [{ssl_imp, new},{reuseaddr, true}]},
{client_verification_opts, [{cacertfile, ClientCaCertFile},
{certfile, ClientCertFile},
@@ -319,6 +327,24 @@ cert_options(Config) ->
{server_opts, [{ssl_imp, new},{reuseaddr, true},
{certfile, ServerCertFile}, {keyfile, ServerKeyFile}]},
{server_anon, [{ssl_imp, new},{reuseaddr, true}, {ciphers, anonymous_suites()}]},
+ {client_psk, [{ssl_imp, new},{reuseaddr, true},
+ {psk_identity, "Test-User"},
+ {user_lookup_fun, {fun user_lookup/3, PskSharedSecret}}]},
+ {server_psk, [{ssl_imp, new},{reuseaddr, true},
+ {certfile, ServerCertFile}, {keyfile, ServerKeyFile},
+ {user_lookup_fun, {fun user_lookup/3, PskSharedSecret}},
+ {ciphers, psk_suites()}]},
+ {server_psk_hint, [{ssl_imp, new},{reuseaddr, true},
+ {certfile, ServerCertFile}, {keyfile, ServerKeyFile},
+ {psk_identity, "HINT"},
+ {user_lookup_fun, {fun user_lookup/3, PskSharedSecret}},
+ {ciphers, psk_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_verification_opts, [{ssl_imp, new},{reuseaddr, true},
{cacertfile, ServerCaCertFile},
{certfile, ServerCertFile}, {keyfile, ServerKeyFile}]},
@@ -356,7 +382,16 @@ make_dsa_cert(Config) ->
{verify, verify_peer}]},
{client_dsa_opts, [{ssl_imp, new},{reuseaddr, true},
{cacertfile, ClientCaCertFile},
- {certfile, ClientCertFile}, {keyfile, ClientKeyFile}]}
+ {certfile, ClientCertFile}, {keyfile, ClientKeyFile}]},
+ {server_srp_dsa, [{ssl_imp, new},{reuseaddr, true},
+ {cacertfile, ServerCaCertFile},
+ {certfile, ServerCertFile}, {keyfile, ServerKeyFile},
+ {user_lookup_fun, {fun user_lookup/3, undefined}},
+ {ciphers, srp_dss_suites()}]},
+ {client_srp_dsa, [{ssl_imp, new},{reuseaddr, true},
+ {srp_identity, {"Test-User", "secret"}},
+ {cacertfile, ClientCaCertFile},
+ {certfile, ClientCertFile}, {keyfile, ClientKeyFile}]}
| Config].
@@ -675,6 +710,33 @@ anonymous_suites() ->
{dh_anon, aes_128_cbc, sha},
{dh_anon, aes_256_cbc, sha}].
+psk_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}].
+
+srp_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_dss_suites() ->
+ [{srp_dss, '3des_ede_cbc', sha},
+ {srp_dss, aes_128_cbc, sha},
+ {srp_dss, aes_256_cbc, sha}].
+
pem_to_der(File) ->
{ok, PemBin} = file:read_file(File),
public_key:pem_decode(PemBin).
diff --git a/lib/stdlib/doc/src/erl_parse.xml b/lib/stdlib/doc/src/erl_parse.xml
index bafc2e0746..56a7131821 100644
--- a/lib/stdlib/doc/src/erl_parse.xml
+++ b/lib/stdlib/doc/src/erl_parse.xml
@@ -4,7 +4,7 @@
<erlref>
<header>
<copyright>
- <year>1996</year><year>2011</year>
+ <year>1996</year><year>2013</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
@@ -167,6 +167,23 @@
<p>Converts the Erlang data structure <c><anno>Data</anno></c> into an
abstract form of type <c><anno>AbsTerm</anno></c>.
This is the inverse of <c>normalise/1</c>.</p>
+ <p><c>erl_parse:abstract(T)</c> is equivalent to
+ <c>erl_parse:abstract(T, 0)</c>.</p>
+ </desc>
+ </func>
+ <func>
+ <name name="abstract" arity="2"/>
+ <fsummary>Convert an Erlang term into an abstract form</fsummary>
+ <desc>
+ <p>Converts the Erlang data structure <c><anno>Data</anno></c> into an
+ abstract form of type <c><anno>AbsTerm</anno></c>.</p>
+ <p>The <c><anno>Line</anno></c> option is the line that will
+ be assigned to each node of the abstract form.</p>
+ <p>The <c><anno>Encoding</anno></c> option is used for
+ selecting which integer lists will be considered
+ as strings. The default is to use the encoding returned by
+ <seealso marker="epp#default_encoding/0">
+ <c>epp:default_encoding/0</c></seealso></p>
</desc>
</func>
</funcs>
diff --git a/lib/stdlib/doc/src/sys.xml b/lib/stdlib/doc/src/sys.xml
index 073faf2df2..a177b80739 100644
--- a/lib/stdlib/doc/src/sys.xml
+++ b/lib/stdlib/doc/src/sys.xml
@@ -211,18 +211,87 @@
<p>Gets the status of the process.</p>
<p>The value of <c><anno>Misc</anno></c> varies for different types of
processes. For example, a <c>gen_server</c> process returns
- the callback module's state, and a <c>gen_fsm</c> process
- returns information such as its current state name. Callback
- modules for <c>gen_server</c> and <c>gen_fsm</c> can also
- customise the value of <c><anno>Misc</anno></c> by exporting
- a <c>format_status/2</c> function that contributes
- module-specific information;
- see <seealso marker="gen_server#Module:format_status/2">gen_server:format_status/2</seealso>
- and <seealso marker="gen_fsm#Module:format_status/2">gen_fsm:format_status/2</seealso>
+ the callback module's state, a <c>gen_fsm</c> process
+ returns information such as its current state name and state data,
+ and a <c>gen_event</c> process returns information about each of its
+ registered handlers. Callback modules for <c>gen_server</c>,
+ <c>gen_fsm</c>, and <c>gen_event</c> can also customise the value
+ of <c><anno>Misc</anno></c> by exporting a <c>format_status/2</c>
+ function that contributes module-specific information;
+ see <seealso marker="gen_server#Module:format_status/2">gen_server:format_status/2</seealso>,
+ <seealso marker="gen_fsm#Module:format_status/2">gen_fsm:format_status/2</seealso>, and
+ <seealso marker="gen_event#Module:format_status/2">gen_event:format_status/2</seealso>
for more details.</p>
</desc>
</func>
<func>
+ <name name="get_state" arity="1"/>
+ <name name="get_state" arity="2"/>
+ <fsummary>Get the state of the process</fsummary>
+ <desc>
+ <p>Gets the state of the process.</p>
+ <note>
+ <p>These functions are intended only to help with debugging. They are provided for
+ convenience, allowing developers to avoid having to create their own state extraction
+ functions and also avoid having to interactively extract state from the return values of
+ <c><seealso marker="get_status/1">get_status/1</seealso></c> or
+ <c><seealso marker="get_status/2">get_status/2</seealso></c> while debugging.</p>
+ </note>
+ <p>The value of <c><anno>State</anno></c> varies for different types of
+ processes. For a <c>gen_server</c> process, the returned <c><anno>State</anno></c>
+ is simply the callback module's state. For a <c>gen_fsm</c> process,
+ <c><anno>State</anno></c> is the tuple <c>{CurrentStateName, CurrentStateData}</c>.
+ For a <c>gen_event</c> process, <c><anno>State</anno></c> a list of tuples,
+ where each tuple corresponds to an event handler registered in the process and contains
+ <c>{Module, Id, HandlerState}</c>, where <c>Module</c> is the event handler's module name,
+ <c>Id</c> is the handler's ID (which is the value <c>false</c> if it was registered without
+ an ID), and <c>HandlerState</c> is the handler's state.</p>
+ <p>To obtain more information about a process, including its state, see
+ <seealso marker="get_status/1">get_status/1</seealso> and
+ <seealso marker="get_status/2">get_status/2</seealso>.</p>
+ </desc>
+ </func>
+ <func>
+ <name name="replace_state" arity="2"/>
+ <name name="replace_state" arity="3"/>
+ <fsummary>Replace the state of the process</fsummary>
+ <desc>
+ <p>Replaces the state of the process, and returns the new state.</p>
+ <note>
+ <p>These functions are intended only to help with debugging, and they should not be
+ be called from normal code. They are provided for convenience, allowing developers
+ to avoid having to create their own custom state replacement functions.</p>
+ </note>
+ <p>The <c><anno>StateFun</anno></c> function provides a new state for the process.
+ The <c><anno>State</anno></c> argument and <c><anno>NewState</anno></c> return value
+ of <c><anno>StateFun</anno></c> vary for different types of processes. For a
+ <c>gen_server</c> process, <c><anno>State</anno></c> is simply the callback module's
+ state, and <c><anno>NewState</anno></c> is a new instance of that state. For a
+ <c>gen_fsm</c> process, <c><anno>State</anno></c> is the tuple
+ <c>{CurrentStateName, CurrentStateData}</c>, and <c><anno>NewState</anno></c>
+ is a similar tuple that may contain a new state name, new state data, or both.
+ For a <c>gen_event</c> process, <c><anno>State</anno></c> is the tuple
+ <c>{Module, Id, HandlerState}</c> where <c>Module</c> is the event handler's module name,
+ <c>Id</c> is the handler's ID (which is the value <c>false</c> if it was registered without
+ an ID), and <c>HandlerState</c> is the handler's state. <c><anno>NewState</anno></c> is a
+ similar tuple where <c>Module</c> and <c>Id</c> shall have the same values as in
+ <c><anno>State</anno></c> but the value of <c>HandlerState</c> may be different. Returning
+ a <c><anno>NewState</anno></c> whose <c>Module</c> or <c>Id</c> values differ from those of
+ <c><anno>State</anno></c> will result in the event handler's state remaining unchanged. For a
+ <c>gen_event</c> process, <c><anno>StateFun</anno></c> is called once for each event handler
+ registered in the <c>gen_event</c> process.</p>
+ <p>If a <c><anno>StateFun</anno></c> function decides not to effect any change in process
+ state, then regardless of process type, it may simply return its <c><anno>State</anno></c>
+ argument.</p>
+ <p>If a <c><anno>StateFun</anno></c> function crashes or throws an exception, then
+ for <c>gen_server</c> and <c>gen_fsm</c> processes, the original state of the process is
+ unchanged. For <c>gen_event</c> processes, a crashing or failing <c><anno>StateFun</anno></c>
+ function means that only the state of the particular event handler it was working on when it
+ failed or crashed is unchanged; it can still succeed in changing the states of other event
+ handlers registered in the same <c>gen_event</c> process.</p>
+ </desc>
+ </func>
+ <func>
<name name="install" arity="2"/>
<name name="install" arity="3"/>
<fsummary>Install a debug function in the process</fsummary>
diff --git a/lib/stdlib/src/erl_parse.yrl b/lib/stdlib/src/erl_parse.yrl
index 9ff25fcbc5..7145b0858f 100644
--- a/lib/stdlib/src/erl_parse.yrl
+++ b/lib/stdlib/src/erl_parse.yrl
@@ -887,6 +887,7 @@ abstract(T, Options) when is_list(Options) ->
abstract(T, Line, Encoding).
-define(UNICODE(C),
+ is_integer(C) andalso
(C >= 0 andalso C < 16#D800 orelse
C > 16#DFFF andalso C < 16#FFFE orelse
C > 16#FFFF andalso C =< 16#10FFFF)).
diff --git a/lib/stdlib/src/erl_scan.erl b/lib/stdlib/src/erl_scan.erl
index 3651f608bc..d988a4d8c7 100644
--- a/lib/stdlib/src/erl_scan.erl
+++ b/lib/stdlib/src/erl_scan.erl
@@ -338,6 +338,7 @@ string_thing(_) -> "string".
-define(DIGIT(C), C >= $0, C =< $9).
-define(CHAR(C), is_integer(C), C >= 0).
-define(UNICODE(C),
+ is_integer(C) andalso
(C >= 0 andalso C < 16#D800 orelse
C > 16#DFFF andalso C < 16#FFFE orelse
C > 16#FFFF andalso C =< 16#10FFFF)).
diff --git a/lib/stdlib/src/gen_event.erl b/lib/stdlib/src/gen_event.erl
index 2b8ba86909..bfebf29080 100644
--- a/lib/stdlib/src/gen_event.erl
+++ b/lib/stdlib/src/gen_event.erl
@@ -229,6 +229,24 @@ wake_hib(Parent, ServerName, MSL, Debug) ->
fetch_msg(Parent, ServerName, MSL, Debug, Hib) ->
receive
+ {system, From, get_state} ->
+ States = [{Mod,Id,State} || #handler{module=Mod, id=Id, state=State} <- MSL],
+ sys:handle_system_msg(get_state, From, Parent, ?MODULE, Debug,
+ {States, [ServerName, MSL, Hib]}, Hib);
+ {system, From, {replace_state, StateFun}} ->
+ {NMSL, NStates} =
+ lists:unzip([begin
+ Cur = {Mod,Id,State},
+ try
+ NState = {Mod,Id,NS} = StateFun(Cur),
+ {HS#handler{state=NS}, NState}
+ catch
+ _:_ ->
+ {HS, Cur}
+ end
+ end || #handler{module=Mod, id=Id, state=State}=HS <- MSL]),
+ sys:handle_system_msg(replace_state, From, Parent, ?MODULE, Debug,
+ {NStates, [ServerName, NMSL, Hib]}, Hib);
{system, From, Req} ->
sys:handle_system_msg(Req, From, Parent, ?MODULE, Debug,
[ServerName, MSL, Hib],Hib);
diff --git a/lib/stdlib/src/gen_fsm.erl b/lib/stdlib/src/gen_fsm.erl
index e480e2ac11..d9411e58cf 100644
--- a/lib/stdlib/src/gen_fsm.erl
+++ b/lib/stdlib/src/gen_fsm.erl
@@ -422,6 +422,17 @@ wake_hib(Parent, Name, StateName, StateData, Mod, Debug) ->
decode_msg(Msg,Parent, Name, StateName, StateData, Mod, Time, Debug, Hib) ->
case Msg of
+ {system, From, get_state} ->
+ Misc = [Name, StateName, StateData, Mod, Time],
+ sys:handle_system_msg(get_state, From, Parent, ?MODULE, Debug,
+ {{StateName, StateData}, Misc}, Hib);
+ {system, From, {replace_state, StateFun}} ->
+ State = {StateName, StateData},
+ NState = {NStateName, NStateData} = try StateFun(State)
+ catch _:_ -> State end,
+ NMisc = [Name, NStateName, NStateData, Mod, Time],
+ sys:handle_system_msg(replace_state, From, Parent, ?MODULE, Debug,
+ {NState, NMisc}, Hib);
{system, From, Req} ->
sys:handle_system_msg(Req, From, Parent, ?MODULE, Debug,
[Name, StateName, StateData, Mod, Time], Hib);
diff --git a/lib/stdlib/src/gen_server.erl b/lib/stdlib/src/gen_server.erl
index 04308a51b7..9c4b95acf6 100644
--- a/lib/stdlib/src/gen_server.erl
+++ b/lib/stdlib/src/gen_server.erl
@@ -372,6 +372,13 @@ wake_hib(Parent, Name, State, Mod, Debug) ->
decode_msg(Msg, Parent, Name, State, Mod, Time, Debug, Hib) ->
case Msg of
+ {system, From, get_state} ->
+ sys:handle_system_msg(get_state, From, Parent, ?MODULE, Debug,
+ {State, [Name, State, Mod, Time]}, Hib);
+ {system, From, {replace_state, StateFun}} ->
+ NState = try StateFun(State) catch _:_ -> State end,
+ sys:handle_system_msg(replace_state, From, Parent, ?MODULE, Debug,
+ {NState, [Name, NState, Mod, Time]}, Hib);
{system, From, Req} ->
sys:handle_system_msg(Req, From, Parent, ?MODULE, Debug,
[Name, State, Mod, Time], Hib);
diff --git a/lib/stdlib/src/sys.erl b/lib/stdlib/src/sys.erl
index 2d6287814e..bffeb44179 100644
--- a/lib/stdlib/src/sys.erl
+++ b/lib/stdlib/src/sys.erl
@@ -21,6 +21,8 @@
%% External exports
-export([suspend/1, suspend/2, resume/1, resume/2,
get_status/1, get_status/2,
+ get_state/1, get_state/2,
+ replace_state/2, replace_state/3,
change_code/4, change_code/5,
log/2, log/3, trace/2, trace/3, statistics/2, statistics/3,
log_to_file/2, log_to_file/3, no_debug/1, no_debug/2,
@@ -97,6 +99,32 @@ get_status(Name) -> send_system_msg(Name, get_status).
| (Misc :: term()).
get_status(Name, Timeout) -> send_system_msg(Name, get_status, Timeout).
+-spec get_state(Name) -> State when
+ Name :: name(),
+ State :: term().
+get_state(Name) -> send_system_msg(Name, get_state).
+
+-spec get_state(Name, Timeout) -> State when
+ Name :: name(),
+ Timeout :: timeout(),
+ State :: term().
+get_state(Name, Timeout) -> send_system_msg(Name, get_state, Timeout).
+
+-spec replace_state(Name, StateFun) -> NewState when
+ Name :: name(),
+ StateFun :: fun((State :: term()) -> NewState :: term()),
+ NewState :: term().
+replace_state(Name, StateFun) ->
+ send_system_msg(Name, {replace_state, StateFun}).
+
+-spec replace_state(Name, StateFun, Timeout) -> NewState when
+ Name :: name(),
+ StateFun :: fun((State :: term()) -> NewState :: term()),
+ Timeout :: timeout(),
+ NewState :: term().
+replace_state(Name, StateFun, Timeout) ->
+ send_system_msg(Name, {replace_state, StateFun}, Timeout).
+
-spec change_code(Name, Module, OldVsn, Extra) -> 'ok' | {error, Reason} when
Name :: name(),
Module :: module(),
@@ -362,6 +390,10 @@ do_cmd(_, suspend, _Parent, _Mod, Debug, Misc) ->
{suspended, ok, Debug, Misc};
do_cmd(_, resume, _Parent, _Mod, Debug, Misc) ->
{running, ok, Debug, Misc};
+do_cmd(SysState, get_state, _Parent, _Mod, Debug, {State, Misc}) ->
+ {SysState, State, Debug, Misc};
+do_cmd(SysState, replace_state, _Parent, _Mod, Debug, {State, Misc}) ->
+ {SysState, State, Debug, Misc};
do_cmd(SysState, get_status, Parent, Mod, Debug, Misc) ->
Res = get_status(SysState, Parent, Mod, Debug, Misc),
{SysState, Res, Debug, Misc};
diff --git a/lib/stdlib/test/erl_scan_SUITE.erl b/lib/stdlib/test/erl_scan_SUITE.erl
index ecd181e87c..361abbb771 100644
--- a/lib/stdlib/test/erl_scan_SUITE.erl
+++ b/lib/stdlib/test/erl_scan_SUITE.erl
@@ -21,7 +21,8 @@
-export([all/0, suite/0,groups/0,init_per_suite/1, end_per_suite/1,
init_per_group/2,end_per_group/2]).
--export([ error_1/1, error_2/1, iso88591/1, otp_7810/1, otp_10302/1]).
+-export([ error_1/1, error_2/1, iso88591/1, otp_7810/1, otp_10302/1,
+ otp_10990/1, otp_10992/1]).
-import(lists, [nth/2,flatten/1]).
-import(io_lib, [print/1]).
@@ -60,7 +61,7 @@ end_per_testcase(_Case, Config) ->
suite() -> [{ct_hooks,[ts_install_cth]}].
all() ->
- [{group, error}, iso88591, otp_7810, otp_10302].
+ [{group, error}, iso88591, otp_7810, otp_10302, otp_10990, otp_10992].
groups() ->
[{error, [], [error_1, error_2]}].
@@ -1121,6 +1122,29 @@ otp_10302(Config) when is_list(Config) ->
erl_parse:abstract("a"++[1024]++"c", [{encoding,latin1}]),
ok.
+otp_10990(doc) ->
+ "OTP-10990. Floating point number in input string.";
+otp_10990(suite) ->
+ [];
+otp_10990(Config) when is_list(Config) ->
+ {'EXIT',_} = (catch {foo, erl_scan:string([$",42.0,$"],1)}),
+ ok.
+
+otp_10992(doc) ->
+ "OTP-10992. List of floats to abstract format.";
+otp_10992(suite) ->
+ [];
+otp_10992(Config) when is_list(Config) ->
+ {cons,0,{float,0,42.0},{nil,0}} =
+ erl_parse:abstract([42.0], [{encoding,unicode}]),
+ {cons,0,{float,0,42.0},{nil,0}} =
+ erl_parse:abstract([42.0], [{encoding,utf8}]),
+ {cons,0,{integer,0,65},{cons,0,{float,0,42.0},{nil,0}}} =
+ erl_parse:abstract([$A,42.0], [{encoding,unicode}]),
+ {cons,0,{integer,0,65},{cons,0,{float,0,42.0},{nil,0}}} =
+ erl_parse:abstract([$A,42.0], [{encoding,utf8}]),
+ ok.
+
test_string(String, Expected) ->
{ok, Expected, _End} = erl_scan:string(String),
test(String).
diff --git a/lib/stdlib/test/gen_event_SUITE.erl b/lib/stdlib/test/gen_event_SUITE.erl
index 5c51e12e35..6be5a299b6 100644
--- a/lib/stdlib/test/gen_event_SUITE.erl
+++ b/lib/stdlib/test/gen_event_SUITE.erl
@@ -26,13 +26,14 @@
delete_handler/1, swap_handler/1, swap_sup_handler/1,
notify/1, sync_notify/1, call/1, info/1, hibernate/1,
call_format_status/1, call_format_status_anon/1,
- error_format_status/1]).
+ error_format_status/1, get_state/1, replace_state/1]).
suite() -> [{ct_hooks,[ts_install_cth]}].
all() ->
[start, {group, test_all}, hibernate,
- call_format_status, call_format_status_anon, error_format_status].
+ call_format_status, call_format_status_anon, error_format_status,
+ get_state, replace_state].
groups() ->
[{test_all, [],
@@ -956,3 +957,45 @@ error_format_status(Config) when is_list(Config) ->
?line ok = gen_event:stop(Pid),
process_flag(trap_exit, OldFl),
ok.
+
+get_state(suite) ->
+ [];
+get_state(doc) ->
+ ["Test that sys:get_state/1,2 return the gen_event state"];
+get_state(Config) when is_list(Config) ->
+ {ok, Pid} = gen_event:start({local, my_dummy_handler}),
+ State1 = self(),
+ ok = gen_event:add_handler(my_dummy_handler, dummy1_h, [State1]),
+ [{dummy1_h,false,State1}] = sys:get_state(Pid),
+ [{dummy1_h,false,State1}] = sys:get_state(Pid, 5000),
+ State2 = {?MODULE, self()},
+ ok = gen_event:add_handler(my_dummy_handler, {dummy1_h,id}, [State2]),
+ Result1 = sys:get_state(Pid),
+ [{dummy1_h,false,State1},{dummy1_h,id,State2}] = lists:sort(Result1),
+ Result2 = sys:get_state(Pid, 5000),
+ [{dummy1_h,false,State1},{dummy1_h,id,State2}] = lists:sort(Result2),
+ ok = gen_event:stop(Pid),
+ ok.
+
+replace_state(suite) ->
+ [];
+replace_state(doc) ->
+ ["Test that replace_state/2,3 replace the gen_event state"];
+replace_state(Config) when is_list(Config) ->
+ {ok, Pid} = gen_event:start({local, my_dummy_handler}),
+ State1 = self(),
+ ok = gen_event:add_handler(my_dummy_handler, dummy1_h, [State1]),
+ [{dummy1_h,false,State1}] = sys:get_state(Pid),
+ NState1 = "replaced",
+ Replace1 = fun({dummy1_h,false,_}=S) -> setelement(3,S,NState1) end,
+ [{dummy1_h,false,NState1}] = sys:replace_state(Pid, Replace1),
+ [{dummy1_h,false,NState1}] = sys:get_state(Pid),
+ NState2 = "replaced again",
+ Replace2 = fun({dummy1_h,false,_}=S) -> setelement(3,S,NState2) end,
+ [{dummy1_h,false,NState2}] = sys:replace_state(Pid, Replace2, 5000),
+ [{dummy1_h,false,NState2}] = sys:get_state(Pid),
+ %% verify no change in state if replace function crashes
+ Replace3 = fun(_) -> exit(fail) end,
+ [{dummy1_h,false,NState2}] = sys:replace_state(Pid, Replace3),
+ [{dummy1_h,false,NState2}] = sys:get_state(Pid),
+ ok.
diff --git a/lib/stdlib/test/gen_fsm_SUITE.erl b/lib/stdlib/test/gen_fsm_SUITE.erl
index a637a8543b..fd15838b7d 100644
--- a/lib/stdlib/test/gen_fsm_SUITE.erl
+++ b/lib/stdlib/test/gen_fsm_SUITE.erl
@@ -31,7 +31,7 @@
-export([shutdown/1]).
--export([ sys1/1, call_format_status/1, error_format_status/1]).
+-export([ sys1/1, call_format_status/1, error_format_status/1, get_state/1, replace_state/1]).
-export([hibernate/1,hiber_idle/3,hiber_wakeup/3,hiber_idle/2,hiber_wakeup/2]).
@@ -66,7 +66,7 @@ groups() ->
start8, start9, start10, start11, start12]},
{abnormal, [], [abnormal1, abnormal2]},
{sys, [],
- [sys1, call_format_status, error_format_status]}].
+ [sys1, call_format_status, error_format_status, get_state, replace_state]}].
init_per_suite(Config) ->
Config.
@@ -413,6 +413,40 @@ error_format_status(Config) when is_list(Config) ->
process_flag(trap_exit, OldFl),
ok.
+get_state(Config) when is_list(Config) ->
+ State = self(),
+ {ok, Pid} = gen_fsm:start(?MODULE, {state_data, State}, []),
+ {idle, State} = sys:get_state(Pid),
+ {idle, State} = sys:get_state(Pid, 5000),
+ stop_it(Pid),
+
+ %% check that get_state can handle a name being an atom (pid is
+ %% already checked by the previous test)
+ {ok, Pid2} = gen_fsm:start({local, gfsm}, gen_fsm_SUITE, {state_data, State}, []),
+ {idle, State} = sys:get_state(gfsm),
+ {idle, State} = sys:get_state(gfsm, 5000),
+ stop_it(Pid2),
+ ok.
+
+replace_state(Config) when is_list(Config) ->
+ State = self(),
+ {ok, Pid} = gen_fsm:start(?MODULE, {state_data, State}, []),
+ {idle, State} = sys:get_state(Pid),
+ NState1 = "replaced",
+ Replace1 = fun({StateName, _}) -> {StateName, NState1} end,
+ {idle, NState1} = sys:replace_state(Pid, Replace1),
+ {idle, NState1} = sys:get_state(Pid),
+ NState2 = "replaced again",
+ Replace2 = fun({idle, _}) -> {state0, NState2} end,
+ {state0, NState2} = sys:replace_state(Pid, Replace2, 5000),
+ {state0, NState2} = sys:get_state(Pid),
+ %% verify no change in state if replace function crashes
+ Replace3 = fun(_) -> error(fail) end,
+ {state0, NState2} = sys:replace_state(Pid, Replace3),
+ {state0, NState2} = sys:get_state(Pid),
+ stop_it(Pid),
+ ok.
+
%% Hibernation
hibernate(suite) -> [];
hibernate(Config) when is_list(Config) ->
diff --git a/lib/stdlib/test/gen_server_SUITE.erl b/lib/stdlib/test/gen_server_SUITE.erl
index dffeadb423..3b6a3f38bc 100644
--- a/lib/stdlib/test/gen_server_SUITE.erl
+++ b/lib/stdlib/test/gen_server_SUITE.erl
@@ -32,7 +32,7 @@
spec_init_local_registered_parent/1,
spec_init_global_registered_parent/1,
otp_5854/1, hibernate/1, otp_7669/1, call_format_status/1,
- error_format_status/1, call_with_huge_message_queue/1
+ error_format_status/1, get_state/1, replace_state/1, call_with_huge_message_queue/1
]).
% spawn export
@@ -57,6 +57,7 @@ all() ->
spec_init_local_registered_parent,
spec_init_global_registered_parent, otp_5854, hibernate,
otp_7669, call_format_status, error_format_status,
+ get_state, replace_state,
call_with_huge_message_queue].
groups() ->
@@ -1033,6 +1034,51 @@ error_format_status(Config) when is_list(Config) ->
process_flag(trap_exit, OldFl),
ok.
+%% Verify that sys:get_state correctly returns gen_server state
+%%
+get_state(suite) ->
+ [];
+get_state(doc) ->
+ ["Test that sys:get_state/1,2 return the gen_server state"];
+get_state(Config) when is_list(Config) ->
+ State = self(),
+ {ok, _Pid} = gen_server:start_link({local, get_state},
+ ?MODULE, {state,State}, []),
+ State = sys:get_state(get_state),
+ State = sys:get_state(get_state, 5000),
+ {ok, Pid} = gen_server:start_link(?MODULE, {state,State}, []),
+ State = sys:get_state(Pid),
+ State = sys:get_state(Pid, 5000),
+ ok.
+
+%% Verify that sys:replace_state correctly replaces gen_server state
+%%
+replace_state(suite) ->
+ [];
+replace_state(doc) ->
+ ["Test that sys:replace_state/1,2 replace the gen_server state"];
+replace_state(Config) when is_list(Config) ->
+ State = self(),
+ {ok, _Pid} = gen_server:start_link({local, replace_state},
+ ?MODULE, {state,State}, []),
+ State = sys:get_state(replace_state),
+ NState1 = "replaced",
+ Replace1 = fun(_) -> NState1 end,
+ NState1 = sys:replace_state(replace_state, Replace1),
+ NState1 = sys:get_state(replace_state),
+ {ok, Pid} = gen_server:start_link(?MODULE, {state,NState1}, []),
+ NState1 = sys:get_state(Pid),
+ Suffix = " again",
+ NState2 = NState1 ++ Suffix,
+ Replace2 = fun(S) -> S ++ Suffix end,
+ NState2 = sys:replace_state(Pid, Replace2, 5000),
+ NState2 = sys:get_state(Pid, 5000),
+ %% verify no change in state if replace function crashes
+ Replace3 = fun(_) -> throw(fail) end,
+ NState2 = sys:replace_state(Pid, Replace3),
+ NState2 = sys:get_state(Pid, 5000),
+ ok.
+
%% 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) ->
diff --git a/lib/stdlib/test/io_proto_SUITE.erl b/lib/stdlib/test/io_proto_SUITE.erl
index e16ba55481..76a8109a8d 100644
--- a/lib/stdlib/test/io_proto_SUITE.erl
+++ b/lib/stdlib/test/io_proto_SUITE.erl
@@ -147,8 +147,7 @@ unicode_prompt(Config) when is_list(Config) ->
%% And one with oldshell
?line rtnode([{putline,""},
{putline, "2."},
- {getline_re, ".*2."},
- {getline, "2"},
+ {getline_re, ".*2$"},
{putline, "shell:prompt_func({io_proto_SUITE,uprompt})."},
{getline_re, ".*default"},
{putline, "io:get_line('')."},
@@ -263,8 +262,7 @@ setopts_getopts(Config) when is_list(Config) ->
%% And one with oldshell
?line rtnode([{putline,""},
{putline, "2."},
- {getline_re, ".*2."},
- {getline, "2"},
+ {getline_re, ".*2$"},
{putline, "lists:keyfind(binary,1,io:getopts())."},
{getline_re, ".*{binary,false}"},
{putline, "io:get_line('')."},
@@ -467,8 +465,7 @@ unicode_options(Config) when is_list(Config) ->
end,
?line rtnode([{putline,""},
{putline, "2."},
- {getline_re, ".*2."},
- {getline, "2"},
+ {getline_re, ".*2$"},
{putline, "lists:keyfind(encoding,1,io:getopts())."},
{getline_re, ".*{encoding,latin1}"},
{putline, "io:format(\"~ts~n\",[[1024]])."},
@@ -701,8 +698,7 @@ binary_options(Config) when is_list(Config) ->
old ->
ok;
new ->
- ?line rtnode([{putline,""},
- {putline, "2."},
+ ?line rtnode([{putline, "2."},
{getline, "2"},
{putline, "lists:keyfind(binary,1,io:getopts())."},
{getline, "{binary,false}"},
@@ -720,10 +716,8 @@ binary_options(Config) when is_list(Config) ->
],[])
end,
%% And one with oldshell
- ?line rtnode([{putline,""},
- {putline, "2."},
- {getline_re, ".*2."},
- {getline, "2"},
+ ?line rtnode([{putline, "2."},
+ {getline_re, ".*2$"},
{putline, "lists:keyfind(binary,1,io:getopts())."},
{getline_re, ".*{binary,false}"},
{putline, "io:get_line('')."},
diff --git a/lib/tools/emacs/erlang-start.el b/lib/tools/emacs/erlang-start.el
index bbcea3e46a..e1dc86621e 100644
--- a/lib/tools/emacs/erlang-start.el
+++ b/lib/tools/emacs/erlang-start.el
@@ -83,6 +83,7 @@
;; Associate files extensions ".erl" and ".hrl" with Erlang mode.
;;
+;;;###autoload
(let ((a '("\\.erl\\'" . erlang-mode))
(b '("\\.hrl\\'" . erlang-mode)))
(or (assoc (car a) auto-mode-alist)
@@ -94,6 +95,7 @@
;; Associate files using interpreter "escript" with Erlang mode.
;;
+;;;###autoload
(add-to-list 'interpreter-mode-alist (cons "escript" 'erlang-mode))
;;
@@ -101,6 +103,7 @@
;; file completion.
;;
+;;;###autoload
(let ((erl-ext '(".jam" ".vee" ".beam")))
(while erl-ext
(let ((cie completion-ignored-extensions))