aboutsummaryrefslogtreecommitdiffstats
path: root/lib
diff options
context:
space:
mode:
Diffstat (limited to 'lib')
-rw-r--r--lib/asn1/doc/src/notes.xml17
-rw-r--r--lib/asn1/src/asn1ct_check.erl8
-rw-r--r--lib/asn1/test/asn1_SUITE.erl5
-rw-r--r--lib/asn1/test/asn1_SUITE_data/Param2.asn148
-rw-r--r--lib/asn1/test/testParameterizedInfObj.erl57
-rw-r--r--lib/asn1/vsn.mk2
-rw-r--r--lib/common_test/priv/ct_default.css8
-rw-r--r--lib/common_test/src/ct_framework.erl11
-rw-r--r--lib/common_test/src/ct_logs.erl1095
-rw-r--r--lib/common_test/src/ct_run.erl14
-rw-r--r--lib/common_test/src/ct_telnet.erl46
-rw-r--r--lib/common_test/src/ct_util.erl2
-rw-r--r--lib/common_test/src/cth_log_redirect.erl8
-rw-r--r--lib/common_test/test/ct_cover_SUITE_data/cover_SUITE.erl50
-rw-r--r--lib/common_test/test/ct_repeat_testrun_SUITE.erl4
-rw-r--r--lib/common_test/test/ct_test_support.erl39
-rw-r--r--lib/compiler/src/beam_receive.erl92
-rw-r--r--lib/compiler/test/receive_SUITE.erl13
-rw-r--r--lib/compiler/test/receive_SUITE_data/ref_opt/yes_14.S71
-rw-r--r--lib/compiler/test/receive_SUITE_data/ref_opt/yes_5.erl6
-rw-r--r--lib/crypto/c_src/crypto.c863
-rw-r--r--[-rwxr-xr-x]lib/crypto/doc/src/crypto.xml1548
-rw-r--r--lib/crypto/doc/src/crypto_app.xml79
-rw-r--r--lib/crypto/src/crypto.erl692
-rw-r--r--lib/crypto/test/crypto_SUITE.erl312
-rw-r--r--lib/debugger/src/dbg_debugged.erl14
-rw-r--r--lib/debugger/src/dbg_istk.erl2
-rw-r--r--lib/dialyzer/src/dialyzer_gui.erl5
-rw-r--r--lib/dialyzer/src/dialyzer_gui_wx.erl5
-rw-r--r--lib/dialyzer/test/behaviour_SUITE_data/src/custom_sup.erl2
-rw-r--r--lib/diameter/doc/src/diameter.xml11
-rw-r--r--lib/diameter/doc/src/diameter_tcp.xml20
-rw-r--r--lib/diameter/doc/src/diameter_transport.xml30
-rw-r--r--lib/diameter/examples/code/peer.erl28
-rw-r--r--lib/diameter/src/Makefile2
-rw-r--r--lib/diameter/src/base/diameter_peer.erl8
-rw-r--r--lib/diameter/src/base/diameter_peer_fsm.erl13
-rw-r--r--lib/diameter/src/base/diameter_service.erl24
-rw-r--r--lib/diameter/src/transport/diameter_tcp.erl79
-rw-r--r--lib/diameter/test/diameter_capx_SUITE.erl2
-rw-r--r--lib/diameter/test/diameter_event_SUITE.erl2
-rw-r--r--lib/diameter/test/diameter_examples_SUITE.erl2
-rw-r--r--lib/diameter/test/diameter_tls_SUITE.erl2
-rw-r--r--lib/diameter/test/diameter_transport_SUITE.erl122
-rw-r--r--lib/diameter/test/diameter_util.erl29
-rw-r--r--lib/diameter/test/diameter_watchdog_SUITE.erl2
-rw-r--r--lib/et/doc/src/et_desc.xmlsrc2
-rw-r--r--lib/et/src/et_collector.erl9
-rw-r--r--lib/hipe/icode/hipe_icode_coordinator.erl18
-rw-r--r--lib/hipe/main/hipe.erl21
-rw-r--r--lib/ic/java_src/com/ericsson/otp/ic/Environment.java4
-rw-r--r--lib/ic/src/icparse.yrl3
-rw-r--r--lib/inets/src/http_server/httpd_manager.erl4
-rw-r--r--lib/jinterface/test/jinterface_SUITE.erl3
-rw-r--r--lib/jinterface/test/jitu.erl38
-rw-r--r--lib/jinterface/test/nc_SUITE.erl12
-rw-r--r--lib/kernel/src/application_master.erl9
-rw-r--r--lib/kernel/src/disk_log.erl18
-rw-r--r--lib/kernel/src/file.erl43
-rw-r--r--lib/kernel/src/file_io_server.erl3
-rw-r--r--lib/kernel/src/file_server.erl3
-rw-r--r--lib/kernel/src/inet_gethost_native.erl3
-rw-r--r--lib/kernel/src/rpc.erl24
-rw-r--r--lib/kernel/test/file_SUITE.erl29
-rw-r--r--lib/kernel/test/gen_sctp_SUITE.erl3
-rw-r--r--lib/kernel/test/global_SUITE_data/global_trace.erl9
-rw-r--r--lib/orber/src/orber_iiop_outproxy.erl35
-rw-r--r--lib/public_key/asn1/ECPrivateKey.asn124
-rw-r--r--lib/public_key/asn1/OTP-PKIX.asn130
-rw-r--r--lib/public_key/asn1/OTP-PUB-KEY.set.asn1
-rw-r--r--lib/public_key/asn1/PKCS-1.asn132
-rw-r--r--lib/public_key/asn1/PKIX1Algorithms88.asn1118
-rw-r--r--lib/public_key/doc/src/public_key.xml47
-rw-r--r--lib/public_key/include/public_key.hrl8
-rw-r--r--lib/public_key/src/pubkey_cert_records.erl88
-rw-r--r--lib/public_key/src/pubkey_pem.erl16
-rw-r--r--lib/public_key/src/public_key.erl185
-rw-r--r--lib/public_key/test/erl_make_certs.erl71
-rw-r--r--lib/public_key/test/pkits_SUITE.erl11
-rw-r--r--lib/public_key/test/public_key_SUITE.erl2
-rw-r--r--lib/reltool/test/reltool_server_SUITE.erl6
-rw-r--r--lib/runtime_tools/src/dbg.erl6
-rw-r--r--lib/runtime_tools/src/ttb_autostart.erl1
-rw-r--r--lib/sasl/test/release_handler_SUITE.erl8
-rw-r--r--lib/snmp/src/agent/snmpa_target_cache.erl37
-rw-r--r--lib/ssh/src/ssh_cli.erl4
-rw-r--r--lib/ssh/src/ssh_xfer.erl26
-rw-r--r--lib/ssl/doc/src/ssl.xml15
-rw-r--r--lib/ssl/src/ssl.erl18
-rw-r--r--lib/ssl/src/ssl_certificate.erl15
-rw-r--r--lib/ssl/src/ssl_certificate_db.erl2
-rw-r--r--lib/ssl/src/ssl_cipher.erl450
-rw-r--r--lib/ssl/src/ssl_cipher.hrl120
-rw-r--r--lib/ssl/src/ssl_connection.erl207
-rw-r--r--lib/ssl/src/ssl_handshake.erl348
-rw-r--r--lib/ssl/src/ssl_handshake.hrl52
-rw-r--r--lib/ssl/src/ssl_internal.hrl6
-rw-r--r--lib/ssl/src/ssl_manager.erl4
-rw-r--r--lib/ssl/src/ssl_record.erl10
-rw-r--r--lib/ssl/src/ssl_ssl3.erl10
-rw-r--r--lib/ssl/src/ssl_tls1.erl115
-rw-r--r--lib/ssl/test/erl_make_certs.erl69
-rw-r--r--lib/ssl/test/ssl_basic_SUITE.erl204
-rw-r--r--lib/ssl/test/ssl_certificate_verify_SUITE.erl18
-rw-r--r--lib/ssl/test/ssl_npn_handshake_SUITE.erl12
-rw-r--r--lib/ssl/test/ssl_npn_hello_SUITE.erl16
-rw-r--r--lib/ssl/test/ssl_packet_SUITE.erl4
-rw-r--r--lib/ssl/test/ssl_payload_SUITE.erl12
-rw-r--r--lib/ssl/test/ssl_session_cache_SUITE.erl2
-rw-r--r--lib/ssl/test/ssl_test_lib.erl286
-rw-r--r--lib/ssl/test/ssl_to_openssl_SUITE.erl129
-rw-r--r--lib/stdlib/doc/src/lists.xml25
-rw-r--r--lib/stdlib/doc/src/unicode_usage.xml1
-rw-r--r--lib/stdlib/src/dets.erl9
-rw-r--r--lib/stdlib/src/epp.erl5
-rw-r--r--lib/stdlib/src/gen.erl31
-rw-r--r--lib/stdlib/src/gen_server.erl18
-rw-r--r--lib/stdlib/src/io.erl6
-rw-r--r--lib/stdlib/src/lists.erl24
-rw-r--r--lib/stdlib/src/otp_internal.erl133
-rw-r--r--lib/stdlib/src/supervisor.erl27
-rw-r--r--lib/stdlib/src/timer.erl4
-rw-r--r--lib/stdlib/test/Makefile1
-rw-r--r--lib/stdlib/test/dets_SUITE.erl77
-rw-r--r--lib/stdlib/test/epp_SUITE.erl4
-rw-r--r--lib/stdlib/test/erl_eval_SUITE.erl3
-rw-r--r--lib/stdlib/test/ets_SUITE.erl85
-rw-r--r--lib/stdlib/test/lists_SUITE.erl4
-rw-r--r--lib/stdlib/test/qlc_SUITE_data/join_info_compat.erl215
-rw-r--r--lib/stdlib/test/shell_SUITE.erl3
-rw-r--r--lib/stdlib/test/supervisor_3.erl45
-rw-r--r--lib/stdlib/test/supervisor_SUITE.erl106
-rw-r--r--lib/test_server/src/erl2html2.erl3
-rw-r--r--lib/test_server/src/test_server_ctrl.erl4
-rw-r--r--lib/test_server/src/test_server_io.erl17
-rw-r--r--lib/test_server/test/test_server_SUITE.erl13
-rw-r--r--lib/tools/src/fprof.erl8
137 files changed, 6345 insertions, 3158 deletions
diff --git a/lib/asn1/doc/src/notes.xml b/lib/asn1/doc/src/notes.xml
index e619408591..76d605569d 100644
--- a/lib/asn1/doc/src/notes.xml
+++ b/lib/asn1/doc/src/notes.xml
@@ -31,6 +31,23 @@
<p>This document describes the changes made to the asn1 application.</p>
+<section><title>Asn1 2.0.1.2</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>
+ When an object set is an actual parameter, the extension
+ marker for the object set could get lost (which would
+ cause the decoding of unknown values to fail).</p>
+ <p>
+ Own Id: OTP-10995 Aux Id: seq12290 </p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
<section><title>Asn1 2.0.1.1</title>
<section><title>Fixed Bugs and Malfunctions</title>
diff --git a/lib/asn1/src/asn1ct_check.erl b/lib/asn1/src/asn1ct_check.erl
index e1911d8170..0622998445 100644
--- a/lib/asn1/src/asn1ct_check.erl
+++ b/lib/asn1/src/asn1ct_check.erl
@@ -1025,8 +1025,8 @@ prepare_objset({{'SingleValue',Set},Ext}) ->
%% {set,lists:append([Set,Ext]),true};
prepare_objset({Set,Ext}) when is_list(Set) ->
{set,merge_sets(Set,Ext),true};
-prepare_objset({ObjDef={object,definedsyntax,_ObjFields},_Ext}) ->
- {set,[ObjDef],true};
+prepare_objset({{object,definedsyntax,_ObjFields}=Set,Ext}) ->
+ {set,merge_sets(Set, Ext),true};
prepare_objset(ObjDef={object,definedsyntax,_ObjFields}) ->
{set,[ObjDef],false};
prepare_objset({ObjDef=#type{},Ext}) when is_list(Ext) ->
@@ -4034,8 +4034,8 @@ categorize(S,value,Type,Value) ->
[#valuedef{type=Type,value=Value,module=S#state.mname}].
-parse_objectset({valueset,T=#type{}}) ->
- [T];
+parse_objectset({valueset,#type{def=#'Externaltypereference'{}=Ref}}) ->
+ Ref;
parse_objectset({valueset,Set}) ->
Set;
parse_objectset(#type{def=Ref}) when is_record(Ref,'Externaltypereference') ->
diff --git a/lib/asn1/test/asn1_SUITE.erl b/lib/asn1/test/asn1_SUITE.erl
index 62418e554e..8deabece37 100644
--- a/lib/asn1/test/asn1_SUITE.erl
+++ b/lib/asn1/test/asn1_SUITE.erl
@@ -829,8 +829,9 @@ testInfObjectClass(Config, Rule, Opts) ->
testParameterizedInfObj(Config) ->
test(Config, fun testParameterizedInfObj/3).
testParameterizedInfObj(Config, Rule, Opts) ->
- asn1_test_lib:compile("Param", Config, [Rule|Opts]),
- testParameterizedInfObj:main(Rule).
+ Files = ["Param","Param2"],
+ asn1_test_lib:compile_all(Files, Config, [Rule|Opts]),
+ testParameterizedInfObj:main(Config, Rule).
testMergeCompile(Config) -> test(Config, fun testMergeCompile/3).
testMergeCompile(Config, Rule, Opts) ->
diff --git a/lib/asn1/test/asn1_SUITE_data/Param2.asn1 b/lib/asn1/test/asn1_SUITE_data/Param2.asn1
new file mode 100644
index 0000000000..09ccb367d8
--- /dev/null
+++ b/lib/asn1/test/asn1_SUITE_data/Param2.asn1
@@ -0,0 +1,48 @@
+Param2 DEFINITIONS AUTOMATIC TAGS ::=
+BEGIN
+
+ S1AP-PROTOCOL-IES ::= CLASS {
+ &id INTEGER UNIQUE,
+ &Value
+ }
+ WITH SYNTAX {
+ ID &id
+ TYPE &Value
+ }
+
+ ProtocolIE-Field {S1AP-PROTOCOL-IES : IEsSetParam} ::= SEQUENCE {
+ id S1AP-PROTOCOL-IES.&id ({IEsSetParam}),
+ value S1AP-PROTOCOL-IES.&Value ({IEsSetParam}{@id})
+ }
+
+ ProtocolIE-Container {S1AP-PROTOCOL-IES : IEsSetParam} ::=
+ SEQUENCE (SIZE (0..10)) OF ProtocolIE-Field {{IEsSetParam}}
+
+ HandoverRequired ::= SEQUENCE {
+ protocolIEs ProtocolIE-Container { { HandoverRequiredIEs } },
+ ...
+ }
+
+ HandoverRequiredIEs S1AP-PROTOCOL-IES ::= {
+ { ID 1 TYPE OCTET STRING } |
+ { ID 2 TYPE INTEGER },
+--Delete-start
+ ...,
+ { ID 100 TYPE INTEGER (0..1023) } |
+ { ID 101 TYPE ENUMERATED {true,false} }
+--Delete-end
+ }
+
+ SingleRoot ::= SEQUENCE {
+ protocolIEs ProtocolIE-Container { { SingleRootIEs } },
+ ...
+ }
+
+ -- The extension was lost when there was a single root item.
+ SingleRootIEs S1AP-PROTOCOL-IES ::= {
+ { ID 1 TYPE OCTET STRING },
+ ...,
+ { ID 2 TYPE INTEGER }
+ }
+
+END
diff --git a/lib/asn1/test/testParameterizedInfObj.erl b/lib/asn1/test/testParameterizedInfObj.erl
index 17108e285b..212df79fd4 100644
--- a/lib/asn1/test/testParameterizedInfObj.erl
+++ b/lib/asn1/test/testParameterizedInfObj.erl
@@ -20,7 +20,7 @@
-module(testParameterizedInfObj).
--export([main/1,ranap/1]).
+-export([main/2,ranap/1]).
-include_lib("test_server/include/test_server.hrl").
@@ -31,7 +31,11 @@
-record('Iu-ReleaseCommand',{protocolIEs,protocolExtensions}).
-main(Erule) ->
+main(Config, Erule) ->
+ param(Erule),
+ param2(Config, Erule).
+
+param(Erule) ->
PERVal = #'AllocationOrRetentionPriority'
{priorityLevel = true,
iE_Extensions =
@@ -84,7 +88,6 @@ main(Erule) ->
ok.
-
ranap(_Erule) ->
PIEVal2 = [{'ProtocolIE-Field',4,ignore,{radioNetwork,'rab-pre-empted'}}],
?line Val2 =
@@ -102,3 +105,51 @@ open_type(uper,Val) when is_list(Val) ->
list_to_binary(Val);
open_type(_,Val) ->
Val.
+
+param2(Config, Erule) ->
+ roundtrip2('HandoverRequired',
+ {'HandoverRequired',
+ [{'ProtocolIE-Field',1,"ABC"},
+ {'ProtocolIE-Field',2,577799}]}),
+ Enc = roundtrip2('HandoverRequired',
+ {'HandoverRequired',
+ [{'ProtocolIE-Field',1,"ABC"},
+ {'ProtocolIE-Field',2,-42},
+ {'ProtocolIE-Field',100,533},
+ {'ProtocolIE-Field',101,true}]}),
+
+ %% Now remove the data after the extension mark in the object set.
+ DataDir = ?config(data_dir, Config),
+ CaseDir = ?config(case_dir, Config),
+ Asn1SrcBase = "Param2.asn1",
+ Asn1SrcFile0 = filename:join(DataDir, Asn1SrcBase),
+ {ok,Src0} = file:read_file(Asn1SrcFile0),
+ Src = re:replace(Src0, "--Delete-start.*?--Delete-end", "...\n",
+ [dotall,global,{return,binary}]),
+ io:format("~s\n\n", [Src]),
+
+ Asn1SrcFile = filename:join(CaseDir, Asn1SrcBase),
+ ok = file:write_file(Asn1SrcFile, Src),
+ ok = asn1ct:compile(Asn1SrcFile,
+ [{i,DataDir},{outdir,CaseDir},Erule]),
+
+ %% Decompile extended data.
+ {ok,{'HandoverRequired',[{'ProtocolIE-Field',1,"ABC"},
+ {'ProtocolIE-Field',2,-42},
+ {'ProtocolIE-Field',100,Open100},
+ {'ProtocolIE-Field',101,Open101}]}} =
+ asn1_wrapper:decode('Param2', 'HandoverRequired', Enc),
+ true = is_binary(Open100),
+ true = is_binary(Open101),
+
+ %% Test single root.
+ roundtrip2('SingleRoot',
+ {'SingleRoot',[{'ProtocolIE-Field',1,"ABC"},
+ {'ProtocolIE-Field',2,9999}]}),
+ ok.
+
+
+roundtrip2(T, V) ->
+ {ok,Enc} = asn1_wrapper:encode('Param2', T, V),
+ {ok,V} = asn1_wrapper:decode('Param2', T, Enc),
+ Enc.
diff --git a/lib/asn1/vsn.mk b/lib/asn1/vsn.mk
index 3c4f3ff122..9245f83280 100644
--- a/lib/asn1/vsn.mk
+++ b/lib/asn1/vsn.mk
@@ -1,2 +1,2 @@
#next version number to use is 2.0
-ASN1_VSN = 2.0.1.1
+ASN1_VSN = 2.0.1.2
diff --git a/lib/common_test/priv/ct_default.css b/lib/common_test/priv/ct_default.css
index 1188f8f676..ff48b4fdc0 100644
--- a/lib/common_test/priv/ct_default.css
+++ b/lib/common_test/priv/ct_default.css
@@ -96,6 +96,14 @@ div.ct_error_notify {
margin: .2em 0 0 0;
}
+div.ct_error_notify a:link {
+ color: #D0D0D0;
+}
+
+div.ct_error_notify a:visited {
+ color: #AAAAAA;
+}
+
div.default {
background: lightgreen; color: black;
font-family: "Monaco", "Andale Mono", "Consolas", monospace;
diff --git a/lib/common_test/src/ct_framework.erl b/lib/common_test/src/ct_framework.erl
index b92fe1555f..276f902b05 100644
--- a/lib/common_test/src/ct_framework.erl
+++ b/lib/common_test/src/ct_framework.erl
@@ -32,6 +32,7 @@
-export([error_in_suite/1, init_per_suite/1, end_per_suite/1,
init_per_group/2, end_per_group/2]).
+-include("ct.hrl").
-include("ct_event.hrl").
-include("ct_util.hrl").
@@ -806,8 +807,14 @@ error_notification(Mod,Func,_Args,{Error,Loc}) ->
"- - - - - - - - - -~n",
io:format(user, lists:concat([Div,ErrFormat,Div,"~n"]),
ErrArgs),
- ct_logs:tc_log(ct_error_notify, "CT Error Notification",
- ErrFormat, ErrArgs)
+ Link =
+ "\n\n<a href=\"#end\">"
+ "Full error description and stacktrace"
+ "</a>",
+ ct_logs:tc_log(ct_error_notify,
+ ?MAX_IMPORTANCE,
+ "CT Error Notification",
+ ErrFormat++Link, ErrArgs)
end,
case Loc of
[{?MODULE,error_in_suite}] ->
diff --git a/lib/common_test/src/ct_logs.erl b/lib/common_test/src/ct_logs.erl
index 752033fdff..f5355bfefe 100644
--- a/lib/common_test/src/ct_logs.erl
+++ b/lib/common_test/src/ct_logs.erl
@@ -41,7 +41,8 @@
-export([uri/1]).
%% Logging stuff directly from testcase
--export([tc_log/3, tc_log/4, tc_log_async/3, tc_print/3, tc_print/4,
+-export([tc_log/3, tc_log/4, tc_log/5, tc_log_async/3, tc_log_async/5,
+ tc_print/3, tc_print/4,
tc_pal/3, tc_pal/4, ct_log/3, basic_html/0]).
%% Simulate logger process for use without ct environment running
@@ -59,6 +60,7 @@
-define(all_runs_name, "all_runs.html").
-define(index_name, "index.html").
-define(totals_name, "totals.info").
+-define(log_cache_name, "ct_log_cache").
-define(table_color1,"#ADD8E6").
-define(table_color2,"#E4F0FE").
@@ -68,6 +70,10 @@
-define(abs(Name), filename:absname(Name)).
+-record(log_cache, {version,
+ all_runs = [],
+ tests = []}).
+
%%%-----------------------------------------------------------------
%%% @spec init(Mode) -> Result
%%% Mode = normal | interactive
@@ -93,14 +99,25 @@ init(Mode, Verbosity) ->
exit({could_not_start_process,?MODULE,Reason})
end.
-make_dirname({{YY,MM,DD},{H,M,S}}) ->
- io_lib:format(logdir_node_prefix()++".~w-~2.2.0w-~2.2.0w_~2.2.0w.~2.2.0w.~2.2.0w",
- [YY,MM,DD,H,M,S]).
-
+date2str({{YY,MM,DD},{H,M,S}}) ->
+ lists:flatten(io_lib:format("~w-~2.2.0w-~2.2.0w_~2.2.0w.~2.2.0w.~2.2.0w",
+ [YY,MM,DD,H,M,S])).
logdir_prefix() ->
"ct_run".
logdir_node_prefix() ->
- logdir_prefix()++"."++atom_to_list(node()).
+ logdir_prefix() ++ "." ++ atom_to_list(node()).
+
+make_dirname(DateTime) ->
+ logdir_node_prefix() ++ "." ++ date2str(DateTime).
+
+datestr_from_dirname([Y1,Y2,Y3,Y4,$-,Mo1,Mo2,$-,D1,D2,$_,
+ H1,H2,$.,M1,M2,$.,S1,S2 | _]) ->
+ [Y1,Y2,Y3,Y4,$-,Mo1,Mo2,$-,D1,D2,$_,
+ H1,H2,$.,M1,M2,$.,S1,S2];
+datestr_from_dirname([_Ch | Rest]) ->
+ datestr_from_dirname(Rest);
+datestr_from_dirname([]) ->
+ "".
%%%-----------------------------------------------------------------
%%% @spec close(Info, StartDir) -> ok
@@ -108,8 +125,21 @@ logdir_node_prefix() ->
%%% @doc Create index pages with test results and close the CT Log
%%% (tool-internal use only).
close(Info, StartDir) ->
- make_last_run_index(),
-
+ %% close executes on the ct_util process, not on the logger process
+ %% so we need to use a local copy of the log cache data
+ LogCacheBin = make_last_run_index(),
+ put(ct_log_cache,LogCacheBin),
+ Cache2File = fun() ->
+ case get(ct_log_cache) of
+ undefined ->
+ ok;
+ CacheBin ->
+ %% save final version of the log cache to file
+ file:write_file(?log_cache_name,CacheBin),
+ put(ct_log_cache,undefined)
+ end
+ end,
+
ct_event:notify(#event{name=stop_logging,node=node(),data=[]}),
case whereis(?MODULE) of
@@ -132,11 +162,13 @@ close(Info, StartDir) ->
io:format("Warning! Cleanup failed: ~p~n", [Error])
end,
make_all_suites_index(stop),
- make_all_runs_index(stop);
+ make_all_runs_index(stop),
+ Cache2File();
true ->
file:set_cwd(".."),
make_all_suites_index(stop),
make_all_runs_index(stop),
+ Cache2File(),
case ct_util:get_profile_data(browser, StartDir) of
undefined ->
ok;
@@ -168,12 +200,19 @@ clear_stylesheet(TC) ->
%%%-----------------------------------------------------------------
%%% @spec get_log_dir() -> {ok,Dir} | {error,Reason}
get_log_dir() ->
- call({get_log_dir,false}).
+ get_log_dir(false).
%%%-----------------------------------------------------------------
%%% @spec get_log_dir(ReturnAbsName) -> {ok,Dir} | {error,Reason}
get_log_dir(ReturnAbsName) ->
- call({get_log_dir,ReturnAbsName}).
+ case call({get_log_dir,ReturnAbsName}) of
+ {error,does_not_exist} when ReturnAbsName == true ->
+ {ok,filename:absname(".")};
+ {error,does_not_exist} ->
+ {ok,"."};
+ Result ->
+ Result
+ end.
%%%-----------------------------------------------------------------
%%% make_last_run_index() -> ok
@@ -333,8 +372,15 @@ tc_log(Category,Format,Args) ->
%%%-----------------------------------------------------------------
%%% @spec tc_log(Category,Importance,Format,Args) -> ok
+%%% @equiv tc_log(Category,Importance,"User",Format,Args)
+tc_log(Category,Importance,Format,Args) ->
+ tc_log(Category,Importance,"User",Format,Args).
+
+%%%-----------------------------------------------------------------
+%%% @spec tc_log(Category,Importance,Printer,Format,Args) -> ok
%%% Category = atom()
%%% Importance = integer()
+%%% Printer = string()
%%% Format = string()
%%% Args = list()
%%%
@@ -343,9 +389,6 @@ tc_log(Category,Format,Args) ->
%%% <p>This function is called by <code>ct</code> when logging
%%% stuff directly from a testcase (i.e. not from within the CT
%%% framework).</p>
-tc_log(Category,Importance,Format,Args) ->
- tc_log(Category,Importance,"User",Format,Args).
-
tc_log(Category,Importance,Printer,Format,Args) ->
cast({log,sync,self(),group_leader(),Category,Importance,
[{div_header(Category,Printer),[]},
@@ -355,14 +398,15 @@ tc_log(Category,Importance,Printer,Format,Args) ->
%%%-----------------------------------------------------------------
%%% @spec tc_log_async(Category,Format,Args) -> ok
-%%% @equiv tc_log_async(Category,?STD_IMPORTANCE,Format,Args)
+%%% @equiv tc_log_async(Category,?STD_IMPORTANCE,"User",Format,Args)
tc_log_async(Category,Format,Args) ->
- tc_log_async(Category,?STD_IMPORTANCE,Format,Args).
+ tc_log_async(Category,?STD_IMPORTANCE,"User",Format,Args).
%%%-----------------------------------------------------------------
%%% @spec tc_log_async(Category,Importance,Format,Args) -> ok
%%% Category = atom()
%%% Importance = integer()
+%%% Printer = string()
%%% Format = string()
%%% Args = list()
%%%
@@ -373,9 +417,9 @@ tc_log_async(Category,Format,Args) ->
%%% to avoid deadlocks when e.g. the hook that handles SASL printouts
%%% prints to the test case log file at the same time test server
%%% asks ct_logs for an html wrapper.</p>
-tc_log_async(Category,Importance,Format,Args) ->
+tc_log_async(Category,Importance,Printer,Format,Args) ->
cast({log,async,self(),group_leader(),Category,Importance,
- [{div_header(Category),[]},
+ [{div_header(Category,Printer),[]},
{Format,Args},
{div_footer(),[]}]}),
ok.
@@ -515,7 +559,6 @@ log_timestamp({MS,S,US}) ->
logger(Parent, Mode, Verbosity) ->
register(?MODULE,self()),
-
%%! Below is a temporary workaround for the limitation of
%%! max one test run per second.
%%! --->
@@ -561,9 +604,10 @@ logger(Parent, Mode, Verbosity) ->
ok ->
case copy_priv_files(PrivFilesSrc, PrivFilesDestRun) of
{error,Src2,Dest2,Reason2} ->
- io:format(user, "ERROR! "++
- "Priv file ~p could not be copied to ~p. "++
- "Reason: ~p~n",
+ io:format(user,
+ "ERROR! "++
+ "Priv file ~p could not be copied to ~p. "
+ ++"Reason: ~p~n",
[Src2,Dest2,Reason2]),
exit({priv_file_error,Dest2});
ok ->
@@ -687,7 +731,7 @@ logger_loop(State) ->
logger_loop(State);
{make_last_run_index,From} ->
make_last_run_index(State#logger_state.start_time),
- return(From,filename:basename(State#logger_state.log_dir)),
+ return(From,get(ct_log_cache)),
logger_loop(State);
{set_stylesheet,_,SSFile} when State#logger_state.stylesheet ==
SSFile ->
@@ -946,40 +990,37 @@ print_style_error(Fd,StyleSheet,Reason) ->
print_style(Fd,undefined).
close_ctlog(Fd) ->
- io:format(Fd,"\n</pre>\n",[]),
- io:format(Fd,footer(),[]),
+ io:format(Fd, "\n</pre>\n", []),
+ io:format(Fd, [xhtml("<br><br>\n", "<br /><br />\n") | footer()], []),
file:close(Fd).
-
%%%-----------------------------------------------------------------
%%% Make an index page for the last run
make_last_run_index(StartTime) ->
IndexName = ?index_name,
AbsIndexName = ?abs(IndexName),
- case catch make_last_run_index1(StartTime,IndexName) of
- {'EXIT', Reason} ->
- io:put_chars("CRASHED while updating " ++ AbsIndexName ++ "!\n"),
- io:format("~p~n", [Reason]),
- {error, Reason};
- {error, Reason} ->
- io:put_chars("FAILED while updating " ++ AbsIndexName ++ "\n"),
- io:format("~p~n", [Reason]),
- {error, Reason};
- ok ->
-% io:put_chars("done\n"),
- ok;
- Err ->
- io:format("Unknown internal error while updating ~ts. "
- "Please report.\n(Err: ~p, ID: 1)",
- [AbsIndexName,Err]),
- {error, Err}
- end.
+ Result =
+ case catch make_last_run_index1(StartTime,IndexName) of
+ {'EXIT', Reason} ->
+ io:put_chars("CRASHED while updating " ++ AbsIndexName ++ "!\n"),
+ io:format("~p~n", [Reason]),
+ {error, Reason};
+ {error, Reason} ->
+ io:put_chars("FAILED while updating " ++ AbsIndexName ++ "\n"),
+ io:format("~p~n", [Reason]),
+ {error, Reason};
+ ok ->
+ ok;
+ Err ->
+ io:format("Unknown internal error while updating ~ts. "
+ "Please report.\n(Err: ~p, ID: 1)",
+ [AbsIndexName,Err]),
+ {error, Err}
+ end,
+ Result.
make_last_run_index1(StartTime,IndexName) ->
- %% this manoeuvre is to ensure the tests get logged
- %% in correct order of time (the 1 sec resolution
- %% of the dirnames may be too big)
Logs1 =
case filelib:wildcard([$*|?logdir_ext]) of
[Log] -> % first test
@@ -1007,7 +1048,8 @@ make_last_run_index1(StartTime,IndexName) ->
0, 0, 0, 0, 0, Missing),
%% write current Totals to file, later to be used in all_runs log
write_totals_file(?totals_name,Label,Logs1,Totals),
- Index = [Index0|index_footer()],
+ Index = [Index0|last_run_index_footer()],
+
case force_write_file(IndexName, unicode:characters_to_binary(Index)) of
ok ->
ok;
@@ -1046,22 +1088,26 @@ make_last_run_index([Name|Rest], Result, TotSucc, TotFail,
TotNotBuilt1, Missing)
end;
-make_last_run_index([], Result, TotSucc, TotFail, UserSkip, AutoSkip, TotNotBuilt, _) ->
- {ok, [Result|total_row(TotSucc, TotFail, UserSkip, AutoSkip, TotNotBuilt, false)],
+make_last_run_index([], Result, TotSucc, TotFail, UserSkip, AutoSkip,
+ TotNotBuilt, _) ->
+ {ok, [Result|total_row(TotSucc, TotFail, UserSkip, AutoSkip,
+ TotNotBuilt, false)],
{TotSucc,TotFail,UserSkip,AutoSkip,TotNotBuilt}}.
make_last_run_index1(SuiteName, [LogDir | LogDirs], Result, TotSucc, TotFail,
UserSkip, AutoSkip, TotNotBuilt, Missing) ->
- case make_one_index_entry(SuiteName, LogDir, "-", false, Missing) of
- {Result1,Succ,Fail,USkip,ASkip,NotBuilt} ->
+ case make_one_index_entry(SuiteName, LogDir, "-", false,
+ Missing, undefined) of
+ {Result1,Succ,Fail,USkip,ASkip,NotBuilt,_URIs1} ->
%% for backwards compatibility
AutoSkip1 = case catch AutoSkip+ASkip of
{'EXIT',_} -> undefined;
Res -> Res
end,
- make_last_run_index1(SuiteName, LogDirs, [Result|Result1], TotSucc+Succ,
- TotFail+Fail, UserSkip+USkip, AutoSkip1,
- TotNotBuilt+NotBuilt, Missing);
+ make_last_run_index1(SuiteName, LogDirs, [Result|Result1],
+ TotSucc+Succ,
+ TotFail+Fail, UserSkip+USkip, AutoSkip1,
+ TotNotBuilt+NotBuilt, Missing);
error ->
make_last_run_index1(SuiteName, LogDirs, Result, TotSucc, TotFail,
UserSkip, AutoSkip, TotNotBuilt, Missing)
@@ -1070,35 +1116,49 @@ make_last_run_index1(_, [], Result, TotSucc, TotFail,
UserSkip, AutoSkip, TotNotBuilt, _) ->
{Result,TotSucc,TotFail,UserSkip,AutoSkip,TotNotBuilt}.
-make_one_index_entry(SuiteName, LogDir, Label, All, Missing) ->
+make_one_index_entry(SuiteName, LogDir, Label, All, Missing, URIs) ->
case count_cases(LogDir) of
{Succ,Fail,UserSkip,AutoSkip} ->
NotBuilt = not_built(SuiteName, LogDir, All, Missing),
- NewResult = make_one_index_entry1(SuiteName, LogDir, Label, Succ, Fail,
- UserSkip, AutoSkip, NotBuilt, All,
- normal),
- {NewResult,Succ,Fail,UserSkip,AutoSkip,NotBuilt};
+ {NewResult,URIs1} = make_one_index_entry1(SuiteName, LogDir, Label,
+ Succ, Fail,
+ UserSkip, AutoSkip,
+ NotBuilt, All,
+ normal, URIs),
+ {NewResult,Succ,Fail,UserSkip,AutoSkip,NotBuilt,URIs1};
error ->
error
end.
make_one_index_entry1(SuiteName, Link, Label, Success, Fail, UserSkip, AutoSkip,
- NotBuilt, All, Mode) ->
+ NotBuilt, All, Mode, URIs) ->
LogFile = filename:join(Link, ?suitelog_name ++ ".html"),
+ CtRunDir = filename:dirname(filename:dirname(Link)),
+ CrashDumpName = SuiteName ++ "_erl_crash.dump",
+
+ URIs1 = {CtRunLogURI,LogFileURI,CrashDumpURI} =
+ case URIs of
+ undefined ->
+ {uri(filename:join(CtRunDir,?ct_log_name)),
+ uri(LogFile),
+ uri(CrashDumpName)};
+ _ ->
+ URIs
+ end,
+
CrashDumpLink = case Mode of
- cached ->
+ temp ->
"";
normal ->
- CrashDumpName = SuiteName ++ "_erl_crash.dump",
case filelib:is_file(CrashDumpName) of
true ->
- ["&nbsp;<a href=\"", uri(CrashDumpName),
+ ["&nbsp;<a href=\"", CrashDumpURI,
"\">(CrashDump)</a>"];
false ->
""
end
end,
- CtRunDir = filename:dirname(filename:dirname(Link)),
+
{Lbl,Timestamp,Node,AllInfo} =
case All of
{true,OldRuns} ->
@@ -1107,7 +1167,9 @@ make_one_index_entry1(SuiteName, Link, Label, Success, Fail, UserSkip, AutoSkip,
0 -> "-";
_ -> NodeOrDate
end,
+
TS = timestamp(CtRunDir),
+
N = xhtml(["<td align=right><font size=\"-1\">",Node1,
"</font></td>\n"],
["<td align=right>",Node1,"</td>\n"]),
@@ -1116,28 +1178,31 @@ make_one_index_entry1(SuiteName, Link, Label, Success, Fail, UserSkip, AutoSkip,
["<td align=center><b>",Label,"</b></td>\n"]),
T = xhtml(["<td><font size=\"-1\">",TS,"</font></td>\n"],
["<td>",TS,"</td>\n"]),
- CtLogFile = filename:join(CtRunDir,?ct_log_name),
+
OldRunsLink =
case OldRuns of
[] -> "none";
_ -> "<a href=\""++?all_runs_name++"\">Old Runs</a>"
end,
- A = xhtml(["<td><font size=\"-1\"><a href=\"",uri(CtLogFile),
+
+ A = xhtml(["<td><font size=\"-1\"><a href=\"",CtRunLogURI,
"\">CT Log</a></font></td>\n",
- "<td><font size=\"-1\">",OldRunsLink,"</font></td>\n"],
- ["<td><a href=\"",uri(CtLogFile),"\">CT Log</a></td>\n",
+ "<td><font size=\"-1\">",OldRunsLink,
+ "</font></td>\n"],
+ ["<td><a href=\"",CtRunLogURI,
+ "\">CT Log</a></td>\n",
"<td>",OldRunsLink,"</td>\n"]),
{L,T,N,A};
false ->
{"","","",""}
end,
+
NotBuiltStr =
if NotBuilt == 0 ->
["<td align=right>",integer_to_list(NotBuilt),"</td>\n"];
true ->
- ["<td align=right><a href=\"",
- uri(filename:join(CtRunDir,?ct_log_name)),"\">",
- integer_to_list(NotBuilt),"</a></td>\n"]
+ ["<td align=right><a href=\"",CtRunLogURI,"\">",
+ integer_to_list(NotBuilt),"</a></td>\n"]
end,
FailStr =
if Fail > 0 ->
@@ -1156,17 +1221,17 @@ make_one_index_entry1(SuiteName, Link, Label, Success, Fail, UserSkip, AutoSkip,
end,
{UserSkip+AutoSkip,integer_to_list(UserSkip),ASStr}
end,
- [xhtml("<tr valign=top>\n",
- ["<tr class=\"",odd_or_even(),"\">\n"]),
- xhtml("<td><font size=\"-1\"><a href=\"", "<td><a href=\""),
- uri(LogFile),"\">",SuiteName,"</a>", CrashDumpLink,
- xhtml("</font></td>\n", "</td>\n"),
- Lbl, Timestamp,
- "<td align=right>",integer_to_list(Success),"</td>\n",
- "<td align=right>",FailStr,"</td>\n",
- "<td align=right>",integer_to_list(AllSkip),
- " (",UserSkipStr,"/",AutoSkipStr,")</td>\n",
- NotBuiltStr, Node, AllInfo, "</tr>\n"].
+ {[xhtml("<tr valign=top>\n",
+ ["<tr class=\"",odd_or_even(),"\">\n"]),
+ xhtml("<td><font size=\"-1\"><a href=\"", "<td><a href=\""),
+ LogFileURI,"\">",SuiteName,"</a>", CrashDumpLink,
+ xhtml("</font></td>\n", "</td>\n"),
+ Lbl, Timestamp,
+ "<td align=right>",integer_to_list(Success),"</td>\n",
+ "<td align=right>",FailStr,"</td>\n",
+ "<td align=right>",integer_to_list(AllSkip),
+ " (",UserSkipStr,"/",AutoSkipStr,")</td>\n",
+ NotBuiltStr, Node, AllInfo, "</tr>\n"], URIs1}.
total_row(Success, Fail, UserSkip, AutoSkip, NotBuilt, All) ->
{Label,TimestampCell,AllInfo} =
@@ -1392,17 +1457,30 @@ header1(Title, SubTitle, TableCols) ->
"</center>\n",
SubTitleHTML,"\n"].
-index_footer() ->
- ["</table>\n"
+last_run_index_footer() ->
+ AllRuns = filename:join("../",?all_runs_name),
+ TestIndex = filename:join("../",?index_name),
+ ["</table>\n",
+ xhtml("<br><hr><p>\n", "<br /><hr /><p>\n"),
+ "<a href=\"", uri(AllRuns),
+ "\">Test run history\n</a> | ",
+ "<a href=\"", uri(TestIndex),
+ "\">Top level test index\n</a>\n</p>\n",
"</center>\n" | footer()].
+all_suites_index_footer() ->
+ ["</table>\n",
+ "</center>\n",
+ xhtml("<br><br>\n", "<br /><br />\n") | footer()].
+
all_runs_index_footer() ->
- ["</tbody>\n</table>\n"
- "</center>\n" | footer()].
+ ["</tbody>\n</table>\n",
+ "</center>\n",
+ xhtml("<br><br>\n", "<br /><br />\n") | footer()].
footer() ->
["<center>\n",
- xhtml("<br><br>\n<hr>\n", "<br /><br />\n"),
+ xhtml("<hr>\n", ""),
xhtml("<p><font size=\"-1\">\n", "<div class=\"copyright\">"),
"Copyright &copy; ", year(),
" <a href=\"http://www.erlang.org\">Open Telecom Platform</a>",
@@ -1414,7 +1492,6 @@ footer() ->
"</body>\n"
"</html>\n"].
-
body_tag() ->
CTPath = code:lib_dir(common_test),
TileFile = filename:join(filename:join(CTPath,"priv"),"tile1.jpg"),
@@ -1580,35 +1657,169 @@ make_all_runs_index(When) ->
if When == start -> ok;
true -> io:put_chars("Updating " ++ AbsName ++ "... ")
end,
+
+ %% check if log cache should be used, and if it exists
+ UseCache =
+ if When == refresh ->
+ save_only;
+ true ->
+ case application:get_env(common_test, disable_log_cache) of
+ {ok,true} ->
+ disabled;
+ _ ->
+ case get(ct_log_cache) of
+ undefined ->
+ file:read_file(?log_cache_name);
+ LogCacheBin ->
+ {ok,LogCacheBin}
+ end
+ end
+ end,
+
Dirs = filelib:wildcard(logdir_prefix()++"*.*"),
DirsSorted = (catch sort_all_runs(Dirs)),
- Header = all_runs_header(),
- Index = [runentry(Dir) || Dir <- DirsSorted],
- Result = file:write_file(AbsName,
- unicode:characters_to_binary(
- Header++Index++all_runs_index_footer())),
+
+ LogCacheInfo = get_cache_data(UseCache),
+
+ Result =
+ case LogCacheInfo of
+ {ok,LogCache} ->
+ %% use the log cache file to generate the index
+ make_all_runs_from_cache(AbsName,DirsSorted,LogCache);
+
+ _WhyNot ->
+ %% no cache file exists (or feature has been disabled)
+ Header = all_runs_header(),
+ GetLogResult =
+ fun(Dir,{RunData,LogTxt}) ->
+ {Tot,XHTML,IxLink} = runentry(Dir,
+ undefined,
+ undefined),
+ {[{Dir,Tot,IxLink}|RunData],[XHTML|LogTxt]}
+ end,
+ {AllRunsData,Index} =
+ lists:foldr(GetLogResult,{[],[]},DirsSorted),
+
+ %% update cache with result unless the cache is disabled
+ if UseCache == disabled -> ok;
+ true -> update_all_runs_in_cache(AllRunsData)
+ end,
+ %% write all_runs log file
+ ok = file:write_file(AbsName,
+ unicode:characters_to_binary(
+ Header++Index++
+ all_runs_index_footer()))
+ end,
+ notify_and_unlock_file(AbsName),
if When == start -> ok;
true -> io:put_chars("done\n")
end,
- notify_and_unlock_file(AbsName),
Result.
+make_all_runs_from_cache(AbsName, Dirs, LogCache) ->
+ Header = all_runs_header(),
+
+ %% Note that both Dirs and the cache is sorted!
+ AllRunsDirs = dir_diff_all_runs(Dirs, LogCache),
+
+ GetLogResult =
+ fun({Dir,no_test_data,IxLink},{RunData,LogTxt}) ->
+ {Tot,XHTML,_} = runentry(Dir,undefined,IxLink),
+ {[{Dir,Tot,IxLink}|RunData],[XHTML|LogTxt]};
+ ({Dir,CachedTotals,IxLink},{RunData,LogTxt}) ->
+ %% create log entry using cached data
+ {Tot,XHTML,_} = runentry(Dir,CachedTotals,IxLink),
+ {[{Dir,Tot,IxLink}|RunData],[XHTML|LogTxt]};
+ (Dir,{RunData,LogTxt}) ->
+ %% create log entry from scratch
+ {Tot,XHTML,IxLink} = runentry(Dir,undefined,undefined),
+ {[{Dir,Tot,IxLink}|RunData],[XHTML|LogTxt]}
+ end,
+ {AllRunsData,Index} = lists:foldr(GetLogResult,{[],[]},AllRunsDirs),
+ %% update cache with result
+ update_all_runs_in_cache(AllRunsData,LogCache),
+ %% write all_runs log file
+ ok = file:write_file(AbsName,
+ unicode:characters_to_binary(
+ Header++Index++
+ all_runs_index_footer())).
+
+update_all_runs_in_cache(AllRunsData) ->
+ case get(ct_log_cache) of
+ undefined ->
+ LogCache = #log_cache{version = cache_vsn(),
+ all_runs = AllRunsData},
+ case {self(),whereis(?MODULE)} of
+ {_Pid,_Pid} ->
+ %% save the cache in RAM so it doesn't have to be
+ %% read from file as long as this logger process is alive
+ put(ct_log_cache,term_to_binary(LogCache));
+ _ ->
+ file:write_file(?log_cache_name,term_to_binary(LogCache))
+ end;
+ SavedLogCache ->
+ update_all_runs_in_cache(AllRunsData,binary_to_term(SavedLogCache))
+ end.
+
+update_all_runs_in_cache(AllRunsData, LogCache) ->
+ LogCache1 = LogCache#log_cache{all_runs = AllRunsData},
+ case {self(),whereis(?MODULE)} of
+ {_Pid,_Pid} ->
+ %% save the cache in RAM so it doesn't have to be
+ %% read from file as long as this logger process is alive
+ put(ct_log_cache,term_to_binary(LogCache1));
+ _ ->
+ file:write_file(?log_cache_name,term_to_binary(LogCache1))
+ end.
+
sort_all_runs(Dirs) ->
%% sort on time string, always last and on the format:
%% "YYYY-MM-DD_HH.MM.SS"
- KeyList =
- lists:map(fun(Dir) ->
- case lists:reverse(string:tokens(Dir,[$.,$_])) of
- [SS,MM,HH,Date|_] ->
- {{Date,HH,MM,SS},Dir};
- _Other ->
- throw(Dirs)
- end
- end,Dirs),
- lists:reverse(lists:map(fun({_,Dir}) ->
- Dir
- end,lists:keysort(1,KeyList))).
+ lists:sort(fun(Dir1,Dir2) ->
+ [SS1,MM1,HH1,Date1|_] =
+ lists:reverse(string:tokens(Dir1,[$.,$_])),
+ [SS2,MM2,HH2,Date2|_] =
+ lists:reverse(string:tokens(Dir2,[$.,$_])),
+ {Date1,HH1,MM1,SS1} > {Date2,HH2,MM2,SS2}
+ end, Dirs).
+
+dir_diff_all_runs(Dirs, LogCache) ->
+ case LogCache#log_cache.all_runs of
+ [] ->
+ Dirs;
+ Cached = [{CDir,_,_}|_] ->
+ AllRunsDirs =
+ dir_diff_all_runs(Dirs, Cached, datestr_from_dirname(CDir), []),
+ lists:reverse(AllRunsDirs)
+ end.
+
+dir_diff_all_runs(LogDirs=[Dir|Dirs], Cached=[CElem|CElems],
+ LatestInCache, AllRunsDirs) ->
+ DirDate = datestr_from_dirname(Dir),
+ if DirDate > LatestInCache ->
+ %% Dir is a new run entry
+ dir_diff_all_runs(Dirs, Cached, LatestInCache,
+ [Dir|AllRunsDirs]);
+ DirDate == LatestInCache, CElems /= [] ->
+ %% Dir is an existing run entry
+ dir_diff_all_runs(Dirs, CElems,
+ datestr_from_dirname(element(1,hd(CElems))),
+ [CElem|AllRunsDirs]);
+ DirDate == LatestInCache, CElems == [] ->
+ %% we're done, Dirs must all be new
+ lists:reverse(Dirs)++[CElem|AllRunsDirs];
+ CElems /= [] -> % DirDate < LatestInCache
+ %% current CDir not in Dirs, update timestamp and check next
+ dir_diff_all_runs(LogDirs, CElems,
+ datestr_from_dirname(element(1,hd(CElems))),
+ AllRunsDirs);
+ CElems == [] ->
+ %% we're done, LogDirs must all be new
+ lists:reverse(LogDirs)++AllRunsDirs
+ end;
+dir_diff_all_runs([], _Cached, _, AllRunsDirs) ->
+ AllRunsDirs.
interactive_link() ->
[Dir|_] = lists:reverse(filelib:wildcard(logdir_prefix()++"*.*")),
@@ -1619,12 +1830,14 @@ interactive_link() ->
"<html>\n"],
["<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Transitional//EN\"\n",
"\"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd\">\n",
- "<html xmlns=\"http://www.w3.org/1999/xhtml\" xml:lang=\"en\" lang=\"en\">\n"]),
+ "<html xmlns=\"http://www.w3.org/1999/xhtml\" ",
+ "xml:lang=\"en\" lang=\"en\">\n"]),
"<!-- autogenerated by '"++atom_to_list(?MODULE)++"' -->\n",
"<head>\n",
"<title>Last interactive run</title>\n",
"<meta http-equiv=\"cache-control\" content=\"no-cache\">\n",
- "<meta http-equiv=\"content-type\" content=\"text/html; charset=utf-8\">\n",
+ "<meta http-equiv=\"content-type\" content=\"text/html; "
+ "charset=utf-8\">\n",
"</head>\n",
"<body>\n",
"Log from last interactive run: <a href=\"",uri(CtLog),"\">",
@@ -1637,98 +1850,120 @@ interactive_link() ->
"Any CT activities will be logged here\n",
[?abs("last_interactive.html")]).
-runentry(Dir) ->
+%% use if cache disabled or non-existing
+runentry(Dir, undefined, _) ->
TotalsFile = filename:join(Dir,?totals_name),
- TotalsStr =
- case read_totals_file(TotalsFile) of
- {Node,Label,Logs,{TotSucc,TotFail,UserSkip,AutoSkip,NotBuilt}} ->
- TotFailStr =
- if TotFail > 0 ->
- ["<font color=\"red\">",
- integer_to_list(TotFail),"</font>"];
- true ->
- integer_to_list(TotFail)
- end,
- {AllSkip,UserSkipStr,AutoSkipStr} =
- if AutoSkip == undefined -> {UserSkip,"?","?"};
- true ->
- ASStr = if AutoSkip > 0 ->
- ["<font color=\"brown\">",
- integer_to_list(AutoSkip),"</font>"];
- true -> integer_to_list(AutoSkip)
- end,
- {UserSkip+AutoSkip,integer_to_list(UserSkip),ASStr}
- end,
- NoOfTests = case length(Logs) of
- 0 -> "-";
- N -> integer_to_list(N)
- end,
- StripExt =
- fun(File) ->
- string:sub_string(File,1,
- length(File)-
- length(?logdir_ext)) ++ ", "
- end,
- Polish = fun(S) -> case lists:reverse(S) of
- [32,$,|Rev] -> lists:reverse(Rev);
- [$,|Rev] -> lists:reverse(Rev);
- _ -> S
- end
- end,
- TestNames = Polish(lists:flatten(lists:map(StripExt,Logs))),
- TestNamesTrunc =
- if TestNames=="" ->
- "";
- length(TestNames) < ?testname_width ->
- TestNames;
- true ->
- Trunc = Polish(string:substr(TestNames,1,?testname_width-3)),
- lists:flatten(io_lib:format("~ts...",[Trunc]))
- end,
- Total = TotSucc+TotFail+AllSkip,
- A = xhtml(["<td align=center><font size=\"-1\">",Node,
- "</font></td>\n",
- "<td align=center><font size=\"-1\"><b>",Label,
- "</b></font></td>\n",
- "<td align=right>",NoOfTests,"</td>\n"],
- ["<td align=center>",Node,"</td>\n",
- "<td align=center><b>",Label,"</b></td>\n",
- "<td align=right>",NoOfTests,"</td>\n"]),
- B = xhtml(["<td align=center title='",TestNames,"'><font size=\"-1\"> ",
- TestNamesTrunc,"</font></td>\n"],
- ["<td align=center title='",TestNames,"'> ",
- TestNamesTrunc,"</td>\n"]),
- C = ["<td align=right>",integer_to_list(Total),"</td>\n",
- "<td align=right>",integer_to_list(TotSucc),"</td>\n",
- "<td align=right>",TotFailStr,"</td>\n",
- "<td align=right>",integer_to_list(AllSkip),
- " (",UserSkipStr,"/",AutoSkipStr,")</td>\n",
- "<td align=right>",integer_to_list(NotBuilt),"</td>\n"],
- A++B++C;
- _ ->
- A = xhtml(["<td align=center><font size=\"-1\" color=\"red\">"
- "Test data missing or corrupt</font></td>\n",
- "<td align=center><font size=\"-1\">?</font></td>\n",
- "<td align=right>?</td>\n"],
- ["<td align=center><font color=\"red\">"
- "Test data missing or corrupt</font></td>\n",
- "<td align=center>?</td>\n",
- "<td align=right>?</td>\n"]),
- B = xhtml(["<td align=center><font size=\"-1\">?</font></td>\n"],
- ["<td align=center>?</td>\n"]),
- C = ["<td align=right>?</td>\n",
- "<td align=right>?</td>\n",
- "<td align=right>?</td>\n",
- "<td align=right>?</td>\n",
- "<td align=right>?</td>\n"],
- A++B++C
- end,
Index = uri(filename:join(Dir,?index_name)),
- [xhtml("<tr>\n", ["<tr class=\"",odd_or_even(),"\">\n"]),
- xhtml(["<td><font size=\"-1\"><a href=\"",Index,"\">",timestamp(Dir),"</a>",
- TotalsStr,"</font></td>\n"],
- ["<td><a href=\"",Index,"\">",timestamp(Dir),"</a>",TotalsStr,"</td>\n"]),
- "</tr>\n"].
+ runentry(Dir, read_totals_file(TotalsFile), Index);
+
+%% use cached data
+runentry(Dir, Totals={Node,Label,Logs,
+ {TotSucc,TotFail,UserSkip,AutoSkip,NotBuilt}}, Index) ->
+ TotFailStr =
+ if TotFail > 0 ->
+ ["<font color=\"red\">",
+ integer_to_list(TotFail),"</font>"];
+ true ->
+ integer_to_list(TotFail)
+ end,
+ {AllSkip,UserSkipStr,AutoSkipStr} =
+ if AutoSkip == undefined -> {UserSkip,"?","?"};
+ true ->
+ ASStr = if AutoSkip > 0 ->
+ ["<font color=\"brown\">",
+ integer_to_list(AutoSkip),
+ "</font>"];
+ true -> integer_to_list(AutoSkip)
+ end,
+ {UserSkip+AutoSkip,integer_to_list(UserSkip),ASStr}
+ end,
+ NoOfTests = case length(Logs) of
+ 0 -> "-";
+ N -> integer_to_list(N)
+ end,
+ StripExt =
+ fun(File) ->
+ string:sub_string(File,1,
+ length(File)-
+ length(?logdir_ext)) ++ ", "
+ end,
+ Polish = fun(S) -> case lists:reverse(S) of
+ [32,$,|Rev] -> lists:reverse(Rev);
+ [$,|Rev] -> lists:reverse(Rev);
+ _ -> S
+ end
+ end,
+ TestNames = Polish(lists:flatten(lists:map(StripExt,Logs))),
+ TestNamesTrunc =
+ if TestNames=="" ->
+ "";
+ length(TestNames) < ?testname_width ->
+ TestNames;
+ true ->
+ Trunc = Polish(string:substr(TestNames,1,
+ ?testname_width-3)),
+ lists:flatten(io_lib:format("~ts...",[Trunc]))
+ end,
+ Total = TotSucc+TotFail+AllSkip,
+ A = xhtml(["<td align=center><font size=\"-1\">",Node,
+ "</font></td>\n",
+ "<td align=center><font size=\"-1\"><b>",Label,
+ "</b></font></td>\n",
+ "<td align=right>",NoOfTests,"</td>\n"],
+ ["<td align=center>",Node,"</td>\n",
+ "<td align=center><b>",Label,"</b></td>\n",
+ "<td align=right>",NoOfTests,"</td>\n"]),
+ B = xhtml(["<td align=center title='",TestNames,
+ "'><font size=\"-1\"> ",
+ TestNamesTrunc,"</font></td>\n"],
+ ["<td align=center title='",TestNames,"'> ",
+ TestNamesTrunc,"</td>\n"]),
+ C = ["<td align=right>",integer_to_list(Total),"</td>\n",
+ "<td align=right>",integer_to_list(TotSucc),"</td>\n",
+ "<td align=right>",TotFailStr,"</td>\n",
+ "<td align=right>",integer_to_list(AllSkip),
+ " (",UserSkipStr,"/",AutoSkipStr,")</td>\n",
+ "<td align=right>",integer_to_list(NotBuilt),"</td>\n"],
+ TotalsStr = A++B++C,
+
+ XHTML = [xhtml("<tr>\n", ["<tr class=\"",odd_or_even(),"\">\n"]),
+ xhtml(["<td><font size=\"-1\"><a href=\"",Index,"\">",
+ timestamp(Dir),"</a>",
+ TotalsStr,"</font></td>\n"],
+ ["<td><a href=\"",Index,"\">",timestamp(Dir),"</a>",TotalsStr,
+ "</td>\n"]),
+ "</tr>\n"],
+ {Totals,XHTML,Index};
+
+%% handle missing or corrupt data (missing e.g. if the test is in progress)
+runentry(Dir, _, _) ->
+ A = xhtml(["<td align=center><font size=\"-1\" color=\"red\">"
+ "Test data missing or corrupt</font></td>\n",
+ "<td align=center><font size=\"-1\">?</font></td>\n",
+ "<td align=right>?</td>\n"],
+ ["<td align=center><font color=\"red\">"
+ "Test data missing or corrupt</font></td>\n",
+ "<td align=center>?</td>\n",
+ "<td align=right>?</td>\n"]),
+ B = xhtml(["<td align=center><font size=\"-1\">?</font></td>\n"],
+ ["<td align=center>?</td>\n"]),
+ C = ["<td align=right>?</td>\n",
+ "<td align=right>?</td>\n",
+ "<td align=right>?</td>\n",
+ "<td align=right>?</td>\n",
+ "<td align=right>?</td>\n"],
+ TotalsStr = A++B++C,
+
+ Index = uri(filename:join(Dir,?index_name)),
+
+ XHTML = [xhtml("<tr>\n", ["<tr class=\"",odd_or_even(),"\">\n"]),
+ xhtml(["<td><font size=\"-1\"><a href=\"",Index,"\">",
+ timestamp(Dir),"</a>",
+ TotalsStr,"</font></td>\n"],
+ ["<td><a href=\"",Index,"\">",timestamp(Dir),"</a>",TotalsStr,
+ "</td>\n"]),
+ "</tr>\n"],
+ {no_test_data,XHTML,Index}.
write_totals_file(Name,Label,Logs,Totals) ->
AbsName = ?abs(Name),
@@ -1755,17 +1990,19 @@ read_totals_file(Name) ->
_ -> Label
end,
case Tot of
- {_Ok,_Fail,_USkip,_ASkip,_NoBuild} -> % latest format
+ {_Ok,_Fail,_USkip,_ASkip,_NoBuild} -> % latest format
{Node,Label1,Ls,Tot};
{TotSucc,TotFail,AllSkip,NotBuilt} ->
- {Node,Label1,Ls,{TotSucc,TotFail,AllSkip,undefined,NotBuilt}}
+ {Node,Label1,Ls,
+ {TotSucc,TotFail,AllSkip,undefined,NotBuilt}}
end;
{Node,Ls,Tot} -> % no label found
case Tot of
- {_Ok,_Fail,_USkip,_ASkip,_NoBuild} -> % latest format
+ {_Ok,_Fail,_USkip,_ASkip,_NoBuild} -> % latest format
{Node,"-",Ls,Tot};
{TotSucc,TotFail,AllSkip,NotBuilt} ->
- {Node,"-",Ls,{TotSucc,TotFail,AllSkip,undefined,NotBuilt}}
+ {Node,"-",Ls,
+ {TotSucc,TotFail,AllSkip,undefined,NotBuilt}}
end;
%% for backwards compatibility
{Ls,Tot} -> {"-",Ls,Tot};
@@ -1819,29 +2056,73 @@ timestamp(Dir) ->
%% run will not show until after the final refresh.
%% -------------------------------------------------------------------------
-%% Creates the top level index file. When == start | refresh.
-%% A copy of the dir tree under logdir is cached as a result.
+%% Creates the top level index file. When == start | stop | refresh.
+%% A copy of the dir tree under logdir is saved temporarily as a result.
make_all_suites_index(When) when is_atom(When) ->
put(basic_html, basic_html()),
AbsIndexName = ?abs(?index_name),
notify_and_lock_file(AbsIndexName),
+
+ %% check if log cache should be used, and if it exists
+ UseCache =
+ if When == refresh ->
+ save_only;
+ true ->
+ case application:get_env(common_test, disable_log_cache) of
+ {ok,true} ->
+ disabled;
+ _ ->
+ case get(ct_log_cache) of
+ undefined ->
+ file:read_file(?log_cache_name);
+ LogCacheBin ->
+ {ok,LogCacheBin}
+ end
+ end
+ end,
+
LogDirs = filelib:wildcard(logdir_prefix()++".*/*"++?logdir_ext),
- Sorted = sort_logdirs(LogDirs, []),
- Result = make_all_suites_index1(When, AbsIndexName, Sorted),
- notify_and_unlock_file(AbsIndexName),
- Result;
-%% This updates the top level index file using cached data from
-%% the initial index file creation.
-make_all_suites_index(NewTestData = {_TestName,DirName}) ->
+ LogCacheInfo = get_cache_data(UseCache),
+
+ Result =
+ case LogCacheInfo of
+ {ok,LogCache} ->
+ %% use the log cache file to generate the index
+ make_all_suites_index_from_cache(When,AbsIndexName,
+ LogDirs,LogCache);
+ _WhyNot ->
+ %% no cache file exists (or feature has been disabled)
+ Sorted = sort_and_filter_logdirs(LogDirs),
+ TempData = make_all_suites_index1(When,AbsIndexName,Sorted),
+ notify_and_unlock_file(AbsIndexName),
+
+ %% save new cache file unless the feature is disabled
+ if UseCache == disabled -> ok;
+ true -> update_tests_in_cache(TempData)
+ end,
+ TempData
+ end,
+
+ case Result of
+ Error = {error,_} -> Error;
+ _ -> ok
+ end;
+
+%% This updates the top level index file using data from the initial
+%% index file creation, saved temporarily in a table.
+make_all_suites_index(NewTestData = {_TestName,DirName}) ->
put(basic_html, basic_html()),
- %% AllLogDirs = [{TestName,Label,Missing,{LastLogDir,Summary},OldDirs}|...]
+
+ %% AllLogDirs = [{TestName,Label,Missing,
+ %% {LastLogDir,Summary,URIs},OldDirs}|...]
+
{AbsIndexName,LogDirData} = ct_util:get_testdata(test_index),
CtRunDirPos = length(filename:split(AbsIndexName)),
CtRunDir = filename:join(lists:sublist(filename:split(DirName),
CtRunDirPos)),
-
+
Label = case read_totals_file(filename:join(CtRunDir, ?totals_name)) of
{_,"-",_,_} -> "...";
{_,Lbl,_,_} -> Lbl;
@@ -1849,10 +2130,10 @@ make_all_suites_index(NewTestData = {_TestName,DirName}) ->
end,
notify_and_lock_file(AbsIndexName),
Result =
- case catch make_all_suites_ix_cached(AbsIndexName,
- NewTestData,
- Label,
- LogDirData) of
+ case catch make_all_suites_ix_temp(AbsIndexName,
+ NewTestData,
+ Label,
+ LogDirData) of
{'EXIT',Reason} ->
io:put_chars("CRASHED while updating " ++ AbsIndexName ++ "!\n"),
io:format("~p~n", [Reason]),
@@ -1869,46 +2150,219 @@ make_all_suites_index(NewTestData = {_TestName,DirName}) ->
[AbsIndexName,Err]),
{error, Err}
end,
- notify_and_unlock_file(AbsIndexName),
+ notify_and_unlock_file(AbsIndexName),
Result.
-sort_logdirs([Dir|Dirs],Groups) ->
+make_all_suites_index_from_cache(When, AbsIndexName, LogDirs, LogCache) ->
+
+ %% The structure of the cache:
+ %%
+ %% #log_cache{tests = {TestName,Label,Missing,
+ %% {LastLogDir,Summary,URIs},OldDirs}
+ %% }
+ %% Summary = {Succ,Fail,USkip,ASkip} | error
+ %%
+
+ {NewAdded,OldTests} = dir_diff_tests(LogDirs,LogCache),
+
+ LogCache1 = delete_tests_from_cache(OldTests,LogCache),
+ Sorted = sort_and_filter_logdirs(NewAdded,
+ LogCache1#log_cache.tests),
+ TempData =
+ if Sorted /= [] ->
+ make_all_suites_index1(When,AbsIndexName,
+ Sorted);
+ true ->
+ Data = LogCache1#log_cache.tests,
+ ct_util:set_testdata_async({test_index,{AbsIndexName,
+ Data}}),
+ Data
+ end,
+
+ notify_and_unlock_file(AbsIndexName),
+
+ update_tests_in_cache(TempData,LogCache1),
+ TempData.
+
+sort_and_filter_logdirs(NewDirs,CachedTests) when CachedTests /= [] ->
+ NewSorted = sort_and_filter_logdirs1(NewDirs,[]),
+ sort_and_filter_logdirs(NewSorted,CachedTests,[]);
+
+sort_and_filter_logdirs(NewDirs,_CachedTests) ->
+ sort_and_filter_logdirs(NewDirs).
+
+%% sort latest dirs found and combine them with cached entries
+sort_and_filter_logdirs([{TestName,IxDirs}|Tests],CachedTests,Combined) ->
+ case lists:keysearch(TestName,1,CachedTests) of
+ {value,{TestName,_,_,{IxDir0,_,_},IxDirs0}} ->
+ Groups = sort_and_filter_logdirs2(TestName,
+ IxDirs++[IxDir0|IxDirs0],
+ []),
+ sort_and_filter_logdirs(Tests,CachedTests,Groups++Combined);
+ _ ->
+ IxDirs1 = lists:map(fun(Elem = {_,_}) ->
+ Elem;
+ (RunDir) ->
+ {filename:basename(RunDir),RunDir}
+ end, IxDirs),
+ sort_and_filter_logdirs(Tests,CachedTests,
+ [{TestName,IxDirs1}|Combined])
+ end;
+sort_and_filter_logdirs([],CachedTests,Combined) ->
+ Cached1 = lists:foldl(fun({TestName,_},Cached) ->
+ lists:keydelete(TestName,1,Cached)
+ end, CachedTests, Combined),
+ lists:keysort(1,sort_each_group(Combined)++Cached1).
+
+sort_and_filter_logdirs(Dirs) ->
+ sort_and_filter_logdirs1(Dirs, []).
+
+%% sort and filter directories (no cache)
+sort_and_filter_logdirs1([Dir|Dirs],Groups) ->
TestName = filename:rootname(filename:basename(Dir)),
case filelib:wildcard(filename:join(Dir,"run.*")) of
RunDirs = [_|_] ->
- Groups1 = sort_logdirs1(TestName,RunDirs,Groups),
- sort_logdirs(Dirs,Groups1);
+ Groups1 = sort_and_filter_logdirs2(TestName,RunDirs,Groups),
+ sort_and_filter_logdirs1(Dirs,Groups1);
_ -> % ignore missing run directory
- sort_logdirs(Dirs,Groups)
+ sort_and_filter_logdirs1(Dirs,Groups)
end;
-sort_logdirs([],Groups) ->
+sort_and_filter_logdirs1([],Groups) ->
lists:keysort(1,sort_each_group(Groups)).
-sort_logdirs1(TestName,[RunDir|RunDirs],Groups) ->
+sort_and_filter_logdirs2(TestName,[RunDir|RunDirs],Groups) ->
Groups1 = insert_test(TestName,{filename:basename(RunDir),RunDir},Groups),
- sort_logdirs1(TestName,RunDirs,Groups1);
-sort_logdirs1(_,[],Groups) ->
+ sort_and_filter_logdirs2(TestName,RunDirs,Groups1);
+sort_and_filter_logdirs2(_,[],Groups) ->
Groups.
+%% new rundir for Test found, add to (not sorted) list of prev rundirs
insert_test(Test,IxDir,[{Test,IxDirs}|Groups]) ->
[{Test,[IxDir|IxDirs]}|Groups];
+%% first occurance of Test
insert_test(Test,IxDir,[]) ->
[{Test,[IxDir]}];
insert_test(Test,IxDir,[TestDir|Groups]) ->
[TestDir|insert_test(Test,IxDir,Groups)].
-
+
+%% sort the list of rundirs for each Test
sort_each_group([{Test,IxDirs}|Groups]) ->
Sorted = lists:reverse([Dir || {_,Dir} <- lists:keysort(1,IxDirs)]),
- [{Test,Sorted}| sort_each_group(Groups)];
+ [{Test,Sorted}|sort_each_group(Groups)];
sort_each_group([]) ->
[].
-make_all_suites_index1(When, AbsIndexName, AllLogDirs) ->
+dir_diff_tests(LogDirs, #log_cache{tests = CachedTests}) ->
+ AllTestNames =
+ [TestName || {TestName,_,_,_,_} <- CachedTests],
+ dir_diff_tests(LogDirs, CachedTests, [], AllTestNames, [], []).
+
+dir_diff_tests([LogDir|LogDirs], CachedTests, NewAdded, DeletedTests,
+ ValidLast, InvalidLast) ->
+ TestName = filename:rootname(filename:basename(LogDir)),
+ Time = datestr_from_dirname(LogDir),
+ %% check if the test already exists in the cache
+ {New,DeletedTests1,ValidLast1,InvalidLast1} =
+ case lists:keysearch(TestName,1,CachedTests) of
+ {value,{_,_,_,{LastLogDir,_,_},_PrevLogDirs}} ->
+ LastLogTime = datestr_from_dirname(LastLogDir),
+ if Time > LastLogTime ->
+ %% this is a new test run, not in cache
+ {[LogDir|NewAdded],
+ lists:delete(TestName,DeletedTests),
+ ValidLast,[{TestName,LastLogDir}|InvalidLast]};
+ Time == LastLogTime ->
+ %% this is the latest test run, already in cache
+ TDir = {TestName,LastLogDir},
+ {NewAdded,
+ lists:delete(TestName,DeletedTests),
+ [TDir|ValidLast],InvalidLast};
+ true ->
+ %% this is an old test run
+ {[],
+ lists:delete(TestName,DeletedTests),
+ ValidLast,[{TestName,LastLogDir}|InvalidLast]}
+ end;
+ _ ->
+ %% this is a test run for a new test, not in cache
+ {[LogDir|NewAdded],
+ DeletedTests,ValidLast,InvalidLast}
+ end,
+ dir_diff_tests(LogDirs, CachedTests, New, DeletedTests1,
+ ValidLast1,InvalidLast1);
+
+dir_diff_tests([], _CachedTests, NewAdded, DeletedTests,
+ ValidLast, InvalidLast) ->
+ %% We have to check if LastLogDir still exists or if it's been
+ %% deleted. InvalidLast contains all log dirs that should be deleted,
+ %% if not present in ValidLast.
+ InvalidLast1 =
+ lists:foldl(fun(TDir,IL) ->
+ case lists:member(TDir,ValidLast) of
+ true ->
+ [TD || TD <- IL, TD /= TDir];
+ false ->
+ [TDir | [TD || TD <- IL, TD /= TDir]]
+ end
+ end, InvalidLast, InvalidLast),
+
+ %% Collect all tests for which LastLogDir has been deleted.
+ DeletedTests1 = [T || {T,_} <- InvalidLast1] ++ DeletedTests,
+
+ %% Make sure that directories for tests that are to be deleted are
+ %% saved in NewAdded so that tests don't disappear from the log if
+ %% older run dirs for them exist.
+ NewAdded1 = lists:map(fun({_TestName,RunDir}) ->
+ [TopDir,TestDir|_] = filename:split(RunDir),
+ filename:join(TopDir,TestDir)
+ end, InvalidLast1) ++ NewAdded,
+
+ {NewAdded1,DeletedTests1}.
+
+delete_tests_from_cache(OldTests, LogCache=#log_cache{tests=Tests}) ->
+ Tests2 = lists:foldl(fun(T,Tests1) ->
+ lists:keydelete(T,1,Tests1)
+ end, Tests, OldTests),
+ LogCache#log_cache{tests = Tests2}.
+
+update_tests_in_cache(TempData) ->
+ case get(ct_log_cache) of
+ undefined ->
+ update_tests_in_cache(TempData,#log_cache{version = cache_vsn(),
+ tests=[]});
+ SavedLogCache ->
+ update_tests_in_cache(TempData,binary_to_term(SavedLogCache))
+ end.
+
+update_tests_in_cache(TempData,LogCache=#log_cache{tests=Tests}) ->
+ Cached1 =
+ if Tests == [] ->
+ [];
+ true ->
+ lists:foldl(fun({TestName,_,_,_,_},Cached) ->
+ lists:keydelete(TestName,1,Cached)
+ end, Tests, TempData)
+ end,
+ Tests1 = lists:keysort(1,TempData++Cached1),
+ CacheBin = term_to_binary(LogCache#log_cache{tests = Tests1}),
+ case {self(),whereis(?MODULE)} of
+ {_Pid,_Pid} ->
+ put(ct_log_cache,CacheBin);
+ _ ->
+ file:write_file(?log_cache_name,CacheBin)
+ end.
+
+%%
+%% AllTestLogDirs =
+%% [{TestName,[IxDir|IxDirs]} | ...] (non-cached), or
+%% [{TestName,Label,Missing,{IxDir,Summary,URIs},IxDirs} | ...] (cached)
+%%
+make_all_suites_index1(When, AbsIndexName, AllTestLogDirs) ->
IndexName = ?index_name,
if When == start -> ok;
true -> io:put_chars("Updating " ++ AbsIndexName ++ "... ")
end,
- case catch make_all_suites_index2(IndexName, AllLogDirs) of
+ case catch make_all_suites_index2(IndexName, AllTestLogDirs) of
{'EXIT', Reason} ->
io:put_chars("CRASHED while updating " ++ AbsIndexName ++ "!\n"),
io:format("~p~n", [Reason]),
@@ -1917,15 +2371,15 @@ make_all_suites_index1(When, AbsIndexName, AllLogDirs) ->
io:put_chars("FAILED while updating " ++ AbsIndexName ++ "\n"),
io:format("~p~n", [Reason]),
{error, Reason};
- {ok,CacheData} ->
+ {ok,TempData} ->
case When of
start ->
ct_util:set_testdata_async({test_index,{AbsIndexName,
- CacheData}}),
- ok;
+ TempData}}),
+ TempData;
_ ->
io:put_chars("done\n"),
- ok
+ TempData
end;
Err ->
io:format("Unknown internal error while updating ~ts. "
@@ -1935,21 +2389,57 @@ make_all_suites_index1(When, AbsIndexName, AllLogDirs) ->
end.
make_all_suites_index2(IndexName, AllTestLogDirs) ->
- {ok,Index0,_Totals,CacheData} =
+ {ok,Index0,_Totals,TempData} =
make_all_suites_index3(AllTestLogDirs,
all_suites_index_header(),
0, 0, 0, 0, 0, [], []),
- Index = [Index0|index_footer()],
+ Index = [Index0|all_suites_index_footer()],
case force_write_file(IndexName, unicode:characters_to_binary(Index)) of
ok ->
- {ok,CacheData};
+ {ok,TempData};
{error, Reason} ->
{error,{index_write_error, Reason}}
end.
+%%
+%% AllTestLogDirs = [{TestName,Label,Missing,{LogDir,Summary,URIs},OldDirs}]
+%% Summary = {Succ,Fail,UserSkip,AutoSkip} | error
+%% URIs = {CtRunLogURI,LogFileURI,CrashDumpURI} | undefined
+%%
+%% this clause is for handling entries in the log cache
+make_all_suites_index3([IxEntry = {TestName,Label,Missing,
+ {LastLogDir,Summary,URIs},OldDirs} | Rest],
+ Result, TotSucc, TotFail, UserSkip, AutoSkip, TotNotBuilt,
+ Labels, TempData) ->
+ [EntryDir|_] = filename:split(LastLogDir),
+ Labels1 = [{EntryDir,Label}|Labels],
+ case Summary of
+ {Succ,Fail,USkip,ASkip} ->
+ All = {true,OldDirs},
+ NotBuilt = not_built(TestName, LastLogDir, All, Missing),
+
+ {Result1,_} = make_one_index_entry1(TestName, LastLogDir, Label,
+ Succ, Fail, USkip, ASkip,
+ NotBuilt, All, temp, URIs),
+
+ AutoSkip1 = case catch AutoSkip+ASkip of
+ {'EXIT',_} -> undefined;
+ Res -> Res
+ end,
+ make_all_suites_index3(Rest, [Result|Result1], TotSucc+Succ,
+ TotFail+Fail, UserSkip+USkip, AutoSkip1,
+ TotNotBuilt+NotBuilt, Labels1,
+ [IxEntry|TempData]);
+ error ->
+ make_all_suites_index3(Rest, Result, TotSucc, TotFail,
+ UserSkip, AutoSkip, TotNotBuilt, Labels1,
+ [IxEntry|TempData])
+ end;
+
+%% this clause is for handling non-cached directories
make_all_suites_index3([{TestName,[LastLogDir|OldDirs]}|Rest],
Result, TotSucc, TotFail, UserSkip, AutoSkip, TotNotBuilt,
- Labels, CacheData) ->
+ Labels, TempData) ->
[EntryDir|_] = filename:split(LastLogDir),
Missing =
case file:read_file(filename:join(EntryDir, ?missing_suites_info)) of
@@ -1966,38 +2456,50 @@ make_all_suites_index3([{TestName,[LastLogDir|OldDirs]}|Rest],
Lbl ->
{Lbl,Labels}
end,
- case make_one_index_entry(TestName, LastLogDir, Label, {true,OldDirs}, Missing) of
- {Result1,Succ,Fail,USkip,ASkip,NotBuilt} ->
+ case make_one_index_entry(TestName, LastLogDir, Label,
+ {true,OldDirs}, Missing, undefined) of
+ {Result1,Succ,Fail,USkip,ASkip,NotBuilt,URIs} ->
%% for backwards compatibility
AutoSkip1 = case catch AutoSkip+ASkip of
{'EXIT',_} -> undefined;
Res -> Res
end,
IxEntry = {TestName,Label,Missing,
- {LastLogDir,{Succ,Fail,USkip,ASkip}},OldDirs},
+ {LastLogDir,{Succ,Fail,USkip,ASkip},URIs},OldDirs},
+
make_all_suites_index3(Rest, [Result|Result1], TotSucc+Succ,
TotFail+Fail, UserSkip+USkip, AutoSkip1,
TotNotBuilt+NotBuilt, Labels1,
- [IxEntry|CacheData]);
+ [IxEntry|TempData]);
error ->
- IxEntry = {TestName,Label,Missing,{LastLogDir,error},OldDirs},
+ IxEntry = {TestName,Label,Missing,
+ {LastLogDir,error,undefined},OldDirs},
make_all_suites_index3(Rest, Result, TotSucc, TotFail,
UserSkip, AutoSkip, TotNotBuilt, Labels1,
- [IxEntry|CacheData])
+ [IxEntry|TempData])
end;
+
+%% something wrong with this test dir, ignore
+make_all_suites_index3([_|Rest], Result, TotSucc, TotFail, UserSkip, AutoSkip,
+ TotNotBuilt, Labels, TempData) ->
+ make_all_suites_index3(Rest, Result, TotSucc, TotFail,
+ UserSkip, AutoSkip, TotNotBuilt, Labels,
+ TempData);
+
make_all_suites_index3([], Result, TotSucc, TotFail, UserSkip, AutoSkip,
- TotNotBuilt, _, CacheData) ->
- {ok, [Result|total_row(TotSucc, TotFail, UserSkip, AutoSkip, TotNotBuilt,true)],
- {TotSucc,TotFail,UserSkip,AutoSkip,TotNotBuilt}, lists:reverse(CacheData)}.
+ TotNotBuilt, _, TempData) ->
+ {ok, [Result|total_row(TotSucc, TotFail, UserSkip, AutoSkip,
+ TotNotBuilt,true)],
+ {TotSucc,TotFail,UserSkip,AutoSkip,TotNotBuilt}, lists:reverse(TempData)}.
-make_all_suites_ix_cached(AbsIndexName, NewTestData, Label, AllTestLogDirs) ->
+make_all_suites_ix_temp(AbsIndexName, NewTestData, Label, AllTestLogDirs) ->
AllTestLogDirs1 = insert_new_test_data(NewTestData, Label, AllTestLogDirs),
IndexDir = filename:dirname(AbsIndexName),
- Index0 = make_all_suites_ix_cached1(AllTestLogDirs1,
- all_suites_index_header(IndexDir),
- 0, 0, 0, 0, 0),
- Index = [Index0|index_footer()],
+ Index0 = make_all_suites_ix_temp1(AllTestLogDirs1,
+ all_suites_index_header(IndexDir),
+ 0, 0, 0, 0, 0),
+ Index = [Index0|all_suites_index_footer()],
case force_write_file(AbsIndexName, unicode:characters_to_binary(Index)) of
ok ->
ok;
@@ -2008,51 +2510,94 @@ make_all_suites_ix_cached(AbsIndexName, NewTestData, Label, AllTestLogDirs) ->
insert_new_test_data({NewTestName,NewTestDir}, NewLabel, AllTestLogDirs) ->
AllTestLogDirs1 =
case lists:keysearch(NewTestName, 1, AllTestLogDirs) of
- {value,{_,_,_,{LastLogDir,_},OldDirs}} ->
- [{NewTestName,NewLabel,[],{NewTestDir,{0,0,0,0}},
+ {value,{_,_,_,{LastLogDir,_,_},OldDirs}} ->
+ [{NewTestName,NewLabel,[],{NewTestDir,{0,0,0,0},undefined},
[LastLogDir|OldDirs]} |
lists:keydelete(NewTestName, 1, AllTestLogDirs)];
false ->
- [{NewTestName,NewLabel,[],{NewTestDir,{0,0,0,0}},[]} |
+ [{NewTestName,NewLabel,[],{NewTestDir,{0,0,0,0},undefined},[]} |
AllTestLogDirs]
end,
lists:keysort(1, AllTestLogDirs1).
-make_all_suites_ix_cached1([{TestName,Label,Missing,LastLogDirData,OldDirs}|Rest],
- Result, TotSucc, TotFail, UserSkip, AutoSkip,
- TotNotBuilt) ->
-
- case make_one_ix_entry_cached(TestName, LastLogDirData,
- Label, {true,OldDirs}, Missing) of
- {Result1,Succ,Fail,USkip,ASkip,NotBuilt} ->
+make_all_suites_ix_temp1([{TestName,Label,Missing,LastLogDirData,OldDirs}|Rest],
+ Result, TotSucc, TotFail, UserSkip, AutoSkip,
+ TotNotBuilt) ->
+ case make_one_ix_entry_temp(TestName, LastLogDirData,
+ Label, {true,OldDirs}, Missing) of
+ {Result1,Succ,Fail,USkip,ASkip,NotBuilt,_URIs} ->
%% for backwards compatibility
AutoSkip1 = case catch AutoSkip+ASkip of
{'EXIT',_} -> undefined;
Res -> Res
end,
- make_all_suites_ix_cached1(Rest, [Result|Result1], TotSucc+Succ,
- TotFail+Fail, UserSkip+USkip, AutoSkip1,
- TotNotBuilt+NotBuilt);
+ make_all_suites_ix_temp1(Rest, [Result|Result1], TotSucc+Succ,
+ TotFail+Fail, UserSkip+USkip, AutoSkip1,
+ TotNotBuilt+NotBuilt);
error ->
- make_all_suites_ix_cached1(Rest, Result, TotSucc, TotFail,
- UserSkip, AutoSkip, TotNotBuilt)
+ make_all_suites_ix_temp1(Rest, Result, TotSucc, TotFail,
+ UserSkip, AutoSkip, TotNotBuilt)
end;
-make_all_suites_ix_cached1([], Result, TotSucc, TotFail, UserSkip, AutoSkip,
- TotNotBuilt) ->
+make_all_suites_ix_temp1([], Result, TotSucc, TotFail, UserSkip, AutoSkip,
+ TotNotBuilt) ->
[Result|total_row(TotSucc, TotFail, UserSkip, AutoSkip, TotNotBuilt, true)].
-make_one_ix_entry_cached(TestName, {LogDir,Summary}, Label, All, Missing) ->
+make_one_ix_entry_temp(TestName, {LogDir,Summary,URIs}, Label, All, Missing) ->
case Summary of
{Succ,Fail,UserSkip,AutoSkip} ->
NotBuilt = not_built(TestName, LogDir, All, Missing),
- NewResult = make_one_index_entry1(TestName, LogDir, Label,
- Succ, Fail, UserSkip, AutoSkip,
- NotBuilt, All, cached),
- {NewResult,Succ,Fail,UserSkip,AutoSkip,NotBuilt};
+ {NewResult,URIs1} = make_one_index_entry1(TestName, LogDir, Label,
+ Succ, Fail,
+ UserSkip, AutoSkip,
+ NotBuilt, All, temp, URIs),
+ {NewResult,Succ,Fail,UserSkip,AutoSkip,NotBuilt,URIs1};
error ->
error
end.
+%%%-----------------------------------------------------------------
+%%%
+get_cache_data({ok,CacheBin}) ->
+ case binary_to_term(CacheBin) of
+ CacheRec when is_record(CacheRec,log_cache) ->
+ %% make sure we don't use a cache on old format
+ case is_correct_cache_vsn(CacheRec) of
+ true ->
+ {ok,CacheRec};
+ false ->
+ file:delete(?log_cache_name),
+ {error,old_cache_file}
+ end;
+ _ ->
+ file:delete(?log_cache_name),
+ {error,invalid_cache_file}
+ end;
+get_cache_data(NoCache) ->
+ NoCache.
+
+cache_vsn() ->
+ application:load(common_test),
+ case application:get_key(common_test,vsn) of
+ {ok,VSN} ->
+ VSN;
+ _ ->
+ EbinDir = filename:dirname(code:which(ct)),
+ VSNfile = filename:join([EbinDir,"..","vsn.mk"]),
+ case file:read_file(VSNfile) of
+ {ok,Bin} ->
+ [_,VSN] = string:tokens(binary_to_list(Bin),[$=,$\n,$ ]),
+ VSN;
+ _ ->
+ undefined
+ end
+ end.
+
+is_correct_cache_vsn(#log_cache{version = CVSN}) ->
+ case cache_vsn() of
+ CVSN -> true;
+ _ -> false
+ end.
+
%%-----------------------------------------------------------------
%% Remove log files.
%% Cwd should always be set to the root logdir when finished.
diff --git a/lib/common_test/src/ct_run.erl b/lib/common_test/src/ct_run.erl
index 57cfab532e..41d53c7b43 100644
--- a/lib/common_test/src/ct_run.erl
+++ b/lib/common_test/src/ct_run.erl
@@ -329,6 +329,13 @@ script_start1(Parent, Args) ->
application:set_env(common_test, basic_html, true),
true
end,
+ %% disable_log_cache - used by ct_logs
+ case proplists:get_value(disable_log_cache, Args) of
+ undefined ->
+ application:set_env(common_test, disable_log_cache, false);
+ _ ->
+ application:set_env(common_test, disable_log_cache, true)
+ end,
Opts = #opts{label = Label, profile = Profile,
vts = Vts, shell = Shell,
@@ -1039,6 +1046,13 @@ run_test2(StartOpts) ->
BasicHtmlBool
end,
+ case proplists:get_value(disable_log_cache, StartOpts) of
+ undefined ->
+ application:set_env(common_test, disable_log_cache, false);
+ DisableCacheBool ->
+ application:set_env(common_test, disable_log_cache, DisableCacheBool)
+ end,
+
%% stepped execution
Step = get_start_opt(step, value, StartOpts),
diff --git a/lib/common_test/src/ct_telnet.erl b/lib/common_test/src/ct_telnet.erl
index 02186864a5..bd74991859 100644
--- a/lib/common_test/src/ct_telnet.erl
+++ b/lib/common_test/src/ct_telnet.erl
@@ -29,7 +29,9 @@
%%% Command timeout = 10 sec (time to wait for a command to return)
%%% Max no of reconnection attempts = 3
%%% Reconnection interval = 5 sek (time to wait in between reconnection attempts)
-%%% Keep alive = true (will send NOP to the server every 10 sec if connection is idle)</pre>
+%%% Keep alive = true (will send NOP to the server every 10 sec if connection is idle)
+%%% Wait for linebreak = true (Will expect answer from server to end with linebreak when
+%%% using ct_telnet:expect)</pre>
%%% <p>These parameters can be altered by the user with the following
%%% configuration term:</p>
%%% <pre>
@@ -37,7 +39,8 @@
%%% {command_timeout,Millisec},
%%% {reconnection_attempts,N},
%%% {reconnection_interval,Millisec},
-%%% {keep_alive,Bool}]}.</pre>
+%%% {keep_alive,Bool},
+%% {wait_for_linebreak, Bool}]}.</pre>
%%% <p><code>Millisec = integer(), N = integer()</code></p>
%%% <p>Enter the <code>telnet_settings</code> term in a configuration
%%% file included in the test and ct_telnet will retrieve the information
@@ -728,7 +731,8 @@ teln_get_all_data(Pid,Prx,Data,Acc,LastLine) ->
haltpatterns=[],
seq=false,
repeat=false,
- found_prompt=false}).
+ found_prompt=false,
+ wait_for_linebreak=true}).
%% @hidden
%% @doc Externally the silent_teln_expect function shall only be used
@@ -754,20 +758,25 @@ silent_teln_expect(Pid,Data,Pattern,Prx,Opts) ->
%% condition is fullfilled.
%% 3b) Repeat (sequence): 2) is repeated either N times or until a
%% halt condition is fullfilled.
-teln_expect(Pid,Data,Pattern0,Prx,Opts) -> HaltPatterns = case
- get_ignore_prompt(Opts) of true -> get_haltpatterns(Opts); false
- -> [prompt | get_haltpatterns(Opts)] end,
-
+teln_expect(Pid,Data,Pattern0,Prx,Opts) ->
+ HaltPatterns = case get_ignore_prompt(Opts) of
+ true ->
+ get_haltpatterns(Opts);
+ false ->
+ [prompt | get_haltpatterns(Opts)]
+ end,
+ WaitForLineBreak = get_line_break_opt(Opts),
Seq = get_seq(Opts),
Pattern = convert_pattern(Pattern0,Seq),
-
+
Timeout = get_timeout(Opts),
-
+
EO = #eo{teln_pid=Pid,
prx=Prx,
timeout=Timeout,
seq=Seq,
- haltpatterns=HaltPatterns},
+ haltpatterns=HaltPatterns,
+ wait_for_linebreak=WaitForLineBreak},
case get_repeat(Opts) of
false ->
@@ -808,6 +817,11 @@ get_timeout(Opts) ->
{value,{timeout,T}} -> T;
false -> ?DEFAULT_TIMEOUT
end.
+get_line_break_opt(Opts) ->
+ case lists:keysearch(wait_for_linebreak,1,Opts) of
+ {value,{wait_for_linebreak,false}} -> false;
+ _ -> true
+ end.
get_repeat(Opts) ->
case lists:keysearch(repeat,1,Opts) of
{value,{repeat,N}} when is_integer(N) ->
@@ -1004,8 +1018,9 @@ seq_expect1(Data,[],Acc,Rest,_EO) ->
%% Split prompt-chunk at lines
match_lines(Data,Patterns,EO) ->
FoundPrompt = EO#eo.found_prompt,
+ NeedLineBreak = EO#eo.wait_for_linebreak,
case one_line(Data,[]) of
- {noline,Rest} when FoundPrompt=/=false ->
+ {noline,Rest} when FoundPrompt=/=false, NeedLineBreak =:= true ->
%% This is the line including the prompt
case match_line(Rest,Patterns,FoundPrompt,EO) of
nomatch ->
@@ -1013,7 +1028,14 @@ match_lines(Data,Patterns,EO) ->
{Tag,Match} ->
{Tag,Match,[]}
end;
- {noline,Rest} ->
+ {noline,Rest} when NeedLineBreak =:= false ->
+ case match_line(Rest,Patterns,FoundPrompt,EO) of
+ nomatch ->
+ {nomatch,prompt};
+ {Tag,Match} ->
+ {Tag,Match,[]}
+ end;
+ {noline, Rest} ->
{nomatch,Rest};
{Line,Rest} ->
case match_line(Line,Patterns,false,EO) of
diff --git a/lib/common_test/src/ct_util.erl b/lib/common_test/src/ct_util.erl
index 02e58d0786..6a8b37bf3b 100644
--- a/lib/common_test/src/ct_util.erl
+++ b/lib/common_test/src/ct_util.erl
@@ -414,6 +414,8 @@ loop(Mode,TestData,StartDir) ->
[#conn{address=A,callback=CB}] ->
%% A connection crashed - remove the connection but don't die
ct_logs:tc_log_async(ct_error_notify,
+ ?MAX_IMPORTANCE,
+ "CT Error Notification",
"Connection process died: "
"Pid: ~w, Address: ~p, Callback: ~w\n"
"Reason: ~p\n\n",
diff --git a/lib/common_test/src/cth_log_redirect.erl b/lib/common_test/src/cth_log_redirect.erl
index 78ae70f37e..958b7a94c7 100644
--- a/lib/common_test/src/cth_log_redirect.erl
+++ b/lib/common_test/src/cth_log_redirect.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2011-2012. All Rights Reserved.
+%% Copyright Ericsson AB 2011-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
@@ -33,6 +33,8 @@
handle_event/2, handle_call/2, handle_info/2,
terminate/1]).
+-include("ct.hrl").
+
id(_Opts) ->
?MODULE.
@@ -78,7 +80,7 @@ handle_event(Event, LogFunc) ->
SReport = sasl_report:format_report(group_leader(), ErrLogType,
tag_event(Event)),
if is_list(SReport) ->
- ct_logs:LogFunc(sasl, SReport, []);
+ ct_logs:LogFunc(sasl, ?STD_IMPORTANCE, "System", SReport, []);
true -> %% Report is an atom if no logging is to be done
ignore
end
@@ -86,7 +88,7 @@ handle_event(Event, LogFunc) ->
EReport = error_logger_tty_h:write_event(
tag_event(Event),io_lib),
if is_list(EReport) ->
- ct_logs:LogFunc(error_logger, EReport, []);
+ ct_logs:LogFunc(error_logger, ?STD_IMPORTANCE, "System", EReport, []);
true -> %% Report is an atom if no logging is to be done
ignore
end,
diff --git a/lib/common_test/test/ct_cover_SUITE_data/cover_SUITE.erl b/lib/common_test/test/ct_cover_SUITE_data/cover_SUITE.erl
index d967590c72..83d368c53d 100644
--- a/lib/common_test/test/ct_cover_SUITE_data/cover_SUITE.erl
+++ b/lib/common_test/test/ct_cover_SUITE_data/cover_SUITE.erl
@@ -52,11 +52,10 @@ init_per_testcase(_Case, Config) ->
[{watchdog, Dog}|Config].
end_per_testcase(Case, Config) ->
- %% try apply(?MODULE,Case,[cleanup,Config])
- %% catch error:undef -> ok
- %% end,
+ try apply(?MODULE,Case,[cleanup,Config])
+ catch error:undef -> ok
+ end,
- kill_slaves(Case,nodes()),
Dog=?config(watchdog, Config),
test_server:timetrap_cancel(Dog),
ok.
@@ -67,12 +66,12 @@ break(_Config) ->
test_server:break(""),
ok.
-default(Config) ->
+default(_Config) ->
cover_compiled = code:which(cover_test_mod),
cover_test_mod:foo(),
ok.
-slave(Config) ->
+slave(_Config) ->
cover_compiled = code:which(cover_test_mod),
cover_test_mod:foo(),
N1 = nodename(slave,1),
@@ -81,8 +80,10 @@ slave(Config) ->
rpc:call(Node,cover_test_mod,foo,[]),
{ok,Node} = ct_slave:stop(N1),
ok.
+slave(cleanup,_Config) ->
+ kill_slaves([nodename(slave,1)]).
-slave_start_slave(Config) ->
+slave_start_slave(_Config) ->
cover_compiled = code:which(cover_test_mod),
cover_test_mod:foo(),
N1 = nodename(slave_start_slave,1),
@@ -90,13 +91,16 @@ slave_start_slave(Config) ->
{ok,Node} = start_slave(N1),
cover_compiled = rpc:call(Node,code,which,[cover_test_mod]),
rpc:call(Node,cover_test_mod,foo,[]),
- {ok,Node2} = rpc:call(Node,ct_slave,start,[N2]),
+ {ok,Node2} = start_slave(Node,N2), % start slave N2 from node Node
rpc:call(Node2,cover_test_mod,foo,[]),
{ok,Node2} = rpc:call(Node,ct_slave,stop,[N2]),
{ok,Node} = ct_slave:stop(N1),
ok.
+slave_start_slave(cleanup,_Config) ->
+ kill_slaves([nodename(slave_start_slave,1),
+ nodename(slave_start_slave,2)]).
-cover_node_option(Config) ->
+cover_node_option(_Config) ->
cover_compiled = code:which(cover_test_mod),
cover_test_mod:foo(),
Node = fullname(existing_node_1),
@@ -104,7 +108,7 @@ cover_node_option(Config) ->
rpc:call(Node,cover_test_mod,foo,[]),
ok.
-ct_cover_add_remove_nodes(Config) ->
+ct_cover_add_remove_nodes(_Config) ->
cover_compiled = code:which(cover_test_mod),
cover_test_mod:foo(),
Node = fullname(existing_node_2),
@@ -143,22 +147,20 @@ fullname(Name) ->
{ok,Host} = inet:gethostname(),
list_to_atom(atom_to_list(Name) ++ "@" ++ Host).
-kill_slaves(Case, [Node|Nodes]) ->
- Prefix = nodeprefix(Case),
- case lists:prefix(Prefix,atom_to_list(Node)) of
- true ->
- rpc:call(Node,erlang,halt,[]);
- _ ->
- ok
- end,
- kill_slaves(Case,Nodes);
-kill_slaves(_,[]) ->
+kill_slaves([Name|Names]) ->
+ _ = rpc:call(fullname(Name),erlang,halt,[]),
+ kill_slaves(Names);
+kill_slaves([]) ->
ok.
start_slave(Name) ->
+ start_slave(node(),Name).
+
+start_slave(FromNode,Name) ->
{ok, HostStr}=inet:gethostname(),
Host = list_to_atom(HostStr),
- ct_slave:start(Host,Name,
- [{boot_timeout,10}, % extending some timers for slow test hosts
- {init_timeout,10},
- {startup_timeout,10}]).
+ rpc:call(FromNode,ct_slave,start,
+ [Host,Name,
+ [{boot_timeout,15}, % extending some timers for slow test hosts
+ {init_timeout,15},
+ {startup_timeout,15}]]).
diff --git a/lib/common_test/test/ct_repeat_testrun_SUITE.erl b/lib/common_test/test/ct_repeat_testrun_SUITE.erl
index 7ec384c932..35d67a10f2 100644
--- a/lib/common_test/test/ct_repeat_testrun_SUITE.erl
+++ b/lib/common_test/test/ct_repeat_testrun_SUITE.erl
@@ -51,8 +51,8 @@
%% 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
+-define(t2,9). % time shall expire during first run of tc1
+-define(t3,19). % time shall expire during second run of tc1
%%--------------------------------------------------------------------
diff --git a/lib/common_test/test/ct_test_support.erl b/lib/common_test/test/ct_test_support.erl
index 70dd087358..6bcac12326 100644
--- a/lib/common_test/test/ct_test_support.erl
+++ b/lib/common_test/test/ct_test_support.erl
@@ -224,11 +224,38 @@ get_opts(Config) ->
%%%-----------------------------------------------------------------
%%%
-run(Opts, Config) when is_list(Opts) ->
+run(Opts0, Config) when is_list(Opts0) ->
+ Opts =
+ %% read (and override) opts from env variable, the form expected:
+ %% "[{some_key1,SomeVal2}, {some_key2,SomeVal2}]"
+ case os:getenv("CT_TEST_OPTS") of
+ false -> Opts0;
+ "" -> Opts0;
+ Terms ->
+ case erl_scan:string(Terms++".", 0) of
+ {ok,Tokens,_} ->
+ case erl_parse:parse_term(Tokens) of
+ {ok,OROpts} ->
+ Override =
+ fun(O={Key,_}, Os) ->
+ io:format(user, "ADDING START "
+ "OPTION: ~p~n", [O]),
+ [O | lists:keydelete(Key, 1, Os)]
+ end,
+ lists:foldl(Override, Opts0, OROpts);
+ _ ->
+ Opts0
+ end;
+ _ ->
+ Opts0
+ end
+ end,
+
%% 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) ->
@@ -236,9 +263,10 @@ run_ct_run_test(Opts,Config) ->
Level = proplists:get_value(trace_level, Config),
test_server:format(Level, "~n[RUN #1] Calling ct:run_test(~p) on ~p~n",
[Opts, CTNode]),
+ T0 = now(),
CtRunTestResult = rpc:call(CTNode, ct, run_test, [Opts]),
- test_server:format(Level, "~n[RUN #1] Got return value ~p~n",
- [CtRunTestResult]),
+ test_server:format(Level, "~n[RUN #1] Got return value ~p after ~p ms~n",
+ [CtRunTestResult,trunc(timer:now_diff(now(), T0)/1000)]),
case rpc:call(CTNode, erlang, whereis, [ct_util_server]) of
undefined ->
ok;
@@ -261,9 +289,10 @@ run_ct_script_start(Opts, Config) ->
[common_test, run_test_start_opts, Opts1]),
test_server:format(Level, "[RUN #2] Calling ct_run:script_start() on ~p~n",
[CTNode]),
+ T0 = now(),
ExitStatus = rpc:call(CTNode, ct_run, script_start, []),
- test_server:format(Level, "[RUN #2] Got exit status value ~p~n",
- [ExitStatus]),
+ test_server:format(Level, "[RUN #2] Got exit status value ~p after ~p ms~n",
+ [ExitStatus,trunc(timer:now_diff(now(), T0)/1000)]),
ExitStatus.
check_result({_Ok,Failed,{_UserSkipped,_AutoSkipped}},1,_Opts)
diff --git a/lib/compiler/src/beam_receive.erl b/lib/compiler/src/beam_receive.erl
index 3dd5ed182e..97a9188ee7 100644
--- a/lib/compiler/src/beam_receive.erl
+++ b/lib/compiler/src/beam_receive.erl
@@ -151,20 +151,20 @@ opt_recv(Is, Regs, D) ->
opt_recv([{label,L}=Lbl,{loop_rec,{f,Fail},_}=Loop|Is], D, R0, _, Acc) ->
R = regs_kill_not_live(0, R0),
- case regs_to_list(R) of
- [{y,_}=RefReg] ->
- %% We now have the new reference in the Y register RefReg
+ case regs_empty(R) of
+ false ->
+ %% We now have the new reference in Y registers
%% and the current instruction is the beginning of a
%% receive statement. We must now verify that only messages
%% that contain the reference will be matched.
- case opt_ref_used(Is, RefReg, Fail, D) of
+ case opt_ref_used(Is, R, Fail, D) of
false ->
no;
true ->
RecvSet = {recv_set,{f,L}},
{yes,reverse(Acc, [RecvSet,Lbl,Loop|Is]),L}
end;
- [] ->
+ true ->
no
end;
opt_recv([I|Is], D, R0, L0, Acc) ->
@@ -226,9 +226,9 @@ opt_update_regs_bl([{set,Ds,_,_}|Is], Regs0) ->
opt_update_regs_bl(Is, Regs);
opt_update_regs_bl([], Regs) -> Regs.
-%% opt_ref_used([Instruction], RefRegister, FailLabel, LabelIndex) -> true|false
+%% opt_ref_used([Instruction], RefRegs, FailLabel, LabelIndex) -> true|false
%% Return 'true' if it is certain that only messages that contain the same
-%% reference as in RefRegister can be matched out. Otherwise return 'false'.
+%% reference as in RefRegs can be matched out. Otherwise return 'false'.
%%
%% Basically, we follow all possible paths through the receive statement.
%% If all paths are safe, we return 'true'.
@@ -236,7 +236,7 @@ opt_update_regs_bl([], Regs) -> Regs.
%% A branch to FailLabel is safe, because it exits the receive statement
%% and no further message may be matched out.
%%
-%% If a path hits an comparision between RefRegister and part of the message,
+%% If a path hits an comparision between RefRegs and part of the message,
%% that path is safe (any messages that may be matched further down the
%% path is guaranteed to contain the reference).
%%
@@ -245,11 +245,11 @@ opt_update_regs_bl([], Regs) -> Regs.
%% we hit an unrecognized instruction, we also give up and return
%% 'false' (the optimization may be unsafe).
-opt_ref_used(Is, RefReg, Fail, D) ->
+opt_ref_used(Is, RefRegs, Fail, D) ->
Done = gb_sets:singleton(Fail),
Regs = regs_init_x0(),
try
- _ = opt_ref_used_1(Is, RefReg, D, Done, Regs),
+ _ = opt_ref_used_1(Is, RefRegs, D, Done, Regs),
true
catch
throw:not_used ->
@@ -258,37 +258,39 @@ opt_ref_used(Is, RefReg, Fail, D) ->
%% This functions only returns if all paths through the receive
%% statement are safe, and throws an 'not_used' term otherwise.
-opt_ref_used_1([{block,Bl}|Is], RefReg, D, Done, Regs0) ->
+opt_ref_used_1([{block,Bl}|Is], RefRegs, D, Done, Regs0) ->
Regs = opt_ref_used_bl(Bl, Regs0),
- opt_ref_used_1(Is, RefReg, D, Done, Regs);
-opt_ref_used_1([{test,is_eq_exact,{f,Fail},Args}|Is], RefReg, D, Done0, Regs) ->
- Done = opt_ref_used_at(Fail, RefReg, D, Done0, Regs),
- case is_ref_msg_comparison(Args, RefReg, Regs) of
+ opt_ref_used_1(Is, RefRegs, D, Done, Regs);
+opt_ref_used_1([{test,is_eq_exact,{f,Fail},Args}|Is],
+ RefRegs, D, Done0, Regs) ->
+ Done = opt_ref_used_at(Fail, RefRegs, D, Done0, Regs),
+ case is_ref_msg_comparison(Args, RefRegs, Regs) of
false ->
- opt_ref_used_1(Is, RefReg, D, Done, Regs);
+ opt_ref_used_1(Is, RefRegs, D, Done, Regs);
true ->
%% The instructions that follow (Is) can only be executed
- %% if the message contains the same reference as in RefReg.
+ %% if the message contains the same reference as in RefRegs.
Done
end;
-opt_ref_used_1([{test,is_ne_exact,{f,Fail},Args}|Is], RefReg, D, Done0, Regs) ->
- Done = opt_ref_used_1(Is, RefReg, D, Done0, Regs),
- case is_ref_msg_comparison(Args, RefReg, Regs) of
+opt_ref_used_1([{test,is_ne_exact,{f,Fail},Args}|Is],
+ RefRegs, D, Done0, Regs) ->
+ Done = opt_ref_used_1(Is, RefRegs, D, Done0, Regs),
+ case is_ref_msg_comparison(Args, RefRegs, Regs) of
false ->
- opt_ref_used_at(Fail, RefReg, D, Done, Regs);
+ opt_ref_used_at(Fail, RefRegs, D, Done, Regs);
true ->
Done
end;
-opt_ref_used_1([{test,_,{f,Fail},_}|Is], RefReg, D, Done0, Regs) ->
- Done = opt_ref_used_at(Fail, RefReg, D, Done0, Regs),
- opt_ref_used_1(Is, RefReg, D, Done, Regs);
-opt_ref_used_1([{select,_,_,{f,Fail},List}|_], RefReg, D, Done, Regs) ->
+opt_ref_used_1([{test,_,{f,Fail},_}|Is], RefRegs, D, Done0, Regs) ->
+ Done = opt_ref_used_at(Fail, RefRegs, D, Done0, Regs),
+ opt_ref_used_1(Is, RefRegs, D, Done, Regs);
+opt_ref_used_1([{select,_,_,{f,Fail},List}|_], RefRegs, D, Done, Regs) ->
Lbls = [F || {f,F} <- List] ++ [Fail],
- opt_ref_used_in_all(Lbls, RefReg, D, Done, Regs);
-opt_ref_used_1([{label,Lbl}|Is], RefReg, D, Done, Regs) ->
+ opt_ref_used_in_all(Lbls, RefRegs, D, Done, Regs);
+opt_ref_used_1([{label,Lbl}|Is], RefRegs, D, Done, Regs) ->
case gb_sets:is_member(Lbl, Done) of
true -> Done;
- false -> opt_ref_used_1(Is, RefReg, D, Done, Regs)
+ false -> opt_ref_used_1(Is, RefRegs, D, Done, Regs)
end;
opt_ref_used_1([{loop_rec_end,_}|_], _, _, Done, _) ->
Done;
@@ -296,27 +298,25 @@ opt_ref_used_1([_I|_], _RefReg, _D, _Done, _Regs) ->
%% The optimization may be unsafe.
throw(not_used).
-%% is_ref_msg_comparison(Args, RefReg, RegisterSet) -> true|false.
+%% is_ref_msg_comparison(Args, RefRegs, RegisterSet) -> true|false.
%% Return 'true' if Args denotes a comparison between the
%% reference and message or part of the message.
-is_ref_msg_comparison([R,RefReg], RefReg, Regs) ->
- regs_is_member(R, Regs);
-is_ref_msg_comparison([RefReg,R], RefReg, Regs) ->
- regs_is_member(R, Regs);
-is_ref_msg_comparison([_,_], _, _) -> false.
-
-opt_ref_used_in_all([L|Ls], RefReg, D, Done0, Regs) ->
- Done = opt_ref_used_at(L, RefReg, D, Done0, Regs),
- opt_ref_used_in_all(Ls, RefReg, D, Done, Regs);
+is_ref_msg_comparison([R1,R2], RefRegs, Regs) ->
+ (regs_is_member(R2, RefRegs) andalso regs_is_member(R1, Regs)) orelse
+ (regs_is_member(R1, RefRegs) andalso regs_is_member(R2, Regs)).
+
+opt_ref_used_in_all([L|Ls], RefRegs, D, Done0, Regs) ->
+ Done = opt_ref_used_at(L, RefRegs, D, Done0, Regs),
+ opt_ref_used_in_all(Ls, RefRegs, D, Done, Regs);
opt_ref_used_in_all([], _, _, Done, _) -> Done.
-opt_ref_used_at(Fail, RefReg, D, Done0, Regs) ->
+opt_ref_used_at(Fail, RefRegs, D, Done0, Regs) ->
case gb_sets:is_member(Fail, Done0) of
true ->
Done0;
false ->
Is = beam_utils:code_at(Fail, D),
- Done = opt_ref_used_1(Is, RefReg, D, Done0, Regs),
+ Done = opt_ref_used_1(Is, RefRegs, D, Done0, Regs),
gb_sets:add(Fail, Done)
end.
@@ -408,15 +408,3 @@ regs_all_members([], _) -> true.
regs_is_member({x,N}, {Regs,_}) -> Regs band (1 bsl N) =/= 0;
regs_is_member({y,N}, {_,Regs}) -> Regs band (1 bsl N) =/= 0;
regs_is_member(_, _) -> false.
-
-%% regs_to_list(RegisterSet) -> [Register]
-%% Convert the register set to an explicit list of registers.
-regs_to_list({Xregs,Yregs}) ->
- regs_to_list_1(Xregs, 0, x, regs_to_list_1(Yregs, 0, y, [])).
-
-regs_to_list_1(0, _, _, Acc) ->
- Acc;
-regs_to_list_1(Regs, N, Tag, Acc) when (Regs band 1) =:= 1 ->
- regs_to_list_1(Regs bsr 1, N+1, Tag, [{Tag,N}|Acc]);
-regs_to_list_1(Regs, N, Tag, Acc) ->
- regs_to_list_1(Regs bsr 1, N+1, Tag, Acc).
diff --git a/lib/compiler/test/receive_SUITE.erl b/lib/compiler/test/receive_SUITE.erl
index b91f2922fb..e60584d4ab 100644
--- a/lib/compiler/test/receive_SUITE.erl
+++ b/lib/compiler/test/receive_SUITE.erl
@@ -188,7 +188,7 @@ ref_opt(Config) when is_list(Config) ->
ref_opt_1(Config) ->
?line DataDir = ?config(data_dir, Config),
?line PrivDir = ?config(priv_dir, Config),
- ?line Sources = filelib:wildcard(filename:join([DataDir,"ref_opt","*.erl"])),
+ Sources = filelib:wildcard(filename:join([DataDir,"ref_opt","*.{erl,S}"])),
?line test_lib:p_run(fun(Src) ->
do_ref_opt(Src, PrivDir)
end, Sources),
@@ -196,10 +196,15 @@ ref_opt_1(Config) ->
do_ref_opt(Source, PrivDir) ->
try
- {ok,Mod} = c:c(Source, [{outdir,PrivDir}]),
+ Ext = filename:extension(Source),
+ {ok,Mod} = compile:file(Source, [report_errors,report_warnings,
+ {outdir,PrivDir}] ++
+ [from_asm || Ext =:= ".S" ]),
+ Base = filename:rootname(filename:basename(Source), Ext),
+ code:purge(list_to_atom(Base)),
+ BeamFile = filename:join(PrivDir, Base),
+ code:load_abs(BeamFile),
ok = Mod:Mod(),
- Base = filename:rootname(filename:basename(Source), ".erl"),
- BeamFile = filename:join(PrivDir, Base),
{beam_file,Mod,_,_,_,Code} = beam_disasm:file(BeamFile),
case Base of
"no_"++_ ->
diff --git a/lib/compiler/test/receive_SUITE_data/ref_opt/yes_14.S b/lib/compiler/test/receive_SUITE_data/ref_opt/yes_14.S
new file mode 100644
index 0000000000..fd14228135
--- /dev/null
+++ b/lib/compiler/test/receive_SUITE_data/ref_opt/yes_14.S
@@ -0,0 +1,71 @@
+{module, yes_14}. %% version = 0
+
+{exports, [{f,2},{module_info,0},{module_info,1},{yes_14,0}]}.
+
+{attributes, []}.
+
+{labels, 12}.
+
+
+{function, yes_14, 0, 2}.
+ {label,1}.
+ {func_info,{atom,yes_14},{atom,yes_14},0}.
+ {label,2}.
+ {move,{atom,ok},{x,0}}.
+ return.
+
+
+{function, f, 2, 4}.
+ {label,3}.
+ {func_info,{atom,yes_14},{atom,f},2}.
+ {label,4}.
+ {allocate_heap,2,3,2}.
+ {move,{x,0},{y,1}}.
+ {put_tuple,2,{y,0}}.
+ {put,{atom,data}}.
+ {put,{x,1}}.
+ {call_ext,0,{extfunc,erlang,make_ref,0}}. % Ref in [x0]
+ {test_heap,4,1}.
+ {put_tuple,3,{x,1}}.
+ {put,{atom,request}}.
+ {put,{x,0}}.
+ {put,{y,0}}.
+ {move,{x,0},{y,0}}. % Ref in [x0,y0]
+ {move,{y,1},{x,0}}. % Ref in [y0]
+ {kill,{y,1}}.
+ send.
+ {move,{y,0},{x,0}}. % Ref in [x0,y0]
+ {move,{x,0},{y,1}}. % Ref in [x0,y0,y1]
+ {label,5}.
+ {loop_rec,{f,7},{x,0}}. % Ref in [y0,y1]
+ {test,is_tuple,{f,6},[{x,0}]}.
+ {test,test_arity,{f,6},[{x,0},2]}.
+ {get_tuple_element,{x,0},0,{x,1}}.
+ {get_tuple_element,{x,0},1,{x,2}}.
+ {test,is_eq_exact,{f,6},[{x,1},{atom,reply}]}.
+ {test,is_eq_exact,{f,6},[{x,2},{y,1}]}.
+ remove_message.
+ {move,{atom,ok},{x,0}}.
+ {deallocate,2}.
+ return.
+ {label,6}.
+ {loop_rec_end,{f,5}}.
+ {label,7}.
+ {wait,{f,5}}.
+
+
+{function, module_info, 0, 9}.
+ {label,8}.
+ {func_info,{atom,yes_14},{atom,module_info},0}.
+ {label,9}.
+ {move,{atom,yes_14},{x,0}}.
+ {call_ext_only,1,{extfunc,erlang,get_module_info,1}}.
+
+
+{function, module_info, 1, 11}.
+ {label,10}.
+ {func_info,{atom,yes_14},{atom,module_info},1}.
+ {label,11}.
+ {move,{x,0},{x,1}}.
+ {move,{atom,yes_14},{x,0}}.
+ {call_ext_only,2,{extfunc,erlang,get_module_info,2}}.
diff --git a/lib/compiler/test/receive_SUITE_data/ref_opt/yes_5.erl b/lib/compiler/test/receive_SUITE_data/ref_opt/yes_5.erl
index 3f02fba6a6..5070e3e546 100644
--- a/lib/compiler/test/receive_SUITE_data/ref_opt/yes_5.erl
+++ b/lib/compiler/test/receive_SUITE_data/ref_opt/yes_5.erl
@@ -24,11 +24,7 @@ do_call(Process, Label, Request, Timeout) ->
{'DOWN', Mref, _, _, Reason} ->
exit(Reason)
after Timeout ->
- erlang:demonitor(Mref),
- receive
- {'DOWN', Mref, _, _, _} -> true
- after 0 -> true
- end,
+ erlang:demonitor(Mref, [flush]),
exit(timeout)
end
catch
diff --git a/lib/crypto/c_src/crypto.c b/lib/crypto/c_src/crypto.c
index fac77308f6..9d43a1d907 100644
--- a/lib/crypto/c_src/crypto.c
+++ b/lib/crypto/c_src/crypto.c
@@ -74,6 +74,19 @@
# define HAVE_DES_ede3_cfb_encrypt
#endif
+#if OPENSSL_VERSION_NUMBER >= 0x009080ffL \
+ && !defined(OPENSSL_NO_EC) \
+ && !defined(OPENSSL_NO_ECDH) \
+ && !defined(OPENSSL_NO_ECDSA)
+# define HAVE_EC
+#endif
+
+#if defined(HAVE_EC)
+#include <openssl/ec.h>
+#include <openssl/ecdh.h>
+#include <openssl/ecdsa.h>
+#endif
+
#ifdef VALGRIND
# include <valgrind/memcheck.h>
@@ -192,7 +205,7 @@ static ERL_NIF_TERM rand_bytes_3(ErlNifEnv* env, int argc, const ERL_NIF_TERM ar
static ERL_NIF_TERM strong_rand_mpint_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
static ERL_NIF_TERM rand_uniform_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
static ERL_NIF_TERM mod_exp_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
-static ERL_NIF_TERM dss_verify(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
+static ERL_NIF_TERM dss_verify_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
static ERL_NIF_TERM rsa_verify_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
static ERL_NIF_TERM aes_cbc_crypt(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
static ERL_NIF_TERM exor(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
@@ -209,13 +222,19 @@ static ERL_NIF_TERM dh_check(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]
static ERL_NIF_TERM dh_generate_key_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
static ERL_NIF_TERM dh_compute_key_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
static ERL_NIF_TERM srp_value_B_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
-static ERL_NIF_TERM srp_client_secret_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
-static ERL_NIF_TERM srp_server_secret_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
+static ERL_NIF_TERM srp_user_secret_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
+static ERL_NIF_TERM srp_host_secret_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
static ERL_NIF_TERM bf_cfb64_crypt(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
static ERL_NIF_TERM bf_cbc_crypt(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
static ERL_NIF_TERM bf_ecb_crypt(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
static ERL_NIF_TERM blowfish_ofb64_encrypt(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
+static ERL_NIF_TERM ec_key_to_term_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
+static ERL_NIF_TERM term_to_ec_key_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
+static ERL_NIF_TERM ec_key_generate(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
+static ERL_NIF_TERM ecdsa_sign_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
+static ERL_NIF_TERM ecdsa_verify_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
+static ERL_NIF_TERM ecdh_compute_key_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
/* helpers */
@@ -247,6 +266,11 @@ static void hmac_sha512(unsigned char *key, int klen,
unsigned char *dbuf, int dlen,
unsigned char *hmacbuf);
#endif
+#ifdef HAVE_EC
+static EC_KEY* ec_key_new(ErlNifEnv* env, ERL_NIF_TERM curve_arg);
+static int term2point(ErlNifEnv* env, ERL_NIF_TERM term,
+ EC_GROUP *group, EC_POINT **pptr);
+#endif
static int library_refc = 0; /* number of users of this dynamic library */
@@ -311,7 +335,7 @@ static ErlNifFunc nif_funcs[] = {
{"strong_rand_mpint_nif", 3, strong_rand_mpint_nif},
{"rand_uniform_nif", 2, rand_uniform_nif},
{"mod_exp_nif", 4, mod_exp_nif},
- {"dss_verify", 4, dss_verify},
+ {"dss_verify_nif", 4, dss_verify_nif},
{"rsa_verify_nif", 4, rsa_verify_nif},
{"aes_cbc_crypt", 4, aes_cbc_crypt},
{"exor", 2, exor},
@@ -325,16 +349,120 @@ static ErlNifFunc nif_funcs[] = {
{"rsa_private_crypt", 4, rsa_private_crypt},
{"dh_generate_parameters_nif", 2, dh_generate_parameters_nif},
{"dh_check", 1, dh_check},
- {"dh_generate_key_nif", 2, dh_generate_key_nif},
+ {"dh_generate_key_nif", 3, dh_generate_key_nif},
{"dh_compute_key_nif", 3, dh_compute_key_nif},
{"srp_value_B_nif", 5, srp_value_B_nif},
- {"srp_client_secret_nif", 7, srp_client_secret_nif},
- {"srp_server_secret_nif", 5, srp_server_secret_nif},
+ {"srp_user_secret_nif", 7, srp_user_secret_nif},
+ {"srp_host_secret_nif", 5, srp_host_secret_nif},
{"bf_cfb64_crypt", 4, bf_cfb64_crypt},
{"bf_cbc_crypt", 4, bf_cbc_crypt},
{"bf_ecb_crypt", 3, bf_ecb_crypt},
- {"blowfish_ofb64_encrypt", 3, blowfish_ofb64_encrypt}
+ {"blowfish_ofb64_encrypt", 3, blowfish_ofb64_encrypt},
+
+ {"ec_key_to_term_nif", 1, ec_key_to_term_nif},
+ {"term_to_ec_key_nif", 3, term_to_ec_key_nif},
+ {"ec_key_generate", 1, ec_key_generate},
+ {"ecdsa_sign_nif", 3, ecdsa_sign_nif},
+ {"ecdsa_verify_nif", 4, ecdsa_verify_nif},
+ {"ecdh_compute_key_nif", 2, ecdh_compute_key_nif}
+};
+
+#if defined(HAVE_EC)
+struct nid_map {
+ char *name;
+ int nid;
+ ERL_NIF_TERM atom;
+};
+
+static struct nid_map ec_curves[] = {
+ /* prime field curves */
+ /* secg curves */
+ { "secp112r1", NID_secp112r1 },
+ { "secp112r2", NID_secp112r2 },
+ { "secp128r1", NID_secp128r1 },
+ { "secp128r2", NID_secp128r2 },
+ { "secp160k1", NID_secp160k1 },
+ { "secp160r1", NID_secp160r1 },
+ { "secp160r2", NID_secp160r2 },
+ /* SECG secp192r1 is the same as X9.62 prime192v1 */
+ { "secp192r1", NID_X9_62_prime192v1 },
+ { "secp192k1", NID_secp192k1 },
+ { "secp224k1", NID_secp224k1 },
+ { "secp224r1", NID_secp224r1 },
+ { "secp256k1", NID_secp256k1 },
+ /* SECG secp256r1 is the same as X9.62 prime256v1 */
+ { "secp256r1", NID_X9_62_prime256v1 },
+ { "secp384r1", NID_secp384r1 },
+ { "secp521r1", NID_secp521r1 },
+ /* X9.62 curves */
+ { "prime192v1", NID_X9_62_prime192v1 },
+ { "prime192v2", NID_X9_62_prime192v2 },
+ { "prime192v3", NID_X9_62_prime192v3 },
+ { "prime239v1", NID_X9_62_prime239v1 },
+ { "prime239v2", NID_X9_62_prime239v2 },
+ { "prime239v3", NID_X9_62_prime239v3 },
+ { "prime256v1", NID_X9_62_prime256v1 },
+ /* characteristic two field curves */
+ /* NIST/SECG curves */
+ { "sect113r1", NID_sect113r1 },
+ { "sect113r2", NID_sect113r2 },
+ { "sect131r1", NID_sect131r1 },
+ { "sect131r2", NID_sect131r2 },
+ { "sect163k1", NID_sect163k1 },
+ { "sect163r1", NID_sect163r1 },
+ { "sect163r2", NID_sect163r2 },
+ { "sect193r1", NID_sect193r1 },
+ { "sect193r2", NID_sect193r2 },
+ { "sect233k1", NID_sect233k1 },
+ { "sect233r1", NID_sect233r1 },
+ { "sect239k1", NID_sect239k1 },
+ { "sect283k1", NID_sect283k1 },
+ { "sect283r1", NID_sect283r1 },
+ { "sect409k1", NID_sect409k1 },
+ { "sect409r1", NID_sect409r1 },
+ { "sect571k1", NID_sect571k1 },
+ { "sect571r1", NID_sect571r1 },
+ /* X9.62 curves */
+ { "c2pnb163v1", NID_X9_62_c2pnb163v1 },
+ { "c2pnb163v2", NID_X9_62_c2pnb163v2 },
+ { "c2pnb163v3", NID_X9_62_c2pnb163v3 },
+ { "c2pnb176v1", NID_X9_62_c2pnb176v1 },
+ { "c2tnb191v1", NID_X9_62_c2tnb191v1 },
+ { "c2tnb191v2", NID_X9_62_c2tnb191v2 },
+ { "c2tnb191v3", NID_X9_62_c2tnb191v3 },
+ { "c2pnb208w1", NID_X9_62_c2pnb208w1 },
+ { "c2tnb239v1", NID_X9_62_c2tnb239v1 },
+ { "c2tnb239v2", NID_X9_62_c2tnb239v2 },
+ { "c2tnb239v3", NID_X9_62_c2tnb239v3 },
+ { "c2pnb272w1", NID_X9_62_c2pnb272w1 },
+ { "c2pnb304w1", NID_X9_62_c2pnb304w1 },
+ { "c2tnb359v1", NID_X9_62_c2tnb359v1 },
+ { "c2pnb368w1", NID_X9_62_c2pnb368w1 },
+ { "c2tnb431r1", NID_X9_62_c2tnb431r1 },
+ /* the WAP/WTLS curves
+ * [unlike SECG, spec has its own OIDs for curves from X9.62] */
+ { "wtls1", NID_wap_wsg_idm_ecid_wtls1 },
+ { "wtls3", NID_wap_wsg_idm_ecid_wtls3 },
+ { "wtls4", NID_wap_wsg_idm_ecid_wtls4 },
+ { "wtls5", NID_wap_wsg_idm_ecid_wtls5 },
+ { "wtls6", NID_wap_wsg_idm_ecid_wtls6 },
+ { "wtls7", NID_wap_wsg_idm_ecid_wtls7 },
+ { "wtls8", NID_wap_wsg_idm_ecid_wtls8 },
+ { "wtls9", NID_wap_wsg_idm_ecid_wtls9 },
+ { "wtls10", NID_wap_wsg_idm_ecid_wtls10 },
+ { "wtls11", NID_wap_wsg_idm_ecid_wtls11 },
+ { "wtls12", NID_wap_wsg_idm_ecid_wtls12 },
+ /* IPSec curves */
+ { "ipsec3", NID_ipsec3 },
+ { "ipsec4", NID_ipsec4 }
+};
+
+#define EC_CURVES_CNT (sizeof(ec_curves)/sizeof(struct nid_map))
+
+struct nif_ec_key {
+ EC_KEY *key;
};
+#endif
ERL_NIF_INIT(crypto,nif_funcs,load,NULL,upgrade,unload)
@@ -368,6 +496,7 @@ static ERL_NIF_TERM atom_sha256;
static ERL_NIF_TERM atom_sha384;
static ERL_NIF_TERM atom_sha512;
static ERL_NIF_TERM atom_md5;
+static ERL_NIF_TERM atom_md4;
static ERL_NIF_TERM atom_ripemd160;
static ERL_NIF_TERM atom_error;
static ERL_NIF_TERM atom_rsa_pkcs1_padding;
@@ -386,6 +515,19 @@ static ERL_NIF_TERM atom_none;
static ERL_NIF_TERM atom_notsup;
static ERL_NIF_TERM atom_digest;
+static ERL_NIF_TERM atom_ec;
+
+#if defined(HAVE_EC)
+static ERL_NIF_TERM atom_prime_field;
+static ERL_NIF_TERM atom_characteristic_two_field;
+static ERL_NIF_TERM atom_tpbasis;
+static ERL_NIF_TERM atom_ppbasis;
+static ERL_NIF_TERM atom_onbasis;
+
+static ErlNifResourceType* res_type_ec_key;
+static void ec_key_dtor(ErlNifEnv* env, void* obj);
+#endif
+
/*
#define PRINTF_ERR0(FMT) enif_fprintf(stderr, FMT "\n")
#define PRINTF_ERR1(FMT, A1) enif_fprintf(stderr, FMT "\n", A1)
@@ -415,6 +557,7 @@ static void error_handler(void* null, const char* errstr)
static int init(ErlNifEnv* env, ERL_NIF_TERM load_info)
{
+ int i;
ErlNifSysInfo sys_info;
get_crypto_callbacks_t* funcp;
struct crypto_callbacks* ccb;
@@ -448,6 +591,7 @@ static int init(ErlNifEnv* env, ERL_NIF_TERM load_info)
atom_sha256 = enif_make_atom(env,"sha256");
atom_sha384 = enif_make_atom(env,"sha384");
atom_sha512 = enif_make_atom(env,"sha512");
+ atom_md4 = enif_make_atom(env,"md4");
atom_md5 = enif_make_atom(env,"md5");
atom_ripemd160 = enif_make_atom(env,"ripemd160");
atom_error = enif_make_atom(env,"error");
@@ -466,6 +610,23 @@ static int init(ErlNifEnv* env, ERL_NIF_TERM load_info)
atom_notsup = enif_make_atom(env,"notsup");
atom_digest = enif_make_atom(env,"digest");
+#if defined(HAVE_EC)
+ atom_ec = enif_make_atom(env,"ec");
+ atom_prime_field = enif_make_atom(env,"prime_field");
+ atom_characteristic_two_field = enif_make_atom(env,"characteristic_two_field");
+ atom_tpbasis = enif_make_atom(env,"tpbasis");
+ atom_ppbasis = enif_make_atom(env,"ppbasis");
+ atom_onbasis = enif_make_atom(env,"onbasis");
+
+ for (i = 0; i < EC_CURVES_CNT; i++)
+ ec_curves[i].atom = enif_make_atom(env,ec_curves[i].name);
+
+ res_type_ec_key = enif_open_resource_type(env,NULL,"crypto.EC_KEY",
+ ec_key_dtor,
+ ERL_NIF_RT_CREATE|ERL_NIF_RT_TAKEOVER,
+ NULL);
+#endif
+
init_digest_types(env);
init_algorithms_types();
@@ -549,12 +710,12 @@ static void unload(ErlNifEnv* env, void* priv_data)
}
static int algos_cnt;
-static ERL_NIF_TERM algos[7]; /* increase when extending the list */
+static ERL_NIF_TERM algos[9]; /* increase when extending the list */
static void init_algorithms_types(void)
{
algos_cnt = 0;
-
+ algos[algos_cnt++] = atom_md4;
algos[algos_cnt++] = atom_md5;
algos[algos_cnt++] = atom_sha;
algos[algos_cnt++] = atom_ripemd160;
@@ -570,6 +731,9 @@ static void init_algorithms_types(void)
#ifdef HAVE_SHA512
algos[algos_cnt++] = atom_sha512;
#endif
+#if defined(HAVE_EC)
+ algos[algos_cnt++] = atom_ec;
+#endif
}
static ERL_NIF_TERM algorithms(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
@@ -1631,13 +1795,7 @@ static ERL_NIF_TERM mod_exp_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM arg
return ret;
}
-static int inspect_mpint(ErlNifEnv* env, ERL_NIF_TERM term, ErlNifBinary* bin)
-{
- return enif_inspect_binary(env, term, bin) &&
- bin->size >= 4 && get_int32(bin->data) == bin->size-4;
-}
-
-static ERL_NIF_TERM dss_verify(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
+static ERL_NIF_TERM dss_verify_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
{/* (DigestType|none, Data|{digest,Digest}, Signature,Key=[P, Q, G, Y]) */
ErlNifBinary data_bin, sign_bin;
BIGNUM *dsa_p = NULL, *dsa_q = NULL, *dsa_g = NULL, *dsa_y = NULL;
@@ -1660,10 +1818,10 @@ static ERL_NIF_TERM dss_verify(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv
digest = data_bin.data;
}
else {
- if (!inspect_mpint(env, argv[1], &data_bin)) {
+ if (!enif_inspect_binary(env, argv[1], &data_bin)) {
return enif_make_badarg(env);
}
- SHA1(data_bin.data+4, data_bin.size-4, hmacbuf);
+ SHA1(data_bin.data, data_bin.size, hmacbuf);
digest = hmacbuf;
}
}
@@ -1675,15 +1833,15 @@ static ERL_NIF_TERM dss_verify(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv
return enif_make_badarg(env);
}
- if (!inspect_mpint(env, argv[2], &sign_bin)
+ if (!enif_inspect_binary(env, argv[2], &sign_bin)
|| !enif_get_list_cell(env, argv[3], &head, &tail)
- || !get_bn_from_mpint(env, head, &dsa_p)
+ || !get_bn_from_bin(env, head, &dsa_p)
|| !enif_get_list_cell(env, tail, &head, &tail)
- || !get_bn_from_mpint(env, head, &dsa_q)
+ || !get_bn_from_bin(env, head, &dsa_q)
|| !enif_get_list_cell(env, tail, &head, &tail)
- || !get_bn_from_mpint(env, head, &dsa_g)
+ || !get_bn_from_bin(env, head, &dsa_g)
|| !enif_get_list_cell(env, tail, &head, &tail)
- || !get_bn_from_mpint(env, head, &dsa_y)
+ || !get_bn_from_bin(env, head, &dsa_y)
|| !enif_is_empty_list(env,tail)) {
if (dsa_p) BN_free(dsa_p);
@@ -1700,7 +1858,7 @@ static ERL_NIF_TERM dss_verify(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv
dsa->priv_key = NULL;
dsa->pub_key = dsa_y;
i = DSA_verify(0, digest, SHA_DIGEST_LENGTH,
- sign_bin.data+4, sign_bin.size-4, dsa);
+ sign_bin.data, sign_bin.size, dsa);
DSA_free(dsa);
return(i > 0) ? atom_true : atom_false;
}
@@ -1826,11 +1984,11 @@ static ERL_NIF_TERM rsa_verify_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM
rsa = RSA_new();
- if (!inspect_mpint(env, argv[2], &sign_bin)
+ if (!enif_inspect_binary(env, argv[2], &sign_bin)
|| !enif_get_list_cell(env, argv[3], &head, &tail)
- || !get_bn_from_mpint(env, head, &rsa->e)
+ || !get_bn_from_bin(env, head, &rsa->e)
|| !enif_get_list_cell(env, tail, &head, &tail)
- || !get_bn_from_mpint(env, head, &rsa->n)
+ || !get_bn_from_bin(env, head, &rsa->n)
|| !enif_is_empty_list(env, tail)) {
ret = enif_make_badarg(env);
@@ -1846,9 +2004,9 @@ static ERL_NIF_TERM rsa_verify_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM
}
digest = data_bin.data;
}
- else if (inspect_mpint(env, argv[1], &data_bin)) {
+ else if (enif_inspect_binary(env, argv[1], &data_bin)) {
digest = hmacbuf;
- digp->funcp(data_bin.data+4, data_bin.size-4, digest);
+ digp->funcp(data_bin.data, data_bin.size, digest);
}
else {
ret = enif_make_badarg(env);
@@ -1856,7 +2014,7 @@ static ERL_NIF_TERM rsa_verify_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM
}
i = RSA_verify(digp->NID_type, digest, digp->len,
- sign_bin.data+4, sign_bin.size-4, rsa);
+ sign_bin.data, sign_bin.size, rsa);
ret = (i==1 ? atom_true : atom_false);
@@ -2001,22 +2159,22 @@ static int get_rsa_private_key(ErlNifEnv* env, ERL_NIF_TERM key, RSA *rsa)
ERL_NIF_TERM head, tail;
if (!enif_get_list_cell(env, key, &head, &tail)
- || !get_bn_from_mpint(env, head, &rsa->e)
+ || !get_bn_from_bin(env, head, &rsa->e)
|| !enif_get_list_cell(env, tail, &head, &tail)
- || !get_bn_from_mpint(env, head, &rsa->n)
+ || !get_bn_from_bin(env, head, &rsa->n)
|| !enif_get_list_cell(env, tail, &head, &tail)
- || !get_bn_from_mpint(env, head, &rsa->d)
+ || !get_bn_from_bin(env, head, &rsa->d)
|| (!enif_is_empty_list(env, tail) &&
(!enif_get_list_cell(env, tail, &head, &tail)
- || !get_bn_from_mpint(env, head, &rsa->p)
+ || !get_bn_from_bin(env, head, &rsa->p)
|| !enif_get_list_cell(env, tail, &head, &tail)
- || !get_bn_from_mpint(env, head, &rsa->q)
+ || !get_bn_from_bin(env, head, &rsa->q)
|| !enif_get_list_cell(env, tail, &head, &tail)
- || !get_bn_from_mpint(env, head, &rsa->dmp1)
+ || !get_bn_from_bin(env, head, &rsa->dmp1)
|| !enif_get_list_cell(env, tail, &head, &tail)
- || !get_bn_from_mpint(env, head, &rsa->dmq1)
+ || !get_bn_from_bin(env, head, &rsa->dmq1)
|| !enif_get_list_cell(env, tail, &head, &tail)
- || !get_bn_from_mpint(env, head, &rsa->iqmp)
+ || !get_bn_from_bin(env, head, &rsa->iqmp)
|| !enif_is_empty_list(env, tail)))) {
return 0;
}
@@ -2053,11 +2211,11 @@ static ERL_NIF_TERM rsa_sign_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM ar
digest = data_bin.data;
}
else {
- if (!inspect_mpint(env,argv[1],&data_bin)) {
+ if (!enif_inspect_binary(env,argv[1],&data_bin)) {
return enif_make_badarg(env);
}
digest = hmacbuf;
- digp->funcp(data_bin.data+4, data_bin.size-4, digest);
+ digp->funcp(data_bin.data, data_bin.size, digest);
}
rsa = RSA_new();
@@ -2112,10 +2270,10 @@ static ERL_NIF_TERM dss_sign_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM ar
digest = data_bin.data;
}
else {
- if (!inspect_mpint(env,argv[1],&data_bin)) {
+ if (!enif_inspect_binary(env,argv[1],&data_bin)) {
return enif_make_badarg(env);
}
- SHA1(data_bin.data+4, data_bin.size-4, hmacbuf);
+ SHA1(data_bin.data, data_bin.size, hmacbuf);
digest = hmacbuf;
}
}
@@ -2133,13 +2291,13 @@ static ERL_NIF_TERM dss_sign_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM ar
dsa->pub_key = NULL;
if (!enif_get_list_cell(env, argv[2], &head, &tail)
- || !get_bn_from_mpint(env, head, &dsa->p)
+ || !get_bn_from_bin(env, head, &dsa->p)
|| !enif_get_list_cell(env, tail, &head, &tail)
- || !get_bn_from_mpint(env, head, &dsa->q)
+ || !get_bn_from_bin(env, head, &dsa->q)
|| !enif_get_list_cell(env, tail, &head, &tail)
- || !get_bn_from_mpint(env, head, &dsa->g)
+ || !get_bn_from_bin(env, head, &dsa->g)
|| !enif_get_list_cell(env, tail, &head, &tail)
- || !get_bn_from_mpint(env, head, &dsa->priv_key)
+ || !get_bn_from_bin(env, head, &dsa->priv_key)
|| !enif_is_empty_list(env,tail)) {
DSA_free(dsa);
return enif_make_badarg(env);
@@ -2187,9 +2345,9 @@ static ERL_NIF_TERM rsa_public_crypt(ErlNifEnv* env, int argc, const ERL_NIF_TER
if (!enif_inspect_binary(env, argv[0], &data_bin)
|| !enif_get_list_cell(env, argv[1], &head, &tail)
- || !get_bn_from_mpint(env, head, &rsa->e)
+ || !get_bn_from_bin(env, head, &rsa->e)
|| !enif_get_list_cell(env, tail, &head, &tail)
- || !get_bn_from_mpint(env, head, &rsa->n)
+ || !get_bn_from_bin(env, head, &rsa->n)
|| !enif_is_empty_list(env,tail)
|| !rsa_pad(argv[2], &padding)) {
@@ -2286,14 +2444,12 @@ static ERL_NIF_TERM dh_generate_parameters_nif(ErlNifEnv* env, int argc, const E
}
p_len = BN_num_bytes(dh_params->p);
g_len = BN_num_bytes(dh_params->g);
- p_ptr = enif_make_new_binary(env, p_len+4, &ret_p);
- g_ptr = enif_make_new_binary(env, g_len+4, &ret_g);
- put_int32(p_ptr, p_len);
- put_int32(g_ptr, g_len);
- BN_bn2bin(dh_params->p, p_ptr+4);
- BN_bn2bin(dh_params->g, g_ptr+4);
- ERL_VALGRIND_MAKE_MEM_DEFINED(p_ptr+4, p_len);
- ERL_VALGRIND_MAKE_MEM_DEFINED(g_ptr+4, g_len);
+ p_ptr = enif_make_new_binary(env, p_len, &ret_p);
+ g_ptr = enif_make_new_binary(env, g_len, &ret_g);
+ BN_bn2bin(dh_params->p, p_ptr);
+ BN_bn2bin(dh_params->g, g_ptr);
+ ERL_VALGRIND_MAKE_MEM_DEFINED(p_ptr, p_len);
+ ERL_VALGRIND_MAKE_MEM_DEFINED(g_ptr, g_len);
DH_free(dh_params);
return enif_make_list2(env, ret_p, ret_g);
}
@@ -2305,9 +2461,9 @@ static ERL_NIF_TERM dh_check(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]
ERL_NIF_TERM ret, head, tail;
if (!enif_get_list_cell(env, argv[0], &head, &tail)
- || !get_bn_from_mpint(env, head, &dh_params->p)
+ || !get_bn_from_bin(env, head, &dh_params->p)
|| !enif_get_list_cell(env, tail, &head, &tail)
- || !get_bn_from_mpint(env, head, &dh_params->g)
+ || !get_bn_from_bin(env, head, &dh_params->g)
|| !enif_is_empty_list(env,tail)) {
DH_free(dh_params);
@@ -2329,19 +2485,21 @@ static ERL_NIF_TERM dh_check(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]
}
static ERL_NIF_TERM dh_generate_key_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
-{/* (PrivKey, DHParams=[P,G]) */
+{/* (PrivKey, DHParams=[P,G], Mpint) */
DH* dh_params = DH_new();
int pub_len, prv_len;
unsigned char *pub_ptr, *prv_ptr;
ERL_NIF_TERM ret, ret_pub, ret_prv, head, tail;
+ int mpint; /* 0 or 4 */
- if (!(get_bn_from_mpint(env, argv[0], &dh_params->priv_key)
+ if (!(get_bn_from_bin(env, argv[0], &dh_params->priv_key)
|| argv[0] == atom_undefined)
|| !enif_get_list_cell(env, argv[1], &head, &tail)
- || !get_bn_from_mpint(env, head, &dh_params->p)
+ || !get_bn_from_bin(env, head, &dh_params->p)
|| !enif_get_list_cell(env, tail, &head, &tail)
- || !get_bn_from_mpint(env, head, &dh_params->g)
- || !enif_is_empty_list(env, tail)) {
+ || !get_bn_from_bin(env, head, &dh_params->g)
+ || !enif_is_empty_list(env, tail)
+ || !enif_get_int(env, argv[2], &mpint) || (mpint & ~4)) {
DH_free(dh_params);
return enif_make_badarg(env);
}
@@ -2349,14 +2507,16 @@ static ERL_NIF_TERM dh_generate_key_nif(ErlNifEnv* env, int argc, const ERL_NIF_
if (DH_generate_key(dh_params)) {
pub_len = BN_num_bytes(dh_params->pub_key);
prv_len = BN_num_bytes(dh_params->priv_key);
- pub_ptr = enif_make_new_binary(env, pub_len+4, &ret_pub);
- prv_ptr = enif_make_new_binary(env, prv_len+4, &ret_prv);
- put_int32(pub_ptr, pub_len);
- put_int32(prv_ptr, prv_len);
- BN_bn2bin(dh_params->pub_key, pub_ptr+4);
- BN_bn2bin(dh_params->priv_key, prv_ptr+4);
- ERL_VALGRIND_MAKE_MEM_DEFINED(pub_ptr+4, pub_len);
- ERL_VALGRIND_MAKE_MEM_DEFINED(prv_ptr+4, prv_len);
+ pub_ptr = enif_make_new_binary(env, pub_len+mpint, &ret_pub);
+ prv_ptr = enif_make_new_binary(env, prv_len+mpint, &ret_prv);
+ if (mpint) {
+ put_int32(pub_ptr, pub_len); pub_ptr += 4;
+ put_int32(prv_ptr, prv_len); prv_ptr += 4;
+ }
+ BN_bn2bin(dh_params->pub_key, pub_ptr);
+ BN_bn2bin(dh_params->priv_key, prv_ptr);
+ ERL_VALGRIND_MAKE_MEM_DEFINED(pub_ptr, pub_len);
+ ERL_VALGRIND_MAKE_MEM_DEFINED(prv_ptr, prv_len);
ret = enif_make_tuple2(env, ret_pub, ret_prv);
}
else {
@@ -2374,12 +2534,12 @@ static ERL_NIF_TERM dh_compute_key_nif(ErlNifEnv* env, int argc, const ERL_NIF_T
ErlNifBinary ret_bin;
ERL_NIF_TERM ret, head, tail;
- if (!get_bn_from_mpint(env, argv[0], &pubkey)
- || !get_bn_from_mpint(env, argv[1], &dh_params->priv_key)
+ if (!get_bn_from_bin(env, argv[0], &pubkey)
+ || !get_bn_from_bin(env, argv[1], &dh_params->priv_key)
|| !enif_get_list_cell(env, argv[2], &head, &tail)
- || !get_bn_from_mpint(env, head, &dh_params->p)
+ || !get_bn_from_bin(env, head, &dh_params->p)
|| !enif_get_list_cell(env, tail, &head, &tail)
- || !get_bn_from_mpint(env, head, &dh_params->g)
+ || !get_bn_from_bin(env, head, &dh_params->g)
|| !enif_is_empty_list(env, tail)) {
ret = enif_make_badarg(env);
@@ -2457,7 +2617,7 @@ static ERL_NIF_TERM srp_value_B_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM
return ret;
}
-static ERL_NIF_TERM srp_client_secret_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
+static ERL_NIF_TERM srp_user_secret_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
{/* (a, u, B, Multiplier, Prime, Exponent, Generator) */
/*
<premaster secret> = (B - (k * g^x)) ^ (a + (u * x)) % N
@@ -2537,7 +2697,7 @@ static ERL_NIF_TERM srp_client_secret_nif(ErlNifEnv* env, int argc, const ERL_NI
return ret;
}
-static ERL_NIF_TERM srp_server_secret_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
+static ERL_NIF_TERM srp_host_secret_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
{/* (Verifier, b, u, A, Prime) */
/*
<premaster secret> = (A * v^u) ^ b % N
@@ -2686,7 +2846,554 @@ static ERL_NIF_TERM blowfish_ofb64_encrypt(ErlNifEnv* env, int argc, const ERL_N
return ret;
}
+#if defined(HAVE_EC)
+static int term2curve_id(ERL_NIF_TERM nid)
+{
+ int i;
+
+ for (i = 0; i < EC_CURVES_CNT; i++)
+ if (ec_curves[i].atom == nid)
+ return ec_curves[i].nid;
+
+ return 0;
+}
+static EC_KEY* ec_key_new(ErlNifEnv* env, ERL_NIF_TERM curve_arg)
+{
+ EC_KEY *key = NULL;
+ int nid = 0;
+ int c_arity = -1;
+ const ERL_NIF_TERM* curve;
+ ErlNifBinary seed;
+ BIGNUM *p = NULL;
+ BIGNUM *a = NULL;
+ BIGNUM *b = NULL;
+ BIGNUM *bn_order = NULL;
+ BIGNUM *cofactor = NULL;
+ EC_GROUP *group = NULL;
+ EC_POINT *point = NULL;
+
+ if (enif_is_atom(env, curve_arg)) {
+ nid = term2curve_id(curve_arg);
+ if (nid == 0)
+ return NULL;
+ key = EC_KEY_new_by_curve_name(nid);
+ }
+ else if (enif_is_tuple(env, curve_arg)
+ && enif_get_tuple(env,curve_arg,&c_arity,&curve)
+ && c_arity == 5
+ && get_bn_from_bin(env, curve[3], &bn_order)
+ && (curve[4] != atom_none && get_bn_from_bin(env, curve[4], &cofactor))) {
+ //* {Field, Prime, Point, Order, CoFactor} = Curve */
+
+ int f_arity = -1;
+ const ERL_NIF_TERM* field;
+ int p_arity = -1;
+ const ERL_NIF_TERM* prime;
+
+ long field_bits;
+
+ /* {A, B, Seed} = Prime */
+ if (!enif_get_tuple(env,curve[1],&p_arity,&prime)
+ || !get_bn_from_bin(env, prime[0], &a)
+ || !get_bn_from_bin(env, prime[1], &b))
+ goto out_err;
+
+ if (!enif_get_tuple(env,curve[0],&f_arity,&field))
+ goto out_err;
+
+ if (f_arity == 2 && field[0] == atom_prime_field) {
+ /* {prime_field, Prime} */
+
+ if (!get_bn_from_bin(env, field[1], &p))
+ goto out_err;
+
+ if (BN_is_negative(p) || BN_is_zero(p))
+ goto out_err;
+
+ field_bits = BN_num_bits(p);
+ if (field_bits > OPENSSL_ECC_MAX_FIELD_BITS)
+ goto out_err;
+
+ /* create the EC_GROUP structure */
+ group = EC_GROUP_new_curve_GFp(p, a, b, NULL);
+
+ } else if (f_arity == 3 && field[0] == atom_characteristic_two_field) {
+ /* {characteristic_two_field, M, Basis} */
+
+ int b_arity = -1;
+ const ERL_NIF_TERM* basis;
+ unsigned int k1, k2, k3;
+
+ if ((p = BN_new()) == NULL)
+ goto out_err;
+
+ if (!enif_get_long(env, field[1], &field_bits)
+ || field_bits > OPENSSL_ECC_MAX_FIELD_BITS)
+ goto out_err;
+
+ if (enif_get_tuple(env,field[2],&b_arity,&basis)) {
+ if (b_arity == 2
+ && basis[0] == atom_tpbasis
+ && enif_get_uint(env, basis[1], &k1)) {
+ /* {tpbasis, k} = Basis */
+
+ if (!(field_bits > k1 && k1 > 0))
+ goto out_err;
+
+ /* create the polynomial */
+ if (!BN_set_bit(p, (int)field_bits)
+ || !BN_set_bit(p, (int)k1)
+ || !BN_set_bit(p, 0))
+ goto out_err;
+
+ } else if (b_arity == 4
+ && basis[0] == atom_ppbasis
+ && enif_get_uint(env, basis[1], &k1)
+ && enif_get_uint(env, basis[2], &k2)
+ && enif_get_uint(env, basis[3], &k3)) {
+ /* {ppbasis, k1, k2, k3} = Basis */
+
+ if (!(field_bits > k3 && k3 > k2 && k2 > k1 && k1 > 0))
+ goto out_err;
+
+ /* create the polynomial */
+ if (!BN_set_bit(p, (int)field_bits)
+ || !BN_set_bit(p, (int)k1)
+ || !BN_set_bit(p, (int)k2)
+ || !BN_set_bit(p, (int)k3)
+ || !BN_set_bit(p, 0))
+ goto out_err;
+
+ } else
+ goto out_err;
+ } else if (field[2] == atom_onbasis) {
+ /* onbasis = Basis */
+ /* no parameters */
+ goto out_err;
+
+ } else
+ goto out_err;
+
+ group = EC_GROUP_new_curve_GF2m(p, a, b, NULL);
+ } else
+ goto out_err;
+
+ if (enif_inspect_binary(env, prime[2], &seed)) {
+ EC_GROUP_set_seed(group, seed.data, seed.size);
+ }
+
+ if (!term2point(env, curve[2], group, &point))
+ goto out_err;
+
+ if (BN_is_negative(bn_order)
+ || BN_is_zero(bn_order)
+ || BN_num_bits(bn_order) > (int)field_bits + 1)
+ goto out_err;
+
+ if (!EC_GROUP_set_generator(group, point, bn_order, cofactor))
+ goto out_err;
+
+ EC_GROUP_set_asn1_flag(group, 0x0);
+
+ key = EC_KEY_new();
+ if (!key)
+ goto out_err;
+ EC_KEY_set_group(key, group);
+ }
+ else {
+ goto out_err;
+ }
+
+
+ goto out;
+
+out_err:
+ if (key) EC_KEY_free(key);
+ key = NULL;
+
+out:
+ /* some OpenSSL structures are mem-dup'ed into the key,
+ so we have to free our copies here */
+ if (p) BN_free(p);
+ if (a) BN_free(a);
+ if (b) BN_free(b);
+ if (bn_order) BN_free(bn_order);
+ if (cofactor) BN_free(cofactor);
+ if (group) EC_GROUP_free(group);
+
+ return key;
+}
+
+
+static ERL_NIF_TERM bn2term(ErlNifEnv* env, const BIGNUM *bn)
+{
+ unsigned dlen;
+ unsigned char* ptr;
+ ERL_NIF_TERM ret;
+
+ if (!bn)
+ return atom_undefined;
+
+ dlen = BN_num_bytes(bn);
+ ptr = enif_make_new_binary(env, dlen, &ret);
+ BN_bn2bin(bn, ptr);
+
+ return ret;
+}
+
+static ERL_NIF_TERM point2term(ErlNifEnv* env,
+ const EC_GROUP *group,
+ const EC_POINT *point,
+ point_conversion_form_t form)
+{
+ unsigned dlen;
+ ErlNifBinary bin;
+
+ dlen = EC_POINT_point2oct(group, point, form, NULL, 0, NULL);
+ if (dlen == 0)
+ return atom_undefined;
+
+ if (!enif_alloc_binary(dlen, &bin))
+ return enif_make_badarg(env);
+
+ if (!EC_POINT_point2oct(group, point, form, bin.data, bin.size, NULL)) {
+ enif_release_binary(&bin);
+ return enif_make_badarg(env);
+ }
+
+ return enif_make_binary(env, &bin);
+}
+#endif
+
+static ERL_NIF_TERM ec_key_to_term_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
+{
+#if defined(HAVE_EC)
+ struct nif_ec_key *obj;
+ const EC_GROUP *group;
+ const EC_POINT *public_key;
+ const BIGNUM *priv_key = NULL;
+ ERL_NIF_TERM pub_key = atom_undefined;
+
+ if (!enif_get_resource(env, argv[0], res_type_ec_key, (void **)&obj))
+ return enif_make_badarg(env);
+
+ group = EC_KEY_get0_group(obj->key);
+ public_key = EC_KEY_get0_public_key(obj->key);
+ priv_key = EC_KEY_get0_private_key(obj->key);
+
+ if (group) {
+ if (public_key)
+ pub_key = point2term(env, group, public_key, EC_KEY_get_conv_form(obj->key));
+ }
+
+ return enif_make_tuple2(env, bn2term(env, priv_key), pub_key);
+#else
+ return atom_notsup;
+#endif
+}
+
+#if defined(HAVE_EC)
+static int term2point(ErlNifEnv* env, ERL_NIF_TERM term,
+ EC_GROUP *group, EC_POINT **pptr)
+{
+ int ret = 0;
+ ErlNifBinary bin;
+ EC_POINT *point;
+
+ if (!enif_inspect_binary(env,term,&bin)) {
+ return 0;
+ }
+
+ if ((*pptr = point = EC_POINT_new(group)) == NULL) {
+ return 0;
+ }
+
+ /* set the point conversion form */
+ EC_GROUP_set_point_conversion_form(group, (point_conversion_form_t)(bin.data[0] & ~0x01));
+
+ /* extract the ec point */
+ if (!EC_POINT_oct2point(group, point, bin.data, bin.size, NULL)) {
+ EC_POINT_free(point);
+ *pptr = NULL;
+ } else
+ ret = 1;
+
+ return ret;
+}
+#endif
+
+static ERL_NIF_TERM term_to_ec_key_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
+{
+#if defined(HAVE_EC)
+ ERL_NIF_TERM ret;
+ EC_KEY *key = NULL;
+ BIGNUM *priv_key = NULL;
+ EC_POINT *pub_key = NULL;
+ struct nif_ec_key *obj;
+ EC_GROUP *group = NULL;
+
+ if (!(argv[1] == atom_undefined || get_bn_from_bin(env, argv[1], &priv_key))
+ || !(argv[2] == atom_undefined || enif_is_binary(env, argv[2]))) {
+ goto out_err;
+ }
+
+ key = ec_key_new(env, argv[0]);
+
+ if (!key) {
+ goto out_err;
+ }
+
+ if (!group)
+ group = EC_GROUP_dup(EC_KEY_get0_group(key));
+
+ if (term2point(env, argv[2], group, &pub_key)) {
+ if (!EC_KEY_set_public_key(key, pub_key)) {
+ goto out_err;
+ }
+ }
+ if (argv[1] != atom_undefined
+ && !BN_is_zero(priv_key)) {
+ if (!EC_KEY_set_private_key(key, priv_key))
+ goto out_err;
+
+ /* calculate public key (if necessary) */
+ if (EC_KEY_get0_public_key(key) == NULL)
+ {
+ /* the public key was not included in the SEC1 private
+ * key => calculate the public key */
+ pub_key = EC_POINT_new(group);
+ if (pub_key == NULL
+ || !EC_POINT_copy(pub_key, EC_GROUP_get0_generator(group))
+ || !EC_POINT_mul(group, pub_key, priv_key, NULL, NULL, NULL)
+ || !EC_KEY_set_public_key(key, pub_key))
+ goto out_err;
+ }
+ }
+
+ obj = enif_alloc_resource(res_type_ec_key, sizeof(struct nif_ec_key));
+ if (!obj)
+ goto out_err;
+
+ obj->key = key;
+ ret = enif_make_resource(env, obj);
+ enif_release_resource(obj);
+
+ goto out;
+
+out_err:
+ if (key) EC_KEY_free(key);
+ ret = enif_make_badarg(env);
+
+out:
+ /* some OpenSSL structures are mem-dup'ed into the key,
+ so we have to free our copies here */
+ if (priv_key) BN_clear_free(priv_key);
+ if (pub_key) EC_POINT_free(pub_key);
+ if (group) EC_GROUP_free(group);
+ return ret;
+#else
+ return atom_notsup;
+#endif
+}
+
+static ERL_NIF_TERM ec_key_generate(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
+{
+#if defined(HAVE_EC)
+ EC_KEY *key = ec_key_new(env, argv[0]);
+
+ if (key && EC_KEY_generate_key(key)) {
+ ERL_NIF_TERM term;
+ struct nif_ec_key *obj = enif_alloc_resource(res_type_ec_key, sizeof(struct nif_ec_key));
+ if (!obj)
+ return atom_error;
+ obj->key = key;
+ term = enif_make_resource(env, obj);
+ enif_release_resource(obj);
+ return term;
+ }
+ else
+ return enif_make_badarg(env);
+#else
+ return atom_notsup;
+#endif
+}
+
+#if defined(HAVE_EC)
+static void ec_key_dtor(ErlNifEnv* env, void* obj)
+{
+ struct nif_ec_key *key = (struct nif_ec_key*) obj;
+ EC_KEY_free(key->key);
+}
+#endif
+
+static ERL_NIF_TERM ecdsa_sign_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
+{/* (Type, Data|{digest,Digest}, Key) */
+#if defined(HAVE_EC)
+ ErlNifBinary data_bin, ret_bin;
+ unsigned char hmacbuf[SHA_DIGEST_LENGTH];
+ unsigned int dsa_s_len;
+ struct nif_ec_key *obj;
+ int i;
+ const ERL_NIF_TERM* tpl_terms;
+ int tpl_arity;
+ struct digest_type_t *digp;
+ unsigned char* digest;
+
+ digp = get_digest_type(argv[0]);
+ if (!digp) {
+ return enif_make_badarg(env);
+ }
+ if (!digp->len) {
+ return atom_notsup;
+ }
+
+ if (!enif_get_resource(env, argv[2], res_type_ec_key, (void **)&obj))
+ return enif_make_badarg(env);
+
+ if (enif_get_tuple(env, argv[1], &tpl_arity, &tpl_terms)) {
+ if (tpl_arity != 2 || tpl_terms[0] != atom_digest
+ || !enif_inspect_binary(env, tpl_terms[1], &data_bin)
+ || data_bin.size != digp->len) {
+
+ return enif_make_badarg(env);
+ }
+ digest = data_bin.data;
+ }
+ else {
+ if (!enif_inspect_binary(env,argv[1],&data_bin)) {
+ return enif_make_badarg(env);
+ }
+ digest = hmacbuf;
+ digp->funcp(data_bin.data, data_bin.size, digest);
+ }
+
+ enif_alloc_binary(ECDSA_size(obj->key), &ret_bin);
+
+ i = ECDSA_sign(digp->NID_type, digest, digp->len,
+ ret_bin.data, &dsa_s_len, obj->key);
+ if (i) {
+ if (dsa_s_len != ret_bin.size) {
+ enif_realloc_binary(&ret_bin, dsa_s_len);
+ }
+ return enif_make_binary(env, &ret_bin);
+ }
+ else {
+ enif_release_binary(&ret_bin);
+ return atom_error;
+ }
+#else
+ return atom_notsup;
+#endif
+}
+
+static ERL_NIF_TERM ecdsa_verify_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
+{/* (Type, Data|{digest,Digest}, Signature, Key) */
+#if defined(HAVE_EC)
+ ErlNifBinary data_bin, sign_bin;
+ unsigned char hmacbuf[SHA512_LEN];
+ int i;
+ struct nif_ec_key *obj;
+ const ERL_NIF_TERM type = argv[0];
+ const ERL_NIF_TERM* tpl_terms;
+ int tpl_arity;
+ struct digest_type_t* digp = NULL;
+ unsigned char* digest = NULL;
+
+ digp = get_digest_type(type);
+ if (!digp) {
+ return enif_make_badarg(env);
+ }
+ if (!digp->len) {
+ return atom_notsup;
+ }
+
+ if (!enif_inspect_binary(env, argv[2], &sign_bin)
+ || !enif_get_resource(env, argv[3], res_type_ec_key, (void **)&obj))
+ return enif_make_badarg(env);
+
+ if (enif_get_tuple(env, argv[1], &tpl_arity, &tpl_terms)) {
+ if (tpl_arity != 2 || tpl_terms[0] != atom_digest
+ || !enif_inspect_binary(env, tpl_terms[1], &data_bin)
+ || data_bin.size != digp->len) {
+
+ return enif_make_badarg(env);
+ }
+ digest = data_bin.data;
+ }
+ else if (enif_inspect_binary(env, argv[1], &data_bin)) {
+ digest = hmacbuf;
+ digp->funcp(data_bin.data, data_bin.size, digest);
+ }
+ else {
+ return enif_make_badarg(env);
+ }
+
+ i = ECDSA_verify(digp->NID_type, digest, digp->len,
+ sign_bin.data, sign_bin.size, obj->key);
+
+ return (i==1 ? atom_true : atom_false);
+#else
+ return atom_notsup;
+#endif
+}
+
+/*
+ (_OthersPublicKey, _MyPrivateKey)
+ (_OthersPublicKey, _MyEC_Point)
+*/
+static ERL_NIF_TERM ecdh_compute_key_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
+{
+#if defined(HAVE_EC)
+ ERL_NIF_TERM ret;
+ unsigned char *p;
+ struct nif_ec_key *other_key;
+ int field_size = 0;
+ int i;
+
+ EC_GROUP *group;
+ const BIGNUM *priv_key;
+ EC_POINT *my_ecpoint;
+ EC_KEY *other_ecdh = NULL;
+
+ if (!enif_get_resource(env, argv[1], res_type_ec_key, (void **)&other_key))
+ return enif_make_badarg(env);
+
+ group = EC_GROUP_dup(EC_KEY_get0_group(other_key->key));
+ priv_key = EC_KEY_get0_private_key(other_key->key);
+
+ if (!term2point(env, argv[0], group, &my_ecpoint)) {
+ goto out_err;
+ }
+
+ if ((other_ecdh = EC_KEY_new()) == NULL
+ || !EC_KEY_set_group(other_ecdh, group)
+ || !EC_KEY_set_private_key(other_ecdh, priv_key))
+ goto out_err;
+
+ field_size = EC_GROUP_get_degree(group);
+ if (field_size <= 0)
+ goto out_err;
+
+ p = enif_make_new_binary(env, (field_size+7)/8, &ret);
+ i = ECDH_compute_key(p, (field_size+7)/8, my_ecpoint, other_ecdh, NULL);
+
+ if (i < 0)
+ goto out_err;
+out:
+ if (group) EC_GROUP_free(group);
+ if (my_ecpoint) EC_POINT_free(my_ecpoint);
+ if (other_ecdh) EC_KEY_free(other_ecdh);
+
+ return ret;
+
+out_err:
+ ret = enif_make_badarg(env);
+ goto out;
+#else
+ return atom_notsup;
+#endif
+}
/* HMAC */
diff --git a/lib/crypto/doc/src/crypto.xml b/lib/crypto/doc/src/crypto.xml
index 29fc885152..df765ade87 100755..100644
--- a/lib/crypto/doc/src/crypto.xml
+++ b/lib/crypto/doc/src/crypto.xml
@@ -22,263 +22,222 @@
</legalnotice>
<title>crypto</title>
- <prepared>Peter H&ouml;gfeldt</prepared>
- <docno></docno>
- <date>2000-06-20</date>
- <rev>B</rev>
</header>
<module>crypto</module>
<modulesummary>Crypto Functions</modulesummary>
<description>
<p>This module provides a set of cryptographic functions.
</p>
- <p>References:</p>
<list type="bulleted">
<item>
- <p>md4: The MD4 Message Digest Algorithm (RFC 1320)</p>
- </item>
- <item>
- <p>md5: The MD5 Message Digest Algorithm (RFC 1321)</p>
- </item>
- <item>
- <p>sha: Secure Hash Standard (FIPS 180-2)</p>
- </item>
- <item>
- <p>hmac: Keyed-Hashing for Message Authentication (RFC 2104)</p>
- </item>
- <item>
- <p>des: Data Encryption Standard (FIPS 46-3)</p>
+ <p>Hash functions -
+ <url href="http://csrc.nist.gov/publications/fips/fips180-4/fips-180-4.pdf"> Secure Hash Standard</url>,
+ <url href="http://www.ietf.org/rfc/rfc1321.txt"> The MD5 Message Digest Algorithm (RFC 1321)</url> and
+ <url href="http://www.ietf.org/rfc/rfc1320.txt">The MD4 Message Digest Algorithm (RFC 1320)</url>
+ </p>
</item>
<item>
- <p>aes: Advanced Encryption Standard (AES) (FIPS 197) </p>
+ <p>Hmac functions - <url href="http://www.ietf.org/rfc/rfc2104.txt"> Keyed-Hashing for Message Authentication (RFC 2104) </url></p>
</item>
<item>
- <p>ecb, cbc, cfb, ofb, ctr: Recommendation for Block Cipher Modes
- of Operation (NIST SP 800-38A).</p>
+ <p>Block ciphers - <url href="http://csrc.nist.gov/groups/ST/toolkit/block_ciphers.html"> </url> DES and AES in
+ Block Cipher Modes - <url href="http://csrc.nist.gov/groups/ST/toolkit/BCM/index.html"> ECB, CBC, CFB, OFB and CTR </url></p>
</item>
<item>
- <p>rsa: Recommendation for Block Cipher Modes of Operation
- (NIST 800-38A)</p>
+ <p><url href="http://www.ietf.org/rfc/rfc1321.txt"> RSA encryption RFC 1321 </url> </p>
</item>
<item>
- <p>dss: Digital Signature Standard (FIPS 186-2)</p>
+ <p>Digital signatures <url href="http://csrc.nist.gov/publications/drafts/fips186-3/fips_186-3.pdf">Digital Signature Standard (DSS)</url> and<url href="http://csrc.nist.gov/groups/STM/cavp/documents/dss2/ecdsa2vs.pdf"> Elliptic Curve Digital
+ Signature Algorithm (ECDSA) </url> </p>
</item>
<item>
- <p>srp: Secure Remote Password Protocol (RFC 2945)</p>
+ <p><url href="http://www.ietf.org/rfc/rfc2945.txt"> Secure Remote Password Protocol (SRP - RFC 2945) </url></p>
</item>
-
-
</list>
- <p>The above publications can be found at <url href="http://csrc.nist.gov/publications">NIST publications</url>, at <url href="http://www.ietf.org">IETF</url>.
- </p>
- <p><em>Types</em></p>
- <pre>
-byte() = 0 ... 255
-ioelem() = byte() | binary() | iolist()
-iolist() = [ioelem()]
-Mpint() = <![CDATA[<<ByteLen:32/integer-big, Bytes:ByteLen/binary>>]]>
- </pre>
- <p></p>
</description>
+
+ <section>
+ <title>DATA TYPES </title>
+
+ <p><code>key_value() = integer() | binary() </code></p>
+
+ <p><code>rsa_public() = [key_value()] = [E, N] </code></p>
+ <p> Where E is the public exponent and N is public modulus. </p>
+
+ <p><code>rsa_private() = [key_value()] = [E, N, D] | [E, N, D, P1, P2, E1, E2, C] </code></p>
+ <p>Where E is the public exponent, N is public modulus and D is
+ the private exponent.The longer key format contains redundant
+ information that will make the calculation faster. P1,P2 are first
+ and second prime factors. E1,E2 are first and second exponents. C
+ is the CRT coefficient. Terminology is taken from <url href="http://www.ietf.org/rfc/rfc3477.txt"> RFC 3447</url>.</p>
+
+ <p><code>dss_public() = [key_value()] = [P, Q, G, Y] </code></p>
+ <p>Where P, Q and G are the dss parameters and Y is the public key.</p>
+
+ <p><code>dss_private() = [key_value()] = [P, Q, G, X] </code></p>
+ <p>Where P, Q and G are the dss parameters and X is the private key.</p>
+
+ <p><code>dss_public() = [key_value()] =[P, Q, G, Y] </code></p>
+
+ <p><code>srp_public() = key_value() </code></p>
+ <p>Where is <c>A</c> or <c>B</c> from <url href="http://srp.stanford.edu/design.html">SRP design</url></p>
+
+ <p><code>srp_private() = key_value() </code></p>
+ <p>Where is <c>a</c> or <c>b</c> from <url href="http://srp.stanford.edu/design.html">SRP design</url></p>
+
+ <p><code>srp_params() = {user, [Generator::binary(), Prime::binary(), Version::atom()]} |
+ {host, [Verifier::binary(), Generator::binary(), Prime::binary(), Version::atom()]}
+ | {user, [DerivedKey::binary(), Prime::binary(), Generator::binary(), Version::atom() | [Scrambler:binary()]]}
+ | {host,[Verifier::binary(), Prime::binary(), Version::atom() | [Scrambler::binary]]} </code></p>
+
+ <p>Where Verifier is <c>v</c>, Generator is <c>g</c> and Prime is<c> N</c>, DerivedKey is <c>X</c>, and Scrambler is
+ <c>u</c> (optional will be genrated if not provided) from <url href="http://srp.stanford.edu/design.html">SRP design</url>
+ Version = '3' | '6' | '6a'
+ </p>
+
+ <p><code>dh_public() = key_value() </code></p>
+
+ <p><code>dh_private() = key_value() </code></p>
+
+ <p><code>dh_params() = [key_value()] = [P, G] </code></p>
+
+ <p><code>ecdh_public() = key_value() </code></p>
+
+ <p><code>ecdh_private() = key_value() </code></p>
+
+ <p><code>ecdh_params() = ec_named_curve() |
+ {ec_field(), Prime :: key_value(), Point :: key_value(), Order :: integer(), CoFactor :: none | integer()} </code></p>
+
+ <p><code>ec_field() = {prime_field, Prime :: integer()} |
+ {characteristic_two_field, M :: integer(), Basis :: ec_basis()}</code></p>
+
+ <p><code>ec_basis() = {tpbasis, K :: non_neg_integer()} |
+ {ppbasis, K1 :: non_neg_integer(), K2 :: non_neg_integer(), K3 :: non_neg_integer()} |
+ onbasis</code></p>
+
+ <p><code>ec_named_curve() ->
+ sect571r1| sect571k1| sect409r1| sect409k1| secp521r1| secp384r1| secp224r1| secp224k1|
+ secp192k1| secp160r2| secp128r2| secp128r1| sect233r1| sect233k1| sect193r2| sect193r1|
+ sect131r2| sect131r1| sect283r1| sect283k1| sect163r2| secp256k1| secp160k1| secp160r1|
+ secp112r2| secp112r1| sect113r2| sect113r1| sect239k1| sect163r1| sect163k1| secp256r1|
+ secp192r1 </code></p>
+
+ <p><code>stream_cipher() = rc4 | aes_ctr </code></p>
+
+ <p><code>block_cipher() = aes_cbc128 | aes_cfb128 | blowfish_cbc |
+ blowfish_cfb64 | des_cbc | des_cfb | des3_cbc | des3_cbf
+ | des_ede3 | rc2_cbc </code></p>
+
+ <p><code>stream_key() = aes_key() | rc4_key() </code></p>
+
+ <p><code>block_key() = aes_key() | blowfish_key() | des_key()| des3_key() </code></p>
+
+ <p><code>aes_key() = iodata() </code> Key length is 128, 192 or 256 bits</p>
+
+ <p><code>rc4_key() = iodata() </code> Variable key length from 8 bits up to 2048 bits (usually between 40 and 256)</p>
+
+ <p><code>blowfish_key() = iodata() </code> Variable key length from 32 bits up to 448 bits</p>
+
+ <p><code>des_key() = iodata() </code> Key length is 64 bits (in CBC mode only 8 bits are used)</p>
+
+ <p><code>des3_key() = [binary(), binary(), binary()] </code> Each key part is 64 bits (in CBC mode only 8 bits are used)</p>
+
+ <p><code> message_digest_algorithms() = md5 | ripemd160 | sha | sha224 | sha256 | sha384 | sha512 </code> md4 is aslo supported for hash_init/1 and hash/2.
+ Note that both md4 and md5 are recommended only for compatibility with existing applications.
+ </p>
+ </section>
+
<funcs>
<func>
- <name>start() -> ok</name>
- <fsummary>Start the crypto server.</fsummary>
- <desc>
- <p>Starts the crypto server.</p>
- </desc>
- </func>
- <func>
- <name>stop() -> ok</name>
- <fsummary>Stop the crypto server.</fsummary>
- <desc>
- <p>Stops the crypto server.</p>
- </desc>
- </func>
- <func>
- <name>info() -> [atom()]</name>
- <fsummary>Provide a list of available crypto functions.</fsummary>
- <desc>
- <p>Provides the available crypto functions in terms of a list
- of atoms.</p>
- </desc>
- </func>
- <func>
- <name>algorithms() -> [atom()]</name>
+ <name>algorithms() -> [message_digest_algorithms() | md4 | ec]</name>
<fsummary>Provide a list of available crypto algorithms.</fsummary>
<desc>
- <p>Provides the available crypto algorithms in terms of a list
- of atoms.</p>
- </desc>
- </func>
- <func>
- <name>info_lib() -> [{Name,VerNum,VerStr}]</name>
- <fsummary>Provides information about the libraries used by crypto.</fsummary>
- <type>
- <v>Name = binary()</v>
- <v>VerNum = integer()</v>
- <v>VerStr = binary()</v>
- </type>
- <desc>
- <p>Provides the name and version of the libraries used by crypto.</p>
- <p><c>Name</c> is the name of the library. <c>VerNum</c> is
- the numeric version according to the library's own versioning
- scheme. <c>VerStr</c> contains a text variant of the version.</p>
- <pre>
-> <input>info_lib().</input>
-[{&lt;&lt;"OpenSSL"&gt;&gt;,9469983,&lt;&lt;"OpenSSL 0.9.8a 11 Oct 2005"&gt;&gt;}]
- </pre>
- <note><p>
- From OTP R16 the <em>numeric version</em> represents the version of the OpenSSL
- <em>header files</em> (<c>openssl/opensslv.h</c>) used when crypto was compiled.
- The text variant represents the OpenSSL library used at runtime.
- In earlier OTP versions both numeric and text was taken from the library.
- </p></note>
- </desc>
- </func>
- <func>
- <name>md4(Data) -> Digest</name>
- <fsummary>Compute an <c>MD4</c>message digest from <c>Data</c></fsummary>
- <type>
- <v>Data = iolist() | binary()</v>
- <v>Digest = binary()</v>
- </type>
- <desc>
- <p>Computes an <c>MD4</c> message digest from <c>Data</c>, where
- the length of the digest is 128 bits (16 bytes).</p>
- </desc>
- </func>
- <func>
- <name>md4_init() -> Context</name>
- <fsummary>Creates an MD4 context</fsummary>
- <type>
- <v>Context = binary()</v>
- </type>
- <desc>
- <p>Creates an MD4 context, to be used in subsequent calls to
- <c>md4_update/2</c>.</p>
- </desc>
- </func>
- <func>
- <name>md4_update(Context, Data) -> NewContext</name>
- <fsummary>Update an MD4 <c>Context</c>with <c>Data</c>, and return a <c>NewContext</c></fsummary>
- <type>
- <v>Data = iolist() | binary()</v>
- <v>Context = NewContext = binary()</v>
- </type>
- <desc>
- <p>Updates an MD4 <c>Context</c> with <c>Data</c>, and returns
- a <c>NewContext</c>.</p>
- </desc>
- </func>
- <func>
- <name>md4_final(Context) -> Digest</name>
- <fsummary>Finish the update of an MD4 <c>Context</c>and return the computed <c>MD4</c>message digest</fsummary>
- <type>
- <v>Context = Digest = binary()</v>
- </type>
- <desc>
- <p>Finishes the update of an MD4 <c>Context</c> and returns
- the computed <c>MD4</c> message digest.</p>
- </desc>
- </func>
- <func>
- <name>md5(Data) -> Digest</name>
- <fsummary>Compute an <c>MD5</c>message digest from <c>Data</c></fsummary>
- <type>
- <v>Data = iolist() | binary()</v>
- <v>Digest = binary()</v>
- </type>
- <desc>
- <p>Computes an <c>MD5</c> message digest from <c>Data</c>, where
- the length of the digest is 128 bits (16 bytes).</p>
+ <p> Can be used to determine if the crypto library has support for elliptic curve (ec) and
+ which message digest algorithms that are supported.</p>
</desc>
</func>
- <func>
- <name>md5_init() -> Context</name>
- <fsummary>Creates an MD5 context</fsummary>
- <type>
- <v>Context = binary()</v>
- </type>
- <desc>
- <p>Creates an MD5 context, to be used in subsequent calls to
- <c>md5_update/2</c>.</p>
- </desc>
- </func>
- <func>
- <name>md5_update(Context, Data) -> NewContext</name>
- <fsummary>Update an MD5 <c>Context</c>with <c>Data</c>, and return a <c>NewContext</c></fsummary>
- <type>
- <v>Data = iolist() | binary()</v>
- <v>Context = NewContext = binary()</v>
- </type>
- <desc>
- <p>Updates an MD5 <c>Context</c> with <c>Data</c>, and returns
- a <c>NewContext</c>.</p>
- </desc>
- </func>
- <func>
- <name>md5_final(Context) -> Digest</name>
- <fsummary>Finish the update of an MD5 <c>Context</c>and return the computed <c>MD5</c>message digest</fsummary>
+
+ <func>
+ <name>block_encrypt(Type, Key, Ivec, PlainText) -> CipherText</name>
+ <fsummary>Encrypt <c>PlainText</c>according to <c>Type</c> block cipher</fsummary>
<type>
- <v>Context = Digest = binary()</v>
+ <v>Key = block_key() </v>
+ <v>PlainText = iodata() </v>
+ <v>IVec = CipherText = binary()</v>
</type>
<desc>
- <p>Finishes the update of an MD5 <c>Context</c> and returns
- the computed <c>MD5</c> message digest.</p>
+ <p>Encrypt <c>PlainText</c>according to <c>Type</c> block cipher.
+ <c>IVec</c> is an arbitrary initializing vector.
+ </p>
</desc>
</func>
+
<func>
- <name>sha(Data) -> Digest</name>
- <fsummary>Compute an <c>SHA</c>message digest from <c>Data</c></fsummary>
+ <name>block_decrypt(Type, Key, Ivec, CipherText) -> PlainText</name>
+ <fsummary>Decrypt <c>CipherText</c>according to <c>Type</c> block cipher</fsummary>
<type>
- <v>Data = iolist() | binary()</v>
- <v>Digest = binary()</v>
+ <v>Key = block_key() </v>
+ <v>PlainText = iodata() </v>
+ <v>IVec = CipherText = binary()</v>
</type>
<desc>
- <p>Computes an <c>SHA</c> message digest from <c>Data</c>, where
- the length of the digest is 160 bits (20 bytes).</p>
+ <p>Decrypt <c>CipherText</c>according to <c>Type</c> block cipher.
+ <c>IVec</c> is an arbitrary initializing vector.
+ </p>
</desc>
</func>
+
<func>
- <name>sha_init() -> Context</name>
- <fsummary>Create an SHA context</fsummary>
+ <name>compute_key(Type, OthersPublicKey, MyPrivateKey, Params) -> SharedSecret</name>
+ <fsummary>Computes the shared secret</fsummary>
<type>
- <v>Context = binary()</v>
+ <v> Type = dh | ecdh | srp </v>
+ <v>OthersPublicKey = dh_public() | ecdh_public() | srp_public() </v>
+ <v>MyPrivate = dh_private() | ecdh_private() | srp_private() </v>
+ <v>Params = dh_params() | edhc_params() | srp_params() </v>
+ <v>SharedSecret = binary()</v>
</type>
<desc>
- <p>Creates an SHA context, to be used in subsequent calls to
- <c>sha_update/2</c>.</p>
+ <p>Computes the shared secret from the private key and the other party's public key.
+ See also <seealso marker="public_key:public_key#compute_key/2">public_key:compute_key/2</seealso>
+ </p>
</desc>
</func>
+
<func>
- <name>sha_update(Context, Data) -> NewContext</name>
- <fsummary>Update an SHA context</fsummary>
+ <name>exor(Data1, Data2) -> Result</name>
+ <fsummary>XOR data</fsummary>
<type>
- <v>Data = iolist() | binary()</v>
- <v>Context = NewContext = binary()</v>
+ <v>Data1, Data2 = iodata()</v>
+ <v>Result = binary()</v>
</type>
<desc>
- <p>Updates an SHA <c>Context</c> with <c>Data</c>, and returns
- a <c>NewContext</c>.</p>
+ <p>Performs bit-wise XOR (exclusive or) on the data supplied.</p>
</desc>
</func>
- <func>
- <name>sha_final(Context) -> Digest</name>
- <fsummary>Finish the update of an SHA context</fsummary>
+
+ <func>
+ <name>generate_key(Type, Params) -> {PublicKey, PrivateKey} </name>
+ <name>generate_key(Type, Params, PrivateKey) -> {PublicKey, PrivateKey} </name>
+ <fsummary>Generates a public keys of type <c>Type</c></fsummary>
<type>
- <v>Context = Digest = binary()</v>
+ <v> Type = dh | ecdh | srp </v>
+ <v>Params = dh_params() | edhc_params() | srp_params() </v>
+ <v>PublicKey = dh_public() | ecdh_public() | srp_public() </v>
+ <v>PrivateKey = dh_private() | ecdh_private() | srp_private() </v>
</type>
<desc>
- <p>Finishes the update of an SHA <c>Context</c> and returns
- the computed <c>SHA</c> message digest.</p>
+ <p>Generates public keys of type <c>Type</c>.
+ See also <seealso marker="public_key:public_key#generate_key/1">public_key:generate_key/1</seealso>
+ </p>
</desc>
</func>
- <func>
+
+ <func>
<name>hash(Type, Data) -> Digest</name>
<fsummary></fsummary>
<type>
- <v>Type = md4 | md5 | ripemd160 | sha | sha224 | sha256 | sha384 | sha512</v>
+ <v>Type = md4 | message_digest_algorithms()</v>
<v>Data = iodata()</v>
<v>Digest = binary()</v>
</type>
@@ -288,11 +247,12 @@ Mpint() = <![CDATA[<<ByteLen:32/integer-big, Bytes:ByteLen/binary>>]]>
is not supported by the underlying OpenSSL implementation.</p>
</desc>
</func>
+
<func>
<name>hash_init(Type) -> Context</name>
<fsummary></fsummary>
<type>
- <v>Type = md4 | md5 | ripemd160 | sha | sha224 | sha256 | sha384 | sha512</v>
+ <v>Type = md4 | message_digest_algorithms()</v>
</type>
<desc>
<p>Initializes the context for streaming hash operations. <c>Type</c> determines
@@ -302,6 +262,7 @@ Mpint() = <![CDATA[<<ByteLen:32/integer-big, Bytes:ByteLen/binary>>]]>
is not supported by the underlying OpenSSL implementation.</p>
</desc>
</func>
+
<func>
<name>hash_update(Context, Data) -> NewContext</name>
<fsummary></fsummary>
@@ -329,38 +290,13 @@ Mpint() = <![CDATA[<<ByteLen:32/integer-big, Bytes:ByteLen/binary>>]]>
function used to generate it.</p>
</desc>
</func>
- <func>
- <name>md5_mac(Key, Data) -> Mac</name>
- <fsummary>Compute an <c>MD5 MAC</c>message authentification code</fsummary>
- <type>
- <v>Key = Data = iolist() | binary()</v>
- <v>Mac = binary()</v>
- </type>
- <desc>
- <p>Computes an <c>MD5 MAC</c> message authentification code
- from <c>Key</c> and <c>Data</c>, where the the length of the
- Mac is 128 bits (16 bytes).</p>
- </desc>
- </func>
- <func>
- <name>md5_mac_96(Key, Data) -> Mac</name>
- <fsummary>Compute an <c>MD5 MAC</c>message authentification code</fsummary>
- <type>
- <v>Key = Data = iolist() | binary()</v>
- <v>Mac = binary()</v>
- </type>
- <desc>
- <p>Computes an <c>MD5 MAC</c> message authentification code
- from <c>Key</c> and <c>Data</c>, where the length of the Mac
- is 96 bits (12 bytes).</p>
- </desc>
- </func>
+
<func>
<name>hmac(Type, Key, Data) -> Mac</name>
<name>hmac(Type, Key, Data, MacLength) -> Mac</name>
<fsummary></fsummary>
<type>
- <v>Type = md5 | sha | sha224 | sha256 | sha384 | sha512</v>
+ <v>Type = message_digest_algorithms() </v>
<v>Key = iodata()</v>
<v>Data = iodata()</v>
<v>MacLength = integer()</v>
@@ -372,12 +308,13 @@ Mpint() = <![CDATA[<<ByteLen:32/integer-big, Bytes:ByteLen/binary>>]]>
will limit the size of the resultant <c>Mac</c>.
</desc>
</func>
+
<func>
<name>hmac_init(Type, Key) -> Context</name>
<fsummary></fsummary>
<type>
- <v>Type = md5 | ripemd160 | sha | sha224 | sha256 | sha384 | sha512</v>
- <v>Key = iolist() | binary()</v>
+ <v>Type = message_digest_algorithms()</v>
+ <v>Key = iodata()</v>
<v>Context = binary()</v>
</type>
<desc>
@@ -386,20 +323,26 @@ Mpint() = <![CDATA[<<ByteLen:32/integer-big, Bytes:ByteLen/binary>>]]>
key. The key can be any length.</p>
</desc>
</func>
+
<func>
<name>hmac_update(Context, Data) -> NewContext</name>
<fsummary></fsummary>
<type>
<v>Context = NewContext = binary()</v>
- <v>Data = iolist() | binary()</v>
+ <v>Data = iodata()</v>
</type>
<desc>
<p>Updates the HMAC represented by <c>Context</c> using the given <c>Data</c>. <c>Context</c>
must have been generated using an HMAC init function (such as
<seealso marker="#hmac_init/2">hmac_init</seealso>). <c>Data</c> can be any length. <c>NewContext</c>
- must be passed into the next call to <c>hmac_update</c>.</p>
+ must be passed into the next call to <c>hmac_update</c>
+ or to one of the functions <seealso marker="#hmac_final/1">hmac_final</seealso> and
+ <seealso marker="#hmac_final_n/1">hmac_final_n</seealso>
+ </p>
+
</desc>
</func>
+
<func>
<name>hmac_final(Context) -> Mac</name>
<fsummary></fsummary>
@@ -411,6 +354,7 @@ Mpint() = <![CDATA[<<ByteLen:32/integer-big, Bytes:ByteLen/binary>>]]>
determined by the type of hash function used to generate it.</p>
</desc>
</func>
+
<func>
<name>hmac_final_n(Context, HashLen) -> Mac</name>
<fsummary></fsummary>
@@ -423,705 +367,88 @@ Mpint() = <![CDATA[<<ByteLen:32/integer-big, Bytes:ByteLen/binary>>]]>
zero. <c>Mac</c> will be a binary with at most <c>HashLen</c> bytes. Note that if HashLen is greater than the actual number of bytes returned from the underlying hash, the returned hash will have fewer than <c>HashLen</c> bytes.</p>
</desc>
</func>
- <func>
- <name>sha_mac(Key, Data) -> Mac</name>
- <name>sha_mac(Key, Data, MacLength) -> Mac</name>
- <fsummary>Compute an <c>MD5 MAC</c>message authentification code</fsummary>
- <type>
- <v>Key = Data = iolist() | binary()</v>
- <v>Mac = binary()</v>
- <v>MacLenength = integer() =&lt; 20 </v>
- </type>
- <desc>
- <p>Computes an <c>SHA MAC</c> message authentification code
- from <c>Key</c> and <c>Data</c>, where the default length of the Mac
- is 160 bits (20 bytes).</p>
- </desc>
- </func>
- <func>
- <name>sha_mac_96(Key, Data) -> Mac</name>
- <fsummary>Compute an <c>SHA MAC</c>message authentification code</fsummary>
- <type>
- <v>Key = Data = iolist() | binary()</v>
- <v>Mac = binary()</v>
- </type>
- <desc>
- <p>Computes an <c>SHA MAC</c> message authentification code
- from <c>Key</c> and <c>Data</c>, where the length of the Mac
- is 96 bits (12 bytes).</p>
- </desc>
- </func>
- <func>
- <name>des_cbc_encrypt(Key, IVec, Text) -> Cipher</name>
- <fsummary>Encrypt <c>Text</c>according to DES in CBC mode</fsummary>
- <type>
- <v>Key = Text = iolist() | binary()</v>
- <v>IVec = Cipher = binary()</v>
- </type>
- <desc>
- <p>Encrypts <c>Text</c> according to DES in CBC
- mode. <c>Text</c> must be a multiple of 64 bits (8
- bytes). <c>Key</c> is the DES key, and <c>IVec</c> is an
- arbitrary initializing vector. The lengths of <c>Key</c> and
- <c>IVec</c> must be 64 bits (8 bytes).</p>
- </desc>
- </func>
- <func>
- <name>des_cbc_decrypt(Key, IVec, Cipher) -> Text</name>
- <fsummary>Decrypt <c>Cipher</c>according to DES in CBC mode</fsummary>
- <type>
- <v>Key = Cipher = iolist() | binary()</v>
- <v>IVec = Text = binary()</v>
- </type>
- <desc>
- <p>Decrypts <c>Cipher</c> according to DES in CBC mode.
- <c>Key</c> is the DES key, and <c>IVec</c> is an arbitrary
- initializing vector. <c>Key</c> and <c>IVec</c> must have
- the same values as those used when encrypting. <c>Cipher</c>
- must be a multiple of 64 bits (8 bytes). The lengths of
- <c>Key</c> and <c>IVec</c> must be 64 bits (8 bytes).</p>
- </desc>
- </func>
- <func>
- <name>des_cbc_ivec(Data) -> IVec</name>
- <fsummary>Get <c>IVec</c> to be used in next iteration of
- <c>des_cbc_[ecrypt|decrypt]</c></fsummary>
- <type>
- <v>Data = iolist() | binary()</v>
- <v>IVec = binary()</v>
- </type>
- <desc>
- <p>Returns the <c>IVec</c> to be used in a next iteration of
- <c>des_cbc_[encrypt|decrypt]</c>. <c>Data</c> is the encrypted
- data from the previous iteration step.</p>
- </desc>
- </func>
- <func>
- <name>des_cfb_encrypt(Key, IVec, Text) -> Cipher</name>
- <fsummary>Encrypt <c>Text</c>according to DES in CFB mode</fsummary>
- <type>
- <v>Key = Text = iolist() | binary()</v>
- <v>IVec = Cipher = binary()</v>
- </type>
- <desc>
- <p>Encrypts <c>Text</c> according to DES in 8-bit CFB
- mode. <c>Key</c> is the DES key, and <c>IVec</c> is an
- arbitrary initializing vector. The lengths of <c>Key</c> and
- <c>IVec</c> must be 64 bits (8 bytes).</p>
- </desc>
- </func>
- <func>
- <name>des_cfb_decrypt(Key, IVec, Cipher) -> Text</name>
- <fsummary>Decrypt <c>Cipher</c>according to DES in CFB mode</fsummary>
- <type>
- <v>Key = Cipher = iolist() | binary()</v>
- <v>IVec = Text = binary()</v>
- </type>
- <desc>
- <p>Decrypts <c>Cipher</c> according to DES in 8-bit CFB mode.
- <c>Key</c> is the DES key, and <c>IVec</c> is an arbitrary
- initializing vector. <c>Key</c> and <c>IVec</c> must have
- the same values as those used when encrypting. The lengths of
- <c>Key</c> and <c>IVec</c> must be 64 bits (8 bytes).</p>
- </desc>
- </func>
- <func>
- <name>des_cfb_ivec(IVec, Data) -> NextIVec</name>
- <fsummary>Get <c>IVec</c> to be used in next iteration of
- <c>des_cfb_[ecrypt|decrypt]</c></fsummary>
- <type>
- <v>IVec = iolist() | binary()</v>
- <v>Data = iolist() | binary()</v>
- <v>NextIVec = binary()</v>
- </type>
- <desc>
- <p>Returns the <c>IVec</c> to be used in a next iteration of
- <c>des_cfb_[encrypt|decrypt]</c>. <c>IVec</c> is the vector
- used in the previous iteration step. <c>Data</c> is the encrypted
- data from the previous iteration step.</p>
- </desc>
- </func>
- <func>
- <name>des3_cbc_encrypt(Key1, Key2, Key3, IVec, Text) -> Cipher</name>
- <fsummary>Encrypt <c>Text</c>according to DES3 in CBC mode</fsummary>
- <type>
- <v>Key1 =Key2 = Key3 Text = iolist() | binary()</v>
- <v>IVec = Cipher = binary()</v>
- </type>
- <desc>
- <p>Encrypts <c>Text</c> according to DES3 in CBC
- mode. <c>Text</c> must be a multiple of 64 bits (8
- bytes). <c>Key1</c>, <c>Key2</c>, <c>Key3</c>, are the DES
- keys, and <c>IVec</c> is an arbitrary initializing
- vector. The lengths of each of <c>Key1</c>, <c>Key2</c>,
- <c>Key3</c> and <c>IVec</c> must be 64 bits (8 bytes).</p>
- </desc>
- </func>
- <func>
- <name>des3_cbc_decrypt(Key1, Key2, Key3, IVec, Cipher) -> Text</name>
- <fsummary>Decrypt <c>Cipher</c>according to DES3 in CBC mode</fsummary>
- <type>
- <v>Key1 = Key2 = Key3 = Cipher = iolist() | binary()</v>
- <v>IVec = Text = binary()</v>
- </type>
- <desc>
- <p>Decrypts <c>Cipher</c> according to DES3 in CBC mode.
- <c>Key1</c>, <c>Key2</c>, <c>Key3</c> are the DES key, and
- <c>IVec</c> is an arbitrary initializing vector.
- <c>Key1</c>, <c>Key2</c>, <c>Key3</c> and <c>IVec</c> must
- and <c>IVec</c> must have the same values as those used when
- encrypting. <c>Cipher</c> must be a multiple of 64 bits (8
- bytes). The lengths of <c>Key1</c>, <c>Key2</c>,
- <c>Key3</c>, and <c>IVec</c> must be 64 bits (8 bytes).</p>
- </desc>
- </func>
- <func>
- <name>des3_cfb_encrypt(Key1, Key2, Key3, IVec, Text) -> Cipher</name>
- <fsummary>Encrypt <c>Text</c>according to DES3 in CFB mode</fsummary>
- <type>
- <v>Key1 =Key2 = Key3 Text = iolist() | binary()</v>
- <v>IVec = Cipher = binary()</v>
- </type>
- <desc>
- <p>Encrypts <c>Text</c> according to DES3 in 8-bit CFB
- mode. <c>Key1</c>, <c>Key2</c>, <c>Key3</c>, are the DES
- keys, and <c>IVec</c> is an arbitrary initializing
- vector. The lengths of each of <c>Key1</c>, <c>Key2</c>,
- <c>Key3</c> and <c>IVec</c> must be 64 bits (8 bytes).</p>
- <p>May throw exception <c>notsup</c> for old OpenSSL
- versions (0.9.7) that does not support this encryption mode.</p>
- </desc>
- </func>
- <func>
- <name>des3_cfb_decrypt(Key1, Key2, Key3, IVec, Cipher) -> Text</name>
- <fsummary>Decrypt <c>Cipher</c>according to DES3 in CFB mode</fsummary>
- <type>
- <v>Key1 = Key2 = Key3 = Cipher = iolist() | binary()</v>
- <v>IVec = Text = binary()</v>
- </type>
- <desc>
- <p>Decrypts <c>Cipher</c> according to DES3 in 8-bit CFB mode.
- <c>Key1</c>, <c>Key2</c>, <c>Key3</c> are the DES key, and
- <c>IVec</c> is an arbitrary initializing vector.
- <c>Key1</c>, <c>Key2</c>, <c>Key3</c> and <c>IVec</c> must
- and <c>IVec</c> must have the same values as those used when
- encrypting. The lengths of <c>Key1</c>, <c>Key2</c>,
- <c>Key3</c>, and <c>IVec</c> must be 64 bits (8 bytes).</p>
- <p>May throw exception <c>notsup</c> for old OpenSSL
- versions (0.9.7) that does not support this encryption mode.</p>
- </desc>
- </func>
-
- <func>
- <name>des_ecb_encrypt(Key, Text) -> Cipher</name>
- <fsummary>Encrypt <c>Text</c>according to DES in ECB mode</fsummary>
- <type>
- <v>Key = Text = iolist() | binary()</v>
- <v>Cipher = binary()</v>
- </type>
- <desc>
- <p>Encrypts <c>Text</c> according to DES in ECB mode.
- <c>Key</c> is the DES key. The lengths of <c>Key</c> and
- <c>Text</c> must be 64 bits (8 bytes).</p>
- </desc>
- </func>
- <func>
- <name>des_ecb_decrypt(Key, Cipher) -> Text</name>
- <fsummary>Decrypt <c>Cipher</c>according to DES in ECB mode</fsummary>
- <type>
- <v>Key = Cipher = iolist() | binary()</v>
- <v>Text = binary()</v>
- </type>
- <desc>
- <p>Decrypts <c>Cipher</c> according to DES in ECB mode.
- <c>Key</c> is the DES key. The lengths of <c>Key</c> and
- <c>Cipher</c> must be 64 bits (8 bytes).</p>
- </desc>
- </func>
-
- <func>
- <name>blowfish_ecb_encrypt(Key, Text) -> Cipher</name>
- <fsummary>Encrypt the first 64 bits of <c>Text</c> using Blowfish in ECB mode</fsummary>
- <type>
- <v>Key = Text = iolist() | binary()</v>
- <v>Cipher = binary()</v>
- </type>
- <desc>
- <p>Encrypts the first 64 bits of <c>Text</c> using Blowfish in ECB mode. <c>Key</c> is the Blowfish key. The length of <c>Text</c> must be at least 64 bits (8 bytes).</p>
- </desc>
- </func>
- <func>
- <name>blowfish_ecb_decrypt(Key, Text) -> Cipher</name>
- <fsummary>Decrypt the first 64 bits of <c>Text</c> using Blowfish in ECB mode</fsummary>
- <type>
- <v>Key = Text = iolist() | binary()</v>
- <v>Cipher = binary()</v>
- </type>
- <desc>
- <p>Decrypts the first 64 bits of <c>Text</c> using Blowfish in ECB mode. <c>Key</c> is the Blowfish key. The length of <c>Text</c> must be at least 64 bits (8 bytes).</p>
- </desc>
- </func>
-
- <func>
- <name>blowfish_cbc_encrypt(Key, IVec, Text) -> Cipher</name>
- <fsummary>Encrypt <c>Text</c> using Blowfish in CBC mode</fsummary>
- <type>
- <v>Key = Text = iolist() | binary()</v>
- <v>IVec = Cipher = binary()</v>
- </type>
- <desc>
- <p>Encrypts <c>Text</c> using Blowfish in CBC mode. <c>Key</c> is the Blowfish key, and <c>IVec</c> is an
- arbitrary initializing vector. The length of <c>IVec</c>
- must be 64 bits (8 bytes). The length of <c>Text</c> must be a multiple of 64 bits (8 bytes).</p>
- </desc>
- </func>
- <func>
- <name>blowfish_cbc_decrypt(Key, IVec, Text) -> Cipher</name>
- <fsummary>Decrypt <c>Text</c> using Blowfish in CBC mode</fsummary>
- <type>
- <v>Key = Text = iolist() | binary()</v>
- <v>IVec = Cipher = binary()</v>
- </type>
- <desc>
- <p>Decrypts <c>Text</c> using Blowfish in CBC mode. <c>Key</c> is the Blowfish key, and <c>IVec</c> is an
- arbitrary initializing vector. The length of <c>IVec</c>
- must be 64 bits (8 bytes). The length of <c>Text</c> must be a multiple 64 bits (8 bytes).</p>
- </desc>
- </func>
-
- <func>
- <name>blowfish_cfb64_encrypt(Key, IVec, Text) -> Cipher</name>
- <fsummary>Encrypt <c>Text</c>using Blowfish in CFB mode with 64
- bit feedback</fsummary>
- <type>
- <v>Key = Text = iolist() | binary()</v>
- <v>IVec = Cipher = binary()</v>
- </type>
- <desc>
- <p>Encrypts <c>Text</c> using Blowfish in CFB mode with 64 bit
- feedback. <c>Key</c> is the Blowfish key, and <c>IVec</c> is an
- arbitrary initializing vector. The length of <c>IVec</c>
- must be 64 bits (8 bytes).</p>
- </desc>
- </func>
- <func>
- <name>blowfish_cfb64_decrypt(Key, IVec, Text) -> Cipher</name>
- <fsummary>Decrypt <c>Text</c>using Blowfish in CFB mode with 64
- bit feedback</fsummary>
- <type>
- <v>Key = Text = iolist() | binary()</v>
- <v>IVec = Cipher = binary()</v>
- </type>
- <desc>
- <p>Decrypts <c>Text</c> using Blowfish in CFB mode with 64 bit
- feedback. <c>Key</c> is the Blowfish key, and <c>IVec</c> is an
- arbitrary initializing vector. The length of <c>IVec</c>
- must be 64 bits (8 bytes).</p>
- </desc>
- </func>
<func>
- <name>blowfish_ofb64_encrypt(Key, IVec, Text) -> Cipher</name>
- <fsummary>Encrypt <c>Text</c>using Blowfish in OFB mode with 64
- bit feedback</fsummary>
+ <name>info_lib() -> [{Name,VerNum,VerStr}]</name>
+ <fsummary>Provides information about the libraries used by crypto.</fsummary>
<type>
- <v>Key = Text = iolist() | binary()</v>
- <v>IVec = Cipher = binary()</v>
+ <v>Name = binary()</v>
+ <v>VerNum = integer()</v>
+ <v>VerStr = binary()</v>
</type>
<desc>
- <p>Encrypts <c>Text</c> using Blowfish in OFB mode with 64 bit
- feedback. <c>Key</c> is the Blowfish key, and <c>IVec</c> is an
- arbitrary initializing vector. The length of <c>IVec</c>
- must be 64 bits (8 bytes).</p>
+ <p>Provides the name and version of the libraries used by crypto.</p>
+ <p><c>Name</c> is the name of the library. <c>VerNum</c> is
+ the numeric version according to the library's own versioning
+ scheme. <c>VerStr</c> contains a text variant of the version.</p>
+ <pre>
+> <input>info_lib().</input>
+[{&lt;&lt;"OpenSSL"&gt;&gt;,9469983,&lt;&lt;"OpenSSL 0.9.8a 11 Oct 2005"&gt;&gt;}]
+ </pre>
+ <note><p>
+ From OTP R16 the <em>numeric version</em> represents the version of the OpenSSL
+ <em>header files</em> (<c>openssl/opensslv.h</c>) used when crypto was compiled.
+ The text variant represents the OpenSSL library used at runtime.
+ In earlier OTP versions both numeric and text was taken from the library.
+ </p></note>
</desc>
</func>
<func>
- <name>aes_cfb_128_encrypt(Key, IVec, Text) -> Cipher</name>
- <fsummary>Encrypt <c>Text</c>according to AES in Cipher Feedback mode</fsummary>
- <type>
- <v>Key = Text = iolist() | binary()</v>
- <v>IVec = Cipher = binary()</v>
- </type>
- <desc>
- <p>Encrypts <c>Text</c> according to AES in Cipher Feedback
- mode (CFB). <c>Key</c> is the
- AES key, and <c>IVec</c> is an arbitrary initializing vector.
- The lengths of <c>Key</c> and <c>IVec</c> must be 128 bits
- (16 bytes).</p>
- </desc>
- </func>
- <func>
- <name>aes_cfb_128_decrypt(Key, IVec, Cipher) -> Text</name>
- <fsummary>Decrypt <c>Cipher</c>according to AES in Cipher Feedback mode</fsummary>
- <type>
- <v>Key = Cipher = iolist() | binary()</v>
- <v>IVec = Text = binary()</v>
- </type>
- <desc>
- <p>Decrypts <c>Cipher</c> according to AES in Cipher Feedback Mode (CFB).
- <c>Key</c> is the AES key, and <c>IVec</c> is an arbitrary
- initializing vector. <c>Key</c> and <c>IVec</c> must have
- the same values as those used when encrypting. The lengths of
- <c>Key</c> and <c>IVec</c> must be 128 bits (16 bytes).</p>
- </desc>
- </func>
- <func>
- <name>aes_cbc_128_encrypt(Key, IVec, Text) -> Cipher</name>
- <fsummary>Encrypt <c>Text</c>according to AES in Cipher Block Chaining mode</fsummary>
- <type>
- <v>Key = Text = iolist() | binary()</v>
- <v>IVec = Cipher = binary()</v>
- </type>
- <desc>
- <p>Encrypts <c>Text</c> according to AES in Cipher Block Chaining
- mode (CBC). <c>Text</c>
- must be a multiple of 128 bits (16 bytes). <c>Key</c> is the
- AES key, and <c>IVec</c> is an arbitrary initializing vector.
- The lengths of <c>Key</c> and <c>IVec</c> must be 128 bits
- (16 bytes).</p>
- </desc>
- </func>
- <func>
- <name>aes_cbc_128_decrypt(Key, IVec, Cipher) -> Text</name>
- <fsummary>Decrypt <c>Cipher</c>according to AES in Cipher Block Chaining mode</fsummary>
- <type>
- <v>Key = Cipher = iolist() | binary()</v>
- <v>IVec = Text = binary()</v>
- </type>
- <desc>
- <p>Decrypts <c>Cipher</c> according to AES in Cipher Block
- Chaining mode (CBC).
- <c>Key</c> is the AES key, and <c>IVec</c> is an arbitrary
- initializing vector. <c>Key</c> and <c>IVec</c> must have
- the same values as those used when encrypting. <c>Cipher</c>
- must be a multiple of 128 bits (16 bytes). The lengths of
- <c>Key</c> and <c>IVec</c> must be 128 bits (16 bytes).</p>
- </desc>
- </func>
- <func>
- <name>aes_cbc_ivec(Data) -> IVec</name>
- <fsummary>Get <c>IVec</c> to be used in next iteration of
- <c>aes_cbc_*_[ecrypt|decrypt]</c></fsummary>
- <type>
- <v>Data = iolist() | binary()</v>
- <v>IVec = binary()</v>
- </type>
- <desc>
- <p>Returns the <c>IVec</c> to be used in a next iteration of
- <c>aes_cbc_*_[encrypt|decrypt]</c>. <c>Data</c> is the encrypted
- data from the previous iteration step.</p>
- </desc>
- </func>
- <func>
- <name>aes_ctr_encrypt(Key, IVec, Text) -> Cipher</name>
- <fsummary>Encrypt <c>Text</c>according to AES in Counter mode</fsummary>
- <type>
- <v>Key = Text = iolist() | binary()</v>
- <v>IVec = Cipher = binary()</v>
- </type>
- <desc>
- <p>Encrypts <c>Text</c> according to AES in Counter mode (CTR). <c>Text</c>
- can be any number of bytes. <c>Key</c> is the AES key and must be either
- 128, 192 or 256 bits long. <c>IVec</c> is an arbitrary initializing vector of 128 bits
- (16 bytes).</p>
- </desc>
- </func>
- <func>
- <name>aes_ctr_decrypt(Key, IVec, Cipher) -> Text</name>
- <fsummary>Decrypt <c>Cipher</c>according to AES in Counter mode</fsummary>
- <type>
- <v>Key = Cipher = iolist() | binary()</v>
- <v>IVec = Text = binary()</v>
- </type>
- <desc>
- <p>Decrypts <c>Cipher</c> according to AES in Counter mode (CTR). <c>Cipher</c>
- can be any number of bytes. <c>Key</c> is the AES key and must be either
- 128, 192 or 256 bits long. <c>IVec</c> is an arbitrary initializing vector of 128 bits
- (16 bytes).</p>
- </desc>
- </func>
- <func>
- <name>aes_ctr_stream_init(Key, IVec) -> State</name>
- <fsummary></fsummary>
- <type>
- <v>State = { K, I, E, C }</v>
- <v>Key = K = iolist()</v>
- <v>IVec = I = E = binary()</v>
- <v>C = integer()</v>
- </type>
- <desc>
- <p>Initializes the state for use in streaming AES encryption using Counter mode (CTR).
- <c>Key</c> is the AES key and must be either 128, 192, or 256 bts long. <c>IVec</c> is
- an arbitrary initializing vector of 128 bits (16 bytes). This state is for use with
- <seealso marker="#aes_ctr_stream_encrypt/2">aes_ctr_stream_encrypt</seealso> and
- <seealso marker="#aes_ctr_stream_decrypt/2">aes_ctr_stream_decrypt</seealso>.</p>
- </desc>
- </func>
- <func>
- <name>aes_ctr_stream_encrypt(State, Text) -> { NewState, Cipher}</name>
- <fsummary></fsummary>
- <type>
- <v>Text = iolist() | binary()</v>
- <v>Cipher = binary()</v>
- </type>
- <desc>
- <p>Encrypts <c>Text</c> according to AES in Counter mode (CTR). This function can be
- used to encrypt a stream of text using a series of calls instead of requiring all
- text to be in memory. <c>Text</c> can be any number of bytes. State is initialized using
- <seealso marker="#aes_ctr_stream_init/2">aes_ctr_stream_init</seealso>. <c>NewState</c> is the new streaming
- encryption state that must be passed to the next call to <c>aes_ctr_stream_encrypt</c>.
- <c>Cipher</c> is the encrypted cipher text.</p>
- </desc>
- </func>
- <func>
- <name>aes_ctr_stream_decrypt(State, Cipher) -> { NewState, Text }</name>
- <fsummary></fsummary>
- <type>
- <v>Cipher = iolist() | binary()</v>
- <v>Text = binary()</v>
- </type>
- <desc>
- <p>Decrypts <c>Cipher</c> according to AES in Counter mode (CTR). This function can be
- used to decrypt a stream of ciphertext using a series of calls instead of requiring all
- ciphertext to be in memory. <c>Cipher</c> can be any number of bytes. State is initialized using
- <seealso marker="#aes_ctr_stream_init/2">aes_ctr_stream_init</seealso>. <c>NewState</c> is the new streaming
- encryption state that must be passed to the next call to <c>aes_ctr_stream_encrypt</c>.
- <c>Text</c> is the decrypted data.</p>
- </desc>
- </func>
- <func>
- <name>erlint(Mpint) -> N</name>
- <name>mpint(N) -> Mpint</name>
- <fsummary>Convert between binary multi-precision integer and erlang big integer</fsummary>
- <type>
- <v>Mpint = binary()</v>
- <v>N = integer()</v>
- </type>
- <desc>
- <p>Convert a binary multi-precision integer <c>Mpint</c> to and from
- an erlang big integer. A multi-precision integer is a binary
- with the following form:
- <c><![CDATA[<<ByteLen:32/integer, Bytes:ByteLen/binary>>]]></c> where both
- <c>ByteLen</c> and <c>Bytes</c> are big-endian. Mpints are used in
- some of the functions in <c>crypto</c> and are not translated
- in the API for performance reasons.</p>
- </desc>
- </func>
- <func>
- <name>rand_bytes(N) -> binary()</name>
- <fsummary>Generate a binary of random bytes</fsummary>
- <type>
- <v>N = integer()</v>
- </type>
- <desc>
- <p>Generates N bytes randomly uniform 0..255, and returns the
- result in a binary. Uses the <c>crypto</c> library pseudo-random
- number generator.</p>
- </desc>
- </func>
- <func>
- <name>strong_rand_bytes(N) -> binary()</name>
- <fsummary>Generate a binary of random bytes</fsummary>
- <type>
- <v>N = integer()</v>
- </type>
- <desc>
- <p>Generates N bytes randomly uniform 0..255, and returns the
- result in a binary. Uses a cryptographically secure prng seeded and
- periodically mixed with operating system provided entropy. By default
- this is the <c>RAND_bytes</c> method from OpenSSL.</p>
- <p>May throw exception <c>low_entropy</c> in case the random generator
- failed due to lack of secure "randomness".</p>
- </desc>
- </func>
- <func>
- <name>rand_uniform(Lo, Hi) -> N</name>
- <fsummary>Generate a random number</fsummary>
- <type>
- <v>Lo, Hi, N = Mpint | integer()</v>
- <v>Mpint = binary()</v>
- </type>
- <desc>
- <p>Generate a random number <c><![CDATA[N, Lo =< N < Hi.]]></c> Uses the
- <c>crypto</c> library pseudo-random number generator. The
- arguments (and result) can be either erlang integers or binary
- multi-precision integers. <c>Hi</c> must be larger than <c>Lo</c>.</p>
- </desc>
- </func>
- <func>
- <name>strong_rand_mpint(N, Top, Bottom) -> Mpint</name>
- <fsummary>Generate an N bit random number</fsummary>
- <type>
- <v>N = non_neg_integer()</v>
- <v>Top = -1 | 0 | 1</v>
- <v>Bottom = 0 | 1</v>
- <v>Mpint = binary()</v>
- </type>
- <desc>
- <p>Generate an N bit random number using OpenSSL's
- cryptographically strong pseudo random number generator
- <c>BN_rand</c>.</p>
- <p>The parameter <c>Top</c> places constraints on the most
- significant bits of the generated number. If <c>Top</c> is 1, then the
- two most significant bits will be set to 1, if <c>Top</c> is 0, the
- most significant bit will be 1, and if <c>Top</c> is -1 then no
- constraints are applied and thus the generated number may be less than
- N bits long.</p>
- <p>If <c>Bottom</c> is 1, then the generated number is
- constrained to be odd.</p>
- <p>May throw exception <c>low_entropy</c> in case the random generator
- failed due to lack of secure "randomness".</p>
- </desc>
- </func>
- <func>
- <name>mod_exp(N, P, M) -> Result</name>
- <fsummary>Perform N ^ P mod M</fsummary>
- <type>
- <v>N, P, M, Result = Mpint</v>
- <v>Mpint = binary()</v>
- </type>
- <desc>
- <p>This function performs the exponentiation <c>N ^ P mod M</c>,
- using the <c>crypto</c> library.</p>
- </desc>
- </func>
- <func>
- <name>mod_exp_prime(N, P, M) -> Result</name>
+ <name>mod_pow(N, P, M) -> Result</name>
<fsummary>Computes the function: N^P mod M</fsummary>
<type>
- <v>N, P, M = binary()</v>
+ <v>N, P, M = binary() | integer()</v>
<v>Result = binary() | error</v>
</type>
<desc>
<p>Computes the function <c>N^P mod M</c>.</p>
</desc>
</func>
- <func>
- <name>rsa_sign(DataOrDigest, Key) -> Signature</name>
- <name>rsa_sign(DigestType, DataOrDigest, Key) -> Signature</name>
- <fsummary>Sign the data using rsa with the given key.</fsummary>
- <type>
- <v>DataOrDigest = Data | {digest,Digest}</v>
- <v>Data = Mpint</v>
- <v>Digest = binary()</v>
- <v>Key = [E, N, D] | [E, N, D, P1, P2, E1, E2, C]</v>
- <v>E, N, D = Mpint</v>
- <d>Where <c>E</c> is the public exponent, <c>N</c> is public modulus and
- <c>D</c> is the private exponent.</d>
- <v>P1, P2, E1, E2, C = Mpint</v>
- <d>The longer key format contains redundant information that will make
- the calculation faster. <c>P1,P2</c> are first and second prime factors.
- <c>E1,E2</c> are first and second exponents. <c>C</c> is the CRT coefficient.
- Terminology is taken from RFC 3447.</d>
- <v>DigestType = md5 | sha | sha224 | sha256 | sha384 | sha512</v>
- <d>The default <c>DigestType</c> is sha.</d>
- <v>Mpint = binary()</v>
- <v>Signature = binary()</v>
- </type>
- <desc>
- <p>Creates a RSA signature with the private key <c>Key</c>
- of a digest. The digest is either calculated as a
- <c>DigestType</c> digest of <c>Data</c> or a precalculated
- binary <c>Digest</c>.</p>
- </desc>
- </func>
<func>
- <name>rsa_verify(DataOrDigest, Signature, Key) -> Verified</name>
- <name>rsa_verify(DigestType, DataOrDigest, Signature, Key) -> Verified </name>
- <fsummary>Verify the digest and signature using rsa with given public key.</fsummary>
- <type>
- <v>Verified = boolean()</v>
- <v>DataOrDigest = Data | {digest|Digest}</v>
- <v>Data, Signature = Mpint</v>
- <v>Digest = binary()</v>
- <v>Key = [E, N]</v>
- <v>E, N = Mpint</v>
- <d>Where <c>E</c> is the public exponent and <c>N</c> is public modulus.</d>
- <v>DigestType = md5 | sha | sha224 | sha256 | sha384 | sha512</v>
- <d>The default <c>DigestType</c> is sha.</d>
- <v>Mpint = binary()</v>
- </type>
- <desc>
- <p>Verifies that a digest matches the RSA signature using the
- signer's public key <c>Key</c>.
- The digest is either calculated as a <c>DigestType</c>
- digest of <c>Data</c> or a precalculated binary <c>Digest</c>.</p>
- <p>May throw exception <c>notsup</c> in case the chosen <c>DigestType</c>
- is not supported by the underlying OpenSSL implementation.</p>
- </desc>
- </func>
-
- <func>
- <name>rsa_public_encrypt(PlainText, PublicKey, Padding) -> ChipherText</name>
- <fsummary>Encrypts Msg using the public Key.</fsummary>
- <type>
- <v>PlainText = binary()</v>
- <v>PublicKey = [E, N]</v>
- <v>E, N = Mpint</v>
- <d>Where <c>E</c> is the public exponent and <c>N</c> is public modulus.</d>
- <v>Padding = rsa_pkcs1_padding | rsa_pkcs1_oaep_padding | rsa_no_padding</v>
- <v>ChipherText = binary()</v>
- </type>
- <desc>
- <p>Encrypts the <c>PlainText</c> (usually a session key) using the <c>PublicKey</c>
- and returns the cipher. The <c>Padding</c> decides what padding mode is used,
- <c>rsa_pkcs1_padding</c> is PKCS #1 v1.5 currently the most
- used mode and <c>rsa_pkcs1_oaep_padding</c> is EME-OAEP as
- defined in PKCS #1 v2.0 with SHA-1, MGF1 and an empty encoding
- parameter. This mode is recommended for all new applications.
- The size of the <c>Msg</c> must be less
- than <c>byte_size(N)-11</c> if
- <c>rsa_pkcs1_padding</c> is used, <c>byte_size(N)-41</c> if
- <c>rsa_pkcs1_oaep_padding</c> is used and <c>byte_size(N)</c> if <c>rsa_no_padding</c>
- is used.
- Where byte_size(N) is the size part of an <c>Mpint-1</c>.
- </p>
- </desc>
+ <name>next_iv(Type, Data) -> </name>
+ <fsummary></fsummary>
+ <type>
+ <v>Type = des_cbc | aes_cbc</v>
+ <v>Data = iodata()</v>
+ </type>
+ <desc>
+ <p>Returns the initialization vector to be used in the next
+ iteration of encrypt/decrypt of type <c>Type</c>. Data is the
+ encrypted data from the previous iteration step.</p>
+ </desc>
</func>
<func>
- <name>rsa_private_decrypt(ChipherText, PrivateKey, Padding) -> PlainText</name>
+ <name>private_decrypt(Type, ChipherText, PrivateKey, Padding) -> PlainText</name>
<fsummary>Decrypts ChipherText using the private Key.</fsummary>
<type>
+ <v>Type = rsa</v>
<v>ChipherText = binary()</v>
- <v>PrivateKey = [E, N, D] | [E, N, D, P1, P2, E1, E2, C]</v>
- <v>E, N, D = Mpint</v>
- <d>Where <c>E</c> is the public exponent, <c>N</c> is public modulus and
- <c>D</c> is the private exponent.</d>
- <v>P1, P2, E1, E2, C = Mpint</v>
- <d>The longer key format contains redundant information that will make
- the calculation faster. <c>P1,P2</c> are first and second prime factors.
- <c>E1,E2</c> are first and second exponents. <c>C</c> is the CRT coefficient.
- Terminology is taken from RFC 3447.</d>
+ <v>PrivateKey = rsa_private()</v>
<v>Padding = rsa_pkcs1_padding | rsa_pkcs1_oaep_padding | rsa_no_padding</v>
<v>PlainText = binary()</v>
</type>
<desc>
- <p>Decrypts the <c>ChipherText</c> (usually a session key encrypted with
- <seealso marker="#rsa_public_encrypt/3">rsa_public_encrypt/3</seealso>)
+ <p>Decrypts the <c>ChipherText</c> (usually a session key encrypted with
+ <seealso marker="#public_encrypt/3">public_encrypt/3</seealso>)
using the <c>PrivateKey</c> and returns the
message. The <c>Padding</c> is the padding mode that was
- used to encrypt the data,
- see <seealso marker="#rsa_public_encrypt/3">rsa_public_encrypt/3</seealso>.
+ used to encrypt the data,
+ see <seealso marker="#public_encrypt/3">public_encrypt/3</seealso>.
+ See also <seealso marker="public_key:public_key#decrypt_private/2">public_key:decrypt_private/[2,3]</seealso>
</p>
</desc>
</func>
+
<func>
- <name>rsa_private_encrypt(PlainText, PrivateKey, Padding) -> ChipherText</name>
+ <name>private_encrypt(Type, PlainText, PrivateKey, Padding) -> ChipherText</name>
<fsummary>Encrypts Msg using the private Key.</fsummary>
<type>
+ <v>Type = rsa</v>
<v>PlainText = binary()</v>
- <v>PrivateKey = [E, N, D] | [E, N, D, P1, P2, E1, E2, C]</v>
- <v>E, N, D = Mpint</v>
- <d>Where <c>E</c> is the public exponent, <c>N</c> is public modulus and
- <c>D</c> is the private exponent.</d>
- <v>P1, P2, E1, E2, C = Mpint</v>
- <d>The longer key format contains redundant information that will make
- the calculation faster. <c>P1,P2</c> are first and second prime factors.
- <c>E1,E2</c> are first and second exponents. <c>C</c> is the CRT coefficient.
- Terminology is taken from RFC 3447.</d>
+ <v>PrivateKey = rsa_private()</v>
<v>Padding = rsa_pkcs1_padding | rsa_no_padding</v>
<v>ChipherText = binary()</v>
</type>
@@ -1131,316 +458,289 @@ Mpint() = <![CDATA[<<ByteLen:32/integer-big, Bytes:ByteLen/binary>>]]>
<c>rsa_pkcs1_padding</c> is PKCS #1 v1.5 currently the most
used mode.
The size of the <c>Msg</c> must be less than <c>byte_size(N)-11</c> if
- <c>rsa_pkcs1_padding</c> is used, and <c>byte_size(N)</c> if <c>rsa_no_padding</c>
- is used. Where byte_size(N) is the size part of an <c>Mpint-1</c>.
+ <c>rsa_pkcs1_padding</c> is used, and <c>byte_size(N)</c> if <c>rsa_no_padding</c>
+ is used.
+ See also <seealso marker="public_key:public_key#encrypt_private/2">public_key:encrypt_private/[2,3]</seealso>
</p>
</desc>
</func>
-
<func>
- <name>rsa_public_decrypt(ChipherText, PublicKey, Padding) -> PlainText</name>
+ <name>public_decrypt(Type, ChipherText, PublicKey, Padding) -> PlainText</name>
<fsummary>Decrypts ChipherText using the public Key.</fsummary>
<type>
+ <v>Type = rsa</v>
<v>ChipherText = binary()</v>
- <v>PublicKey = [E, N]</v>
- <v>E, N = Mpint</v>
- <d>Where <c>E</c> is the public exponent and <c>N</c> is public modulus</d>
+ <v>PublicKey = rsa_public() </v>
<v>Padding = rsa_pkcs1_padding | rsa_no_padding</v>
<v>PlainText = binary()</v>
</type>
<desc>
- <p>Decrypts the <c>ChipherText</c> (encrypted with
- <seealso marker="#rsa_private_encrypt/3">rsa_private_encrypt/3</seealso>)
+ <p>Decrypts the <c>ChipherText</c> (encrypted with
+ <seealso marker="#private_encrypt/3">private_encrypt/3</seealso>)
using the <c>PrivateKey</c> and returns the
message. The <c>Padding</c> is the padding mode that was
- used to encrypt the data,
- see <seealso marker="#rsa_private_encrypt/3">rsa_private_encrypt/3</seealso>.
+ used to encrypt the data,
+ see <seealso marker="#private_encrypt/3">private_encrypt/3</seealso>.
+ See also <seealso marker="public_key:public_key#decrypt_public/2">public_key:decrypt_public/[2,3]</seealso>
</p>
</desc>
</func>
-
+
<func>
- <name>dss_sign(DataOrDigest, Key) -> Signature</name>
- <name>dss_sign(DigestType, DataOrDigest, Key) -> Signature</name>
- <fsummary>Sign the data using dsa with given private key.</fsummary>
+ <name>public_encrypt(Type, PlainText, PublicKey, Padding) -> ChipherText</name>
+ <fsummary>Encrypts Msg using the public Key.</fsummary>
<type>
- <v>DigestType = sha</v>
- <v>DataOrDigest = Mpint | {digest,Digest}</v>
- <v>Key = [P, Q, G, X]</v>
- <v>P, Q, G, X = Mpint</v>
- <d> Where <c>P</c>, <c>Q</c> and <c>G</c> are the dss
- parameters and <c>X</c> is the private key.</d>
- <v>Digest = binary() with length 20 bytes</v>
- <v>Signature = binary()</v>
+ <v>Type = rsa</v>
+ <v>PlainText = binary()</v>
+ <v>PublicKey = rsa_public()</v>
+ <v>Padding = rsa_pkcs1_padding | rsa_pkcs1_oaep_padding | rsa_no_padding</v>
+ <v>ChipherText = binary()</v>
</type>
<desc>
- <p>Creates a DSS signature with the private key <c>Key</c> of
- a digest. The digest is either calculated as a SHA1
- digest of <c>Data</c> or a precalculated binary <c>Digest</c>.</p>
- <p>A deprecated feature is having <c>DigestType = 'none'</c>
- in which case <c>DataOrDigest</c> is a precalculated SHA1
- digest.</p>
+ <p>Encrypts the <c>PlainText</c> (usually a session key) using the <c>PublicKey</c>
+ and returns the <c>CipherText</c>. The <c>Padding</c> decides what padding mode is used,
+ <c>rsa_pkcs1_padding</c> is PKCS #1 v1.5 currently the most
+ used mode and <c>rsa_pkcs1_oaep_padding</c> is EME-OAEP as
+ defined in PKCS #1 v2.0 with SHA-1, MGF1 and an empty encoding
+ parameter. This mode is recommended for all new applications.
+ The size of the <c>Msg</c> must be less
+ than <c>byte_size(N)-11</c> if
+ <c>rsa_pkcs1_padding</c> is used, <c>byte_size(N)-41</c> if
+ <c>rsa_pkcs1_oaep_padding</c> is used and <c>byte_size(N)</c> if <c>rsa_no_padding</c>
+ is used.
+ See also <seealso marker="public_key:public_key#encrypt_public/2">public_key:encrypt_public/[2,3]</seealso>
+ </p>
</desc>
</func>
<func>
- <name>dss_verify(DataOrDigest, Signature, Key) -> Verified</name>
- <name>dss_verify(DigestType, DataOrDigest, Signature, Key) -> Verified</name>
- <fsummary>Verify the data and signature using dsa with given public key.</fsummary>
+ <name>rand_bytes(N) -> binary()</name>
+ <fsummary>Generate a binary of random bytes</fsummary>
<type>
- <v>Verified = boolean()</v>
- <v>DigestType = sha</v>
- <v>DataOrDigest = Mpint | {digest,Digest}</v>
- <v>Data = Mpint | ShaDigest</v>
- <v>Signature = Mpint</v>
- <v>Key = [P, Q, G, Y]</v>
- <v>P, Q, G, Y = Mpint</v>
- <d> Where <c>P</c>, <c>Q</c> and <c>G</c> are the dss
- parameters and <c>Y</c> is the public key.</d>
- <v>Digest = binary() with length 20 bytes</v>
+ <v>N = integer()</v>
</type>
<desc>
- <p>Verifies that a digest matches the DSS signature using the
- public key <c>Key</c>. The digest is either calculated as a SHA1
- digest of <c>Data</c> or is a precalculated binary <c>Digest</c>.</p>
- <p>A deprecated feature is having <c>DigestType = 'none'</c>
- in which case <c>DataOrDigest</c> is a precalculated SHA1
- digest binary.</p>
+ <p>Generates N bytes randomly uniform 0..255, and returns the
+ result in a binary. Uses the <c>crypto</c> library pseudo-random
+ number generator.</p>
</desc>
</func>
- <func>
- <name>rc2_cbc_encrypt(Key, IVec, Text) -> Cipher</name>
- <fsummary>Encrypt <c>Text</c>according to RC2 in CBC mode</fsummary>
+ <func>
+ <name>rand_uniform(Lo, Hi) -> N</name>
+ <fsummary>Generate a random number</fsummary>
<type>
- <v>Key = Text = iolist() | binary()</v>
- <v>Ivec = Cipher = binary()</v>
+ <v>Lo, Hi, N = integer()</v>
</type>
<desc>
- <p>Encrypts <c>Text</c> according to RC2 in CBC mode.</p>
+ <p>Generate a random number <c><![CDATA[N, Lo =< N < Hi.]]></c> Uses the
+ <c>crypto</c> library pseudo-random number generator.
+ <c>Hi</c> must be larger than <c>Lo</c>.</p>
</desc>
</func>
<func>
- <name>rc2_cbc_decrypt(Key, IVec, Cipher) -> Text</name>
- <fsummary>Decrypts <c>Cipher</c>according to RC2 in CBC mode</fsummary>
+ <name>sign(Algorithm, DigestType, Msg, Key) -> binary()</name>
+ <fsummary> Create digital signature.</fsummary>
<type>
- <v>Key = Text = iolist() | binary()</v>
- <v>Ivec = Cipher = binary()</v>
+ <v>Algorithm = rsa | dss | ecdsa </v>
+ <v>Msg = binary() | {digest,binary()}</v>
+ <d>The msg is either the binary "plain text" data to be
+ signed or it is the hashed value of "plain text" i.e. the
+ digest.</d>
+ <v>DigestType = digest_type()</v>
+ <v>Key = rsa_private_key() | dsa_private_key() | ec_private_key()</v>
</type>
<desc>
- <p>Decrypts <c>Cipher</c> according to RC2 in CBC mode.</p>
+ <p> Creates a digital signature.</p>
+ See also <seealso marker="public_key:public_key#sign/3">public_key:sign/3</seealso>
</desc>
</func>
-
+
<func>
- <name>rc4_encrypt(Key, Data) -> Result</name>
- <fsummary>Encrypt data using RC4</fsummary>
+ <name>start() -> ok</name>
+ <fsummary> Equivalent to application:start(crypto). </fsummary>
+ <desc>
+ <p> Equivalent to application:start(crypto).</p>
+ </desc>
+ </func>
+ <func>
+ <name>stop() -> ok</name>
+ <fsummary> Equivalent to application:stop(crypto).</fsummary>
+ <desc>
+ <p> Equivalent to application:stop(crypto).</p>
+ </desc>
+ </func>
+
+ <func>
+ <name>strong_rand_bytes(N) -> binary()</name>
+ <fsummary>Generate a binary of random bytes</fsummary>
<type>
- <v>Key, Data = iolist() | binary()</v>
- <v>Result = binary()</v>
+ <v>N = integer()</v>
</type>
<desc>
- <p>Encrypts the data with RC4 symmetric stream encryption.
- Since it is symmetric, the same function is used for
- decryption.</p>
+ <p>Generates N bytes randomly uniform 0..255, and returns the
+ result in a binary. Uses a cryptographically secure prng seeded and
+ periodically mixed with operating system provided entropy. By default
+ this is the <c>RAND_bytes</c> method from OpenSSL.</p>
+ <p>May throw exception <c>low_entropy</c> in case the random generator
+ failed due to lack of secure "randomness".</p>
</desc>
</func>
-
<func>
- <name>dh_generate_key(DHParams) -> {PublicKey,PrivateKey} </name>
- <name>dh_generate_key(PrivateKey, DHParams) -> {PublicKey,PrivateKey} </name>
- <fsummary>Generates a Diffie-Hellman public key</fsummary>
+ <name>stream_init(Type, Key) -> State</name>
+ <fsummary></fsummary>
<type>
- <v>DHParameters = [P, G]</v>
- <v>P, G = Mpint</v>
- <d> Where <c>P</c> is the shared prime number and <c>G</c> is the shared generator.</d>
- <v>PublicKey, PrivateKey = Mpint()</v>
+ <v>Type rc4 </v>
+ <v>State = opaque() </v>
+ <v>Key = iodata()</v>
+ <v>IVec = binary()</v>
</type>
<desc>
- <p>Generates a Diffie-Hellman <c>PublicKey</c> and <c>PrivateKey</c> (if not given).
- </p>
+ <p>Initializes the state for use in RC4 stream encryption
+ <seealso marker="#stream_encrypt/2">stream_encrypt</seealso> and
+ <seealso marker="#stream_decrypt/2">stream_decrypt</seealso></p>
</desc>
</func>
- <func>
- <name>dh_compute_key(OthersPublicKey, MyPrivateKey, DHParams) -> SharedSecret</name>
- <fsummary>Computes the shared secret</fsummary>
+ <func>
+ <name>stream_init(Type, Key, IVec) -> State</name>
+ <fsummary></fsummary>
<type>
- <v>DHParameters = [P, G]</v>
- <v>P, G = Mpint</v>
- <d> Where <c>P</c> is the shared prime number and <c>G</c> is the shared generator.</d>
- <v>OthersPublicKey, MyPrivateKey = Mpint()</v>
- <v>SharedSecret = binary()</v>
+ <v>Type aes_ctr </v>
+ <v>State = opaque() </v>
+ <v>Key = iodata()</v>
+ <v>IVec = binary()</v>
</type>
<desc>
- <p>Computes the shared secret from the private key and the other party's public key.
- </p>
+ <p>Initializes the state for use in streaming AES encryption using Counter mode (CTR).
+ <c>Key</c> is the AES key and must be either 128, 192, or 256 bts long. <c>IVec</c> is
+ an arbitrary initializing vector of 128 bits (16 bytes). This state is for use with
+ <seealso marker="#stream_encrypt/2">stream_encrypt</seealso> and
+ <seealso marker="#stream_decrypt/2">stream_decrypt</seealso>.</p>
</desc>
</func>
-
+
<func>
- <name>srp_generate_key(Generator, Prime, Version) -> {PublicKey, PrivateKey} </name>
- <name>srp_generate_key(Generator, Prime, Version, Private) -> {PublicKey, PrivateKey} </name>
- <name>srp_generate_key(Verifier, Generator, Prime, Version) -> {PublicKey, PrivateKey} </name>
- <name>srp_generate_key(Verifier, Generator, Prime, Version, Private) -> {PublicKey, PrivateKey} </name>
- <fsummary>Generates SRP public keys</fsummary>
+ <name>stream_encrypt(State, PlainText) -> { NewState, CipherText}</name>
+ <fsummary></fsummary>
<type>
- <v>Verifier = binary()</v>
- <d>Parameter v from <url href="http://srp.stanford.edu/design.html">SRP design</url>
- </d>
- <v>Generator = binary() </v>
- <d>Parameter g from <url href="http://srp.stanford.edu/design.html">SRP design</url>
- </d>
- <v>Prime = binary() </v>
- <d>Parameter N from <url href="http://srp.stanford.edu/design.html">SRP design</url>
- </d>
- <v>Version = '3' | '6' | '6a' </v>
- <d>SRP version, TLS SRP cipher suites uses '6a'.</d>
- <v>PublicKey = binary()</v>
- <d> Parameter A or B from <url href="http://srp.stanford.edu/design.html">SRP design</url></d>
- <v>Private = PrivateKey = binary() - generated if not supplied</v>
- <d>Parameter a or b from <url href="http://srp.stanford.edu/design.html">SRP design</url></d>
+ <v>Text = iodata()</v>
+ <v>CipherText = binary()</v>
</type>
<desc>
- <p>Generates SRP public keys for the client side (first argument is Generator)
- or for the server side (first argument is Verifier).</p>
+ <p>Encrypts <c>PlainText</c> according to the stream cipher <c>Type</c> specified in stream_init/3.
+ <c>Text</c> can be any number of bytes. The initial <c>State</c> is created using
+ <seealso marker="#stream_init/2">stream_init</seealso>.
+ <c>NewState</c> must be passed into the next call to <c>stream_encrypt</c>.</p>
</desc>
</func>
<func>
- <name>srp_compute_key(DerivedKey, Prime, Generator,
- ClientPublic, ClientPrivate, ServerPublic, Version) -> SessionKey</name>
- <name>srp_compute_key(DerivedKey, Prime, Generator,
- ClientPublic, ClientPrivate, ServerPublic, Version, Scrambler) -> SessionKey</name>
- <name>srp_compute_key(Verifier, Prime,
- ClientPublic, ServerPublic, ServerPrivate, Version, Scrambler)-> SessionKey</name>
- <name>srp_compute_key(Verifier, Prime,
- ClientPublic, ServerPublic, ServerPrivate, Version) -> SessionKey</name>
-
- <fsummary>Computes SRP session key</fsummary>
+ <name>stream_decrypt(State, CipherText) -> { NewState, PlainText }</name>
+ <fsummary></fsummary>
<type>
- <v>DerivedKey = binary()</v>
- <d>Parameter x from <url href="http://srp.stanford.edu/design.html">SRP design</url>
- </d>
- <v>Verifier = binary()</v>
- <d>Parameter v from <url href="http://srp.stanford.edu/design.html">SRP design</url>
- </d>
- <v>Prime = binary() </v>
- <d>Parameter N from <url href="http://srp.stanford.edu/design.html">SRP design</url>
- </d>
- <v>Generator = binary() </v>
- <d>Parameter g from <url href="http://srp.stanford.edu/design.html">SRP design</url>
- </d>
- <v>ClientPublic = binary() </v>
- <d>Parameter A from <url href="http://srp.stanford.edu/design.html">SRP design</url>
- </d>
- <v>ClientPrivate = binary() </v>
- <d>Parameter a from <url href="http://srp.stanford.edu/design.html">SRP design</url>
- </d>
- <v>ServerPublic = binary() </v>
- <d>Parameter B from <url href="http://srp.stanford.edu/design.html">SRP design</url>
- </d>
- <v>ServerPrivate = binary() </v>
- <d>Parameter b from <url href="http://srp.stanford.edu/design.html">SRP design</url>
- </d>
- <v>Version = '3' | '6' | '6a' </v>
- <d>SRP version, TLS SRP cipher suites uses '6a'.</d>
- <v>SessionKey = binary()</v>
- <d>Result K from <url href="http://srp.stanford.edu/design.html">SRP design</url>
- </d>
+ <v>CipherText = iodata()</v>
+ <v>PlainText = binary()</v>
</type>
<desc>
- <p>
- Computes the SRP session key (shared secret) for the client side (first argument is DerivedKey)
- or for the server side (first argument is Verifier). Also used
- as premaster secret by TLS-SRP ciher suites.
- </p>
+ <p>Decrypts <c>CipherText</c> according to the stream cipher <c>Type</c> specified in stream_init/3.
+ <c>PlainText</c> can be any number of bytes. The initial <c>State</c> is created using
+ <seealso marker="#stream_init/2">stream_init</seealso>.
+ <c>NewState</c> must be passed into the next call to <c>stream_encrypt</c>.</p>
</desc>
</func>
-
- <func>
- <name>exor(Data1, Data2) -> Result</name>
- <fsummary>XOR data</fsummary>
+
+ <func>
+ <name>verify(Algorithm, DigestType, Msg, Signature, Key) -> boolean()</name>
+ <fsummary>Verifies a digital signature.</fsummary>
<type>
- <v>Data1, Data2 = iolist() | binary()</v>
- <v>Result = binary()</v>
+ <v> Algorithm = rsa | dss | ecdsa </v>
+ <v>Msg = binary() | {digest,binary()}</v>
+ <d>The msg is either the binary "plain text" data
+ or it is the hashed value of "plain text" i.e. the digest.</d>
+ <v>DigestType = digest_type()</v>
+ <v>Signature = binary()</v>
+ <v>Key = rsa_public_key() | dsa_public_key() | ec_public_key()</v>
</type>
<desc>
- <p>Performs bit-wise XOR (exclusive or) on the data supplied.</p>
+ <p>Verifies a digital signature</p>
+ See also <seealso marker="public_key:public_key#sign/3">public_key:verify/3</seealso>
</desc>
</func>
- </funcs>
- <section>
- <title>DES in CBC mode</title>
- <p>The Data Encryption Standard (DES) defines an algorithm for
- encrypting and decrypting an 8 byte quantity using an 8 byte key
- (actually only 56 bits of the key is used).
- </p>
- <p>When it comes to encrypting and decrypting blocks that are
- multiples of 8 bytes various modes are defined (NIST SP
- 800-38A). One of those modes is the Cipher Block Chaining (CBC)
- mode, where the encryption of an 8 byte segment depend not only
- of the contents of the segment itself, but also on the result of
- encrypting the previous segment: the encryption of the previous
- segment becomes the initializing vector of the encryption of the
- current segment.
- </p>
- <p>Thus the encryption of every segment depends on the encryption
- key (which is secret) and the encryption of the previous
- segment, except the first segment which has to be provided with
- an initial initializing vector. That vector could be chosen at
- random, or be a counter of some kind. It does not have to be
- secret.
- </p>
- <p>The following example is drawn from the old FIPS 81 standard
- (replaced by NIST SP 800-38A), where both the plain text and the
- resulting cipher text is settled. The following code fragment
- returns `true'.
- </p>
- <pre><![CDATA[
-
- Key = <<16#01,16#23,16#45,16#67,16#89,16#ab,16#cd,16#ef>>,
- IVec = <<16#12,16#34,16#56,16#78,16#90,16#ab,16#cd,16#ef>>,
- P = "Now is the time for all ",
- C = crypto:des_cbc_encrypt(Key, IVec, P),
- % Which is the same as
- P1 = "Now is t", P2 = "he time ", P3 = "for all ",
- C1 = crypto:des_cbc_encrypt(Key, IVec, P1),
- C2 = crypto:des_cbc_encrypt(Key, C1, P2),
- C3 = crypto:des_cbc_encrypt(Key, C2, P3),
-
- C = <<C1/binary, C2/binary, C3/binary>>,
- C = <<16#e5,16#c7,16#cd,16#de,16#87,16#2b,16#f2,16#7c,
- 16#43,16#e9,16#34,16#00,16#8c,16#38,16#9c,16#0f,
- 16#68,16#37,16#88,16#49,16#9a,16#7c,16#05,16#f6>>,
- <<"Now is the time for all ">> ==
- crypto:des_cbc_decrypt(Key, IVec, C).
- ]]></pre>
- <p>The following is true for the DES CBC mode. For all
- decompositions <c>P1 ++ P2 = P</c> of a plain text message
- <c>P</c> (where the length of all quantities are multiples of 8
- bytes), the encryption <c>C</c> of <c>P</c> is equal to <c>C1 ++
- C2</c>, where <c>C1</c> is obtained by encrypting <c>P1</c> with
- <c>Key</c> and the initializing vector <c>IVec</c>, and where
- <c>C2</c> is obtained by encrypting <c>P2</c> with <c>Key</c>
- and the initializing vector <c>last8(C1)</c>,
- where <c>last(Binary)</c> denotes the last 8 bytes of the
- binary <c>Binary</c>.
- </p>
- <p>Similarly, for all decompositions <c>C1 ++ C2 = C</c> of a
- cipher text message <c>C</c> (where the length of all quantities
- are multiples of 8 bytes), the decryption <c>P</c> of <c>C</c>
- is equal to <c>P1 ++ P2</c>, where <c>P1</c> is obtained by
- decrypting <c>C1</c> with <c>Key</c> and the initializing vector
- <c>IVec</c>, and where <c>P2</c> is obtained by decrypting
- <c>C2</c> with <c>Key</c> and the initializing vector
- <c>last8(C1)</c>, where <c>last8(Binary)</c> is as above.
- </p>
- <p>For DES3 (which uses three 64 bit keys) the situation is the
- same.
- </p>
- </section>
+ </funcs>
+
+ <!-- Maybe put this in the users guide -->
+ <!-- <section> -->
+ <!-- <title>DES in CBC mode</title> -->
+ <!-- <p>The Data Encryption Standard (DES) defines an algorithm for -->
+ <!-- encrypting and decrypting an 8 byte quantity using an 8 byte key -->
+ <!-- (actually only 56 bits of the key is used). -->
+ <!-- </p> -->
+ <!-- <p>When it comes to encrypting and decrypting blocks that are -->
+ <!-- multiples of 8 bytes various modes are defined (NIST SP -->
+ <!-- 800-38A). One of those modes is the Cipher Block Chaining (CBC) -->
+ <!-- mode, where the encryption of an 8 byte segment depend not only -->
+ <!-- of the contents of the segment itself, but also on the result of -->
+ <!-- encrypting the previous segment: the encryption of the previous -->
+ <!-- segment becomes the initializing vector of the encryption of the -->
+ <!-- current segment. -->
+ <!-- </p> -->
+ <!-- <p>Thus the encryption of every segment depends on the encryption -->
+ <!-- key (which is secret) and the encryption of the previous -->
+ <!-- segment, except the first segment which has to be provided with -->
+ <!-- an initial initializing vector. That vector could be chosen at -->
+ <!-- random, or be a counter of some kind. It does not have to be -->
+ <!-- secret. -->
+ <!-- </p> -->
+ <!-- <p>The following example is drawn from the old FIPS 81 standard -->
+ <!-- (replaced by NIST SP 800-38A), where both the plain text and the -->
+ <!-- resulting cipher text is settled. The following code fragment -->
+ <!-- returns `true'. -->
+ <!-- </p> -->
+ <!-- <pre><![CDATA[ -->
+
+ <!-- Key = <<16#01,16#23,16#45,16#67,16#89,16#ab,16#cd,16#ef>>, -->
+ <!-- IVec = <<16#12,16#34,16#56,16#78,16#90,16#ab,16#cd,16#ef>>, -->
+ <!-- P = "Now is the time for all ", -->
+ <!-- C = crypto:des_cbc_encrypt(Key, IVec, P), -->
+ <!-- % Which is the same as -->
+ <!-- P1 = "Now is t", P2 = "he time ", P3 = "for all ", -->
+ <!-- C1 = crypto:des_cbc_encrypt(Key, IVec, P1), -->
+ <!-- C2 = crypto:des_cbc_encrypt(Key, C1, P2), -->
+ <!-- C3 = crypto:des_cbc_encrypt(Key, C2, P3), -->
+
+ <!-- C = <<C1/binary, C2/binary, C3/binary>>, -->
+ <!-- C = <<16#e5,16#c7,16#cd,16#de,16#87,16#2b,16#f2,16#7c, -->
+ <!-- 16#43,16#e9,16#34,16#00,16#8c,16#38,16#9c,16#0f, -->
+ <!-- 16#68,16#37,16#88,16#49,16#9a,16#7c,16#05,16#f6>>, -->
+ <!-- <<"Now is the time for all ">> == -->
+ <!-- crypto:des_cbc_decrypt(Key, IVec, C). -->
+ <!-- ]]></pre> -->
+ <!-- <p>The following is true for the DES CBC mode. For all -->
+ <!-- decompositions <c>P1 ++ P2 = P</c> of a plain text message -->
+ <!-- <c>P</c> (where the length of all quantities are multiples of 8 -->
+ <!-- bytes), the encryption <c>C</c> of <c>P</c> is equal to <c>C1 ++ -->
+ <!-- C2</c>, where <c>C1</c> is obtained by encrypting <c>P1</c> with -->
+ <!-- <c>Key</c> and the initializing vector <c>IVec</c>, and where -->
+ <!-- <c>C2</c> is obtained by encrypting <c>P2</c> with <c>Key</c> -->
+ <!-- and the initializing vector <c>last8(C1)</c>, -->
+ <!-- where <c>last(Binary)</c> denotes the last 8 bytes of the -->
+ <!-- binary <c>Binary</c>. -->
+ <!-- </p> -->
+ <!-- <p>Similarly, for all decompositions <c>C1 ++ C2 = C</c> of a -->
+ <!-- cipher text message <c>C</c> (where the length of all quantities -->
+ <!-- are multiples of 8 bytes), the decryption <c>P</c> of <c>C</c> -->
+ <!-- is equal to <c>P1 ++ P2</c>, where <c>P1</c> is obtained by -->
+ <!-- decrypting <c>C1</c> with <c>Key</c> and the initializing vector -->
+ <!-- <c>IVec</c>, and where <c>P2</c> is obtained by decrypting -->
+ <!-- <c>C2</c> with <c>Key</c> and the initializing vector -->
+ <!-- <c>last8(C1)</c>, where <c>last8(Binary)</c> is as above. -->
+ <!-- </p> -->
+ <!-- <p>For DES3 (which uses three 64 bit keys) the situation is the -->
+ <!-- same. -->
+ <!-- </p> -->
+ <!-- </section> -->
</erlref>
diff --git a/lib/crypto/doc/src/crypto_app.xml b/lib/crypto/doc/src/crypto_app.xml
index 8371db1ff2..6d26076c04 100644
--- a/lib/crypto/doc/src/crypto_app.xml
+++ b/lib/crypto/doc/src/crypto_app.xml
@@ -1,4 +1,4 @@
-<?xml version="1.0" encoding="latin1" ?>
+<?xml version="1.0" encoding="iso-8859-1" ?>
<!DOCTYPE appref SYSTEM "appref.dtd">
<appref>
@@ -24,81 +24,28 @@
</legalnotice>
<title>crypto</title>
- <prepared>Peter H&ouml;gfeldt</prepared>
- <responsible>Peter H&ouml;gfeldt</responsible>
- <docno></docno>
- <approved>Peter H&ouml;gfeldt</approved>
- <checked>Peter H&ouml;gfeldt</checked>
- <date>2003-06-01</date>
- <rev>B</rev>
<file>crypto_app.sgml</file>
</header>
<app>crypto</app>
<appsummary>The Crypto Application</appsummary>
<description>
- <p>The purpose of the Crypto application is to provide message
- digest and DES encryption for SMNPv3. It provides computation of
- message digests MD5 and SHA, and CBC-DES encryption and
- decryption.</p>
- <p></p>
+ <p>The purpose of the Crypto application is to provide an Erlang API
+ to cryptographic functions, see <seealso marker="crypto">crypto(3)</seealso>.
+ Note that the API is on a fairly low level and there are some
+ corresponding API functions available in <seealso marker="public_key:public_key">public_key(3)</seealso>,
+ on a higher abstraction level, that uses the crypto application in its implementation.
+ </p>
</description>
<section>
- <title>Configuration</title>
- <p>The following environment configuration parameters are defined
- for the Crypto application. Refer to application(3) for more
- information about configuration parameters.
- </p>
- <taglist>
- <tag><c><![CDATA[debug = true | false <optional>]]></c></tag>
- <item>
- <p>Causes debug information to be written to standard
- error or standard output. Default is <c>false</c>.
- </p>
- </item>
- </taglist>
- </section>
+ <title>DEPENDENCIES</title>
- <section>
- <title>OpenSSL libraries</title>
- <p>The current implementation of the Erlang Crypto application is
- based on the <em>OpenSSL</em> package version 0.9.8 or higher.
- There are source and binary releases on the web.
- </p>
+ <p>The current crypto implementation uses nifs to interface OpenSSLs crypto library
+ and requires <em>OpenSSL</em> package version 0.9.8 or higher.</p>
<p>Source releases of OpenSSL can be downloaded from the <url href="http://www.openssl.org">OpenSSL</url> project home page,
- or mirror sites listed there.
- </p>
- <p>The same URL also contains links to some compiled binaries and
- libraries of OpenSSL (see the <c>Related/Binaries</c> menu) of
- which the <url href="http://www.shininglightpro.com/search.php?searchname=Win32+OpenSSL">Shining Light Productions Win32 and OpenSSL</url> pages are of
- interest for the Win32 user.
- </p>
- <p>For some Unix flavours there are binary packages available
- on the net.
- </p>
- <p>If you cannot find a suitable binary OpenSSL package, you
- have to fetch an OpenSSL source release and compile it.
- </p>
- <p>You then have to compile and install the library
- <c>libcrypto.so</c> (Unix), or the library <c>libeay32.dll</c>
- (Win32).
- </p>
- <p>For Unix The <c>crypto_drv</c> dynamic driver is delivered linked
- to OpenSSL libraries in <c>/usr/local/lib</c>, but the default
- dynamic linking will also accept libraries in <c>/lib</c> and
- <c>/usr/lib</c>.
- </p>
- <p>If that is not applicable to the particular Unix operating
- system used, the example <c>Makefile</c> in the Crypto
- <c>priv/obj</c> directory, should be used as a basis for
- relinking the final version of the port program.
- </p>
- <p>For <c>Win32</c> it is only required that the library can be
- found from the <c>PATH</c> environment variable, or that they
- reside in the appropriate <c>SYSTEM32</c> directory; hence no
- particular relinking is need. Hence no example <c>Makefile</c>
- for Win32 is provided.</p>
- </section>
+ or mirror sites listed there.
+ </p>
+ </section>
<section>
<title>SEE ALSO</title>
diff --git a/lib/crypto/src/crypto.erl b/lib/crypto/src/crypto.erl
index 1d0a9943c3..f4e157198c 100644
--- a/lib/crypto/src/crypto.erl
+++ b/lib/crypto/src/crypto.erl
@@ -21,104 +21,220 @@
-module(crypto).
--export([start/0, stop/0, info/0, info_lib/0, algorithms/0, version/0]).
+-export([start/0, stop/0, info_lib/0, algorithms/0, version/0]).
-export([hash/2, hash_init/1, hash_update/2, hash_final/1]).
+-export([sign/4, verify/5]).
+-export([generate_key/2, generate_key/3, compute_key/4]).
+-export([hmac/3, hmac/4, hmac_init/2, hmac_update/2, hmac_final/1, hmac_final_n/2]).
+-export([exor/2, strong_rand_bytes/1, mod_pow/3]).
+-export([rand_bytes/1, rand_bytes/3, rand_uniform/2]).
+-export([block_encrypt/3, block_decrypt/3, block_encrypt/4, block_decrypt/4]).
+-export([next_iv/2, next_iv/3]).
+-export([stream_init/2, stream_init/3, stream_encrypt/2, stream_decrypt/2]).
+-export([public_encrypt/4, private_decrypt/4]).
+-export([private_encrypt/4, public_decrypt/4]).
+
+-export([dh_generate_parameters/2, dh_check/1]). %% Testing see
+
+%% DEPRECATED
+%% Replaced by hash_*
-export([md4/1, md4_init/0, md4_update/2, md4_final/1]).
-export([md5/1, md5_init/0, md5_update/2, md5_final/1]).
-export([sha/1, sha_init/0, sha_update/2, sha_final/1]).
--export([sha224/1, sha224_init/0, sha224_update/2, sha224_final/1]).
--export([sha256/1, sha256_init/0, sha256_update/2, sha256_final/1]).
--export([sha384/1, sha384_init/0, sha384_update/2, sha384_final/1]).
--export([sha512/1, sha512_init/0, sha512_update/2, sha512_final/1]).
+-deprecated({md4, 1, next_major_release}).
+-deprecated({md5, 1, next_major_release}).
+-deprecated({sha, 1, next_major_release}).
+-deprecated({md4_init, 0, next_major_release}).
+-deprecated({md5_init, 0, next_major_release}).
+-deprecated({sha_init, 0, next_major_release}).
+-deprecated({md4_update, 2, next_major_release}).
+-deprecated({md5_update, 2, next_major_release}).
+-deprecated({sha_update, 2, next_major_release}).
+-deprecated({md4_final, 1, next_major_release}).
+-deprecated({md5_final, 1, next_major_release}).
+-deprecated({sha_final, 1, next_major_release}).
+
+%% Replaced by hmac_*
-export([md5_mac/2, md5_mac_96/2, sha_mac/2, sha_mac/3, sha_mac_96/2]).
--export([sha224_mac/2, sha224_mac/3]).
--export([sha256_mac/2, sha256_mac/3]).
--export([sha384_mac/2, sha384_mac/3]).
--export([sha512_mac/2, sha512_mac/3]).
--export([hmac/3, hmac/4, hmac_init/2, hmac_update/2, hmac_final/1, hmac_final_n/2]).
+-deprecated({md5_mac, 2, next_major_release}).
+-deprecated({md5_mac_96, 2, next_major_release}).
+-deprecated({sha_mac, 2, next_major_release}).
+-deprecated({sha_mac, 3, next_major_release}).
+-deprecated({sha_mac_96, 2, next_major_release}).
+
+%% Replaced by sign/verify
+-export([dss_verify/3, dss_verify/4, rsa_verify/3, rsa_verify/4]).
+-export([dss_sign/2, dss_sign/3, rsa_sign/2, rsa_sign/3]).
+-deprecated({dss_verify, 3, next_major_release}).
+-deprecated({dss_verify, 4, next_major_release}).
+-deprecated({rsa_verify, 3, next_major_release}).
+-deprecated({rsa_verify, 4, next_major_release}).
+-deprecated({dss_sign, 2, next_major_release}).
+-deprecated({dss_sign, 3, next_major_release}).
+-deprecated({rsa_sign, 2, next_major_release}).
+-deprecated({rsa_sign, 3, next_major_release}).
+
+%% Replaced by generate_key
+-export([dh_generate_key/1, dh_generate_key/2, dh_compute_key/3]).
+-deprecated({dh_generate_key, 1, next_major_release}).
+-deprecated({dh_generate_key, 2, next_major_release}).
+-deprecated({dh_compute_key, 3, next_major_release}).
+
+%% Replaced by mod_exp_prim and no longer needed
+-export([mod_exp/3, mpint/1, erlint/1, strong_rand_mpint/3]).
+-deprecated({mod_exp, 3, next_major_release}).
+-deprecated({mpint, 1, next_major_release}).
+-deprecated({erlint, 1, next_major_release}).
+-deprecated({strong_rand_mpint, 3, next_major_release}).
+
+%% Replaced by block_*
-export([des_cbc_encrypt/3, des_cbc_decrypt/3, des_cbc_ivec/1]).
+-export([des3_cbc_encrypt/5, des3_cbc_decrypt/5]).
-export([des_ecb_encrypt/2, des_ecb_decrypt/2]).
+-export([des_ede3_cbc_encrypt/5, des_ede3_cbc_decrypt/5]).
-export([des_cfb_encrypt/3, des_cfb_decrypt/3, des_cfb_ivec/2]).
--export([des3_cbc_encrypt/5, des3_cbc_decrypt/5]).
-export([des3_cfb_encrypt/5, des3_cfb_decrypt/5]).
+-deprecated({des_cbc_encrypt, 3, next_major_release}).
+-deprecated({des_cbc_decrypt, 3, next_major_release}).
+-deprecated({des_cbc_ivec, 1, next_major_release}).
+-deprecated({des3_cbc_encrypt, 5, next_major_release}).
+-deprecated({des3_cbc_decrypt, 5, next_major_release}).
+-deprecated({des_ecb_encrypt, 2, next_major_release}).
+-deprecated({des_ecb_decrypt, 2, next_major_release}).
+-deprecated({des_ede3_cbc_encrypt, 5, next_major_release}).
+-deprecated({des_ede3_cbc_decrypt, 5, next_major_release}).
+-deprecated({des_cfb_encrypt, 3, next_major_release}).
+-deprecated({des_cfb_decrypt, 3, next_major_release}).
+-deprecated({des_cfb_ivec, 2, next_major_release}).
+-deprecated({des3_cfb_encrypt, 5, next_major_release}).
+-deprecated({des3_cfb_decrypt, 5, next_major_release}).
-export([blowfish_ecb_encrypt/2, blowfish_ecb_decrypt/2]).
-export([blowfish_cbc_encrypt/3, blowfish_cbc_decrypt/3]).
-export([blowfish_cfb64_encrypt/3, blowfish_cfb64_decrypt/3]).
-export([blowfish_ofb64_encrypt/3]).
--export([des_ede3_cbc_encrypt/5, des_ede3_cbc_decrypt/5]).
+-deprecated({blowfish_ecb_encrypt, 2, next_major_release}).
+-deprecated({blowfish_ecb_decrypt, 2, next_major_release}).
+-deprecated({blowfish_cbc_encrypt, 3, next_major_release}).
+-deprecated({blowfish_cbc_decrypt, 3, next_major_release}).
+-deprecated({blowfish_cfb64_encrypt, 3, next_major_release}).
+-deprecated({blowfish_cfb64_decrypt, 3, next_major_release}).
+-deprecated({blowfish_ofb64_encrypt, 3, next_major_release}).
-export([aes_cfb_128_encrypt/3, aes_cfb_128_decrypt/3]).
--export([exor/2]).
--export([rc4_encrypt/2, rc4_set_key/1, rc4_encrypt_with_state/2]).
--export([rc2_cbc_encrypt/3, rc2_cbc_decrypt/3, rc2_40_cbc_encrypt/3, rc2_40_cbc_decrypt/3]).
--export([dss_verify/3, dss_verify/4, rsa_verify/3, rsa_verify/4]).
--export([dss_sign/2, dss_sign/3, rsa_sign/2, rsa_sign/3]).
--export([rsa_public_encrypt/3, rsa_private_decrypt/3]).
--export([rsa_private_encrypt/3, rsa_public_decrypt/3]).
--export([dh_generate_key/1, dh_generate_key/2, dh_compute_key/3]).
--export([rand_bytes/1, rand_bytes/3, rand_uniform/2]).
--export([strong_rand_bytes/1, strong_rand_mpint/3]).
--export([mod_exp/3, mod_exp_prime/3, mpint/1, erlint/1]).
--export([srp_generate_key/4, srp_generate_key/3,
- srp_generate_key/5, srp_compute_key/6, srp_compute_key/7, srp_compute_key/8]).
-
-%% -export([idea_cbc_encrypt/3, idea_cbc_decrypt/3]).
-export([aes_cbc_128_encrypt/3, aes_cbc_128_decrypt/3]).
-export([aes_cbc_256_encrypt/3, aes_cbc_256_decrypt/3]).
-export([aes_cbc_ivec/1]).
--export([aes_ctr_encrypt/3, aes_ctr_decrypt/3]).
+-deprecated({aes_cfb_128_encrypt, 3, next_major_release}).
+-deprecated({aes_cfb_128_decrypt, 3, next_major_release}).
+-deprecated({aes_cbc_128_encrypt, 3, next_major_release}).
+-deprecated({aes_cbc_128_decrypt, 3, next_major_release}).
+-deprecated({aes_cbc_256_encrypt, 3, next_major_release}).
+-deprecated({aes_cbc_256_decrypt, 3, next_major_release}).
+-deprecated({aes_cbc_ivec, 1, next_major_release}).
+-export([rc2_cbc_encrypt/3, rc2_cbc_decrypt/3]).
+-export([rc2_40_cbc_encrypt/3, rc2_40_cbc_decrypt/3]).
+-deprecated({rc2_cbc_encrypt, 3, next_major_release}).
+-deprecated({rc2_cbc_decrypt, 3, next_major_release}).
+%% allready replaced by above!
+-deprecated({rc2_40_cbc_encrypt, 3, next_major_release}).
+-deprecated({rc2_40_cbc_decrypt, 3, next_major_release}).
+
+%% Replaced by stream_*
-export([aes_ctr_stream_init/2, aes_ctr_stream_encrypt/2, aes_ctr_stream_decrypt/2]).
-
--export([dh_generate_parameters/2, dh_check/1]). %% Testing see below
-
-
--define(FUNC_LIST, [md4, md4_init, md4_update, md4_final,
+-export([rc4_set_key/1, rc4_encrypt_with_state/2]).
+-deprecated({aes_ctr_stream_init, 2, next_major_release}).
+-deprecated({aes_ctr_stream_encrypt, 2, next_major_release}).
+-deprecated({aes_ctr_stream_decrypt, 2, next_major_release}).
+-deprecated({rc4_set_key, 1, next_major_release}).
+-deprecated({rc4_encrypt_with_state, 2, next_major_release}).
+
+%% Not needed special case of stream_*
+-export([aes_ctr_encrypt/3, aes_ctr_decrypt/3, rc4_encrypt/2]).
+-deprecated({aes_ctr_encrypt, 3, next_major_release}).
+-deprecated({aes_ctr_decrypt, 3, next_major_release}).
+-deprecated({rc4_encrypt, 2, next_major_release}).
+
+%% Replace by public/private_encrypt/decrypt
+-export([rsa_public_encrypt/3, rsa_private_decrypt/3]).
+-export([rsa_private_encrypt/3, rsa_public_decrypt/3]).
+-deprecated({rsa_public_encrypt, 3, next_major_release}).
+-deprecated({rsa_private_decrypt, 3, next_major_release}).
+-deprecated({rsa_public_decrypt, 3, next_major_release}).
+-deprecated({rsa_private_encrypt, 3, next_major_release}).
+
+%% Replaced by crypto:module_info()
+-export([info/0]).
+-deprecated({info, 0, next_major_release}).
+
+-define(FUNC_LIST, [hash, hash_init, hash_update, hash_final,
+ hmac, hmac_init, hmac_update, hmac_final, hmac_final_n,
+ %% deprecated
+ md4, md4_init, md4_update, md4_final,
md5, md5_init, md5_update, md5_final,
sha, sha_init, sha_update, sha_final,
- sha224, sha224_init, sha224_update, sha224_final,
- sha256, sha256_init, sha256_update, sha256_final,
- sha384, sha384_init, sha384_update, sha384_final,
- sha512, sha512_init, sha512_update, sha512_final,
md5_mac, md5_mac_96,
sha_mac, sha_mac_96,
- sha224_mac, sha256_mac, sha384_mac, sha512_mac,
+ %%
+ block_encrypt, block_decrypt,
+ %% deprecated
des_cbc_encrypt, des_cbc_decrypt,
des_cfb_encrypt, des_cfb_decrypt,
des_ecb_encrypt, des_ecb_decrypt,
des3_cbc_encrypt, des3_cbc_decrypt,
des3_cfb_encrypt, des3_cfb_decrypt,
aes_cfb_128_encrypt, aes_cfb_128_decrypt,
+ rc2_cbc_encrypt, rc2_cbc_decrypt,
+ rc2_40_cbc_encrypt, rc2_40_cbc_decrypt,
+ aes_cbc_128_encrypt, aes_cbc_128_decrypt,
+ aes_cbc_256_encrypt, aes_cbc_256_decrypt,
+ blowfish_cbc_encrypt, blowfish_cbc_decrypt,
+ blowfish_cfb64_encrypt, blowfish_cfb64_decrypt,
+ blowfish_ecb_encrypt, blowfish_ecb_decrypt, blowfish_ofb64_encrypt,
+ %%
rand_bytes,
strong_rand_bytes,
- strong_rand_mpint,
rand_uniform,
- mod_exp, mod_exp_prime,
+ mod_pow,
+ exor,
+ %% deprecated
+ mod_exp,strong_rand_mpint,erlint, mpint,
+ %%
+ sign, verify, generate_key, compute_key,
+ %% deprecated
dss_verify,dss_sign,
rsa_verify,rsa_sign,
rsa_public_encrypt,rsa_private_decrypt,
rsa_private_encrypt,rsa_public_decrypt,
dh_generate_key, dh_compute_key,
- aes_cbc_128_encrypt, aes_cbc_128_decrypt,
- exor,
+ %%
+ stream_init, stream_encrypt, stream_decrypt,
+ %% deprecated
rc4_encrypt, rc4_set_key, rc4_encrypt_with_state,
- rc2_40_cbc_encrypt, rc2_40_cbc_decrypt,
- %% idea_cbc_encrypt, idea_cbc_decrypt,
- aes_cbc_256_encrypt, aes_cbc_256_decrypt,
aes_ctr_encrypt, aes_ctr_decrypt,
aes_ctr_stream_init, aes_ctr_stream_encrypt, aes_ctr_stream_decrypt,
- aes_cbc_ivec, blowfish_cbc_encrypt, blowfish_cbc_decrypt,
- blowfish_cfb64_encrypt, blowfish_cfb64_decrypt,
- blowfish_ecb_encrypt, blowfish_ecb_decrypt, blowfish_ofb64_encrypt,
- des_cbc_ivec, des_cfb_ivec, erlint, mpint,
- hash, hash_init, hash_update, hash_final,
- hmac, hmac_init, hmac_update, hmac_final, hmac_final_n, info,
- rc2_cbc_encrypt, rc2_cbc_decrypt,
- srp_generate_key, srp_compute_key,
+ %%
+ next_iv,
+ %% deprecated
+ aes_cbc_ivec,
+ des_cbc_ivec, des_cfb_ivec,
+ info,
+ %%
info_lib, algorithms]).
+-type mpint() :: binary().
-type rsa_digest_type() :: 'md5' | 'sha' | 'sha224' | 'sha256' | 'sha384' | 'sha512'.
-type dss_digest_type() :: 'none' | 'sha'.
+%%-type ecdsa_digest_type() :: 'md5' | 'sha' | 'sha256' | 'sha384' | 'sha512'.
-type data_or_digest() :: binary() | {digest, binary()}.
-type crypto_integer() :: binary() | integer().
+-type ec_key_res() :: any(). %% nif resource
+-type ec_named_curve() :: atom().
+-type ec_point() :: crypto_integer().
+-type ec_basis() :: {tpbasis, K :: non_neg_integer()} | {ppbasis, K1 :: non_neg_integer(), K2 :: non_neg_integer(), K3 :: non_neg_integer()} | onbasis.
+-type ec_field() :: {prime_field, Prime :: integer()} | {characteristic_two_field, M :: integer(), Basis :: ec_basis()}.
+-type ec_prime() :: {A :: crypto_integer(), B :: crypto_integer(), Seed :: binary() | none}.
+-type ec_curve_spec() :: {Field :: ec_field(), Prime :: ec_prime(), Point :: crypto_integer(), Order :: integer(), CoFactor :: none | integer()}.
+-type ec_curve() :: ec_named_curve() | ec_curve_spec().
+-type ec_key() :: {Curve :: ec_curve(), PrivKey :: binary() | undefined, PubKey :: ec_point() | undefined}.
-define(nif_stub,nif_stub_error(?LINE)).
@@ -565,6 +681,110 @@ sha512_mac(Key, Data, MacSz) ->
sha512_mac_nif(_Key,_Data,_MacSz) -> ?nif_stub.
+
+%% Ecrypt/decrypt %%%
+
+-spec block_encrypt(des_cbc | des_cfb | des3_cbc | des3_cbf | des_ede3 | blowfish_cbc |
+ blowfish_cfb64 | aes_cbc128 | aes_cfb128 | aes_cbc256 | rc2_cbc,
+ Key::iodata(), Ivec::binary(), Data::iodata()) -> binary().
+
+block_encrypt(des_cbc, Key, Ivec, Data) ->
+ des_cbc_encrypt(Key, Ivec, Data);
+block_encrypt(des_cfb, Key, Ivec, Data) ->
+ des_cfb_encrypt(Key, Ivec, Data);
+block_encrypt(des3_cbc, [Key1, Key2, Key3], Ivec, Data) ->
+ des3_cbc_encrypt(Key1, Key2, Key3, Ivec, Data);
+block_encrypt(des3_cbf, [Key1, Key2, Key3], Ivec, Data) ->
+ des3_cfb_encrypt(Key1, Key2, Key3, Ivec, Data);
+block_encrypt(des_ede3, [Key1, Key2, Key3], Ivec, Data) ->
+ des_ede3_cbc_encrypt(Key1, Key2, Key3, Ivec, Data);
+block_encrypt(blowfish_cbc, Key, Ivec, Data) ->
+ blowfish_cbc_encrypt(Key, Ivec, Data);
+block_encrypt(blowfish_cfb64, Key, Ivec, Data) ->
+ blowfish_cfb64_encrypt(Key, Ivec, Data);
+block_encrypt(blowfish_ofb64, Key, Ivec, Data) ->
+ blowfish_ofb64_encrypt(Key, Ivec, Data);
+block_encrypt(aes_cbc128, Key, Ivec, Data) ->
+ aes_cbc_128_encrypt(Key, Ivec, Data);
+block_encrypt(aes_cbc256, Key, Ivec, Data) ->
+ aes_cbc_256_encrypt(Key, Ivec, Data);
+block_encrypt(aes_cfb128, Key, Ivec, Data) ->
+ aes_cfb_128_encrypt(Key, Ivec, Data);
+block_encrypt(rc2_cbc, Key, Ivec, Data) ->
+ rc2_cbc_encrypt(Key, Ivec, Data).
+
+-spec block_decrypt(des_cbc | des_cfb | des3_cbc | des3_cbf | des_ede3 | blowfish_cbc |
+ blowfish_cfb64 | blowfish_ofb64 | aes_cbc128 | aes_cbc256 | aes_cfb128 | rc2_cbc,
+ Key::iodata(), Ivec::binary(), Data::iodata()) -> binary().
+
+block_decrypt(des_cbc, Key, Ivec, Data) ->
+ des_cbc_decrypt(Key, Ivec, Data);
+block_decrypt(des_cfb, Key, Ivec, Data) ->
+ des_cfb_decrypt(Key, Ivec, Data);
+block_decrypt(des3_cbc, [Key1, Key2, Key3], Ivec, Data) ->
+ des3_cbc_decrypt(Key1, Key2, Key3, Ivec, Data);
+block_decrypt(des3_cbf, [Key1, Key2, Key3], Ivec, Data) ->
+ des3_cfb_decrypt(Key1, Key2, Key3, Ivec, Data);
+block_decrypt(des_ede3, [Key1, Key2, Key3], Ivec, Data) ->
+ des_ede3_cbc_decrypt(Key1, Key2, Key3, Ivec, Data);
+block_decrypt(blowfish_cbc, Key, Ivec, Data) ->
+ blowfish_cbc_decrypt(Key, Ivec, Data);
+block_decrypt(blowfish_cfb64, Key, Ivec, Data) ->
+ blowfish_cfb64_decrypt(Key, Ivec, Data);
+block_decrypt(blowfish_ofb, Key, Ivec, Data) ->
+ blowfish_ofb64_decrypt(Key, Ivec, Data);
+block_decrypt(aes_cbc128, Key, Ivec, Data) ->
+ aes_cbc_128_decrypt(Key, Ivec, Data);
+block_decrypt(aes_cbc256, Key, Ivec, Data) ->
+ aes_cbc_256_decrypt(Key, Ivec, Data);
+block_decrypt(aes_cfb128, Key, Ivec, Data) ->
+ aes_cfb_128_decrypt(Key, Ivec, Data);
+block_decrypt(rc2_cbc, Key, Ivec, Data) ->
+ rc2_cbc_decrypt(Key, Ivec, Data).
+
+-spec block_encrypt(des_ecb | blowfish_ecb, Key::iodata(), Data::iodata()) -> binary().
+
+block_encrypt(des_ecb, Key, Data) ->
+ des_ecb_encrypt(Key, Data);
+block_encrypt(blowfish_ecb, Key, Data) ->
+ blowfish_ecb_encrypt(Key, Data).
+
+-spec block_decrypt(des_ecb | blowfish_ecb, Key::iodata(), Data::iodata()) -> binary().
+
+block_decrypt(des_ecb, Key, Data) ->
+ des_ecb_decrypt(Key, Data);
+block_decrypt(blowfish_ecb, Key, Data) ->
+ blowfish_ecb_decrypt(Key, Data).
+
+-spec next_iv(des_cbc | aes_cbc, Data::iodata()) -> binary().
+
+next_iv(des_cbc, Data) ->
+ des_cbc_ivec(Data);
+next_iv(aes_cbc, Data) ->
+ aes_cbc_ivec(Data).
+
+-spec next_iv(des_cbf, Ivec::binary(), Data::iodata()) -> binary().
+
+next_iv(des_cbf, Ivec, Data) ->
+ des_cfb_ivec(Ivec, Data).
+
+stream_init(aes_ctr, Key, Ivec) ->
+ {aes_ctr, aes_ctr_stream_init(Key, Ivec)}.
+stream_init(rc4, Key) ->
+ {rc4, rc4_set_key(Key)}.
+stream_encrypt({aes_ctr, State}, Data) ->
+ {State, Cipher} = aes_ctr_stream_encrypt(State, Data),
+ {{aes_ctr, State}, Cipher};
+stream_encrypt({rc4, State0}, Data) ->
+ {State, Cipher} = rc4_encrypt_with_state(State0, Data),
+ {{rc4, State}, Cipher}.
+stream_decrypt({aes_ctr, State0}, Data) ->
+ {State, Text} = aes_ctr_stream_decrypt(State0, Data),
+ {{aes_ctr, State}, Text};
+stream_decrypt({rc4, State0}, Data) ->
+ {State, Text} = rc4_encrypt_with_state (State0, Data),
+ {{rc4, State}, Text}.
+
%%
%% CRYPTO FUNCTIONS
%%
@@ -713,8 +933,12 @@ blowfish_cfb64_decrypt(Key, IVec, Data) ->
bf_cfb64_crypt(_Key, _IVec, _Data, _IsEncrypt) -> ?nif_stub.
+blowfish_ofb64_decrypt(Key, Ivec, Data) ->
+ blowfish_ofb64_encrypt(Key, Ivec, Data).
+
blowfish_ofb64_encrypt(_Key, _IVec, _Data) -> ?nif_stub.
+
%%
%% AES in cipher feedback mode (CFB)
%%
@@ -798,9 +1022,9 @@ mod_exp(Base, Exponent, Modulo)
mod_exp(Base, Exponent, Modulo) ->
mod_exp_nif(mpint_to_bin(Base),mpint_to_bin(Exponent),mpint_to_bin(Modulo), 4).
--spec mod_exp_prime(binary(), binary(), binary()) -> binary() | error.
-mod_exp_prime(Base, Exponent, Prime) ->
- case mod_exp_nif(Base, Exponent, Prime, 0) of
+-spec mod_pow(binary()|integer(), binary()|integer(), binary()|integer()) -> binary() | error.
+mod_pow(Base, Exponent, Prime) ->
+ case mod_exp_nif(ensure_int_as_bin(Base), ensure_int_as_bin(Exponent), ensure_int_as_bin(Prime), 0) of
<<0>> -> error;
R -> R
end.
@@ -819,19 +1043,40 @@ mod_exp_nif(_Base,_Exp,_Mod,_bin_hdr) -> ?nif_stub.
%% Key = [P,Q,G,Y] P,Q,G=DSSParams Y=PublicKey
dss_verify(Data,Signature,Key) ->
- dss_verify(sha, Data, Signature, Key).
-dss_verify(_Type,_Data,_Signature,_Key) -> ?nif_stub.
+ dss_verify(sha, Data, Signature, Key).
+
+dss_verify(Type,Data,Signature,Key) when is_binary(Data), Type=/=none ->
+ verify(dss,Type,mpint_to_bin(Data),mpint_to_bin(Signature),map_mpint_to_bin(Key));
+dss_verify(Type,Digest,Signature,Key) ->
+ verify(dss,Type,Digest,mpint_to_bin(Signature),map_mpint_to_bin(Key)).
% Key = [E,N] E=PublicExponent N=PublicModulus
rsa_verify(Data,Signature,Key) ->
- rsa_verify_nif(sha, Data,Signature,Key).
-rsa_verify(Type, DataOrDigest, Signature, Key) ->
- case rsa_verify_nif(Type, DataOrDigest, Signature, Key) of
+ rsa_verify(sha, Data,Signature,Key).
+rsa_verify(Type, Data, Signature, Key) when is_binary(Data) ->
+ verify(rsa, Type, mpint_to_bin(Data), mpint_to_bin(Signature), map_mpint_to_bin(Key));
+rsa_verify(Type, Digest, Signature, Key) ->
+ verify(rsa, Type, Digest, mpint_to_bin(Signature), map_mpint_to_bin(Key)).
+
+
+verify(dss, Type, Data, Signature, Key) ->
+ dss_verify_nif(Type, Data, Signature, map_ensure_int_as_bin(Key));
+
+verify(rsa, Type, DataOrDigest, Signature, Key) ->
+ case rsa_verify_nif(Type, DataOrDigest, Signature, map_ensure_int_as_bin(Key)) of
notsup -> erlang:error(notsup);
Bool -> Bool
+ end;
+verify(ecdsa, Type, DataOrDigest, Signature, [Key, Curve]) ->
+ case ecdsa_verify_nif(Type, DataOrDigest, Signature, term_to_ec_key({Curve, undefined, Key})) of
+ notsup -> erlang:error(notsup);
+ Bool -> Bool
end.
+
+dss_verify_nif(_Type, _Data, _Signature, _Key) -> ?nif_stub.
rsa_verify_nif(_Type, _Data, _Signature, _Key) -> ?nif_stub.
+ecdsa_verify_nif(_Type, _DataOrDigest, _Signature, _Key) -> ?nif_stub.
%%
@@ -845,24 +1090,103 @@ rsa_verify_nif(_Type, _Data, _Signature, _Key) -> ?nif_stub.
dss_sign(DataOrDigest,Key) ->
dss_sign(sha,DataOrDigest,Key).
-dss_sign(Type, DataOrDigest, Key) ->
- case dss_sign_nif(Type,DataOrDigest,Key) of
- error -> erlang:error(badkey, [DataOrDigest, Key]);
- Sign -> Sign
- end.
+dss_sign(Type, Data, Key) when is_binary(Data), Type=/=none ->
+ sign(dss, Type, mpint_to_bin(Data), map_mpint_to_bin(Key));
+dss_sign(Type, Digest, Key) ->
+ sign(dss, Type, Digest, map_mpint_to_bin(Key)).
-dss_sign_nif(_Type,_Data,_Key) -> ?nif_stub.
%% Key = [E,N,D] E=PublicExponent N=PublicModulus D=PrivateExponent
rsa_sign(DataOrDigest,Key) ->
rsa_sign(sha, DataOrDigest, Key).
-rsa_sign(Type, DataOrDigest, Key) ->
- case rsa_sign_nif(Type,DataOrDigest,Key) of
+
+rsa_sign(Type, Data, Key) when is_binary(Data) ->
+ sign(rsa, Type, mpint_to_bin(Data), map_mpint_to_bin(Key));
+rsa_sign(Type, Digest, Key) ->
+ sign(rsa, Type, Digest, map_mpint_to_bin(Key)).
+
+map_mpint_to_bin(List) ->
+ lists:map(fun(E) -> mpint_to_bin(E) end, List ).
+
+map_ensure_int_as_bin([H|_]=List) when is_integer(H) ->
+ lists:map(fun(E) -> int_to_bin(E) end, List);
+map_ensure_int_as_bin(List) ->
+ List.
+
+ensure_int_as_bin(Int) when is_integer(Int) ->
+ int_to_bin(Int);
+ensure_int_as_bin(Bin) ->
+ Bin.
+
+map_to_norm_bin([H|_]=List) when is_integer(H) ->
+ lists:map(fun(E) -> int_to_bin(E) end, List);
+map_to_norm_bin(List) ->
+ lists:map(fun(E) -> mpint_to_bin(E) end, List).
+
+
+sign(rsa, Type, DataOrDigest, Key) ->
+ case rsa_sign_nif(Type, DataOrDigest, map_ensure_int_as_bin(Key)) of
+ error -> erlang:error(badkey, [Type,DataOrDigest,Key]);
+ Sign -> Sign
+ end;
+sign(dss, Type, DataOrDigest, Key) ->
+ case dss_sign_nif(Type, DataOrDigest, map_ensure_int_as_bin(Key)) of
+ error -> erlang:error(badkey, [DataOrDigest, Key]);
+ Sign -> Sign
+ end;
+sign(ecdsa, Type, DataOrDigest, [Key, Curve]) ->
+ case ecdsa_sign_nif(Type, DataOrDigest, term_to_ec_key({Curve, Key, undefined})) of
error -> erlang:error(badkey, [Type,DataOrDigest,Key]);
Sign -> Sign
end.
rsa_sign_nif(_Type,_Data,_Key) -> ?nif_stub.
+dss_sign_nif(_Type,_Data,_Key) -> ?nif_stub.
+ecdsa_sign_nif(_Type, _DataOrDigest, _Key) -> ?nif_stub.
+
+
+
+
+-spec public_encrypt(rsa, binary(), [binary()], rsa_padding()) ->
+ binary().
+-spec public_decrypt(rsa, binary(), [integer() | binary()], rsa_padding()) ->
+ binary().
+-spec private_encrypt(rsa, binary(), [integer() | binary()], rsa_padding()) ->
+ binary().
+-spec private_decrypt(rsa, binary(), [integer() | binary()], rsa_padding()) ->
+ binary().
+
+public_encrypt(rsa, BinMesg, Key, Padding) ->
+ case rsa_public_crypt(BinMesg, map_ensure_int_as_bin(Key), Padding, true) of
+ error ->
+ erlang:error(encrypt_failed, [BinMesg,Key, Padding]);
+ Sign -> Sign
+ end.
+
+%% Binary, Key = [E,N,D]
+private_decrypt(rsa, BinMesg, Key, Padding) ->
+ case rsa_private_crypt(BinMesg, map_ensure_int_as_bin(Key), Padding, false) of
+ error ->
+ erlang:error(decrypt_failed, [BinMesg,Key, Padding]);
+ Sign -> Sign
+ end.
+
+
+%% Binary, Key = [E,N,D]
+private_encrypt(rsa, BinMesg, Key, Padding) ->
+ case rsa_private_crypt(BinMesg, map_ensure_int_as_bin(Key), Padding, true) of
+ error ->
+ erlang:error(encrypt_failed, [BinMesg,Key, Padding]);
+ Sign -> Sign
+ end.
+
+%% Binary, Key = [E,N]
+public_decrypt(rsa, BinMesg, Key, Padding) ->
+ case rsa_public_crypt(BinMesg, map_ensure_int_as_bin(Key), Padding, false) of
+ error ->
+ erlang:error(decrypt_failed, [BinMesg,Key, Padding]);
+ Sign -> Sign
+ end.
%%
@@ -872,16 +1196,16 @@ rsa_sign_nif(_Type,_Data,_Key) -> ?nif_stub.
-spec rsa_public_encrypt(binary(), [binary()], rsa_padding()) ->
binary().
--spec rsa_public_decrypt(binary(), [binary()], rsa_padding()) ->
+-spec rsa_public_decrypt(binary(), [integer() | mpint()], rsa_padding()) ->
binary().
--spec rsa_private_encrypt(binary(), [binary()], rsa_padding()) ->
+-spec rsa_private_encrypt(binary(), [integer() | mpint()], rsa_padding()) ->
binary().
--spec rsa_private_decrypt(binary(), [binary()], rsa_padding()) ->
+-spec rsa_private_decrypt(binary(), [integer() | mpint()], rsa_padding()) ->
binary().
%% Binary, Key = [E,N]
rsa_public_encrypt(BinMesg, Key, Padding) ->
- case rsa_public_crypt(BinMesg, Key, Padding, true) of
+ case rsa_public_crypt(BinMesg, map_to_norm_bin(Key), Padding, true) of
error ->
erlang:error(encrypt_failed, [BinMesg,Key, Padding]);
Sign -> Sign
@@ -891,7 +1215,7 @@ rsa_public_crypt(_BinMsg, _Key, _Padding, _IsEncrypt) -> ?nif_stub.
%% Binary, Key = [E,N,D]
rsa_private_decrypt(BinMesg, Key, Padding) ->
- case rsa_private_crypt(BinMesg, Key, Padding, false) of
+ case rsa_private_crypt(BinMesg, map_to_norm_bin(Key), Padding, false) of
error ->
erlang:error(decrypt_failed, [BinMesg,Key, Padding]);
Sign -> Sign
@@ -902,7 +1226,7 @@ rsa_private_crypt(_BinMsg, _Key, _Padding, _IsEncrypt) -> ?nif_stub.
%% Binary, Key = [E,N,D]
rsa_private_encrypt(BinMesg, Key, Padding) ->
- case rsa_private_crypt(BinMesg, Key, Padding, true) of
+ case rsa_private_crypt(BinMesg, map_to_norm_bin(Key), Padding, true) of
error ->
erlang:error(encrypt_failed, [BinMesg,Key, Padding]);
Sign -> Sign
@@ -910,7 +1234,7 @@ rsa_private_encrypt(BinMesg, Key, Padding) ->
%% Binary, Key = [E,N]
rsa_public_decrypt(BinMesg, Key, Padding) ->
- case rsa_public_crypt(BinMesg, Key, Padding, false) of
+ case rsa_public_crypt(BinMesg, map_to_norm_bin(Key), Padding, false) of
error ->
erlang:error(decrypt_failed, [BinMesg,Key, Padding]);
Sign -> Sign
@@ -1052,120 +1376,142 @@ dh_check([_Prime,_Gen]) -> ?nif_stub.
{binary(),binary()}.
dh_generate_key(DHParameters) ->
- dh_generate_key(undefined, DHParameters).
+ dh_generate_key_nif(undefined, map_mpint_to_bin(DHParameters), 4).
dh_generate_key(PrivateKey, DHParameters) ->
- case dh_generate_key_nif(PrivateKey, DHParameters) of
- error -> erlang:error(generation_failed, [PrivateKey,DHParameters]);
- Res -> Res
- end.
+ dh_generate_key_nif(mpint_to_bin(PrivateKey), map_mpint_to_bin(DHParameters), 4).
-dh_generate_key_nif(_PrivateKey, _DHParameters) -> ?nif_stub.
+dh_generate_key_nif(_PrivateKey, _DHParameters, _Mpint) -> ?nif_stub.
%% DHParameters = [P (Prime)= mpint(), G(Generator) = mpint()]
-%% MyPrivKey, OthersPublicKey = mpint()
+%% MyPrivKey, OthersPublicKey = mpint()
-spec dh_compute_key(binary(), binary(), [binary()]) -> binary().
dh_compute_key(OthersPublicKey, MyPrivateKey, DHParameters) ->
- case dh_compute_key_nif(OthersPublicKey,MyPrivateKey,DHParameters) of
- error -> erlang:error(computation_failed, [OthersPublicKey,MyPrivateKey,DHParameters]);
- Ret -> Ret
- end.
+ compute_key(dh, mpint_to_bin(OthersPublicKey), mpint_to_bin(MyPrivateKey),
+ map_mpint_to_bin(DHParameters)).
+
dh_compute_key_nif(_OthersPublicKey, _MyPrivateKey, _DHParameters) -> ?nif_stub.
+generate_key(Type, Params) ->
+ generate_key(Type, Params, undefined).
+
+generate_key(dh, DHParameters, PrivateKey) ->
+ dh_generate_key_nif(PrivateKey, map_ensure_int_as_bin(DHParameters), 0);
+
+generate_key(srp, {host, [Verifier, Generator, Prime, Version]}, PrivArg)
+ when is_binary(Verifier), is_binary(Generator), is_binary(Prime), is_atom(Version) ->
+ Private = case PrivArg of
+ undefined -> random_bytes(32);
+ _ -> PrivArg
+ end,
+ host_srp_gen_key(Private, Verifier, Generator, Prime, Version);
+
+generate_key(srp, {user, [Generator, Prime, Version]}, PrivateArg)
+ when is_binary(Generator), is_binary(Prime), is_atom(Version) ->
+ Private = case PrivateArg of
+ undefined -> random_bytes(32);
+ _ -> PrivateArg
+ end,
+ user_srp_gen_key(Private, Generator, Prime);
-%%% SRP
--spec srp_generate_key(binary(), binary(), atom() | binary(), atom() | binary() ) -> {Public::binary(), Private::binary()}.
-srp_generate_key(Verifier, Generator, Prime, Version) when is_binary(Verifier),
- is_binary(Generator),
- is_binary(Prime),
- is_atom(Version) ->
- Private = random_bytes(32),
- server_srp_gen_key(Private, Verifier, Generator, Prime, Version);
-
-srp_generate_key(Generator, Prime, Version, Private) when is_binary(Generator),
- is_binary(Prime),
- is_atom(Version),
- is_binary(Private) ->
- client_srp_gen_key(Private, Generator, Prime).
-
--spec srp_generate_key(binary(), binary(), binary(), atom(), binary()) -> {Public::binary(), Private::binary()}.
-srp_generate_key(Verifier, Generator, Prime, Version, Private) when is_binary(Verifier),
- is_binary(Generator),
- is_binary(Prime),
- is_atom(Version),
- is_binary(Private)
- ->
- server_srp_gen_key(Private, Verifier, Generator, Prime, Version).
-
--spec srp_generate_key(binary(), binary(), atom()) -> {Public::binary(), Private::binary()}.
-srp_generate_key(Generator, Prime, Version) when is_binary(Generator),
- is_binary(Prime),
- is_atom(Version) ->
- Private = random_bytes(32),
- client_srp_gen_key(Private, Generator, Prime).
-
--spec srp_compute_key(binary(), binary(), binary(), binary(), binary(), atom()| binary(), atom() | binary() ) -> binary().
-srp_compute_key(DerivedKey, Prime, Generator, ClientPublic, ClientPrivate, ServerPublic, Version) when
- is_binary(Prime),
+generate_key(ecdh, Curve, undefined) ->
+ ec_key_to_term(ec_key_generate(Curve)).
+
+
+ec_key_generate(_Key) -> ?nif_stub.
+
+
+compute_key(dh, OthersPublicKey, MyPrivateKey, DHParameters) ->
+ case dh_compute_key_nif(OthersPublicKey,MyPrivateKey, map_ensure_int_as_bin(DHParameters)) of
+ error -> erlang:error(computation_failed,
+ [OthersPublicKey,MyPrivateKey,DHParameters]);
+ Ret -> Ret
+ end;
+
+compute_key(srp, HostPublic, {UserPublic, UserPrivate},
+ {user, [DerivedKey, Prime, Generator, Version | ScramblerArg]}) when
+ is_binary(Prime),
is_binary(Generator),
- is_binary(ClientPublic),
- is_binary(ClientPrivate),
- is_binary(ServerPublic),
+ is_binary(UserPublic),
+ is_binary(UserPrivate),
+ is_binary(HostPublic),
is_atom(Version) ->
Multiplier = srp_multiplier(Version, Generator, Prime),
- Scrambler = srp_scrambler(Version, ClientPublic, ServerPublic, Prime),
- srp_client_secret_nif(ClientPrivate, Scrambler, ServerPublic, Multiplier,
- Generator, DerivedKey, Prime);
-
-srp_compute_key(Verifier, Prime, ClientPublic, ServerPublic, ServerPrivate, Version, Scrambler) when
+ Scrambler = case ScramblerArg of
+ [] -> srp_scrambler(Version, UserPublic, HostPublic, Prime);
+ [S] -> S
+ end,
+ srp_user_secret_nif(UserPrivate, Scrambler, HostPublic, Multiplier,
+ Generator, DerivedKey, Prime);
+
+compute_key(srp, UserPublic, {HostPublic, HostPrivate},
+ {host,[Verifier, Prime, Version | ScramblerArg]}) when
is_binary(Verifier),
- is_binary(Prime),
- is_binary(ClientPublic),
- is_binary(ServerPublic),
- is_binary(ServerPrivate),
- is_atom(Version),
- is_binary(Scrambler) ->
- srp_server_secret_nif(Verifier, ServerPrivate, Scrambler, ClientPublic, Prime).
-
--spec srp_compute_key(binary(), binary(), binary(), binary(), binary(), binary(), atom(), binary()) -> binary().
-srp_compute_key(DerivedKey, Prime, Generator, ClientPublic, ClientPrivate,
- ServerPublic, Version, Scrambler) when is_binary(DerivedKey),
- is_binary(Prime),
- is_binary(Generator),
- is_binary(ClientPublic),
- is_binary(ClientPrivate),
- is_binary(ServerPublic),
- is_atom(Version),
- is_binary(Scrambler) ->
- Multiplier = srp_multiplier(Version, Generator, Prime),
- srp_client_secret_nif(ClientPrivate, Scrambler, ServerPublic, Multiplier,
- Generator, DerivedKey, Prime).
-
--spec srp_compute_key(binary(), binary(), binary(), binary(), binary(), atom()) -> binary().
-srp_compute_key(Verifier, Prime, ClientPublic, ServerPublic, ServerPrivate, Version) when
- is_binary(Verifier),
- is_binary(Prime),
- is_binary(ClientPublic),
- is_binary(ServerPublic),
- is_binary(ServerPrivate),
+ is_binary(Prime),
+ is_binary(UserPublic),
+ is_binary(HostPublic),
+ is_binary(HostPrivate),
is_atom(Version) ->
- Scrambler = srp_scrambler(Version, ClientPublic, ServerPublic, Prime),
- srp_server_secret_nif(Verifier, ServerPrivate, Scrambler, ClientPublic, Prime).
+ Scrambler = case ScramblerArg of
+ [] -> srp_scrambler(Version, UserPublic, HostPublic, Prime);
+ [S] -> S
+ end,
+ srp_host_secret_nif(Verifier, HostPrivate, Scrambler, UserPublic, Prime);
+
+compute_key(ecdh, Others, My, Curve) ->
+ ecdh_compute_key_nif(Others, term_to_ec_key({Curve,My,undefined})).
+
+ecdh_compute_key_nif(_Others, _My) -> ?nif_stub.
+
%%
+%% EC
+%%
+ec_key_to_term(Key) ->
+ case ec_key_to_term_nif(Key) of
+ {PrivKey, PubKey} ->
+ {bin_to_int(PrivKey), PubKey};
+ _ ->
+ erlang:error(conversion_failed)
+ end.
+
+ec_key_to_term_nif(_Key) -> ?nif_stub.
+
+term_to_nif_prime({prime_field, Prime}) ->
+ {prime_field, int_to_bin(Prime)};
+term_to_nif_prime(PrimeField) ->
+ PrimeField.
+term_to_nif_curve({A, B, Seed}) ->
+ {ensure_int_as_bin(A), ensure_int_as_bin(B), Seed}.
+term_to_nif_curve_parameters({PrimeField, Curve, BasePoint, Order, CoFactor}) ->
+ {term_to_nif_prime(PrimeField), term_to_nif_curve(Curve), ensure_int_as_bin(BasePoint), int_to_bin(Order), int_to_bin(CoFactor)};
+term_to_nif_curve_parameters(Curve) when is_atom(Curve) ->
+ %% named curve
+ Curve.
+
+-spec term_to_ec_key(ec_key()) -> ec_key_res().
+term_to_ec_key({Curve, undefined, PubKey}) ->
+ term_to_ec_key_nif(term_to_nif_curve_parameters(Curve), undefined, PubKey);
+term_to_ec_key({Curve, PrivKey, PubKey}) ->
+ term_to_ec_key_nif(term_to_nif_curve_parameters(Curve), int_to_bin(PrivKey), PubKey).
+
+term_to_ec_key_nif(_Curve, _PrivKey, _PubKey) -> ?nif_stub.
+
+
+
%% LOCAL FUNCTIONS
%%
-client_srp_gen_key(Private, Generator, Prime) ->
- case mod_exp_prime(Generator, Private, Prime) of
+user_srp_gen_key(Private, Generator, Prime) ->
+ case mod_pow(Generator, Private, Prime) of
error ->
error;
Public ->
{Public, Private}
end.
-server_srp_gen_key(Private, Verifier, Generator, Prime, Version) ->
+host_srp_gen_key(Private, Verifier, Generator, Prime, Version) ->
Multiplier = srp_multiplier(Version, Generator, Prime),
case srp_value_B_nif(Multiplier, Verifier, Generator, Private, Prime) of
error ->
@@ -1185,17 +1531,17 @@ srp_multiplier('6', _, _) ->
srp_multiplier('3', _, _) ->
<<1/integer>>.
-srp_scrambler(Version, ClientPublic, ServerPublic, Prime) when Version == '6'; Version == '6a'->
+srp_scrambler(Version, UserPublic, HostPublic, Prime) when Version == '6'; Version == '6a'->
%% SHA1(PAD(A) | PAD(B)) from http://srp.stanford.edu/design.html
PadLength = erlang:byte_size(Prime),
C0 = sha_init(),
- C1 = sha_update(C0, srp_pad_to(PadLength, ClientPublic)),
- C2 = sha_update(C1, srp_pad_to(PadLength, ServerPublic)),
+ C1 = sha_update(C0, srp_pad_to(PadLength, UserPublic)),
+ C2 = sha_update(C1, srp_pad_to(PadLength, HostPublic)),
sha_final(C2);
-srp_scrambler('3', _, ServerPublic, _Prime) ->
+srp_scrambler('3', _, HostPublic, _Prime) ->
%% The parameter u is a 32-bit unsigned integer which takes its value
%% from the first 32 bits of the SHA1 hash of B, MSB first.
- <<U:32/bits, _/binary>> = sha(ServerPublic),
+ <<U:32/bits, _/binary>> = sha(HostPublic),
U.
srp_pad_length(Width, Length) ->
@@ -1207,9 +1553,9 @@ srp_pad_to(Width, Binary) ->
N -> << 0:(N*8), Binary/binary>>
end.
-srp_server_secret_nif(_Verifier, _B, _U, _A, _Prime) -> ?nif_stub.
+srp_host_secret_nif(_Verifier, _B, _U, _A, _Prime) -> ?nif_stub.
-srp_client_secret_nif(_A, _U, _B, _Multiplier, _Generator, _Exponent, _Prime) -> ?nif_stub.
+srp_user_secret_nif(_A, _U, _B, _Multiplier, _Generator, _Exponent, _Prime) -> ?nif_stub.
srp_value_B_nif(_Multiplier, _Verifier, _Generator, _Exponent, _Prime) -> ?nif_stub.
@@ -1253,10 +1599,12 @@ int_to_bin_neg(X,Ds) ->
int_to_bin_neg(X bsr 8, [(X band 255)|Ds]).
-bin_to_int(Bin) ->
+bin_to_int(Bin) when is_binary(Bin) ->
Bits = bit_size(Bin),
<<Integer:Bits/integer>> = Bin,
- Integer.
+ Integer;
+bin_to_int(undefined) ->
+ undefined.
%% int from integer in a binary with 32bit length
erlint(<<MPIntSize:32/integer,MPIntValue/binary>>) ->
diff --git a/lib/crypto/test/crypto_SUITE.erl b/lib/crypto/test/crypto_SUITE.erl
index 08ecad3233..eddb6b83f9 100644
--- a/lib/crypto/test/crypto_SUITE.erl
+++ b/lib/crypto/test/crypto_SUITE.erl
@@ -76,6 +76,7 @@
rsa_encrypt_decrypt/1,
dh/1,
srp3/1, srp6/1, srp6a/1,
+ ec/1,
exor_test/1,
rc4_test/1,
rc4_stream_test/1,
@@ -105,7 +106,7 @@ groups() ->
rand_uniform_test, strong_rand_test,
rsa_verify_test, dsa_verify_test, rsa_sign_test,
rsa_sign_hash_test, dsa_sign_test, dsa_sign_hash_test,
- rsa_encrypt_decrypt, dh, srp3, srp6, srp6a, exor_test,
+ rsa_encrypt_decrypt, dh, srp3, srp6, srp6a, ec, exor_test,
rc4_test, rc4_stream_test, mod_exp_test, blowfish_cfb64,
smp]}].
@@ -190,8 +191,8 @@ ldd_program() ->
Ldd when is_list(Ldd) -> Ldd
end.
-%%
-%%
+
+
info(doc) ->
["Call the info function."];
info(suite) ->
@@ -207,10 +208,10 @@ info(Config) when is_list(Config) ->
?line [] = Info -- Exports,
?line NotInInfo = Exports -- Info,
io:format("NotInInfo = ~p\n", [NotInInfo]),
- BlackList = lists:sort([des_ede3_cbc_decrypt, des_ede3_cbc_encrypt,
- dh_check, dh_generate_parameters,
- module_info, start, stop, version]),
- ?line BlackList = NotInInfo,
+ %% BlackList = lists:sort([des_ede3_cbc_decrypt, des_ede3_cbc_encrypt,
+ %% dh_check, dh_generate_parameters,
+ %% module_info, start, stop, version]),
+ %% ?line BlackList = NotInInfo,
?line InfoLib = crypto:info_lib(),
?line [_|_] = InfoLib,
@@ -221,10 +222,10 @@ info(Config) when is_list(Config) ->
Me(T,Me);
([],_) ->
ok
- end,
+ end,
?line F(InfoLib,F),
?line crypto:stop()
- end.
+ end.
%%
%%
@@ -359,7 +360,7 @@ hmac_update_sha(Config) when is_list(Config) ->
?line Ctx2 = crypto:hmac_update(Ctx, Data),
?line Ctx3 = crypto:hmac_update(Ctx2, Data2),
?line Mac = crypto:hmac_final(Ctx3),
- ?line Exp = crypto:sha_mac(Key, lists:flatten([Data, Data2])),
+ ?line Exp = crypto:hmac(sha, Key, lists:flatten([Data, Data2])),
?line m(Exp, Mac).
hmac_update_sha256(doc) ->
@@ -381,7 +382,7 @@ hmac_update_sha256_do() ->
?line Ctx2 = crypto:hmac_update(Ctx, Data),
?line Ctx3 = crypto:hmac_update(Ctx2, Data2),
?line Mac = crypto:hmac_final(Ctx3),
- ?line Exp = crypto:sha256_mac(Key, lists:flatten([Data, Data2])),
+ ?line Exp = crypto:hmac(sha256, Key, lists:flatten([Data, Data2])),
?line m(Exp, Mac).
hmac_update_sha512(doc) ->
@@ -403,7 +404,7 @@ hmac_update_sha512_do() ->
?line Ctx2 = crypto:hmac_update(Ctx, Data),
?line Ctx3 = crypto:hmac_update(Ctx2, Data2),
?line Mac = crypto:hmac_final(Ctx3),
- ?line Exp = crypto:sha512_mac(Key, lists:flatten([Data, Data2])),
+ ?line Exp = crypto:hmac(sha512, Key, lists:flatten([Data, Data2])),
?line m(Exp, Mac).
hmac_update_md5(doc) ->
@@ -618,68 +619,64 @@ hmac_rfc4231_sha512(suite) ->
hmac_rfc4231_sha512(Config) when is_list(Config) ->
if_supported(sha512, fun() -> hmac_rfc4231_sha512_do() end).
-hmac_rfc4231_case(Hash, HashFun, case1, Exp) ->
+hmac_rfc4231_case(Hash, case1, Exp) ->
%% Test 1
Key = binary:copy(<<16#0b>>, 20),
Data = <<"Hi There">>,
- hmac_rfc4231_case(Hash, HashFun, Key, Data, Exp);
+ hmac_rfc4231_case(Hash, Key, Data, Exp);
-hmac_rfc4231_case(Hash, HashFun, case2, Exp) ->
+hmac_rfc4231_case(Hash, case2, Exp) ->
%% Test 2
Key = <<"Jefe">>,
Data = <<"what do ya want for nothing?">>,
- hmac_rfc4231_case(Hash, HashFun, Key, Data, Exp);
+ hmac_rfc4231_case(Hash, Key, Data, Exp);
-hmac_rfc4231_case(Hash, HashFun, case3, Exp) ->
+hmac_rfc4231_case(Hash, case3, Exp) ->
%% Test 3
Key = binary:copy(<<16#aa>>, 20),
Data = binary:copy(<<16#dd>>, 50),
- hmac_rfc4231_case(Hash, HashFun, Key, Data, Exp);
+ hmac_rfc4231_case(Hash, Key, Data, Exp);
-hmac_rfc4231_case(Hash, HashFun, case4, Exp) ->
+hmac_rfc4231_case(Hash, case4, Exp) ->
%% Test 4
Key = list_to_binary(lists:seq(1, 16#19)),
Data = binary:copy(<<16#cd>>, 50),
- hmac_rfc4231_case(Hash, HashFun, Key, Data, Exp);
+ hmac_rfc4231_case(Hash, Key, Data, Exp);
-hmac_rfc4231_case(Hash, HashFun, case5, Exp) ->
+hmac_rfc4231_case(Hash, case5, Exp) ->
%% Test 5
Key = binary:copy(<<16#0c>>, 20),
Data = <<"Test With Truncation">>,
- hmac_rfc4231_case(Hash, HashFun, Key, Data, 16, Exp);
+ hmac_rfc4231_case(Hash, Key, Data, 16, Exp);
-hmac_rfc4231_case(Hash, HashFun, case6, Exp) ->
+hmac_rfc4231_case(Hash, case6, Exp) ->
%% Test 6
Key = binary:copy(<<16#aa>>, 131),
Data = <<"Test Using Larger Than Block-Size Key - Hash Key First">>,
- hmac_rfc4231_case(Hash, HashFun, Key, Data, Exp);
+ hmac_rfc4231_case(Hash, Key, Data, Exp);
-hmac_rfc4231_case(Hash, HashFun, case7, Exp) ->
+hmac_rfc4231_case(Hash, case7, Exp) ->
%% Test Case 7
Key = binary:copy(<<16#aa>>, 131),
Data = <<"This is a test using a larger than block-size key and a larger t",
"han block-size data. The key needs to be hashed before being use",
"d by the HMAC algorithm.">>,
- hmac_rfc4231_case(Hash, HashFun, Key, Data, Exp).
+ hmac_rfc4231_case(Hash, Key, Data, Exp).
-hmac_rfc4231_case(Hash, HashFun, Key, Data, Exp) ->
+hmac_rfc4231_case(Hash, Key, Data, Exp) ->
?line Ctx = crypto:hmac_init(Hash, Key),
?line Ctx2 = crypto:hmac_update(Ctx, Data),
?line Mac1 = crypto:hmac_final(Ctx2),
- ?line Mac2 = crypto:HashFun(Key, Data),
?line Mac3 = crypto:hmac(Hash, Key, Data),
?line m(Exp, Mac1),
- ?line m(Exp, Mac2),
?line m(Exp, Mac3).
-hmac_rfc4231_case(Hash, HashFun, Key, Data, Trunc, Exp) ->
+hmac_rfc4231_case(Hash, Key, Data, Trunc, Exp) ->
?line Ctx = crypto:hmac_init(Hash, Key),
?line Ctx2 = crypto:hmac_update(Ctx, Data),
?line Mac1 = crypto:hmac_final_n(Ctx2, Trunc),
- ?line Mac2 = crypto:HashFun(Key, Data, Trunc),
?line Mac3 = crypto:hmac(Hash, Key, Data, Trunc),
?line m(Exp, Mac1),
- ?line m(Exp, Mac2),
?line m(Exp, Mac3).
hmac_rfc4231_sha224_do() ->
@@ -696,7 +693,7 @@ hmac_rfc4231_sha224_do() ->
"d499f112f2d2b7273fa6870e"),
Case7 = hexstr2bin("3a854166ac5d9f023f54d517d0b39dbd"
"946770db9c2b95c9f6f565d1"),
- hmac_rfc4231_cases_do(sha224, sha224_mac, [Case1, Case2, Case3, Case4, Case5, Case6, Case7]).
+ hmac_rfc4231_cases_do(sha224, [Case1, Case2, Case3, Case4, Case5, Case6, Case7]).
hmac_rfc4231_sha256_do() ->
Case1 = hexstr2bin("b0344c61d8db38535ca8afceaf0bf12b"
@@ -712,7 +709,7 @@ hmac_rfc4231_sha256_do() ->
"8e0bc6213728c5140546040f0ee37f54"),
Case7 = hexstr2bin("9b09ffa71b942fcb27635fbcd5b0e944"
"bfdc63644f0713938a7f51535c3a35e2"),
- hmac_rfc4231_cases_do(sha256, sha256_mac, [Case1, Case2, Case3, Case4, Case5, Case6, Case7]).
+ hmac_rfc4231_cases_do(sha256, [Case1, Case2, Case3, Case4, Case5, Case6, Case7]).
hmac_rfc4231_sha384_do() ->
Case1 = hexstr2bin("afd03944d84895626b0825f4ab46907f"
@@ -734,7 +731,7 @@ hmac_rfc4231_sha384_do() ->
Case7 = hexstr2bin("6617178e941f020d351e2f254e8fd32c"
"602420feb0b8fb9adccebb82461e99c5"
"a678cc31e799176d3860e6110c46523e"),
- hmac_rfc4231_cases_do(sha384, sha384_mac, [Case1, Case2, Case3, Case4, Case5, Case6, Case7]).
+ hmac_rfc4231_cases_do(sha384, [Case1, Case2, Case3, Case4, Case5, Case6, Case7]).
hmac_rfc4231_sha512_do() ->
Case1 = hexstr2bin("87aa7cdea5ef619d4ff0b4241a1d6cb0"
@@ -762,16 +759,16 @@ hmac_rfc4231_sha512_do() ->
"debd71f8867289865df5a32d20cdc944"
"b6022cac3c4982b10d5eeb55c3e4de15"
"134676fb6de0446065c97440fa8c6a58"),
- hmac_rfc4231_cases_do(sha512, sha512_mac, [Case1, Case2, Case3, Case4, Case5, Case6, Case7]).
+ hmac_rfc4231_cases_do(sha512, [Case1, Case2, Case3, Case4, Case5, Case6, Case7]).
-hmac_rfc4231_cases_do(Hash, HashFun, CasesData) ->
- hmac_rfc4231_cases_do(Hash, HashFun, [case1, case2, case3, case4, case5, case6, case7], CasesData).
+hmac_rfc4231_cases_do(Hash, CasesData) ->
+ hmac_rfc4231_cases_do(Hash, [case1, case2, case3, case4, case5, case6, case7], CasesData).
-hmac_rfc4231_cases_do(_Hash, _HashFun, _, []) ->
+hmac_rfc4231_cases_do(_Hash, _, []) ->
ok;
-hmac_rfc4231_cases_do(Hash, HashFun, [C|Cases], [D|CasesData]) ->
- hmac_rfc4231_case(Hash, HashFun, C, D),
- hmac_rfc4231_cases_do(Hash, HashFun, Cases, CasesData).
+hmac_rfc4231_cases_do(Hash, [C|Cases], [D|CasesData]) ->
+ hmac_rfc4231_case(Hash, C, D),
+ hmac_rfc4231_cases_do(Hash, Cases, CasesData).
hmac_update_md5_io(doc) ->
["Generate an MD5 HMAC using hmac_init, hmac_update, and hmac_final. "
@@ -858,10 +855,10 @@ sha256(Config) when is_list(Config) ->
if_supported(sha256, fun() -> sha256_do() end).
sha256_do() ->
- ?line m(crypto:sha256("abc"),
+ ?line m(crypto:hash(sha256, "abc"),
hexstr2bin("BA7816BF8F01CFEA4141"
"40DE5DAE2223B00361A396177A9CB410FF61F20015AD")),
- ?line m(crypto:sha256("abcdbcdecdefdefgefghfghighijhijkijkljklmklm"
+ ?line m(crypto:hash(sha256, "abcdbcdecdefdefgefghfghighijhijkijkljklmklm"
"nlmnomnopnopq"),
hexstr2bin("248D6A61D20638B8"
"E5C026930C3E6039A33CE45964FF2167F6ECEDD419DB06C1")).
@@ -877,10 +874,10 @@ sha256_update(Config) when is_list(Config) ->
if_supported(sha256, fun() -> sha256_update_do() end).
sha256_update_do() ->
- ?line Ctx = crypto:sha256_init(),
- ?line Ctx1 = crypto:sha256_update(Ctx, "abcdbcdecdefdefgefghfghighi"),
- ?line Ctx2 = crypto:sha256_update(Ctx1, "jhijkijkljklmklmnlmnomnopnopq"),
- ?line m(crypto:sha256_final(Ctx2),
+ ?line Ctx = crypto:hash_init(sha256),
+ ?line Ctx1 = crypto:hash_update(Ctx, "abcdbcdecdefdefgefghfghighi"),
+ ?line Ctx2 = crypto:hash_update(Ctx1, "jhijkijkljklmklmnlmnomnopnopq"),
+ ?line m(crypto:hash_final(Ctx2),
hexstr2bin("248D6A61D20638B8"
"E5C026930C3E6039A33CE45964FF2167F6ECEDD419DB06C1")).
@@ -896,11 +893,11 @@ sha512(Config) when is_list(Config) ->
if_supported(sha512, fun() -> sha512_do() end).
sha512_do() ->
- ?line m(crypto:sha512("abc"),
+ ?line m(crypto:hash(sha512, "abc"),
hexstr2bin("DDAF35A193617ABACC417349AE20413112E6FA4E89A97EA2"
"0A9EEEE64B55D39A2192992A274FC1A836BA3C23A3FEEBBD"
"454D4423643CE80E2A9AC94FA54CA49F")),
- ?line m(crypto:sha512("abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmn"
+ ?line m(crypto:hash(sha512, "abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmn"
"hijklmnoijklmnopjklmnopqklmnopqrlmnopqrsmnopqrstnopqrstu"),
hexstr2bin("8E959B75DAE313DA8CF4F72814FC143F8F7779C6EB9F7FA1"
"7299AEADB6889018501D289E4900F7E4331B99DEC4B5433A"
@@ -917,10 +914,10 @@ sha512_update(Config) when is_list(Config) ->
if_supported(sha512, fun() -> sha512_update_do() end).
sha512_update_do() ->
- ?line Ctx = crypto:sha512_init(),
- ?line Ctx1 = crypto:sha512_update(Ctx, "abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmn"),
- ?line Ctx2 = crypto:sha512_update(Ctx1, "hijklmnoijklmnopjklmnopqklmnopqrlmnopqrsmnopqrstnopqrstu"),
- ?line m(crypto:sha512_final(Ctx2),
+ ?line Ctx = crypto:hash_init(sha512),
+ ?line Ctx1 = crypto:hash_update(Ctx, "abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmn"),
+ ?line Ctx2 = crypto:hash_update(Ctx1, "hijklmnoijklmnopjklmnopqklmnopqrlmnopqrsmnopqrstnopqrstu"),
+ ?line m(crypto:hash_final(Ctx2),
hexstr2bin("8E959B75DAE313DA8CF4F72814FC143F8F7779C6EB9F7FA1"
"7299AEADB6889018501D289E4900F7E4331B99DEC4B5433A"
"C7D329EEB6DD26545E96E55B874BE909")).
@@ -1629,8 +1626,11 @@ dsa_verify_test(Config) when is_list(Config) ->
BadArg = (catch my_dss_verify(sized_binary(Msg), <<SizeErr:32, SigBlob/binary>>,
ValidKey)),
- ?line m(element(1,element(2,BadArg)), badarg),
-
+ badarg = case element(1,element(2,BadArg)) of
+ badarg -> badarg;
+ function_clause -> badarg;
+ X -> X
+ end,
InValidKey = [crypto:mpint(P_p),
crypto:mpint(Q_p),
crypto:mpint(G_p),
@@ -1663,20 +1663,29 @@ rsa_sign_test(Config) when is_list(Config) ->
Msg = <<"7896345786348756234 Hejsan Svejsan, erlang crypto debugger"
"09812312908312378623487263487623412039812 huagasd">>,
- PrivKey = [crypto:mpint(PubEx), crypto:mpint(Mod), crypto:mpint(PrivEx)],
- PubKey = [crypto:mpint(PubEx), crypto:mpint(Mod)],
- ?line Sig1 = crypto:rsa_sign(sized_binary(Msg), PrivKey),
- ?line m(crypto:rsa_verify(sized_binary(Msg), sized_binary(Sig1),PubKey), true),
+ PrivKey = [PubEx, Mod, PrivEx],
+ PubKey = [PubEx, Mod],
+ PubKeyMpint = map_int_to_mpint(PubKey),
+ Sig1 = crypto:rsa_sign(sized_binary(Msg), map_int_to_mpint(PrivKey)),
+ Sig1 = crypto:sign(rsa, sha, Msg, PrivKey),
+ true = crypto:rsa_verify(sized_binary(Msg), sized_binary(Sig1), PubKeyMpint),
+ true = crypto:verify(rsa, sha, Msg, Sig1, PubKey),
- ?line Sig2 = crypto:rsa_sign(md5, sized_binary(Msg), PrivKey),
- ?line m(crypto:rsa_verify(md5, sized_binary(Msg), sized_binary(Sig2),PubKey), true),
+ Sig2 = crypto:rsa_sign(md5, sized_binary(Msg), map_int_to_mpint(PrivKey)),
+ Sig2 = crypto:sign(rsa, md5, Msg, PrivKey),
+ true = crypto:rsa_verify(md5, sized_binary(Msg), sized_binary(Sig2), PubKeyMpint),
+ true = crypto:verify(rsa, md5, Msg, Sig2, PubKey),
- ?line m(Sig1 =:= Sig2, false),
- ?line m(crypto:rsa_verify(md5, sized_binary(Msg), sized_binary(Sig1),PubKey), false),
- ?line m(crypto:rsa_verify(sha, sized_binary(Msg), sized_binary(Sig1),PubKey), true),
-
+ false = (Sig1 =:= Sig2),
+ false = crypto:rsa_verify(md5, sized_binary(Msg), sized_binary(Sig1), PubKeyMpint),
+ false = crypto:verify(rsa, md5, Msg, Sig1, PubKey),
+ true = crypto:rsa_verify(sha, sized_binary(Msg), sized_binary(Sig1), PubKeyMpint),
+ true = crypto:verify(rsa, sha, Msg, Sig1, PubKey),
+
ok.
-
+map_int_to_mpint(List) ->
+ lists:map(fun(E) -> crypto:mpint(E) end, List).
+
rsa_sign_hash_test(doc) ->
"rsa_sign_hash testing";
rsa_sign_hash_test(suite) ->
@@ -1774,46 +1783,65 @@ rsa_encrypt_decrypt(Config) when is_list(Config) ->
PrivEx = 7531712708607620783801185371644749935066152052780368689827275932079815492940396744378735701395659435842364793962992309884847527234216715366607660219930945,
Mod = 7919488123861148172698919999061127847747888703039837999377650217570191053151807772962118671509138346758471459464133273114654252861270845708312601272799123,
- PrivKey = [crypto:mpint(PubEx), crypto:mpint(Mod), crypto:mpint(PrivEx)],
- PubKey = [crypto:mpint(PubEx), crypto:mpint(Mod)],
+ PrivKey = [PubEx, Mod, PrivEx],
+ PubKey = [PubEx, Mod],
Msg = <<"7896345786348 Asldi">>,
- ?line PKCS1 = crypto:rsa_public_encrypt(Msg, PubKey, rsa_pkcs1_padding),
- ?line PKCS1Dec = crypto:rsa_private_decrypt(PKCS1, PrivKey, rsa_pkcs1_padding),
+ ?line PKCS1 = rsa_public_encrypt(Msg, PubKey, rsa_pkcs1_padding),
+ ?line PKCS1Dec = rsa_private_decrypt(PKCS1, PrivKey, rsa_pkcs1_padding),
io:format("PKCS1Dec ~p~n",[PKCS1Dec]),
?line Msg = PKCS1Dec,
- ?line OAEP = crypto:rsa_public_encrypt(Msg, PubKey, rsa_pkcs1_oaep_padding),
- ?line Msg = crypto:rsa_private_decrypt(OAEP, PrivKey, rsa_pkcs1_oaep_padding),
+ ?line OAEP = rsa_public_encrypt(Msg, PubKey, rsa_pkcs1_oaep_padding),
+ ?line Msg = rsa_private_decrypt(OAEP, PrivKey, rsa_pkcs1_oaep_padding),
<<Msg2Len:32,_/binary>> = crypto:mpint(Mod),
Msg2 = list_to_binary(lists:duplicate(Msg2Len-1, $X)),
- ?line NoPad = crypto:rsa_public_encrypt(Msg2, PubKey, rsa_no_padding),
- ?line NoPadDec = crypto:rsa_private_decrypt(NoPad, PrivKey, rsa_no_padding),
+ ?line NoPad = rsa_public_encrypt(Msg2, PubKey, rsa_no_padding),
+ ?line NoPadDec = rsa_private_decrypt(NoPad, PrivKey, rsa_no_padding),
?line NoPadDec = Msg2,
- ShouldBeError = (catch crypto:rsa_public_encrypt(Msg, PubKey, rsa_no_padding)),
+ ShouldBeError = (catch rsa_public_encrypt(Msg, PubKey, rsa_no_padding)),
?line {'EXIT', {encrypt_failed,_}} = ShouldBeError,
-%% ?line SSL = crypto:rsa_public_encrypt(Msg, PubKey, rsa_sslv23_padding),
-%% ?line Msg = crypto:rsa_private_decrypt(SSL, PrivKey, rsa_sslv23_padding),
+%% ?line SSL = rsa_public_encrypt(Msg, PubKey, rsa_sslv23_padding),
+%% ?line Msg = rsa_private_decrypt(SSL, PrivKey, rsa_sslv23_padding),
- ?line PKCS1_2 = crypto:rsa_private_encrypt(Msg, PrivKey, rsa_pkcs1_padding),
- ?line PKCS1_2Dec = crypto:rsa_public_decrypt(PKCS1_2, PubKey, rsa_pkcs1_padding),
+ ?line PKCS1_2 = rsa_private_encrypt(Msg, PrivKey, rsa_pkcs1_padding),
+ ?line PKCS1_2Dec = rsa_public_decrypt(PKCS1_2, PubKey, rsa_pkcs1_padding),
io:format("PKCS2Dec ~p~n",[PKCS1_2Dec]),
?line Msg = PKCS1_2Dec,
- ?line PKCS1_3 = crypto:rsa_private_encrypt(Msg2, PrivKey, rsa_no_padding),
- ?line PKCS1_3Dec = crypto:rsa_public_decrypt(PKCS1_3, PubKey, rsa_no_padding),
+ ?line PKCS1_3 = rsa_private_encrypt(Msg2, PrivKey, rsa_no_padding),
+ ?line PKCS1_3Dec = rsa_public_decrypt(PKCS1_3, PubKey, rsa_no_padding),
io:format("PKCS2Dec ~p~n",[PKCS1_3Dec]),
?line Msg2 = PKCS1_3Dec,
?line {'EXIT', {encrypt_failed,_}} =
- (catch crypto:rsa_private_encrypt(Msg, PrivKey, rsa_no_padding)),
+ (catch rsa_private_encrypt(Msg, PrivKey, rsa_no_padding)),
ok.
+rsa_public_encrypt(Msg, Key, Pad) ->
+ C1 = crypto:rsa_public_encrypt(Msg, Key, Pad),
+ C2 = crypto:rsa_public_encrypt(Msg, lists:map(fun(E) -> crypto:mpint(E) end, Key), Pad),
+ {C1,C2}.
+
+rsa_public_decrypt(Msg, Key, Pad) ->
+ R = crypto:rsa_public_decrypt(Msg, Key, Pad),
+ R = crypto:rsa_public_decrypt(Msg, lists:map(fun(E) -> crypto:mpint(E) end, Key), Pad).
+
+rsa_private_encrypt(Msg, Key, Pad) ->
+ R = crypto:rsa_private_encrypt(Msg, Key, Pad),
+ R = crypto:rsa_private_encrypt(Msg, lists:map(fun(E) -> crypto:mpint(E) end, Key), Pad).
+
+rsa_private_decrypt({C1,C2}, Key, Pad) ->
+ R = crypto:rsa_private_decrypt(C1, Key, Pad),
+ R = crypto:rsa_private_decrypt(C2, Key, Pad),
+ R = crypto:rsa_private_decrypt(C1, lists:map(fun(E) -> crypto:mpint(E) end, Key), Pad),
+ R = crypto:rsa_private_decrypt(C2, lists:map(fun(E) -> crypto:mpint(E) end, Key), Pad).
+
dh(doc) ->
["Test dh (Diffie-Hellman) functions."];
@@ -1832,13 +1860,16 @@ dh(Config) when is_list(Config) ->
{param, DHPs} ->
timer:sleep(100),
io:format("DHP ~p~n", [DHPs]),
- ?line {Pub1,Priv1} = crypto:dh_generate_key(DHPs),
+ DHPs_mpint = lists:map(fun(E) -> sized_binary(E) end, DHPs),
+ ?line {Pub1,Priv1} = crypto:generate_key(dh, DHPs),
io:format("Key1:~n~p~n~p~n~n", [Pub1,Priv1]),
- ?line {Pub2,Priv2} = crypto:dh_generate_key(DHPs),
+ ?line {Pub2,Priv2} = crypto:dh_generate_key(DHPs_mpint),
io:format("Key2:~n~p~n~p~n~n", [Pub2,Priv2]),
- ?line A = crypto:dh_compute_key(Pub1, Priv2, DHPs),
+ ?line A = crypto:compute_key(dh, Pub1, unsized_binary(Priv2), DHPs),
+ ?line A = crypto:dh_compute_key(sized_binary(Pub1), Priv2, DHPs_mpint),
timer:sleep(100), %% Get another thread see if that triggers problem
- ?line B = crypto:dh_compute_key(Pub2, Priv1, DHPs),
+ ?line B = crypto:compute_key(dh, unsized_binary(Pub2), Priv1, DHPs),
+ ?line B = crypto:dh_compute_key(Pub2, sized_binary(Priv1), DHPs_mpint),
io:format("A ~p~n",[A]),
io:format("B ~p~n",[B]),
?line A = B
@@ -1847,6 +1878,64 @@ dh(Config) when is_list(Config) ->
exit(Pid, kill)
end.
+
+ec(doc) ->
+ ["Test ec (Ecliptic Curve) functions."];
+ec(suite) -> [];
+ec(Config) when is_list(Config) ->
+ if_supported(ec, fun() -> ec_do() end).
+
+ec_do() ->
+ %% test for a name curve
+ {D2_priv, D2_pub} = crypto:generate_key(ecdh, sect113r2),
+ PrivECDH = [D2_priv, sect113r2],
+ PubECDH = [D2_pub, sect113r2],
+ %%TODO: find a published test case for a EC key
+
+ %% test for a full specified curve and public key,
+ %% taken from csca-germany_013_self_signed_cer.pem
+ PubKey = <<16#04, 16#4a, 16#94, 16#49, 16#81, 16#77, 16#9d, 16#df,
+ 16#1d, 16#a5, 16#e7, 16#c5, 16#27, 16#e2, 16#7d, 16#24,
+ 16#71, 16#a9, 16#28, 16#eb, 16#4d, 16#7b, 16#67, 16#75,
+ 16#ae, 16#09, 16#0a, 16#51, 16#45, 16#19, 16#9b, 16#d4,
+ 16#7e, 16#a0, 16#81, 16#e5, 16#5e, 16#d4, 16#a4, 16#3f,
+ 16#60, 16#7c, 16#6a, 16#50, 16#ee, 16#36, 16#41, 16#8a,
+ 16#87, 16#ff, 16#cd, 16#a6, 16#10, 16#39, 16#ca, 16#95,
+ 16#76, 16#7d, 16#ae, 16#ca, 16#c3, 16#44, 16#3f, 16#e3, 16#2c>>,
+ <<P:264/integer>> = <<16#00, 16#a9, 16#fb, 16#57, 16#db, 16#a1, 16#ee, 16#a9,
+ 16#bc, 16#3e, 16#66, 16#0a, 16#90, 16#9d, 16#83, 16#8d,
+ 16#72, 16#6e, 16#3b, 16#f6, 16#23, 16#d5, 16#26, 16#20,
+ 16#28, 16#20, 16#13, 16#48, 16#1d, 16#1f, 16#6e, 16#53, 16#77>>,
+ <<A:256/integer>> = <<16#7d, 16#5a, 16#09, 16#75, 16#fc, 16#2c, 16#30, 16#57,
+ 16#ee, 16#f6, 16#75, 16#30, 16#41, 16#7a, 16#ff, 16#e7,
+ 16#fb, 16#80, 16#55, 16#c1, 16#26, 16#dc, 16#5c, 16#6c,
+ 16#e9, 16#4a, 16#4b, 16#44, 16#f3, 16#30, 16#b5, 16#d9>>,
+ <<B:256/integer>> = <<16#26, 16#dc, 16#5c, 16#6c, 16#e9, 16#4a, 16#4b, 16#44,
+ 16#f3, 16#30, 16#b5, 16#d9, 16#bb, 16#d7, 16#7c, 16#bf,
+ 16#95, 16#84, 16#16, 16#29, 16#5c, 16#f7, 16#e1, 16#ce,
+ 16#6b, 16#cc, 16#dc, 16#18, 16#ff, 16#8c, 16#07, 16#b6>>,
+ BasePoint = <<16#04, 16#8b, 16#d2, 16#ae, 16#b9, 16#cb, 16#7e, 16#57,
+ 16#cb, 16#2c, 16#4b, 16#48, 16#2f, 16#fc, 16#81, 16#b7,
+ 16#af, 16#b9, 16#de, 16#27, 16#e1, 16#e3, 16#bd, 16#23,
+ 16#c2, 16#3a, 16#44, 16#53, 16#bd, 16#9a, 16#ce, 16#32,
+ 16#62, 16#54, 16#7e, 16#f8, 16#35, 16#c3, 16#da, 16#c4,
+ 16#fd, 16#97, 16#f8, 16#46, 16#1a, 16#14, 16#61, 16#1d,
+ 16#c9, 16#c2, 16#77, 16#45, 16#13, 16#2d, 16#ed, 16#8e,
+ 16#54, 16#5c, 16#1d, 16#54, 16#c7, 16#2f, 16#04, 16#69, 16#97>>,
+ <<Order:264/integer>> = <<16#00, 16#a9, 16#fb, 16#57, 16#db, 16#a1, 16#ee, 16#a9,
+ 16#bc, 16#3e, 16#66, 16#0a, 16#90, 16#9d, 16#83, 16#8d,
+ 16#71, 16#8c, 16#39, 16#7a, 16#a3, 16#b5, 16#61, 16#a6,
+ 16#f7, 16#90, 16#1e, 16#0e, 16#82, 16#97, 16#48, 16#56, 16#a7>>,
+ CoFactor = 1,
+ Curve = {{prime_field,P},{A,B,none},BasePoint, Order,CoFactor},
+
+ Msg = <<99,234,6,64,190,237,201,99,80,248,58,40,70,45,149,218,5,246,242,63>>,
+ Sign = crypto:sign(ecdsa, sha, Msg, PrivECDH),
+ ?line true = crypto:verify(ecdsa, sha, Msg, Sign, PubECDH),
+ ?line false = crypto:verify(ecdsa, sha, Msg, <<10,20>>, PubECDH),
+
+ ok.
+
srp3(doc) ->
["SRP-3 test vectors generated by http://srp.stanford.edu/demo/demo.html"];
srp3(suite) -> [];
@@ -1890,15 +1979,15 @@ srp3(Config) when is_list(Config) ->
"9176A9192615DC0277AE7C12F1F6A7F6563FCA11675D809AF578BDE5"
"2B51E05D440B63099A017A0B45044801"),
UserPassHash = crypto:sha([Salt, crypto:sha([Username, <<$:>>, Password])]),
- Verifier = crypto:mod_exp_prime(Generator, UserPassHash, Prime),
- ClientPublic = crypto:mod_exp_prime(Generator, ClientPrivate, Prime),
+ Verifier = crypto:mod_pow(Generator, UserPassHash, Prime),
+ ClientPublic = crypto:mod_pow(Generator, ClientPrivate, Prime),
- {ClientPublic, ClientPrivate} = crypto:srp_generate_key(Generator, Prime, Version, ClientPrivate),
- {ServerPublic, ServerPrivate} = crypto:srp_generate_key(Verifier, Generator, Prime, Version, ServerPrivate),
- SessionKey = crypto:srp_compute_key(UserPassHash, Prime, Generator, ClientPublic,
- ClientPrivate, ServerPublic, Version, Scrambler),
- SessionKey = crypto:srp_compute_key(Verifier, Prime, ClientPublic,
- ServerPublic, ServerPrivate, Version, Scrambler).
+ {ClientPublic, ClientPrivate} = crypto:generate_key(srp, {user, [Generator, Prime, Version]}, ClientPrivate),
+ {ServerPublic, ServerPrivate} = crypto:generate_key(srp, {host, [Verifier, Generator, Prime, Version]}, ServerPrivate),
+ SessionKey = crypto:compute_key(srp, ServerPublic, {ClientPublic, ClientPrivate},
+ {user, [UserPassHash, Prime, Generator, Version, Scrambler]}),
+ SessionKey = crypto:compute_key(srp, ClientPublic, {ServerPublic, ServerPrivate},
+ {host, [Verifier, Prime, Version, Scrambler]}).
srp6(doc) ->
["SRP-6 test vectors generated by http://srp.stanford.edu/demo/demo.html"];
@@ -1941,15 +2030,15 @@ srp6(Config) when is_list(Config) ->
"72E992AAD89095A84B6A5FADA152369AB1E350A03693BEF044DF3EDF"
"0C34741F4696C30E9F675D09F58ACBEB"),
UserPassHash = crypto:sha([Salt, crypto:sha([Username, <<$:>>, Password])]),
- Verifier = crypto:mod_exp_prime(Generator, UserPassHash, Prime),
- ClientPublic = crypto:mod_exp_prime(Generator, ClientPrivate, Prime),
+ Verifier = crypto:mod_pow(Generator, UserPassHash, Prime),
+ ClientPublic = crypto:mod_pow(Generator, ClientPrivate, Prime),
- {ClientPublic, ClientPrivate} = crypto:srp_generate_key(Generator, Prime, Version, ClientPrivate),
- {ServerPublic, ServerPrivate} = crypto:srp_generate_key(Verifier, Generator, Prime, Version, ServerPrivate),
- SessionKey = crypto:srp_compute_key(UserPassHash, Prime, Generator, ClientPublic,
- ClientPrivate, ServerPublic, Version, Scrambler),
- SessionKey = crypto:srp_compute_key(Verifier, Prime, ClientPublic,
- ServerPublic, ServerPrivate, Version, Scrambler).
+ {ClientPublic, ClientPrivate} = crypto:generate_key(srp, {user, [Generator, Prime, Version]}, ClientPrivate),
+ {ServerPublic, ServerPrivate} = crypto:generate_key(srp, {host, [Verifier, Generator, Prime, Version]}, ServerPrivate),
+ SessionKey = crypto:compute_key(srp, ServerPublic, {ClientPublic, ClientPrivate},
+ {user, [UserPassHash, Prime, Generator, Version, Scrambler]}),
+ SessionKey = crypto:compute_key(srp, ClientPublic, {ServerPublic, ServerPrivate},
+ {host, [Verifier, Prime, Version, Scrambler]}).
srp6a(doc) ->
["SRP-6a test vectors from RFC5054."];
@@ -1992,15 +2081,15 @@ srp6a(Config) when is_list(Config) ->
"3499B200210DCC1F10EB33943CD67FC88A2F39A4BE5BEC4EC0A3212D"
"C346D7E474B29EDE8A469FFECA686E5A"),
UserPassHash = crypto:sha([Salt, crypto:sha([Username, <<$:>>, Password])]),
- Verifier = crypto:mod_exp_prime(Generator, UserPassHash, Prime),
+ Verifier = crypto:mod_pow(Generator, UserPassHash, Prime),
- {ClientPublic, ClientPrivate} = crypto:srp_generate_key(Generator, Prime, Version, ClientPrivate),
- {ServerPublic, ServerPrivate} = crypto:srp_generate_key(Verifier, Generator, Prime, Version, ServerPrivate),
+ {ClientPublic, ClientPrivate} = crypto:generate_key(srp, {user, [Generator, Prime, Version]}, ClientPrivate),
+ {ServerPublic, ServerPrivate} = crypto:generate_key(srp, {host, [Verifier, Generator, Prime, Version]}, ServerPrivate),
- SessionKey = crypto:srp_compute_key(UserPassHash, Prime, Generator, ClientPublic,
- ClientPrivate, ServerPublic, Version, Scrambler),
- SessionKey = crypto:srp_compute_key(Verifier, Prime, ClientPublic,
- ServerPublic, ServerPrivate, Version, Scrambler).
+ SessionKey = crypto:compute_key(srp, ServerPublic, {ClientPublic, ClientPrivate},
+ {user, [UserPassHash, Prime, Generator, Version, Scrambler]}),
+ SessionKey = crypto:compute_key(srp, ClientPublic, {ServerPublic, ServerPrivate},
+ {host, [Verifier, Prime, Version, Scrambler]}).
%%
%%
@@ -2195,6 +2284,9 @@ sized_binary(Binary) when is_binary(Binary) ->
sized_binary(List) ->
sized_binary(list_to_binary(List)).
+unsized_binary(<<Sz:32/integer, Binary:Sz/binary>>) ->
+ Binary.
+
xor_bytes(Bin1, Bin2) when is_binary(Bin1), is_binary(Bin2) ->
L1 = binary_to_list(Bin1),
L2 = binary_to_list(Bin2),
diff --git a/lib/debugger/src/dbg_debugged.erl b/lib/debugger/src/dbg_debugged.erl
index c21ad486e8..d8285d7288 100644
--- a/lib/debugger/src/dbg_debugged.erl
+++ b/lib/debugger/src/dbg_debugged.erl
@@ -19,8 +19,6 @@
-module(dbg_debugged).
%% External exports
-%% Avoid warning for local function demonitor/1 clashing with autoimported BIF.
--compile({no_auto_import,[demonitor/1]}).
-export([eval/3]).
%%====================================================================
@@ -47,7 +45,7 @@ msg_loop(Meta, Mref, SaveStacktrace) ->
%% Evaluated function has returned a value
{sys, Meta, {ready, Val}} ->
- demonitor(Mref),
+ erlang:demonitor(Mref, [flush]),
%% Restore original stacktrace and return the value
try erlang:raise(throw, stack, SaveStacktrace)
@@ -63,7 +61,7 @@ msg_loop(Meta, Mref, SaveStacktrace) ->
%% Evaluated function raised an (uncaught) exception
{sys, Meta, {exception,{Class,Reason,Stacktrace}}} ->
- demonitor(Mref),
+ erlang:demonitor(Mref, [flush]),
%% ...raise the same exception
erlang:error(erlang:raise(Class, Reason, Stacktrace),
@@ -107,14 +105,6 @@ reply({eval,Expr,Bs}) ->
%% Bindings is an orddict (sort them)
erl_eval:expr(Expr, lists:sort(Bs)). % {value, Value, Bs2}
-%% Demonitor and delete message from inbox
-%%
-demonitor(Mref) ->
- erlang:demonitor(Mref),
- receive {'DOWN',Mref,_,_,_} -> ok
- after 0 -> ok
- end.
-
%% Fix stacktrace - keep all above call to this module.
%%
stacktrace_f([]) -> [];
diff --git a/lib/debugger/src/dbg_istk.erl b/lib/debugger/src/dbg_istk.erl
index c6922a80e4..ced42a5f9f 100644
--- a/lib/debugger/src/dbg_istk.erl
+++ b/lib/debugger/src/dbg_istk.erl
@@ -78,7 +78,7 @@ push(Bs, #ieval{level=Le,module=Mod,function=Name,
pop() ->
case get(trace_stack) of
false -> ignore;
- _ -> % all ¦ no_tail
+ _ -> % all | no_tail
case get(?STACK) of
[_Entry|Entries] ->
put(?STACK, Entries);
diff --git a/lib/dialyzer/src/dialyzer_gui.erl b/lib/dialyzer/src/dialyzer_gui.erl
index ac9844c22c..97e5752577 100644
--- a/lib/dialyzer/src/dialyzer_gui.erl
+++ b/lib/dialyzer/src/dialyzer_gui.erl
@@ -2,7 +2,7 @@
%%------------------------------------------------------------------------
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2006-2012. All Rights Reserved.
+%% Copyright Ericsson AB 2006-2013. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -1331,7 +1331,8 @@ build_analysis_record(#gui_state{mode = Mode, menu = Menu, options = Options,
#analysis{defines = Options#options.defines,
include_dirs = Options#options.include_dirs,
plt = InitPlt,
- start_from = StartFrom}.
+ start_from = StartFrom,
+ solvers = Options#options.solvers}.
get_anal_files(#gui_state{chosen_box = ChosenBox}, StartFrom) ->
Files = gs:read(ChosenBox, items),
diff --git a/lib/dialyzer/src/dialyzer_gui_wx.erl b/lib/dialyzer/src/dialyzer_gui_wx.erl
index c6f7c56227..08f31c1e13 100644
--- a/lib/dialyzer/src/dialyzer_gui_wx.erl
+++ b/lib/dialyzer/src/dialyzer_gui_wx.erl
@@ -2,7 +2,7 @@
%%------------------------------------------------------------------------
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2009-2012. All Rights Reserved.
+%% Copyright Ericsson AB 2009-2013. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -810,7 +810,8 @@ build_analysis_record(#gui_state{mode = Mode, menu = Menu, options = Options,
#analysis{defines = Options#options.defines,
include_dirs = Options#options.include_dirs,
plt = InitPlt,
- start_from = StartFrom}.
+ start_from = StartFrom,
+ solvers = Options#options.solvers}.
get_anal_files(#gui_state{files_to_analyze = Files}, StartFrom) ->
FilteredMods =
diff --git a/lib/dialyzer/test/behaviour_SUITE_data/src/custom_sup.erl b/lib/dialyzer/test/behaviour_SUITE_data/src/custom_sup.erl
index 8ec84d798f..7eb4c6ec97 100644
--- a/lib/dialyzer/test/behaviour_SUITE_data/src/custom_sup.erl
+++ b/lib/dialyzer/test/behaviour_SUITE_data/src/custom_sup.erl
@@ -1,3 +1,5 @@
+%%% -*- coding: utf-8 -*-
+%%%
%%% Dialyzer was giving a warning with this input because of a bug in the
%%% substitution of remote types in specs. Remote types in the first element of
%%% a tuple would not update the tuple's tag set and we could end up with a
diff --git a/lib/diameter/doc/src/diameter.xml b/lib/diameter/doc/src/diameter.xml
index 7ea93d480b..318c98f786 100644
--- a/lib/diameter/doc/src/diameter.xml
+++ b/lib/diameter/doc/src/diameter.xml
@@ -343,8 +343,9 @@ Has one of the following types.</p>
An address list is available to the start function of a
&transport_module;, which
can return a new list for use in the subsequent CER or CEA.
-Host-IP-Address need not be specified if the transport start function
-returns an address list.</p>
+Host-IP-Address need not be specified if the transport module in
+question communicates an address list as described in
+&man_transport;</p>
</item>
<tag><c>{'Vendor-Id', &dict_Unsigned32;}</c></tag>
@@ -780,10 +781,10 @@ connections to the same peer.</p>
<p>
If type <c>[node()]</c> then a connection is rejected if another already
exists on any of the specified nodes.
-Values of type <c>false</c>, <c>node</c>, <c>nodes</c> or
+Types <c>false</c>, <c>node</c>, <c>nodes</c> and
&evaluable; are equivalent to
-values <c>[]</c>, <c>[node()]</c>, <c>[node()|nodes()]</c> and the
-evaluated value, respectively, evaluation of each expression taking
+<c>[]</c>, <c>[node()]</c>, <c>[node()|nodes()]</c> and the
+evaluated value respectively, evaluation of each expression taking
place whenever a new connection is to be established.
Note that <c>false</c> allows an unlimited number of connections to be
established with the same peer.</p>
diff --git a/lib/diameter/doc/src/diameter_tcp.xml b/lib/diameter/doc/src/diameter_tcp.xml
index 01c781d553..8e509aa829 100644
--- a/lib/diameter/doc/src/diameter_tcp.xml
+++ b/lib/diameter/doc/src/diameter_tcp.xml
@@ -1,5 +1,6 @@
<?xml version="1.0" encoding="latin1" ?>
<!DOCTYPE erlref SYSTEM "erlref.dtd" [
+ <!ENTITY start '<seealso marker="#start-3">start/3</seealso>'>
<!ENTITY gen_tcp_connect3
'<seealso marker="kernel:gen_tcp#connect-3">gen_tcp:connect/3</seealso>'>
<!ENTITY gen_tcp_listen2
@@ -81,7 +82,9 @@ before configuring TLS capability on diameter transports.</p>
<func>
<name>start({Type, Ref}, Svc, [Opt])
- -> {ok, Pid, [LAddr]} | {error, Reason}</name>
+ -> {ok, Pid}
+ | {ok, Pid, [LAddr]}
+ | {error, Reason}</name>
<fsummary>Start a transport process.</fsummary>
<type>
<v>Type = connect | accept</v>
@@ -153,13 +156,14 @@ that will not be forthcoming, which will eventually cause the RFC 3539
watchdog to take down the connection.</p>
<p>
-If the <c>#diameter_service{}</c> record has more than one
-<c>Host-IP-Address</c> and option <c>ip</c> is unspecified then the
-first of the these addresses is used as the local address.</p>
-
-<p>
-The returned local address list has length one.</p>
-
+If an <c>ip</c> option is not specified then the first element of a
+non-empty <c>Host-IP-Address</c> list in <c>Svc</c> provides the local
+IP address.
+If neither is specified then the default address selected by &gen_tcp;
+is used.
+In all cases, the selected address is either returned from
+&start; or passed in a <c>connected</c> message over the transport
+interface.</p>
</desc>
</func>
diff --git a/lib/diameter/doc/src/diameter_transport.xml b/lib/diameter/doc/src/diameter_transport.xml
index 55b531155f..8bccf6521e 100644
--- a/lib/diameter/doc/src/diameter_transport.xml
+++ b/lib/diameter/doc/src/diameter_transport.xml
@@ -1,6 +1,8 @@
<?xml version="1.0" encoding="latin1" ?>
<!DOCTYPE erlref SYSTEM "erlref.dtd" [
<!ENTITY message '<seealso marker="#message">message()</seealso>'>
+ <!ENTITY MESSAGES '<seealso marker="#MESSAGES">MESSAGES</seealso>'>
+ <!ENTITY start '<seealso marker="#Mod:start-3">start/3</seealso>'>
<!ENTITY ip_address
'<seealso marker="kernel:inet#type-ip_address">inet:ip_address()</seealso>'>
<!ENTITY % also SYSTEM "seealso.ent" >
@@ -12,7 +14,7 @@
<erlref>
<header>
<copyright>
-<year>2011</year><year>2012</year>
+<year>2011</year><year>2013</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
@@ -125,7 +127,7 @@ Ref is the value that was returned from the call to &mod_add_transport;
that has lead to starting of a transport process.</p>
<p>
-<c>Svc</c> contains the capabilities passed to &mod_start_service; and
+<c>Svc</c> contains capabilities passed to &mod_start_service; and
&mod_add_transport;, values passed to the latter overriding those
passed to the former.</p>
@@ -134,13 +136,16 @@ passed to the former.</p>
&mod_transport_opt; list passed to &mod_add_transport;.</p>
<p>
-The start function should use the <c>Host-IP-Address</c> list and/or
-<c>Config</c> to select an appropriate list of local IP addresses,
-and should return this list if different from the
-<c>#diameter_service{}</c> addresses.
-The returned list is used to populate <c>Host-IP-Address</c> AVPs in
-outgoing capabilities exchange messages, the
-<c>#diameter_service{}</c> addresses being used otherwise.</p>
+The start function should use the <c>Host-IP-Address</c> list in
+<c>Svc</c> and/or <c>Config</c> to select an appropriate list of local
+IP addresses, and should return this list if different from the
+<c>Svc</c> addresses.
+In the connecting case, the local address list can instead be
+communicated in a <c>connected</c> message (see &MESSAGES; below)
+following connection establishment.
+In either case, the local address list is used to populate
+<c>Host-IP-Address</c> AVPs in outgoing capabilities exchange
+messages.</p>
<p>
A transport process must implement the message interface documented below.
@@ -230,13 +235,16 @@ Not sent if the transport process has <c>Type=connect</c>.</p>
</item>
<tag><c>{diameter, {self(), connected, Remote}}</c></tag>
+<tag><c>{diameter, {self(), connected, Remote, [LocalAddr]}}</c></tag>
<item>
<p>
Inform the parent that the transport process with <c>Type=connect</c>
has established a connection with a peer.
-Not sent if the transport process has <c>Type=accept</c>.
+Not sent if the transport process has <c>Type=accept</c>.&nbsp;
<c>Remote</c> is an arbitrary term that uniquely identifies the remote
-endpoint to which the transport has connected.</p>
+endpoint to which the transport has connected.
+A <c>LocalAddr</c> list has the same semantics as one returned from
+&start;.</p>
</item>
<tag><c>{diameter, {recv, &message;}}</c></tag>
diff --git a/lib/diameter/examples/code/peer.erl b/lib/diameter/examples/code/peer.erl
index 8fdeba57bf..b4ee17e4b7 100644
--- a/lib/diameter/examples/code/peer.erl
+++ b/lib/diameter/examples/code/peer.erl
@@ -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
@@ -51,7 +51,6 @@
| {protocol(), ip_address(), non_neg_integer()}
| {protocol(), ip_address(), ip_address(), non_neg_integer()}.
--define(DEFAULT_ADDR, {127,0,0,1}).
-define(DEFAULT_PORT, 3868).
%% ---------------------------------------------------------------------------
@@ -111,7 +110,7 @@ server({T, Addr, Port}) ->
{port, Port}]}];
server(T) ->
- server({T, ?DEFAULT_ADDR, ?DEFAULT_PORT}).
+ server({T, loopback, ?DEFAULT_PORT}).
%% client/1
%%
@@ -124,21 +123,28 @@ client({all, LA, RA, RP}) ->
client({T, LA, RA, RP}) ->
[{transport_module, tmod(T)},
- {transport_config, [{ip, addr(LA)},
- {raddr, addr(RA)},
+ {transport_config, [{raddr, addr(RA)},
{rport, RP},
- {reuseaddr, true}]}];
+ {reuseaddr, true}
+ | ip(LA)]}];
-client({T, LA, RP}) ->
- client({T, LA, LA, RP});
+client({T, RA, RP}) ->
+ client({T, default, RA, RP});
client(T) ->
- client({T, ?DEFAULT_ADDR, ?DEFAULT_ADDR, ?DEFAULT_PORT}).
+ client({T, loopback, loopback, ?DEFAULT_PORT}).
tmod(tcp) -> diameter_tcp;
tmod(sctp) -> diameter_sctp.
-addr(default) ->
- ?DEFAULT_ADDR;
+ip(default) ->
+ [];
+ip(loopback) ->
+ [{ip, {127,0,0,1}}];
+ip(Addr) ->
+ [{ip, Addr}].
+
+addr(loopback) ->
+ {127,0,0,1};
addr(A) ->
A.
diff --git a/lib/diameter/src/Makefile b/lib/diameter/src/Makefile
index df10c33268..c0cf418f06 100644
--- a/lib/diameter/src/Makefile
+++ b/lib/diameter/src/Makefile
@@ -230,7 +230,7 @@ include $(ERL_TOP)/make/otp_release_targets.mk
# Can't $(INSTALL_DIR) more than one directory at a time on Solaris.
release_spec: opt
- for d in bin ebin include src/dict; do \
+ for d in bin ebin examples include src/dict; do \
$(INSTALL_DIR) "$(RELSYSDIR)/$$d"; \
done
$(INSTALL_SCRIPT) $(BINS:%=../bin/%) "$(RELSYSDIR)/bin"
diff --git a/lib/diameter/src/base/diameter_peer.erl b/lib/diameter/src/base/diameter_peer.erl
index dfc76eb76e..0d2efd4d1f 100644
--- a/lib/diameter/src/base/diameter_peer.erl
+++ b/lib/diameter/src/base/diameter_peer.erl
@@ -24,7 +24,8 @@
%% Interface towards transport modules ...
-export([recv/2,
up/1,
- up/2]).
+ up/2,
+ up/3]).
%% ... and the stack.
-export([start/1,
@@ -180,7 +181,7 @@ start(Mod, Args) ->
apply(Mod, start, Args).
%%% ---------------------------------------------------------------------------
-%%% # up/[12]
+%%% # up/1-3
%%% ---------------------------------------------------------------------------
up(Pid) -> %% accepting transport
@@ -189,6 +190,9 @@ up(Pid) -> %% accepting transport
up(Pid, Remote) -> %% connecting transport
ifc_send(Pid, {self(), connected, Remote}).
+up(Pid, Remote, LAddrs) -> %% connecting transport
+ ifc_send(Pid, {self(), connected, Remote, LAddrs}).
+
%%% ---------------------------------------------------------------------------
%%% # recv/2
%%% ---------------------------------------------------------------------------
diff --git a/lib/diameter/src/base/diameter_peer_fsm.erl b/lib/diameter/src/base/diameter_peer_fsm.erl
index bee3e507fd..6be4259510 100644
--- a/lib/diameter/src/base/diameter_peer_fsm.erl
+++ b/lib/diameter/src/base/diameter_peer_fsm.erl
@@ -351,10 +351,17 @@ transition({diameter, {TPid, connected, Remote}},
mode = M}
= S) ->
{'Wait-Conn-Ack', _} = PS, %% assert
- connect = M, %%
+ connect = M, %%
keep_transport(TPid),
send_CER(S#state{mode = {M, Remote}});
+transition({diameter, {TPid, connected, Remote, LAddrs}},
+ #state{transport = TPid,
+ service = Svc}
+ = S) ->
+ transition({diameter, {TPid, connected, Remote}},
+ S#state{service = readdr(Svc, LAddrs)});
+
%% Connection from peer.
transition({diameter, {TPid, connected}},
#state{transport = TPid,
@@ -363,7 +370,7 @@ transition({diameter, {TPid, connected}},
parent = Pid}
= S) ->
{'Wait-Conn-Ack', Tmo} = PS, %% assert
- accept = M, %%
+ accept = M, %%
keep_transport(TPid),
Pid ! {accepted, self()},
start_timer(Tmo, S#state{state = recv_CER});
@@ -376,6 +383,8 @@ transition({diameter, {_, connected}}, _) ->
{stop, connection_timeout};
transition({diameter, {_, connected, _}}, _) ->
{stop, connection_timeout};
+transition({diameter, {_, connected, _, _}}, _) ->
+ {stop, connection_timeout};
%% Connection has timed out: start an alternate.
transition({connection_timeout = T, TPid},
diff --git a/lib/diameter/src/base/diameter_service.erl b/lib/diameter/src/base/diameter_service.erl
index e4d1c60727..112e83476d 100644
--- a/lib/diameter/src/base/diameter_service.erl
+++ b/lib/diameter/src/base/diameter_service.erl
@@ -861,17 +861,21 @@ watchdog(TPid, [], ?WD_SUSPECT, ?WD_OKAY, Wd, State) ->
%% Watchdog has an unresponsive connection.
watchdog(TPid, [], ?WD_OKAY, ?WD_SUSPECT = To, Wd, State) ->
#watchdog{peer = TPid} = Wd, %% assert
- connection_down(Wd, To, State);
+ watchdog_down(Wd, To, State);
%% Watchdog has lost its connection.
watchdog(TPid, [], _, ?WD_DOWN = To, Wd, #state{peerT = PeerT} = S) ->
close(Wd, S),
- connection_down(Wd, To, S),
+ watchdog_down(Wd, To, S),
ets:delete(PeerT, TPid);
watchdog(_, [], _, _, _, _) ->
ok.
+watchdog_down(Wd, To, #state{watchdogT = WatchdogT} = S) ->
+ insert(WatchdogT, Wd#watchdog{state = To}),
+ connection_down(Wd, To, S).
+
%% ---------------------------------------------------------------------------
%% # connection_up/3
%% ---------------------------------------------------------------------------
@@ -1029,21 +1033,17 @@ connection_down(#watchdog{state = ?WD_OKAY,
remove_local_peer(SApps, {{TPid, Caps}, {SvcName, Apps}}, LDict),
diameter_traffic:peer_down(TPid);
-connection_down(#watchdog{}, #peer{}, _) ->
- ok;
-
-connection_down(#watchdog{state = WS,
+connection_down(#watchdog{state = ?WD_OKAY,
peer = TPid}
= Wd,
To,
- #state{watchdogT = WatchdogT,
- peerT = PeerT}
+ #state{peerT = PeerT}
= S)
when is_atom(To) ->
- insert(WatchdogT, Wd#watchdog{state = To}),
- ?WD_OKAY == WS
- andalso
- connection_down(Wd, fetch(PeerT, TPid), S).
+ connection_down(Wd, #peer{} = fetch(PeerT, TPid), S);
+
+connection_down(#watchdog{}, _, _) ->
+ ok.
remove_local_peer(SApps, T, LDict) ->
lists:foldl(fun(A,D) -> rlp(A, T, D) end, LDict, SApps).
diff --git a/lib/diameter/src/transport/diameter_tcp.erl b/lib/diameter/src/transport/diameter_tcp.erl
index 132088b514..cbbba714ac 100644
--- a/lib/diameter/src/transport/diameter_tcp.erl
+++ b/lib/diameter/src/transport/diameter_tcp.erl
@@ -100,6 +100,18 @@
%% # start/3
%% ---------------------------------------------------------------------------
+-spec start({accept, Ref}, Svc, [Opt])
+ -> {ok, pid(), [inet:ip_address()]}
+ when Ref :: diameter:transport_ref(),
+ Svc :: #diameter_service{},
+ Opt :: diameter:transport_opt();
+ ({connect, Ref}, Svc, [Opt])
+ -> {ok, pid(), [inet:ip_address()]}
+ | {ok, pid()}
+ when Ref :: diameter:transport_ref(),
+ Svc :: #diameter_service{},
+ Opt :: diameter:transport_opt().
+
start({T, Ref}, #diameter_service{capabilities = Caps}, Opts) ->
diameter_tcp_sup:start(), %% start tcp supervisors on demand
{Mod, Rest} = split(Opts),
@@ -172,7 +184,7 @@ i({T, Ref, Mod, Pid, Opts, Addrs})
OwnOpts,
?DEFAULT_FRAGMENT_TIMEOUT),
?IS_TIMEOUT(Tmo) orelse ?ERROR({fragment_timer, Tmo}),
- Sock = i(T, Ref, Mod, Pid, SslOpts, Rest, Addrs),
+ Sock = init(T, Ref, Mod, Pid, SslOpts, Rest, Addrs),
MPid ! {stop, self()}, %% tell the monitor to die
M = if SslOpts -> ssl; true -> Mod end,
setopts(M, Sock),
@@ -199,14 +211,21 @@ i(#monitor{parent = Pid, transport = TPid} = S) ->
i({listen, LRef, APid, {Mod, Opts, Addrs}}) ->
{[LA, LP], Rest} = proplists:split(Opts, [ip, port]),
- LAddr = get_addr(LA, Addrs),
+ LAddrOpt = get_addr(LA, Addrs),
LPort = get_port(LP),
- {ok, LSock} = Mod:listen(LPort, gen_opts(LAddr, Rest)),
+ {ok, LSock} = Mod:listen(LPort, gen_opts(LAddrOpt, Rest)),
+ LAddr = laddr(LAddrOpt, Mod, LSock),
true = diameter_reg:add_new({?MODULE, listener, {LRef, {LAddr, LSock}}}),
proc_lib:init_ack({ok, self(), {LAddr, LSock}}),
erlang:monitor(process, APid),
start_timer(#listener{socket = LSock}).
+laddr([], Mod, Sock) ->
+ {ok, {Addr, _Port}} = sockname(Mod, Sock),
+ Addr;
+laddr([{ip, Addr}], _, _) ->
+ Addr.
+
own(Opts) ->
{Own, Rest} = proplists:split(Opts, [fragment_timer]),
{lists:append(Own), Rest}.
@@ -225,17 +244,19 @@ ssl_opts([{ssl_options, Opts}])
ssl_opts(L) ->
?ERROR({ssl_options, L}).
-%% i/7
+%% init/7
%% Establish a TLS connection before capabilities exchange ...
-i(Type, Ref, Mod, Pid, true, Opts, Addrs) ->
- i(Type, Ref, ssl, Pid, [{cb_info, ?TCP_CB(Mod)} | Opts], Addrs);
+init(Type, Ref, Mod, Pid, true, Opts, Addrs) ->
+ init(Type, Ref, ssl, Pid, [{cb_info, ?TCP_CB(Mod)} | Opts], Addrs);
%% ... or not.
-i(Type, Ref, Mod, Pid, _, Opts, Addrs) ->
- i(Type, Ref, Mod, Pid, Opts, Addrs).
+init(Type, Ref, Mod, Pid, _, Opts, Addrs) ->
+ init(Type, Ref, Mod, Pid, Opts, Addrs).
+
+%% init/6
-i(accept = T, Ref, Mod, Pid, Opts, Addrs) ->
+init(accept = T, Ref, Mod, Pid, Opts, Addrs) ->
{LAddr, LSock} = listener(Ref, {Mod, Opts, Addrs}),
proc_lib:init_ack({ok, self(), [LAddr]}),
Sock = ok(accept(Mod, LSock)),
@@ -243,17 +264,28 @@ i(accept = T, Ref, Mod, Pid, Opts, Addrs) ->
diameter_peer:up(Pid),
Sock;
-i(connect = T, Ref, Mod, Pid, Opts, Addrs) ->
+init(connect = T, Ref, Mod, Pid, Opts, Addrs) ->
{[LA, RA, RP], Rest} = proplists:split(Opts, [ip, raddr, rport]),
- LAddr = get_addr(LA, Addrs),
- RAddr = get_addr(RA, []),
+ LAddrOpt = get_addr(LA, Addrs),
+ RAddr = get_addr(RA),
RPort = get_port(RP),
- proc_lib:init_ack({ok, self(), [LAddr]}),
- Sock = ok(connect(Mod, RAddr, RPort, gen_opts(LAddr, Rest))),
+ proc_lib:init_ack(init_rc(LAddrOpt)),
+ Sock = ok(connect(Mod, RAddr, RPort, gen_opts(LAddrOpt, Rest))),
publish(Mod, T, Ref, Sock),
- diameter_peer:up(Pid, {RAddr, RPort}),
+ up(Pid, {RAddr, RPort}, LAddrOpt, Mod, Sock),
Sock.
+init_rc([{ip, Addr}]) ->
+ {ok, self(), [Addr]};
+init_rc([]) ->
+ {ok, self()}.
+
+up(Pid, Remote, [{ip, _Addr}], _, _) ->
+ diameter_peer:up(Pid, Remote);
+up(Pid, Remote, [], Mod, Sock) ->
+ {Addr, _Port} = ok(sockname(Mod, Sock)),
+ diameter_peer:up(Pid, Remote, [Addr]).
+
publish(Mod, T, Ref, Sock) ->
true = diameter_reg:add_new({?MODULE, T, {Ref, Sock}}),
putr(?INFO_KEY, {Mod, Sock}). %% for info/1
@@ -281,10 +313,17 @@ l([], LRef, T) ->
{ok, _, AS} = diameter_tcp_sup:start_child({listen, LRef, self(), T}),
AS.
+%% get_addr/1
+
+get_addr(As) ->
+ diameter_lib:ipaddr(addr(As, [])).
+
%% get_addr/2
+get_addr([], []) ->
+ [];
get_addr(As, Def) ->
- diameter_lib:ipaddr(addr(As, Def)).
+ [{ip, diameter_lib:ipaddr(addr(As, Def))}].
%% Take the first address from the service if several are unspecified.
addr([], [Addr | _]) ->
@@ -305,14 +344,10 @@ get_port(Ps) ->
%% gen_opts/2
-gen_opts(LAddr, Opts) ->
+gen_opts(LAddrOpt, Opts) ->
{L,_} = proplists:split(Opts, [binary, packet, active]),
[[],[],[]] == L orelse ?ERROR({reserved_options, Opts}),
- [binary,
- {packet, 0},
- {active, once},
- {ip, LAddr}
- | Opts].
+ [binary, {packet, 0}, {active, once}] ++ LAddrOpt ++ Opts.
%% ---------------------------------------------------------------------------
%% # ports/1
diff --git a/lib/diameter/test/diameter_capx_SUITE.erl b/lib/diameter/test/diameter_capx_SUITE.erl
index 9e6619ecdd..8c9bb67e61 100644
--- a/lib/diameter/test/diameter_capx_SUITE.erl
+++ b/lib/diameter/test/diameter_capx_SUITE.erl
@@ -444,7 +444,7 @@ connect(Config, T, Opts) ->
{CRef, LRef}.
connect(LRef, Opts) ->
- [PortNr] = ?util:lport(tcp, LRef, 20),
+ [PortNr] = ?util:lport(tcp, LRef),
{ok, CRef} = diameter:add_transport(?CLIENT,
{connect, opts(PortNr, Opts)}),
CRef.
diff --git a/lib/diameter/test/diameter_event_SUITE.erl b/lib/diameter/test/diameter_event_SUITE.erl
index 18bdcb1f54..94b4967921 100644
--- a/lib/diameter/test/diameter_event_SUITE.erl
+++ b/lib/diameter/test/diameter_event_SUITE.erl
@@ -100,7 +100,7 @@ start_server(Config) ->
ok = diameter:start_service(?SERVER, ?SERVICE(?SERVER, [?DICT_COMMON])),
LRef = ?util:listen(?SERVER, tcp, [{capabilities_cb, fun capx_cb/2},
{capx_timeout, ?SERVER_CAPX_TMO}]),
- [PortNr] = ?util:lport(tcp, LRef, 20),
+ [PortNr] = ?util:lport(tcp, LRef),
?util:write_priv(Config, portnr, PortNr),
start = event(?SERVER).
diff --git a/lib/diameter/test/diameter_examples_SUITE.erl b/lib/diameter/test/diameter_examples_SUITE.erl
index 6d797f6911..585fc9d3b8 100644
--- a/lib/diameter/test/diameter_examples_SUITE.erl
+++ b/lib/diameter/test/diameter_examples_SUITE.erl
@@ -283,7 +283,7 @@ start(server) ->
ok = diameter:start(),
ok = server:start(),
{ok, Ref} = server:listen(tcp),
- [_] = ?util:lport(tcp, Ref, 20),
+ [_] = ?util:lport(tcp, Ref),
ok;
start(client) ->
diff --git a/lib/diameter/test/diameter_tls_SUITE.erl b/lib/diameter/test/diameter_tls_SUITE.erl
index 77194a0f56..5a79c63d36 100644
--- a/lib/diameter/test/diameter_tls_SUITE.erl
+++ b/lib/diameter/test/diameter_tls_SUITE.erl
@@ -343,7 +343,7 @@ join(Strs) ->
server(Host, {Caps, Opts}) ->
ok = diameter:start_service(Host, ?SERVICE(Host, ?DICT_COMMON)),
{ok, LRef} = diameter:add_transport(Host, ?LISTEN(Caps, Opts)),
- {LRef, hd([_] = ?util:lport(tcp, LRef, 20))}.
+ {LRef, hd([_] = ?util:lport(tcp, LRef))}.
sopts(?SERVER1, Dir) ->
{inband_security([?TLS]),
diff --git a/lib/diameter/test/diameter_transport_SUITE.erl b/lib/diameter/test/diameter_transport_SUITE.erl
index 893b7ba2f9..97f4cec11f 100644
--- a/lib/diameter/test/diameter_transport_SUITE.erl
+++ b/lib/diameter/test/diameter_transport_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2010-2011. 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
@@ -36,6 +36,7 @@
tcp_connect/1,
sctp_accept/1,
sctp_connect/1,
+ reconnect/1, reconnect/0,
stop/1]).
-export([accept/1,
@@ -54,9 +55,6 @@
-define(RECV(Pat, Ret), receive Pat -> Ret end).
-define(RECV(Pat), ?RECV(Pat, now())).
-%% Or not.
--define(WAIT(Ms), receive after Ms -> now() end).
-
%% Sockets are opened on the loopback address.
-define(ADDR, {127,0,0,1}).
@@ -102,7 +100,8 @@ tc() ->
[tcp_accept,
tcp_connect,
sctp_accept,
- sctp_connect].
+ sctp_connect,
+ reconnect].
init_per_suite(Config) ->
[{sctp, have_sctp()} | Config].
@@ -165,6 +164,90 @@ connect(Prot) ->
[] = ?util:run([{?MODULE, [init, X, T]} || X <- [gen_accept, connect]]).
%% ===========================================================================
+%% reconnect/1
+%%
+%% Exercise reconnection behaviour: that a connecting transport
+%% doesn't try to establish a new connection until the old one is
+%% broken.
+
+reconnect() ->
+ [{timetrap, {minutes, 4}}].
+
+reconnect({listen, Ref}) ->
+ SvcName = make_ref(),
+ ok = start_service(SvcName),
+ LRef = ?util:listen(SvcName, tcp, [{watchdog_timer, 6000}]),
+ [_] = diameter_reg:wait({diameter_tcp, listener, {LRef, '_'}}),
+ true = diameter_reg:add_new({?MODULE, Ref, LRef}),
+
+ %% Wait for partner to request transport death: kill to force the
+ %% peer to reconnect.
+ TPid = abort(SvcName, LRef, Ref),
+
+ exit(TPid, kill),
+
+ abort(SvcName, LRef, Ref);
+
+reconnect({connect, Ref}) ->
+ SvcName = make_ref(),
+ true = diameter:subscribe(SvcName),
+ ok = start_service(SvcName),
+ [{{_, _, LRef}, Pid}] = diameter_reg:wait({?MODULE, Ref, '_'}),
+ CRef = ?util:connect(SvcName, tcp, LRef, [{reconnect_timer, 2000},
+ {watchdog_timer, 6000}]),
+
+ %% Tell partner to kill transport after seeing that there are no
+ %% reconnection attempts.
+ abort(SvcName, Pid, Ref),
+
+ %% Transport does down and is reestablished.
+ ?RECV(#diameter_event{service = SvcName, info = {down, CRef, _, _}}),
+ ?RECV(#diameter_event{service = SvcName, info = {reconnect, CRef, _}}),
+ ?RECV(#diameter_event{service = SvcName, info = {up, CRef, _, _, _}}),
+
+ %% Kill again.
+ abort(SvcName, Pid, Ref),
+
+ %% Wait for partner to die.
+ MRef = erlang:monitor(process, Pid),
+ ?RECV({'DOWN', MRef, process, _, _});
+
+reconnect(_) ->
+ Ref = make_ref(),
+ [] = ?util:run([{?MODULE, [reconnect, {T, Ref}]}
+ || T <- [listen, connect]]).
+
+start_service(SvcName) ->
+ OH = io_lib:format("~p-~p-~p", tuple_to_list(now())),
+ Opts = [{application, [{dictionary, diameter_gen_base_rfc6733},
+ {module, diameter_callback}]},
+ {'Origin-Host', OH},
+ {'Origin-Realm', OH ++ ".org"},
+ {'Vendor-Id', 0},
+ {'Product-Name', "x"},
+ {'Auth-Application-Id', [0]}],
+ diameter:start_service(SvcName, Opts).
+
+abort(SvcName, Pid, Ref)
+ when is_pid(Pid) ->
+ receive
+ #diameter_event{service = SvcName, info = {reconnect, _, _}} = E ->
+ erlang:error(E)
+ after 45000 ->
+ ok
+ end,
+ Pid ! {abort, Ref};
+
+abort(SvcName, LRef, Ref)
+ when is_reference(LRef) ->
+ ?RECV({abort, Ref}),
+ [[{ref, LRef}, {type, listen}, {options, _}, {accept, [_,_] = Ts} | _]]
+ %% assert on two accepting
+ = diameter:service_info(SvcName, transport),
+ [TPid] = [P || [{watchdog, {_,_,okay}}, {peer, {P,_}} | _] <- Ts],
+ TPid.
+
+%% ===========================================================================
%% ===========================================================================
%% have_sctp/0
@@ -209,7 +292,7 @@ init(accept, {Prot, Ref}) ->
init(gen_connect, {Prot, Ref}) ->
%% Lookup the peer's listening socket.
- [PortNr] = ?util:lport(Prot, Ref, 20),
+ [PortNr] = ?util:lport(Prot, Ref),
%% Connect, send a message and receive it back.
{ok, Sock} = gen_connect(Prot, PortNr),
@@ -230,7 +313,8 @@ init(gen_accept, {Prot, Ref}) ->
init(connect, {Prot, Ref}) ->
%% Lookup the peer's listening socket.
- [{?TEST_LISTENER(_, PortNr), _}] = match(?TEST_LISTENER(Ref, '_')),
+ [{?TEST_LISTENER(_, PortNr), _}]
+ = diameter_reg:wait(?TEST_LISTENER(Ref, '_')),
%% Start a connecting transport and receive notification of
%% the connection.
@@ -246,18 +330,6 @@ init(connect, {Prot, Ref}) ->
MRef = erlang:monitor(process, TPid),
?RECV({'DOWN', MRef, process, _, _}).
-match(Pat) ->
- match(Pat, 20).
-
-match(Pat, T) ->
- L = diameter_reg:match(Pat),
- if [] /= L orelse 1 == T ->
- L;
- true ->
- ?WAIT(50),
- match(Pat, T-1)
- end.
-
bin(sctp, #diameter_packet{bin = Bin}) ->
Bin;
bin(tcp, Bin) ->
@@ -310,22 +382,18 @@ start_connect(tcp, T, Svc, Opts) ->
%% start_accept/2
%%
%% Start transports sequentially by having each wait for a message
-%% from a job in a queue before commencing. Only one transport with
-%% a pending accept is started at a time since diameter_sctp currently
-%% assumes (and diameter currently implements) this.
+%% from a job in a queue before commencing. Only one transport with a
+%% pending accept is started at a time since diameter_{tcp,sctp}
+%% currently assume (and diameter currently implements) this.
start_accept(Prot, Ref) ->
Pid = sync(accept, Ref),
-
- %% Configure the same port number for transports on the same
- %% reference.
- [PortNr | _] = ?util:lport(Prot, Ref) ++ [0],
{Mod, Opts} = tmod(Prot),
try
{ok, TPid, [?ADDR]} = Mod:start({accept, Ref},
?SVC([?ADDR]),
- [{port, PortNr} | Opts]),
+ [{port, 0} | Opts]),
?RECV(?TMSG({TPid, connected})),
TPid
after
diff --git a/lib/diameter/test/diameter_util.erl b/lib/diameter/test/diameter_util.erl
index a9872f32e1..aa489fef5f 100644
--- a/lib/diameter/test/diameter_util.erl
+++ b/lib/diameter/test/diameter_util.erl
@@ -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
@@ -33,7 +33,6 @@
%% diameter-specific
-export([lport/2,
- lport/3,
listen/2, listen/3,
connect/3, connect/4,
disconnect/4,
@@ -251,27 +250,17 @@ path(Config, Name) ->
filename:join([Dir, Name]).
%% ---------------------------------------------------------------------------
-%% lport/2-3
+%% lport/2
%%
%% Lookup the port number of a tcp/sctp listening transport.
-lport(M, Ref) ->
- lport(M, Ref, 1).
+lport(M, {Node, Ref}) ->
+ rpc:call(Node, ?MODULE, lport, [M, Ref]);
-lport(M, {Node, Ref}, Tries) ->
- rpc:call(Node, ?MODULE, lport, [M, Ref, Tries]);
-
-lport(M, Ref, Tries) ->
- lp(tmod(M), Ref, Tries).
-
-lp(M, Ref, T) ->
- L = [N || {listen, N, _} <- M:ports(Ref)],
- if [] /= L orelse T =< 1 ->
- L;
- true ->
- receive after 50 -> ok end,
- lp(M, Ref, T-1)
- end.
+lport(Prot, Ref) ->
+ Mod = tmod(Prot),
+ [_] = diameter_reg:wait({'_', listener, {Ref, '_'}}),
+ [N || {listen, N, _} <- Mod:ports(Ref)].
%% ---------------------------------------------------------------------------
%% listen/2-3
@@ -297,7 +286,7 @@ connect(Client, Prot, LRef) ->
connect(Client, Prot, LRef, []).
connect(Client, Prot, LRef, Opts) ->
- [PortNr] = lport(Prot, LRef, 20),
+ [PortNr] = lport(Prot, LRef),
Client = diameter:service_info(Client, name), %% assert
true = diameter:subscribe(Client),
Ref = add_transport(Client, {connect, opts(Prot, PortNr) ++ Opts}),
diff --git a/lib/diameter/test/diameter_watchdog_SUITE.erl b/lib/diameter/test/diameter_watchdog_SUITE.erl
index 704bf110c7..b6e8730ec2 100644
--- a/lib/diameter/test/diameter_watchdog_SUITE.erl
+++ b/lib/diameter/test/diameter_watchdog_SUITE.erl
@@ -524,7 +524,7 @@ cfg(listen, _) ->
cfg(connect, Ref) ->
[{{_, _, SvcName}, _Pid}] = diameter_reg:wait({listen, Ref, '_'}),
[[{ref, LRef} | _]] = diameter:service_info(SvcName, transport),
- [LP] = ?util:lport(tcp, LRef, 20),
+ [LP] = ?util:lport(tcp, LRef),
[{raddr, ?ADDR}, {rport, LP}].
%% ===========================================================================
diff --git a/lib/et/doc/src/et_desc.xmlsrc b/lib/et/doc/src/et_desc.xmlsrc
index c02517ae01..36274f6316 100644
--- a/lib/et/doc/src/et_desc.xmlsrc
+++ b/lib/et/doc/src/et_desc.xmlsrc
@@ -150,7 +150,7 @@
NewEvent = #event{}]]></code>
<p>The interface of the filter function is the same as the the
- filter functions for the good old <c>lists:zf/2</c>. If the filter
+ filter functions for the good old <c>lists:filtermap/2</c>. If the filter
returns <c>false</c> it means that the trace data should silently
be dropped. <c>true</c> means that the trace data data already is
an <c>Event Record</c> and that it should be kept as it is.
diff --git a/lib/et/src/et_collector.erl b/lib/et/src/et_collector.erl
index a63d15fb4c..ce8cf6d4e0 100644
--- a/lib/et/src/et_collector.erl
+++ b/lib/et/src/et_collector.erl
@@ -654,13 +654,8 @@ start_trace_client(CollectorPid, Type, FileName) when Type =:= file ->
Ref = erlang:monitor(process, Pid),
receive
WaitFor ->
- erlang:demonitor(Ref),
- receive
- {'DOWN', Ref, _, _, _} ->
- file_loaded
- after 0 ->
- file_loaded
- end;
+ erlang:demonitor(Ref, [flush]),
+ file_loaded;
{'DOWN', Ref, _, _, Reason} ->
exit(Reason)
end;
diff --git a/lib/hipe/icode/hipe_icode_coordinator.erl b/lib/hipe/icode/hipe_icode_coordinator.erl
index d8c82cf01c..79e3304e6f 100644
--- a/lib/hipe/icode/hipe_icode_coordinator.erl
+++ b/lib/hipe/icode/hipe_icode_coordinator.erl
@@ -2,7 +2,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2007-2011. 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
@@ -36,18 +36,16 @@
%%---------------------------------------------------------------------
--spec coordinate(hipe_digraph:hdg(), [{mfa(),boolean()}], [mfa()], module()) ->
+-spec coordinate(hipe_digraph:hdg(), [mfa()], [mfa()], module()) ->
no_return().
coordinate(CG, Escaping, NonEscaping, Mod) ->
ServerPid = initialize_server(Escaping, Mod),
- Clean = [MFA || {MFA, _} <- Escaping],
- All = NonEscaping ++ Clean,
- Restart =
- fun (MFALists, PM) -> restart_funs(MFALists, PM, All, ServerPid) end,
- LastAction =
- fun (PM) -> last_action(PM, ServerPid, Mod, All) end,
- coordinate({Clean,All}, CG, gb_trees:empty(), Restart, LastAction, ServerPid).
+ All = ordsets:from_list(Escaping ++ NonEscaping),
+ Restart = fun (MFALs, PM) -> restart_funs(MFALs, PM, All, ServerPid) end,
+ LastAction = fun (PM) -> last_action(PM, ServerPid, Mod, All) end,
+ MFALists = {Escaping, All},
+ coordinate(MFALists, CG, gb_trees:empty(), Restart, LastAction, ServerPid).
-type mfalists() :: {[mfa()], [mfa()]}.
@@ -129,7 +127,7 @@ restart_funs({Queue, Busy} = QB, PM, All, ServerPid) ->
initialize_server(Escaping, Mod) ->
Pid = spawn_link(fun () -> info_server(Mod) end),
- lists:foreach(fun ({MFA, _}) -> Pid ! {set_escaping, MFA} end, Escaping),
+ lists:foreach(fun (MFA) -> Pid ! {set_escaping, MFA} end, Escaping),
Pid.
safe_get_args(MFA, Cfg, Pid, Mod) ->
diff --git a/lib/hipe/main/hipe.erl b/lib/hipe/main/hipe.erl
index 6e00b13292..434d5c3061 100644
--- a/lib/hipe/main/hipe.erl
+++ b/lib/hipe/main/hipe.erl
@@ -2,7 +2,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2001-2012. All Rights Reserved.
+%% Copyright Ericsson AB 2001-2013. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -242,8 +242,7 @@
%%
%% @see load/2
--spec load(Mod) -> {'module', Mod} | {'error', term()}
- when is_subtype(Mod, mod()).
+-spec load(Mod) -> {'module', Mod} | {'error', term()} when Mod :: mod().
load(Mod) ->
load(Mod, beam_file(Mod)).
@@ -265,7 +264,7 @@ load(Mod) ->
%% @see load/1
-spec load(Mod, string()) -> {'module', Mod} | {'error', term()}
- when is_subtype(Mod, mod()).
+ when Mod :: mod().
load(Mod, BeamFileName) when is_list(BeamFileName) ->
Architecture = erlang:system_info(hipe_architecture),
@@ -522,7 +521,7 @@ compile(Name, Core, File, Opts) when is_atom(Name) ->
%% @equiv file(File, [])
-spec file(Mod) -> {'ok', Mod, compile_ret()} | {'error', term()}
- when is_subtype(Mod, mod()).
+ when Mod :: mod().
file(File) ->
file(File, []).
@@ -542,7 +541,7 @@ file(File) ->
-spec file(Mod, comp_options()) -> {'ok', Mod, compile_ret()}
| {'error', term()}
- when is_subtype(Mod, mod()).
+ when Mod :: mod().
file(File, Options) when is_atom(File) ->
case beam_lib:info(File) of
L when is_list(L) ->
@@ -760,13 +759,15 @@ finalize_fun_concurrent(MfaIcodeList, Exports, Opts) ->
case MfaIcodeList of
[{{M,_,_},_}|_] ->
CallGraph = hipe_icode_callgraph:construct_callgraph(MfaIcodeList),
- Closures = [{MFA, true} || {MFA, Icode} <- MfaIcodeList,
- hipe_icode:icode_is_closure(Icode)],
- Exported = [{{M, F, A}, false} || {F, A} <- Exports],
+ Exported = [{M, F, A} || {F, A} <- Exports],
+ Closures = [MFA || {MFA, Icode} <- MfaIcodeList,
+ hipe_icode:icode_is_closure(Icode)],
+ %% In principle, a function could both be exported and used as a
+ %% closure so make sure to add it only once in Escaping below
+ Escaping = ordsets:from_list(Exported ++ Closures),
NonEscaping = [MFA || {{_M, F, A} = MFA, Icode} <- MfaIcodeList,
not lists:member({F, A}, Exports),
not hipe_icode:icode_is_closure(Icode)],
- Escaping = Closures ++ Exported,
TypeServerFun =
fun() ->
hipe_icode_coordinator:coordinate(CallGraph, Escaping,
diff --git a/lib/ic/java_src/com/ericsson/otp/ic/Environment.java b/lib/ic/java_src/com/ericsson/otp/ic/Environment.java
index fff854a5f8..4b321fbce7 100644
--- a/lib/ic/java_src/com/ericsson/otp/ic/Environment.java
+++ b/lib/ic/java_src/com/ericsson/otp/ic/Environment.java
@@ -135,8 +135,8 @@ public class Environment {
if (connection == null)
connection = self.connect(peer);
- clientP = new com.ericsson.otp.erlang.OtpErlangPid(self); /* This is not perfect */
- send_ref = new com.ericsson.otp.erlang.OtpErlangRef(self);
+ clientP = self.createPid(); /* This is not perfect */
+ send_ref = self.createRef();
}
diff --git a/lib/ic/src/icparse.yrl b/lib/ic/src/icparse.yrl
index d0dd6cde4c..b0286d57f4 100644
--- a/lib/ic/src/icparse.yrl
+++ b/lib/ic/src/icparse.yrl
@@ -230,6 +230,9 @@ Terminals
Rootsymbol '<specification>'.
+Expect 9.
+
+
%%------------------------------------------------------------
%% Clauses
%%
diff --git a/lib/inets/src/http_server/httpd_manager.erl b/lib/inets/src/http_server/httpd_manager.erl
index 672a70a394..c83d06a158 100644
--- a/lib/inets/src/http_server/httpd_manager.erl
+++ b/lib/inets/src/http_server/httpd_manager.erl
@@ -691,11 +691,11 @@ handle_unblock(S, FromA) ->
handle_unblock(S, _FromA, unblocked) ->
{ok,S};
handle_unblock(S, FromA, _AdminState) ->
- stop_block_tmr(S#state.blocking_tmr),
case S#state.blocking_tmr of
- {_Tmr,FromB,Ref} ->
+ {Tmr,FromB,Ref} ->
%% Another process is trying to unblock
%% Inform the blocker
+ stop_block_tmr(Tmr),
FromB ! {block_reply, {error,{unblocked,FromA}},Ref};
_ ->
ok
diff --git a/lib/jinterface/test/jinterface_SUITE.erl b/lib/jinterface/test/jinterface_SUITE.erl
index b438da12d0..de8d611efc 100644
--- a/lib/jinterface/test/jinterface_SUITE.erl
+++ b/lib/jinterface/test/jinterface_SUITE.erl
@@ -180,7 +180,7 @@ init_per_testcase(Case, _Config)
Case =:= kill_mbox_from_erlang ->
{skip, "Not yet implemented"};
init_per_testcase(_Case,Config) ->
- Dog = ?t:timetrap({seconds,10}),
+ Dog = ?t:timetrap({seconds,30}),
[{watch_dog,Dog}|Config].
end_per_testcase(_Case,Config) ->
@@ -188,6 +188,7 @@ end_per_testcase(_Case,Config) ->
undefined -> ok;
Pid -> exit(Pid,kill)
end,
+ jitu:kill_all_jnodes(),
?t:timetrap_cancel(?config(watch_dog,Config)),
ok.
diff --git a/lib/jinterface/test/jitu.erl b/lib/jinterface/test/jitu.erl
index 0e1af0ff22..a029c063bc 100644
--- a/lib/jinterface/test/jitu.erl
+++ b/lib/jinterface/test/jitu.erl
@@ -27,7 +27,10 @@
java/4,
java/5,
init_all/1,
- finish_all/1]).
+ finish_all/1,
+ kill_all_jnodes/0]).
+
+-include("ct.hrl").
%%
%% Lots of stuff here are originating from java_client_erl_server_SUITE.erl
@@ -51,10 +54,33 @@ java(Java, Dir, Class, Args, Props) ->
init_all(Config) when is_list(Config) ->
case find_executable(["java"]) of
false -> {skip,"Found no Java VM"};
- Path -> [{java,Path}|Config]
+ Path ->
+ Pid = spawn(fun() ->
+ ets:new(jitu_tab,[set,named_table,public]),
+ receive stop -> ets:delete(jitu_tab) end
+ end),
+ [{java,Path},{tab_proc,Pid}|Config]
end.
-finish_all(Config) -> Config.
+finish_all(Config) ->
+ kill_all_jnodes(),
+ ?config(tab_proc,Config) ! stop,
+ Config.
+
+kill_all_jnodes() ->
+ Jnodes = ets:tab2list(jitu_tab),
+ [begin
+% ct:pal("Killing OsPid=~w started with ~p",[OsPid,_Cmd]),
+ kill_os_process(os:type(),integer_to_list(OsPid))
+ end || {OsPid,_Cmd} <- Jnodes],
+ ets:delete_all_objects(jitu_tab),
+ ok.
+
+kill_os_process({win32,_},OsPid) ->
+ os:cmd("taskkill /PID " ++ OsPid);
+kill_os_process(_,OsPid) ->
+ os:cmd("kill " ++ OsPid).
+
%%
%% Internal stuff...
@@ -110,6 +136,12 @@ cmd(Cmd) ->
io:format("cmd: ~s~n", [Cmd]),
case catch open_port({spawn,Cmd}, PortOpts) of
Port when is_port(Port) ->
+ case erlang:port_info(Port,os_pid) of
+ {os_pid,OsPid} ->
+ ets:insert(jitu_tab,{OsPid,Cmd});
+ _ ->
+ ok
+ end,
Result = cmd_loop(Port, []),
io:format("cmd res: ~w~n", [Result]),
case Result of
diff --git a/lib/jinterface/test/nc_SUITE.erl b/lib/jinterface/test/nc_SUITE.erl
index 63c78ebdaa..f1493a3cc9 100644
--- a/lib/jinterface/test/nc_SUITE.erl
+++ b/lib/jinterface/test/nc_SUITE.erl
@@ -105,12 +105,13 @@ end_per_suite(Config) ->
init_per_testcase(Case, Config) ->
T = case atom_to_list(Case) of
"unicode"++_ -> 240;
- _ -> 30
+ _ -> 120
end,
WatchDog = test_server:timetrap(test_server:seconds(T)),
[{watchdog, WatchDog}| Config].
end_per_testcase(_Case, Config) ->
+ jitu:kill_all_jnodes(),
WatchDog = ?config(watchdog, Config),
test_server:timetrap_cancel(WatchDog).
@@ -695,15 +696,18 @@ run_server(Server, Config, Action, ExtraArgs) ->
true = register(Name, self()),
JName = make_name(),
spawn_link(fun () ->
+ %% Setting max memory to 256. This is due to
+ %% echo_server sometimes failing with
+ %% OutOfMemoryException one some test machines.
ok = jitu:java(?config(java, Config),
?config(data_dir, Config),
atom_to_list(Server),
[JName,
erlang:get_cookie(),
node(),
- Name]++ExtraArgs
- ),
- %,"-DOtpConnection.trace=3"),
+ Name]++ExtraArgs,
+ " -Xmx256m"),
+ %% " -Xmx256m -DOtpConnection.trace=3"),
Name ! {done, JName}
end),
receive
diff --git a/lib/kernel/src/application_master.erl b/lib/kernel/src/application_master.erl
index 679fefaed9..34a3efcaf2 100644
--- a/lib/kernel/src/application_master.erl
+++ b/lib/kernel/src/application_master.erl
@@ -76,13 +76,8 @@ call(AppMaster, Req) ->
{'DOWN', Ref, process, _, _Info} ->
ok;
{Tag, Res} ->
- erlang:demonitor(Ref),
- receive
- {'DOWN', Ref, process, _, _Info} ->
- Res
- after 0 ->
- Res
- end
+ erlang:demonitor(Ref, [flush]),
+ Res
end.
%%%-----------------------------------------------------------------
diff --git a/lib/kernel/src/disk_log.erl b/lib/kernel/src/disk_log.erl
index 0c5af2857e..c238eff12f 100644
--- a/lib/kernel/src/disk_log.erl
+++ b/lib/kernel/src/disk_log.erl
@@ -1914,13 +1914,8 @@ multi_req(Msg, Pids) ->
{'DOWN', Ref, process, Pid, _Info} ->
Reply;
{disk_log, Pid, _Reply} ->
- erlang:demonitor(Ref),
- receive
- {'DOWN', Ref, process, Pid, _Reason} ->
- ok
- after 0 ->
- ok
- end
+ erlang:demonitor(Ref, [flush]),
+ ok
end
end, {error, nonode}, Refs).
@@ -1965,13 +1960,8 @@ monitor_request(Pid, Req) ->
{error, no_such_log};
{disk_log, Pid, Reply} when not is_tuple(Reply) orelse
element(2, Reply) =/= disk_log_stopped ->
- erlang:demonitor(Ref),
- receive
- {'DOWN', Ref, process, Pid, _Reason} ->
- Reply
- after 0 ->
- Reply
- end
+ erlang:demonitor(Ref, [flush]),
+ Reply
end.
req2(Pid, R) ->
diff --git a/lib/kernel/src/file.erl b/lib/kernel/src/file.erl
index a4c56b346f..36289053eb 100644
--- a/lib/kernel/src/file.erl
+++ b/lib/kernel/src/file.erl
@@ -480,8 +480,7 @@ open(Item, Mode) ->
Reason :: posix() | badarg | terminated.
close(File) when is_pid(File) ->
- R = file_request(File, close),
- case wait_file_reply(File, R) of
+ case file_request(File, close) of
{error, terminated} ->
ok;
Other ->
@@ -503,8 +502,7 @@ close(_) ->
Reason :: posix() | badarg.
advise(File, Offset, Length, Advise) when is_pid(File) ->
- R = file_request(File, {advise, Offset, Length, Advise}),
- wait_file_reply(File, R);
+ file_request(File, {advise, Offset, Length, Advise});
advise(#file_descriptor{module = Module} = Handle, Offset, Length, Advise) ->
Module:advise(Handle, Offset, Length, Advise);
advise(_, _, _, _) ->
@@ -517,8 +515,7 @@ advise(_, _, _, _) ->
Length :: non_neg_integer().
allocate(File, Offset, Length) when is_pid(File) ->
- R = file_request(File, {allocate, Offset, Length}),
- wait_file_reply(File, R);
+ file_request(File, {allocate, Offset, Length});
allocate(#file_descriptor{module = Module} = Handle, Offset, Length) ->
Module:allocate(Handle, Offset, Length).
@@ -601,8 +598,7 @@ pread_int(_, _, _) ->
Reason :: posix() | badarg | terminated.
pread(File, At, Sz) when is_pid(File), is_integer(Sz), Sz >= 0 ->
- R = file_request(File, {pread, At, Sz}),
- wait_file_reply(File, R);
+ file_request(File, {pread, At, Sz});
pread(#file_descriptor{module = Module} = Handle, Offs, Sz)
when is_integer(Sz), Sz >= 0 ->
Module:pread(Handle, Offs, Sz);
@@ -658,8 +654,7 @@ pwrite_int(_, _, _) ->
Reason :: posix() | badarg | terminated.
pwrite(File, At, Bytes) when is_pid(File) ->
- R = file_request(File, {pwrite, At, Bytes}),
- wait_file_reply(File, R);
+ file_request(File, {pwrite, At, Bytes});
pwrite(#file_descriptor{module = Module} = Handle, Offs, Bytes) ->
Module:pwrite(Handle, Offs, Bytes);
pwrite(_, _, _) ->
@@ -670,8 +665,7 @@ pwrite(_, _, _) ->
Reason :: posix() | badarg | terminated.
datasync(File) when is_pid(File) ->
- R = file_request(File, datasync),
- wait_file_reply(File, R);
+ file_request(File, datasync);
datasync(#file_descriptor{module = Module} = Handle) ->
Module:datasync(Handle);
datasync(_) ->
@@ -682,8 +676,7 @@ datasync(_) ->
Reason :: posix() | badarg | terminated.
sync(File) when is_pid(File) ->
- R = file_request(File, sync),
- wait_file_reply(File, R);
+ file_request(File, sync);
sync(#file_descriptor{module = Module} = Handle) ->
Module:sync(Handle);
sync(_) ->
@@ -696,8 +689,7 @@ sync(_) ->
Reason :: posix() | badarg | terminated.
position(File, At) when is_pid(File) ->
- R = file_request(File, {position,At}),
- wait_file_reply(File, R);
+ file_request(File, {position,At});
position(#file_descriptor{module = Module} = Handle, At) ->
Module:position(Handle, At);
position(_, _) ->
@@ -708,8 +700,7 @@ position(_, _) ->
Reason :: posix() | badarg | terminated.
truncate(File) when is_pid(File) ->
- R = file_request(File, truncate),
- wait_file_reply(File, R);
+ file_request(File, truncate);
truncate(#file_descriptor{module = Module} = Handle) ->
Module:truncate(Handle);
truncate(_) ->
@@ -1497,25 +1488,19 @@ check_args([]) ->
ok.
%%-----------------------------------------------------------------
-%% Functions for communicating with a file io server.
+%% Function for communicating with a file io server.
%% The messages sent have the following formats:
%%
%% {file_request,From,ReplyAs,Request}
%% {file_reply,ReplyAs,Reply}
file_request(Io, Request) ->
- R = erlang:monitor(process, Io),
- Io ! {file_request,self(),Io,Request},
- R.
-
-wait_file_reply(From, Ref) ->
+ Ref = erlang:monitor(process, Io),
+ Io ! {file_request,self(),Ref,Request},
receive
- {file_reply,From,Reply} ->
- erlang:demonitor(Ref),
- receive {'DOWN', Ref, _, _, _} -> ok after 0 -> ok end,
- %% receive {'EXIT', From, _} -> ok after 0 -> ok end,
+ {file_reply,Ref,Reply} ->
+ erlang:demonitor(Ref, [flush]),
Reply;
{'DOWN', Ref, _, _, _} ->
- %% receive {'EXIT', From, _} -> ok after 0 -> ok end,
{error, terminated}
end.
diff --git a/lib/kernel/src/file_io_server.erl b/lib/kernel/src/file_io_server.erl
index fad2ed7fb3..07fb55f390 100644
--- a/lib/kernel/src/file_io_server.erl
+++ b/lib/kernel/src/file_io_server.erl
@@ -92,8 +92,7 @@ do_start(Spawn, Owner, FileName, ModeList) ->
Mref = erlang:monitor(process, Pid),
receive
{Ref, {error, _Reason} = Error} ->
- erlang:demonitor(Mref),
- receive {'DOWN', Mref, _, _, _} -> ok after 0 -> ok end,
+ erlang:demonitor(Mref, [flush]),
Error;
{Ref, ok} ->
erlang:demonitor(Mref),
diff --git a/lib/kernel/src/file_server.erl b/lib/kernel/src/file_server.erl
index 49ec6f96cc..d036dbb516 100644
--- a/lib/kernel/src/file_server.erl
+++ b/lib/kernel/src/file_server.erl
@@ -317,8 +317,7 @@ do_start_slave(start, Filer, Name) ->
SlaveMonitor = erlang:monitor(process, Slave),
receive
{started, Token} ->
- erlang:demonitor(SlaveMonitor),
- receive {'DOWN', SlaveMonitor, _, _, _} -> ok after 0 -> ok end,
+ erlang:demonitor(SlaveMonitor, [flush]),
{ok, Slave};
{'DOWN', SlaveMonitor, _, _, Reason} ->
exit(Reason)
diff --git a/lib/kernel/src/inet_gethost_native.erl b/lib/kernel/src/inet_gethost_native.erl
index db3e44ce6f..df866660b4 100644
--- a/lib/kernel/src/inet_gethost_native.erl
+++ b/lib/kernel/src/inet_gethost_native.erl
@@ -503,8 +503,7 @@ getit(Req, DefaultName) ->
Pid, Reason} ->
{error, Reason}
end,
- catch erlang:demonitor(Ref2),
- receive {'DOWN',Ref2,_,_,_} -> ok after 0 -> ok end,
+ catch erlang:demonitor(Ref2, [flush]),
Res2
end.
diff --git a/lib/kernel/src/rpc.erl b/lib/kernel/src/rpc.erl
index 7c965ca384..83e0b59cc2 100644
--- a/lib/kernel/src/rpc.erl
+++ b/lib/kernel/src/rpc.erl
@@ -388,13 +388,8 @@ server_call(Node, Name, ReplyWrapper, Msg)
{'DOWN', Ref, _, _, _} ->
{error, nodedown};
{ReplyWrapper, Node, Reply} ->
- erlang:demonitor(Ref),
- receive
- {'DOWN', Ref, _, _, _} ->
- Reply
- after 0 ->
- Reply
- end
+ erlang:demonitor(Ref, [flush]),
+ Reply
end
end.
@@ -501,17 +496,6 @@ start_monitor(Node, Name) ->
{Node,erlang:monitor(process, {Name, Node})}
end.
-%% Cancels a monitor started with Ref=erlang:monitor(_, _),
-%% i.e return value {Node, Ref} from start_monitor/2 above.
-unmonitor(Ref) when is_reference(Ref) ->
- erlang:demonitor(Ref),
- receive
- {'DOWN', Ref, _, _, _} ->
- true
- after 0 ->
- true
- end.
-
%% Call apply(M,F,A) on all nodes in parallel
-spec multicall(Module, Function, Args) -> {ResL, BadNodes} when
@@ -635,10 +619,10 @@ rec_nodes(Name, [{N,R} | Tail], Badnodes, Replies) ->
rec_nodes(Name, Tail, [N|Badnodes], Replies);
{?NAME, N, {nonexisting_name, _}} ->
%% used by sbcast()
- unmonitor(R),
+ erlang:demonitor(R, [flush]),
rec_nodes(Name, Tail, [N|Badnodes], Replies);
{Name, N, Reply} -> %% Name is bound !!!
- unmonitor(R),
+ erlang:demonitor(R, [flush]),
rec_nodes(Name, Tail, Badnodes, [Reply|Replies])
end.
diff --git a/lib/kernel/test/file_SUITE.erl b/lib/kernel/test/file_SUITE.erl
index c604e7073f..4218cfa646 100644
--- a/lib/kernel/test/file_SUITE.erl
+++ b/lib/kernel/test/file_SUITE.erl
@@ -91,6 +91,8 @@
-export([standard_io/1,mini_server/1]).
+-export([old_io_protocol/1]).
+
%% Debug exports
-export([create_file_slow/2, create_file/2, create_bin/2]).
-export([verify_file/2, verify_bin/3]).
@@ -114,7 +116,7 @@ all() ->
delayed_write, read_ahead, segment_read, segment_write,
ipread, pid2name, interleaved_read_write, otp_5814, otp_10852,
large_file, large_write, read_line_1, read_line_2, read_line_3,
- read_line_4, standard_io].
+ read_line_4, standard_io, old_io_protocol].
groups() ->
[{dirs, [], [make_del_dir, cur_dir_0, cur_dir_1,
@@ -310,6 +312,31 @@ standard_io(Config) when is_list(Config) ->
Pid ! die,
receive after 1000 -> ok end.
+old_io_protocol(suite) ->
+ [];
+old_io_protocol(doc) ->
+ ["Test that the old file IO protocol =< R16B still works"];
+old_io_protocol(Config) when is_list(Config) ->
+ Dog = test_server:timetrap(test_server:seconds(5)),
+ RootDir = ?config(priv_dir,Config),
+ Name = filename:join(RootDir,
+ atom_to_list(?MODULE)
+ ++"old_io_protocol.fil"),
+ MyData = "0123456789abcdefghijklmnopqrstuvxyz",
+ ok = ?FILE_MODULE:write_file(Name, MyData),
+ {ok, Fd} = ?FILE_MODULE:open(Name, write),
+ Fd ! {file_request,self(),Fd,truncate},
+ receive
+ {file_reply,Fd,ok} -> ok
+ end,
+ ok = ?FILE_MODULE:close(Fd),
+ {ok, <<>>} = ?FILE_MODULE:read_file(Name),
+ test_server:timetrap_cancel(Dog),
+ [] = flush(),
+ ok.
+
+
+
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
read_write_file(suite) -> [];
diff --git a/lib/kernel/test/gen_sctp_SUITE.erl b/lib/kernel/test/gen_sctp_SUITE.erl
index 2a886b2efc..c5d8becfd3 100644
--- a/lib/kernel/test/gen_sctp_SUITE.erl
+++ b/lib/kernel/test/gen_sctp_SUITE.erl
@@ -1399,8 +1399,7 @@ s_req(S, Req) ->
{'DOWN',Mref,_,_,Error} ->
exit(Error);
{S,Mref,Reply} ->
- erlang:demonitor(Mref),
- receive {'DOWN',Mref,_,_,_} -> ok after 0 -> ok end,
+ erlang:demonitor(Mref, [flush]),
Reply
end.
diff --git a/lib/kernel/test/global_SUITE_data/global_trace.erl b/lib/kernel/test/global_SUITE_data/global_trace.erl
index 4f253baac4..ddbe608c0a 100644
--- a/lib/kernel/test/global_SUITE_data/global_trace.erl
+++ b/lib/kernel/test/global_SUITE_data/global_trace.erl
@@ -1,3 +1,4 @@
+%% -*- coding: utf-8 -*-
%%
%% %CopyrightBegin%
%%
@@ -122,12 +123,12 @@ state(Else) ->
%%% {ops,Ops}]
%%% NewKnown = Known ++ AddedNodes
%%% AddedNodes = NewNodes -- Known
-%%% NewNodes �r h�r den man f�rhandlat med plus de noder den k�nner till.
+%%% NewNodes är här den man förhandlat med plus de noder den känner till.
%%% {added, AddedNodes}, Extra = [{ops,Ops}]
%%% NewKnown = Known ++ AddedNodes
-%%% Den (passiva) noden f�r Nodes som �r NewNodes
-%%% hos den f�rhandlande. Sedan: AddedNodes = (Nodes -- Known) -- [node()].
-%%% Det �r som hos f�rhandlaren.
+%%% Den (passiva) noden får Nodes som är NewNodes
+%%% hos den förhandlande. Sedan: AddedNodes = (Nodes -- Known) -- [node()].
+%%% Det är som hos förhandlaren.
%%% {nodes_changed, {New,Old}}
%%% Every now and then the list [node() | nodes()] is checked for updates.
%%% New are the nodes that global does not know of (yet).
diff --git a/lib/orber/src/orber_iiop_outproxy.erl b/lib/orber/src/orber_iiop_outproxy.erl
index 879af8222d..9c4e603753 100644
--- a/lib/orber/src/orber_iiop_outproxy.erl
+++ b/lib/orber/src/orber_iiop_outproxy.erl
@@ -69,13 +69,8 @@ request(Pid, true, Timeout, Msg, RequestId) ->
gen_server:cast(Pid, {request, Timeout, Msg, RequestId, self(), MRef}),
receive
{MRef, Reply} ->
- erlang:demonitor(MRef),
- receive
- {'DOWN', MRef, _, _, _} ->
- Reply
- after 0 ->
- Reply
- end;
+ erlang:demonitor(MRef, [flush]),
+ Reply;
{'DOWN', MRef, _, Pid, _Reason} when is_pid(Pid) ->
receive
%% Clear EXIT message from queue
@@ -444,13 +439,7 @@ collect_fragments(GIOPHdr1, InBuffer, Bytes, Proxy, RequestId, MRef) ->
%% the reply and send it to the client.
{fragment, #giop_message{byte_order = ByteOrder,
message = Message} = GIOPHdr2, RequestId, MRef} ->
- erlang:demonitor(MRef),
- receive
- {'DOWN', MRef, _, _, _} ->
- ok
- after 0 ->
- ok
- end,
+ erlang:demonitor(MRef, [flush]),
case catch cdr_decode:dec_message_header(null, GIOPHdr2, Message) of
{_, #fragment_header{}, FragBody, _, _} ->
%% This buffer is all the fragments concatenated.
@@ -484,13 +473,8 @@ Unable to decode Reply or LocateReply header",[?LINE, NewGIOP, Error], ?DEBUG_LE
{MRef, {'EXCEPTION', E}} ->
orber:dbg("[~p] orber_iiop:collect_fragments(~p);",
[?LINE, E], ?DEBUG_LEVEL),
- erlang:demonitor(MRef),
- receive
- {'DOWN', MRef, _, _, _} ->
- corba:raise(E)
- after 0 ->
- corba:raise(E)
- end;
+ erlang:demonitor(MRef, [flush]),
+ corba:raise(E);
{'DOWN', MRef, _, Proxy, Reason} when is_pid(Proxy) ->
orber:dbg("[~p] orber_iiop:collect_fragments(~p);~n"
"Monitor generated a DOWN message.",
@@ -511,13 +495,8 @@ clear_queue(Proxy, RequestId, MRef) ->
{MRef, RequestId, cancelled} ->
%% This is the last message that the proxy will send
%% after we've cancelled the request.
- erlang:demonitor(MRef),
- receive
- {'DOWN', MRef, _, _, _} ->
- ok
- after 0 ->
- ok
- end;
+ erlang:demonitor(MRef, [flush]),
+ ok;
{'DOWN', MRef, _, Proxy, _Reason} ->
%% The proxy terminated. Clear EXIT message from queue
receive
diff --git a/lib/public_key/asn1/ECPrivateKey.asn1 b/lib/public_key/asn1/ECPrivateKey.asn1
new file mode 100644
index 0000000000..a20fa4009c
--- /dev/null
+++ b/lib/public_key/asn1/ECPrivateKey.asn1
@@ -0,0 +1,24 @@
+ECPrivateKey { iso(1) identified-organization(3) dod(6)
+ internet(1) security(5) mechanisms(5) pkix(7) id-mod(0)
+ id-mod-ecprivateKey(65) }
+
+DEFINITIONS EXPLICIT TAGS ::=
+
+BEGIN
+
+-- EXPORTS ALL;
+
+IMPORTS
+
+-- FROM New PKIX ASN.1 [RFC5912]
+
+EcpkParameters FROM PKIX1Algorithms88;
+
+ECPrivateKey ::= SEQUENCE {
+ version INTEGER,
+ privateKey OCTET STRING,
+ parameters [0] EcpkParameters OPTIONAL,
+ publicKey [1] BIT STRING OPTIONAL
+}
+
+END
diff --git a/lib/public_key/asn1/OTP-PKIX.asn1 b/lib/public_key/asn1/OTP-PKIX.asn1
index a90fe2840c..911a156d6c 100644
--- a/lib/public_key/asn1/OTP-PKIX.asn1
+++ b/lib/public_key/asn1/OTP-PKIX.asn1
@@ -103,15 +103,16 @@ IMPORTS
md5WithRSAEncryption,
sha1WithRSAEncryption,
rsaEncryption, RSAPublicKey,
- dhpublicnumber, DomainParameters, DHPublicKey,
+ dhpublicnumber, DomainParameters, DHPublicKey,
id-keyExchangeAlgorithm, KEA-Parms-Id, --KEA-PublicKey,
- ecdsa-with-SHA1,
+ ecdsa-with-SHA1, ecdsa-with-SHA224,
+ ecdsa-with-SHA256, ecdsa-with-SHA384, ecdsa-with-SHA512,
prime-field, Prime-p,
characteristic-two-field, --Characteristic-two,
gnBasis,
tpBasis, Trinomial,
ppBasis, Pentanomial,
- id-ecPublicKey, EcpkParameters, ECPoint
+ id-ecPublicKey, EcpkParameters, ECParameters, ECPoint
FROM PKIX1Algorithms88 { iso(1) identified-organization(3) dod(6)
internet(1) security(5) mechanisms(5) pkix(7) id-mod(0)
id-mod-pkix1-algorithms(17) }
@@ -321,7 +322,11 @@ SupportedSignatureAlgorithms SIGNATURE-ALGORITHM-CLASS ::= {
sha256-with-rsa-encryption |
sha384-with-rsa-encryption |
sha512-with-rsa-encryption |
- ecdsa-with-sha1 }
+ ecdsa-with-sha1 |
+ ecdsa-with-sha224 |
+ ecdsa-with-sha256 |
+ ecdsa-with-sha384 |
+ ecdsa-with-sha512 }
SupportedPublicKeyAlgorithms PUBLIC-KEY-ALGORITHM-CLASS ::= {
dsa | rsa-encryption | dh | kea | ec-public-key }
@@ -439,6 +444,22 @@ SupportedPublicKeyAlgorithms PUBLIC-KEY-ALGORITHM-CLASS ::= {
ID ecdsa-with-SHA1
TYPE NULL } -- XXX Must be empty and not NULL
+ ecdsa-with-sha224 SIGNATURE-ALGORITHM-CLASS ::= {
+ ID ecdsa-with-SHA224
+ TYPE NULL } -- XXX Must be empty and not NULL
+
+ ecdsa-with-sha256 SIGNATURE-ALGORITHM-CLASS ::= {
+ ID ecdsa-with-SHA256
+ TYPE NULL } -- XXX Must be empty and not NULL
+
+ ecdsa-with-sha384 SIGNATURE-ALGORITHM-CLASS ::= {
+ ID ecdsa-with-SHA384
+ TYPE NULL } -- XXX Must be empty and not NULL
+
+ ecdsa-with-sha512 SIGNATURE-ALGORITHM-CLASS ::= {
+ ID ecdsa-with-SHA512
+ TYPE NULL } -- XXX Must be empty and not NULL
+
FIELD-ID-CLASS ::= CLASS {
&id OBJECT IDENTIFIER UNIQUE,
&Type }
@@ -489,6 +510,7 @@ SupportedPublicKeyAlgorithms PUBLIC-KEY-ALGORITHM-CLASS ::= {
ID ppBasis
TYPE Pentanomial }
+
-- SubjectPublicKeyInfo.algorithm
ec-public-key PUBLIC-KEY-ALGORITHM-CLASS ::= {
diff --git a/lib/public_key/asn1/OTP-PUB-KEY.set.asn b/lib/public_key/asn1/OTP-PUB-KEY.set.asn
index f8fb318c93..e94f428e4b 100644
--- a/lib/public_key/asn1/OTP-PUB-KEY.set.asn
+++ b/lib/public_key/asn1/OTP-PUB-KEY.set.asn
@@ -6,5 +6,6 @@ PKIX1Algorithms88.asn1
PKCS-1.asn1
PKCS-3.asn1
DSS.asn1
+ECPrivateKey.asn1
PKCS-7.asn1
PKCS-10.asn1
diff --git a/lib/public_key/asn1/PKCS-1.asn1 b/lib/public_key/asn1/PKCS-1.asn1
index b5754790e7..117eacd8ad 100644
--- a/lib/public_key/asn1/PKCS-1.asn1
+++ b/lib/public_key/asn1/PKCS-1.asn1
@@ -52,8 +52,40 @@ id-md5 OBJECT IDENTIFIER ::= {
iso(1) member-body(2) us(840) rsadsi(113549) digestAlgorithm(2) 5
}
+id-hmacWithSHA224 OBJECT IDENTIFIER ::= {
+ iso(1) member-body(2) us(840) rsadsi(113549) digestAlgorithm(2) 8
+}
+
+id-hmacWithSHA256 OBJECT IDENTIFIER ::= {
+ iso(1) member-body(2) us(840) rsadsi(113549) digestAlgorithm(2) 9
+}
+
+id-hmacWithSHA384 OBJECT IDENTIFIER ::= {
+ iso(1) member-body(2) us(840) rsadsi(113549) digestAlgorithm(2) 10
+}
+
+id-hmacWithSHA512 OBJECT IDENTIFIER ::= {
+ iso(1) member-body(2) us(840) rsadsi(113549) digestAlgorithm(2) 11
+}
+
id-mgf1 OBJECT IDENTIFIER ::= { pkcs-1 8 }
+id-sha224 OBJECT IDENTIFIER ::= { joint-iso-itu-t(2)
+ country(16) us(840) organization(1) gov(101) csor(3)
+ nistalgorithm(4) hashalgs(2) 4 }
+
+id-sha256 OBJECT IDENTIFIER ::= { joint-iso-itu-t(2)
+ country(16) us(840) organization(1) gov(101) csor(3)
+ nistalgorithm(4) hashalgs(2) 1 }
+
+id-sha384 OBJECT IDENTIFIER ::= { joint-iso-itu-t(2)
+ country(16) us(840) organization(1) gov(101) csor(3)
+ nistalgorithm(4) hashalgs(2) 2 }
+
+id-sha512 OBJECT IDENTIFIER ::= { joint-iso-itu-t(2)
+ country(16) us(840) organization(1) gov(101) csor(3)
+ nistalgorithm(4) hashalgs(2) 3 }
+
RSAPublicKey ::= SEQUENCE {
modulus INTEGER, -- n
diff --git a/lib/public_key/asn1/PKIX1Algorithms88.asn1 b/lib/public_key/asn1/PKIX1Algorithms88.asn1
index 74225747d3..6cc6745af6 100644
--- a/lib/public_key/asn1/PKIX1Algorithms88.asn1
+++ b/lib/public_key/asn1/PKIX1Algorithms88.asn1
@@ -98,6 +98,11 @@
-- OID for ECDSA signatures with SHA-1
ecdsa-with-SHA1 OBJECT IDENTIFIER ::= { id-ecSigType 1 }
+ ecdsa-with-SHA2 OBJECT IDENTIFIER ::= { id-ecSigType 3 }
+ ecdsa-with-SHA224 OBJECT IDENTIFIER ::= { ecdsa-with-SHA2 1 }
+ ecdsa-with-SHA256 OBJECT IDENTIFIER ::= { ecdsa-with-SHA2 2 }
+ ecdsa-with-SHA384 OBJECT IDENTIFIER ::= { ecdsa-with-SHA2 3 }
+ ecdsa-with-SHA512 OBJECT IDENTIFIER ::= { ecdsa-with-SHA2 4 }
-- OID for an elliptic curve signature
-- format for the value of an ECDSA signature value
@@ -199,40 +204,83 @@
-- Named Elliptic Curves in ANSI X9.62.
- ellipticCurve OBJECT IDENTIFIER ::= { ansi-X9-62 curves(3) }
-
- c-TwoCurve OBJECT IDENTIFIER ::= {
- ellipticCurve characteristicTwo(0) }
-
- c2pnb163v1 OBJECT IDENTIFIER ::= { c-TwoCurve 1 }
- c2pnb163v2 OBJECT IDENTIFIER ::= { c-TwoCurve 2 }
- c2pnb163v3 OBJECT IDENTIFIER ::= { c-TwoCurve 3 }
- c2pnb176w1 OBJECT IDENTIFIER ::= { c-TwoCurve 4 }
- c2tnb191v1 OBJECT IDENTIFIER ::= { c-TwoCurve 5 }
- c2tnb191v2 OBJECT IDENTIFIER ::= { c-TwoCurve 6 }
- c2tnb191v3 OBJECT IDENTIFIER ::= { c-TwoCurve 7 }
- c2onb191v4 OBJECT IDENTIFIER ::= { c-TwoCurve 8 }
- c2onb191v5 OBJECT IDENTIFIER ::= { c-TwoCurve 9 }
- c2pnb208w1 OBJECT IDENTIFIER ::= { c-TwoCurve 10 }
- c2tnb239v1 OBJECT IDENTIFIER ::= { c-TwoCurve 11 }
- c2tnb239v2 OBJECT IDENTIFIER ::= { c-TwoCurve 12 }
- c2tnb239v3 OBJECT IDENTIFIER ::= { c-TwoCurve 13 }
- c2onb239v4 OBJECT IDENTIFIER ::= { c-TwoCurve 14 }
- c2onb239v5 OBJECT IDENTIFIER ::= { c-TwoCurve 15 }
- c2pnb272w1 OBJECT IDENTIFIER ::= { c-TwoCurve 16 }
- c2pnb304w1 OBJECT IDENTIFIER ::= { c-TwoCurve 17 }
- c2tnb359v1 OBJECT IDENTIFIER ::= { c-TwoCurve 18 }
- c2pnb368w1 OBJECT IDENTIFIER ::= { c-TwoCurve 19 }
- c2tnb431r1 OBJECT IDENTIFIER ::= { c-TwoCurve 20 }
-
- primeCurve OBJECT IDENTIFIER ::= { ellipticCurve prime(1) }
-
- prime192v1 OBJECT IDENTIFIER ::= { primeCurve 1 }
- prime192v2 OBJECT IDENTIFIER ::= { primeCurve 2 }
- prime192v3 OBJECT IDENTIFIER ::= { primeCurve 3 }
- prime239v1 OBJECT IDENTIFIER ::= { primeCurve 4 }
- prime239v2 OBJECT IDENTIFIER ::= { primeCurve 5 }
- prime239v3 OBJECT IDENTIFIER ::= { primeCurve 6 }
- prime256v1 OBJECT IDENTIFIER ::= { primeCurve 7 }
+ -- ellipticCurve OBJECT IDENTIFIER ::= { ansi-X9-62 curves(3) }
+
+ -- c-TwoCurve OBJECT IDENTIFIER ::= {
+ -- ansi-ellipticCurve characteristicTwo(0) }
+
+ -- c2pnb163v1 OBJECT IDENTIFIER ::= { c-TwoCurve 1 }
+ -- c2pnb163v2 OBJECT IDENTIFIER ::= { c-TwoCurve 2 }
+ -- c2pnb163v3 OBJECT IDENTIFIER ::= { c-TwoCurve 3 }
+ -- c2pnb176w1 OBJECT IDENTIFIER ::= { c-TwoCurve 4 }
+ -- c2tnb191v1 OBJECT IDENTIFIER ::= { c-TwoCurve 5 }
+ -- c2tnb191v2 OBJECT IDENTIFIER ::= { c-TwoCurve 6 }
+ -- c2tnb191v3 OBJECT IDENTIFIER ::= { c-TwoCurve 7 }
+ -- c2onb191v4 OBJECT IDENTIFIER ::= { c-TwoCurve 8 }
+ -- c2onb191v5 OBJECT IDENTIFIER ::= { c-TwoCurve 9 }
+ -- c2pnb208w1 OBJECT IDENTIFIER ::= { c-TwoCurve 10 }
+ -- c2tnb239v1 OBJECT IDENTIFIER ::= { c-TwoCurve 11 }
+ -- c2tnb239v2 OBJECT IDENTIFIER ::= { c-TwoCurve 12 }
+ -- c2tnb239v3 OBJECT IDENTIFIER ::= { c-TwoCurve 13 }
+ -- c2onb239v4 OBJECT IDENTIFIER ::= { c-TwoCurve 14 }
+ -- c2onb239v5 OBJECT IDENTIFIER ::= { c-TwoCurve 15 }
+ -- c2pnb272w1 OBJECT IDENTIFIER ::= { c-TwoCurve 16 }
+ -- c2pnb304w1 OBJECT IDENTIFIER ::= { c-TwoCurve 17 }
+ -- c2tnb359v1 OBJECT IDENTIFIER ::= { c-TwoCurve 18 }
+ -- c2pnb368w1 OBJECT IDENTIFIER ::= { c-TwoCurve 19 }
+ -- c2tnb431r1 OBJECT IDENTIFIER ::= { c-TwoCurve 20 }
+
+ -- primeCurve OBJECT IDENTIFIER ::= { ansi-ellipticCurve prime(1) }
+
+ -- prime192v1 OBJECT IDENTIFIER ::= { primeCurve 1 }
+ -- prime192v2 OBJECT IDENTIFIER ::= { primeCurve 2 }
+ -- prime192v3 OBJECT IDENTIFIER ::= { primeCurve 3 }
+ -- prime239v1 OBJECT IDENTIFIER ::= { primeCurve 4 }
+ -- prime239v2 OBJECT IDENTIFIER ::= { primeCurve 5 }
+ -- prime239v3 OBJECT IDENTIFIER ::= { primeCurve 6 }
+ -- prime256v1 OBJECT IDENTIFIER ::= { primeCurve 7 }
+
+ certicom-arc OBJECT IDENTIFIER ::= {
+ iso(1) identified-organization(3) certicom(132)
+ }
+
+ ellipticCurve OBJECT IDENTIFIER ::= {
+ iso(1) identified-organization(3) certicom(132) curve(0)
+ }
+
+ secp192r1 OBJECT IDENTIFIER ::= { ansi-X9-62 curves(3) prime(1) 1 }
+ secp256r1 OBJECT IDENTIFIER ::= { ansi-X9-62 curves(3) prime(1) 7 }
+
+ sect163k1 OBJECT IDENTIFIER ::= { ellipticCurve 1 }
+ sect163r1 OBJECT IDENTIFIER ::= { ellipticCurve 2 }
+ sect239k1 OBJECT IDENTIFIER ::= { ellipticCurve 3 }
+ sect113r1 OBJECT IDENTIFIER ::= { ellipticCurve 4 }
+ sect113r2 OBJECT IDENTIFIER ::= { ellipticCurve 5 }
+ secp112r1 OBJECT IDENTIFIER ::= { ellipticCurve 6 }
+ secp112r2 OBJECT IDENTIFIER ::= { ellipticCurve 7 }
+ secp160r1 OBJECT IDENTIFIER ::= { ellipticCurve 8 }
+ secp160k1 OBJECT IDENTIFIER ::= { ellipticCurve 9 }
+ secp256k1 OBJECT IDENTIFIER ::= { ellipticCurve 10 }
+ sect163r2 OBJECT IDENTIFIER ::= { ellipticCurve 15 }
+ sect283k1 OBJECT IDENTIFIER ::= { ellipticCurve 16 }
+ sect283r1 OBJECT IDENTIFIER ::= { ellipticCurve 17 }
+ sect131r1 OBJECT IDENTIFIER ::= { ellipticCurve 22 }
+ sect131r2 OBJECT IDENTIFIER ::= { ellipticCurve 23 }
+ sect193r1 OBJECT IDENTIFIER ::= { ellipticCurve 24 }
+ sect193r2 OBJECT IDENTIFIER ::= { ellipticCurve 25 }
+ sect233k1 OBJECT IDENTIFIER ::= { ellipticCurve 26 }
+ sect233r1 OBJECT IDENTIFIER ::= { ellipticCurve 27 }
+ secp128r1 OBJECT IDENTIFIER ::= { ellipticCurve 28 }
+ secp128r2 OBJECT IDENTIFIER ::= { ellipticCurve 29 }
+ secp160r2 OBJECT IDENTIFIER ::= { ellipticCurve 30 }
+ secp192k1 OBJECT IDENTIFIER ::= { ellipticCurve 31 }
+ secp224k1 OBJECT IDENTIFIER ::= { ellipticCurve 32 }
+ secp224r1 OBJECT IDENTIFIER ::= { ellipticCurve 33 }
+ secp384r1 OBJECT IDENTIFIER ::= { ellipticCurve 34 }
+ secp521r1 OBJECT IDENTIFIER ::= { ellipticCurve 35 }
+ sect409k1 OBJECT IDENTIFIER ::= { ellipticCurve 36 }
+ sect409r1 OBJECT IDENTIFIER ::= { ellipticCurve 37 }
+ sect571k1 OBJECT IDENTIFIER ::= { ellipticCurve 38 }
+ sect571r1 OBJECT IDENTIFIER ::= { ellipticCurve 39 }
END
diff --git a/lib/public_key/doc/src/public_key.xml b/lib/public_key/doc/src/public_key.xml
index 84300f6e65..10c95a39ac 100644
--- a/lib/public_key/doc/src/public_key.xml
+++ b/lib/public_key/doc/src/public_key.xml
@@ -84,7 +84,8 @@
<p><code>pki_asn1_type() = 'Certificate' | 'RSAPrivateKey'| 'RSAPublicKey' |
'DSAPrivateKey' | 'DSAPublicKey' | 'DHParameter' | 'SubjectPublicKeyInfo' |
- 'PrivateKeyInfo' | 'CertificationRequest'</code></p>
+ 'PrivateKeyInfo' | 'CertificationRequest' | 'ECPrivateKey'|
+ 'EcpkParameters'</code></p>
<p><code>pem_entry () = {pki_asn1_type(), binary(), %% DER or encrypted DER
not_encrypted | cipher_info()} </code></p>
@@ -99,7 +100,11 @@
<p><code>dsa_public_key() = {integer(), #'Dss-Parms'{}} </code></p>
<p><code>dsa_private_key() = #'DSAPrivateKey'{}</code></p>
+
+ <p><code>ec_public_key() = {#'ECPoint'{}, #'EcpkParameters'{} | {namedCurve, oid()}} </code></p>
+ <p><code>ec_private_key() = #'ECPrivateKey'{}</code></p>
+
<p><code> public_crypt_options() = [{rsa_pad, rsa_padding()}]. </code></p>
<p><code> rsa_padding() = 'rsa_pkcs1_padding' | 'rsa_pkcs1_oaep_padding'
@@ -109,6 +114,8 @@
<p><code> dss_digest_type() = 'sha' </code></p>
+ <p><code> ecdsa_digest_type() = 'sha'| 'sha224' | 'sha256' | 'sha384' | 'sha512' </code></p>
+
<p><code> crl_reason() = unspecified | keyCompromise | cACompromise | affiliationChanged | superseded | cessationOfOperation | certificateHold | privilegeWithdrawn | aACompromise
</code></p>
@@ -147,6 +154,19 @@
<funcs>
<func>
+ <name> compute_key(OthersKey, MyKey)-></name>
+ <name> compute_key(OthersKey, MyKey, Params)-></name>
+ <fsummary> Compute shared secret</fsummary>
+ <type>
+ <v>OthersKey = #'ECPoint'{} | binary(), MyKey = #'ECPrivateKey'{} | binary()</v>
+ <v>Params = #'DHParameter'{}</v>
+ </type>
+ <desc>
+ <p> Compute shared secret </p>
+ </desc>
+ </func>
+
+ <func>
<name>decrypt_private(CipherText, Key) -> binary()</name>
<name>decrypt_private(CipherText, Key, Options) -> binary()</name>
<fsummary>Public key decryption.</fsummary>
@@ -204,6 +224,17 @@
</func>
<func>
+ <name>generate_key(Params) -> {Public::binary(), Private::binary()} | #'ECPrivateKey'{} </name>
+ <fsummary>Generates a new keypair</fsummary>
+ <type>
+ <v> Params = #'DHParameter'{} | {namedCurve, oid()} | #'ECParameters'{} </v>
+ </type>
+ <desc>
+ <p>Generates a new keypair</p>
+ </desc>
+ </func>
+
+ <func>
<name>pem_decode(PemBin) -> [pem_entry()]</name>
<fsummary>Decode PEM binary data and return
entries as ASN.1 DER encoded entities. </fsummary>
@@ -528,8 +559,8 @@ fun(OtpCert :: #'OTPCertificate'{}, Event :: {bad_cert, Reason :: atom()} |
<d>The msg is either the binary "plain text" data to be
signed or it is the hashed value of "plain text" i.e. the
digest.</d>
- <v>DigestType = rsa_digest_type() | dss_digest_type()</v>
- <v>Key = rsa_private_key() | dsa_private_key()</v>
+ <v>DigestType = rsa_digest_type() | dss_digest_type() | ecdsa_digest_type()</v>
+ <v>Key = rsa_private_key() | dsa_private_key() | ec_private_key()</v>
</type>
<desc>
<p> Creates a digital signature.</p>
@@ -592,12 +623,12 @@ fun(OtpCert :: #'OTPCertificate'{}, Event :: {bad_cert, Reason :: atom()} |
<v>Msg = binary() | {digest,binary()}</v>
<d>The msg is either the binary "plain text" data
or it is the hashed value of "plain text" i.e. the digest.</d>
- <v>DigestType = rsa_digest_type() | dss_digest_type()</v>
+ <v>DigestType = rsa_digest_type() | dss_digest_type() | ecdsa_digest_type()</v>
<v>Signature = binary()</v>
- <v>Key = rsa_public_key() | dsa_public_key()</v>
- </type>
- <desc>
- <p>Verifies a digital signature</p>
+ <v>Key = rsa_public_key() | dsa_public_key() | ec_public_key()</v>
+ </type>
+ <desc>
+ <p>Verifies a digital signature</p>
</desc>
</func>
diff --git a/lib/public_key/include/public_key.hrl b/lib/public_key/include/public_key.hrl
index 4d1d510f29..1e882e76ee 100644
--- a/lib/public_key/include/public_key.hrl
+++ b/lib/public_key/include/public_key.hrl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2008-2012. All Rights Reserved.
+%% Copyright Ericsson AB 2008-2013. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -72,6 +72,10 @@
valid_ext
}).
+-record('ECPoint', {
+ point
+ }).
+
-define(unspecified, 0).
-define(keyCompromise, 1).
@@ -89,6 +93,8 @@
-type rsa_private_key() :: #'RSAPrivateKey'{}.
-type dsa_private_key() :: #'DSAPrivateKey'{}.
-type dsa_public_key() :: {integer(), #'Dss-Parms'{}}.
+-type ec_public_key() :: {#'ECPoint'{},{namedCurve, Oid::tuple()} | #'ECParameters'{}}.
+-type ec_private_key() :: #'ECPrivateKey'{}.
-type der_encoded() :: binary().
-type decrypt_der() :: binary().
-type pki_asn1_type() :: 'Certificate' | 'RSAPrivateKey' | 'RSAPublicKey'
diff --git a/lib/public_key/src/pubkey_cert_records.erl b/lib/public_key/src/pubkey_cert_records.erl
index 98004c71a3..0449129809 100644
--- a/lib/public_key/src/pubkey_cert_records.erl
+++ b/lib/public_key/src/pubkey_cert_records.erl
@@ -23,7 +23,8 @@
-include("public_key.hrl").
--export([decode_cert/1, transform/2, supportedPublicKeyAlgorithms/1]).
+-export([decode_cert/1, transform/2, supportedPublicKeyAlgorithms/1,
+ supportedCurvesTypes/1, namedCurves/1]).
%%====================================================================
%% Internal application API
@@ -101,6 +102,77 @@ supportedPublicKeyAlgorithms(?'dhpublicnumber') -> 'DHPublicKey';
supportedPublicKeyAlgorithms(?'id-keyExchangeAlgorithm') -> 'KEA-PublicKey';
supportedPublicKeyAlgorithms(?'id-ecPublicKey') -> 'ECPoint'.
+supportedCurvesTypes(?'characteristic-two-field') -> characteristic_two_field;
+supportedCurvesTypes(?'prime-field') -> prime_field.
+
+namedCurves(?'sect571r1') -> sect571r1;
+namedCurves(?'sect571k1') -> sect571k1;
+namedCurves(?'sect409r1') -> sect409r1;
+namedCurves(?'sect409k1') -> sect409k1;
+namedCurves(?'secp521r1') -> secp521r1;
+namedCurves(?'secp384r1') -> secp384r1;
+namedCurves(?'secp224r1') -> secp224r1;
+namedCurves(?'secp224k1') -> secp224k1;
+namedCurves(?'secp192k1') -> secp192k1;
+namedCurves(?'secp160r2') -> secp160r2;
+namedCurves(?'secp128r2') -> secp128r2;
+namedCurves(?'secp128r1') -> secp128r1;
+namedCurves(?'sect233r1') -> sect233r1;
+namedCurves(?'sect233k1') -> sect233k1;
+namedCurves(?'sect193r2') -> sect193r2;
+namedCurves(?'sect193r1') -> sect193r1;
+namedCurves(?'sect131r2') -> sect131r2;
+namedCurves(?'sect131r1') -> sect131r1;
+namedCurves(?'sect283r1') -> sect283r1;
+namedCurves(?'sect283k1') -> sect283k1;
+namedCurves(?'sect163r2') -> sect163r2;
+namedCurves(?'secp256k1') -> secp256k1;
+namedCurves(?'secp160k1') -> secp160k1;
+namedCurves(?'secp160r1') -> secp160r1;
+namedCurves(?'secp112r2') -> secp112r2;
+namedCurves(?'secp112r1') -> secp112r1;
+namedCurves(?'sect113r2') -> sect113r2;
+namedCurves(?'sect113r1') -> sect113r1;
+namedCurves(?'sect239k1') -> sect239k1;
+namedCurves(?'sect163r1') -> sect163r1;
+namedCurves(?'sect163k1') -> sect163k1;
+namedCurves(?'secp256r1') -> secp256r1;
+namedCurves(?'secp192r1') -> secp192r1;
+
+namedCurves(sect571r1) -> ?'sect571r1';
+namedCurves(sect571k1) -> ?'sect571k1';
+namedCurves(sect409r1) -> ?'sect409r1';
+namedCurves(sect409k1) -> ?'sect409k1';
+namedCurves(secp521r1) -> ?'secp521r1';
+namedCurves(secp384r1) -> ?'secp384r1';
+namedCurves(secp224r1) -> ?'secp224r1';
+namedCurves(secp224k1) -> ?'secp224k1';
+namedCurves(secp192k1) -> ?'secp192k1';
+namedCurves(secp160r2) -> ?'secp160r2';
+namedCurves(secp128r2) -> ?'secp128r2';
+namedCurves(secp128r1) -> ?'secp128r1';
+namedCurves(sect233r1) -> ?'sect233r1';
+namedCurves(sect233k1) -> ?'sect233k1';
+namedCurves(sect193r2) -> ?'sect193r2';
+namedCurves(sect193r1) -> ?'sect193r1';
+namedCurves(sect131r2) -> ?'sect131r2';
+namedCurves(sect131r1) -> ?'sect131r1';
+namedCurves(sect283r1) -> ?'sect283r1';
+namedCurves(sect283k1) -> ?'sect283k1';
+namedCurves(sect163r2) -> ?'sect163r2';
+namedCurves(secp256k1) -> ?'secp256k1';
+namedCurves(secp160k1) -> ?'secp160k1';
+namedCurves(secp160r1) -> ?'secp160r1';
+namedCurves(secp112r2) -> ?'secp112r2';
+namedCurves(secp112r1) -> ?'secp112r1';
+namedCurves(sect113r2) -> ?'sect113r2';
+namedCurves(sect113r1) -> ?'sect113r1';
+namedCurves(sect239k1) -> ?'sect239k1';
+namedCurves(sect163r1) -> ?'sect163r1';
+namedCurves(sect163k1) -> ?'sect163k1';
+namedCurves(secp256r1) -> ?'secp256r1';
+namedCurves(secp192r1) -> ?'secp192r1'.
+
%%--------------------------------------------------------------------
%%% Internal functions
%%--------------------------------------------------------------------
@@ -111,14 +183,24 @@ decode_supportedPublicKey(#'OTPSubjectPublicKeyInfo'{algorithm= PA =
#'PublicKeyAlgorithm'{algorithm=Algo},
subjectPublicKey = {0,SPK0}}) ->
Type = supportedPublicKeyAlgorithms(Algo),
- {ok, SPK} = 'OTP-PUB-KEY':decode(Type, SPK0),
+ SPK = case Type of
+ 'ECPoint' -> #'ECPoint'{point = SPK0};
+ _ -> {ok, SPK1} = 'OTP-PUB-KEY':decode(Type, SPK0),
+ SPK1
+ end,
#'OTPSubjectPublicKeyInfo'{subjectPublicKey = SPK, algorithm=PA}.
encode_supportedPublicKey(#'OTPSubjectPublicKeyInfo'{algorithm= PA =
#'PublicKeyAlgorithm'{algorithm=Algo},
subjectPublicKey = SPK0}) ->
Type = supportedPublicKeyAlgorithms(Algo),
- {ok, SPK} = 'OTP-PUB-KEY':encode(Type, SPK0),
+ SPK = case Type of
+ 'ECPoint' ->
+ SPK0#'ECPoint'.point;
+ _ ->
+ {ok, SPK1} = 'OTP-PUB-KEY':encode(Type, SPK0),
+ SPK1
+ end,
#'OTPSubjectPublicKeyInfo'{subjectPublicKey = {0,SPK}, algorithm=PA}.
%%% Extensions
diff --git a/lib/public_key/src/pubkey_pem.erl b/lib/public_key/src/pubkey_pem.erl
index 6bdc35fb79..746d142ec3 100644
--- a/lib/public_key/src/pubkey_pem.erl
+++ b/lib/public_key/src/pubkey_pem.erl
@@ -202,7 +202,11 @@ pem_start('CertificationRequest') ->
pem_start('ContentInfo') ->
<<"-----BEGIN PKCS7-----">>;
pem_start('CertificateList') ->
- <<"-----BEGIN X509 CRL-----">>.
+ <<"-----BEGIN X509 CRL-----">>;
+pem_start('OTPEcpkParameters') ->
+ <<"-----BEGIN EC PARAMETERS-----">>;
+pem_start('ECPrivateKey') ->
+ <<"-----BEGIN EC PRIVATE KEY-----">>.
pem_end(<<"-----BEGIN CERTIFICATE-----">>) ->
<<"-----END CERTIFICATE-----">>;
@@ -226,6 +230,10 @@ pem_end(<<"-----BEGIN PKCS7-----">>) ->
<<"-----END PKCS7-----">>;
pem_end(<<"-----BEGIN X509 CRL-----">>) ->
<<"-----END X509 CRL-----">>;
+pem_end(<<"-----BEGIN EC PARAMETERS-----">>) ->
+ <<"-----END EC PARAMETERS-----">>;
+pem_end(<<"-----BEGIN EC PRIVATE KEY-----">>) ->
+ <<"-----END EC PRIVATE KEY-----">>;
pem_end(_) ->
undefined.
@@ -250,7 +258,11 @@ asn1_type(<<"-----BEGIN CERTIFICATE REQUEST-----">>) ->
asn1_type(<<"-----BEGIN PKCS7-----">>) ->
'ContentInfo';
asn1_type(<<"-----BEGIN X509 CRL-----">>) ->
- 'CertificateList'.
+ 'CertificateList';
+asn1_type(<<"-----BEGIN EC PARAMETERS-----">>) ->
+ 'OTPEcpkParameters';
+asn1_type(<<"-----BEGIN EC PRIVATE KEY-----">>) ->
+ 'ECPrivateKey'.
pem_decrypt() ->
<<"Proc-Type: 4,ENCRYPTED">>.
diff --git a/lib/public_key/src/public_key.erl b/lib/public_key/src/public_key.erl
index 736c18cdd4..648dba3d5a 100644
--- a/lib/public_key/src/public_key.erl
+++ b/lib/public_key/src/public_key.erl
@@ -35,6 +35,8 @@
encrypt_public/2, encrypt_public/3,
decrypt_public/2, decrypt_public/3,
sign/3, verify/4,
+ generate_key/1,
+ compute_key/2, compute_key/3,
pkix_sign/2, pkix_verify/2,
pkix_sign_types/1,
pkix_is_self_signed/1,
@@ -52,6 +54,7 @@
-type public_crypt_options() :: [{rsa_pad, rsa_padding()}].
-type rsa_digest_type() :: 'md5' | 'sha'| 'sha224' | 'sha256' | 'sha384' | 'sha512'.
-type dss_digest_type() :: 'none' | 'sha'. %% None is for backwards compatibility
+-type ecdsa_digest_type() :: 'sha'| 'sha224' | 'sha256' | 'sha384' | 'sha512'.
-type crl_reason() :: unspecified | keyCompromise | cACompromise | affiliationChanged | superseded
| cessationOfOperation | certificateHold | privilegeWithdrawn | aACompromise.
-type oid() :: tuple().
@@ -94,7 +97,9 @@ pem_entry_decode({'SubjectPublicKeyInfo', Der, _}) ->
der_decode(KeyType, Key0);
'DSAPublicKey' ->
{params, DssParams} = der_decode('DSAParams', Params),
- {der_decode(KeyType, Key0), DssParams}
+ {der_decode(KeyType, Key0), DssParams};
+ 'ECPoint' ->
+ der_decode(KeyType, Key0)
end;
pem_entry_decode({Asn1Type, Der, not_encrypted}) when is_atom(Asn1Type),
is_binary(Der) ->
@@ -251,10 +256,9 @@ decrypt_private(CipherText,
privateExponent = D} = Key,
Options)
when is_binary(CipherText),
- is_integer(N), is_integer(E), is_integer(D),
is_list(Options) ->
Padding = proplists:get_value(rsa_pad, Options, rsa_pkcs1_padding),
- crypto:rsa_private_decrypt(CipherText, format_rsa_private_key(Key), Padding).
+ crypto:private_decrypt(rsa, CipherText, format_rsa_private_key(Key), Padding).
%%--------------------------------------------------------------------
-spec decrypt_public(CipherText :: binary(), rsa_public_key() | rsa_private_key()) ->
@@ -318,30 +322,41 @@ encrypt_private(PlainText,
Options)
when is_binary(PlainText),
is_integer(N), is_integer(E), is_integer(D),
- is_list(Options) ->
+ is_list(Options) ->
Padding = proplists:get_value(rsa_pad, Options, rsa_pkcs1_padding),
- crypto:rsa_private_encrypt(PlainText, format_rsa_private_key(Key), Padding).
+ crypto:private_encrypt(rsa, PlainText, format_rsa_private_key(Key), Padding).
+%%--------------------------------------------------------------------
+-spec generate_key(#'DHParameter'{} | {namedCurve, Name ::atom()} |
+ #'ECParameters'{}) -> {Public::binary(), Private::binary()} |
+ #'ECPrivateKey'{}.
+%% Description: Generates a new keypair
+%%--------------------------------------------------------------------
+generate_key(#'DHParameter'{prime = P, base = G}) ->
+ crypto:generate_key(dh, [P, G]);
+generate_key({namedCurve, _} = Params) ->
+ ec_generate_key(Params);
+generate_key(#'ECParameters'{} = Params) ->
+ ec_generate_key(Params).
-format_rsa_private_key(#'RSAPrivateKey'{modulus = N, publicExponent = E,
- privateExponent = D,
- prime1 = P1, prime2 = P2,
- exponent1 = E1, exponent2 = E2,
- coefficient = C})
- when is_integer(P1), is_integer(P2),
- is_integer(E1), is_integer(E2), is_integer(C) ->
- [crypto:mpint(K) || K <- [E, N, D, P1, P2, E1, E2, C]];
+%%--------------------------------------------------------------------
+-spec compute_key(#'ECPoint'{} , #'ECPrivateKey'{}) -> binary().
+-spec compute_key(OthersKey ::binary(), MyKey::binary(), #'DHParameter'{}) -> binary().
+%% Description: Compute shared secret
+%%--------------------------------------------------------------------
+compute_key(#'ECPoint'{point = Point}, #'ECPrivateKey'{privateKey = PrivKey,
+ parameters = Param}) ->
+ ECCurve = ec_curve_spec(Param),
+ crypto:compute_key(ecdh, Point, list2int(PrivKey), ECCurve).
-format_rsa_private_key(#'RSAPrivateKey'{modulus = N, publicExponent = E,
- privateExponent = D}) ->
- [crypto:mpint(K) || K <- [E, N, D]].
+compute_key(PubKey, PrivKey, #'DHParameter'{prime = P, base = G}) ->
+ crypto:compute_key(dh, PubKey, PrivKey, [P, G]).
%%--------------------------------------------------------------------
-
-spec pkix_sign_types(SignatureAlg::oid()) ->
%% Relevant dsa digest type is subpart of rsa digest type
{ DigestType :: rsa_digest_type(),
- SignatureType :: rsa | dsa
+ SignatureType :: rsa | dsa | ecdsa
}.
%% Description:
%%--------------------------------------------------------------------
@@ -362,68 +377,60 @@ pkix_sign_types(?md5WithRSAEncryption) ->
pkix_sign_types(?'id-dsa-with-sha1') ->
{sha, dsa};
pkix_sign_types(?'id-dsaWithSHA1') ->
- {sha, dsa}.
+ {sha, dsa};
+pkix_sign_types(?'ecdsa-with-SHA1') ->
+ {sha, ecdsa};
+pkix_sign_types(?'ecdsa-with-SHA256') ->
+ {sha256, ecdsa};
+pkix_sign_types(?'ecdsa-with-SHA384') ->
+ {sha384, ecdsa};
+pkix_sign_types(?'ecdsa-with-SHA512') ->
+ {sha512, ecdsa}.
%%--------------------------------------------------------------------
--spec sign(binary() | {digest, binary()}, rsa_digest_type() | dss_digest_type(),
+-spec sign(binary() | {digest, binary()}, rsa_digest_type() | dss_digest_type() | ecdsa_digest_type(),
rsa_private_key() |
- dsa_private_key()) -> Signature :: binary().
+ dsa_private_key() | ec_private_key()) -> Signature :: binary().
%% Description: Create digital signature.
%%--------------------------------------------------------------------
-sign({digest,_}=Digest, DigestType, Key = #'RSAPrivateKey'{}) ->
- crypto:rsa_sign(DigestType, Digest, format_rsa_private_key(Key));
+sign(DigestOrPlainText, DigestType, Key = #'RSAPrivateKey'{}) ->
+ crypto:sign(rsa, DigestType, DigestOrPlainText, format_rsa_private_key(Key));
-sign(PlainText, DigestType, Key = #'RSAPrivateKey'{}) ->
- crypto:rsa_sign(DigestType, sized_binary(PlainText), format_rsa_private_key(Key));
+sign(DigestOrPlainText, sha, #'DSAPrivateKey'{p = P, q = Q, g = G, x = X}) ->
+ crypto:sign(dss, sha, DigestOrPlainText, [P, Q, G, X]);
-sign({digest,_}=Digest, sha, #'DSAPrivateKey'{p = P, q = Q, g = G, x = X}) ->
- crypto:dss_sign(Digest,
- [crypto:mpint(P), crypto:mpint(Q),
- crypto:mpint(G), crypto:mpint(X)]);
-
-sign(PlainText, sha, #'DSAPrivateKey'{p = P, q = Q, g = G, x = X}) ->
- crypto:dss_sign(sized_binary(PlainText),
- [crypto:mpint(P), crypto:mpint(Q),
- crypto:mpint(G), crypto:mpint(X)]);
+sign(DigestOrPlainText, DigestType, #'ECPrivateKey'{privateKey = PrivKey,
+ parameters = Param}) ->
+ ECCurve = ec_curve_spec(Param),
+ crypto:sign(ecdsa, DigestType, DigestOrPlainText, [list2int(PrivKey), ECCurve]);
%% Backwards compatible
sign(Digest, none, #'DSAPrivateKey'{} = Key) ->
sign({digest,Digest}, sha, Key).
%%--------------------------------------------------------------------
--spec verify(binary() | {digest, binary()}, rsa_digest_type() | dss_digest_type(),
+-spec verify(binary() | {digest, binary()}, rsa_digest_type() | dss_digest_type() | ecdsa_digest_type(),
Signature :: binary(), rsa_public_key()
- | dsa_public_key()) -> boolean().
+ | dsa_public_key() | ec_public_key()) -> boolean().
%% Description: Verifies a digital signature.
%%--------------------------------------------------------------------
-verify({digest,_}=Digest, DigestType, Signature,
+verify(DigestOrPlainText, DigestType, Signature,
#'RSAPublicKey'{modulus = Mod, publicExponent = Exp}) ->
- crypto:rsa_verify(DigestType, Digest,
- sized_binary(Signature),
- [crypto:mpint(Exp), crypto:mpint(Mod)]);
+ crypto:verify(rsa, DigestType, DigestOrPlainText, Signature,
+ [Exp, Mod]);
-verify(PlainText, DigestType, Signature,
- #'RSAPublicKey'{modulus = Mod, publicExponent = Exp}) ->
- crypto:rsa_verify(DigestType,
- sized_binary(PlainText),
- sized_binary(Signature),
- [crypto:mpint(Exp), crypto:mpint(Mod)]);
+verify(DigestOrPlaintext, DigestType, Signature, {#'ECPoint'{point = Point}, Param}) ->
+ ECCurve = ec_curve_spec(Param),
+ crypto:verify(ecdsa, DigestType, DigestOrPlaintext, Signature, [Point, ECCurve]);
-verify({digest,_}=Digest, sha, Signature, {Key, #'Dss-Parms'{p = P, q = Q, g = G}})
- when is_integer(Key), is_binary(Signature) ->
- crypto:dss_verify(Digest, sized_binary(Signature),
- [crypto:mpint(P), crypto:mpint(Q),
- crypto:mpint(G), crypto:mpint(Key)]);
%% Backwards compatibility
verify(Digest, none, Signature, {_, #'Dss-Parms'{}} = Key ) ->
verify({digest,Digest}, sha, Signature, Key);
-verify(PlainText, sha, Signature, {Key, #'Dss-Parms'{p = P, q = Q, g = G}})
- when is_integer(Key), is_binary(PlainText), is_binary(Signature) ->
- crypto:dss_verify(sized_binary(PlainText),
- sized_binary(Signature),
- [crypto:mpint(P), crypto:mpint(Q),
- crypto:mpint(G), crypto:mpint(Key)]).
+verify(DigestOrPlainText, sha = DigestType, Signature, {Key, #'Dss-Parms'{p = P, q = Q, g = G}})
+ when is_integer(Key), is_binary(Signature) ->
+ crypto:verify(dss, DigestType, DigestOrPlainText, Signature, [P, Q, G, Key]).
+
%%--------------------------------------------------------------------
-spec pkix_sign(#'OTPTBSCertificate'{},
rsa_private_key() | dsa_private_key()) -> Der::binary().
@@ -446,7 +453,7 @@ pkix_sign(#'OTPTBSCertificate'{signature =
%%--------------------------------------------------------------------
-spec pkix_verify(Cert::binary(), rsa_public_key()|
- dsa_public_key()) -> boolean().
+ dsa_public_key() | ec_public_key()) -> boolean().
%%
%% Description: Verify pkix x.509 certificate signature.
%%--------------------------------------------------------------------
@@ -458,7 +465,12 @@ pkix_verify(DerCert, {Key, #'Dss-Parms'{}} = DSAKey)
pkix_verify(DerCert, #'RSAPublicKey'{} = RSAKey)
when is_binary(DerCert) ->
{DigestType, PlainText, Signature} = pubkey_cert:verify_data(DerCert),
- verify(PlainText, DigestType, Signature, RSAKey).
+ verify(PlainText, DigestType, Signature, RSAKey);
+
+pkix_verify(DerCert, Key = {#'ECPoint'{}, _})
+ when is_binary(DerCert) ->
+ {DigestType, PlainText, Signature} = pubkey_cert:verify_data(DerCert),
+ verify(PlainText, DigestType, Signature, Key).
%%--------------------------------------------------------------------
-spec pkix_is_issuer(Cert :: der_encoded()| #'OTPCertificate'{} | #'CertificateList'{},
@@ -640,13 +652,11 @@ do_pem_entry_decode({Asn1Type,_, _} = PemEntry, Password) ->
encrypt_public(PlainText, N, E, Options)->
Padding = proplists:get_value(rsa_pad, Options, rsa_pkcs1_padding),
- crypto:rsa_public_encrypt(PlainText, [crypto:mpint(E),crypto:mpint(N)],
- Padding).
+ crypto:public_encrypt(rsa, PlainText, [E,N], Padding).
-decrypt_public(CipherText, N,E, Options) ->
+decrypt_public(CipherText, N,E, Options) ->
Padding = proplists:get_value(rsa_pad, Options, rsa_pkcs1_padding),
- crypto:rsa_public_decrypt(CipherText,[crypto:mpint(E), crypto:mpint(N)],
- Padding).
+ crypto:public_decrypt(rsa, CipherText,[E, N], Padding).
path_validation([], #path_validation_state{working_public_key_algorithm
= Algorithm,
@@ -732,10 +742,6 @@ validate(Cert, #path_validation_state{working_issuer_name = Issuer,
pubkey_cert:prepare_for_next_cert(OtpCert, ValidationState).
-sized_binary(Binary) ->
- Size = size(Binary),
- <<?UINT32(Size), Binary/binary>>.
-
otp_cert(Der) when is_binary(Der) ->
pkix_decode_cert(Der, otp);
otp_cert(#'OTPCertificate'{} =Cert) ->
@@ -842,3 +848,46 @@ combine(CRL, DeltaCRLs) ->
end,
lists:foldl(Fun, hd(Deltas), tl(Deltas))
end.
+
+format_rsa_private_key(#'RSAPrivateKey'{modulus = N, publicExponent = E,
+ privateExponent = D,
+ prime1 = P1, prime2 = P2,
+ exponent1 = E1, exponent2 = E2,
+ coefficient = C})
+ when is_integer(N), is_integer(E), is_integer(D),
+ is_integer(P1), is_integer(P2),
+ is_integer(E1), is_integer(E2), is_integer(C) ->
+ [E, N, D, P1, P2, E1, E2, C];
+
+format_rsa_private_key(#'RSAPrivateKey'{modulus = N, publicExponent = E,
+ privateExponent = D}) when is_integer(N),
+ is_integer(E),
+ is_integer(D) ->
+ [E, N, D].
+
+ec_generate_key(Params) ->
+ Curve = ec_curve_spec(Params),
+ Term = crypto:generate_key(ecdh, Curve),
+ ec_key(Term, Params).
+
+ec_curve_spec( #'ECParameters'{fieldID = FieldId, curve = PCurve, base = Base, order = Order, cofactor = CoFactor }) ->
+ Field = {pubkey_cert_records:supportedCurvesTypes(FieldId#'FieldID'.fieldType),
+ FieldId#'FieldID'.parameters},
+ Curve = {erlang:list_to_binary(PCurve#'Curve'.a), erlang:list_to_binary(PCurve#'Curve'.b), none},
+ {Field, Curve, erlang:list_to_binary(Base), Order, CoFactor};
+ec_curve_spec({namedCurve, OID}) ->
+ pubkey_cert_records:namedCurves(OID).
+
+ec_key({PrivateKey, PubKey}, Params) ->
+ #'ECPrivateKey'{version = 1,
+ privateKey = int2list(PrivateKey),
+ parameters = Params,
+ publicKey = {0, PubKey}}.
+
+list2int(L) ->
+ S = length(L) * 8,
+ <<R:S/integer>> = erlang:iolist_to_binary(L),
+ R.
+int2list(I) ->
+ L = (length(integer_to_list(I, 16)) + 1) div 2,
+ binary_to_list(<<I:(L*8)>>).
diff --git a/lib/public_key/test/erl_make_certs.erl b/lib/public_key/test/erl_make_certs.erl
index 95e288cd71..14efbcc7e0 100644
--- a/lib/public_key/test/erl_make_certs.erl
+++ b/lib/public_key/test/erl_make_certs.erl
@@ -45,7 +45,7 @@
%% {dnQualifer, DnQ}
%% issuer = {Issuer, IssuerKey} true (i.e. a ca cert is created)
%% (obs IssuerKey migth be {Key, Password}
-%% key = KeyFile|KeyBin|rsa|dsa Subject PublicKey rsa or dsa generates key
+%% key = KeyFile|KeyBin|rsa|dsa|ec Subject PublicKey rsa, dsa or ec generates key
%%
%%
%% (OBS: The generated keys are for testing only)
@@ -91,6 +91,16 @@ gen_dsa(LSize,NSize) when is_integer(LSize), is_integer(NSize) ->
{Key, encode_key(Key)}.
%%--------------------------------------------------------------------
+%% @doc Creates a ec key (OBS: for testing only)
+%% the sizes are in bytes
+%% @spec (::integer()) -> {::atom(), ::binary(), ::opaque()}
+%% @end
+%%--------------------------------------------------------------------
+gen_ec(Curve) when is_atom(Curve) ->
+ Key = gen_ec2(Curve),
+ {Key, encode_key(Key)}.
+
+%%--------------------------------------------------------------------
%% @doc Verifies cert signatures
%% @spec (::binary(), ::tuple()) -> ::boolean()
%% @end
@@ -102,7 +112,10 @@ verify_signature(DerEncodedCert, DerKey, _KeyParams) ->
public_key:pkix_verify(DerEncodedCert,
#'RSAPublicKey'{modulus=Mod, publicExponent=Exp});
#'DSAPrivateKey'{p=P, q=Q, g=G, y=Y} ->
- public_key:pkix_verify(DerEncodedCert, {Y, #'Dss-Parms'{p=P, q=Q, g=G}})
+ public_key:pkix_verify(DerEncodedCert, {Y, #'Dss-Parms'{p=P, q=Q, g=G}});
+ #'ECPrivateKey'{version = _Version, privateKey = _PrivKey,
+ parameters = _Params, publicKey = _PubKey} ->
+ public_key:pkix_verify(DerEncodedCert, Key)
end.
%%%%%%%%%%%%%%%%%%%%%%%%% Implementation %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
@@ -112,6 +125,7 @@ get_key(Opts) ->
undefined -> make_key(rsa, Opts);
rsa -> make_key(rsa, Opts);
dsa -> make_key(dsa, Opts);
+ ec -> make_key(ec, Opts);
Key ->
Password = proplists:get_value(password, Opts, no_passwd),
decode_key(Key, Password)
@@ -129,6 +143,8 @@ decode_key(#'RSAPrivateKey'{} = Key,_) ->
Key;
decode_key(#'DSAPrivateKey'{} = Key,_) ->
Key;
+decode_key(#'ECPrivateKey'{} = Key,_) ->
+ Key;
decode_key(PemEntry = {_,_,_}, Pw) ->
public_key:pem_entry_decode(PemEntry, Pw);
decode_key(PemBin, Pw) ->
@@ -140,7 +156,10 @@ encode_key(Key = #'RSAPrivateKey'{}) ->
{'RSAPrivateKey', Der, not_encrypted};
encode_key(Key = #'DSAPrivateKey'{}) ->
{ok, Der} = 'OTP-PUB-KEY':encode('DSAPrivateKey', Key),
- {'DSAPrivateKey', Der, not_encrypted}.
+ {'DSAPrivateKey', Der, not_encrypted};
+encode_key(Key = #'ECPrivateKey'{}) ->
+ {ok, Der} = 'OTP-PUB-KEY':encode('ECPrivateKey', Key),
+ {'ECPrivateKey', Der, not_encrypted}.
make_tbs(SubjectKey, Opts) ->
Version = list_to_atom("v"++integer_to_list(proplists:get_value(version, Opts, 3))),
@@ -282,7 +301,14 @@ publickey(#'RSAPrivateKey'{modulus=N, publicExponent=E}) ->
publickey(#'DSAPrivateKey'{p=P, q=Q, g=G, y=Y}) ->
Algo = #'PublicKeyAlgorithm'{algorithm= ?'id-dsa',
parameters={params, #'Dss-Parms'{p=P, q=Q, g=G}}},
- #'OTPSubjectPublicKeyInfo'{algorithm = Algo, subjectPublicKey = Y}.
+ #'OTPSubjectPublicKeyInfo'{algorithm = Algo, subjectPublicKey = Y};
+publickey(#'ECPrivateKey'{version = _Version,
+ privateKey = _PrivKey,
+ parameters = Params,
+ publicKey = {0, PubKey}}) ->
+ Algo = #'PublicKeyAlgorithm'{algorithm= ?'id-ecPublicKey', parameters=Params},
+ #'OTPSubjectPublicKeyInfo'{algorithm = Algo,
+ subjectPublicKey = #'ECPoint'{point = PubKey}}.
validity(Opts) ->
DefFrom0 = calendar:gregorian_days_to_date(calendar:date_to_gregorian_days(date())-1),
@@ -303,13 +329,24 @@ sign_algorithm(#'RSAPrivateKey'{}, Opts) ->
end,
{Type, 'NULL'};
sign_algorithm(#'DSAPrivateKey'{p=P, q=Q, g=G}, _Opts) ->
- {?'id-dsa-with-sha1', {params,#'Dss-Parms'{p=P, q=Q, g=G}}}.
+ {?'id-dsa-with-sha1', {params,#'Dss-Parms'{p=P, q=Q, g=G}}};
+sign_algorithm(#'ECPrivateKey'{}, Opts) ->
+ Type = case proplists:get_value(digest, Opts, sha1) of
+ sha1 -> ?'ecdsa-with-SHA1';
+ sha512 -> ?'ecdsa-with-SHA512';
+ sha384 -> ?'ecdsa-with-SHA384';
+ sha256 -> ?'ecdsa-with-SHA256'
+ end,
+ {Type, 'NULL'}.
make_key(rsa, _Opts) ->
%% (OBS: for testing only)
gen_rsa2(64);
make_key(dsa, _Opts) ->
- gen_dsa2(128, 20). %% Bytes i.e. {1024, 160}
+ gen_dsa2(128, 20); %% Bytes i.e. {1024, 160}
+make_key(ec, _Opts) ->
+ %% (OBS: for testing only)
+ gen_ec2(secp256k1).
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%% RSA key generation (OBS: for testing only)
@@ -354,13 +391,13 @@ gen_dsa2(LSize, NSize) ->
X0 = prime(LSize),
P0 = prime((LSize div 2) +1),
- %% Choose L-bit prime modulus P such that p–1 is a multiple of q.
+ %% Choose L-bit prime modulus P such that p-1 is a multiple of q.
case dsa_search(X0 div (2*Q*P0), P0, Q, 1000) of
error ->
gen_dsa2(LSize, NSize);
P ->
G = crypto:mod_exp(2, (P-1) div Q, P), % Choose G a number whose multiplicative order modulo p is q.
- %% such that This may be done by setting g = h^(p–1)/q mod p, commonly h=2 is used.
+ %% such that This may be done by setting g = h^(p-1)/q mod p, commonly h=2 is used.
X = prime(20), %% Choose x by some random method, where 0 < x < q.
Y = crypto:mod_exp(G, X, P), %% Calculate y = g^x mod p.
@@ -368,6 +405,24 @@ gen_dsa2(LSize, NSize) ->
#'DSAPrivateKey'{version=0, p=P, q=Q, g=G, y=Y, x=X}
end.
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%% EC key generation (OBS: for testing only)
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+int2list(I) ->
+ L = (length(integer_to_list(I, 16)) + 1) div 2,
+ binary_to_list(<<I:(L*8)>>).
+
+gen_ec2(CurveId) ->
+ Key = crypto:ec_key_new(CurveId),
+ crypto:ec_key_generate(Key),
+ {_Curve, PrivKey, PubKey} = crypto:ec_key_to_term(Key),
+
+ #'ECPrivateKey'{version = 1,
+ privateKey = int2list(PrivKey),
+ parameters = {namedCurve, pubkey_cert_records:namedCurves(CurveId)},
+ publicKey = {0, PubKey}}.
+
%% See fips_186-3.pdf
dsa_search(T, P0, Q, Iter) when Iter > 0 ->
P = 2*T*Q*P0 + 1,
diff --git a/lib/public_key/test/pkits_SUITE.erl b/lib/public_key/test/pkits_SUITE.erl
index d901adaadd..8cdf0aaae3 100644
--- a/lib/public_key/test/pkits_SUITE.erl
+++ b/lib/public_key/test/pkits_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2008-2012. All Rights Reserved.
+%% Copyright Ericsson AB 2008-2013. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -758,11 +758,10 @@ warning(Format, Args, File0, Line) ->
io:format("~s(~p): Warning "++Format, [File,Line|Args]).
crypto_support_check(Config) ->
- try crypto:sha256(<<"Test">>) of
- _ ->
- Config
- catch error:notsup ->
- crypto:stop(),
+ case proplists:get_bool(sha256, crypto:algorithms()) of
+ true ->
+ Config;
+ false ->
{skip, "To old version of openssl"}
end.
diff --git a/lib/public_key/test/public_key_SUITE.erl b/lib/public_key/test/public_key_SUITE.erl
index 0de80edeac..5a64140c67 100644
--- a/lib/public_key/test/public_key_SUITE.erl
+++ b/lib/public_key/test/public_key_SUITE.erl
@@ -551,7 +551,7 @@ dsa_sign_verify(Config) when is_list(Config) ->
false = public_key:verify(Msg, sha, <<1:8, DSASign/binary>>,
{DSAPublicKey, DSAParams}),
- Digest = crypto:sha(Msg),
+ Digest = crypto:hash(sha,Msg),
DigestSign = public_key:sign(Digest, none, DSAPrivateKey),
true = public_key:verify(Digest, none, DigestSign, {DSAPublicKey, DSAParams}),
<<_:8, RestDigest/binary>> = Digest,
diff --git a/lib/reltool/test/reltool_server_SUITE.erl b/lib/reltool/test/reltool_server_SUITE.erl
index b1e1787f18..752037042d 100644
--- a/lib/reltool/test/reltool_server_SUITE.erl
+++ b/lib/reltool/test/reltool_server_SUITE.erl
@@ -2595,8 +2595,8 @@ start_node(Name, ErlPath, Args0) ->
%io:format("open_port({spawn_executable, ~p}, [{args,~p}])~n",[ErlPath,Args]),
case open_port({spawn_executable, ErlPath}, [{args,Args}]) of
Port when is_port(Port) ->
- unlink(Port),
- erlang:port_close(Port),
+ %% no need to close port since node is detached (see
+ %% mk_node_args) so port will be closed anyway.
case ping_node(FullName, 50) of
ok -> {ok, FullName};
Other -> exit({failed_to_start_node, FullName, Other})
@@ -2629,7 +2629,7 @@ mk_node_args(Name, Args) ->
end,
{ok, Pwd} = file:get_cwd(),
NameStr = atom_to_list(Name),
- ["-detached", "-noinput",
+ ["-detached",
NameSw, NameStr,
"-pa", Pa,
"-env", "ERL_CRASH_DUMP", Pwd ++ "/erl_crash_dump." ++ NameStr,
diff --git a/lib/runtime_tools/src/dbg.erl b/lib/runtime_tools/src/dbg.erl
index 6e3bfe31c6..6b2fb0460f 100644
--- a/lib/runtime_tools/src/dbg.erl
+++ b/lib/runtime_tools/src/dbg.erl
@@ -551,8 +551,7 @@ c(M, F, A, Flags) ->
stop_clear(),
{error, Reason};
{Pid, Res} ->
- erlang:demonitor(Mref),
- receive {'DOWN', Mref, _, _, _} -> ok after 0 -> ok end,
+ erlang:demonitor(Mref, [flush]),
%% 'sleep' prevents the tracer (recv_all_traces) from
%% receiving garbage {'EXIT',...} when dbg i stopped.
timer:sleep(1),
@@ -592,8 +591,7 @@ req(R) ->
{'DOWN', Mref, _, _, _} -> % If server died
exit(dbg_server_crash);
{dbg, Reply} ->
- erlang:demonitor(Mref),
- receive {'DOWN', Mref, _, _, _} -> ok after 0 -> ok end,
+ erlang:demonitor(Mref, [flush]),
Reply
end.
diff --git a/lib/runtime_tools/src/ttb_autostart.erl b/lib/runtime_tools/src/ttb_autostart.erl
index 4c6971c119..5339507cec 100644
--- a/lib/runtime_tools/src/ttb_autostart.erl
+++ b/lib/runtime_tools/src/ttb_autostart.erl
@@ -1,3 +1,4 @@
+%%%-*- coding: utf-8 -*-
%%%-------------------------------------------------------------------
%%% File : ttb_autostart.erl
%%% Author : Bartłomiej Puzoń <[email protected]>
diff --git a/lib/sasl/test/release_handler_SUITE.erl b/lib/sasl/test/release_handler_SUITE.erl
index 97ba70c9bd..a56924d5ca 100644
--- a/lib/sasl/test/release_handler_SUITE.erl
+++ b/lib/sasl/test/release_handler_SUITE.erl
@@ -1112,10 +1112,10 @@ otp_9395_update_many_mods(Conf) when is_list(Conf) ->
true = rpc:call(Node,erlang,check_old_code,[m10]),
%% Run check_install_release with purge before install this time
- {TCheck,{ok, _RelVsn1, []}} =
+ {_TCheck,{ok, _RelVsn1, []}} =
timer:tc(rpc,call,[Node, release_handler, check_install_release,
[RelVsn2,[purge]]]),
-% ct:log("check_install_release with purge: ~.2f",[TCheck/1000000]),
+% ct:log("check_install_release with purge: ~.2f",[_TCheck/1000000]),
%% Finally install release after check and purge, and check that
%% this install was faster than the first.
@@ -1209,10 +1209,10 @@ otp_9395_rm_many_mods(Conf) when is_list(Conf) ->
true = rpc:call(Node,erlang,check_old_code,[m10]),
%% Run check_install_release with purge before install this time
- {TCheck,{ok, _RelVsn1, []}} =
+ {_TCheck,{ok, _RelVsn1, []}} =
timer:tc(rpc,call,[Node, release_handler, check_install_release,
[RelVsn2,[purge]]]),
-% ct:log("check_install_release with purge: ~.2f",[TCheck/1000000]),
+% ct:log("check_install_release with purge: ~.2f",[_TCheck/1000000]),
%% Finally install release after check and purge, and check that
%% this install was faster than the first.
diff --git a/lib/snmp/src/agent/snmpa_target_cache.erl b/lib/snmp/src/agent/snmpa_target_cache.erl
index 2aa35aa46a..1fcaf82373 100644
--- a/lib/snmp/src/agent/snmpa_target_cache.erl
+++ b/lib/snmp/src/agent/snmpa_target_cache.erl
@@ -21,8 +21,6 @@
-behaviour(gen_server).
%% External exports
-%% Avoid warning for local function demonitor/1 clashing with autoimported BIF.
--compile({no_auto_import,[demonitor/1]}).
-export([start_link/2, stop/0, verbosity/1]).
-export([
@@ -213,21 +211,6 @@ do_init(Prio, Opts) ->
%% requests will have to wait.
%%
-monitor(Pid) -> erlang:monitor(process, Pid).
--ifdef(SNMP_R10).
-demonitor(Ref) ->
- erlang:demonitor(Ref),
- receive
- {_, Ref, _, _, _} ->
- true
- after 0 ->
- true
- end.
--else.
-demonitor(Ref) ->
- erlang:demonitor(Ref, [flush]).
--endif.
-
%% (1) No write_lock active or waiting
handle_call({lock, read = Type, infinity}, {Pid, _} = From,
@@ -236,7 +219,7 @@ handle_call({lock, read = Type, infinity}, {Pid, _} = From,
"entry when no waiting or active writer with"
"~n Pid: ~p"
"~n Cnt: ~p", [Pid, Cnt]),
- MonRef = monitor(Pid),
+ MonRef = erlang:monitor(process, Pid),
Locker = #locker{pid = Pid,
from = From,
mon_ref = MonRef,
@@ -252,7 +235,7 @@ handle_call({lock, read = Type, infinity}, {Pid, _} = From, State) ->
?vlog("lock(read, infinity) -> "
"entry when active or waiting write locks with"
"~n Pid: ~p", [Pid]),
- MonRef = monitor(Pid),
+ MonRef = erlang:monitor(process, Pid),
Locker = #locker{pid = Pid,
from = From,
mon_ref = MonRef,
@@ -273,7 +256,7 @@ handle_call({lock, write = Type, infinity}, {Pid, _} = From,
?vlog("lock(write, infinity) -> "
"entry when no active lockers with"
"~n Pid: ~p", [Pid]),
- MonRef = monitor(Pid),
+ MonRef = erlang:monitor(process, Pid),
Locker = #locker{pid = Pid,
from = From,
mon_ref = MonRef,
@@ -290,7 +273,7 @@ handle_call({lock, write = Type, infinity}, {Pid, _} = From,
?vlog("lock(write, infinity) -> "
"entry when active lockers with"
"~n Pid: ~p", [Pid]),
- MonRef = monitor(Pid),
+ MonRef = erlang:monitor(process, Pid),
Locker = #locker{pid = Pid,
from = From,
mon_ref = MonRef,
@@ -307,7 +290,7 @@ handle_call({lock, write = Type, infinity}, {Pid, _} = From,
#state{writer = true} = State) ->
?vlog("lock(write, infinity) -> entry with"
"~n Pid: ~p", [Pid]),
- MonRef = monitor(Pid),
+ MonRef = erlang:monitor(process, Pid),
Locker = #locker{pid = Pid,
from = From,
mon_ref = MonRef,
@@ -429,7 +412,7 @@ handle_cast({unlock, Pid},
[#locker{mon_ref = MonRef, type = read}] ->
?vdebug("unlock -> found read locker"
"~n MonRef: ~p", [MonRef]),
- demonitor(MonRef),
+ erlang:demonitor(MonRef, [flush]),
ets:delete(?LOCKER_TAB, Pid),
%% ?vtrace("unlock -> done when"
%% "~n Lockers: ~p", [ets:tab2list(?LOCKER_TAB)]),
@@ -437,7 +420,7 @@ handle_cast({unlock, Pid},
[#locker{mon_ref = MonRef, type = write}] ->
?vdebug("unlock -> found write locker"
"~n MonRef: ~p", [MonRef]),
- demonitor(MonRef),
+ erlang:demonitor(MonRef, [flush]),
ets:delete(?LOCKER_TAB, Pid),
%% ?vtrace("unlock -> done when"
%% "~n Lockers: ~p", [ets:tab2list(?LOCKER_TAB)]),
@@ -459,7 +442,7 @@ handle_cast({unlock, Pid},
[#locker{mon_ref = MonRef, type = read}] when (Cnt == 1) ->
?vdebug("unlock -> found read locker"
"~n MonRef: ~p", [MonRef]),
- demonitor(MonRef),
+ erlang:demonitor(MonRef, [flush]),
ets:delete(?LOCKER_TAB, Pid),
case active_waiting_writer(Waiting) of
{true, StillWaiting} ->
@@ -482,7 +465,7 @@ handle_cast({unlock, Pid},
[#locker{mon_ref = MonRef, type = read}] ->
?vdebug("unlock -> found read locker"
"~n MonRef: ~p", [MonRef]),
- demonitor(MonRef),
+ erlang:demonitor(MonRef, [flush]),
ets:delete(?LOCKER_TAB, Pid),
%% ?vtrace("unlock -> done when"
%% "~n Lockers: ~p", [ets:tab2list(?LOCKER_TAB)]),
@@ -492,7 +475,7 @@ handle_cast({unlock, Pid},
%% Release the hord (maybe)
?vdebug("unlock -> found write locker"
"~n MonRef: ~p", [MonRef]),
- demonitor(MonRef),
+ erlang:demonitor(MonRef, [flush]),
ets:delete(?LOCKER_TAB, Pid),
{Active, StillWaiting, Writer} =
activate_waiting_readers_or_maybe_writer(Waiting),
diff --git a/lib/ssh/src/ssh_cli.erl b/lib/ssh/src/ssh_cli.erl
index 0531ad7830..69b1ab186f 100644
--- a/lib/ssh/src/ssh_cli.erl
+++ b/lib/ssh/src/ssh_cli.erl
@@ -230,11 +230,11 @@ io_request({window_change, OldTty}, Buf, Tty) ->
io_request({put_chars, Cs}, Buf, Tty) ->
put_chars(bin_to_list(Cs), Buf, Tty);
io_request({put_chars, unicode, Cs}, Buf, Tty) ->
- put_chars([Ch || Ch <- unicode:characters_to_list(Cs,unicode), Ch =< 255], Buf, Tty);
+ put_chars(unicode:characters_to_list(Cs,unicode), Buf, Tty);
io_request({insert_chars, Cs}, Buf, Tty) ->
insert_chars(bin_to_list(Cs), Buf, Tty);
io_request({insert_chars, unicode, Cs}, Buf, Tty) ->
- insert_chars([Ch || Ch <- unicode:characters_to_list(Cs,unicode), Ch =< 255], Buf, Tty);
+ insert_chars(unicode:characters_to_list(Cs,unicode), Buf, Tty);
io_request({move_rel, N}, Buf, Tty) ->
move_rel(N, Buf, Tty);
io_request({delete_chars,N}, Buf, Tty) ->
diff --git a/lib/ssh/src/ssh_xfer.erl b/lib/ssh/src/ssh_xfer.erl
index 4dfd9ed8b0..93f9e20663 100644
--- a/lib/ssh/src/ssh_xfer.erl
+++ b/lib/ssh/src/ssh_xfer.erl
@@ -72,7 +72,7 @@ protocol_version_request(XF) ->
open(XF, ReqID, FileName, Access, Flags, Attrs) ->
Vsn = XF#ssh_xfer.vsn,
- FileName1 = list_to_binary(FileName),
+ FileName1 = unicode:characters_to_binary(FileName),
MBits = if Vsn >= 5 ->
M = encode_ace_mask(Access),
?uint32(M);
@@ -115,7 +115,7 @@ write(XF,ReqID, Handle, Offset, Data) ->
is_binary(Data) ->
Data;
is_list(Data) ->
- list_to_binary(Data)
+ unicode:characters_to_binary(Data)
end,
xf_request(XF,?SSH_FXP_WRITE,
[?uint32(ReqID),
@@ -132,8 +132,8 @@ remove(XF, ReqID, File) ->
%% Rename a file/directory
rename(XF, ReqID, Old, New, Flags) ->
Vsn = XF#ssh_xfer.vsn,
- OldPath = list_to_binary(Old),
- NewPath = list_to_binary(New),
+ OldPath = unicode:characters_to_binary(Old),
+ NewPath = unicode:characters_to_binary(New),
FlagBits
= if Vsn >= 5 ->
F0 = encode_rename_flags(Flags),
@@ -151,7 +151,7 @@ rename(XF, ReqID, Old, New, Flags) ->
%% Create directory
mkdir(XF, ReqID, Path, Attrs) ->
- Path1 = list_to_binary(Path),
+ Path1 = unicode:characters_to_binary(Path),
xf_request(XF, ?SSH_FXP_MKDIR,
[?uint32(ReqID),
?binary(Path1),
@@ -159,14 +159,14 @@ mkdir(XF, ReqID, Path, Attrs) ->
%% Remove a directory
rmdir(XF, ReqID, Dir) ->
- Dir1 = list_to_binary(Dir),
+ Dir1 = unicode:characters_to_binary(Dir),
xf_request(XF, ?SSH_FXP_RMDIR,
[?uint32(ReqID),
?binary(Dir1)]).
%% Stat file
stat(XF, ReqID, Path, Flags) ->
- Path1 = list_to_binary(Path),
+ Path1 = unicode:characters_to_binary(Path),
Vsn = XF#ssh_xfer.vsn,
AttrFlags = if Vsn >= 5 ->
F = encode_attr_flags(Vsn, Flags),
@@ -182,7 +182,7 @@ stat(XF, ReqID, Path, Flags) ->
%% Stat file - follow symbolic links
lstat(XF, ReqID, Path, Flags) ->
- Path1 = list_to_binary(Path),
+ Path1 = unicode:characters_to_binary(Path),
Vsn = XF#ssh_xfer.vsn,
AttrFlags = if Vsn >= 5 ->
F = encode_attr_flags(Vsn, Flags),
@@ -211,7 +211,7 @@ fstat(XF, ReqID, Handle, Flags) ->
%% Modify file attributes
setstat(XF, ReqID, Path, Attrs) ->
- Path1 = list_to_binary(Path),
+ Path1 = unicode:characters_to_binary(Path),
xf_request(XF, ?SSH_FXP_SETSTAT,
[?uint32(ReqID),
?binary(Path1),
@@ -227,7 +227,7 @@ fsetstat(XF, ReqID, Handle, Attrs) ->
%% Read a symbolic link
readlink(XF, ReqID, Path) ->
- Path1 = list_to_binary(Path),
+ Path1 = unicode:characters_to_binary(Path),
xf_request(XF, ?SSH_FXP_READLINK,
[?uint32(ReqID),
?binary(Path1)]).
@@ -235,8 +235,8 @@ readlink(XF, ReqID, Path) ->
%% Create a symbolic link
symlink(XF, ReqID, LinkPath, TargetPath) ->
- LinkPath1 = list_to_binary(LinkPath),
- TargetPath1 = list_to_binary(TargetPath),
+ LinkPath1 = unicode:characters_to_binary(LinkPath),
+ TargetPath1 = unicode:characters_to_binary(TargetPath),
xf_request(XF, ?SSH_FXP_SYMLINK,
[?uint32(ReqID),
?binary(LinkPath1),
@@ -244,7 +244,7 @@ symlink(XF, ReqID, LinkPath, TargetPath) ->
%% Convert a path into a 'canonical' form
realpath(XF, ReqID, Path) ->
- Path1 = list_to_binary(Path),
+ Path1 = unicode:characters_to_binary(Path),
xf_request(XF, ?SSH_FXP_REALPATH,
[?uint32(ReqID),
?binary(Path1)]).
diff --git a/lib/ssl/doc/src/ssl.xml b/lib/ssl/doc/src/ssl.xml
index d5615fecfc..1645eb15f3 100644
--- a/lib/ssl/doc/src/ssl.xml
+++ b/lib/ssl/doc/src/ssl.xml
@@ -37,17 +37,21 @@
<list type="bulleted">
<item>ssl requires the crypto and public_key applications.</item>
<item>Supported SSL/TLS-versions are SSL-3.0, TLS-1.0,
- TLS-1.1 and TLS-1.2 (no support for elliptic curve cipher suites yet).</item>
+ TLS-1.1 and TLS-1.2.</item>
<item>For security reasons sslv2 is not supported.</item>
<item>Ephemeral Diffie-Hellman cipher suites are supported
but not Diffie Hellman Certificates cipher suites.</item>
+ <item>Elliptic Curve cipher suites are supported if crypto
+ supports it and named curves are used.
+ </item>
<item>Export cipher suites are not supported as the
U.S. lifted its export restrictions in early 2000.</item>
<item>IDEA cipher suites are not supported as they have
become deprecated by the latest TLS spec so there is not any
real motivation to implement them.</item>
- <item>CRL and policy certificate
- extensions are not supported yet. </item>
+ <item>CRL and policy certificate extensions are not supported
+ yet. However CRL verification is supported by public_key, only not integrated
+ in ssl yet. </item>
</list>
</section>
@@ -75,7 +79,7 @@
{fail_if_no_peer_cert, boolean()}
{depth, integer()} |
{cert, der_encoded()}| {certfile, path()} |
- {key, {'RSAPrivateKey'| 'DSAPrivateKey' | 'PrivateKeyInfo', der_encoded()}} |
+ {key, {'RSAPrivateKey'| 'DSAPrivateKey' | 'ECPrivateKey' |'PrivateKeyInfo', der_encoded()}} |
{keyfile, path()} | {password, string()} |
{cacerts, [der_encoded()]} | {cacertfile, path()} |
|{dh, der_encoded()} | {dhfile, path()} | {ciphers, ciphers()} |
@@ -125,6 +129,7 @@
<p><c>key_exchange() = rsa | dhe_dss | dhe_rsa | dh_anon
| psk | dhe_psk | rsa_psk | srp_anon | srp_dss | srp_rsa
+ | ecdh_anon | ecdh_ecdsa | ecdhe_ecdsa | ecdh_rsa | ecdhe_rsa
</c></p>
<p><c>cipher() = rc4_128 | des_cbc | '3des_ede_cbc'
@@ -157,7 +162,7 @@
<tag>{certfile, path()}</tag>
<item>Path to a file containing the user's certificate.</item>
- <tag>{key, {'RSAPrivateKey'| 'DSAPrivateKey' | 'PrivateKeyInfo', der_encoded()}}</tag>
+ <tag>{key, {'RSAPrivateKey'| 'DSAPrivateKey' | 'ECPrivateKey' |'PrivateKeyInfo', der_encoded()}}</tag>
<item> The DER encoded users private key. If this option
is supplied it will override the keyfile option.</item>
diff --git a/lib/ssl/src/ssl.erl b/lib/ssl/src/ssl.erl
index 70f3b4f050..f52862729a 100644
--- a/lib/ssl/src/ssl.erl
+++ b/lib/ssl/src/ssl.erl
@@ -364,11 +364,11 @@ cipher_suites() ->
cipher_suites(erlang) ->
Version = ssl_record:highest_protocol_version([]),
- [suite_definition(S) || S <- ssl_cipher:suites(Version)];
+ [suite_definition(S) || S <- cipher_suites(Version, [])];
cipher_suites(openssl) ->
Version = ssl_record:highest_protocol_version([]),
- [ssl_cipher:openssl_suite_name(S) || S <- ssl_cipher:suites(Version)];
+ [ssl_cipher:openssl_suite_name(S) || S <- cipher_suites(Version, [])];
cipher_suites(all) ->
Version = ssl_record:highest_protocol_version([]),
@@ -739,6 +739,7 @@ validate_option(key, {KeyType, Value}) when is_binary(Value),
KeyType == dsa; %% Backwards compatibility
KeyType == 'RSAPrivateKey';
KeyType == 'DSAPrivateKey';
+ KeyType == 'ECPrivateKey';
KeyType == 'PrivateKeyInfo' ->
{KeyType, Value};
@@ -947,21 +948,22 @@ emulated_options([], Inet,Emulated) ->
{Inet, Emulated}.
cipher_suites(Version, []) ->
- ssl_cipher:suites(Version);
+ ssl_cipher:filter_suites(ssl_cipher:suites(Version));
cipher_suites(Version, [{_,_,_,_}| _] = Ciphers0) -> %% Backwards compatibility
Ciphers = [{KeyExchange, Cipher, Hash} || {KeyExchange, Cipher, Hash, _} <- Ciphers0],
- cipher_suites(Version, Ciphers);
+ ssl_cipher:filter_suites(cipher_suites(Version, Ciphers));
cipher_suites(Version, [{_,_,_}| _] = Ciphers0) ->
Ciphers = [ssl_cipher:suite(C) || C <- Ciphers0],
- cipher_suites(Version, Ciphers);
+ ssl_cipher:filter_suites(cipher_suites(Version, Ciphers));
cipher_suites(Version, [Cipher0 | _] = Ciphers0) when is_binary(Cipher0) ->
- Supported = ssl_cipher:suites(Version)
+ Supported0 = ssl_cipher:suites(Version)
++ ssl_cipher:anonymous_suites()
++ ssl_cipher:psk_suites(Version)
++ ssl_cipher:srp_suites(),
- case [Cipher || Cipher <- Ciphers0, lists:member(Cipher, Supported)] of
+ Supported1 = ssl_cipher:filter_suites(Supported0),
+ case [Cipher || Cipher <- Ciphers0, lists:member(Cipher, Supported1)] of
[] ->
- Supported;
+ Supported1;
Ciphers ->
Ciphers
end;
diff --git a/lib/ssl/src/ssl_certificate.erl b/lib/ssl/src/ssl_certificate.erl
index 01a7cd93b5..9e1c3a09bf 100644
--- a/lib/ssl/src/ssl_certificate.erl
+++ b/lib/ssl/src/ssl_certificate.erl
@@ -37,7 +37,8 @@
is_valid_extkey_usage/2,
is_valid_key_usage/2,
select_extension/2,
- extensions_list/1
+ extensions_list/1,
+ public_key_type/1
]).
%%====================================================================
@@ -166,6 +167,18 @@ extensions_list(Extensions) ->
Extensions.
%%--------------------------------------------------------------------
+-spec public_key_type(term()) -> rsa | dsa | ec.
+%%
+%% Description:
+%%--------------------------------------------------------------------
+public_key_type(?'rsaEncryption') ->
+ rsa;
+public_key_type(?'id-dsa') ->
+ dsa;
+public_key_type(?'id-ecPublicKey') ->
+ ec.
+
+%%--------------------------------------------------------------------
%%% Internal functions
%%--------------------------------------------------------------------
certificate_chain(OtpCert, _Cert, CertDbHandle, CertsDbRef, Chain) ->
diff --git a/lib/ssl/src/ssl_certificate_db.erl b/lib/ssl/src/ssl_certificate_db.erl
index ff36b5ee26..cdff73336e 100644
--- a/lib/ssl/src/ssl_certificate_db.erl
+++ b/lib/ssl/src/ssl_certificate_db.erl
@@ -100,7 +100,7 @@ add_trusted_certs(_Pid, {der, DerList}, [CerDb, _,_]) ->
{ok, NewRef};
add_trusted_certs(_Pid, File, [CertsDb, RefDb, PemChache] = Db) ->
- MD5 = crypto:md5(File),
+ MD5 = crypto:hash(md5, File),
case lookup_cached_pem(Db, MD5) of
[{_Content, Ref}] ->
ref_count(Ref, RefDb, 1),
diff --git a/lib/ssl/src/ssl_cipher.erl b/lib/ssl/src/ssl_cipher.erl
index 173c53709b..dc413d6dfc 100644
--- a/lib/ssl/src/ssl_cipher.erl
+++ b/lib/ssl/src/ssl_cipher.erl
@@ -35,7 +35,7 @@
-export([security_parameters/3, suite_definition/1,
decipher/5, cipher/5,
suite/1, suites/1, anonymous_suites/0, psk_suites/1, srp_suites/0,
- openssl_suite/1, openssl_suite_name/1, filter/2,
+ openssl_suite/1, openssl_suite_name/1, filter/2, filter_suites/1,
hash_algorithm/1, sign_algorithm/1]).
-compile(inline).
@@ -73,25 +73,25 @@ cipher(?NULL, CipherState, <<>>, Fragment, _Version) ->
{GenStreamCipherList, CipherState};
cipher(?RC4, CipherState, Mac, Fragment, _Version) ->
State0 = case CipherState#cipher_state.state of
- undefined -> crypto:rc4_set_key(CipherState#cipher_state.key);
+ undefined -> crypto:stream_init(rc4, CipherState#cipher_state.key);
S -> S
end,
GenStreamCipherList = [Fragment, Mac],
- {State1, T} = crypto:rc4_encrypt_with_state(State0, GenStreamCipherList),
+ {State1, T} = crypto:stream_encrypt(State0, GenStreamCipherList),
{T, CipherState#cipher_state{state = State1}};
cipher(?DES, CipherState, Mac, Fragment, Version) ->
block_cipher(fun(Key, IV, T) ->
- crypto:des_cbc_encrypt(Key, IV, T)
+ crypto:block_encrypt(des_cbc, Key, IV, T)
end, block_size(des_cbc), CipherState, Mac, Fragment, Version);
cipher(?'3DES', CipherState, Mac, Fragment, Version) ->
block_cipher(fun(<<K1:8/binary, K2:8/binary, K3:8/binary>>, IV, T) ->
- crypto:des3_cbc_encrypt(K1, K2, K3, IV, T)
+ crypto:block_encrypt(des3_cbc, [K1, K2, K3], IV, T)
end, block_size(des_cbc), CipherState, Mac, Fragment, Version);
cipher(?AES, CipherState, Mac, Fragment, Version) ->
block_cipher(fun(Key, IV, T) when byte_size(Key) =:= 16 ->
- crypto:aes_cbc_128_encrypt(Key, IV, T);
+ crypto:block_encrypt(aes_cbc128, Key, IV, T);
(Key, IV, T) when byte_size(Key) =:= 32 ->
- crypto:aes_cbc_256_encrypt(Key, IV, T)
+ crypto:block_encrypt(aes_cbc256, Key, IV, T)
end, block_size(aes_128_cbc), CipherState, Mac, Fragment, Version).
build_cipher_block(BlockSz, Mac, Fragment) ->
@@ -127,10 +127,10 @@ decipher(?NULL, _HashSz, CipherState, Fragment, _) ->
{Fragment, <<>>, CipherState};
decipher(?RC4, HashSz, CipherState, Fragment, _) ->
State0 = case CipherState#cipher_state.state of
- undefined -> crypto:rc4_set_key(CipherState#cipher_state.key);
+ undefined -> crypto:stream_init(rc4, CipherState#cipher_state.key);
S -> S
end,
- try crypto:rc4_encrypt_with_state(State0, Fragment) of
+ try crypto:stream_decrypt(State0, Fragment) of
{State, Text} ->
GSC = generic_stream_cipher_from_bin(Text, HashSz),
#generic_stream_cipher{content = Content, mac = Mac} = GSC,
@@ -147,17 +147,17 @@ decipher(?RC4, HashSz, CipherState, Fragment, _) ->
decipher(?DES, HashSz, CipherState, Fragment, Version) ->
block_decipher(fun(Key, IV, T) ->
- crypto:des_cbc_decrypt(Key, IV, T)
+ crypto:block_decrypt(des_cbc, Key, IV, T)
end, CipherState, HashSz, Fragment, Version);
decipher(?'3DES', HashSz, CipherState, Fragment, Version) ->
block_decipher(fun(<<K1:8/binary, K2:8/binary, K3:8/binary>>, IV, T) ->
- crypto:des3_cbc_decrypt(K1, K2, K3, IV, T)
+ crypto:block_decrypt(des3_cbc, [K1, K2, K3], IV, T)
end, CipherState, HashSz, Fragment, Version);
decipher(?AES, HashSz, CipherState, Fragment, Version) ->
block_decipher(fun(Key, IV, T) when byte_size(Key) =:= 16 ->
- crypto:aes_cbc_128_decrypt(Key, IV, T);
+ crypto:block_decrypt(aes_cbc128, Key, IV, T);
(Key, IV, T) when byte_size(Key) =:= 32 ->
- crypto:aes_cbc_256_decrypt(Key, IV, T)
+ crypto:block_decrypt(aes_cbc256, Key, IV, T)
end, CipherState, HashSz, Fragment, Version).
block_decipher(Fun, #cipher_state{key=Key, iv=IV} = CipherState0,
@@ -212,10 +212,14 @@ anonymous_suites() ->
?TLS_DH_anon_WITH_AES_128_CBC_SHA,
?TLS_DH_anon_WITH_AES_256_CBC_SHA,
?TLS_DH_anon_WITH_AES_128_CBC_SHA256,
- ?TLS_DH_anon_WITH_AES_256_CBC_SHA256].
+ ?TLS_DH_anon_WITH_AES_256_CBC_SHA256,
+ ?TLS_ECDH_anon_WITH_RC4_128_SHA,
+ ?TLS_ECDH_anon_WITH_3DES_EDE_CBC_SHA,
+ ?TLS_ECDH_anon_WITH_AES_128_CBC_SHA,
+ ?TLS_ECDH_anon_WITH_AES_256_CBC_SHA].
%%--------------------------------------------------------------------
--spec psk_suites(tls_version()) -> [cipher_suite()].
+-spec psk_suites(tls_version() | integer()) -> [cipher_suite()].
%%
%% Description: Returns a list of the PSK cipher suites, only supported
%% if explicitly set by user.
@@ -274,6 +278,11 @@ srp_suites() ->
%% TLS v1.1 suites
suite_definition(?TLS_NULL_WITH_NULL_NULL) ->
{null, null, null, null};
+%% RFC 5746 - Not a real cipher suite used to signal empty "renegotiation_info" extension
+%% to avoid handshake failure from old servers that do not ignore
+%% hello extension data as they should.
+suite_definition(?TLS_EMPTY_RENEGOTIATION_INFO_SCSV) ->
+ {null, null, null, null};
%% suite_definition(?TLS_RSA_WITH_NULL_MD5) ->
%% {rsa, null, md5, default_prf};
%% suite_definition(?TLS_RSA_WITH_NULL_SHA) ->
@@ -423,8 +432,81 @@ suite_definition(?TLS_SRP_SHA_WITH_AES_256_CBC_SHA) ->
suite_definition(?TLS_SRP_SHA_RSA_WITH_AES_256_CBC_SHA) ->
{srp_rsa, aes_256_cbc, sha, default_prf};
suite_definition(?TLS_SRP_SHA_DSS_WITH_AES_256_CBC_SHA) ->
- {srp_dss, aes_256_cbc, sha, default_prf}.
-
+ {srp_dss, aes_256_cbc, sha, default_prf};
+
+%% RFC 4492 EC TLS suites
+suite_definition(?TLS_ECDH_ECDSA_WITH_NULL_SHA) ->
+ {ecdh_ecdsa, null, sha, default_prf};
+suite_definition(?TLS_ECDH_ECDSA_WITH_RC4_128_SHA) ->
+ {ecdh_ecdsa, rc4_128, sha, default_prf};
+suite_definition(?TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA) ->
+ {ecdh_ecdsa, '3des_ede_cbc', sha, default_prf};
+suite_definition(?TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA) ->
+ {ecdh_ecdsa, aes_128_cbc, sha, default_prf};
+suite_definition(?TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA) ->
+ {ecdh_ecdsa, aes_256_cbc, sha, default_prf};
+
+suite_definition(?TLS_ECDHE_ECDSA_WITH_NULL_SHA) ->
+ {ecdhe_ecdsa, null, sha, default_prf};
+suite_definition(?TLS_ECDHE_ECDSA_WITH_RC4_128_SHA) ->
+ {ecdhe_ecdsa, rc4_128, sha, default_prf};
+suite_definition(?TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA) ->
+ {ecdhe_ecdsa, '3des_ede_cbc', sha, default_prf};
+suite_definition(?TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA) ->
+ {ecdhe_ecdsa, aes_128_cbc, sha, default_prf};
+suite_definition(?TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA) ->
+ {ecdhe_ecdsa, aes_256_cbc, sha, default_prf};
+
+suite_definition(?TLS_ECDH_RSA_WITH_NULL_SHA) ->
+ {ecdh_rsa, null, sha, default_prf};
+suite_definition(?TLS_ECDH_RSA_WITH_RC4_128_SHA) ->
+ {ecdh_rsa, rc4_128, sha, default_prf};
+suite_definition(?TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA) ->
+ {ecdh_rsa, '3des_ede_cbc', sha, default_prf};
+suite_definition(?TLS_ECDH_RSA_WITH_AES_128_CBC_SHA) ->
+ {ecdh_rsa, aes_128_cbc, sha, default_prf};
+suite_definition(?TLS_ECDH_RSA_WITH_AES_256_CBC_SHA) ->
+ {ecdh_rsa, aes_256_cbc, sha, default_prf};
+
+suite_definition(?TLS_ECDHE_RSA_WITH_NULL_SHA) ->
+ {ecdhe_rsa, null, sha, default_prf};
+suite_definition(?TLS_ECDHE_RSA_WITH_RC4_128_SHA) ->
+ {ecdhe_rsa, rc4_128, sha, default_prf};
+suite_definition(?TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA) ->
+ {ecdhe_rsa, '3des_ede_cbc', sha, default_prf};
+suite_definition(?TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA) ->
+ {ecdhe_rsa, aes_128_cbc, sha, default_prf};
+suite_definition(?TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA) ->
+ {ecdhe_rsa, aes_256_cbc, sha, default_prf};
+
+suite_definition(?TLS_ECDH_anon_WITH_NULL_SHA) ->
+ {ecdh_anon, null, sha, default_prf};
+suite_definition(?TLS_ECDH_anon_WITH_RC4_128_SHA) ->
+ {ecdh_anon, rc4_128, sha, default_prf};
+suite_definition(?TLS_ECDH_anon_WITH_3DES_EDE_CBC_SHA) ->
+ {ecdh_anon, '3des_ede_cbc', sha, default_prf};
+suite_definition(?TLS_ECDH_anon_WITH_AES_128_CBC_SHA) ->
+ {ecdh_anon, aes_128_cbc, sha, default_prf};
+suite_definition(?TLS_ECDH_anon_WITH_AES_256_CBC_SHA) ->
+ {ecdh_anon, aes_256_cbc, sha, default_prf};
+
+%% RFC 5289 EC TLS suites
+suite_definition(?TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256) ->
+ {ecdhe_ecdsa, aes_128_cbc, sha256, sha256};
+suite_definition(?TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384) ->
+ {ecdhe_ecdsa, aes_256_cbc, sha384, sha384};
+suite_definition(?TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA256) ->
+ {ecdh_ecdsa, aes_128_cbc, sha256, sha256};
+suite_definition(?TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA384) ->
+ {ecdh_ecdsa, aes_256_cbc, sha384, sha384};
+suite_definition(?TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256) ->
+ {ecdhe_rsa, aes_128_cbc, sha256, sha256};
+suite_definition(?TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384) ->
+ {ecdhe_rsa, aes_256_cbc, sha384, sha384};
+suite_definition(?TLS_ECDH_RSA_WITH_AES_128_CBC_SHA256) ->
+ {ecdh_rsa, aes_128_cbc, sha256, sha256};
+suite_definition(?TLS_ECDH_RSA_WITH_AES_256_CBC_SHA384) ->
+ {ecdh_rsa, aes_256_cbc, sha384, sha384}.
%%--------------------------------------------------------------------
-spec suite(erl_cipher_suite()) -> cipher_suite().
@@ -573,7 +655,81 @@ suite({srp_anon, aes_256_cbc, sha}) ->
suite({srp_rsa, aes_256_cbc, sha}) ->
?TLS_SRP_SHA_RSA_WITH_AES_256_CBC_SHA;
suite({srp_dss, aes_256_cbc, sha}) ->
- ?TLS_SRP_SHA_DSS_WITH_AES_256_CBC_SHA.
+ ?TLS_SRP_SHA_DSS_WITH_AES_256_CBC_SHA;
+
+%%% RFC 4492 EC TLS suites
+suite({ecdh_ecdsa, null, sha}) ->
+ ?TLS_ECDH_ECDSA_WITH_NULL_SHA;
+suite({ecdh_ecdsa, rc4_128, sha}) ->
+ ?TLS_ECDH_ECDSA_WITH_RC4_128_SHA;
+suite({ecdh_ecdsa, '3des_ede_cbc', sha}) ->
+ ?TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA;
+suite({ecdh_ecdsa, aes_128_cbc, sha}) ->
+ ?TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA;
+suite({ecdh_ecdsa, aes_256_cbc, sha}) ->
+ ?TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA;
+
+suite({ecdhe_ecdsa, null, sha}) ->
+ ?TLS_ECDHE_ECDSA_WITH_NULL_SHA;
+suite({ecdhe_ecdsa, rc4_128, sha}) ->
+ ?TLS_ECDHE_ECDSA_WITH_RC4_128_SHA;
+suite({ecdhe_ecdsa, '3des_ede_cbc', sha}) ->
+ ?TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA;
+suite({ecdhe_ecdsa, aes_128_cbc, sha}) ->
+ ?TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA;
+suite({ecdhe_ecdsa, aes_256_cbc, sha}) ->
+ ?TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA;
+
+suite({ecdh_rsa, null, sha}) ->
+ ?TLS_ECDH_RSA_WITH_NULL_SHA;
+suite({ecdh_rsa, rc4_128, sha}) ->
+ ?TLS_ECDH_RSA_WITH_RC4_128_SHA;
+suite({ecdh_rsa, '3des_ede_cbc', sha}) ->
+ ?TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA;
+suite({ecdh_rsa, aes_128_cbc, sha}) ->
+ ?TLS_ECDH_RSA_WITH_AES_128_CBC_SHA;
+suite({ecdh_rsa, aes_256_cbc, sha}) ->
+ ?TLS_ECDH_RSA_WITH_AES_256_CBC_SHA;
+
+suite({ecdhe_rsa, null, sha}) ->
+ ?TLS_ECDHE_RSA_WITH_NULL_SHA;
+suite({ecdhe_rsa, rc4_128, sha}) ->
+ ?TLS_ECDHE_RSA_WITH_RC4_128_SHA;
+suite({ecdhe_rsa, '3des_ede_cbc', sha}) ->
+ ?TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA;
+suite({ecdhe_rsa, aes_128_cbc, sha}) ->
+ ?TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA;
+suite({ecdhe_rsa, aes_256_cbc, sha}) ->
+ ?TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA;
+
+suite({ecdh_anon, null, sha}) ->
+ ?TLS_ECDH_anon_WITH_NULL_SHA;
+suite({ecdh_anon, rc4_128, sha}) ->
+ ?TLS_ECDH_anon_WITH_RC4_128_SHA;
+suite({ecdh_anon, '3des_ede_cbc', sha}) ->
+ ?TLS_ECDH_anon_WITH_3DES_EDE_CBC_SHA;
+suite({ecdh_anon, aes_128_cbc, sha}) ->
+ ?TLS_ECDH_anon_WITH_AES_128_CBC_SHA;
+suite({ecdh_anon, aes_256_cbc, sha}) ->
+ ?TLS_ECDH_anon_WITH_AES_256_CBC_SHA;
+
+%%% RFC 5289 EC TLS suites
+suite({ecdhe_ecdsa, aes_128_cbc, sha256}) ->
+ ?TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256;
+suite({ecdhe_ecdsa, aes_256_cbc, sha384}) ->
+ ?TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384;
+suite({ecdh_ecdsa, aes_128_cbc, sha256}) ->
+ ?TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA256;
+suite({ecdh_ecdsa, aes_256_cbc, sha384}) ->
+ ?TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA384;
+suite({ecdhe_rsa, aes_128_cbc, sha256}) ->
+ ?TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256;
+suite({ecdhe_rsa, aes_256_cbc, sha384}) ->
+ ?TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384;
+suite({ecdh_rsa, aes_128_cbc, sha256}) ->
+ ?TLS_ECDH_RSA_WITH_AES_128_CBC_SHA256;
+suite({ecdh_rsa, aes_256_cbc, sha384}) ->
+ ?TLS_ECDH_RSA_WITH_AES_256_CBC_SHA384.
%%--------------------------------------------------------------------
-spec openssl_suite(openssl_cipher_suite()) -> cipher_suite().
@@ -633,8 +789,62 @@ openssl_suite("SRP-RSA-3DES-EDE-CBC-SHA") ->
openssl_suite("SRP-DSS-AES-128-CBC-SHA") ->
?TLS_SRP_SHA_DSS_WITH_AES_128_CBC_SHA;
openssl_suite("SRP-RSA-AES-128-CBC-SHA") ->
- ?TLS_SRP_SHA_RSA_WITH_AES_128_CBC_SHA.
+ ?TLS_SRP_SHA_RSA_WITH_AES_128_CBC_SHA;
+%% RFC 4492 EC TLS suites
+openssl_suite("ECDH-ECDSA-RC4-SHA") ->
+ ?TLS_ECDH_ECDSA_WITH_RC4_128_SHA;
+openssl_suite("ECDH-ECDSA-DES-CBC3-SHA") ->
+ ?TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA;
+openssl_suite("ECDH-ECDSA-AES128-SHA") ->
+ ?TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA;
+openssl_suite("ECDH-ECDSA-AES256-SHA") ->
+ ?TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA;
+
+openssl_suite("ECDHE-ECDSA-RC4-SHA") ->
+ ?TLS_ECDHE_ECDSA_WITH_RC4_128_SHA;
+openssl_suite("ECDHE-ECDSA-DES-CBC3-SHA") ->
+ ?TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA;
+openssl_suite("ECDHE-ECDSA-AES128-SHA") ->
+ ?TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA;
+openssl_suite("ECDHE-ECDSA-AES256-SHA") ->
+ ?TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA;
+
+openssl_suite("ECDHE-RSA-RC4-SHA") ->
+ ?TLS_ECDHE_RSA_WITH_RC4_128_SHA;
+openssl_suite("ECDHE-RSA-DES-CBC3-SHA") ->
+ ?TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA;
+openssl_suite("ECDHE-RSA-AES128-SHA") ->
+ ?TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA;
+openssl_suite("ECDHE-RSA-AES256-SHA") ->
+ ?TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA;
+
+openssl_suite("ECDH-RSA-RC4-SHA") ->
+ ?TLS_ECDH_RSA_WITH_RC4_128_SHA;
+openssl_suite("ECDH-RSA-DES-CBC3-SHA") ->
+ ?TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA;
+openssl_suite("ECDH-RSA-AES128-SHA") ->
+ ?TLS_ECDH_RSA_WITH_AES_128_CBC_SHA;
+openssl_suite("ECDH-RSA-AES256-SHA") ->
+ ?TLS_ECDH_RSA_WITH_AES_256_CBC_SHA;
+
+%% RFC 5289 EC TLS suites
+openssl_suite("ECDHE-ECDSA-AES128-SHA256") ->
+ ?TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256;
+openssl_suite("ECDHE-ECDSA-AES256-SHA384") ->
+ ?TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384;
+openssl_suite("ECDH-ECDSA-AES128-SHA256") ->
+ ?TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA256;
+openssl_suite("ECDH-ECDSA-AES256-SHA384") ->
+ ?TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA384;
+openssl_suite("ECDHE-RSA-AES128-SHA256") ->
+ ?TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256;
+openssl_suite("ECDHE-RSA-AES256-SHA384") ->
+ ?TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384;
+openssl_suite("ECDH-RSA-AES128-SHA256") ->
+ ?TLS_ECDH_RSA_WITH_AES_128_CBC_SHA256;
+openssl_suite("ECDH-RSA-AES256-SHA384") ->
+ ?TLS_ECDH_RSA_WITH_AES_256_CBC_SHA384.
%%--------------------------------------------------------------------
-spec openssl_suite_name(cipher_suite()) -> openssl_cipher_suite().
@@ -716,6 +926,61 @@ openssl_suite_name(?TLS_SRP_SHA_RSA_WITH_AES_256_CBC_SHA) ->
openssl_suite_name(?TLS_SRP_SHA_DSS_WITH_AES_256_CBC_SHA) ->
"SRP-DSS-AES-256-CBC-SHA";
+%% RFC 4492 EC TLS suites
+openssl_suite_name(?TLS_ECDH_ECDSA_WITH_RC4_128_SHA) ->
+ "ECDH-ECDSA-RC4-SHA";
+openssl_suite_name(?TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA) ->
+ "ECDH-ECDSA-DES-CBC3-SHA";
+openssl_suite_name(?TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA) ->
+ "ECDH-ECDSA-AES128-SHA";
+openssl_suite_name(?TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA) ->
+ "ECDH-ECDSA-AES256-SHA";
+
+openssl_suite_name(?TLS_ECDHE_ECDSA_WITH_RC4_128_SHA) ->
+ "ECDHE-ECDSA-RC4-SHA";
+openssl_suite_name(?TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA) ->
+ "ECDHE-ECDSA-DES-CBC3-SHA";
+openssl_suite_name(?TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA) ->
+ "ECDHE-ECDSA-AES128-SHA";
+openssl_suite_name(?TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA) ->
+ "ECDHE-ECDSA-AES256-SHA";
+
+openssl_suite_name(?TLS_ECDH_RSA_WITH_RC4_128_SHA) ->
+ "ECDH-RSA-RC4-SHA";
+openssl_suite_name(?TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA) ->
+ "ECDH-RSA-DES-CBC3-SHA";
+openssl_suite_name(?TLS_ECDH_RSA_WITH_AES_128_CBC_SHA) ->
+ "ECDH-RSA-AES128-SHA";
+openssl_suite_name(?TLS_ECDH_RSA_WITH_AES_256_CBC_SHA) ->
+ "ECDH-RSA-AES256-SHA";
+
+openssl_suite_name(?TLS_ECDHE_RSA_WITH_RC4_128_SHA) ->
+ "ECDHE-RSA-RC4-SHA";
+openssl_suite_name(?TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA) ->
+ "ECDHE-RSA-DES-CBC3-SHA";
+openssl_suite_name(?TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA) ->
+ "ECDHE-RSA-AES128-SHA";
+openssl_suite_name(?TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA) ->
+ "ECDHE-RSA-AES256-SHA";
+
+%% RFC 5289 EC TLS suites
+openssl_suite_name(?TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256) ->
+ "ECDHE-ECDSA-AES128-SHA256";
+openssl_suite_name(?TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384) ->
+ "ECDHE-ECDSA-AES256-SHA384";
+openssl_suite_name(?TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA256) ->
+ "ECDH-ECDSA-AES128-SHA256";
+openssl_suite_name(?TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA384) ->
+ "ECDH-ECDSA-AES256-SHA384";
+openssl_suite_name(?TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256) ->
+ "ECDHE-RSA-AES128-SHA256";
+openssl_suite_name(?TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384) ->
+ "ECDHE-RSA-AES256-SHA384";
+openssl_suite_name(?TLS_ECDH_RSA_WITH_AES_128_CBC_SHA256) ->
+ "ECDH-RSA-AES128-SHA256";
+openssl_suite_name(?TLS_ECDH_RSA_WITH_AES_256_CBC_SHA384) ->
+ "ECDH-RSA-AES256-SHA384";
+
%% No oppenssl name
openssl_suite_name(Cipher) ->
suite_definition(Cipher).
@@ -730,14 +995,85 @@ filter(undefined, Ciphers) ->
filter(DerCert, Ciphers) ->
OtpCert = public_key:pkix_decode_cert(DerCert, otp),
SigAlg = OtpCert#'OTPCertificate'.signatureAlgorithm,
+ PubKeyInfo = OtpCert#'OTPCertificate'.tbsCertificate#'OTPTBSCertificate'.subjectPublicKeyInfo,
+ PubKeyAlg = PubKeyInfo#'OTPSubjectPublicKeyInfo'.algorithm,
+
+ Ciphers1 =
+ case ssl_certificate:public_key_type(PubKeyAlg#'PublicKeyAlgorithm'.algorithm) of
+ rsa ->
+ filter_keyuse(OtpCert, ((Ciphers -- dsa_signed_suites()) -- ec_keyed_suites()) -- ecdh_suites(),
+ rsa_suites(), dhe_rsa_suites() ++ ecdhe_rsa_suites());
+ dsa ->
+ (Ciphers -- rsa_keyed_suites()) -- ec_keyed_suites();
+ ec ->
+ filter_keyuse(OtpCert, (Ciphers -- rsa_keyed_suites()) -- dsa_signed_suites(),
+ [], ecdhe_ecdsa_suites())
+ end,
case public_key:pkix_sign_types(SigAlg#'SignatureAlgorithm'.algorithm) of
{_, rsa} ->
- filter_rsa(OtpCert, Ciphers -- dsa_signed_suites());
+ Ciphers1 -- ecdsa_signed_suites();
{_, dsa} ->
- Ciphers -- rsa_signed_suites()
+ Ciphers1;
+ {_, ecdsa} ->
+ Ciphers1 -- rsa_signed_suites()
end.
%%--------------------------------------------------------------------
+-spec filter_suites([cipher_suite()]) -> [cipher_suite()].
+%%
+%% Description: filter suites for algorithms
+%%-------------------------------------------------------------------
+filter_suites(Suites = [{_,_,_}|_]) ->
+ Algos = crypto:algorithms(),
+ lists:filter(fun({KeyExchange, Cipher, Hash}) ->
+ is_acceptable_keyexchange(KeyExchange, Algos) andalso
+ is_acceptable_cipher(Cipher, Algos) andalso
+ is_acceptable_hash(Hash, Algos)
+ end, Suites);
+
+filter_suites(Suites = [{_,_,_,_}|_]) ->
+ Algos = crypto:algorithms(),
+ lists:filter(fun({KeyExchange, Cipher, Hash, Prf}) ->
+ is_acceptable_keyexchange(KeyExchange, Algos) andalso
+ is_acceptable_cipher(Cipher, Algos) andalso
+ is_acceptable_hash(Hash, Algos) andalso
+ is_acceptable_prf(Prf, Algos)
+ end, Suites);
+
+filter_suites(Suites) ->
+ Algos = crypto:algorithms(),
+ lists:filter(fun(Suite) ->
+ {KeyExchange, Cipher, Hash, Prf} = ssl_cipher:suite_definition(Suite),
+ is_acceptable_keyexchange(KeyExchange, Algos) andalso
+ is_acceptable_cipher(Cipher, Algos) andalso
+ is_acceptable_hash(Hash, Algos) andalso
+ is_acceptable_prf(Prf, Algos)
+ end, Suites).
+
+is_acceptable_keyexchange(KeyExchange, Algos)
+ when KeyExchange == ecdh_ecdsa;
+ KeyExchange == ecdhe_ecdsa;
+ KeyExchange == ecdh_rsa;
+ KeyExchange == ecdhe_rsa;
+ KeyExchange == ecdh_anon ->
+ proplists:get_bool(ec, Algos);
+is_acceptable_keyexchange(_, _) ->
+ true.
+
+is_acceptable_cipher(_, _) ->
+ true.
+
+is_acceptable_hash(null, _Algos) ->
+ true;
+is_acceptable_hash(Hash, Algos) ->
+ proplists:get_bool(Hash, Algos).
+
+is_acceptable_prf(default_prf, _) ->
+ true;
+is_acceptable_prf(Prf, Algos) ->
+ proplists:get_bool(Prf, Algos).
+
+%%--------------------------------------------------------------------
%%% Internal functions
%%--------------------------------------------------------------------
@@ -950,7 +1286,13 @@ next_iv(Bin, IV) ->
rsa_signed_suites() ->
dhe_rsa_suites() ++ rsa_suites() ++
- psk_rsa_suites() ++ srp_rsa_suites().
+ psk_rsa_suites() ++ srp_rsa_suites() ++
+ ecdh_rsa_suites().
+
+rsa_keyed_suites() ->
+ dhe_rsa_suites() ++ rsa_suites() ++
+ psk_rsa_suites() ++ srp_rsa_suites() ++
+ ecdhe_rsa_suites().
dhe_rsa_suites() ->
[?TLS_DHE_RSA_WITH_AES_256_CBC_SHA256,
@@ -982,7 +1324,25 @@ rsa_suites() ->
?TLS_RSA_WITH_RC4_128_SHA,
?TLS_RSA_WITH_RC4_128_MD5,
?TLS_RSA_WITH_DES_CBC_SHA].
-
+
+ecdh_rsa_suites() ->
+ [?TLS_ECDH_RSA_WITH_NULL_SHA,
+ ?TLS_ECDH_RSA_WITH_RC4_128_SHA,
+ ?TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA,
+ ?TLS_ECDH_RSA_WITH_AES_128_CBC_SHA,
+ ?TLS_ECDH_RSA_WITH_AES_256_CBC_SHA,
+ ?TLS_ECDH_RSA_WITH_AES_128_CBC_SHA256,
+ ?TLS_ECDH_RSA_WITH_AES_256_CBC_SHA384].
+
+ecdhe_rsa_suites() ->
+ [?TLS_ECDHE_RSA_WITH_NULL_SHA,
+ ?TLS_ECDHE_RSA_WITH_RC4_128_SHA,
+ ?TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA,
+ ?TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA,
+ ?TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA,
+ ?TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256,
+ ?TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384].
+
dsa_signed_suites() ->
dhe_dss_suites() ++ srp_dss_suites().
@@ -999,24 +1359,52 @@ srp_dss_suites() ->
?TLS_SRP_SHA_DSS_WITH_AES_128_CBC_SHA,
?TLS_SRP_SHA_DSS_WITH_AES_256_CBC_SHA].
-filter_rsa(OtpCert, RsaCiphers) ->
+ec_keyed_suites() ->
+ ecdh_ecdsa_suites() ++ ecdhe_ecdsa_suites()
+ ++ ecdh_rsa_suites().
+
+ecdsa_signed_suites() ->
+ ecdh_ecdsa_suites() ++ ecdhe_ecdsa_suites().
+
+ecdh_suites() ->
+ ecdh_rsa_suites() ++ ecdh_ecdsa_suites().
+
+ecdh_ecdsa_suites() ->
+ [?TLS_ECDH_ECDSA_WITH_NULL_SHA,
+ ?TLS_ECDH_ECDSA_WITH_RC4_128_SHA,
+ ?TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA,
+ ?TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA,
+ ?TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA,
+ ?TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA256,
+ ?TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA384].
+
+ecdhe_ecdsa_suites() ->
+ [?TLS_ECDHE_ECDSA_WITH_NULL_SHA,
+ ?TLS_ECDHE_ECDSA_WITH_RC4_128_SHA,
+ ?TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA,
+ ?TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA,
+ ?TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA,
+ ?TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256,
+ ?TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384].
+
+filter_keyuse(OtpCert, Ciphers, Suites, SignSuites) ->
TBSCert = OtpCert#'OTPCertificate'.tbsCertificate,
TBSExtensions = TBSCert#'OTPTBSCertificate'.extensions,
Extensions = ssl_certificate:extensions_list(TBSExtensions),
case ssl_certificate:select_extension(?'id-ce-keyUsage', Extensions) of
undefined ->
- RsaCiphers;
+ Ciphers;
#'Extension'{extnValue = KeyUse} ->
- Result = filter_rsa_suites(keyEncipherment,
- KeyUse, RsaCiphers, rsa_suites()),
- filter_rsa_suites(digitalSignature,
- KeyUse, Result, dhe_rsa_suites())
+ Result = filter_keyuse_suites(keyEncipherment,
+ KeyUse, Ciphers, Suites),
+ filter_keyuse_suites(digitalSignature,
+ KeyUse, Result, SignSuites)
end.
-filter_rsa_suites(Use, KeyUse, CipherSuits, RsaSuites) ->
+filter_keyuse_suites(Use, KeyUse, CipherSuits, Suites) ->
case ssl_certificate:is_valid_key_usage(KeyUse, Use) of
true ->
CipherSuits;
false ->
- CipherSuits -- RsaSuites
+ CipherSuits -- Suites
end.
diff --git a/lib/ssl/src/ssl_cipher.hrl b/lib/ssl/src/ssl_cipher.hrl
index 90d3704efd..c7c71ee1a7 100644
--- a/lib/ssl/src/ssl_cipher.hrl
+++ b/lib/ssl/src/ssl_cipher.hrl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2007-2012. All Rights Reserved.
+%% Copyright Ericsson AB 2007-2013. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -28,9 +28,9 @@
-type cipher() :: null |rc4_128 | idea_cbc | des40_cbc | des_cbc | '3des_ede_cbc'
| aes_128_cbc | aes_256_cbc.
--type hash() :: null | sha | md5 | sha256 | sha384 | sha512.
+-type hash() :: null | sha | md5 | ssh224 | sha256 | sha384 | sha512.
-type erl_cipher_suite() :: {key_algo(), cipher(), hash()}.
--type int_cipher_suite() :: {key_algo(), cipher(), hash(), hash()}.
+-type int_cipher_suite() :: {key_algo(), cipher(), hash(), hash() | default_prf}.
-type cipher_suite() :: binary().
-type cipher_enum() :: integer().
-type openssl_cipher_suite() :: string().
@@ -219,6 +219,120 @@
%% TLS_DH_anon_WITH_AES_256_CBC_SHA256 = { 0x00,0x6D };
-define(TLS_DH_anon_WITH_AES_256_CBC_SHA256, <<?BYTE(16#00), ?BYTE(16#6D)>>).
+%% RFC 4492 EC TLS suites
+
+%% ECDH_ECDSA
+
+%% TLS_ECDH_ECDSA_WITH_NULL_SHA = { 0xC0, 0x01 }
+-define(TLS_ECDH_ECDSA_WITH_NULL_SHA, <<?BYTE(16#C0), ?BYTE(16#01)>>).
+
+%% TLS_ECDH_ECDSA_WITH_RC4_128_SHA = { 0xC0, 0x02 }
+-define(TLS_ECDH_ECDSA_WITH_RC4_128_SHA, <<?BYTE(16#C0), ?BYTE(16#02)>>).
+
+%% TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA = { 0xC0, 0x03 }
+-define(TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA, <<?BYTE(16#C0), ?BYTE(16#03)>>).
+
+%% TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA = { 0xC0, 0x04 }
+-define(TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA, <<?BYTE(16#C0), ?BYTE(16#04)>>).
+
+%% TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA = { 0xC0, 0x05 }
+-define(TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA, <<?BYTE(16#C0), ?BYTE(16#05)>>).
+
+%% ECDHE_ECDSA
+
+%% TLS_ECDHE_ECDSA_WITH_NULL_SHA = { 0xC0, 0x06 }
+-define(TLS_ECDHE_ECDSA_WITH_NULL_SHA, <<?BYTE(16#C0), ?BYTE(16#06)>>).
+
+%% TLS_ECDHE_ECDSA_WITH_RC4_128_SHA = { 0xC0, 0x07 }
+-define(TLS_ECDHE_ECDSA_WITH_RC4_128_SHA, <<?BYTE(16#C0), ?BYTE(16#07)>>).
+
+%% TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA = { 0xC0, 0x08 }
+-define(TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA, <<?BYTE(16#C0), ?BYTE(16#08)>>).
+
+%% TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA = { 0xC0, 0x09 }
+-define(TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA, <<?BYTE(16#C0), ?BYTE(16#09)>>).
+
+%% TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA = { 0xC0, 0x0A }
+-define(TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA, <<?BYTE(16#C0), ?BYTE(16#0A)>>).
+
+%% ECDH_RSA
+
+%% TLS_ECDH_RSA_WITH_NULL_SHA = { 0xC0, 0x0B }
+-define(TLS_ECDH_RSA_WITH_NULL_SHA, <<?BYTE(16#C0), ?BYTE(16#0B)>>).
+
+%% TLS_ECDH_RSA_WITH_RC4_128_SHA = { 0xC0, 0x0C }
+-define(TLS_ECDH_RSA_WITH_RC4_128_SHA, <<?BYTE(16#C0), ?BYTE(16#0C)>>).
+
+%% TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA = { 0xC0, 0x0D }
+-define(TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA, <<?BYTE(16#C0), ?BYTE(16#0D)>>).
+
+%% TLS_ECDH_RSA_WITH_AES_128_CBC_SHA = { 0xC0, 0x0E }
+-define(TLS_ECDH_RSA_WITH_AES_128_CBC_SHA, <<?BYTE(16#C0), ?BYTE(16#0E)>>).
+
+%% TLS_ECDH_RSA_WITH_AES_256_CBC_SHA = { 0xC0, 0x0F }
+-define(TLS_ECDH_RSA_WITH_AES_256_CBC_SHA, <<?BYTE(16#C0), ?BYTE(16#0F)>>).
+
+%% ECDHE_RSA
+
+%% TLS_ECDHE_RSA_WITH_NULL_SHA = { 0xC0, 0x10 }
+-define(TLS_ECDHE_RSA_WITH_NULL_SHA, <<?BYTE(16#C0), ?BYTE(16#10)>>).
+
+%% TLS_ECDHE_RSA_WITH_RC4_128_SHA = { 0xC0, 0x11 }
+-define(TLS_ECDHE_RSA_WITH_RC4_128_SHA, <<?BYTE(16#C0), ?BYTE(16#11)>>).
+
+%% TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA = { 0xC0, 0x12 }
+-define(TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA, <<?BYTE(16#C0), ?BYTE(16#12)>>).
+
+%% TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA = { 0xC0, 0x13 }
+-define(TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA, <<?BYTE(16#C0), ?BYTE(16#13)>>).
+
+%% TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA = { 0xC0, 0x14 }
+-define(TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA, <<?BYTE(16#C0), ?BYTE(16#14)>>).
+
+%% ECDH_anon
+
+%% TLS_ECDH_anon_WITH_NULL_SHA = { 0xC0, 0x15 }
+-define(TLS_ECDH_anon_WITH_NULL_SHA, <<?BYTE(16#C0), ?BYTE(16#15)>>).
+
+%% TLS_ECDH_anon_WITH_RC4_128_SHA = { 0xC0, 0x16 }
+-define(TLS_ECDH_anon_WITH_RC4_128_SHA, <<?BYTE(16#C0), ?BYTE(16#16)>>).
+
+%% TLS_ECDH_anon_WITH_3DES_EDE_CBC_SHA = { 0xC0, 0x17 }
+-define(TLS_ECDH_anon_WITH_3DES_EDE_CBC_SHA, <<?BYTE(16#C0), ?BYTE(16#17)>>).
+
+%% TLS_ECDH_anon_WITH_AES_128_CBC_SHA = { 0xC0, 0x18 }
+-define(TLS_ECDH_anon_WITH_AES_128_CBC_SHA, <<?BYTE(16#C0), ?BYTE(16#18)>>).
+
+%% TLS_ECDH_anon_WITH_AES_256_CBC_SHA = { 0xC0, 0x19 }
+-define(TLS_ECDH_anon_WITH_AES_256_CBC_SHA, <<?BYTE(16#C0), ?BYTE(16#19)>>).
+
+
+%% RFC 5289 EC TLS suites
+
+%% TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256 = {0xC0,0x23};
+-define(TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256, <<?BYTE(16#C0), ?BYTE(16#23)>>).
+
+%% TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384 = {0xC0,0x24};
+-define(TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384, <<?BYTE(16#C0), ?BYTE(16#24)>>).
+
+%% TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA256 = {0xC0,0x25};
+-define(TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA256, <<?BYTE(16#C0), ?BYTE(16#25)>>).
+
+%% TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA384 = {0xC0,0x26};
+-define(TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA384, <<?BYTE(16#C0), ?BYTE(16#26)>>).
+
+%% TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256 = {0xC0,0x27};
+-define(TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256, <<?BYTE(16#C0), ?BYTE(16#27)>>).
+
+%% TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384 = {0xC0,0x28};
+-define(TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384, <<?BYTE(16#C0), ?BYTE(16#28)>>).
+
+%% TLS_ECDH_RSA_WITH_AES_128_CBC_SHA256 = {0xC0,0x29};
+-define(TLS_ECDH_RSA_WITH_AES_128_CBC_SHA256, <<?BYTE(16#C0), ?BYTE(16#29)>>).
+
+%% TLS_ECDH_RSA_WITH_AES_256_CBC_SHA384 = {0xC0,0x2A};
+-define(TLS_ECDH_RSA_WITH_AES_256_CBC_SHA384, <<?BYTE(16#C0), ?BYTE(16#2A)>>).
+
%%% Kerberos Cipher Suites
%% TLS_KRB5_WITH_DES_CBC_SHA = { 0x00,0x1E };
diff --git a/lib/ssl/src/ssl_connection.erl b/lib/ssl/src/ssl_connection.erl
index 1843377582..54eed03d3c 100644
--- a/lib/ssl/src/ssl_connection.erl
+++ b/lib/ssl/src/ssl_connection.erl
@@ -98,7 +98,8 @@
terminated = false, %
allow_renegotiate = true,
expecting_next_protocol_negotiation = false :: boolean(),
- next_protocol = undefined :: undefined | binary()
+ next_protocol = undefined :: undefined | binary(),
+ client_ecc % {Curves, PointFmt}
}).
-define(DEFAULT_DIFFIE_HELLMAN_PARAMS,
@@ -416,11 +417,14 @@ hello(Hello = #client_hello{client_version = ClientVersion},
ssl_options = SslOpts}) ->
case ssl_handshake:hello(Hello, SslOpts, {Port, Session0, Cache, CacheCb,
ConnectionStates0, Cert}, Renegotiation) of
- {Version, {Type, Session}, ConnectionStates, ProtocolsToAdvertise} ->
- do_server_hello(Type, ProtocolsToAdvertise, State#state{connection_states =
- ConnectionStates,
- negotiated_version = Version,
- session = Session});
+ {Version, {Type, Session}, ConnectionStates, ProtocolsToAdvertise,
+ EcPointFormats, EllipticCurves} ->
+ do_server_hello(Type, ProtocolsToAdvertise,
+ EcPointFormats, EllipticCurves,
+ State#state{connection_states = ConnectionStates,
+ negotiated_version = Version,
+ session = Session,
+ client_ecc = {EllipticCurves, EcPointFormats}});
#alert{} = Alert ->
handle_own_alert(Alert, ClientVersion, hello, State)
end;
@@ -533,7 +537,9 @@ certify(#certificate{} = Cert,
certify(#server_key_exchange{} = KeyExchangeMsg,
#state{role = client, negotiated_version = Version,
key_algorithm = Alg} = State0)
- when Alg == dhe_dss; Alg == dhe_rsa; Alg == dh_anon;
+ when Alg == dhe_dss; Alg == dhe_rsa;
+ Alg == ecdhe_rsa; Alg == ecdhe_ecdsa;
+ Alg == dh_anon; Alg == ecdh_anon;
Alg == psk; Alg == dhe_psk; Alg == rsa_psk;
Alg == srp_dss; Alg == srp_rsa; Alg == srp_anon ->
case handle_server_key(KeyExchangeMsg, State0) of
@@ -669,9 +675,20 @@ certify_client_key_exchange(#encrypted_premaster_secret{premaster_secret= EncPMS
certify_client_key_exchange(#client_diffie_hellman_public{dh_public = ClientPublicDhKey},
#state{negotiated_version = Version,
diffie_hellman_params = #'DHParameter'{prime = P,
- base = G},
+ base = G} = Params,
diffie_hellman_keys = {_, ServerDhPrivateKey}} = State0) ->
- case dh_master_secret(crypto:mpint(P), crypto:mpint(G), ClientPublicDhKey, ServerDhPrivateKey, State0) of
+ case dh_master_secret(Params, ClientPublicDhKey, ServerDhPrivateKey, State0) of
+ #state{} = State1 ->
+ {Record, State} = next_record(State1),
+ next_state(certify, cipher, Record, State);
+ #alert{} = Alert ->
+ handle_own_alert(Alert, Version, certify, State0)
+ end;
+
+certify_client_key_exchange(#client_ec_diffie_hellman_public{dh_public = ClientPublicEcDhPoint},
+ #state{negotiated_version = Version,
+ diffie_hellman_keys = ECDHKey} = State0) ->
+ case ec_dh_master_secret(ECDHKey, #'ECPoint'{point = ClientPublicEcDhPoint}, State0) of
#state{} = State1 ->
{Record, State} = next_record(State1),
next_state(certify, cipher, Record, State);
@@ -696,7 +713,7 @@ certify_client_key_exchange(#client_dhe_psk_identity{
diffie_hellman_params = #'DHParameter'{prime = P,
base = G},
diffie_hellman_keys = {_, ServerDhPrivateKey}} = State0) ->
- case dhe_psk_master_secret(ClientPSKIdentity, crypto:mpint(P), crypto:mpint(G), ClientPublicDhKey, ServerDhPrivateKey, State0) of
+ case dhe_psk_master_secret(ClientPSKIdentity, P, G, ClientPublicDhKey, ServerDhPrivateKey, State0) of
#state{} = State1 ->
{Record, State} = next_record(State1),
next_state(certify, cipher, Record, State);
@@ -1278,6 +1295,7 @@ init_private_key(DbHandle, undefined, KeyFile, Password, _) ->
[PemEntry] = [PemEntry || PemEntry = {PKey, _ , _} <- List,
PKey =:= 'RSAPrivateKey' orelse
PKey =:= 'DSAPrivateKey' orelse
+ PKey =:= 'ECPrivateKey' orelse
PKey =:= 'PrivateKeyInfo'
],
private_key(public_key:pem_entry_decode(PemEntry, Password))
@@ -1291,6 +1309,8 @@ init_private_key(_,{rsa, PrivateKey}, _, _,_) ->
init_private_key('RSAPrivateKey', PrivateKey);
init_private_key(_,{dsa, PrivateKey},_,_,_) ->
init_private_key('DSAPrivateKey', PrivateKey);
+init_private_key(_,{ec, PrivateKey},_,_,_) ->
+ init_private_key('ECPrivateKey', PrivateKey);
init_private_key(_,{Asn1Type, PrivateKey},_,_,_) ->
private_key(init_private_key(Asn1Type, PrivateKey)).
@@ -1306,6 +1326,7 @@ private_key(#'PrivateKeyInfo'{privateKeyAlgorithm =
#'PrivateKeyInfo_privateKeyAlgorithm'{algorithm = ?'id-dsa'},
privateKey = Key}) ->
public_key:der_decode('DSAPrivateKey', iolist_to_binary(Key));
+
private_key(Key) ->
Key.
@@ -1357,7 +1378,15 @@ handle_peer_cert(PeerCert, PublicKeyInfo,
State1 = State0#state{session =
Session#session{peer_certificate = PeerCert},
public_key_info = PublicKeyInfo},
- {Record, State} = next_record(State1),
+ State2 = case PublicKeyInfo of
+ {?'id-ecPublicKey', #'ECPoint'{point = _ECPoint} = PublicKey, PublicKeyParams} ->
+ ECDHKey = public_key:generate_key(PublicKeyParams),
+ State3 = State1#state{diffie_hellman_keys = ECDHKey},
+ ec_dh_master_secret(ECDHKey, PublicKey, State3);
+
+ _ -> State1
+ end,
+ {Record, State} = next_record(State2),
next_state(certify, certify, Record, State).
certify_client(#state{client_certificate_requested = true, role = client,
@@ -1407,15 +1436,18 @@ verify_client_cert(#state{client_certificate_requested = true, role = client,
verify_client_cert(#state{client_certificate_requested = false} = State) ->
State.
-do_server_hello(Type, NextProtocolsToSend, #state{negotiated_version = Version,
- session = #session{session_id = SessId},
- connection_states = ConnectionStates0,
- renegotiation = {Renegotiation, _}}
+do_server_hello(Type, NextProtocolsToSend,
+ EcPointFormats, EllipticCurves,
+ #state{negotiated_version = Version,
+ session = #session{session_id = SessId},
+ connection_states = ConnectionStates0,
+ renegotiation = {Renegotiation, _}}
= State0) when is_atom(Type) ->
ServerHello =
ssl_handshake:server_hello(SessId, Version,
- ConnectionStates0, Renegotiation, NextProtocolsToSend),
+ ConnectionStates0, Renegotiation,
+ NextProtocolsToSend, EcPointFormats, EllipticCurves),
State = server_hello(ServerHello,
State0#state{expecting_next_protocol_negotiation =
NextProtocolsToSend =/= undefined}),
@@ -1547,7 +1579,7 @@ server_hello_done(#state{transport_cb = Transport,
tls_handshake_history = Handshake}.
certify_server(#state{key_algorithm = Algo} = State)
- when Algo == dh_anon; Algo == psk; Algo == dhe_psk ->
+ when Algo == dh_anon; Algo == ecdh_anon; Algo == psk; Algo == dhe_psk; Algo == srp_anon ->
State;
certify_server(#state{transport_cb = Transport,
@@ -1574,7 +1606,7 @@ key_exchange(#state{role = server, key_algorithm = rsa} = State) ->
State;
key_exchange(#state{role = server, key_algorithm = Algo,
hashsign_algorithm = HashSignAlgo,
- diffie_hellman_params = #'DHParameter'{prime = P, base = G} = Params,
+ diffie_hellman_params = #'DHParameter'{} = Params,
private_key = PrivateKey,
connection_states = ConnectionStates0,
negotiated_version = Version,
@@ -1585,13 +1617,13 @@ key_exchange(#state{role = server, key_algorithm = Algo,
when Algo == dhe_dss;
Algo == dhe_rsa;
Algo == dh_anon ->
- Keys = crypto:dh_generate_key([crypto:mpint(P), crypto:mpint(G)]),
+ DHKeys = public_key:generate_key(Params),
ConnectionState =
ssl_record:pending_connection_state(ConnectionStates0, read),
SecParams = ConnectionState#connection_state.security_parameters,
#security_parameters{client_random = ClientRandom,
server_random = ServerRandom} = SecParams,
- Msg = ssl_handshake:key_exchange(server, Version, {dh, Keys, Params,
+ Msg = ssl_handshake:key_exchange(server, Version, {dh, DHKeys, Params,
HashSignAlgo, ClientRandom,
ServerRandom,
PrivateKey}),
@@ -1599,9 +1631,41 @@ key_exchange(#state{role = server, key_algorithm = Algo,
encode_handshake(Msg, Version, ConnectionStates0, Handshake0),
Transport:send(Socket, BinMsg),
State#state{connection_states = ConnectionStates,
- diffie_hellman_keys = Keys,
+ diffie_hellman_keys = DHKeys,
tls_handshake_history = Handshake};
+key_exchange(#state{role = server, private_key = Key, key_algorithm = Algo} = State)
+ when Algo == ecdh_ecdsa; Algo == ecdh_rsa ->
+ State#state{diffie_hellman_keys = Key};
+key_exchange(#state{role = server, key_algorithm = Algo,
+ hashsign_algorithm = HashSignAlgo,
+ private_key = PrivateKey,
+ connection_states = ConnectionStates0,
+ negotiated_version = Version,
+ tls_handshake_history = Handshake0,
+ socket = Socket,
+ transport_cb = Transport
+ } = State)
+ when Algo == ecdhe_ecdsa; Algo == ecdhe_rsa;
+ Algo == ecdh_anon ->
+
+ ECDHKeys = public_key:generate_key(select_curve(State)),
+ ConnectionState =
+ ssl_record:pending_connection_state(ConnectionStates0, read),
+ SecParams = ConnectionState#connection_state.security_parameters,
+ #security_parameters{client_random = ClientRandom,
+ server_random = ServerRandom} = SecParams,
+ Msg = ssl_handshake:key_exchange(server, Version, {ecdh, ECDHKeys,
+ HashSignAlgo, ClientRandom,
+ ServerRandom,
+ PrivateKey}),
+ {BinMsg, ConnectionStates, Handshake1} =
+ encode_handshake(Msg, Version, ConnectionStates0, Handshake0),
+ Transport:send(Socket, BinMsg),
+ State#state{connection_states = ConnectionStates,
+ diffie_hellman_keys = ECDHKeys,
+ tls_handshake_history = Handshake1};
+
key_exchange(#state{role = server, key_algorithm = psk,
ssl_options = #ssl_options{psk_identity = undefined}} = State) ->
State;
@@ -1633,7 +1697,7 @@ key_exchange(#state{role = server, key_algorithm = psk,
key_exchange(#state{role = server, key_algorithm = dhe_psk,
ssl_options = #ssl_options{psk_identity = PskIdentityHint},
hashsign_algorithm = HashSignAlgo,
- diffie_hellman_params = #'DHParameter'{prime = P, base = G} = Params,
+ diffie_hellman_params = #'DHParameter'{} = Params,
private_key = PrivateKey,
connection_states = ConnectionStates0,
negotiated_version = Version,
@@ -1641,13 +1705,13 @@ key_exchange(#state{role = server, key_algorithm = dhe_psk,
socket = Socket,
transport_cb = Transport
} = State) ->
- Keys = crypto:dh_generate_key([crypto:mpint(P), crypto:mpint(G)]),
+ DHKeys = public_key:generate_key(Params),
ConnectionState =
ssl_record:pending_connection_state(ConnectionStates0, read),
SecParams = ConnectionState#connection_state.security_parameters,
#security_parameters{client_random = ClientRandom,
server_random = ServerRandom} = SecParams,
- Msg = ssl_handshake:key_exchange(server, Version, {dhe_psk, PskIdentityHint, Keys, Params,
+ Msg = ssl_handshake:key_exchange(server, Version, {dhe_psk, PskIdentityHint, DHKeys, Params,
HashSignAlgo, ClientRandom,
ServerRandom,
PrivateKey}),
@@ -1655,7 +1719,7 @@ key_exchange(#state{role = server, key_algorithm = dhe_psk,
encode_handshake(Msg, Version, ConnectionStates0, Handshake0),
Transport:send(Socket, BinMsg),
State#state{connection_states = ConnectionStates,
- diffie_hellman_keys = Keys,
+ diffie_hellman_keys = DHKeys,
tls_handshake_history = Handshake};
key_exchange(#state{role = server, key_algorithm = rsa_psk,
@@ -1756,6 +1820,23 @@ key_exchange(#state{role = client,
tls_handshake_history = Handshake};
key_exchange(#state{role = client,
+ connection_states = ConnectionStates0,
+ key_algorithm = Algorithm,
+ negotiated_version = Version,
+ diffie_hellman_keys = Keys,
+ socket = Socket, transport_cb = Transport,
+ tls_handshake_history = Handshake0} = State)
+ when Algorithm == ecdhe_ecdsa; Algorithm == ecdhe_rsa;
+ Algorithm == ecdh_ecdsa; Algorithm == ecdh_rsa;
+ Algorithm == ecdh_anon ->
+ Msg = ssl_handshake:key_exchange(client, Version, {ecdh, Keys}),
+ {BinMsg, ConnectionStates, Handshake} =
+ encode_handshake(Msg, Version, ConnectionStates0, Handshake0),
+ Transport:send(Socket, BinMsg),
+ State#state{connection_states = ConnectionStates,
+ tls_handshake_history = Handshake};
+
+key_exchange(#state{role = client,
ssl_options = SslOpts,
connection_states = ConnectionStates0,
key_algorithm = psk,
@@ -1936,7 +2017,7 @@ handle_server_key(#server_key_exchange{exchange_keys = Keys},
Params = ssl_handshake:decode_server_key(Keys, KeyAlg, Version),
HashSign = connection_hashsign(Params#server_key_params.hashsign, State),
case HashSign of
- {_, anon} ->
+ {_, SignAlgo} when SignAlgo == anon; SignAlgo == ecdh_anon ->
server_master_secret(Params#server_key_params.params, State);
_ ->
verify_server_key(Params, HashSign, State)
@@ -1969,6 +2050,11 @@ server_master_secret(#server_dh_params{dh_p = P, dh_g = G, dh_y = ServerPublicDh
State) ->
dh_master_secret(P, G, ServerPublicDhKey, undefined, State);
+server_master_secret(#server_ecdh_params{curve = ECCurve, public = ECServerPubKey},
+ State) ->
+ ECDHKeys = public_key:generate_key(ECCurve),
+ ec_dh_master_secret(ECDHKeys, #'ECPoint'{point = ECServerPubKey}, State#state{diffie_hellman_keys = ECDHKeys});
+
server_master_secret(#server_psk_params{
hint = IdentityHint},
State) ->
@@ -2000,17 +2086,23 @@ master_from_premaster_secret(PremasterSecret,
Alert
end.
+dh_master_secret(#'DHParameter'{} = Params, OtherPublicDhKey, MyPrivateKey, State) ->
+ PremasterSecret =
+ public_key:compute_key(OtherPublicDhKey, MyPrivateKey, Params),
+ master_from_premaster_secret(PremasterSecret, State).
+
dh_master_secret(Prime, Base, PublicDhKey, undefined, State) ->
- PMpint = mpint_binary(Prime),
- GMpint = mpint_binary(Base),
- Keys = {_, PrivateDhKey} =
- crypto:dh_generate_key([PMpint,GMpint]),
- dh_master_secret(PMpint, GMpint, PublicDhKey, PrivateDhKey, State#state{diffie_hellman_keys = Keys});
+ Keys = {_, PrivateDhKey} = crypto:generate_key(dh, [Prime, Base]),
+ dh_master_secret(Prime, Base, PublicDhKey, PrivateDhKey, State#state{diffie_hellman_keys = Keys});
+
+dh_master_secret(Prime, Base, PublicDhKey, PrivateDhKey, State) ->
+ PremasterSecret =
+ crypto:compute_key(dh, PublicDhKey, PrivateDhKey, [Prime, Base]),
+ master_from_premaster_secret(PremasterSecret, State).
-dh_master_secret(PMpint, GMpint, PublicDhKey, PrivateDhKey, State) ->
+ec_dh_master_secret(ECDHKeys, ECPoint, State) ->
PremasterSecret =
- crypto:dh_compute_key(mpint_binary(PublicDhKey), PrivateDhKey,
- [PMpint, GMpint]),
+ public_key:compute_key(ECPoint, ECDHKeys),
master_from_premaster_secret(PremasterSecret, State).
handle_psk_identity(_PSKIdentity, LookupFun)
@@ -2033,20 +2125,18 @@ server_psk_master_secret(ClientPSKIdentity,
end.
dhe_psk_master_secret(PSKIdentity, Prime, Base, PublicDhKey, undefined, State) ->
- PMpint = mpint_binary(Prime),
- GMpint = mpint_binary(Base),
Keys = {_, PrivateDhKey} =
- crypto:dh_generate_key([PMpint,GMpint]),
- dhe_psk_master_secret(PSKIdentity, PMpint, GMpint, PublicDhKey, PrivateDhKey,
+ crypto:generate_key(dh, [Prime, Base]),
+ dhe_psk_master_secret(PSKIdentity, Prime, Base, PublicDhKey, PrivateDhKey,
State#state{diffie_hellman_keys = Keys});
-dhe_psk_master_secret(PSKIdentity, PMpint, GMpint, PublicDhKey, PrivateDhKey,
+dhe_psk_master_secret(PSKIdentity, Prime, Base, PublicDhKey, PrivateDhKey,
#state{ssl_options = SslOpts} = State) ->
case handle_psk_identity(PSKIdentity, SslOpts#ssl_options.user_lookup_fun) of
{ok, PSK} when is_binary(PSK) ->
DHSecret =
- crypto:dh_compute_key(mpint_binary(PublicDhKey), PrivateDhKey,
- [PMpint, GMpint]),
+ crypto:compute_key(dh, PublicDhKey, PrivateDhKey,
+ [Prime, Base]),
DHLen = erlang:byte_size(DHSecret),
Len = erlang:byte_size(PSK),
PremasterSecret = <<?UINT16(DHLen), DHSecret/binary, ?UINT16(Len), PSK/binary>>,
@@ -2075,7 +2165,7 @@ generate_srp_server_keys(_SrpParams, 10) ->
generate_srp_server_keys(SrpParams =
#srp_user{generator = Generator, prime = Prime,
verifier = Verifier}, N) ->
- case crypto:srp_generate_key(Verifier, Generator, Prime, '6a') of
+ case crypto:generate_key(srp, {host, [Verifier, Generator, Prime, '6a']}) of
error ->
generate_srp_server_keys(SrpParams, N+1);
Keys ->
@@ -2086,7 +2176,7 @@ generate_srp_client_keys(_Generator, _Prime, 10) ->
?ALERT_REC(?FATAL, ?ILLEGAL_PARAMETER);
generate_srp_client_keys(Generator, Prime, N) ->
- case crypto:srp_generate_key(Generator, Prime, '6a') of
+ case crypto:generate_key(srp, {user, [Generator, Prime, '6a']}) of
error ->
generate_srp_client_keys(Generator, Prime, N+1);
Keys ->
@@ -2098,7 +2188,7 @@ handle_srp_identity(Username, {Fun, UserState}) ->
{ok, {SRPParams, Salt, DerivedKey}}
when is_atom(SRPParams), is_binary(Salt), is_binary(DerivedKey) ->
{Generator, Prime} = ssl_srp_primes:get_srp_params(SRPParams),
- Verifier = crypto:mod_exp_prime(Generator, DerivedKey, Prime),
+ Verifier = crypto:mod_pow(Generator, DerivedKey, Prime),
#srp_user{generator = Generator, prime = Prime,
salt = Salt, verifier = Verifier};
#alert{} = Alert ->
@@ -2107,8 +2197,8 @@ handle_srp_identity(Username, {Fun, UserState}) ->
throw(?ALERT_REC(?FATAL, ?ILLEGAL_PARAMETER))
end.
-server_srp_master_secret(Verifier, Prime, ClientPub, State = #state{srp_keys = {ServerPub, ServerPriv}}) ->
- case crypto:srp_compute_key(Verifier, Prime, ClientPub, ServerPub, ServerPriv, '6a') of
+server_srp_master_secret(Verifier, Prime, ClientPub, State = #state{srp_keys = ServerKeys}) ->
+ case crypto:compute_key(srp, ClientPub, ServerKeys, {host, [Verifier, Prime, '6a']}) of
error ->
?ALERT_REC(?FATAL, ?ILLEGAL_PARAMETER);
PremasterSecret ->
@@ -2121,14 +2211,13 @@ client_srp_master_secret(Generator, Prime, Salt, ServerPub, undefined, State) ->
Keys = generate_srp_client_keys(Generator, Prime, 0),
client_srp_master_secret(Generator, Prime, Salt, ServerPub, Keys, State#state{srp_keys = Keys});
-client_srp_master_secret(Generator, Prime, Salt, ServerPub, {ClientPub, ClientPriv},
- #state{ssl_options = SslOpts} = State) ->
+client_srp_master_secret(Generator, Prime, Salt, ServerPub, ClientKeys,
+ #state{ssl_options = SslOpts} = State) ->
case ssl_srp_primes:check_srp_params(Generator, Prime) of
ok ->
{Username, Password} = SslOpts#ssl_options.srp_identity,
DerivedKey = crypto:sha([Salt, crypto:sha([Username, <<$:>>, Password])]),
-
- case crypto:srp_compute_key(DerivedKey, Prime, Generator, ClientPub, ClientPriv, ServerPub, '6a') of
+ case crypto:compute_key(srp, ServerPub, ClientKeys, {user, [DerivedKey, Prime, Generator, '6a']}) of
error ->
?ALERT_REC(?FATAL, ?ILLEGAL_PARAMETER);
PremasterSecret ->
@@ -2798,11 +2887,6 @@ make_premaster_secret({MajVer, MinVer}, rsa) ->
make_premaster_secret(_, _) ->
undefined.
-mpint_binary(Binary) ->
- Size = erlang:byte_size(Binary),
- <<?UINT32(Size), Binary/binary>>.
-
-
ack_connection(#state{renegotiation = {true, Initiater}} = State)
when Initiater == internal;
Initiater == peer ->
@@ -2938,21 +3022,29 @@ default_hashsign(_Version = {Major, Minor}, KeyExchange)
(KeyExchange == rsa orelse
KeyExchange == dhe_rsa orelse
KeyExchange == dh_rsa orelse
+ KeyExchange == ecdhe_rsa orelse
KeyExchange == srp_rsa) ->
{sha, rsa};
default_hashsign(_Version, KeyExchange)
when KeyExchange == rsa;
KeyExchange == dhe_rsa;
KeyExchange == dh_rsa;
+ KeyExchange == ecdhe_rsa;
KeyExchange == srp_rsa ->
{md5sha, rsa};
default_hashsign(_Version, KeyExchange)
+ when KeyExchange == ecdhe_ecdsa;
+ KeyExchange == ecdh_ecdsa;
+ KeyExchange == ecdh_rsa ->
+ {sha, ecdsa};
+default_hashsign(_Version, KeyExchange)
when KeyExchange == dhe_dss;
KeyExchange == dh_dss;
KeyExchange == srp_dss ->
{sha, dsa};
default_hashsign(_Version, KeyExchange)
when KeyExchange == dh_anon;
+ KeyExchange == ecdh_anon;
KeyExchange == psk;
KeyExchange == dhe_psk;
KeyExchange == rsa_psk;
@@ -2987,3 +3079,8 @@ handle_close_alert(Data, StateName, State0) ->
_ ->
ok
end.
+
+select_curve(#state{client_ecc = {[Curve|_], _}}) ->
+ {namedCurve, Curve};
+select_curve(_) ->
+ {namedCurve, ?secp256k1}.
diff --git a/lib/ssl/src/ssl_handshake.erl b/lib/ssl/src/ssl_handshake.erl
index 83c0092de2..e358cbe9bb 100644
--- a/lib/ssl/src/ssl_handshake.erl
+++ b/lib/ssl/src/ssl_handshake.erl
@@ -31,7 +31,7 @@
-include("ssl_srp.hrl").
-include_lib("public_key/include/public_key.hrl").
--export([master_secret/4, client_hello/8, server_hello/5, hello/4,
+-export([master_secret/4, client_hello/8, server_hello/7, hello/4,
hello_request/0, certify/7, certificate/4,
client_certificate_verify/6, certificate_verify/6, verify_signature/5,
certificate_request/3, key_exchange/3, server_key_exchange_hash/2,
@@ -47,6 +47,8 @@
#client_key_exchange{} | #finished{} | #certificate_verify{} |
#hello_request{} | #next_protocol{}.
+-define(NAMED_CURVE_TYPE, 3).
+
%%====================================================================
%% Internal application API
%%====================================================================
@@ -67,6 +69,7 @@ client_hello(Host, Port, ConnectionStates,
SecParams = Pending#connection_state.security_parameters,
Ciphers = available_suites(UserSuites, Version),
SRP = srp_user(SslOpts),
+ {EcPointFormats, EllipticCurves} = default_ecc_extensions(Version),
Id = ssl_session:client_id({Host, Port, SslOpts}, Cache, CacheCb, OwnCert),
@@ -80,6 +83,8 @@ client_hello(Host, Port, ConnectionStates,
renegotiation_info(client, ConnectionStates, Renegotiation),
srp = SRP,
hash_signs = default_hash_signs(),
+ ec_point_formats = EcPointFormats,
+ elliptic_curves = EllipticCurves,
next_protocol_negotiation =
encode_client_protocol_negotiation(SslOpts#ssl_options.next_protocol_selector, Renegotiation)
}.
@@ -96,11 +101,14 @@ encode_protocols_advertised_on_server(Protocols) ->
%%--------------------------------------------------------------------
-spec server_hello(session_id(), tls_version(), #connection_states{},
- boolean(), [binary()] | undefined) -> #server_hello{}.
+ boolean(), [binary()] | undefined,
+ #ec_point_formats{} | undefined,
+ #elliptic_curves{} | undefined) -> #server_hello{}.
%%
%% Description: Creates a server hello message.
%%--------------------------------------------------------------------
-server_hello(SessionId, Version, ConnectionStates, Renegotiation, ProtocolsAdvertisedOnServer) ->
+server_hello(SessionId, Version, ConnectionStates, Renegotiation,
+ ProtocolsAdvertisedOnServer, EcPointFormats, EllipticCurves) ->
Pending = ssl_record:pending_connection_state(ConnectionStates, read),
SecParams = Pending#connection_state.security_parameters,
#server_hello{server_version = Version,
@@ -111,6 +119,8 @@ server_hello(SessionId, Version, ConnectionStates, Renegotiation, ProtocolsAdver
session_id = SessionId,
renegotiation_info =
renegotiation_info(server, ConnectionStates, Renegotiation),
+ ec_point_formats = EcPointFormats,
+ elliptic_curves = EllipticCurves,
next_protocol_negotiation = encode_protocols_advertised_on_server(ProtocolsAdvertisedOnServer)
}.
@@ -129,7 +139,8 @@ hello_request() ->
atom(), #connection_states{}, binary()},
boolean()) ->
{tls_version(), session_id(), #connection_states{}, binary() | undefined}|
- {tls_version(), {resumed | new, #session{}}, #connection_states{}, list(binary()) | undefined} |
+ {tls_version(), {resumed | new, #session{}}, #connection_states{}, [binary()] | undefined,
+ [oid()] | undefined, [oid()] | undefined} |
#alert{}.
%%
%% Description: Handles a recieved hello message
@@ -163,44 +174,27 @@ hello(#server_hello{cipher_suite = CipherSuite, server_version = Version,
?ALERT_REC(?FATAL, ?PROTOCOL_VERSION)
end;
-hello(#client_hello{client_version = ClientVersion, random = Random,
- cipher_suites = CipherSuites,
- renegotiation_info = Info,
- srp = SRP} = Hello,
- #ssl_options{versions = Versions,
- secure_renegotiate = SecureRenegotation} = SslOpts,
+hello(#client_hello{client_version = ClientVersion} = Hello,
+ #ssl_options{versions = Versions} = SslOpts,
{Port, Session0, Cache, CacheCb, ConnectionStates0, Cert}, Renegotiation) ->
-%% TODO: select hash and signature algorithm
+ %% TODO: select hash and signature algorithm
Version = select_version(ClientVersion, Versions),
case ssl_record:is_acceptable_version(Version, Versions) of
true ->
- {Type, #session{cipher_suite = CipherSuite,
- compression_method = Compression} = Session1}
+ %% TODO: need to take supported Curves into Account when selecting the CipherSuite....
+ %% if whe have an ECDSA cert with an unsupported curve, we need to drop ECDSA ciphers
+ {Type, #session{cipher_suite = CipherSuite} = Session1}
= select_session(Hello, Port, Session0, Version,
SslOpts, Cache, CacheCb, Cert),
case CipherSuite of
no_suite ->
?ALERT_REC(?FATAL, ?INSUFFICIENT_SECURITY);
_ ->
- Session = handle_srp_info(SRP, Session1),
- case handle_renegotiation_info(server, Info, ConnectionStates0,
- Renegotiation, SecureRenegotation,
- CipherSuites) of
- {ok, ConnectionStates1} ->
- ConnectionStates =
- hello_pending_connection_states(server,
- Version,
- CipherSuite,
- Random,
- Compression,
- ConnectionStates1),
- case handle_next_protocol_on_server(Hello, Renegotiation, SslOpts) of
- #alert{} = Alert ->
- Alert;
- ProtocolsToAdvertise ->
- {Version, {Type, Session}, ConnectionStates, ProtocolsToAdvertise}
- end;
- #alert{} = Alert ->
+ try handle_hello_extensions(Hello, Version, SslOpts, Session1, ConnectionStates0, Renegotiation) of
+ {Session, ConnectionStates, ProtocolsToAdvertise, ECPointFormats, EllipticCurves} ->
+ {Version, {Type, Session}, ConnectionStates,
+ ProtocolsToAdvertise, ECPointFormats, EllipticCurves}
+ catch throw:Alert ->
Alert
end
end;
@@ -350,9 +344,10 @@ verify_signature(_Version, Hash, _HashAlgo, Signature, {?rsaEncryption, PubKey,
_ -> false
end;
verify_signature(_Version, Hash, {HashAlgo, dsa}, Signature, {?'id-dsa', PublicKey, PublicKeyParams}) ->
+ public_key:verify({digest, Hash}, HashAlgo, Signature, {PublicKey, PublicKeyParams});
+verify_signature(_Version, Hash, {HashAlgo, ecdsa}, Signature, {?'id-ecPublicKey', PublicKey, PublicKeyParams}) ->
public_key:verify({digest, Hash}, HashAlgo, Signature, {PublicKey, PublicKeyParams}).
-
%%--------------------------------------------------------------------
-spec certificate_request(#connection_states{}, db_handle(), certdb_ref()) ->
#certificate_request{}.
@@ -378,6 +373,7 @@ certificate_request(ConnectionStates, CertDbHandle, CertDbRef) ->
{dh, binary()} |
{dh, {binary(), binary()}, #'DHParameter'{}, {HashAlgo::atom(), SignAlgo::atom()},
binary(), binary(), private_key()} |
+ {ecdh, #'ECPrivateKey'{}} |
{psk, binary()} |
{dhe_psk, binary(), binary()} |
{srp, {binary(), binary()}, #srp_user{}, {HashAlgo::atom(), SignAlgo::atom()},
@@ -391,19 +387,25 @@ key_exchange(client, _Version, {premaster_secret, Secret, {_, PublicKey, _}}) ->
encrypted_premaster_secret(Secret, PublicKey),
#client_key_exchange{exchange_keys = EncPremasterSecret};
-key_exchange(client, _Version, {dh, <<?UINT32(Len), PublicKey:Len/binary>>}) ->
+key_exchange(client, _Version, {dh, PublicKey}) ->
#client_key_exchange{
exchange_keys = #client_diffie_hellman_public{
dh_public = PublicKey}
};
+key_exchange(client, _Version, {ecdh, #'ECPrivateKey'{publicKey = {0, ECPublicKey}}}) ->
+ #client_key_exchange{
+ exchange_keys = #client_ec_diffie_hellman_public{
+ dh_public = ECPublicKey}
+ };
+
key_exchange(client, _Version, {psk, Identity}) ->
#client_key_exchange{
exchange_keys = #client_psk_identity{
identity = Identity}
};
-key_exchange(client, _Version, {dhe_psk, Identity, <<?UINT32(Len), PublicKey:Len/binary>>}) ->
+key_exchange(client, _Version, {dhe_psk, Identity, PublicKey}) ->
#client_key_exchange{
exchange_keys = #client_dhe_psk_identity{
identity = Identity,
@@ -415,7 +417,7 @@ key_exchange(client, _Version, {psk_premaster_secret, PskIdentity, Secret, {_, P
encrypted_premaster_secret(Secret, PublicKey),
#client_key_exchange{
exchange_keys = #client_rsa_psk_identity{
- identity = PskIdentity,
+ identity = PskIdentity,
exchange_keys = EncPremasterSecret}};
key_exchange(client, _Version, {srp, PublicKey}) ->
@@ -424,31 +426,34 @@ key_exchange(client, _Version, {srp, PublicKey}) ->
srp_a = PublicKey}
};
-key_exchange(server, Version, {dh, {<<?UINT32(Len), PublicKey:Len/binary>>, _},
- #'DHParameter'{prime = P, base = G},
- HashSign, ClientRandom, ServerRandom, PrivateKey}) ->
- <<?UINT32(_), PBin/binary>> = crypto:mpint(P),
- <<?UINT32(_), GBin/binary>> = crypto:mpint(G),
- ServerDHParams = #server_dh_params{dh_p = PBin,
- dh_g = GBin, dh_y = PublicKey},
+key_exchange(server, Version, {dh, {PublicKey, _},
+ #'DHParameter'{prime = P, base = G},
+ HashSign, ClientRandom, ServerRandom, PrivateKey}) ->
+ ServerDHParams = #server_dh_params{dh_p = int_to_bin(P),
+ dh_g = int_to_bin(G), dh_y = PublicKey},
enc_server_key_exchange(Version, ServerDHParams, HashSign,
ClientRandom, ServerRandom, PrivateKey);
+key_exchange(server, Version, {ecdh, #'ECPrivateKey'{publicKey = {0, ECPublicKey},
+ parameters = ECCurve}, HashSign, ClientRandom, ServerRandom,
+ PrivateKey}) ->
+ ServerECParams = #server_ecdh_params{curve = ECCurve, public = ECPublicKey},
+ enc_server_key_exchange(Version, ServerECParams, HashSign,
+ ClientRandom, ServerRandom, PrivateKey);
+
key_exchange(server, Version, {psk, PskIdentityHint,
HashSign, ClientRandom, ServerRandom, PrivateKey}) ->
ServerPSKParams = #server_psk_params{hint = PskIdentityHint},
enc_server_key_exchange(Version, ServerPSKParams, HashSign,
ClientRandom, ServerRandom, PrivateKey);
-key_exchange(server, Version, {dhe_psk, PskIdentityHint, {<<?UINT32(Len), PublicKey:Len/binary>>, _},
+key_exchange(server, Version, {dhe_psk, PskIdentityHint, {PublicKey, _},
#'DHParameter'{prime = P, base = G},
HashSign, ClientRandom, ServerRandom, PrivateKey}) ->
- <<?UINT32(_), PBin/binary>> = crypto:mpint(P),
- <<?UINT32(_), GBin/binary>> = crypto:mpint(G),
ServerEDHPSKParams = #server_dhe_psk_params{
hint = PskIdentityHint,
- dh_params = #server_dh_params{dh_p = PBin,
- dh_g = GBin, dh_y = PublicKey}
+ dh_params = #server_dh_params{dh_p = int_to_bin(P),
+ dh_g = int_to_bin(G), dh_y = PublicKey}
},
enc_server_key_exchange(Version, ServerEDHPSKParams,
HashSign, ClientRandom, ServerRandom, PrivateKey);
@@ -591,6 +596,7 @@ get_tls_handshake(Version, Data, Buffer) ->
-spec decode_client_key(binary(), key_algo(), tls_version()) ->
#encrypted_premaster_secret{}
| #client_diffie_hellman_public{}
+ | #client_ec_diffie_hellman_public{}
| #client_psk_identity{}
| #client_dhe_psk_identity{}
| #client_rsa_psk_identity{}
@@ -661,8 +667,8 @@ decrypt_premaster_secret(Secret, RSAPrivateKey) ->
%% Description: Calculate server key exchange hash
%%--------------------------------------------------------------------
server_key_exchange_hash(md5sha, Value) ->
- MD5 = crypto:md5(Value),
- SHA = crypto:sha(Value),
+ MD5 = crypto:hash(md5, Value),
+ SHA = crypto:hash(sha, Value),
<<MD5/binary, SHA/binary>>;
server_key_exchange_hash(Hash, Value) ->
@@ -833,10 +839,35 @@ select_next_protocol(Protocols, NextProtocolSelector) ->
Protocol
end.
-handle_srp_info(undefined, Session) ->
- Session;
-handle_srp_info(#srp{username = Username}, Session) ->
- Session#session{srp_username = Username}.
+default_ecc_extensions(Version) ->
+ case proplists:get_bool(ec, crypto:algorithms()) of
+ true ->
+ EcPointFormats = #ec_point_formats{ec_point_format_list = [?ECPOINT_UNCOMPRESSED]},
+ EllipticCurves = #elliptic_curves{elliptic_curve_list = ssl_tls1:ecc_curves(Version)},
+ {EcPointFormats, EllipticCurves};
+ _ ->
+ {undefined, undefined}
+ end.
+
+handle_ecc_extensions(Version, EcPointFormats0, EllipticCurves0) ->
+ case proplists:get_bool(ec, crypto:algorithms()) of
+ true ->
+ EcPointFormats1 = handle_ecc_point_fmt_extension(EcPointFormats0),
+ EllipticCurves1 = handle_ecc_curves_extension(Version, EllipticCurves0),
+ {EcPointFormats1, EllipticCurves1};
+ _ ->
+ {undefined, undefined}
+ end.
+
+handle_ecc_point_fmt_extension(undefined) ->
+ undefined;
+handle_ecc_point_fmt_extension(_) ->
+ #ec_point_formats{ec_point_format_list = [?ECPOINT_UNCOMPRESSED]}.
+
+handle_ecc_curves_extension(Version, undefined) ->
+ undefined;
+handle_ecc_curves_extension(Version, _) ->
+ #elliptic_curves{elliptic_curve_list = ssl_tls1:ecc_curves(Version)}.
handle_renegotiation_info(_, #renegotiation_info{renegotiated_connection = ?byte(0)},
ConnectionStates, false, _, _) ->
@@ -1022,6 +1053,8 @@ dec_hs(_Version, ?CLIENT_HELLO, <<?BYTE(Major), ?BYTE(Minor), Random:32/binary,
RenegotiationInfo = proplists:get_value(renegotiation_info, DecodedExtensions, undefined),
SRP = proplists:get_value(srp, DecodedExtensions, undefined),
HashSigns = proplists:get_value(hash_signs, DecodedExtensions, undefined),
+ EllipticCurves = proplists:get_value(elliptic_curves, DecodedExtensions,
+ undefined),
NextProtocolNegotiation = proplists:get_value(next_protocol_negotiation, DecodedExtensions, undefined),
#client_hello{
@@ -1033,6 +1066,7 @@ dec_hs(_Version, ?CLIENT_HELLO, <<?BYTE(Major), ?BYTE(Minor), Random:32/binary,
renegotiation_info = RenegotiationInfo,
srp = SRP,
hash_signs = HashSigns,
+ elliptic_curves = EllipticCurves,
next_protocol_negotiation = NextProtocolNegotiation
};
@@ -1046,7 +1080,8 @@ dec_hs(_Version, ?SERVER_HELLO, <<?BYTE(Major), ?BYTE(Minor), Random:32/binary,
cipher_suite = Cipher_suite,
compression_method = Comp_method,
renegotiation_info = undefined,
- hash_signs = undefined};
+ hash_signs = undefined,
+ elliptic_curves = undefined};
dec_hs(_Version, ?SERVER_HELLO, <<?BYTE(Major), ?BYTE(Minor), Random:32/binary,
?BYTE(SID_length), Session_ID:SID_length/binary,
@@ -1058,6 +1093,8 @@ dec_hs(_Version, ?SERVER_HELLO, <<?BYTE(Major), ?BYTE(Minor), Random:32/binary,
undefined),
HashSigns = proplists:get_value(hash_signs, HelloExtensions,
undefined),
+ EllipticCurves = proplists:get_value(elliptic_curves, HelloExtensions,
+ undefined),
NextProtocolNegotiation = proplists:get_value(next_protocol_negotiation, HelloExtensions, undefined),
#server_hello{
@@ -1068,6 +1105,7 @@ dec_hs(_Version, ?SERVER_HELLO, <<?BYTE(Major), ?BYTE(Minor), Random:32/binary,
compression_method = Comp_method,
renegotiation_info = RenegotiationInfo,
hash_signs = HashSigns,
+ elliptic_curves = EllipticCurves,
next_protocol_negotiation = NextProtocolNegotiation};
dec_hs(_Version, ?CERTIFICATE, <<?UINT24(ACLen), ASN1Certs:ACLen/binary>>) ->
#certificate{asn1_certificates = certs_to_list(ASN1Certs)};
@@ -1111,6 +1149,11 @@ dec_client_key(<<>>, ?KEY_EXCHANGE_DIFFIE_HELLMAN, _) ->
dec_client_key(<<?UINT16(DH_YLen), DH_Y:DH_YLen/binary>>,
?KEY_EXCHANGE_DIFFIE_HELLMAN, _) ->
#client_diffie_hellman_public{dh_public = DH_Y};
+dec_client_key(<<>>, ?KEY_EXCHANGE_EC_DIFFIE_HELLMAN, _) ->
+ throw(?ALERT_REC(?FATAL, ?UNSUPPORTED_CERTIFICATE));
+dec_client_key(<<?BYTE(DH_YLen), DH_Y:DH_YLen/binary>>,
+ ?KEY_EXCHANGE_EC_DIFFIE_HELLMAN, _) ->
+ #client_ec_diffie_hellman_public{dh_public = DH_Y};
dec_client_key(<<?UINT16(Len), Id:Len/binary>>,
?KEY_EXCHANGE_PSK, _) ->
#client_psk_identity{identity = Id};
@@ -1161,6 +1204,19 @@ dec_server_key(<<?UINT16(PLen), P:PLen/binary,
params_bin = BinMsg,
hashsign = HashSign,
signature = Signature};
+%% ECParameters with named_curve
+%% TODO: explicit curve
+dec_server_key(<<?BYTE(?NAMED_CURVE), ?UINT16(CurveID),
+ ?BYTE(PointLen), ECPoint:PointLen/binary,
+ _/binary>> = KeyStruct,
+ ?KEY_EXCHANGE_EC_DIFFIE_HELLMAN, Version) ->
+ Params = #server_ecdh_params{curve = {namedCurve, ssl_tls1:enum_to_oid(CurveID)},
+ public = ECPoint},
+ {BinMsg, HashSign, Signature} = dec_ske_params(PointLen + 4, KeyStruct, Version),
+ #server_key_params{params = Params,
+ params_bin = BinMsg,
+ hashsign = HashSign,
+ signature = Signature};
dec_server_key(<<?UINT16(Len), PskIdentityHint:Len/binary>> = KeyStruct,
KeyExchange, Version)
when KeyExchange == ?KEY_EXCHANGE_PSK; KeyExchange == ?KEY_EXCHANGE_RSA_PSK ->
@@ -1237,6 +1293,22 @@ dec_hello_extensions(<<?UINT16(?SIGNATURE_ALGORITHMS_EXT), ?UINT16(Len),
dec_hello_extensions(Rest, [{hash_signs,
#hash_sign_algos{hash_sign_algos = HashSignAlgos}} | Acc]);
+dec_hello_extensions(<<?UINT16(?ELLIPTIC_CURVES_EXT), ?UINT16(Len),
+ ExtData:Len/binary, Rest/binary>>, Acc) ->
+ EllipticCurveListLen = Len - 2,
+ <<?UINT16(EllipticCurveListLen), EllipticCurveList/binary>> = ExtData,
+ EllipticCurves = [ssl_tls1:enum_to_oid(X) || <<X:16>> <= EllipticCurveList],
+ dec_hello_extensions(Rest, [{elliptic_curves,
+ #elliptic_curves{elliptic_curve_list = EllipticCurves}} | Acc]);
+
+dec_hello_extensions(<<?UINT16(?EC_POINT_FORMATS_EXT), ?UINT16(Len),
+ ExtData:Len/binary, Rest/binary>>, Acc) ->
+ ECPointFormatListLen = Len - 1,
+ <<?BYTE(ECPointFormatListLen), ECPointFormatList/binary>> = ExtData,
+ ECPointFormats = binary_to_list(ECPointFormatList),
+ dec_hello_extensions(Rest, [{ec_point_formats,
+ #ec_point_formats{ec_point_format_list = ECPointFormats}} | Acc]);
+
%% Ignore data following the ClientHello (i.e.,
%% extensions) if not understood.
@@ -1287,13 +1359,17 @@ enc_hs(#client_hello{client_version = {Major, Minor},
renegotiation_info = RenegotiationInfo,
srp = SRP,
hash_signs = HashSigns,
+ ec_point_formats = EcPointFormats,
+ elliptic_curves = EllipticCurves,
next_protocol_negotiation = NextProtocolNegotiation}, _Version) ->
SIDLength = byte_size(SessionID),
BinCompMethods = list_to_binary(CompMethods),
CmLength = byte_size(BinCompMethods),
BinCipherSuites = list_to_binary(CipherSuites),
CsLength = byte_size(BinCipherSuites),
- Extensions0 = hello_extensions(RenegotiationInfo, SRP, NextProtocolNegotiation),
+ Extensions0 = hello_extensions(RenegotiationInfo, SRP, NextProtocolNegotiation)
+ ++ ec_hello_extensions(lists:map(fun ssl_cipher:suite_definition/1, CipherSuites), EcPointFormats)
+ ++ ec_hello_extensions(lists:map(fun ssl_cipher:suite_definition/1, CipherSuites), EllipticCurves),
Extensions1 = if
Major == 3, Minor >=3 -> Extensions0 ++ hello_extensions(HashSigns);
true -> Extensions0
@@ -1308,16 +1384,21 @@ enc_hs(#client_hello{client_version = {Major, Minor},
enc_hs(#server_hello{server_version = {Major, Minor},
random = Random,
session_id = Session_ID,
- cipher_suite = Cipher_suite,
+ cipher_suite = CipherSuite,
compression_method = Comp_method,
renegotiation_info = RenegotiationInfo,
+ ec_point_formats = EcPointFormats,
+ elliptic_curves = EllipticCurves,
next_protocol_negotiation = NextProtocolNegotiation}, _Version) ->
SID_length = byte_size(Session_ID),
- Extensions = hello_extensions(RenegotiationInfo, NextProtocolNegotiation),
+ CipherSuites = [ssl_cipher:suite_definition(CipherSuite)],
+ Extensions = hello_extensions(RenegotiationInfo, NextProtocolNegotiation)
+ ++ ec_hello_extensions(CipherSuites, EcPointFormats)
+ ++ ec_hello_extensions(CipherSuites, EllipticCurves),
ExtensionsBin = enc_hello_extensions(Extensions),
{?SERVER_HELLO, <<?BYTE(Major), ?BYTE(Minor), Random:32/binary,
?BYTE(SID_length), Session_ID/binary,
- Cipher_suite/binary, ?BYTE(Comp_method), ExtensionsBin/binary>>};
+ CipherSuite/binary, ?BYTE(Comp_method), ExtensionsBin/binary>>};
enc_hs(#certificate{asn1_certificates = ASN1CertList}, _Version) ->
ASN1Certs = certs_from_list(ASN1CertList),
ACLen = erlang:iolist_size(ASN1Certs),
@@ -1370,6 +1451,9 @@ enc_cke(#encrypted_premaster_secret{premaster_secret = PKEPMS}, _) ->
enc_cke(#client_diffie_hellman_public{dh_public = DHPublic}, _) ->
Len = byte_size(DHPublic),
<<?UINT16(Len), DHPublic/binary>>;
+enc_cke(#client_ec_diffie_hellman_public{dh_public = DHPublic}, _) ->
+ Len = byte_size(DHPublic),
+ <<?BYTE(Len), DHPublic/binary>>;
enc_cke(#client_psk_identity{identity = undefined}, _) ->
Id = <<"psk_identity">>,
Len = byte_size(Id),
@@ -1398,6 +1482,11 @@ enc_server_key(#server_dh_params{dh_p = P, dh_g = G, dh_y = Y}) ->
GLen = byte_size(G),
YLen = byte_size(Y),
<<?UINT16(PLen), P/binary, ?UINT16(GLen), G/binary, ?UINT16(YLen), Y/binary>>;
+enc_server_key(#server_ecdh_params{curve = {namedCurve, ECCurve}, public = ECPubKey}) ->
+ %%TODO: support arbitrary keys
+ KLen = size(ECPubKey),
+ <<?BYTE(?NAMED_CURVE_TYPE), ?UINT16((ssl_tls1:oid_to_enum(ECCurve))),
+ ?BYTE(KLen), ECPubKey/binary>>;
enc_server_key(#server_psk_params{hint = PskIdentityHint}) ->
Len = byte_size(PskIdentityHint),
<<?UINT16(Len), PskIdentityHint/binary>>;
@@ -1431,11 +1520,46 @@ enc_sign(_HashSign, Sign, _Version) ->
SignLen = byte_size(Sign),
<<?UINT16(SignLen), Sign/binary>>.
+
+ec_hello_extensions(CipherSuites, #elliptic_curves{} = Info) ->
+ case advertises_ec_ciphers(CipherSuites) of
+ true ->
+ [Info];
+ false ->
+ []
+ end;
+ec_hello_extensions(CipherSuites, #ec_point_formats{} = Info) ->
+ case advertises_ec_ciphers(CipherSuites) of
+ true ->
+ [Info];
+ false ->
+ []
+ end;
+ec_hello_extensions(_, undefined) ->
+ [].
+
hello_extensions(RenegotiationInfo, NextProtocolNegotiation) ->
hello_extensions(RenegotiationInfo) ++ next_protocol_extension(NextProtocolNegotiation).
hello_extensions(RenegotiationInfo, SRP, NextProtocolNegotiation) ->
- hello_extensions(RenegotiationInfo) ++ hello_extensions(SRP) ++ next_protocol_extension(NextProtocolNegotiation).
+ hello_extensions(RenegotiationInfo)
+ ++ hello_extensions(SRP)
+ ++ next_protocol_extension(NextProtocolNegotiation).
+
+advertises_ec_ciphers([]) ->
+ false;
+advertises_ec_ciphers([{ecdh_ecdsa, _,_,_} | _]) ->
+ true;
+advertises_ec_ciphers([{ecdhe_ecdsa, _,_,_} | _]) ->
+ true;
+advertises_ec_ciphers([{ecdh_rsa, _,_,_} | _]) ->
+ true;
+advertises_ec_ciphers([{ecdhe_rsa, _,_,_} | _]) ->
+ true;
+advertises_ec_ciphers([{ecdh_anon, _,_,_} | _]) ->
+ true;
+advertises_ec_ciphers([_| Rest]) ->
+ advertises_ec_ciphers(Rest).
%% Renegotiation info
hello_extensions(#renegotiation_info{renegotiated_connection = undefined}) ->
@@ -1473,12 +1597,22 @@ enc_hello_extensions([#renegotiation_info{renegotiated_connection = Info} | Rest
InfoLen = byte_size(Info),
Len = InfoLen +1,
enc_hello_extensions(Rest, <<?UINT16(?RENEGOTIATION_EXT), ?UINT16(Len), ?BYTE(InfoLen), Info/binary, Acc/binary>>);
-
+enc_hello_extensions([#elliptic_curves{elliptic_curve_list = EllipticCurves} | Rest], Acc) ->
+ EllipticCurveList = << <<(ssl_tls1:oid_to_enum(X)):16>> || X <- EllipticCurves>>,
+ ListLen = byte_size(EllipticCurveList),
+ Len = ListLen + 2,
+ enc_hello_extensions(Rest, <<?UINT16(?ELLIPTIC_CURVES_EXT),
+ ?UINT16(Len), ?UINT16(ListLen), EllipticCurveList/binary, Acc/binary>>);
+enc_hello_extensions([#ec_point_formats{ec_point_format_list = ECPointFormats} | Rest], Acc) ->
+ ECPointFormatList = list_to_binary(ECPointFormats),
+ ListLen = byte_size(ECPointFormatList),
+ Len = ListLen + 1,
+ enc_hello_extensions(Rest, <<?UINT16(?EC_POINT_FORMATS_EXT),
+ ?UINT16(Len), ?BYTE(ListLen), ECPointFormatList/binary, Acc/binary>>);
enc_hello_extensions([#srp{username = UserName} | Rest], Acc) ->
SRPLen = byte_size(UserName),
Len = SRPLen + 2,
enc_hello_extensions(Rest, <<?UINT16(?SRP_EXT), ?UINT16(Len), ?BYTE(SRPLen), UserName/binary, Acc/binary>>);
-
enc_hello_extensions([#hash_sign_algos{hash_sign_algos = HashSignAlgos} | Rest], Acc) ->
SignAlgoList = << <<(ssl_cipher:hash_algorithm(Hash)):8, (ssl_cipher:sign_algorithm(Sign)):8>> ||
{Hash, Sign} <- HashSignAlgos >>,
@@ -1513,9 +1647,15 @@ from_2bytes(<<?UINT16(N), Rest/binary>>, Acc) ->
certificate_types({KeyExchange, _, _, _})
when KeyExchange == rsa;
KeyExchange == dhe_dss;
- KeyExchange == dhe_rsa ->
+ KeyExchange == dhe_rsa;
+ KeyExchange == ecdhe_rsa ->
<<?BYTE(?RSA_SIGN), ?BYTE(?DSS_SIGN)>>;
+certificate_types({KeyExchange, _, _, _})
+ when KeyExchange == dh_ecdsa;
+ KeyExchange == dhe_ecdsa ->
+ <<?BYTE(?ECDSA_SIGN)>>;
+
certificate_types(_) ->
<<?BYTE(?RSA_SIGN)>>.
@@ -1532,9 +1672,6 @@ certificate_authorities(CertDbHandle, CertDbRef) ->
Enc = fun(#'OTPCertificate'{tbsCertificate=TBSCert}) ->
OTPSubj = TBSCert#'OTPTBSCertificate'.subject,
DNEncodedBin = public_key:pkix_encode('Name', OTPSubj, otp),
- %%Subj = public_key:pkix_transform(OTPSubj, encode),
- %% {ok, DNEncoded} = 'OTP-PUB-KEY':encode('Name', Subj),
- %% DNEncodedBin = iolist_to_binary(DNEncoded),
DNEncodedLen = byte_size(DNEncodedBin),
<<?UINT16(DNEncodedLen), DNEncodedBin/binary>>
end,
@@ -1555,7 +1692,9 @@ digitally_signed(_Version, Hash, HashAlgo, #'DSAPrivateKey'{} = Key) ->
public_key:sign({digest, Hash}, HashAlgo, Key);
digitally_signed(_Version, Hash, _HashAlgo, #'RSAPrivateKey'{} = Key) ->
public_key:encrypt_private(Hash, Key,
- [{rsa_pad, rsa_pkcs1_padding}]).
+ [{rsa_pad, rsa_pkcs1_padding}]);
+digitally_signed(_Version, Hash, HashAlgo, Key) ->
+ public_key:sign({digest, Hash}, HashAlgo, Key).
calc_master_secret({3,0}, _PrfAlgo, PremasterSecret, ClientRandom, ServerRandom) ->
ssl_ssl3:master_secret(PremasterSecret, ClientRandom, ServerRandom);
@@ -1588,6 +1727,10 @@ key_exchange_alg(rsa) ->
key_exchange_alg(Alg) when Alg == dhe_rsa; Alg == dhe_dss;
Alg == dh_dss; Alg == dh_rsa; Alg == dh_anon ->
?KEY_EXCHANGE_DIFFIE_HELLMAN;
+key_exchange_alg(Alg) when Alg == ecdhe_rsa; Alg == ecdh_rsa;
+ Alg == ecdhe_ecdsa; Alg == ecdh_ecdsa;
+ Alg == ecdh_anon ->
+ ?KEY_EXCHANGE_EC_DIFFIE_HELLMAN;
key_exchange_alg(psk) ->
?KEY_EXCHANGE_PSK;
key_exchange_alg(dhe_psk) ->
@@ -1612,15 +1755,70 @@ apply_user_fun(Fun, OtpCert, ExtensionOrError, UserState0, SslState) ->
-define(TLSEXT_SIGALG_RSA(MD), {MD, rsa}).
-define(TLSEXT_SIGALG_DSA(MD), {MD, dsa}).
+-define(TLSEXT_SIGALG_ECDSA(MD), {MD, ecdsa}).
--define(TLSEXT_SIGALG(MD), ?TLSEXT_SIGALG_RSA(MD)).
+-define(TLSEXT_SIGALG(MD), ?TLSEXT_SIGALG_ECDSA(MD), ?TLSEXT_SIGALG_RSA(MD)).
default_hash_signs() ->
+ HashSigns = [?TLSEXT_SIGALG(sha512),
+ ?TLSEXT_SIGALG(sha384),
+ ?TLSEXT_SIGALG(sha256),
+ ?TLSEXT_SIGALG(sha224),
+ ?TLSEXT_SIGALG(sha),
+ ?TLSEXT_SIGALG_DSA(sha),
+ ?TLSEXT_SIGALG_RSA(md5)],
+ HasECC = proplists:get_bool(ec, crypto:algorithms()),
#hash_sign_algos{hash_sign_algos =
- [?TLSEXT_SIGALG(sha512),
- ?TLSEXT_SIGALG(sha384),
- ?TLSEXT_SIGALG(sha256),
- ?TLSEXT_SIGALG(sha224),
- ?TLSEXT_SIGALG(sha),
- ?TLSEXT_SIGALG_DSA(sha),
- ?TLSEXT_SIGALG_RSA(md5)]}.
+ lists:filter(fun({_, ecdsa}) -> HasECC;
+ (_) -> true end, HashSigns)}.
+
+handle_hello_extensions(#client_hello{random = Random,
+ cipher_suites = CipherSuites,
+ renegotiation_info = Info,
+ srp = SRP,
+ ec_point_formats = EcPointFormats0,
+ elliptic_curves = EllipticCurves0} = Hello, Version,
+ #ssl_options{secure_renegotiate = SecureRenegotation} = Opts,
+ Session0, ConnectionStates0, Renegotiation) ->
+ Session = handle_srp_extension(SRP, Session0),
+ ConnectionStates = handle_renegotiation_extension(Version, Info, Random, Session, ConnectionStates0,
+ Renegotiation, SecureRenegotation, CipherSuites),
+ ProtocolsToAdvertise = handle_next_protocol_extension(Hello, Renegotiation, Opts),
+ {EcPointFormats, EllipticCurves} = handle_ecc_extensions(Version, EcPointFormats0, EllipticCurves0),
+ %%TODO make extensions compund data structure
+ {Session, ConnectionStates, ProtocolsToAdvertise, EcPointFormats, EllipticCurves}.
+
+
+handle_renegotiation_extension(Version, Info, Random, #session{cipher_suite = CipherSuite,
+ compression_method = Compression},
+ ConnectionStates0, Renegotiation, SecureRenegotation, CipherSuites) ->
+ case handle_renegotiation_info(server, Info, ConnectionStates0,
+ Renegotiation, SecureRenegotation,
+ CipherSuites) of
+ {ok, ConnectionStates1} ->
+ hello_pending_connection_states(server,
+ Version,
+ CipherSuite,
+ Random,
+ Compression,
+ ConnectionStates1);
+ #alert{} = Alert ->
+ throw(Alert)
+ end.
+
+handle_next_protocol_extension(Hello, Renegotiation, SslOpts)->
+ case handle_next_protocol_on_server(Hello, Renegotiation, SslOpts) of
+ #alert{} = Alert ->
+ throw(Alert);
+ ProtocolsToAdvertise ->
+ ProtocolsToAdvertise
+ end.
+
+handle_srp_extension(undefined, Session) ->
+ Session;
+handle_srp_extension(#srp{username = Username}, Session) ->
+ Session#session{srp_username = Username}.
+
+int_to_bin(I) ->
+ L = (length(integer_to_list(I, 16)) + 1) div 2,
+ <<I:(L*8)>>.
diff --git a/lib/ssl/src/ssl_handshake.hrl b/lib/ssl/src/ssl_handshake.hrl
index 1fbb88f5f6..b2387a0ee7 100644
--- a/lib/ssl/src/ssl_handshake.hrl
+++ b/lib/ssl/src/ssl_handshake.hrl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2007-2012. All Rights Reserved.
+%% Copyright Ericsson AB 2007-2013. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -28,9 +28,9 @@
-include_lib("public_key/include/public_key.hrl").
--type algo_oid() :: ?'rsaEncryption' | ?'id-dsa'.
--type public_key_params() :: #'Dss-Parms'{} | term().
--type public_key_info() :: {algo_oid(), #'RSAPublicKey'{} | integer() , public_key_params()}.
+-type oid() :: tuple().
+-type public_key_params() :: #'Dss-Parms'{} | {namedCurve, oid()} | #'ECParameters'{} | term().
+-type public_key_info() :: {oid(), #'RSAPublicKey'{} | integer() | #'ECPoint'{}, public_key_params()}.
-type tls_handshake_history() :: {[binary()], [binary()]}.
-define(NO_PROTOCOL, <<>>).
@@ -102,6 +102,8 @@
renegotiation_info,
srp, % srp username to send
hash_signs, % supported combinations of hashes/signature algos
+ ec_point_formats, % supported ec point formats
+ elliptic_curves, % supported elliptic curver
next_protocol_negotiation = undefined % [binary()]
}).
@@ -113,6 +115,8 @@
compression_method, % compression_method
renegotiation_info,
hash_signs, % supported combinations of hashes/signature algos
+ ec_point_formats, % supported ec point formats
+ elliptic_curves, % supported elliptic curver
next_protocol_negotiation = undefined % [binary()]
}).
@@ -130,6 +134,7 @@
-define(KEY_EXCHANGE_RSA, 0).
-define(KEY_EXCHANGE_DIFFIE_HELLMAN, 1).
+-define(KEY_EXCHANGE_EC_DIFFIE_HELLMAN, 6).
-define(KEY_EXCHANGE_PSK, 2).
-define(KEY_EXCHANGE_DHE_PSK, 3).
-define(KEY_EXCHANGE_RSA_PSK, 4).
@@ -146,6 +151,11 @@
dh_y %% opaque DH_Ys<1..2^16-1>
}).
+-record(server_ecdh_params, {
+ curve,
+ public %% opaque encoded ECpoint
+ }).
+
-record(server_psk_params, {
hint
}).
@@ -195,6 +205,9 @@
-define(DSS_SIGN, 2).
-define(RSA_FIXED_DH, 3).
-define(DSS_FIXED_DH, 4).
+-define(ECDSA_SIGN, 64).
+-define(RSA_FIXED_ECDH, 65).
+-define(ECDSA_FIXED_ECDH, 66).
% opaque DistinguishedName<1..2^16-1>;
@@ -231,6 +244,10 @@
dh_public
}).
+-record(client_ec_diffie_hellman_public, {
+ dh_public
+ }).
+
-record(client_psk_identity, {
identity
}).
@@ -304,6 +321,33 @@
-record(next_protocol, {selected_protocol}).
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%% ECC Extensions RFC 4492 section 4 and 5
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+-define(ELLIPTIC_CURVES_EXT, 10).
+-define(EC_POINT_FORMATS_EXT, 11).
+
+-record(elliptic_curves, {
+ elliptic_curve_list
+ }).
+
+-record(ec_point_formats, {
+ ec_point_format_list
+ }).
+
+-define(ECPOINT_UNCOMPRESSED, 0).
+-define(ECPOINT_ANSIX962_COMPRESSED_PRIME, 1).
+-define(ECPOINT_ANSIX962_COMPRESSED_CHAR2, 2).
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%% ECC RFC 4492 Handshake Messages, Section 5
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+-define(EXPLICIT_PRIME, 1).
+-define(EXPLICIT_CHAR2, 2).
+-define(NAMED_CURVE, 3).
+
-endif. % -ifdef(ssl_handshake).
diff --git a/lib/ssl/src/ssl_internal.hrl b/lib/ssl/src/ssl_internal.hrl
index 96a1c8e1ce..14db4a6067 100644
--- a/lib/ssl/src/ssl_internal.hrl
+++ b/lib/ssl/src/ssl_internal.hrl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2007-2012. All Rights Reserved.
+%% Copyright Ericsson AB 2007-2013. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -37,9 +37,9 @@
-type tls_atom_version() :: sslv3 | tlsv1 | 'tlsv1.1' | 'tlsv1.2'.
-type certdb_ref() :: reference().
-type db_handle() :: term().
--type key_algo() :: null | rsa | dhe_rsa | dhe_dss | dh_anon.
+-type key_algo() :: null | rsa | dhe_rsa | dhe_dss | ecdhe_ecdsa| ecdh_ecdsa | ecdh_rsa| srp_rsa| srp_dss | psk | dhe_psk | rsa_psk | dh_anon | ecdh_anon | srp_anon.
-type der_cert() :: binary().
--type private_key() :: #'RSAPrivateKey'{} | #'DSAPrivateKey'{}.
+-type private_key() :: #'RSAPrivateKey'{} | #'DSAPrivateKey'{} | #'ECPrivateKey'{}.
-type issuer() :: tuple().
-type serialnumber() :: integer().
-type cert_key() :: {reference(), integer(), issuer()}.
diff --git a/lib/ssl/src/ssl_manager.erl b/lib/ssl/src/ssl_manager.erl
index aa9da65bb8..caea528a08 100644
--- a/lib/ssl/src/ssl_manager.erl
+++ b/lib/ssl/src/ssl_manager.erl
@@ -103,7 +103,7 @@ connection_init(Trustedcerts, Role) ->
%% Description: Cach a pem file and return its content.
%%--------------------------------------------------------------------
cache_pem_file(File, DbHandle) ->
- MD5 = crypto:md5(File),
+ MD5 = crypto:hash(md5, File),
case ssl_certificate_db:lookup_cached_pem(DbHandle, MD5) of
[{Content,_}] ->
{ok, Content};
@@ -468,7 +468,7 @@ new_id(Port, Tries, Cache, CacheCb) ->
clean_cert_db(Ref, CertDb, RefDb, PemCache, File) ->
case ssl_certificate_db:ref_count(Ref, RefDb, 0) of
0 ->
- MD5 = crypto:md5(File),
+ MD5 = crypto:hash(md5, File),
case ssl_certificate_db:lookup_cached_pem(PemCache, MD5) of
[{Content, Ref}] ->
ssl_certificate_db:insert(MD5, Content, PemCache);
diff --git a/lib/ssl/src/ssl_record.erl b/lib/ssl/src/ssl_record.erl
index 26aca56739..50b1b2cda9 100644
--- a/lib/ssl/src/ssl_record.erl
+++ b/lib/ssl/src/ssl_record.erl
@@ -712,12 +712,4 @@ mac_hash({3, N} = Version, MacAlg, MacSecret, SeqNo, Type, Length, Fragment)
Length, Fragment).
sufficient_tlsv1_2_crypto_support() ->
- Data = "Sampl",
- Data2 = "e #1",
- Key = <<0,1,2,3,16,17,18,19,32,33,34,35,48,49,50,51,4,5,6,7,20,21,22,23,36,37,38,39,
- 52,53,54,55,8,9,10,11,24,25,26,27,40,41,42,43,56,57,58,59>>,
- try
- crypto:sha256_mac(Key, lists:flatten([Data, Data2])),
- true
- catch _:_ -> false
- end.
+ proplists:get_bool(sha256, crypto:algorithms()).
diff --git a/lib/ssl/src/ssl_ssl3.erl b/lib/ssl/src/ssl_ssl3.erl
index a11c5b8c0c..013c27ebb5 100644
--- a/lib/ssl/src/ssl_ssl3.erl
+++ b/lib/ssl/src/ssl_ssl3.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2007-2012. All Rights Reserved.
+%% Copyright Ericsson AB 2007-2013. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -154,9 +154,9 @@ suites() ->
%%--------------------------------------------------------------------
hash(?MD5, Data) ->
- crypto:md5(Data);
+ crypto:hash(md5, Data);
hash(?SHA, Data) ->
- crypto:sha(Data).
+ crypto:hash(sha, Data).
%%pad_1(?NULL) ->
%% "";
@@ -198,6 +198,6 @@ gen(_Secret, _All, Wanted, Len, _C, _N, Acc) when Wanted =< Len ->
Block;
gen(Secret, All, Wanted, Len, C, N, Acc) ->
Prefix = lists:duplicate(N, C),
- SHA = crypto:sha([Prefix, All]),
- MD5 = crypto:md5([Secret, SHA]),
+ SHA = crypto:hash(sha, [Prefix, All]),
+ MD5 = crypto:hash(md5, [Secret, SHA]),
gen(Secret, All, Wanted, Len + 16, C+1, N+1, [MD5 | Acc]).
diff --git a/lib/ssl/src/ssl_tls1.erl b/lib/ssl/src/ssl_tls1.erl
index 41dc1bf0dc..f8fd9efd07 100644
--- a/lib/ssl/src/ssl_tls1.erl
+++ b/lib/ssl/src/ssl_tls1.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2007-2012. All Rights Reserved.
+%% Copyright Ericsson AB 2007-2013. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -29,7 +29,8 @@
-include("ssl_record.hrl").
-export([master_secret/4, finished/5, certificate_verify/3, mac_hash/7,
- setup_keys/8, suites/1, prf/5]).
+ setup_keys/8, suites/1, prf/5,
+ ecc_curves/1, oid_to_enum/1, enum_to_oid/1]).
%%====================================================================
%% Internal application API
@@ -57,8 +58,8 @@ finished(Role, Version, PrfAlgo, MasterSecret, Handshake)
%% verify_data
%% PRF(master_secret, finished_label, MD5(handshake_messages) +
%% SHA-1(handshake_messages)) [0..11];
- MD5 = crypto:md5(Handshake),
- SHA = crypto:sha(Handshake),
+ MD5 = crypto:hash(md5, Handshake),
+ SHA = crypto:hash(sha, Handshake),
prf(?MD5SHA, MasterSecret, finished_label(Role), [MD5, SHA], 12);
finished(Role, Version, PrfAlgo, MasterSecret, Handshake)
@@ -76,8 +77,8 @@ finished(Role, Version, PrfAlgo, MasterSecret, Handshake)
-spec certificate_verify(md5sha | sha, integer(), [binary()]) -> binary().
certificate_verify(md5sha, _Version, Handshake) ->
- MD5 = crypto:md5(Handshake),
- SHA = crypto:sha(Handshake),
+ MD5 = crypto:hash(md5, Handshake),
+ SHA = crypto:hash(sha, Handshake),
<<MD5/binary, SHA/binary>>;
certificate_verify(HashAlgo, _Version, Handshake) ->
@@ -184,27 +185,56 @@ mac_hash(Method, Mac_write_secret, Seq_num, Type, {Major, Minor},
suites(Minor) when Minor == 1; Minor == 2->
[
+ ?TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA,
+ ?TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA,
?TLS_DHE_RSA_WITH_AES_256_CBC_SHA,
?TLS_DHE_DSS_WITH_AES_256_CBC_SHA,
+ ?TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA,
+ ?TLS_ECDH_RSA_WITH_AES_256_CBC_SHA,
?TLS_RSA_WITH_AES_256_CBC_SHA,
+
+ ?TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA,
+ ?TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA,
?TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA,
?TLS_DHE_DSS_WITH_3DES_EDE_CBC_SHA,
+ ?TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA,
+ ?TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA,
?TLS_RSA_WITH_3DES_EDE_CBC_SHA,
+
+ ?TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA,
+ ?TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA,
?TLS_DHE_RSA_WITH_AES_128_CBC_SHA,
?TLS_DHE_DSS_WITH_AES_128_CBC_SHA,
+ ?TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA,
+ ?TLS_ECDH_RSA_WITH_AES_128_CBC_SHA,
?TLS_RSA_WITH_AES_128_CBC_SHA,
%%?TLS_RSA_WITH_IDEA_CBC_SHA,
+ ?TLS_ECDHE_ECDSA_WITH_RC4_128_SHA,
+ ?TLS_ECDHE_RSA_WITH_RC4_128_SHA,
?TLS_RSA_WITH_RC4_128_SHA,
?TLS_RSA_WITH_RC4_128_MD5,
?TLS_DHE_RSA_WITH_DES_CBC_SHA,
+ ?TLS_ECDH_ECDSA_WITH_RC4_128_SHA,
+ ?TLS_ECDH_RSA_WITH_RC4_128_SHA,
?TLS_RSA_WITH_DES_CBC_SHA
];
suites(Minor) when Minor == 3 ->
[
+ ?TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384,
+ ?TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384,
+ ?TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA384,
+ ?TLS_ECDH_RSA_WITH_AES_256_CBC_SHA384,
+
?TLS_DHE_RSA_WITH_AES_256_CBC_SHA256,
?TLS_DHE_DSS_WITH_AES_256_CBC_SHA256,
?TLS_RSA_WITH_AES_256_CBC_SHA256,
+
+ ?TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256,
+ ?TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256,
+ ?TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA256,
+ ?TLS_ECDH_RSA_WITH_AES_128_CBC_SHA256,
+
?TLS_DHE_RSA_WITH_AES_128_CBC_SHA256,
?TLS_DHE_DSS_WITH_AES_128_CBC_SHA256,
?TLS_RSA_WITH_AES_128_CBC_SHA256
@@ -218,16 +248,8 @@ suites(Minor) when Minor == 3 ->
%%%% HMAC and the Pseudorandom Functions RFC 2246 & 4346 - 5.%%%%
hmac_hash(?NULL, _, _) ->
<<>>;
-hmac_hash(?MD5, Key, Value) ->
- crypto:md5_mac(Key, Value);
-hmac_hash(?SHA, Key, Value) ->
- crypto:sha_mac(Key, Value);
-hmac_hash(?SHA256, Key, Value) ->
- crypto:sha256_mac(Key, Value);
-hmac_hash(?SHA384, Key, Value) ->
- crypto:sha384_mac(Key, Value);
-hmac_hash(?SHA512, Key, Value) ->
- crypto:sha512_mac(Key, Value).
+hmac_hash(Alg, Key, Value) ->
+ crypto:hmac(mac_algo(Alg), Key, Value).
mac_algo(?MD5) -> md5;
mac_algo(?SHA) -> sha;
@@ -303,3 +325,64 @@ finished_label(client) ->
<<"client finished">>;
finished_label(server) ->
<<"server finished">>.
+
+%% list ECC curves in prefered order
+ecc_curves(_Minor) ->
+ [?sect571r1,?sect571k1,?secp521r1,?sect409k1,?sect409r1,
+ ?secp384r1,?sect283k1,?sect283r1,?secp256k1,?secp256r1,
+ ?sect239k1,?sect233k1,?sect233r1,?secp224k1,?secp224r1,
+ ?sect193r1,?sect193r2,?secp192k1,?secp192r1,?sect163k1,
+ ?sect163r1,?sect163r2,?secp160k1,?secp160r1,?secp160r2].
+
+%% ECC curves from draft-ietf-tls-ecc-12.txt (Oct. 17, 2005)
+oid_to_enum(?sect163k1) -> 1;
+oid_to_enum(?sect163r1) -> 2;
+oid_to_enum(?sect163r2) -> 3;
+oid_to_enum(?sect193r1) -> 4;
+oid_to_enum(?sect193r2) -> 5;
+oid_to_enum(?sect233k1) -> 6;
+oid_to_enum(?sect233r1) -> 7;
+oid_to_enum(?sect239k1) -> 8;
+oid_to_enum(?sect283k1) -> 9;
+oid_to_enum(?sect283r1) -> 10;
+oid_to_enum(?sect409k1) -> 11;
+oid_to_enum(?sect409r1) -> 12;
+oid_to_enum(?sect571k1) -> 13;
+oid_to_enum(?sect571r1) -> 14;
+oid_to_enum(?secp160k1) -> 15;
+oid_to_enum(?secp160r1) -> 16;
+oid_to_enum(?secp160r2) -> 17;
+oid_to_enum(?secp192k1) -> 18;
+oid_to_enum(?secp192r1) -> 19;
+oid_to_enum(?secp224k1) -> 20;
+oid_to_enum(?secp224r1) -> 21;
+oid_to_enum(?secp256k1) -> 22;
+oid_to_enum(?secp256r1) -> 23;
+oid_to_enum(?secp384r1) -> 24;
+oid_to_enum(?secp521r1) -> 25.
+
+enum_to_oid(1) -> ?sect163k1;
+enum_to_oid(2) -> ?sect163r1;
+enum_to_oid(3) -> ?sect163r2;
+enum_to_oid(4) -> ?sect193r1;
+enum_to_oid(5) -> ?sect193r2;
+enum_to_oid(6) -> ?sect233k1;
+enum_to_oid(7) -> ?sect233r1;
+enum_to_oid(8) -> ?sect239k1;
+enum_to_oid(9) -> ?sect283k1;
+enum_to_oid(10) -> ?sect283r1;
+enum_to_oid(11) -> ?sect409k1;
+enum_to_oid(12) -> ?sect409r1;
+enum_to_oid(13) -> ?sect571k1;
+enum_to_oid(14) -> ?sect571r1;
+enum_to_oid(15) -> ?secp160k1;
+enum_to_oid(16) -> ?secp160r1;
+enum_to_oid(17) -> ?secp160r2;
+enum_to_oid(18) -> ?secp192k1;
+enum_to_oid(19) -> ?secp192r1;
+enum_to_oid(20) -> ?secp224k1;
+enum_to_oid(21) -> ?secp224r1;
+enum_to_oid(22) -> ?secp256k1;
+enum_to_oid(23) -> ?secp256r1;
+enum_to_oid(24) -> ?secp384r1;
+enum_to_oid(25) -> ?secp521r1.
diff --git a/lib/ssl/test/erl_make_certs.erl b/lib/ssl/test/erl_make_certs.erl
index 5b92e551a5..723ccf4496 100644
--- a/lib/ssl/test/erl_make_certs.erl
+++ b/lib/ssl/test/erl_make_certs.erl
@@ -45,7 +45,7 @@
%% {dnQualifer, DnQ}
%% issuer = {Issuer, IssuerKey} true (i.e. a ca cert is created)
%% (obs IssuerKey migth be {Key, Password}
-%% key = KeyFile|KeyBin|rsa|dsa Subject PublicKey rsa or dsa generates key
+%% key = KeyFile|KeyBin|rsa|dsa|ec Subject PublicKey rsa, dsa or ec generates key
%%
%%
%% (OBS: The generated keys are for testing only)
@@ -91,6 +91,16 @@ gen_dsa(LSize,NSize) when is_integer(LSize), is_integer(NSize) ->
{Key, encode_key(Key)}.
%%--------------------------------------------------------------------
+%% @doc Creates a ec key (OBS: for testing only)
+%% the sizes are in bytes
+%% @spec (::integer()) -> {::atom(), ::binary(), ::opaque()}
+%% @end
+%%--------------------------------------------------------------------
+gen_ec(Curve) when is_atom(Curve) ->
+ Key = gen_ec2(Curve),
+ {Key, encode_key(Key)}.
+
+%%--------------------------------------------------------------------
%% @doc Verifies cert signatures
%% @spec (::binary(), ::tuple()) -> ::boolean()
%% @end
@@ -102,7 +112,10 @@ verify_signature(DerEncodedCert, DerKey, _KeyParams) ->
public_key:pkix_verify(DerEncodedCert,
#'RSAPublicKey'{modulus=Mod, publicExponent=Exp});
#'DSAPrivateKey'{p=P, q=Q, g=G, y=Y} ->
- public_key:pkix_verify(DerEncodedCert, {Y, #'Dss-Parms'{p=P, q=Q, g=G}})
+ public_key:pkix_verify(DerEncodedCert, {Y, #'Dss-Parms'{p=P, q=Q, g=G}});
+ #'ECPrivateKey'{version = _Version, privateKey = _PrivKey,
+ parameters = Params, publicKey = {0, PubKey}} ->
+ public_key:pkix_verify(DerEncodedCert, {#'ECPoint'{point = PubKey}, Params})
end.
%%%%%%%%%%%%%%%%%%%%%%%%% Implementation %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
@@ -112,6 +125,7 @@ get_key(Opts) ->
undefined -> make_key(rsa, Opts);
rsa -> make_key(rsa, Opts);
dsa -> make_key(dsa, Opts);
+ ec -> make_key(ec, Opts);
Key ->
Password = proplists:get_value(password, Opts, no_passwd),
decode_key(Key, Password)
@@ -129,6 +143,8 @@ decode_key(#'RSAPrivateKey'{} = Key,_) ->
Key;
decode_key(#'DSAPrivateKey'{} = Key,_) ->
Key;
+decode_key(#'ECPrivateKey'{} = Key,_) ->
+ Key;
decode_key(PemEntry = {_,_,_}, Pw) ->
public_key:pem_entry_decode(PemEntry, Pw);
decode_key(PemBin, Pw) ->
@@ -140,7 +156,10 @@ encode_key(Key = #'RSAPrivateKey'{}) ->
{'RSAPrivateKey', Der, not_encrypted};
encode_key(Key = #'DSAPrivateKey'{}) ->
{ok, Der} = 'OTP-PUB-KEY':encode('DSAPrivateKey', Key),
- {'DSAPrivateKey', Der, not_encrypted}.
+ {'DSAPrivateKey', Der, not_encrypted};
+encode_key(Key = #'ECPrivateKey'{}) ->
+ {ok, Der} = 'OTP-PUB-KEY':encode('ECPrivateKey', Key),
+ {'ECPrivateKey', Der, not_encrypted}.
make_tbs(SubjectKey, Opts) ->
Version = list_to_atom("v"++integer_to_list(proplists:get_value(version, Opts, 3))),
@@ -277,7 +296,14 @@ publickey(#'RSAPrivateKey'{modulus=N, publicExponent=E}) ->
publickey(#'DSAPrivateKey'{p=P, q=Q, g=G, y=Y}) ->
Algo = #'PublicKeyAlgorithm'{algorithm= ?'id-dsa',
parameters={params, #'Dss-Parms'{p=P, q=Q, g=G}}},
- #'OTPSubjectPublicKeyInfo'{algorithm = Algo, subjectPublicKey = Y}.
+ #'OTPSubjectPublicKeyInfo'{algorithm = Algo, subjectPublicKey = Y};
+publickey(#'ECPrivateKey'{version = _Version,
+ privateKey = _PrivKey,
+ parameters = Params,
+ publicKey = {0, PubKey}}) ->
+ Algo = #'PublicKeyAlgorithm'{algorithm= ?'id-ecPublicKey', parameters=Params},
+ #'OTPSubjectPublicKeyInfo'{algorithm = Algo,
+ subjectPublicKey = #'ECPoint'{point = PubKey}}.
validity(Opts) ->
DefFrom0 = calendar:gregorian_days_to_date(calendar:date_to_gregorian_days(date())-1),
@@ -298,13 +324,24 @@ sign_algorithm(#'RSAPrivateKey'{}, Opts) ->
end,
{Type, 'NULL'};
sign_algorithm(#'DSAPrivateKey'{p=P, q=Q, g=G}, _Opts) ->
- {?'id-dsa-with-sha1', {params,#'Dss-Parms'{p=P, q=Q, g=G}}}.
+ {?'id-dsa-with-sha1', {params,#'Dss-Parms'{p=P, q=Q, g=G}}};
+sign_algorithm(#'ECPrivateKey'{}, Opts) ->
+ Type = case proplists:get_value(digest, Opts, sha1) of
+ sha1 -> ?'ecdsa-with-SHA1';
+ sha512 -> ?'ecdsa-with-SHA512';
+ sha384 -> ?'ecdsa-with-SHA384';
+ sha256 -> ?'ecdsa-with-SHA256'
+ end,
+ {Type, 'NULL'}.
make_key(rsa, _Opts) ->
%% (OBS: for testing only)
gen_rsa2(64);
make_key(dsa, _Opts) ->
- gen_dsa2(128, 20). %% Bytes i.e. {1024, 160}
+ gen_dsa2(128, 20); %% Bytes i.e. {1024, 160}
+make_key(ec, _Opts) ->
+ %% (OBS: for testing only)
+ gen_ec2(secp256k1).
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%% RSA key generation (OBS: for testing only)
@@ -349,13 +386,13 @@ gen_dsa2(LSize, NSize) ->
X0 = prime(LSize),
P0 = prime((LSize div 2) +1),
- %% Choose L-bit prime modulus P such that p–1 is a multiple of q.
+ %% Choose L-bit prime modulus P such that p-1 is a multiple of q.
case dsa_search(X0 div (2*Q*P0), P0, Q, 1000) of
error ->
gen_dsa2(LSize, NSize);
P ->
G = crypto:mod_exp(2, (P-1) div Q, P), % Choose G a number whose multiplicative order modulo p is q.
- %% such that This may be done by setting g = h^(p–1)/q mod p, commonly h=2 is used.
+ %% such that This may be done by setting g = h^(p-1)/q mod p, commonly h=2 is used.
X = prime(20), %% Choose x by some random method, where 0 < x < q.
Y = crypto:mod_exp(G, X, P), %% Calculate y = g^x mod p.
@@ -363,6 +400,22 @@ gen_dsa2(LSize, NSize) ->
#'DSAPrivateKey'{version=0, p=P, q=Q, g=G, y=Y, x=X}
end.
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%% EC key generation (OBS: for testing only)
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+int2list(I) ->
+ L = (length(integer_to_list(I, 16)) + 1) div 2,
+ binary_to_list(<<I:(L*8)>>).
+
+gen_ec2(CurveId) ->
+ {PrivKey, PubKey} = crypto:generate_key(ecdh, CurveId),
+
+ #'ECPrivateKey'{version = 1,
+ privateKey = int2list(PrivKey),
+ parameters = {namedCurve, pubkey_cert_records:namedCurves(CurveId)},
+ publicKey = {0, PubKey}}.
+
%% See fips_186-3.pdf
dsa_search(T, P0, Q, Iter) when Iter > 0 ->
P = 2*T*Q*P0 + 1,
diff --git a/lib/ssl/test/ssl_basic_SUITE.erl b/lib/ssl/test/ssl_basic_SUITE.erl
index 5cedde5d27..165a8a5fcc 100644
--- a/lib/ssl/test/ssl_basic_SUITE.erl
+++ b/lib/ssl/test/ssl_basic_SUITE.erl
@@ -69,6 +69,7 @@ groups() ->
{session, [], session_tests()},
{renegotiate, [], renegotiate_tests()},
{ciphers, [], cipher_tests()},
+ {ciphers_ec, [], cipher_tests_ec()},
{error_handling_tests, [], error_handling_tests()}
].
@@ -76,6 +77,7 @@ all_versions_groups ()->
[{group, api},
{group, renegotiate},
{group, ciphers},
+ {group, ciphers_ec},
{group, error_handling_tests}].
@@ -156,10 +158,19 @@ cipher_tests() ->
anonymous_cipher_suites,
psk_cipher_suites,
psk_with_hint_cipher_suites,
+ psk_anon_cipher_suites,
+ psk_anon_with_hint_cipher_suites,
srp_cipher_suites,
+ srp_anon_cipher_suites,
srp_dsa_cipher_suites,
default_reject_anonymous].
+cipher_tests_ec() ->
+ [ciphers_ecdsa_signed_certs,
+ ciphers_ecdsa_signed_certs_openssl_names,
+ ciphers_ecdh_rsa_signed_certs,
+ ciphers_ecdh_rsa_signed_certs_openssl_names].
+
error_handling_tests()->
[controller_dies,
client_closes_socket,
@@ -185,10 +196,12 @@ init_per_suite(Config0) ->
Result =
(catch make_certs:all(?config(data_dir, Config0),
?config(priv_dir, Config0))),
- ct:print("Make certs ~p~n", [Result]),
+ ct:log("Make certs ~p~n", [Result]),
Config1 = ssl_test_lib:make_dsa_cert(Config0),
- Config = ssl_test_lib:cert_options(Config1),
+ Config2 = ssl_test_lib:make_ecdsa_cert(Config1),
+ Config3 = ssl_test_lib:make_ecdh_rsa_cert(Config2),
+ Config = ssl_test_lib:cert_options(Config3),
[{watchdog, Dog} | Config]
catch _:_ ->
{skip, "Crypto did not start"}
@@ -253,7 +266,7 @@ init_per_testcase(empty_protocol_versions, Config) ->
%% ssl_test_lib:make_mix_cert(Config0);
init_per_testcase(_TestCase, Config0) ->
- ct:print("TLS/SSL version ~p~n ", [ssl_record:supported_protocol_versions()]),
+ ct:log("TLS/SSL version ~p~n ", [ssl_record:supported_protocol_versions()]),
Config = lists:keydelete(watchdog, 1, Config0),
Dog = ct:timetrap(?TIMEOUT),
[{watchdog, Dog} | Config].
@@ -316,7 +329,7 @@ connection_info(Config) when is_list(Config) ->
[{ciphers,[{rsa,rc4_128,sha,no_export}]} |
ClientOpts]}]),
- ct:print("Testcase ~p, Client ~p Server ~p ~n",
+ ct:log("Testcase ~p, Client ~p Server ~p ~n",
[self(), Client, Server]),
Version =
@@ -369,7 +382,7 @@ controlling_process(Config) when is_list(Config) ->
ClientMsg]}},
{options, ClientOpts}]),
- ct:print("Testcase ~p, Client ~p Server ~p ~n",
+ ct:log("Testcase ~p, Client ~p Server ~p ~n",
[self(), Client, Server]),
receive
@@ -419,7 +432,7 @@ controller_dies(Config) when is_list(Config) ->
ClientMsg]}},
{options, ClientOpts}]),
- ct:print("Testcase ~p, Client ~p Server ~p ~n", [self(), Client, Server]),
+ ct:log("Testcase ~p, Client ~p Server ~p ~n", [self(), Client, Server]),
ct:sleep(?SLEEP), %% so that they are connected
process_flag(trap_exit, true),
@@ -457,12 +470,12 @@ controller_dies(Config) when is_list(Config) ->
Client3 ! die_nice
end,
- ct:print("Wating on exit ~p~n",[Client3]),
+ ct:log("Wating on exit ~p~n",[Client3]),
receive {'EXIT', Client3, normal} -> ok end,
receive %% Client3 is dead but that doesn't matter, socket should not be closed.
Unexpected ->
- ct:print("Unexpected ~p~n",[Unexpected]),
+ ct:log("Unexpected ~p~n",[Unexpected]),
ct:fail({line, ?LINE-1})
after 1000 ->
ok
@@ -593,7 +606,7 @@ peername(Config) when is_list(Config) ->
ServerMsg = {ok, {ClientIp, ClientPort}},
ClientMsg = {ok, {ServerIp, Port}},
- ct:print("Testcase ~p, Client ~p Server ~p ~n",
+ ct:log("Testcase ~p, Client ~p Server ~p ~n",
[self(), Client, Server]),
ssl_test_lib:check_result(Server, ServerMsg, Client, ClientMsg),
@@ -626,7 +639,7 @@ peercert(Config) when is_list(Config) ->
ServerMsg = {error, no_peercert},
ClientMsg = {ok, BinCert},
- ct:print("Testcase ~p, Client ~p Server ~p ~n",
+ ct:log("Testcase ~p, Client ~p Server ~p ~n",
[self(), Client, Server]),
ssl_test_lib:check_result(Server, ServerMsg, Client, ClientMsg),
@@ -664,7 +677,7 @@ peercert_with_client_cert(Config) when is_list(Config) ->
ServerMsg = {ok, ClientBinCert},
ClientMsg = {ok, ServerBinCert},
- ct:print("Testcase ~p, Client ~p Server ~p ~n",
+ ct:log("Testcase ~p, Client ~p Server ~p ~n",
[self(), Client, Server]),
ssl_test_lib:check_result(Server, ServerMsg, Client, ClientMsg),
@@ -696,7 +709,7 @@ sockname(Config) when is_list(Config) ->
ServerMsg = {ok, {ServerIp, Port}},
ClientMsg = {ok, {ClientIp, ClientPort}},
- ct:print("Testcase ~p, Client ~p Server ~p ~n",
+ ct:log("Testcase ~p, Client ~p Server ~p ~n",
[self(), Client, Server]),
ssl_test_lib:check_result(Server, ServerMsg, Client, ClientMsg),
@@ -769,7 +782,7 @@ socket_options_result(Socket, Options, DefaultValues, NewOptions, NewValues) ->
ssl:setopts(Socket, [{nodelay, true}]),
{ok,[{nodelay, true}]} = ssl:getopts(Socket, [nodelay]),
{ok, All} = ssl:getopts(Socket, []),
- ct:print("All opts ~p~n", [All]),
+ ct:log("All opts ~p~n", [All]),
ok.
@@ -792,7 +805,7 @@ invalid_inet_get_option(Config) when is_list(Config) ->
{mfa, {ssl_test_lib, no_result, []}},
{options, ClientOpts}]),
- ct:print("Testcase ~p, Client ~p Server ~p ~n",
+ ct:log("Testcase ~p, Client ~p Server ~p ~n",
[self(), Client, Server]),
ssl_test_lib:check_result(Server, ok),
@@ -818,7 +831,7 @@ invalid_inet_get_option_not_list(Config) when is_list(Config) ->
{mfa, {ssl_test_lib, no_result, []}},
{options, ClientOpts}]),
- ct:print("Testcase ~p, Client ~p Server ~p ~n",
+ ct:log("Testcase ~p, Client ~p Server ~p ~n",
[self(), Client, Server]),
ssl_test_lib:check_result(Server, ok),
@@ -850,7 +863,7 @@ invalid_inet_get_option_improper_list(Config) when is_list(Config) ->
{mfa, {ssl_test_lib, no_result, []}},
{options, ClientOpts}]),
- ct:print("Testcase ~p, Client ~p Server ~p ~n",
+ ct:log("Testcase ~p, Client ~p Server ~p ~n",
[self(), Client, Server]),
ssl_test_lib:check_result(Server, ok),
@@ -881,7 +894,7 @@ invalid_inet_set_option(Config) when is_list(Config) ->
{mfa, {ssl_test_lib, no_result, []}},
{options, ClientOpts}]),
- ct:print("Testcase ~p, Client ~p Server ~p ~n",
+ ct:log("Testcase ~p, Client ~p Server ~p ~n",
[self(), Client, Server]),
ssl_test_lib:check_result(Server, ok),
@@ -913,7 +926,7 @@ invalid_inet_set_option_not_list(Config) when is_list(Config) ->
{mfa, {ssl_test_lib, no_result, []}},
{options, ClientOpts}]),
- ct:print("Testcase ~p, Client ~p Server ~p ~n",
+ ct:log("Testcase ~p, Client ~p Server ~p ~n",
[self(), Client, Server]),
ssl_test_lib:check_result(Server, ok),
@@ -945,7 +958,7 @@ invalid_inet_set_option_improper_list(Config) when is_list(Config) ->
{mfa, {ssl_test_lib, no_result, []}},
{options, ClientOpts}]),
- ct:print("Testcase ~p, Client ~p Server ~p ~n",
+ ct:log("Testcase ~p, Client ~p Server ~p ~n",
[self(), Client, Server]),
ssl_test_lib:check_result(Server, ok),
@@ -986,7 +999,7 @@ misc_ssl_options(Config) when is_list(Config) ->
{mfa, {ssl_test_lib, send_recv_result_active, []}},
{options, TestOpts ++ ClientOpts}]),
- ct:print("Testcase ~p, Client ~p Server ~p ~n",
+ ct:log("Testcase ~p, Client ~p Server ~p ~n",
[self(), Client, Server]),
ssl_test_lib:check_result(Server, ok, Client, ok),
@@ -999,7 +1012,7 @@ versions() ->
versions(Config) when is_list(Config) ->
[_|_] = Versions = ssl:versions(),
- ct:print("~p~n", [Versions]).
+ ct:log("~p~n", [Versions]).
%%--------------------------------------------------------------------
send_recv() ->
@@ -1021,7 +1034,7 @@ send_recv(Config) when is_list(Config) ->
{mfa, {ssl_test_lib, send_recv_result, []}},
{options, [{active, false} | ClientOpts]}]),
- ct:print("Testcase ~p, Client ~p Server ~p ~n",
+ ct:log("Testcase ~p, Client ~p Server ~p ~n",
[self(), Client, Server]),
ssl_test_lib:check_result(Server, ok, Client, ok),
@@ -1047,7 +1060,7 @@ send_close(Config) when is_list(Config) ->
{ok, SslS} = rpc:call(ClientNode, ssl, connect,
[TcpS,[{active, false}|ClientOpts]]),
- ct:print("Testcase ~p, Client ~p Server ~p ~n",
+ ct:log("Testcase ~p, Client ~p Server ~p ~n",
[self(), self(), Server]),
ok = ssl:send(SslS, "Hello world"),
{ok,<<"Hello world">>} = ssl:recv(SslS, 11),
@@ -1132,7 +1145,7 @@ upgrade(Config) when is_list(Config) ->
{tcp_options, TcpOpts},
{ssl_options, ClientOpts}]),
- ct:print("Testcase ~p, Client ~p Server ~p ~n",
+ ct:log("Testcase ~p, Client ~p Server ~p ~n",
[self(), Client, Server]),
ssl_test_lib:check_result(Server, ok, Client, ok),
@@ -1182,7 +1195,7 @@ upgrade_with_timeout(Config) when is_list(Config) ->
{tcp_options, TcpOpts},
{ssl_options, ClientOpts}]),
- ct:print("Testcase ~p, Client ~p Server ~p ~n",
+ ct:log("Testcase ~p, Client ~p Server ~p ~n",
[self(), Client, Server]),
ssl_test_lib:check_result(Server, ok, Client, ok),
@@ -1208,14 +1221,14 @@ tcp_connect(Config) when is_list(Config) ->
Port = ssl_test_lib:inet_port(Server),
{ok, Socket} = gen_tcp:connect(Hostname, Port, [binary, {packet, 0}]),
- ct:print("Testcase ~p connected to Server ~p ~n", [self(), Server]),
+ ct:log("Testcase ~p connected to Server ~p ~n", [self(), Server]),
gen_tcp:send(Socket, "<SOME GARBLED NON SSL MESSAGE>"),
receive
{tcp_closed, Socket} ->
receive
{Server, {error, Error}} ->
- ct:print("Error ~p", [Error])
+ ct:log("Error ~p", [Error])
end
end.
%%--------------------------------------------------------------------
@@ -1236,7 +1249,7 @@ tcp_connect_big(Config) when is_list(Config) ->
Port = ssl_test_lib:inet_port(Server),
{ok, Socket} = gen_tcp:connect(Hostname, Port, [binary, {packet, 0}]),
- ct:print("Testcase ~p connected to Server ~p ~n", [self(), Server]),
+ ct:log("Testcase ~p connected to Server ~p ~n", [self(), Server]),
Rand = crypto:rand_bytes(?MAX_CIPHER_TEXT_LENGTH+1),
gen_tcp:send(Socket, <<?BYTE(0),
@@ -1248,7 +1261,7 @@ tcp_connect_big(Config) when is_list(Config) ->
{Server, {error, timeout}} ->
ct:fail("hangs");
{Server, {error, Error}} ->
- ct:print("Error ~p", [Error])
+ ct:log("Error ~p", [Error])
end
end.
@@ -1278,7 +1291,7 @@ ipv6(Config) when is_list(Config) ->
{options,
[inet6, {active, false} | ClientOpts]}]),
- ct:print("Testcase ~p, Client ~p Server ~p ~n",
+ ct:log("Testcase ~p, Client ~p Server ~p ~n",
[self(), Client, Server]),
ssl_test_lib:check_result(Server, ok, Client, ok),
@@ -1536,8 +1549,8 @@ ciphers_rsa_signed_certs(Config) when is_list(Config) ->
Version =
ssl_record:protocol_version(ssl_record:highest_protocol_version([])),
- Ciphers = ssl_test_lib:rsa_suites(),
- ct:print("~p erlang cipher suites ~p~n", [Version, Ciphers]),
+ Ciphers = ssl_test_lib:rsa_suites(erlang),
+ ct:log("~p erlang cipher suites ~p~n", [Version, Ciphers]),
run_suites(Ciphers, Version, Config, rsa).
%%-------------------------------------------------------------------
ciphers_rsa_signed_certs_openssl_names() ->
@@ -1547,7 +1560,7 @@ ciphers_rsa_signed_certs_openssl_names(Config) when is_list(Config) ->
Version =
ssl_record:protocol_version(ssl_record:highest_protocol_version([])),
Ciphers = ssl_test_lib:openssl_rsa_suites(),
- ct:print("tls1 openssl cipher suites ~p~n", [Ciphers]),
+ ct:log("tls1 openssl cipher suites ~p~n", [Ciphers]),
run_suites(Ciphers, Version, Config, rsa).
%%-------------------------------------------------------------------
@@ -1559,7 +1572,7 @@ ciphers_dsa_signed_certs(Config) when is_list(Config) ->
ssl_record:protocol_version(ssl_record:highest_protocol_version([])),
Ciphers = ssl_test_lib:dsa_suites(),
- ct:print("~p erlang cipher suites ~p~n", [Version, Ciphers]),
+ ct:log("~p erlang cipher suites ~p~n", [Version, Ciphers]),
run_suites(Ciphers, Version, Config, dsa).
%%-------------------------------------------------------------------
ciphers_dsa_signed_certs_openssl_names() ->
@@ -1570,7 +1583,7 @@ ciphers_dsa_signed_certs_openssl_names(Config) when is_list(Config) ->
ssl_record:protocol_version(ssl_record:highest_protocol_version([])),
Ciphers = ssl_test_lib:openssl_dsa_suites(),
- ct:print("tls1 openssl cipher suites ~p~n", [Ciphers]),
+ ct:log("tls1 openssl cipher suites ~p~n", [Ciphers]),
run_suites(Ciphers, Version, Config, dsa).
%%-------------------------------------------------------------------
anonymous_cipher_suites()->
@@ -1594,6 +1607,20 @@ psk_with_hint_cipher_suites(Config) when is_list(Config) ->
Ciphers = ssl_test_lib:psk_suites(),
run_suites(Ciphers, Version, Config, psk_with_hint).
%%-------------------------------------------------------------------
+psk_anon_cipher_suites() ->
+ [{doc, "Test the anonymous PSK ciphersuites WITHOUT server supplied identity hint"}].
+psk_anon_cipher_suites(Config) when is_list(Config) ->
+ Version = ssl_record:protocol_version(ssl_record:highest_protocol_version([])),
+ Ciphers = ssl_test_lib:psk_anon_suites(),
+ run_suites(Ciphers, Version, Config, psk_anon).
+%%-------------------------------------------------------------------
+psk_anon_with_hint_cipher_suites()->
+ [{doc, "Test the anonymous PSK ciphersuites WITH server supplied identity hint"}].
+psk_anon_with_hint_cipher_suites(Config) when is_list(Config) ->
+ Version = ssl_record:protocol_version(ssl_record:highest_protocol_version([])),
+ Ciphers = ssl_test_lib:psk_anon_suites(),
+ run_suites(Ciphers, Version, Config, psk_anon_with_hint).
+%%-------------------------------------------------------------------
srp_cipher_suites()->
[{doc, "Test the SRP ciphersuites"}].
srp_cipher_suites(Config) when is_list(Config) ->
@@ -1601,6 +1628,13 @@ srp_cipher_suites(Config) when is_list(Config) ->
Ciphers = ssl_test_lib:srp_suites(),
run_suites(Ciphers, Version, Config, srp).
%%-------------------------------------------------------------------
+srp_anon_cipher_suites()->
+ [{doc, "Test the anonymous SRP ciphersuites"}].
+srp_anon_cipher_suites(Config) when is_list(Config) ->
+ Version = ssl_record:protocol_version(ssl_record:highest_protocol_version([])),
+ Ciphers = ssl_test_lib:srp_anon_suites(),
+ run_suites(Ciphers, Version, Config, srp_anon).
+%%-------------------------------------------------------------------
srp_dsa_cipher_suites()->
[{doc, "Test the SRP DSA ciphersuites"}].
srp_dsa_cipher_suites(Config) when is_list(Config) ->
@@ -1632,6 +1666,48 @@ default_reject_anonymous(Config) when is_list(Config) ->
Client, {error, {tls_alert, "insufficient security"}}).
%%--------------------------------------------------------------------
+ciphers_ecdsa_signed_certs() ->
+ [{doc, "Test all ecdsa ssl cipher suites in highest support ssl/tls version"}].
+
+ciphers_ecdsa_signed_certs(Config) when is_list(Config) ->
+ Version =
+ ssl_record:protocol_version(ssl_record:highest_protocol_version([])),
+
+ Ciphers = ssl_test_lib:ecdsa_suites(),
+ ct:log("~p erlang cipher suites ~p~n", [Version, Ciphers]),
+ run_suites(Ciphers, Version, Config, ecdsa).
+%%--------------------------------------------------------------------
+ciphers_ecdsa_signed_certs_openssl_names() ->
+ [{doc, "Test all ecdsa ssl cipher suites in highest support ssl/tls version"}].
+
+ciphers_ecdsa_signed_certs_openssl_names(Config) when is_list(Config) ->
+ Version =
+ ssl_record:protocol_version(ssl_record:highest_protocol_version([])),
+ Ciphers = ssl_test_lib:openssl_ecdsa_suites(),
+ ct:log("tls1 openssl cipher suites ~p~n", [Ciphers]),
+ run_suites(Ciphers, Version, Config, ecdsa).
+%%--------------------------------------------------------------------
+ciphers_ecdh_rsa_signed_certs() ->
+ [{doc, "Test all ecdh_rsa ssl cipher suites in highest support ssl/tls version"}].
+
+ciphers_ecdh_rsa_signed_certs(Config) when is_list(Config) ->
+ Version =
+ ssl_record:protocol_version(ssl_record:highest_protocol_version([])),
+
+ Ciphers = ssl_test_lib:ecdh_rsa_suites(),
+ ct:log("~p erlang cipher suites ~p~n", [Version, Ciphers]),
+ run_suites(Ciphers, Version, Config, ecdh_rsa).
+%%--------------------------------------------------------------------
+ciphers_ecdh_rsa_signed_certs_openssl_names() ->
+ [{doc, "Test all ecdh_rsa ssl cipher suites in highest support ssl/tls version"}].
+
+ciphers_ecdh_rsa_signed_certs_openssl_names(Config) when is_list(Config) ->
+ Version =
+ ssl_record:protocol_version(ssl_record:highest_protocol_version([])),
+ Ciphers = ssl_test_lib:openssl_ecdh_rsa_suites(),
+ ct:log("tls1 openssl cipher suites ~p~n", [Ciphers]),
+ run_suites(Ciphers, Version, Config, ecdh_rsa).
+%%--------------------------------------------------------------------
reuse_session() ->
[{doc,"Test reuse of sessions (short handshake)"}].
reuse_session(Config) when is_list(Config) ->
@@ -1670,7 +1746,7 @@ reuse_session(Config) when is_list(Config) ->
{Client1, SessionInfo} ->
ok;
{Client1, Other} ->
- ct:print("Expected: ~p, Unexpected: ~p~n",
+ ct:log("Expected: ~p, Unexpected: ~p~n",
[SessionInfo, Other]),
ct:fail(session_not_reused)
end,
@@ -1728,7 +1804,7 @@ reuse_session(Config) when is_list(Config) ->
ct:fail(
session_reused_when_session_reuse_disabled_by_server);
{Client4, _Other} ->
- ct:print("OTHER: ~p ~n", [_Other]),
+ ct:log("OTHER: ~p ~n", [_Other]),
ok
end,
@@ -1778,7 +1854,7 @@ reuse_session_expired(Config) when is_list(Config) ->
{Client1, SessionInfo} ->
ok;
{Client1, Other} ->
- ct:print("Expected: ~p, Unexpected: ~p~n",
+ ct:log("Expected: ~p, Unexpected: ~p~n",
[SessionInfo, Other]),
ct:fail(session_not_reused)
end,
@@ -2481,7 +2557,7 @@ connect_twice(Config) when is_list(Config) ->
{options, [{keepalive, true},{active, false}
| ClientOpts]}]),
- ct:print("Testcase ~p, Client ~p Server ~p ~n",
+ ct:log("Testcase ~p, Client ~p Server ~p ~n",
[self(), Client, Server]),
ssl_test_lib:check_result(Server, ok, Client, ok),
@@ -2827,9 +2903,9 @@ result_ok(_Socket) ->
ok.
renegotiate(Socket, Data) ->
- ct:print("Renegotiating ~n", []),
+ ct:log("Renegotiating ~n", []),
Result = ssl:renegotiate(Socket),
- ct:print("Result ~p~n", [Result]),
+ ct:log("Result ~p~n", [Result]),
ssl:send(Socket, Data),
case Result of
ok ->
@@ -2858,7 +2934,7 @@ renegotiate_immediately(Socket) ->
{error, renegotiation_rejected} = ssl:renegotiate(Socket),
ct:sleep(?RENEGOTIATION_DISABLE_TIME +1),
ok = ssl:renegotiate(Socket),
- ct:print("Renegotiated again"),
+ ct:log("Renegotiated again"),
ssl:send(Socket, "Hello world"),
ok.
@@ -2877,7 +2953,7 @@ new_config(PrivDir, ServerOpts0) ->
ServerOpts = proplists:delete(keyfile, ServerOpts2),
{ok, PEM} = file:read_file(NewCaCertFile),
- ct:print("CA file content: ~p~n", [public_key:pem_decode(PEM)]),
+ ct:log("CA file content: ~p~n", [public_key:pem_decode(PEM)]),
[{cacertfile, NewCaCertFile}, {certfile, NewCertFile},
{keyfile, NewKeyFile} | ServerOpts].
@@ -3073,15 +3149,15 @@ get_close(Pid, Where) ->
{'EXIT', Pid, _Reason} ->
receive
{_, {ssl_closed, Socket}} ->
- ct:print("Socket closed ~p~n",[Socket]);
+ ct:log("Socket closed ~p~n",[Socket]);
Unexpected ->
- ct:print("Unexpected ~p~n",[Unexpected]),
+ ct:log("Unexpected ~p~n",[Unexpected]),
ct:fail({line, ?LINE-1})
after 5000 ->
ct:fail({timeout, {line, ?LINE, Where}})
end;
Unexpected ->
- ct:print("Unexpected ~p~n",[Unexpected]),
+ ct:log("Unexpected ~p~n",[Unexpected]),
ct:fail({line, ?LINE-1})
after 5000 ->
ct:fail({timeout, {line, ?LINE, Where}})
@@ -3095,7 +3171,7 @@ run_send_recv_rizzo(Ciphers, Config, Version, Mfa) ->
[] ->
ok;
Error ->
- ct:print("Cipher suite errors: ~p~n", [Error]),
+ ct:log("Cipher suite errors: ~p~n", [Error]),
ct:fail(cipher_suite_failed_see_test_case_log)
end.
@@ -3125,12 +3201,21 @@ rizzo_test(Cipher, Config, Version, Mfa) ->
[{Cipher, Error}]
end.
-client_server_opts({KeyAlgo,_,_}, Config) when KeyAlgo == rsa orelse KeyAlgo == dhe_rsa ->
+client_server_opts({KeyAlgo,_,_}, Config)
+ when KeyAlgo == rsa orelse
+ KeyAlgo == dhe_rsa orelse
+ KeyAlgo == ecdhe_rsa ->
{?config(client_opts, Config),
?config(server_opts, Config)};
client_server_opts({KeyAlgo,_,_}, Config) when KeyAlgo == dss orelse KeyAlgo == dhe_dss ->
{?config(client_dsa_opts, Config),
- ?config(server_dsa_opts, Config)}.
+ ?config(server_dsa_opts, Config)};
+client_server_opts({KeyAlgo,_,_}, Config) when KeyAlgo == ecdh_ecdsa orelse KeyAlgo == ecdhe_ecdsa ->
+ {?config(client_opts, Config),
+ ?config(server_ecdsa_opts, Config)};
+client_server_opts({KeyAlgo,_,_}, Config) when KeyAlgo == ecdh_rsa ->
+ {?config(client_opts, Config),
+ ?config(server_ecdh_rsa_opts, Config)}.
run_suites(Ciphers, Version, Config, Type) ->
{ClientOpts, ServerOpts} =
@@ -3151,12 +3236,27 @@ run_suites(Ciphers, Version, Config, Type) ->
psk_with_hint ->
{?config(client_psk, Config),
?config(server_psk_hint, Config)};
+ psk_anon ->
+ {?config(client_psk, Config),
+ ?config(server_psk_anon, Config)};
+ psk_anon_with_hint ->
+ {?config(client_psk, Config),
+ ?config(server_psk_anon_hint, Config)};
srp ->
{?config(client_srp, Config),
?config(server_srp, Config)};
+ srp_anon ->
+ {?config(client_srp, Config),
+ ?config(server_srp_anon, Config)};
srp_dsa ->
{?config(client_srp_dsa, Config),
- ?config(server_srp_dsa, Config)}
+ ?config(server_srp_dsa, Config)};
+ ecdsa ->
+ {?config(client_opts, Config),
+ ?config(server_ecdsa_opts, Config)};
+ ecdh_rsa ->
+ {?config(client_opts, Config),
+ ?config(server_ecdh_rsa_opts, Config)}
end,
Result = lists:map(fun(Cipher) ->
@@ -3166,7 +3266,7 @@ run_suites(Ciphers, Version, Config, Type) ->
[] ->
ok;
Error ->
- ct:print("Cipher suite errors: ~p~n", [Error]),
+ ct:log("Cipher suite errors: ~p~n", [Error]),
ct:fail(cipher_suite_failed_see_test_case_log)
end.
@@ -3177,7 +3277,7 @@ erlang_cipher_suite(Suite) ->
cipher(CipherSuite, Version, Config, ClientOpts, ServerOpts) ->
%% process_flag(trap_exit, true),
- ct:print("Testing CipherSuite ~p~n", [CipherSuite]),
+ ct:log("Testing CipherSuite ~p~n", [CipherSuite]),
{ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
ErlangCipherSuite = erlang_cipher_suite(CipherSuite),
diff --git a/lib/ssl/test/ssl_certificate_verify_SUITE.erl b/lib/ssl/test/ssl_certificate_verify_SUITE.erl
index 26938bda50..2703d2d79c 100644
--- a/lib/ssl/test/ssl_certificate_verify_SUITE.erl
+++ b/lib/ssl/test/ssl_certificate_verify_SUITE.erl
@@ -86,7 +86,7 @@ init_per_suite(Config0) ->
Result =
(catch make_certs:all(?config(data_dir, Config0),
?config(priv_dir, Config0))),
- ct:print("Make certs ~p~n", [Result]),
+ ct:log("Make certs ~p~n", [Result]),
Config1 = ssl_test_lib:make_dsa_cert(Config0),
Config = ssl_test_lib:cert_options(Config1),
@@ -297,7 +297,7 @@ verify_fun_always_run_client(Config) when is_list(Config) ->
%% this is not a bug it is a circumstance of how tcp works!
receive
{Server, ServerError} ->
- ct:print("Server Error ~p~n", [ServerError])
+ ct:log("Server Error ~p~n", [ServerError])
end,
ssl_test_lib:check_result(Client, {error, {tls_alert, "handshake failure"}}).
@@ -346,7 +346,7 @@ verify_fun_always_run_server(Config) when is_list(Config) ->
%% this is not a bug it is a circumstance of how tcp works!
receive
{Client, ClientError} ->
- ct:print("Client Error ~p~n", [ClientError])
+ ct:log("Client Error ~p~n", [ClientError])
end,
ssl_test_lib:check_result(Server, {error, {tls_alert, "handshake failure"}}).
@@ -413,7 +413,7 @@ cert_expired(Config) when is_list(Config) ->
two_digits_str(Sec)])),
NewValidity = {'Validity', {generalTime, NotBeforeStr}, {generalTime, NotAfterStr}},
- ct:print("Validity: ~p ~n NewValidity: ~p ~n",
+ ct:log("Validity: ~p ~n NewValidity: ~p ~n",
[OTPTbsCert#'OTPTBSCertificate'.validity, NewValidity]),
NewOTPTbsCert = OTPTbsCert#'OTPTBSCertificate'{validity = NewValidity},
@@ -644,7 +644,7 @@ no_authority_key_identifier(Config) when is_list(Config) ->
NewExtensions = delete_authority_key_extension(Extensions, []),
NewOTPTbsCert = OTPTbsCert#'OTPTBSCertificate'{extensions = NewExtensions},
- ct:print("Extensions ~p~n, NewExtensions: ~p~n", [Extensions, NewExtensions]),
+ ct:log("Extensions ~p~n, NewExtensions: ~p~n", [Extensions, NewExtensions]),
NewDerCert = public_key:pkix_sign(NewOTPTbsCert, Key),
ssl_test_lib:der_to_pem(NewCertFile, [{'Certificate', NewDerCert, not_encrypted}]),
@@ -955,10 +955,10 @@ client_msg(Client, ClientMsg) ->
{Client, ClientMsg} ->
ok;
{Client, {error,closed}} ->
- ct:print("client got close"),
+ ct:log("client got close"),
ok;
{Client, {error, Reason}} ->
- ct:print("client got econnaborted: ~p", [Reason]),
+ ct:log("client got econnaborted: ~p", [Reason]),
ok;
Unexpected ->
ct:fail(Unexpected)
@@ -968,10 +968,10 @@ server_msg(Server, ServerMsg) ->
{Server, ServerMsg} ->
ok;
{Server, {error,closed}} ->
- ct:print("server got close"),
+ ct:log("server got close"),
ok;
{Server, {error, Reason}} ->
- ct:print("server got econnaborted: ~p", [Reason]),
+ ct:log("server got econnaborted: ~p", [Reason]),
ok;
Unexpected ->
ct:fail(Unexpected)
diff --git a/lib/ssl/test/ssl_npn_handshake_SUITE.erl b/lib/ssl/test/ssl_npn_handshake_SUITE.erl
index 8c1b22cf5e..7b271c4d5d 100644
--- a/lib/ssl/test/ssl_npn_handshake_SUITE.erl
+++ b/lib/ssl/test/ssl_npn_handshake_SUITE.erl
@@ -74,7 +74,7 @@ init_per_suite(Config) ->
Result =
(catch make_certs:all(?config(data_dir, Config),
?config(priv_dir, Config))),
- ct:print("Make certs ~p~n", [Result]),
+ ct:log("Make certs ~p~n", [Result]),
ssl_test_lib:cert_options(Config)
catch _:_ ->
{skip, "Crypto did not start"}
@@ -311,13 +311,13 @@ run_npn_handshake(Config, ClientExtraOpts, ServerExtraOpts, ExpectedProtocol) ->
assert_npn(Socket, Protocol) ->
- ct:print("Negotiated Protocol ~p, Expecting: ~p ~n",
+ ct:log("Negotiated Protocol ~p, Expecting: ~p ~n",
[ssl:negotiated_next_protocol(Socket), Protocol]),
Protocol = ssl:negotiated_next_protocol(Socket).
assert_npn_and_renegotiate_and_send_data(Socket, Protocol, Data) ->
assert_npn(Socket, Protocol),
- ct:print("Renegotiating ~n", []),
+ ct:log("Renegotiating ~n", []),
ok = ssl:renegotiate(Socket),
ssl:send(Socket, Data),
assert_npn(Socket, Protocol),
@@ -332,7 +332,7 @@ ssl_receive_and_assert_npn(Socket, Protocol, Data) ->
ssl_receive(Socket, Data).
ssl_send(Socket, Data) ->
- ct:print("Connection info: ~p~n",
+ ct:log("Connection info: ~p~n",
[ssl:connection_info(Socket)]),
ssl:send(Socket, Data).
@@ -340,11 +340,11 @@ ssl_receive(Socket, Data) ->
ssl_receive(Socket, Data, []).
ssl_receive(Socket, Data, Buffer) ->
- ct:print("Connection info: ~p~n",
+ ct:log("Connection info: ~p~n",
[ssl:connection_info(Socket)]),
receive
{ssl, Socket, MoreData} ->
- ct:print("Received ~p~n",[MoreData]),
+ ct:log("Received ~p~n",[MoreData]),
NewBuffer = Buffer ++ MoreData,
case NewBuffer of
Data ->
diff --git a/lib/ssl/test/ssl_npn_hello_SUITE.erl b/lib/ssl/test/ssl_npn_hello_SUITE.erl
index 72768bcb55..43fa72ea28 100644
--- a/lib/ssl/test/ssl_npn_hello_SUITE.erl
+++ b/lib/ssl/test/ssl_npn_hello_SUITE.erl
@@ -25,6 +25,8 @@
-compile(export_all).
-include("ssl_handshake.hrl").
-include("ssl_record.hrl").
+-include("ssl_cipher.hrl").
+-include("ssl_internal.hrl").
-include_lib("common_test/include/ct.hrl").
%%--------------------------------------------------------------------
@@ -75,17 +77,19 @@ encode_and_decode_npn_server_hello_test(_Config) ->
{[{DecodedHandshakeMessage, _Raw}], _} =
ssl_handshake:get_tls_handshake(Version, list_to_binary(HandShakeData), <<>>),
NextProtocolNegotiation = DecodedHandshakeMessage#server_hello.next_protocol_negotiation,
- ct:print("~p ~n", [NextProtocolNegotiation]),
+ ct:log("~p ~n", [NextProtocolNegotiation]),
NextProtocolNegotiation = #next_protocol_negotiation{extension_data = <<6, "spdy/2">>}.
%%--------------------------------------------------------------------
create_server_hello_with_no_advertised_protocols_test(_Config) ->
- Hello = ssl_handshake:server_hello(<<>>, {3, 0}, create_connection_states(), false, undefined),
+ Hello = ssl_handshake:server_hello(<<>>, {3, 0}, create_connection_states(), false,
+ undefined, undefined, undefined),
undefined = Hello#server_hello.next_protocol_negotiation.
%%--------------------------------------------------------------------
create_server_hello_with_advertised_protocols_test(_Config) ->
Hello = ssl_handshake:server_hello(<<>>, {3, 0}, create_connection_states(),
- false, [<<"spdy/1">>, <<"http/1.0">>, <<"http/1.1">>]),
+ false, [<<"spdy/1">>, <<"http/1.0">>, <<"http/1.1">>],
+ undefined, undefined),
#next_protocol_negotiation{extension_data = <<6, "spdy/1", 8, "http/1.0", 8, "http/1.1">>} =
Hello#server_hello.next_protocol_negotiation.
%%--------------------------------------------------------------------
@@ -96,7 +100,7 @@ create_client_handshake(Npn) ->
client_version = {1, 2},
random = <<1:256>>,
session_id = <<>>,
- cipher_suites = "",
+ cipher_suites = [?TLS_DHE_DSS_WITH_DES_CBC_SHA],
compression_methods = "",
next_protocol_negotiation = Npn,
renegotiation_info = #renegotiation_info{}
@@ -107,7 +111,7 @@ create_server_handshake(Npn) ->
server_version = {1, 2},
random = <<1:256>>,
session_id = <<>>,
- cipher_suite = <<1,2>>,
+ cipher_suite = ?TLS_DHE_DSS_WITH_DES_CBC_SHA,
compression_method = 1,
next_protocol_negotiation = Npn,
renegotiation_info = #renegotiation_info{}
@@ -119,7 +123,7 @@ create_connection_states() ->
security_parameters = #security_parameters{
server_random = <<1:256>>,
compression_algorithm = 1,
- cipher_suite = <<1, 2>>
+ cipher_suite = ?TLS_DHE_DSS_WITH_DES_CBC_SHA
}
},
diff --git a/lib/ssl/test/ssl_packet_SUITE.erl b/lib/ssl/test/ssl_packet_SUITE.erl
index 4116bb39d1..5a374e234d 100644
--- a/lib/ssl/test/ssl_packet_SUITE.erl
+++ b/lib/ssl/test/ssl_packet_SUITE.erl
@@ -143,7 +143,7 @@ init_per_suite(Config) ->
Result =
(catch make_certs:all(?config(data_dir, Config),
?config(priv_dir, Config))),
- ct:print("Make certs ~p~n", [Result]),
+ ct:log("Make certs ~p~n", [Result]),
ssl_test_lib:cert_options(Config)
catch _:_ ->
{skip, "Crypto did not start"}
@@ -2069,7 +2069,7 @@ client_packet_decode(Socket, [Head | Tail] = Packet) ->
client_packet_decode(Socket, [Head], Tail, Packet).
client_packet_decode(Socket, P1, P2, Packet) ->
- ct:print("Packet: ~p ~n", [Packet]),
+ ct:log("Packet: ~p ~n", [Packet]),
ok = ssl:send(Socket, P1),
ok = ssl:send(Socket, P2),
receive
diff --git a/lib/ssl/test/ssl_payload_SUITE.erl b/lib/ssl/test/ssl_payload_SUITE.erl
index 77ad546420..5f5166391f 100644
--- a/lib/ssl/test/ssl_payload_SUITE.erl
+++ b/lib/ssl/test/ssl_payload_SUITE.erl
@@ -556,33 +556,33 @@ send(Socket, Data, Size, Repeate,F) ->
sender(Socket, Data, Size) ->
ok = send(Socket, Data, Size, 100, fun() -> do_recv(Socket, Data, Size, <<>>, false) end),
- ct:print("Sender recv: ~p~n", [ssl:getopts(Socket, [active])]),
+ ct:log("Sender recv: ~p~n", [ssl:getopts(Socket, [active])]),
ok.
sender_once(Socket, Data, Size) ->
send(Socket, Data, Size, 100,
fun() -> do_active_once(Socket, Data, Size, <<>>, false) end),
- ct:print("Sender active once: ~p~n",
+ ct:log("Sender active once: ~p~n",
[ssl:getopts(Socket, [active])]),
ok.
sender_active(Socket, Data, Size) ->
F = fun() -> do_active(Socket, Data, Size, <<>>, false) end,
send(Socket, Data, Size, 100, F),
- ct:print("Sender active: ~p~n", [ssl:getopts(Socket, [active])]),
+ ct:log("Sender active: ~p~n", [ssl:getopts(Socket, [active])]),
ok.
echoer(Socket, Data, Size) ->
- ct:print("Echoer recv: ~p~n", [ssl:getopts(Socket, [active])]),
+ ct:log("Echoer recv: ~p~n", [ssl:getopts(Socket, [active])]),
echo(fun() -> do_recv(Socket, Data, Size, <<>>, true) end, 100).
echoer_once(Socket, Data, Size) ->
- ct:print("Echoer active once: ~p ~n",
+ ct:log("Echoer active once: ~p ~n",
[ssl:getopts(Socket, [active])]),
echo(fun() -> do_active_once(Socket, Data, Size, <<>>, true) end, 100).
echoer_active(Socket, Data, Size) ->
- ct:print("Echoer active: ~p~n", [ssl:getopts(Socket, [active])]),
+ ct:log("Echoer active: ~p~n", [ssl:getopts(Socket, [active])]),
echo(fun() -> do_active(Socket, Data, Size, <<>>, true) end, 100).
echo(_Fun, 0) -> ok;
diff --git a/lib/ssl/test/ssl_session_cache_SUITE.erl b/lib/ssl/test/ssl_session_cache_SUITE.erl
index fd9a0a594c..6cc6c4bdb2 100644
--- a/lib/ssl/test/ssl_session_cache_SUITE.erl
+++ b/lib/ssl/test/ssl_session_cache_SUITE.erl
@@ -63,7 +63,7 @@ init_per_suite(Config0) ->
Result =
(catch make_certs:all(?config(data_dir, Config0),
?config(priv_dir, Config0))),
- ct:print("Make certs ~p~n", [Result]),
+ ct:log("Make certs ~p~n", [Result]),
Config1 = ssl_test_lib:make_dsa_cert(Config0),
Config = ssl_test_lib:cert_options(Config1),
diff --git a/lib/ssl/test/ssl_test_lib.erl b/lib/ssl/test/ssl_test_lib.erl
index d655d7659e..a8ff5187b6 100644
--- a/lib/ssl/test/ssl_test_lib.erl
+++ b/lib/ssl/test/ssl_test_lib.erl
@@ -59,7 +59,7 @@ run_server(Opts) ->
Options = proplists:get_value(options, Opts),
Pid = proplists:get_value(from, Opts),
Transport = proplists:get_value(transport, Opts, ssl),
- ct:print("ssl:listen(~p, ~p)~n", [Port, Options]),
+ ct:log("ssl:listen(~p, ~p)~n", [Port, Options]),
{ok, ListenSocket} = rpc:call(Node, Transport, listen, [Port, Options]),
Pid ! {listen, up},
send_selected_port(Pid, Port, ListenSocket),
@@ -77,13 +77,13 @@ do_run_server(ListenSocket, AcceptSocket, Opts) ->
Pid = proplists:get_value(from, Opts),
Transport = proplists:get_value(transport, Opts, ssl),
{Module, Function, Args} = proplists:get_value(mfa, Opts),
- ct:print("Server: apply(~p,~p,~p)~n",
+ ct:log("Server: apply(~p,~p,~p)~n",
[Module, Function, [AcceptSocket | Args]]),
case rpc:call(Node, Module, Function, [AcceptSocket | Args]) of
no_result_msg ->
ok;
Msg ->
- ct:print("Server Msg: ~p ~n", [Msg]),
+ ct:log("Server Msg: ~p ~n", [Msg]),
Pid ! {self(), Msg}
end,
receive
@@ -92,10 +92,10 @@ do_run_server(ListenSocket, AcceptSocket, Opts) ->
{listen, MFA} ->
run_server(ListenSocket, [MFA | proplists:delete(mfa, Opts)]);
close ->
- ct:print("Server closing ~p ~n", [self()]),
+ ct:log("Server closing ~p ~n", [self()]),
Result = rpc:call(Node, Transport, close, [AcceptSocket], 500),
Result1 = rpc:call(Node, Transport, close, [ListenSocket], 500),
- ct:print("Result ~p : ~p ~n", [Result, Result1]);
+ ct:log("Result ~p : ~p ~n", [Result, Result1]);
{ssl_closed, _} ->
ok
end.
@@ -115,7 +115,7 @@ connect(#sslsocket{} = ListenSocket, Opts) ->
end;
connect(ListenSocket, Opts) ->
Node = proplists:get_value(node, Opts),
- ct:print("gen_tcp:accept(~p)~n", [ListenSocket]),
+ ct:log("gen_tcp:accept(~p)~n", [ListenSocket]),
{ok, AcceptSocket} = rpc:call(Node, gen_tcp, accept,
[ListenSocket]),
AcceptSocket.
@@ -123,10 +123,10 @@ connect(ListenSocket, Opts) ->
connect(_, _, 0, AcceptSocket, _) ->
AcceptSocket;
connect(ListenSocket, Node, N, _, Timeout) ->
- ct:print("ssl:transport_accept(~p)~n", [ListenSocket]),
+ ct:log("ssl:transport_accept(~p)~n", [ListenSocket]),
{ok, AcceptSocket} = rpc:call(Node, ssl, transport_accept,
[ListenSocket]),
- ct:print("ssl:ssl_accept(~p, ~p)~n", [AcceptSocket, Timeout]),
+ ct:log("ssl:ssl_accept(~p, ~p)~n", [AcceptSocket, Timeout]),
case rpc:call(Node, ssl, ssl_accept, [AcceptSocket, Timeout]) of
ok ->
@@ -161,27 +161,27 @@ run_client(Opts) ->
Pid = proplists:get_value(from, Opts),
Transport = proplists:get_value(transport, Opts, ssl),
Options = proplists:get_value(options, Opts),
- ct:print("ssl:connect(~p, ~p, ~p)~n", [Host, Port, Options]),
+ ct:log("ssl:connect(~p, ~p, ~p)~n", [Host, Port, Options]),
case rpc:call(Node, Transport, connect, [Host, Port, Options]) of
{ok, Socket} ->
Pid ! { connected, Socket },
- ct:print("Client: connected~n", []),
+ ct:log("Client: connected~n", []),
%% In special cases we want to know the client port, it will
%% be indicated by sending {port, 0} in options list!
send_selected_port(Pid, proplists:get_value(port, Options), Socket),
{Module, Function, Args} = proplists:get_value(mfa, Opts),
- ct:print("Client: apply(~p,~p,~p)~n",
+ ct:log("Client: apply(~p,~p,~p)~n",
[Module, Function, [Socket | Args]]),
case rpc:call(Node, Module, Function, [Socket | Args]) of
no_result_msg ->
ok;
Msg ->
- ct:print("Client Msg: ~p ~n", [Msg]),
+ ct:log("Client Msg: ~p ~n", [Msg]),
Pid ! {self(), Msg}
end,
receive
close ->
- ct:print("Client closing~n", []),
+ ct:log("Client closing~n", []),
rpc:call(Node, Transport, close, [Socket]);
{ssl_closed, Socket} ->
ok;
@@ -189,18 +189,18 @@ run_client(Opts) ->
ok
end;
{error, Reason} ->
- ct:print("Client: connection failed: ~p ~n", [Reason]),
+ ct:log("Client: connection failed: ~p ~n", [Reason]),
Pid ! {self(), {error, Reason}}
end.
close(Pid) ->
- ct:print("Close ~p ~n", [Pid]),
+ ct:log("Close ~p ~n", [Pid]),
Monitor = erlang:monitor(process, Pid),
Pid ! close,
receive
{'DOWN', Monitor, process, Pid, Reason} ->
erlang:demonitor(Monitor),
- ct:print("Pid: ~p down due to:~p ~n", [Pid, Reason])
+ ct:log("Pid: ~p down due to:~p ~n", [Pid, Reason])
end.
check_result(Server, ServerMsg, Client, ClientMsg) ->
@@ -339,12 +339,22 @@ cert_options(Config) ->
{psk_identity, "HINT"},
{user_lookup_fun, {fun user_lookup/3, PskSharedSecret}},
{ciphers, psk_suites()}]},
+ {server_psk_anon, [{ssl_imp, new},{reuseaddr, true},
+ {user_lookup_fun, {fun user_lookup/3, PskSharedSecret}},
+ {ciphers, psk_anon_suites()}]},
+ {server_psk_anon_hint, [{ssl_imp, new},{reuseaddr, true},
+ {psk_identity, "HINT"},
+ {user_lookup_fun, {fun user_lookup/3, PskSharedSecret}},
+ {ciphers, psk_anon_suites()}]},
{client_srp, [{ssl_imp, new},{reuseaddr, true},
{srp_identity, {"Test-User", "secret"}}]},
{server_srp, [{ssl_imp, new},{reuseaddr, true},
{certfile, ServerCertFile}, {keyfile, ServerKeyFile},
{user_lookup_fun, {fun user_lookup/3, undefined}},
{ciphers, srp_suites()}]},
+ {server_srp_anon, [{ssl_imp, new},{reuseaddr, true},
+ {user_lookup_fun, {fun user_lookup/3, undefined}},
+ {ciphers, srp_anon_suites()}]},
{server_verification_opts, [{ssl_imp, new},{reuseaddr, true},
{cacertfile, ServerCaCertFile},
{certfile, ServerCertFile}, {keyfile, ServerKeyFile}]},
@@ -394,6 +404,49 @@ make_dsa_cert(Config) ->
{certfile, ClientCertFile}, {keyfile, ClientKeyFile}]}
| Config].
+make_ecdsa_cert(Config) ->
+ case proplists:get_bool(ec, crypto:algorithms()) of
+ true ->
+ {ServerCaCertFile, ServerCertFile, ServerKeyFile} = make_cert_files("server", Config, ec, ec, ""),
+ {ClientCaCertFile, ClientCertFile, ClientKeyFile} = make_cert_files("client", Config, ec, ec, ""),
+ [{server_ecdsa_opts, [{ssl_imp, new},{reuseaddr, true},
+ {cacertfile, ServerCaCertFile},
+ {certfile, ServerCertFile}, {keyfile, ServerKeyFile}]},
+ {server_ecdsa_verify_opts, [{ssl_imp, new},{reuseaddr, true},
+ {cacertfile, ClientCaCertFile},
+ {certfile, ServerCertFile}, {keyfile, ServerKeyFile},
+ {verify, verify_peer}]},
+ {client_ecdsa_opts, [{ssl_imp, new},{reuseaddr, true},
+ {cacertfile, ClientCaCertFile},
+ {certfile, ClientCertFile}, {keyfile, ClientKeyFile}]}
+ | Config];
+ _ ->
+ Config
+ end.
+
+%% RFC 4492, Sect. 2.3. ECDH_RSA
+%%
+%% This key exchange algorithm is the same as ECDH_ECDSA except that the
+%% server's certificate MUST be signed with RSA rather than ECDSA.
+make_ecdh_rsa_cert(Config) ->
+ case proplists:get_bool(ec, crypto:algorithms()) of
+ true ->
+ {ServerCaCertFile, ServerCertFile, ServerKeyFile} = make_cert_files("server", Config, rsa, ec, "rsa_"),
+ {ClientCaCertFile, ClientCertFile, ClientKeyFile} = make_cert_files("client", Config, rsa, ec, "rsa_"),
+ [{server_ecdh_rsa_opts, [{ssl_imp, new},{reuseaddr, true},
+ {cacertfile, ServerCaCertFile},
+ {certfile, ServerCertFile}, {keyfile, ServerKeyFile}]},
+ {server_ecdh_rsa_verify_opts, [{ssl_imp, new},{reuseaddr, true},
+ {cacertfile, ClientCaCertFile},
+ {certfile, ServerCertFile}, {keyfile, ServerKeyFile},
+ {verify, verify_peer}]},
+ {client_ecdh_rsa_opts, [{ssl_imp, new},{reuseaddr, true},
+ {cacertfile, ClientCaCertFile},
+ {certfile, ClientCertFile}, {keyfile, ClientKeyFile}]}
+ | Config];
+ _ ->
+ Config
+ end.
make_mix_cert(Config) ->
{ServerCaCertFile, ServerCertFile, ServerKeyFile} = make_cert_files("server", Config, dsa,
@@ -445,33 +498,33 @@ run_upgrade_server(Opts) ->
SslOptions = proplists:get_value(ssl_options, Opts),
Pid = proplists:get_value(from, Opts),
- ct:print("gen_tcp:listen(~p, ~p)~n", [Port, TcpOptions]),
+ ct:log("gen_tcp:listen(~p, ~p)~n", [Port, TcpOptions]),
{ok, ListenSocket} = rpc:call(Node, gen_tcp, listen, [Port, TcpOptions]),
Pid ! {listen, up},
send_selected_port(Pid, Port, ListenSocket),
- ct:print("gen_tcp:accept(~p)~n", [ListenSocket]),
+ ct:log("gen_tcp:accept(~p)~n", [ListenSocket]),
{ok, AcceptSocket} = rpc:call(Node, gen_tcp, accept, [ListenSocket]),
try
{ok, SslAcceptSocket} = case TimeOut of
infinity ->
- ct:print("ssl:ssl_accept(~p, ~p)~n",
+ ct:log("ssl:ssl_accept(~p, ~p)~n",
[AcceptSocket, SslOptions]),
rpc:call(Node, ssl, ssl_accept,
[AcceptSocket, SslOptions]);
_ ->
- ct:print("ssl:ssl_accept(~p, ~p, ~p)~n",
+ ct:log("ssl:ssl_accept(~p, ~p, ~p)~n",
[AcceptSocket, SslOptions, TimeOut]),
rpc:call(Node, ssl, ssl_accept,
[AcceptSocket, SslOptions, TimeOut])
end,
{Module, Function, Args} = proplists:get_value(mfa, Opts),
Msg = rpc:call(Node, Module, Function, [SslAcceptSocket | Args]),
- ct:print("Upgrade Server Msg: ~p ~n", [Msg]),
+ ct:log("Upgrade Server Msg: ~p ~n", [Msg]),
Pid ! {self(), Msg},
receive
close ->
- ct:print("Upgrade Server closing~n", []),
+ ct:log("Upgrade Server closing~n", []),
rpc:call(Node, ssl, close, [SslAcceptSocket])
end
catch error:{badmatch, Error} ->
@@ -489,24 +542,24 @@ run_upgrade_client(Opts) ->
TcpOptions = proplists:get_value(tcp_options, Opts),
SslOptions = proplists:get_value(ssl_options, Opts),
- ct:print("gen_tcp:connect(~p, ~p, ~p)~n",
+ ct:log("gen_tcp:connect(~p, ~p, ~p)~n",
[Host, Port, TcpOptions]),
{ok, Socket} = rpc:call(Node, gen_tcp, connect, [Host, Port, TcpOptions]),
send_selected_port(Pid, Port, Socket),
- ct:print("ssl:connect(~p, ~p)~n", [Socket, SslOptions]),
+ ct:log("ssl:connect(~p, ~p)~n", [Socket, SslOptions]),
{ok, SslSocket} = rpc:call(Node, ssl, connect, [Socket, SslOptions]),
{Module, Function, Args} = proplists:get_value(mfa, Opts),
- ct:print("apply(~p, ~p, ~p)~n",
+ ct:log("apply(~p, ~p, ~p)~n",
[Module, Function, [SslSocket | Args]]),
Msg = rpc:call(Node, Module, Function, [SslSocket | Args]),
- ct:print("Upgrade Client Msg: ~p ~n", [Msg]),
+ ct:log("Upgrade Client Msg: ~p ~n", [Msg]),
Pid ! {self(), Msg},
receive
close ->
- ct:print("Upgrade Client closing~n", []),
+ ct:log("Upgrade Client closing~n", []),
rpc:call(Node, ssl, close, [SslSocket])
end.
@@ -525,20 +578,20 @@ run_upgrade_server_error(Opts) ->
SslOptions = proplists:get_value(ssl_options, Opts),
Pid = proplists:get_value(from, Opts),
- ct:print("gen_tcp:listen(~p, ~p)~n", [Port, TcpOptions]),
+ ct:log("gen_tcp:listen(~p, ~p)~n", [Port, TcpOptions]),
{ok, ListenSocket} = rpc:call(Node, gen_tcp, listen, [Port, TcpOptions]),
Pid ! {listen, up},
send_selected_port(Pid, Port, ListenSocket),
- ct:print("gen_tcp:accept(~p)~n", [ListenSocket]),
+ ct:log("gen_tcp:accept(~p)~n", [ListenSocket]),
{ok, AcceptSocket} = rpc:call(Node, gen_tcp, accept, [ListenSocket]),
Error = case TimeOut of
infinity ->
- ct:print("ssl:ssl_accept(~p, ~p)~n",
+ ct:log("ssl:ssl_accept(~p, ~p)~n",
[AcceptSocket, SslOptions]),
rpc:call(Node, ssl, ssl_accept,
[AcceptSocket, SslOptions]);
_ ->
- ct:print("ssl:ssl_accept(~p, ~p, ~p)~n",
+ ct:log("ssl:ssl_accept(~p, ~p, ~p)~n",
[AcceptSocket, SslOptions, TimeOut]),
rpc:call(Node, ssl, ssl_accept,
[AcceptSocket, SslOptions, TimeOut])
@@ -558,26 +611,26 @@ run_server_error(Opts) ->
Options = proplists:get_value(options, Opts),
Pid = proplists:get_value(from, Opts),
Transport = proplists:get_value(transport, Opts, ssl),
- ct:print("ssl:listen(~p, ~p)~n", [Port, Options]),
+ ct:log("ssl:listen(~p, ~p)~n", [Port, Options]),
case rpc:call(Node, Transport, listen, [Port, Options]) of
{ok, #sslsocket{} = ListenSocket} ->
%% To make sure error_client will
%% get {error, closed} and not {error, connection_refused}
Pid ! {listen, up},
send_selected_port(Pid, Port, ListenSocket),
- ct:print("ssl:transport_accept(~p)~n", [ListenSocket]),
+ ct:log("ssl:transport_accept(~p)~n", [ListenSocket]),
case rpc:call(Node, Transport, transport_accept, [ListenSocket]) of
{error, _} = Error ->
Pid ! {self(), Error};
{ok, AcceptSocket} ->
- ct:print("ssl:ssl_accept(~p)~n", [AcceptSocket]),
+ ct:log("ssl:ssl_accept(~p)~n", [AcceptSocket]),
Error = rpc:call(Node, ssl, ssl_accept, [AcceptSocket]),
Pid ! {self(), Error}
end;
{ok, ListenSocket} ->
Pid ! {listen, up},
send_selected_port(Pid, Port, ListenSocket),
- ct:print("~p:accept(~p)~n", [Transport, ListenSocket]),
+ ct:log("~p:accept(~p)~n", [Transport, ListenSocket]),
case rpc:call(Node, Transport, accept, [ListenSocket]) of
{error, _} = Error ->
Pid ! {self(), Error}
@@ -599,7 +652,7 @@ run_client_error(Opts) ->
Pid = proplists:get_value(from, Opts),
Transport = proplists:get_value(transport, Opts, ssl),
Options = proplists:get_value(options, Opts),
- ct:print("ssl:connect(~p, ~p, ~p)~n", [Host, Port, Options]),
+ ct:log("ssl:connect(~p, ~p, ~p)~n", [Host, Port, Options]),
Error = rpc:call(Node, Transport, connect, [Host, Port, Options]),
Pid ! {self(), Error}.
@@ -656,11 +709,16 @@ send_selected_port(Pid, 0, Socket) ->
send_selected_port(_,_,_) ->
ok.
-rsa_suites() ->
- lists:filter(fun({dhe_dss, _, _}) ->
- false;
+rsa_suites(CounterPart) ->
+ ECC = is_sane_ecc(CounterPart),
+ lists:filter(fun({rsa, _, _}) ->
+ true;
+ ({dhe_rsa, _, _}) ->
+ true;
+ ({ecdhe_rsa, _, _}) when ECC == true ->
+ true;
(_) ->
- true
+ false
end,
ssl:cipher_suites()).
@@ -680,17 +738,32 @@ dsa_suites() ->
end,
ssl:cipher_suites()).
+ecdsa_suites() ->
+ lists:filter(fun({ecdhe_ecdsa, _, _}) ->
+ true;
+ (_) ->
+ false
+ end,
+ ssl:cipher_suites()).
+
+ecdh_rsa_suites() ->
+ lists:filter(fun({ecdh_rsa, _, _}) ->
+ true;
+ (_) ->
+ false
+ end,
+ ssl:cipher_suites()).
openssl_rsa_suites() ->
Ciphers = ssl:cipher_suites(openssl),
lists:filter(fun(Str) ->
- case re:run(Str,"DSS",[]) of
+ case re:run(Str,"DSS|ECDH-RSA|ECDSA",[]) of
nomatch ->
true;
_ ->
false
end
- end, Ciphers).
+ end, Ciphers).
openssl_dsa_suites() ->
Ciphers = ssl:cipher_suites(openssl),
@@ -703,14 +776,58 @@ openssl_dsa_suites() ->
end
end, Ciphers).
+openssl_ecdsa_suites() ->
+ Ciphers = ssl:cipher_suites(openssl),
+ lists:filter(fun(Str) ->
+ case re:run(Str,"ECDHE-ECDSA",[]) of
+ nomatch ->
+ false;
+ _ ->
+ true
+ end
+ end, Ciphers).
+
+openssl_ecdh_rsa_suites() ->
+ Ciphers = ssl:cipher_suites(openssl),
+ lists:filter(fun(Str) ->
+ case re:run(Str,"ECDH-RSA",[]) of
+ nomatch ->
+ false;
+ _ ->
+ true
+ end
+ end, Ciphers).
+
anonymous_suites() ->
- [{dh_anon, rc4_128, md5},
- {dh_anon, des_cbc, sha},
- {dh_anon, '3des_ede_cbc', sha},
- {dh_anon, aes_128_cbc, sha},
- {dh_anon, aes_256_cbc, sha}].
+ Suites =
+ [{dh_anon, rc4_128, md5},
+ {dh_anon, des_cbc, sha},
+ {dh_anon, '3des_ede_cbc', sha},
+ {dh_anon, aes_128_cbc, sha},
+ {dh_anon, aes_256_cbc, sha},
+ {ecdh_anon,rc4_128,sha},
+ {ecdh_anon,'3des_ede_cbc',sha},
+ {ecdh_anon,aes_128_cbc,sha},
+ {ecdh_anon,aes_256_cbc,sha}],
+ ssl_cipher:filter_suites(Suites).
psk_suites() ->
+ Suites =
+ [{psk, rc4_128, sha},
+ {psk, '3des_ede_cbc', sha},
+ {psk, aes_128_cbc, sha},
+ {psk, aes_256_cbc, sha},
+ {dhe_psk, rc4_128, sha},
+ {dhe_psk, '3des_ede_cbc', sha},
+ {dhe_psk, aes_128_cbc, sha},
+ {dhe_psk, aes_256_cbc, sha},
+ {rsa_psk, rc4_128, sha},
+ {rsa_psk, '3des_ede_cbc', sha},
+ {rsa_psk, aes_128_cbc, sha},
+ {rsa_psk, aes_256_cbc, sha}],
+ ssl_cipher:filter_suites(Suites).
+
+psk_anon_suites() ->
[{psk, rc4_128, sha},
{psk, '3des_ede_cbc', sha},
{psk, aes_128_cbc, sha},
@@ -718,24 +835,29 @@ psk_suites() ->
{dhe_psk, rc4_128, sha},
{dhe_psk, '3des_ede_cbc', sha},
{dhe_psk, aes_128_cbc, sha},
- {dhe_psk, aes_256_cbc, sha},
- {rsa_psk, rc4_128, sha},
- {rsa_psk, '3des_ede_cbc', sha},
- {rsa_psk, aes_128_cbc, sha},
- {rsa_psk, aes_256_cbc, sha}].
+ {dhe_psk, aes_256_cbc, sha}].
srp_suites() ->
+ Suites =
+ [{srp_anon, '3des_ede_cbc', sha},
+ {srp_rsa, '3des_ede_cbc', sha},
+ {srp_anon, aes_128_cbc, sha},
+ {srp_rsa, aes_128_cbc, sha},
+ {srp_anon, aes_256_cbc, sha},
+ {srp_rsa, aes_256_cbc, sha}],
+ ssl_cipher:filter_suites(Suites).
+
+srp_anon_suites() ->
[{srp_anon, '3des_ede_cbc', sha},
- {srp_rsa, '3des_ede_cbc', sha},
{srp_anon, aes_128_cbc, sha},
- {srp_rsa, aes_128_cbc, sha},
- {srp_anon, aes_256_cbc, sha},
- {srp_rsa, aes_256_cbc, sha}].
+ {srp_anon, aes_256_cbc, sha}].
srp_dss_suites() ->
- [{srp_dss, '3des_ede_cbc', sha},
- {srp_dss, aes_128_cbc, sha},
- {srp_dss, aes_256_cbc, sha}].
+ Suites =
+ [{srp_dss, '3des_ede_cbc', sha},
+ {srp_dss, aes_128_cbc, sha},
+ {srp_dss, aes_256_cbc, sha}],
+ ssl_cipher:filter_suites(Suites).
pem_to_der(File) ->
{ok, PemBin} = file:read_file(File),
@@ -747,7 +869,7 @@ der_to_pem(File, Entries) ->
cipher_result(Socket, Result) ->
Result = ssl:connection_info(Socket),
- ct:print("Successfull connect: ~p~n", [Result]),
+ ct:log("Successfull connect: ~p~n", [Result]),
%% Importante to send two packets here
%% to properly test "cipher state" handling
ssl:send(Socket, "Hello\n"),
@@ -817,15 +939,9 @@ init_tls_version(Version) ->
ssl:start().
sufficient_crypto_support('tlsv1.2') ->
- Data = "Sampl",
- Data2 = "e #1",
- Key = <<0,1,2,3,16,17,18,19,32,33,34,35,48,49,50,51,4,5,6,7,20,21,22,23,36,37,38,39,
- 52,53,54,55,8,9,10,11,24,25,26,27,40,41,42,43,56,57,58,59>>,
- try
- crypto:sha256_mac(Key, lists:flatten([Data, Data2])),
- true
- catch _:_ -> false
- end;
+ proplists:get_bool(sha256, crypto:algorithms());
+sufficient_crypto_support(ciphers_ec) ->
+ proplists:get_bool(ec, crypto:algorithms());
sufficient_crypto_support(_) ->
true.
@@ -858,3 +974,35 @@ send_recv_result_active_once(Socket) ->
{ssl, Socket, "Hello world"} ->
ok
end.
+
+is_sane_ecc(openssl) ->
+ case os:cmd("openssl version") of
+ "OpenSSL 1.0.0a" ++ _ -> % Known bug in openssl
+ %% manifests as SSL_CHECK_SERVERHELLO_TLSEXT:tls invalid ecpointformat list
+ false;
+ "OpenSSL 1.0.0" ++ _ -> % Known bug in openssl
+ %% manifests as SSL_CHECK_SERVERHELLO_TLSEXT:tls invalid ecpointformat list
+ false;
+ "OpenSSL 0.9.8" ++ _ -> % Does not support ECC
+ false;
+ "OpenSSL 0.9.7" ++ _ -> % Does not support ECC
+ false;
+ _ ->
+ true
+ end;
+is_sane_ecc(_) ->
+ true.
+
+cipher_restriction(Config0) ->
+ case is_sane_ecc(openssl) of
+ false ->
+ Opts = proplists:get_value(server_opts, Config0),
+ Config1 = proplists:delete(server_opts, Config0),
+ VerOpts = proplists:get_value(server_verification_opts, Config1),
+ Config = proplists:delete(server_verification_opts, Config1),
+ Restricted0 = ssl:cipher_suites() -- ecdsa_suites(),
+ Restricted = Restricted0 -- ecdh_rsa_suites(),
+ [{server_opts, [{ciphers, Restricted} | Opts]}, {server_verification_opts, [{ciphers, Restricted} | VerOpts] } | Config];
+ true ->
+ Config0
+ end.
diff --git a/lib/ssl/test/ssl_to_openssl_SUITE.erl b/lib/ssl/test/ssl_to_openssl_SUITE.erl
index a3d382f837..075b4b1ec4 100644
--- a/lib/ssl/test/ssl_to_openssl_SUITE.erl
+++ b/lib/ssl/test/ssl_to_openssl_SUITE.erl
@@ -104,10 +104,11 @@ init_per_suite(Config0) ->
Result =
(catch make_certs:all(?config(data_dir, Config0),
?config(priv_dir, Config0))),
- ct:print("Make certs ~p~n", [Result]),
+ ct:log("Make certs ~p~n", [Result]),
Config1 = ssl_test_lib:make_dsa_cert(Config0),
Config = ssl_test_lib:cert_options(Config1),
- [{watchdog, Dog} | Config]
+ NewConfig = [{watchdog, Dog} | Config],
+ ssl_test_lib:cipher_restriction(NewConfig)
catch _:_ ->
{skip, "Crypto did not start"}
end
@@ -200,7 +201,7 @@ basic_erlang_client_openssl_server(Config) when is_list(Config) ->
Cmd = "openssl s_server -accept " ++ integer_to_list(Port) ++
" -cert " ++ CertFile ++ " -key " ++ KeyFile,
- ct:print("openssl cmd: ~p~n", [Cmd]),
+ ct:log("openssl cmd: ~p~n", [Cmd]),
OpensslPort = open_port({spawn, Cmd}, [stderr_to_stdout]),
@@ -212,7 +213,7 @@ basic_erlang_client_openssl_server(Config) when is_list(Config) ->
{mfa, {?MODULE,
erlang_ssl_receive, [Data]}},
{options, ClientOpts}]),
- port_command(OpensslPort, Data),
+ true = port_command(OpensslPort, Data),
ssl_test_lib:check_result(Client, ok),
@@ -241,10 +242,10 @@ basic_erlang_server_openssl_client(Config) when is_list(Config) ->
Cmd = "openssl s_client -port " ++ integer_to_list(Port) ++
" -host localhost",
- ct:print("openssl cmd: ~p~n", [Cmd]),
+ ct:log("openssl cmd: ~p~n", [Cmd]),
OpenSslPort = open_port({spawn, Cmd}, [stderr_to_stdout]),
- port_command(OpenSslPort, Data),
+ true = port_command(OpenSslPort, Data),
ssl_test_lib:check_result(Server, ok),
@@ -272,7 +273,7 @@ erlang_client_openssl_server(Config) when is_list(Config) ->
Cmd = "openssl s_server -accept " ++ integer_to_list(Port) ++ version_flag(Version) ++
" -cert " ++ CertFile ++ " -key " ++ KeyFile,
- ct:print("openssl cmd: ~p~n", [Cmd]),
+ ct:log("openssl cmd: ~p~n", [Cmd]),
OpensslPort = open_port({spawn, Cmd}, [stderr_to_stdout]),
@@ -284,7 +285,7 @@ erlang_client_openssl_server(Config) when is_list(Config) ->
{mfa, {?MODULE,
erlang_ssl_receive, [Data]}},
{options, ClientOpts}]),
- port_command(OpensslPort, Data),
+ true = port_command(OpensslPort, Data),
ssl_test_lib:check_result(Client, ok),
@@ -314,10 +315,10 @@ erlang_server_openssl_client(Config) when is_list(Config) ->
Cmd = "openssl s_client -port " ++ integer_to_list(Port) ++ version_flag(Version) ++
" -host localhost",
- ct:print("openssl cmd: ~p~n", [Cmd]),
+ ct:log("openssl cmd: ~p~n", [Cmd]),
OpenSslPort = open_port({spawn, Cmd}, [stderr_to_stdout]),
- port_command(OpenSslPort, Data),
+ true = port_command(OpenSslPort, Data),
ssl_test_lib:check_result(Server, ok),
@@ -349,7 +350,7 @@ erlang_client_openssl_server_dsa_cert(Config) when is_list(Config) ->
" -cert " ++ CertFile ++ " -CAfile " ++ CaCertFile
++ " -key " ++ KeyFile ++ " -Verify 2 -msg",
- ct:print("openssl cmd: ~p~n", [Cmd]),
+ ct:log("openssl cmd: ~p~n", [Cmd]),
OpensslPort = open_port({spawn, Cmd}, [stderr_to_stdout]),
@@ -362,7 +363,7 @@ erlang_client_openssl_server_dsa_cert(Config) when is_list(Config) ->
erlang_ssl_receive, [Data]}},
{options, ClientOpts}]),
- port_command(OpensslPort, Data),
+ true = port_command(OpensslPort, Data),
ssl_test_lib:check_result(Client, ok),
@@ -396,10 +397,10 @@ erlang_server_openssl_client_dsa_cert(Config) when is_list(Config) ->
" -host localhost " ++ " -cert " ++ CertFile ++ " -CAfile " ++ CaCertFile
++ " -key " ++ KeyFile ++ " -msg",
- ct:print("openssl cmd: ~p~n", [Cmd]),
+ ct:log("openssl cmd: ~p~n", [Cmd]),
OpenSslPort = open_port({spawn, Cmd}, [stderr_to_stdout]),
- port_command(OpenSslPort, Data),
+ true = port_command(OpenSslPort, Data),
ssl_test_lib:check_result(Server, ok),
@@ -431,11 +432,11 @@ erlang_server_openssl_client_reuse_session(Config) when is_list(Config) ->
Cmd = "openssl s_client -port " ++ integer_to_list(Port) ++ version_flag(Version) ++
" -host localhost -reconnect",
- ct:print("openssl cmd: ~p~n", [Cmd]),
+ ct:log("openssl cmd: ~p~n", [Cmd]),
OpenSslPort = open_port({spawn, Cmd}, [stderr_to_stdout]),
- port_command(OpenSslPort, Data),
+ true = port_command(OpenSslPort, Data),
ssl_test_lib:check_result(Server, ok),
@@ -467,7 +468,7 @@ erlang_client_openssl_server_renegotiate(Config) when is_list(Config) ->
Cmd = "openssl s_server -accept " ++ integer_to_list(Port) ++ version_flag(Version) ++
" -cert " ++ CertFile ++ " -key " ++ KeyFile ++ " -msg",
- ct:print("openssl cmd: ~p~n", [Cmd]),
+ ct:log("openssl cmd: ~p~n", [Cmd]),
OpensslPort = open_port({spawn, Cmd}, [stderr_to_stdout]),
@@ -480,9 +481,9 @@ erlang_client_openssl_server_renegotiate(Config) when is_list(Config) ->
delayed_send, [[ErlData, OpenSslData]]}},
{options, ClientOpts}]),
- port_command(OpensslPort, ?OPENSSL_RENEGOTIATE),
+ true = port_command(OpensslPort, ?OPENSSL_RENEGOTIATE),
ct:sleep(?SLEEP),
- port_command(OpensslPort, OpenSslData),
+ true = port_command(OpensslPort, OpenSslData),
ssl_test_lib:check_result(Client, ok),
@@ -516,7 +517,7 @@ erlang_client_openssl_server_nowrap_seqnum(Config) when is_list(Config) ->
Cmd = "openssl s_server -accept " ++ integer_to_list(Port) ++ version_flag(Version) ++
" -cert " ++ CertFile ++ " -key " ++ KeyFile ++ " -msg",
- ct:print("openssl cmd: ~p~n", [Cmd]),
+ ct:log("openssl cmd: ~p~n", [Cmd]),
OpensslPort = open_port({spawn, Cmd}, [stderr_to_stdout]),
@@ -562,11 +563,11 @@ erlang_server_openssl_client_nowrap_seqnum(Config) when is_list(Config) ->
Cmd = "openssl s_client -port " ++ integer_to_list(Port) ++ version_flag(Version) ++
" -host localhost -msg",
- ct:print("openssl cmd: ~p~n", [Cmd]),
+ ct:log("openssl cmd: ~p~n", [Cmd]),
OpenSslPort = open_port({spawn, Cmd}, [stderr_to_stdout]),
- port_command(OpenSslPort, Data),
+ true = port_command(OpenSslPort, Data),
ssl_test_lib:check_result(Server, ok),
@@ -597,7 +598,7 @@ erlang_client_openssl_server_no_server_ca_cert(Config) when is_list(Config) ->
Cmd = "openssl s_server -accept " ++ integer_to_list(Port) ++ version_flag(Version) ++
" -cert " ++ CertFile ++ " -key " ++ KeyFile ++ " -msg",
- ct:print("openssl cmd: ~p~n", [Cmd]),
+ ct:log("openssl cmd: ~p~n", [Cmd]),
OpensslPort = open_port({spawn, Cmd}, [stderr_to_stdout]),
@@ -610,7 +611,7 @@ erlang_client_openssl_server_no_server_ca_cert(Config) when is_list(Config) ->
erlang_ssl_receive, [Data]}},
{options, ClientOpts}]),
- port_command(OpensslPort, Data),
+ true = port_command(OpensslPort, Data),
ssl_test_lib:check_result(Client, ok),
@@ -640,7 +641,7 @@ erlang_client_openssl_server_client_cert(Config) when is_list(Config) ->
" -cert " ++ CertFile ++ " -CAfile " ++ CaCertFile
++ " -key " ++ KeyFile ++ " -Verify 2",
- ct:print("openssl cmd: ~p~n", [Cmd]),
+ ct:log("openssl cmd: ~p~n", [Cmd]),
OpensslPort = open_port({spawn, Cmd}, [stderr_to_stdout]),
@@ -652,7 +653,7 @@ erlang_client_openssl_server_client_cert(Config) when is_list(Config) ->
{mfa, {?MODULE,
erlang_ssl_receive, [Data]}},
{options, ClientOpts}]),
- port_command(OpensslPort, Data),
+ true = port_command(OpensslPort, Data),
ssl_test_lib:check_result(Client, ok),
@@ -691,10 +692,10 @@ erlang_server_openssl_client_client_cert(Config) when is_list(Config) ->
++ " -key " ++ KeyFile ++ " -port " ++ integer_to_list(Port) ++ version_flag(Version) ++
" -host localhost",
- ct:print("openssl cmd: ~p~n", [Cmd]),
+ ct:log("openssl cmd: ~p~n", [Cmd]),
OpenSslPort = open_port({spawn, Cmd}, [stderr_to_stdout]),
- port_command(OpenSslPort, Data),
+ true = port_command(OpenSslPort, Data),
ssl_test_lib:check_result(Server, ok),
@@ -749,7 +750,7 @@ ciphers_rsa_signed_certs(Config) when is_list(Config) ->
Version =
ssl_record:protocol_version(ssl_record:highest_protocol_version([])),
- Ciphers = ssl_test_lib:rsa_suites(),
+ Ciphers = ssl_test_lib:rsa_suites(openssl),
run_suites(Ciphers, Version, Config, rsa).
%%--------------------------------------------------------------------
@@ -779,7 +780,7 @@ erlang_client_bad_openssl_server(Config) when is_list(Config) ->
Cmd = "openssl s_server -accept " ++ integer_to_list(Port) ++ version_flag(Version) ++
" -cert " ++ CertFile ++ " -key " ++ KeyFile ++ "",
- ct:print("openssl cmd: ~p~n", [Cmd]),
+ ct:log("openssl cmd: ~p~n", [Cmd]),
OpensslPort = open_port({spawn, Cmd}, [stderr_to_stdout]),
@@ -793,7 +794,7 @@ erlang_client_bad_openssl_server(Config) when is_list(Config) ->
[{versions, [Version]} | ClientOpts]}]),
%% Send garbage
- port_command(OpensslPort, ?OPENSSL_GARBAGE),
+ true = port_command(OpensslPort, ?OPENSSL_GARBAGE),
ct:sleep(?SLEEP),
@@ -835,7 +836,7 @@ expired_session(Config) when is_list(Config) ->
Cmd = "openssl s_server -accept " ++ integer_to_list(Port) ++
" -cert " ++ CertFile ++ " -key " ++ KeyFile ++ "",
- ct:print("openssl cmd: ~p~n", [Cmd]),
+ ct:log("openssl cmd: ~p~n", [Cmd]),
OpensslPort = open_port({spawn, Cmd}, [stderr_to_stdout]),
@@ -893,10 +894,10 @@ ssl2_erlang_server_openssl_client(Config) when is_list(Config) ->
Cmd = "openssl s_client -port " ++ integer_to_list(Port) ++
" -host localhost -ssl2 -msg",
- ct:print("openssl cmd: ~p~n", [Cmd]),
+ ct:log("openssl cmd: ~p~n", [Cmd]),
OpenSslPort = open_port({spawn, Cmd}, [stderr_to_stdout]),
- port_command(OpenSslPort, Data),
+ true = port_command(OpenSslPort, Data),
receive
{'EXIT', OpenSslPort, _} ->
ok
@@ -912,7 +913,7 @@ erlang_client_openssl_server_npn() ->
erlang_client_openssl_server_npn(Config) when is_list(Config) ->
Data = "From openssl to erlang",
start_erlang_client_and_openssl_server_for_npn_negotiation(Config, Data, fun(Client, OpensslPort) ->
- port_command(OpensslPort, Data),
+ true = port_command(OpensslPort, Data),
ssl_test_lib:check_result(Client, ok)
end),
@@ -925,9 +926,9 @@ erlang_client_openssl_server_npn_renegotiate() ->
erlang_client_openssl_server_npn_renegotiate(Config) when is_list(Config) ->
Data = "From openssl to erlang",
start_erlang_client_and_openssl_server_for_npn_negotiation(Config, Data, fun(Client, OpensslPort) ->
- port_command(OpensslPort, ?OPENSSL_RENEGOTIATE),
+ true = port_command(OpensslPort, ?OPENSSL_RENEGOTIATE),
ct:sleep(?SLEEP),
- port_command(OpensslPort, Data),
+ true = port_command(OpensslPort, Data),
ssl_test_lib:check_result(Client, ok)
end),
ok.
@@ -939,7 +940,7 @@ erlang_server_openssl_client_npn(Config) when is_list(Config) ->
Data = "From openssl to erlang",
start_erlang_server_and_openssl_client_for_npn_negotiation(Config, Data, fun(Server, OpensslPort) ->
- port_command(OpensslPort, Data),
+ true = port_command(OpensslPort, Data),
ssl_test_lib:check_result(Server, ok)
end),
ok.
@@ -951,9 +952,9 @@ erlang_server_openssl_client_npn_renegotiate() ->
erlang_server_openssl_client_npn_renegotiate(Config) when is_list(Config) ->
Data = "From openssl to erlang",
start_erlang_server_and_openssl_client_for_npn_negotiation(Config, Data, fun(Server, OpensslPort) ->
- port_command(OpensslPort, ?OPENSSL_RENEGOTIATE),
+ true = port_command(OpensslPort, ?OPENSSL_RENEGOTIATE),
ct:sleep(?SLEEP),
- port_command(OpensslPort, Data),
+ true = port_command(OpensslPort, Data),
ssl_test_lib:check_result(Server, ok)
end),
ok.
@@ -962,7 +963,7 @@ erlang_client_openssl_server_npn_only_server(Config) when is_list(Config) ->
Data = "From openssl to erlang",
start_erlang_client_and_openssl_server_with_opts(Config, [],
"-nextprotoneg spdy/2", Data, fun(Server, OpensslPort) ->
- port_command(OpensslPort, Data),
+ true = port_command(OpensslPort, Data),
ssl_test_lib:check_result(Server, ok)
end),
ok.
@@ -975,7 +976,7 @@ erlang_client_openssl_server_npn_only_client(Config) when is_list(Config) ->
[{client_preferred_next_protocols,
{client, [<<"spdy/2">>], <<"http/1.1">>}}], "",
Data, fun(Server, OpensslPort) ->
- port_command(OpensslPort, Data),
+ true = port_command(OpensslPort, Data),
ssl_test_lib:check_result(Server, ok)
end),
ok.
@@ -985,7 +986,7 @@ erlang_server_openssl_client_npn_only_server(Config) when is_list(Config) ->
Data = "From openssl to erlang",
start_erlang_server_and_openssl_client_with_opts(Config, [{next_protocols_advertised, [<<"spdy/2">>]}], "",
Data, fun(Server, OpensslPort) ->
- port_command(OpensslPort, Data),
+ true = port_command(OpensslPort, Data),
ssl_test_lib:check_result(Server, ok)
end),
ok.
@@ -994,7 +995,7 @@ erlang_server_openssl_client_npn_only_client(Config) when is_list(Config) ->
Data = "From openssl to erlang",
start_erlang_server_and_openssl_client_with_opts(Config, [], "-nextprotoneg spdy/2",
Data, fun(Server, OpensslPort) ->
- port_command(OpensslPort, Data),
+ true = port_command(OpensslPort, Data),
ssl_test_lib:check_result(Server, ok)
end),
ok.
@@ -1020,13 +1021,13 @@ run_suites(Ciphers, Version, Config, Type) ->
[] ->
ok;
Error ->
- ct:print("Cipher suite errors: ~p~n", [Error]),
+ ct:log("Cipher suite errors: ~p~n", [Error]),
ct:fail(cipher_suite_failed_see_test_case_log)
end.
cipher(CipherSuite, Version, Config, ClientOpts, ServerOpts) ->
process_flag(trap_exit, true),
- ct:print("Testing CipherSuite ~p~n", [CipherSuite]),
+ ct:log("Testing CipherSuite ~p~n", [CipherSuite]),
{ClientNode, _ServerNode, Hostname} = ssl_test_lib:run_where(Config),
Port = ssl_test_lib:inet_port(node()),
@@ -1036,7 +1037,7 @@ cipher(CipherSuite, Version, Config, ClientOpts, ServerOpts) ->
Cmd = "openssl s_server -accept " ++ integer_to_list(Port) ++ version_flag(Version) ++
" -cert " ++ CertFile ++ " -key " ++ KeyFile ++ "",
- ct:print("openssl cmd: ~p~n", [Cmd]),
+ ct:log("openssl cmd: ~p~n", [Cmd]),
OpenSslPort = open_port({spawn, Cmd}, [stderr_to_stdout]),
@@ -1052,19 +1053,19 @@ cipher(CipherSuite, Version, Config, ClientOpts, ServerOpts) ->
[{ciphers,[CipherSuite]} |
ClientOpts]}]),
- port_command(OpenSslPort, "Hello\n"),
+ true = port_command(OpenSslPort, "Hello\n"),
receive
{Port, {data, _}} when is_port(Port) ->
ok
after 500 ->
- ct:print("Time out on openssl port, check that"
+ ct:log("Time out on openssl port, check that"
" the messages Hello and world are received"
" during close of port" , []),
ok
end,
- port_command(OpenSslPort, " world\n"),
+ true = port_command(OpenSslPort, " world\n"),
Result = ssl_test_lib:wait_for_result(Client, ok),
@@ -1100,7 +1101,7 @@ start_erlang_client_and_openssl_server_with_opts(Config, ErlangClientOpts, Opens
integer_to_list(Port) ++ version_flag(Version) ++
" -cert " ++ CertFile ++ " -key " ++ KeyFile,
- ct:print("openssl cmd: ~p~n", [Cmd]),
+ ct:log("openssl cmd: ~p~n", [Cmd]),
OpensslPort = open_port({spawn, Cmd}, [stderr_to_stdout]),
@@ -1139,7 +1140,7 @@ start_erlang_client_and_openssl_server_for_npn_negotiation(Config, Data, Callbac
Cmd = "openssl s_server -msg -nextprotoneg http/1.1,spdy/2 -accept " ++ integer_to_list(Port) ++ version_flag(Version) ++
" -cert " ++ CertFile ++ " -key " ++ KeyFile,
- ct:print("openssl cmd: ~p~n", [Cmd]),
+ ct:log("openssl cmd: ~p~n", [Cmd]),
OpensslPort = open_port({spawn, Cmd}, [stderr_to_stdout]),
@@ -1177,7 +1178,7 @@ start_erlang_server_and_openssl_client_for_npn_negotiation(Config, Data, Callbac
Cmd = "openssl s_client -nextprotoneg http/1.0,spdy/2 -msg -port " ++ integer_to_list(Port) ++ version_flag(Version) ++
" -host localhost",
- ct:print("openssl cmd: ~p~n", [Cmd]),
+ ct:log("openssl cmd: ~p~n", [Cmd]),
OpenSslPort = open_port({spawn, Cmd}, [stderr_to_stdout]),
@@ -1206,7 +1207,7 @@ start_erlang_server_and_openssl_client_with_opts(Config, ErlangServerOpts, OpenS
Cmd = "openssl s_client " ++ OpenSSLClientOpts ++ " -msg -port " ++ integer_to_list(Port) ++ version_flag(Version) ++
" -host localhost",
- ct:print("openssl cmd: ~p~n", [Cmd]),
+ ct:log("openssl cmd: ~p~n", [Cmd]),
OpenSslPort = open_port({spawn, Cmd}, [stderr_to_stdout]),
@@ -1225,7 +1226,7 @@ erlang_ssl_receive_and_assert_npn(Socket, Protocol, Data) ->
ok.
erlang_ssl_receive(Socket, Data) ->
- ct:print("Connection info: ~p~n",
+ ct:log("Connection info: ~p~n",
[ssl:connection_info(Socket)]),
receive
{ssl, Socket, Data} ->
@@ -1247,7 +1248,7 @@ erlang_ssl_receive(Socket, Data) ->
connection_info(Socket, Version) ->
case ssl:connection_info(Socket) of
{ok, {Version, _} = Info} ->
- ct:print("Connection info: ~p~n", [Info]),
+ ct:log("Connection info: ~p~n", [Info]),
ok;
{ok, {OtherVersion, _}} ->
{wrong_version, OtherVersion}
@@ -1269,28 +1270,28 @@ close_port(Port) ->
close_loop(Port, Time, SentClose) ->
receive
{Port, {data,Debug}} when is_port(Port) ->
- io:format("openssl ~s~n",[Debug]),
+ ct:log("openssl ~s~n",[Debug]),
close_loop(Port, Time, SentClose);
{ssl,_,Msg} ->
- io:format("ssl Msg ~s~n",[Msg]),
+ ct:log("ssl Msg ~s~n",[Msg]),
close_loop(Port, Time, SentClose);
{Port, closed} ->
- io:format("Port Closed~n",[]),
+ ct:log("Port Closed~n",[]),
ok;
{'EXIT', Port, Reason} ->
- io:format("Port Closed ~p~n",[Reason]),
+ ct:log("Port Closed ~p~n",[Reason]),
ok;
Msg ->
- io:format("Port Msg ~p~n",[Msg]),
+ ct:log("Port Msg ~p~n",[Msg]),
close_loop(Port, Time, SentClose)
after Time ->
case SentClose of
false ->
- io:format("Closing port ~n",[]),
+ ct:log("Closing port ~n",[]),
catch erlang:port_close(Port),
close_loop(Port, Time, true);
true ->
- io:format("Timeout~n",[])
+ ct:log("Timeout~n",[])
end
end.
@@ -1305,7 +1306,7 @@ server_sent_garbage(Socket) ->
wait_for_openssl_server() ->
receive
{Port, {data, Debug}} when is_port(Port) ->
- io:format("openssl ~s~n",[Debug]),
+ ct:log("openssl ~s~n",[Debug]),
%% openssl has started make sure
%% it will be in accept. Parsing
%% output is too error prone. (Even
diff --git a/lib/stdlib/doc/src/lists.xml b/lib/stdlib/doc/src/lists.xml
index b6c0fa4e05..1aff78f4fc 100644
--- a/lib/stdlib/doc/src/lists.xml
+++ b/lib/stdlib/doc/src/lists.xml
@@ -152,6 +152,31 @@
</desc>
</func>
<func>
+ <name name="filtermap" arity="2"/>
+ <fsummary>Filter and map elements which satisfy a function</fsummary>
+ <desc>
+ <p>Calls <c><anno>Fun</anno>(<anno>Elem</anno>)</c> on successive elements <c>Elem</c>
+ of <c><anno>List1</anno></c>. <c><anno>Fun</anno>/2</c> must return either a boolean
+ or a tuple <c>{true, <anno>Value</anno>}</c>. The function returns the list of elements
+ for which <c><anno>Fun</anno></c> returns a new value, where a value of <c>true</c>
+ is synonymous with <c>{true, <anno>Elem</anno>}</c>.</p>
+ <p>That is, <c>filtermap</c> behaves as if it had been defined as follows:</p>
+ <code type="none">
+filtermap(Fun, List1) ->
+ lists:foldr(fun(Elem, Acc) ->
+ case Fun(Elem) of
+ false -> Acc;
+ true -> [Elem|Acc];
+ {true,Value} -> [Value|Acc]
+ end,
+ end, [], List1).</code>
+ <p>Example:</p>
+ <pre>
+> <input>lists:filtermap(fun(X) -> case X rem 2 of 0 -> {true, X div 2}; _ -> false end end, [1,2,3,4,5]).</input>
+[1,2]</pre>
+ </desc>
+ </func>
+ <func>
<name name="flatlength" arity="1"/>
<fsummary>Length of flattened deep list</fsummary>
<desc>
diff --git a/lib/stdlib/doc/src/unicode_usage.xml b/lib/stdlib/doc/src/unicode_usage.xml
index c5d476e54b..1f64b38554 100644
--- a/lib/stdlib/doc/src/unicode_usage.xml
+++ b/lib/stdlib/doc/src/unicode_usage.xml
@@ -625,6 +625,7 @@ Eshell V5.10.1 (abort with ^G)
</section>
<section>
<title>Unicode File Names</title>
+ <marker id="unicode_file_names"/>
<p>Most modern operating systems support Unicode file names in some
way or another. There are several different ways to do this and
Erlang by default treats the different approaches differently:</p>
diff --git a/lib/stdlib/src/dets.erl b/lib/stdlib/src/dets.erl
index 45aef0ea80..50812cc532 100644
--- a/lib/stdlib/src/dets.erl
+++ b/lib/stdlib/src/dets.erl
@@ -1246,13 +1246,8 @@ req(Proc, R) ->
{'DOWN', Ref, process, Proc, _Info} ->
badarg;
{Proc, Reply} ->
- erlang:demonitor(Ref),
- receive
- {'DOWN', Ref, process, Proc, _Reason} ->
- Reply
- after 0 ->
- Reply
- end
+ erlang:demonitor(Ref, [flush]),
+ Reply
end.
%% Inlined.
diff --git a/lib/stdlib/src/epp.erl b/lib/stdlib/src/epp.erl
index 0a1caa7178..d1d060ebc8 100644
--- a/lib/stdlib/src/epp.erl
+++ b/lib/stdlib/src/epp.erl
@@ -601,7 +601,7 @@ enter_file2(NewF, Pname, From, St0, AtLocation) ->
%% file will depend on the order of file inclusions in the parent files
Path = [filename:dirname(Pname) | tl(St0#epp.path)],
_ = set_encoding(NewF),
- #epp{file=NewF,location=Loc,name=Pname,delta=0,
+ #epp{file=NewF,location=Loc,name=Pname,name2=Pname,delta=0,
sstk=[St0|St0#epp.sstk],path=Path,macs=Ms}.
enter_file_reply(From, Name, Location, AtLocation) ->
@@ -1339,8 +1339,7 @@ epp_reply(From, Rep) ->
wait_epp_reply(Epp, Mref) ->
receive
{epp_reply,Epp,Rep} ->
- erlang:demonitor(Mref),
- receive {'DOWN',Mref,_,_,_} -> ok after 0 -> ok end,
+ erlang:demonitor(Mref, [flush]),
Rep;
{'DOWN',Mref,_,_,E} ->
receive {epp_reply,Epp,Rep} -> Rep
diff --git a/lib/stdlib/src/gen.erl b/lib/stdlib/src/gen.erl
index 42555aedd7..5df5530ba1 100644
--- a/lib/stdlib/src/gen.erl
+++ b/lib/stdlib/src/gen.erl
@@ -17,6 +17,7 @@
%% %CopyrightEnd%
%%
-module(gen).
+-compile({inline,[get_node/1]}).
%%%-----------------------------------------------------------------
%%% This module implements the really generic stuff of the generic
@@ -194,16 +195,6 @@ call({_Name, Node}=Process, Label, Request, Timeout)
end.
do_call(Process, Label, Request, Timeout) ->
- %% We trust the arguments to be correct, i.e
- %% Process is either a local or remote pid,
- %% or a {Name, Node} tuple (of atoms) and in this
- %% case this node (node()) _is_ distributed and Node =/= node().
- Node = case Process of
- {_S, N} when is_atom(N) ->
- N;
- _ when is_pid(Process) ->
- node(Process)
- end,
try erlang:monitor(process, Process) of
Mref ->
%% If the monitor/2 call failed to set up a connection to a
@@ -222,15 +213,12 @@ do_call(Process, Label, Request, Timeout) ->
erlang:demonitor(Mref, [flush]),
{ok, Reply};
{'DOWN', Mref, _, _, noconnection} ->
+ Node = get_node(Process),
exit({nodedown, Node});
{'DOWN', Mref, _, _, Reason} ->
exit(Reason)
after Timeout ->
- erlang:demonitor(Mref),
- receive
- {'DOWN', Mref, _, _, _} -> true
- after 0 -> true
- end,
+ erlang:demonitor(Mref, [flush]),
exit(timeout)
end
catch
@@ -241,6 +229,7 @@ do_call(Process, Label, Request, Timeout) ->
%% Do the best possible with monitor_node/2.
%% This code may hang indefinitely if the Process
%% does not exist. It is only used for featureweak remote nodes.
+ Node = get_node(Process),
monitor_node(Node, true),
receive
{nodedown, Node} ->
@@ -253,6 +242,18 @@ do_call(Process, Label, Request, Timeout) ->
end
end.
+get_node(Process) ->
+ %% We trust the arguments to be correct, i.e
+ %% Process is either a local or remote pid,
+ %% or a {Name, Node} tuple (of atoms) and in this
+ %% case this node (node()) _is_ distributed and Node =/= node().
+ case Process of
+ {_S, N} when is_atom(N) ->
+ N;
+ _ when is_pid(Process) ->
+ node(Process)
+ end.
+
wait_resp(Node, Tag, Timeout) ->
receive
{Tag, Reply} ->
diff --git a/lib/stdlib/src/gen_server.erl b/lib/stdlib/src/gen_server.erl
index 9c4b95acf6..30a81ade49 100644
--- a/lib/stdlib/src/gen_server.erl
+++ b/lib/stdlib/src/gen_server.erl
@@ -472,11 +472,11 @@ rec_nodes(Tag, [{N,R}|Tail], Name, Badnodes, Replies, Time, TimerId ) ->
{'DOWN', R, _, _, _} ->
rec_nodes(Tag, Tail, Name, [N|Badnodes], Replies, Time, TimerId);
{{Tag, N}, Reply} -> %% Tag is bound !!!
- unmonitor(R),
+ erlang:demonitor(R, [flush]),
rec_nodes(Tag, Tail, Name, Badnodes,
[{N,Reply}|Replies], Time, TimerId);
{timeout, TimerId, _} ->
- unmonitor(R),
+ erlang:demonitor(R, [flush]),
%% Collect all replies that already have arrived
rec_nodes_rest(Tag, Tail, Name, [N|Badnodes], Replies)
end;
@@ -527,10 +527,10 @@ rec_nodes_rest(Tag, [{N,R}|Tail], Name, Badnodes, Replies) ->
{'DOWN', R, _, _, _} ->
rec_nodes_rest(Tag, Tail, Name, [N|Badnodes], Replies);
{{Tag, N}, Reply} -> %% Tag is bound !!!
- unmonitor(R),
+ erlang:demonitor(R, [flush]),
rec_nodes_rest(Tag, Tail, Name, Badnodes, [{N,Reply}|Replies])
after 0 ->
- unmonitor(R),
+ erlang:demonitor(R, [flush]),
rec_nodes_rest(Tag, Tail, Name, [N|Badnodes], Replies)
end;
rec_nodes_rest(Tag, [N|Tail], Name, Badnodes, Replies) ->
@@ -572,16 +572,6 @@ start_monitor(Node, Name) when is_atom(Node), is_atom(Name) ->
end
end.
-%% Cancels a monitor started with Ref=erlang:monitor(_, _).
-unmonitor(Ref) when is_reference(Ref) ->
- erlang:demonitor(Ref),
- receive
- {'DOWN', Ref, _, _, _} ->
- true
- after 0 ->
- true
- end.
-
%%% ---------------------------------------------------
%%% Message handling functions
%%% ---------------------------------------------------
diff --git a/lib/stdlib/src/io.erl b/lib/stdlib/src/io.erl
index c92e9e3ade..53728237ca 100644
--- a/lib/stdlib/src/io.erl
+++ b/lib/stdlib/src/io.erl
@@ -598,11 +598,7 @@ default_output() ->
wait_io_mon_reply(From, Mref) ->
receive
{io_reply, From, Reply} ->
- erlang:demonitor(Mref),
- receive
- {'DOWN', Mref, _, _, _} -> true
- after 0 -> true
- end,
+ erlang:demonitor(Mref, [flush]),
Reply;
{'EXIT', From, _What} ->
receive
diff --git a/lib/stdlib/src/lists.erl b/lib/stdlib/src/lists.erl
index 961c060019..0c033acd88 100644
--- a/lib/stdlib/src/lists.erl
+++ b/lib/stdlib/src/lists.erl
@@ -36,7 +36,7 @@
-export([merge/3, rmerge/3, sort/2, umerge/3, rumerge/3, usort/2]).
-export([all/2,any/2,map/2,flatmap/2,foldl/3,foldr/3,filter/2,
- partition/2,zf/2,
+ partition/2,zf/2,filtermap/2,
mapfoldl/3,mapfoldr/3,foreach/2,takewhile/2,dropwhile/2,splitwith/2,
split/2]).
@@ -1291,18 +1291,28 @@ partition(Pred, [H | T], As, Bs) ->
partition(Pred, [], As, Bs) when is_function(Pred, 1) ->
{reverse(As), reverse(Bs)}.
--spec zf(fun((T) -> boolean() | {'true', X}), [T]) -> [(T | X)].
+-spec filtermap(Fun, List1) -> List2 when
+ Fun :: fun((Elem) -> boolean() | {'true', Value}),
+ List1 :: [Elem],
+ List2 :: [Elem | Value],
+ Elem :: term(),
+ Value :: term().
-zf(F, [Hd|Tail]) ->
+filtermap(F, [Hd|Tail]) ->
case F(Hd) of
true ->
- [Hd|zf(F, Tail)];
+ [Hd|filtermap(F, Tail)];
{true,Val} ->
- [Val|zf(F, Tail)];
+ [Val|filtermap(F, Tail)];
false ->
- zf(F, Tail)
+ filtermap(F, Tail)
end;
-zf(F, []) when is_function(F, 1) -> [].
+filtermap(F, []) when is_function(F, 1) -> [].
+
+-spec zf(fun((T) -> boolean() | {'true', X}), [T]) -> [(T | X)].
+
+zf(F, L) ->
+ filtermap(F, L).
-spec foreach(Fun, List) -> ok when
Fun :: fun((Elem :: T) -> term()),
diff --git a/lib/stdlib/src/otp_internal.erl b/lib/stdlib/src/otp_internal.erl
index a4f4035c79..f2849e50ec 100644
--- a/lib/stdlib/src/otp_internal.erl
+++ b/lib/stdlib/src/otp_internal.erl
@@ -66,6 +66,139 @@ obsolete_1(rpc, safe_multi_server_call, A) when A =:= 2; A =:= 3 ->
{deprecated, {rpc, multi_server_call, A}};
+%% *** CRYPTO add in R16B01 ***
+
+obsolete_1(crypto, md4, 1) ->
+ {deprecated, {crypto, hash, 2}};
+obsolete_1(crypto, md5, 1) ->
+ {deprecated, {crypto, hash, 2}};
+obsolete_1(crypto, sha, 1) ->
+ {deprecated, {crypto, hash, 2}};
+
+obsolete_1(crypto, md4_init, 1) ->
+ {deprecated, {crypto, hash_init, 2}};
+obsolete_1(crypto, md5_init, 1) ->
+ {deprecated, {crypto, hash_init, 2}};
+obsolete_1(crypto, sha_init, 1) ->
+ {deprecated, {crypto, hash_init, 2}};
+
+obsolete_1(crypto, md4_update, 2) ->
+ {deprecated, {crypto, hash_update, 3}};
+obsolete_1(crypto, md5_update, 2) ->
+ {deprecated, {crypto, hash_update, 3}};
+obsolete_1(crypto, sah_update, 2) ->
+ {deprecated, {crypto, hash_update, 3}};
+
+obsolete_1(crypto, md4_final, 1) ->
+ {deprecated, {crypto, hash_final, 2}};
+obsolete_1(crypto, md5_final, 1) ->
+ {deprecated, {crypto, hash_final, 2}};
+obsolete_1(crypto, sha_final, 1) ->
+ {deprecated, {crypto, hash_final, 2}};
+
+obsolete_1(crypto, md5_mac, 2) ->
+ {deprecated, {crypto, hmac, 3}};
+obsolete_1(crypto, sha_mac, 2) ->
+ {deprecated, {crypto, hmac, 3}};
+
+obsolete_1(crypto, sha_mac_96, 2) ->
+ {deprecated, {crypto, hmac_n, 3}};
+obsolete_1(crypto, md5_mac_96, 2) ->
+ {deprecated, {crypto, hmac_n, 3}};
+
+obsolete_1(crypto, rsa_sign, 3) ->
+ {deprecated, {crypto, sign, 4}};
+obsolete_1(crypto, rsa_verify, 3) ->
+ {deprecated, {crypto, verify, 4}};
+
+obsolete_1(crypto, dss_sign, 2) ->
+ {deprecated, {crypto, sign, 4}};
+obsolete_1(crypto, dss_sign, 3) ->
+ {deprecated, {crypto, sign, 4}};
+
+obsolete_1(crypto, dss_verify, 3) ->
+ {deprecated, {crypto, verify, 4}};
+obsolete_1(crypto, dss_verify, 4) ->
+ {deprecated, {crypto, verify, 4}};
+
+obsolete_1(crypto, mod_exp, 3) ->
+ {deprecated, {crypto, mod_pow, 3}};
+
+obsolete_1(crypto, dh_compute_key, 3) ->
+ {deprecated, {crypto, compute_key, 4}};
+obsolete_1(crypto, dh_generate_key, 1) ->
+ {deprecated, {crypto, generate_key, 3}};
+obsolete_1(crypto, dh_generate_key, 2) ->
+ {deprecated, {crypto, generate_key, 3}};
+
+obsolete_1(crypto, des_cbc_encrypt, 3) ->
+ {deprecated, {crypto, block_encrypt, 4}};
+obsolete_1(crypto, des3_cbc_encrypt, 5) ->
+ {deprecated, {crypto, block_encrypt, 4}};
+obsolete_1(crypto, des_ecb_encrypt, 3) ->
+ {deprecated, {crypto, block_encrypt, 4}};
+obsolete_1(crypto, des_ede3_cbc_encrypt, 5) ->
+ {deprecated, {crypto, block_encrypt, 4}};
+obsolete_1(crypto, des_cfb_encrypt, 3) ->
+ {deprecated, {crypto, block_encrypt, 4}};
+obsolete_1(crypto, des3_cfb_encrypt, 5) ->
+ {deprecated, {crypto, block_encrypt, 4}};
+obsolete_1(crypto, blowfish_ecb_encrypt, 2) ->
+ {deprecated, {crypto, block_encrypt, 3}};
+obsolete_1(crypto, blowfish_cbc_encrypt, 3) ->
+ {deprecated, {crypto, block_encrypt, 4}};
+obsolete_1(crypto, blowfish_cfb64_encrypt, 3) ->
+ {deprecated, {crypto, block_encrypt, 4}};
+obsolete_1(crypto, blowfish_ofb64_encrypt, 3) ->
+ {deprecated, {crypto, block_encrypt, 4}};
+obsolete_1(crypto, aes_cfb_128_encrypt, 3) ->
+ {deprecated, {crypto, block_encrypt, 4}};
+obsolete_1(crypto, aes_cbc_256_encrypt, 3) ->
+ {deprecated, {crypto, block_encrypt, 4}};
+obsolete_1(crypto,rc2_cbc_encrypt, 3) ->
+ {deprecated, {crypto, block_encrypt, 4}};
+obsolete_1(crypto,rc2_40_cbc_encrypt, 3) ->
+ {deprecated, {crypto, block_encrypt, 4}};
+
+obsolete_1(crypto, des_cbc_decrypt, 3) ->
+ {deprecated, {crypto, block_decrypt, 4}};
+obsolete_1(crypto, des3_cbc_decrypt, 5) ->
+ {deprecated, {crypto, block_decrypt, 4}};
+obsolete_1(crypto, des_ecb_decrypt, 3) ->
+ {deprecated, {crypto, block_decrypt, 4}};
+obsolete_1(crypto, des_ede3_cbc_decrypt, 5) ->
+ {deprecated, {crypto, block_decrypt, 4}};
+obsolete_1(crypto, des_cfb_decrypt, 3) ->
+ {deprecated, {crypto, block_decrypt, 4}};
+obsolete_1(crypto, des3_cfb_decrypt, 5) ->
+ {deprecated, {crypto, block_decrypt, 4}};
+obsolete_1(crypto, blowfish_ecb_decrypt, 2) ->
+ {deprecated, {crypto, block_decrypt, 3}};
+obsolete_1(crypto, blowfish_cbc_decrypt, 3) ->
+ {deprecated, {crypto, block_decrypt, 4}};
+obsolete_1(crypto, blowfish_cfb64_decrypt, 3) ->
+ {deprecated, {crypto, block_decrypt, 4}};
+obsolete_1(crypto, blowfish_ofb64_decrypt, 3) ->
+ {deprecated, {crypto, block_decrypt, 4}};
+obsolete_1(crypto, aes_cfb_128_decrypt, 3) ->
+ {deprecated, {crypto, block_decrypt, 4}};
+obsolete_1(crypto, aes_cbc_256_decrypt, 3) ->
+ {deprecated, {crypto, block_decrypt, 4}};
+obsolete_1(crypto,rc2_cbc_decrypt, 3) ->
+ {deprecated, {crypto, block_decrypt, 4}};
+obsolete_1(crypto,rc2_40_cbc_decrypt, 3) ->
+ {deprecated, {crypto, block_decrypt, 4}};
+
+obsolete_1(crypto,info, 0) ->
+ {deprecated, {crypto, module_info, 0}};
+
+obsolete_1(crypto, strong_rand_mpint, 3) ->
+ {deprecated, "needed only by deprecated functions"};
+obsolete_1(crypto, erlint, 3) ->
+ {deprecated, "needed only by deprecated functions"};
+obsolete_1(crypto, mpint, 3) ->
+ {deprecated, "needed only by deprecated functions"};
+
%% *** SNMP ***
obsolete_1(snmp, N, A) ->
diff --git a/lib/stdlib/src/supervisor.erl b/lib/stdlib/src/supervisor.erl
index 9f93747c3e..54328cd9ff 100644
--- a/lib/stdlib/src/supervisor.erl
+++ b/lib/stdlib/src/supervisor.erl
@@ -63,7 +63,9 @@
%%--------------------------------------------------------------------------
-record(child, {% pid is undefined when child is not running
- pid = undefined :: child() | {restarting,pid()} | [pid()],
+ pid = undefined :: child()
+ | {restarting, pid() | undefined}
+ | [pid()],
name :: child_id(),
mfargs :: mfargs(),
restart_type :: restart(),
@@ -752,6 +754,9 @@ restart(Child, State) ->
end,
timer:apply_after(0,?MODULE,try_again_restart,[self(),Id]),
{ok,NState2};
+ {try_again, NState2, #child{name=ChName}} ->
+ timer:apply_after(0,?MODULE,try_again_restart,[self(),ChName]),
+ {ok,NState2};
Other ->
Other
end;
@@ -798,10 +803,16 @@ restart(rest_for_one, Child, State) ->
case start_children(ChAfter2, State#state.name) of
{ok, ChAfter3} ->
{ok, State#state{children = ChAfter3 ++ ChBefore}};
- {error, ChAfter3, _Reason} ->
+ {error, ChAfter3, {failed_to_start_child, ChName, _Reason}}
+ when ChName =:= Child#child.name ->
NChild = Child#child{pid=restarting(Child#child.pid)},
NState = State#state{children = ChAfter3 ++ ChBefore},
- {try_again, replace_child(NChild,NState)}
+ {try_again, replace_child(NChild,NState)};
+ {error, ChAfter3, {failed_to_start_child, ChName, _Reason}} ->
+ NChild = lists:keyfind(ChName, #child.name, ChAfter3),
+ NChild2 = NChild#child{pid=?restarting(undefined)},
+ NState = State#state{children = ChAfter3 ++ ChBefore},
+ {try_again, replace_child(NChild2,NState), NChild2}
end;
restart(one_for_all, Child, State) ->
Children1 = del_child(Child#child.pid, State#state.children),
@@ -809,10 +820,16 @@ restart(one_for_all, Child, State) ->
case start_children(Children2, State#state.name) of
{ok, NChs} ->
{ok, State#state{children = NChs}};
- {error, NChs, _Reason} ->
+ {error, NChs, {failed_to_start_child, ChName, _Reason}}
+ when ChName =:= Child#child.name ->
NChild = Child#child{pid=restarting(Child#child.pid)},
NState = State#state{children = NChs},
- {try_again, replace_child(NChild,NState)}
+ {try_again, replace_child(NChild,NState)};
+ {error, NChs, {failed_to_start_child, ChName, _Reason}} ->
+ NChild = lists:keyfind(ChName, #child.name, NChs),
+ NChild2 = NChild#child{pid=?restarting(undefined)},
+ NState = State#state{children = NChs},
+ {try_again, replace_child(NChild2,NState), NChild2}
end.
restarting(Pid) when is_pid(Pid) -> ?restarting(Pid);
diff --git a/lib/stdlib/src/timer.erl b/lib/stdlib/src/timer.erl
index 689e42051f..e11fb046e9 100644
--- a/lib/stdlib/src/timer.erl
+++ b/lib/stdlib/src/timer.erl
@@ -354,7 +354,7 @@ timer_timeout(SysTime) ->
'$end_of_table' ->
infinity;
{Time, _Ref} when Time > SysTime ->
- Timeout = (Time - SysTime) div 1000,
+ Timeout = (Time - SysTime + 999) div 1000,
%% Returned timeout must fit in a small int
erlang:min(Timeout, ?MAX_TIMEOUT);
Key ->
@@ -414,7 +414,7 @@ next_timeout() ->
'$end_of_table' ->
infinity;
{Time, _} ->
- erlang:min(positive((Time - system_time()) div 1000), ?MAX_TIMEOUT)
+ erlang:min(positive((Time - system_time() + 999) div 1000), ?MAX_TIMEOUT)
end.
%% Help functions
diff --git a/lib/stdlib/test/Makefile b/lib/stdlib/test/Makefile
index 6aa09d7bd0..af82f22b21 100644
--- a/lib/stdlib/test/Makefile
+++ b/lib/stdlib/test/Makefile
@@ -66,6 +66,7 @@ MODULES= \
string_SUITE \
supervisor_1 \
supervisor_2 \
+ supervisor_3 \
supervisor_deadlock \
naughty_child \
shell_SUITE \
diff --git a/lib/stdlib/test/dets_SUITE.erl b/lib/stdlib/test/dets_SUITE.erl
index 065b74ad41..8ff7c3ccc9 100644
--- a/lib/stdlib/test/dets_SUITE.erl
+++ b/lib/stdlib/test/dets_SUITE.erl
@@ -33,8 +33,6 @@
-define(datadir(Conf), ?config(data_dir, Conf)).
-endif.
--compile(r13). % OTP-9607
-
-export([all/0, suite/0,groups/0,init_per_suite/1, end_per_suite/1,
init_per_group/2,end_per_group/2,
newly_started/1, basic_v8/1, basic_v9/1,
@@ -54,7 +52,7 @@
simultaneous_open/1, insert_new/1, repair_continuation/1,
otp_5487/1, otp_6206/1, otp_6359/1, otp_4738/1, otp_7146/1,
otp_8070/1, otp_8856/1, otp_8898/1, otp_8899/1, otp_8903/1,
- otp_8923/1, otp_9282/1, otp_9607/1]).
+ otp_8923/1, otp_9282/1]).
-export([dets_dirty_loop/0]).
@@ -111,7 +109,7 @@ all() ->
many_clients, otp_4906, otp_5402, simultaneous_open,
insert_new, repair_continuation, otp_5487, otp_6206,
otp_6359, otp_4738, otp_7146, otp_8070, otp_8856, otp_8898,
- otp_8899, otp_8903, otp_8923, otp_9282, otp_9607
+ otp_8899, otp_8903, otp_8923, otp_9282
].
groups() ->
@@ -3899,77 +3897,6 @@ some_calls(Tab, Config) ->
ok = dets:close(T),
file:delete(File).
-otp_9607(doc) ->
- ["OTP-9607. Test downgrading the slightly changed format."];
-otp_9607(suite) ->
- [];
-otp_9607(Config) when is_list(Config) ->
- %% Note: the bug is about almost full tables. The fix of that
- %% problem is *not* tested here.
- Version = r13b,
- case ?t:is_release_available(atom_to_list(Version)) of
- true ->
- T = otp_9607,
- File = filename(T, Config),
- Key = a,
- Value = 1,
- Args = [{file,File}],
- {ok, T} = dets:open_file(T, Args),
- ok = dets:insert(T, {Key, Value}),
- ok = dets:close(T),
-
- Call = fun(P, A) ->
- P ! {self(), A},
- receive
- {P, Ans} ->
- Ans
- after 5000 ->
- exit(other_process_dead)
- end
- end,
- %% Create a file on the modified format, read the file
- %% with an emulator that doesn't know about the modified
- %% format.
- {ok, Node} = start_node_rel(Version, Version, slave),
- Pid = rpc:call(Node, erlang, spawn,
- [?MODULE, dets_dirty_loop, []]),
- {error,{needs_repair, File}} =
- Call(Pid, [open, T, Args++[{repair,false}]]),
- io:format("Expect repair:~n"),
- {ok, T} = Call(Pid, [open, T, Args]),
- [{Key,Value}] = Call(Pid, [read, T, Key]),
- ok = Call(Pid, [close, T]),
- file:delete(File),
-
- %% Create a file on the unmodified format. Modify the file
- %% using an emulator that must not turn the file into the
- %% modified format. Read the file and make sure it is not
- %% repaired.
- {ok, T} = Call(Pid, [open, T, Args]),
- ok = Call(Pid, [write, T, {Key,Value}]),
- [{Key,Value}] = Call(Pid, [read, T, Key]),
- ok = Call(Pid, [close, T]),
-
- Key2 = b,
- Value2 = 2,
-
- {ok, T} = dets:open_file(T, Args),
- [{Key,Value}] = dets:lookup(T, Key),
- ok = dets:insert(T, {Key2,Value2}),
- ok = dets:close(T),
-
- {ok, T} = Call(Pid, [open, T, Args++[{repair,false}]]),
- [{Key2,Value2}] = Call(Pid, [read, T, Key2]),
- ok = Call(Pid, [close, T]),
-
- ?t:stop_node(Node),
- file:delete(File),
- ok;
- false ->
- {skipped, "No support for old node"}
- end.
-
-
%%
%% Parts common to several test cases
diff --git a/lib/stdlib/test/epp_SUITE.erl b/lib/stdlib/test/epp_SUITE.erl
index b2f1aa955a..0cbdf76270 100644
--- a/lib/stdlib/test/epp_SUITE.erl
+++ b/lib/stdlib/test/epp_SUITE.erl
@@ -104,6 +104,8 @@ include_local(suite) ->
include_local(Config) when is_list(Config) ->
?line DataDir = ?config(data_dir, Config),
?line File = filename:join(DataDir, "include_local.erl"),
+ FooHrl = filename:join([DataDir,"include","foo.hrl"]),
+ BarHrl = filename:join([DataDir,"include","bar.hrl"]),
%% include_local.erl includes include/foo.hrl which
%% includes bar.hrl (also in include/) without requiring
%% any additional include path, and overriding any file
@@ -111,6 +113,8 @@ include_local(Config) when is_list(Config) ->
?line {ok, List} = epp:parse_file(File, [DataDir], []),
?line {value, {attribute,_,a,{true,true}}} =
lists:keysearch(a,3,List),
+ [{File,1},{FooHrl,1},{BarHrl,1},{FooHrl,5},{File,5}] =
+ [ FileLine || {attribute,_,file,FileLine} <- List ],
ok.
%%% Here is a little reimplementation of epp:parse_file, which times out
diff --git a/lib/stdlib/test/erl_eval_SUITE.erl b/lib/stdlib/test/erl_eval_SUITE.erl
index 7ff4c81ea6..18ec17a4bf 100644
--- a/lib/stdlib/test/erl_eval_SUITE.erl
+++ b/lib/stdlib/test/erl_eval_SUITE.erl
@@ -1,3 +1,4 @@
+%% -*- coding: utf-8 -*-
%%
%% %CopyrightBegin%
%%
@@ -992,7 +993,7 @@ otp_10622(Config) when is_list(Config) ->
<<0>>),
check(fun() -> <<"\x{aa}ff"/utf8>> = <<"\x{aa}ff"/utf8>> end,
"<<\"\\x{aa}ff\"/utf8>> = <<\"\\x{aa}ff\"/utf8>>. ",
- <<"�\xaaff">>),
+ <<"Â\xaaff">>),
%% The same bug as last example:
check(fun() -> case <<"foo"/utf8>> of
<<"foo"/utf8>> -> true
diff --git a/lib/stdlib/test/ets_SUITE.erl b/lib/stdlib/test/ets_SUITE.erl
index d40609eeb0..bd69019892 100644
--- a/lib/stdlib/test/ets_SUITE.erl
+++ b/lib/stdlib/test/ets_SUITE.erl
@@ -75,6 +75,7 @@
-export([otp_9932/1]).
-export([otp_9423/1]).
-export([otp_10182/1]).
+-export([memory_check_summary/1]).
-export([init_per_testcase/2, end_per_testcase/2]).
%% Convenience for manual testing
@@ -149,7 +150,9 @@ all() ->
give_away, setopts, bad_table, types,
otp_10182,
otp_9932,
- otp_9423].
+ otp_9423,
+
+ memory_check_summary]. % MUST BE LAST
groups() ->
[{new, [],
@@ -185,7 +188,8 @@ init_per_suite(Config) ->
end_per_suite(_Config) ->
stop_spawn_logger(),
- catch erts_debug:set_internal_state(available_internal_state, false).
+ catch erts_debug:set_internal_state(available_internal_state, false),
+ ok.
init_per_group(_GroupName, Config) ->
Config.
@@ -193,6 +197,26 @@ init_per_group(_GroupName, Config) ->
end_per_group(_GroupName, Config) ->
Config.
+%% Test that we did not have "too many" failed verify_etsmem()'s
+%% in the test suite.
+%% verify_etsmem() may give a low number of false positives
+%% as concurrent activities, such as lingering processes
+%% from earlier test suites, may do unrelated ets (de)allocations.
+memory_check_summary(_Config) ->
+ case whereis(ets_test_spawn_logger) of
+ undefined ->
+ ?t:fail("No spawn logger exist");
+ _ ->
+ ets_test_spawn_logger ! {self(), get_failed_memchecks},
+ receive {get_failed_memchecks, FailedMemchecks} -> ok end,
+ io:format("Failed memchecks: ~p\n",[FailedMemchecks]),
+ if FailedMemchecks > 3 ->
+ ct:fail("Too many failed (~p) memchecks", [FailedMemchecks]);
+ true ->
+ ok
+ end
+ end.
+
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
@@ -3268,15 +3292,14 @@ delete_large_named_table_1(Name, Flags, Data, Fix) ->
end,
Parent = self(),
{Pid, MRef} = my_spawn_opt(fun() ->
- receive
- {trace,Parent,call,_} ->
- ets_new(Name, [named_table])
- end
- end, [link, monitor]),
- ?line erlang:trace(self(), true, [call,{tracer,Pid}]),
- ?line erlang:trace_pattern({ets,delete,1}, true, [global]),
- ?line erlang:yield(), true = ets:delete(Tab),
- ?line erlang:trace_pattern({ets,delete,1}, false, [global]),
+ receive
+ ets_new ->
+ ets_new(Name, [named_table])
+ end
+ end,
+ [link, monitor]),
+ true = ets:delete(Tab),
+ Pid ! ets_new,
receive {'DOWN',MRef,process,Pid,_} -> ok end,
ok.
@@ -5636,7 +5659,8 @@ verify_etsmem({MemInfo,AllTabs}) ->
io:format("Actual: ~p", [MemInfo2]),
io:format("Changed tables before: ~p\n",[AllTabs -- AllTabs2]),
io:format("Changed tables after: ~p\n", [AllTabs2 -- AllTabs]),
- ?t:fail()
+ ets_test_spawn_logger ! failed_memcheck,
+ {comment, "Failed memory check"}
end.
@@ -5658,10 +5682,10 @@ stop_loopers(Loopers) ->
looper(Fun, State) ->
looper(Fun, Fun(State)).
-spawn_logger(Procs) ->
+spawn_logger(Procs, FailedMemchecks) ->
receive
{new_test_proc, Proc} ->
- spawn_logger([Proc|Procs]);
+ spawn_logger([Proc|Procs], FailedMemchecks);
{sync_test_procs, Kill, From} ->
lists:foreach(fun (Proc) when From == Proc ->
ok;
@@ -5684,7 +5708,14 @@ spawn_logger(Procs) ->
end
end, Procs),
From ! test_procs_synced,
- spawn_logger([From])
+ spawn_logger([From], FailedMemchecks);
+
+ failed_memcheck ->
+ spawn_logger(Procs, FailedMemchecks+1);
+
+ {Pid, get_failed_memchecks} ->
+ Pid ! {get_failed_memchecks, FailedMemchecks},
+ spawn_logger(Procs, FailedMemchecks)
end.
pid_status(Pid) ->
@@ -5700,7 +5731,7 @@ start_spawn_logger() ->
case whereis(ets_test_spawn_logger) of
Pid when is_pid(Pid) -> true;
_ -> register(ets_test_spawn_logger,
- spawn_opt(fun () -> spawn_logger([]) end,
+ spawn_opt(fun () -> spawn_logger([], 0) end,
[{priority, max}]))
end.
@@ -5711,8 +5742,7 @@ start_spawn_logger() ->
stop_spawn_logger() ->
Mon = erlang:monitor(process, ets_test_spawn_logger),
(catch exit(whereis(ets_test_spawn_logger), kill)),
- receive {'DOWN', Mon, _, _, _} -> ok end,
- ok.
+ receive {'DOWN', Mon, _, _, _} -> ok end.
wait_for_test_procs() ->
wait_for_test_procs(false).
@@ -5812,7 +5842,7 @@ spawn_monitor_with_pid(Pid, Fun, N) ->
end) of
Pid ->
{Pid, erlang:monitor(process, Pid)};
- Other ->
+ _Other ->
spawn_monitor_with_pid(Pid,Fun,N-1)
end.
@@ -6118,11 +6148,18 @@ repeat_for_opts(F, OptGenList) ->
repeat_for_opts(F, OptGenList, []).
repeat_for_opts(F, [], Acc) ->
- lists:map(fun(Opts) ->
- OptList = lists:filter(fun(E) -> E =/= void end, Opts),
- io:format("Calling with options ~p\n",[OptList]),
- F(OptList)
- end, Acc);
+ lists:foldl(fun(Opts, RV_Acc) ->
+ OptList = lists:filter(fun(E) -> E =/= void end, Opts),
+ io:format("Calling with options ~p\n",[OptList]),
+ RV = F(OptList),
+ case RV_Acc of
+ {comment,_} -> RV_Acc;
+ _ -> case RV of
+ {comment,_} -> RV;
+ _ -> [RV | RV_Acc]
+ end
+ end
+ end, [], Acc);
repeat_for_opts(F, [OptList | Tail], []) when is_list(OptList) ->
repeat_for_opts(F, Tail, [[Opt] || Opt <- OptList]);
repeat_for_opts(F, [OptList | Tail], AccList) when is_list(OptList) ->
diff --git a/lib/stdlib/test/lists_SUITE.erl b/lib/stdlib/test/lists_SUITE.erl
index b56f0b39d8..cd7210f8ec 100644
--- a/lib/stdlib/test/lists_SUITE.erl
+++ b/lib/stdlib/test/lists_SUITE.erl
@@ -2532,8 +2532,8 @@ otp_5939(Config) when is_list(Config) ->
?line [] = lists:filter(Pred, []),
?line {'EXIT', _} = (catch lists:partition(func, [])),
?line {[],[]} = lists:partition(Pred, []),
- ?line {'EXIT', _} = (catch lists:zf(func, [])),
- ?line [] = lists:zf(Fun1, []),
+ ?line {'EXIT', _} = (catch lists:filtermap(func, [])),
+ ?line [] = lists:filtermap(Fun1, []),
?line {'EXIT', _} = (catch lists:foreach(func, [])),
?line ok = lists:foreach(Fun1, []),
?line {'EXIT', _} = (catch lists:mapfoldl(func, [], [])),
diff --git a/lib/stdlib/test/qlc_SUITE_data/join_info_compat.erl b/lib/stdlib/test/qlc_SUITE_data/join_info_compat.erl
index e0db132c47..b93b907392 100644
--- a/lib/stdlib/test/qlc_SUITE_data/join_info_compat.erl
+++ b/lib/stdlib/test/qlc_SUITE_data/join_info_compat.erl
@@ -1,3 +1,4 @@
+%% -*- coding: utf-8 -*-
%%
%% %CopyrightBegin%
%%
@@ -515,7 +516,7 @@ create_handle() ->
$.:8/integer-unit:1-unsigned-big,
$x:8/integer-unit:1-unsigned-big,
$\234:8/integer-unit:1-unsigned-big,
- $�:8/integer-unit:1-unsigned-big,
+ $Ë:8/integer-unit:1-unsigned-big,
$`:8/integer-unit:1-unsigned-big,
$N:8/integer-unit:1-unsigned-big,
$a:8/integer-unit:1-unsigned-big,
@@ -523,16 +524,16 @@ create_handle() ->
$-:8/integer-unit:1-unsigned-big,
$):8/integer-unit:1-unsigned-big,
$-:8/integer-unit:1-unsigned-big,
- $�:8/integer-unit:1-unsigned-big,
+ $È:8/integer-unit:1-unsigned-big,
$I:8/integer-unit:1-unsigned-big,
$M:8/integer-unit:1-unsigned-big,
- $�:8/integer-unit:1-unsigned-big,
- $�:8/integer-unit:1-unsigned-big,
+ $ä:8/integer-unit:1-unsigned-big,
+ $Ê:8/integer-unit:1-unsigned-big,
$a:8/integer-unit:1-unsigned-big,
$`:8/integer-unit:1-unsigned-big,
$`:8/integer-unit:1-unsigned-big,
$`:8/integer-unit:1-unsigned-big,
- $�:8/integer-unit:1-unsigned-big,
+ $Ê:8/integer-unit:1-unsigned-big,
$\000:8/integer-unit:1-unsigned-big,
$\n:8/integer-unit:1-unsigned-big,
$0:8/integer-unit:1-unsigned-big,
@@ -541,19 +542,19 @@ create_handle() ->
$\026:8/integer-unit:1-unsigned-big,
$%:8/integer-unit:1-unsigned-big,
$r:8/integer-unit:1-unsigned-big,
- $�:8/integer-unit:1-unsigned-big,
+ $¥:8/integer-unit:1-unsigned-big,
$0:8/integer-unit:1-unsigned-big,
$0:8/integer-unit:1-unsigned-big,
$F:8/integer-unit:1-unsigned-big,
- $�:8/integer-unit:1-unsigned-big,
- $�:8/integer-unit:1-unsigned-big,
+ $ :8/integer-unit:1-unsigned-big,
+ $ð:8/integer-unit:1-unsigned-big,
$":8/integer-unit:1-unsigned-big,
- $�:8/integer-unit:1-unsigned-big,
+ $³:8/integer-unit:1-unsigned-big,
$\000:8/integer-unit:1-unsigned-big,
- $�:8/integer-unit:1-unsigned-big,
- $�:8/integer-unit:1-unsigned-big,
+ $þ:8/integer-unit:1-unsigned-big,
+ $Ì:8/integer-unit:1-unsigned-big,
$\n:8/integer-unit:1-unsigned-big,
- $�:8/integer-unit:1-unsigned-big>>,
+ $É:8/integer-unit:1-unsigned-big>>,
<<$\203:8/integer-unit:1-unsigned-big,
$P:8/integer-unit:1-unsigned-big,
$\000:8/integer-unit:1-unsigned-big,
@@ -562,7 +563,7 @@ create_handle() ->
$<:8/integer-unit:1-unsigned-big,
$x:8/integer-unit:1-unsigned-big,
$\234:8/integer-unit:1-unsigned-big,
- $�:8/integer-unit:1-unsigned-big,
+ $Ë:8/integer-unit:1-unsigned-big,
$`:8/integer-unit:1-unsigned-big,
$N:8/integer-unit:1-unsigned-big,
$a:8/integer-unit:1-unsigned-big,
@@ -570,16 +571,16 @@ create_handle() ->
$-:8/integer-unit:1-unsigned-big,
$):8/integer-unit:1-unsigned-big,
$-:8/integer-unit:1-unsigned-big,
- $�:8/integer-unit:1-unsigned-big,
+ $È:8/integer-unit:1-unsigned-big,
$I:8/integer-unit:1-unsigned-big,
$M:8/integer-unit:1-unsigned-big,
- $�:8/integer-unit:1-unsigned-big,
- $�:8/integer-unit:1-unsigned-big,
+ $ä:8/integer-unit:1-unsigned-big,
+ $Ê:8/integer-unit:1-unsigned-big,
$a:8/integer-unit:1-unsigned-big,
$`:8/integer-unit:1-unsigned-big,
$`:8/integer-unit:1-unsigned-big,
$`:8/integer-unit:1-unsigned-big,
- $�:8/integer-unit:1-unsigned-big,
+ $Î:8/integer-unit:1-unsigned-big,
$\000:8/integer-unit:1-unsigned-big,
$\n:8/integer-unit:1-unsigned-big,
$0:8/integer-unit:1-unsigned-big,
@@ -588,22 +589,22 @@ create_handle() ->
$\026:8/integer-unit:1-unsigned-big,
$%:8/integer-unit:1-unsigned-big,
$r:8/integer-unit:1-unsigned-big,
- $�:8/integer-unit:1-unsigned-big,
+ $¥:8/integer-unit:1-unsigned-big,
$0:8/integer-unit:1-unsigned-big,
$0:8/integer-unit:1-unsigned-big,
$::8/integer-unit:1-unsigned-big,
- $�:8/integer-unit:1-unsigned-big,
- $�:8/integer-unit:1-unsigned-big,
+ $¡:8/integer-unit:1-unsigned-big,
+ $ð:8/integer-unit:1-unsigned-big,
$":8/integer-unit:1-unsigned-big,
$P:8/integer-unit:1-unsigned-big,
$x:8/integer-unit:1-unsigned-big,
- $�:8/integer-unit:1-unsigned-big,
+ $ñ:8/integer-unit:1-unsigned-big,
$Y:8/integer-unit:1-unsigned-big,
$\000:8/integer-unit:1-unsigned-big,
- $�:8/integer-unit:1-unsigned-big,
+ $ª:8/integer-unit:1-unsigned-big,
$9:8/integer-unit:1-unsigned-big,
$\r:8/integer-unit:1-unsigned-big,
- $�:8/integer-unit:1-unsigned-big>>,
+ $ý:8/integer-unit:1-unsigned-big>>,
<<$\203:8/integer-unit:1-unsigned-big,
$P:8/integer-unit:1-unsigned-big,
$\000:8/integer-unit:1-unsigned-big,
@@ -612,51 +613,51 @@ create_handle() ->
$I:8/integer-unit:1-unsigned-big,
$x:8/integer-unit:1-unsigned-big,
$\234:8/integer-unit:1-unsigned-big,
- $�:8/integer-unit:1-unsigned-big,
+ $Ë:8/integer-unit:1-unsigned-big,
$`:8/integer-unit:1-unsigned-big,
$M:8/integer-unit:1-unsigned-big,
$a:8/integer-unit:1-unsigned-big,
$`:8/integer-unit:1-unsigned-big,
- $�:8/integer-unit:1-unsigned-big,
+ $Ê:8/integer-unit:1-unsigned-big,
$/:8/integer-unit:1-unsigned-big,
$H:8/integer-unit:1-unsigned-big,
- $�:8/integer-unit:1-unsigned-big,
+ $ä:8/integer-unit:1-unsigned-big,
$N:8/integer-unit:1-unsigned-big,
$a:8/integer-unit:1-unsigned-big,
$`:8/integer-unit:1-unsigned-big,
- $�:8/integer-unit:1-unsigned-big,
- $�:8/integer-unit:1-unsigned-big,
- $�:8/integer-unit:1-unsigned-big,
- $�:8/integer-unit:1-unsigned-big,
+ $¶:8/integer-unit:1-unsigned-big,
+ $µ:8/integer-unit:1-unsigned-big,
+ $²:8/integer-unit:1-unsigned-big,
+ $Í:8/integer-unit:1-unsigned-big,
$`:8/integer-unit:1-unsigned-big,
$\006:8/integer-unit:1-unsigned-big,
- $�:8/integer-unit:1-unsigned-big,
+ $Ò:8/integer-unit:1-unsigned-big,
$e:8/integer-unit:1-unsigned-big,
$\211:8/integer-unit:1-unsigned-big,
$E:8/integer-unit:1-unsigned-big,
$\s:8/integer-unit:1-unsigned-big,
$>:8/integer-unit:1-unsigned-big,
- $�:8/integer-unit:1-unsigned-big,
+ $£:8/integer-unit:1-unsigned-big,
$\023:8/integer-unit:1-unsigned-big,
$\210:8/integer-unit:1-unsigned-big,
- $�:8/integer-unit:1-unsigned-big,
+ $Ç:8/integer-unit:1-unsigned-big,
$\232:8/integer-unit:1-unsigned-big,
$\226:8/integer-unit:1-unsigned-big,
$\223:8/integer-unit:1-unsigned-big,
$\237:8/integer-unit:1-unsigned-big,
$X:8/integer-unit:1-unsigned-big,
$\222:8/integer-unit:1-unsigned-big,
- $�:8/integer-unit:1-unsigned-big,
+ $È:8/integer-unit:1-unsigned-big,
$\235:8/integer-unit:1-unsigned-big,
$l:8/integer-unit:1-unsigned-big,
- $�:8/integer-unit:1-unsigned-big,
+ $¨:8/integer-unit:1-unsigned-big,
$g:8/integer-unit:1-unsigned-big,
$i:8/integer-unit:1-unsigned-big,
$d:8/integer-unit:1-unsigned-big,
$\200:8/integer-unit:1-unsigned-big,
$\001:8/integer-unit:1-unsigned-big,
$R:8/integer-unit:1-unsigned-big,
- $�:8/integer-unit:1-unsigned-big,
+ $µ:8/integer-unit:1-unsigned-big,
$\r:8/integer-unit:1-unsigned-big,
$\214:8/integer-unit:1-unsigned-big,
$\030:8/integer-unit:1-unsigned-big,
@@ -664,7 +665,7 @@ create_handle() ->
$\000:8/integer-unit:1-unsigned-big,
$\000:8/integer-unit:1-unsigned-big,
$c:8/integer-unit:1-unsigned-big,
- $�:8/integer-unit:1-unsigned-big,
+ $Ö:8/integer-unit:1-unsigned-big,
$\017:8/integer-unit:1-unsigned-big,
$=:8/integer-unit:1-unsigned-big>>,
<<$\203:8/integer-unit:1-unsigned-big,
@@ -708,24 +709,24 @@ create_handle() ->
$*:8/integer-unit:1-unsigned-big,
$x:8/integer-unit:1-unsigned-big,
$\234:8/integer-unit:1-unsigned-big,
- $�:8/integer-unit:1-unsigned-big,
+ $Ë:8/integer-unit:1-unsigned-big,
$`:8/integer-unit:1-unsigned-big,
$M:8/integer-unit:1-unsigned-big,
$a:8/integer-unit:1-unsigned-big,
$`:8/integer-unit:1-unsigned-big,
- $�:8/integer-unit:1-unsigned-big,
+ $Ê:8/integer-unit:1-unsigned-big,
$/:8/integer-unit:1-unsigned-big,
$H:8/integer-unit:1-unsigned-big,
- $�:8/integer-unit:1-unsigned-big,
+ $ä:8/integer-unit:1-unsigned-big,
$\005:8/integer-unit:1-unsigned-big,
$R:8/integer-unit:1-unsigned-big,
- $�:8/integer-unit:1-unsigned-big,
- $�:8/integer-unit:1-unsigned-big,
+ $¶:8/integer-unit:1-unsigned-big,
+ $¶:8/integer-unit:1-unsigned-big,
$\031:8/integer-unit:1-unsigned-big,
- $�:8/integer-unit:1-unsigned-big,
+ $Ì:8/integer-unit:1-unsigned-big,
$):8/integer-unit:1-unsigned-big,
$\f:8/integer-unit:1-unsigned-big,
- $�:8/integer-unit:1-unsigned-big,
+ $Ì:8/integer-unit:1-unsigned-big,
$e:8/integer-unit:1-unsigned-big,
$\211:8/integer-unit:1-unsigned-big,
$E:8/integer-unit:1-unsigned-big,
@@ -737,7 +738,7 @@ create_handle() ->
$/:8/integer-unit:1-unsigned-big,
$\022:8/integer-unit:1-unsigned-big,
$\000:8/integer-unit:1-unsigned-big,
- $�:8/integer-unit:1-unsigned-big,
+ $Ì:8/integer-unit:1-unsigned-big,
$\205:8/integer-unit:1-unsigned-big,
$\t:8/integer-unit:1-unsigned-big,
$\216:8/integer-unit:1-unsigned-big>>,
@@ -749,33 +750,33 @@ create_handle() ->
$j:8/integer-unit:1-unsigned-big,
$x:8/integer-unit:1-unsigned-big,
$\234:8/integer-unit:1-unsigned-big,
- $�:8/integer-unit:1-unsigned-big,
+ $Ë:8/integer-unit:1-unsigned-big,
$`:8/integer-unit:1-unsigned-big,
$I:8/integer-unit:1-unsigned-big,
$a:8/integer-unit:1-unsigned-big,
$`:8/integer-unit:1-unsigned-big,
$I:8/integer-unit:1-unsigned-big,
- $�:8/integer-unit:1-unsigned-big,
- $�:8/integer-unit:1-unsigned-big,
+ $Î:8/integer-unit:1-unsigned-big,
+ $Ï:8/integer-unit:1-unsigned-big,
$+:8/integer-unit:1-unsigned-big,
$N:8/integer-unit:1-unsigned-big,
- $�:8/integer-unit:1-unsigned-big,
- $�:8/integer-unit:1-unsigned-big,
- $�:8/integer-unit:1-unsigned-big,
- $�:8/integer-unit:1-unsigned-big,
- $�:8/integer-unit:1-unsigned-big,
+ $ú:8/integer-unit:1-unsigned-big,
+ $ÿ:8/integer-unit:1-unsigned-big,
+ $ÿ:8/integer-unit:1-unsigned-big,
+ $ÿ:8/integer-unit:1-unsigned-big,
+ $·:8/integer-unit:1-unsigned-big,
$\f:8/integer-unit:1-unsigned-big,
- $�:8/integer-unit:1-unsigned-big,
+ $æ:8/integer-unit:1-unsigned-big,
$\024:8/integer-unit:1-unsigned-big,
$\006:8/integer-unit:1-unsigned-big,
- $�:8/integer-unit:1-unsigned-big,
+ $Ö:8/integer-unit:1-unsigned-big,
$\222:8/integer-unit:1-unsigned-big,
- $�:8/integer-unit:1-unsigned-big,
+ $Ò:8/integer-unit:1-unsigned-big,
$\202:8/integer-unit:1-unsigned-big,
$\234:8/integer-unit:1-unsigned-big,
- $�:8/integer-unit:1-unsigned-big,
+ $Ô:8/integer-unit:1-unsigned-big,
$D:8/integer-unit:1-unsigned-big,
- $�:8/integer-unit:1-unsigned-big,
+ $®:8/integer-unit:1-unsigned-big,
$\034:8/integer-unit:1-unsigned-big,
$\006:8/integer-unit:1-unsigned-big,
$\006:8/integer-unit:1-unsigned-big,
@@ -791,7 +792,7 @@ create_handle() ->
$W:8/integer-unit:1-unsigned-big,
$\n:8/integer-unit:1-unsigned-big,
$\003:8/integer-unit:1-unsigned-big,
- $�:8/integer-unit:1-unsigned-big,
+ $£:8/integer-unit:1-unsigned-big,
$\023:8/integer-unit:1-unsigned-big,
$\n:8/integer-unit:1-unsigned-big,
$/:8/integer-unit:1-unsigned-big,
@@ -800,18 +801,18 @@ create_handle() ->
$\027:8/integer-unit:1-unsigned-big,
$\237:8/integer-unit:1-unsigned-big,
$\205:8/integer-unit:1-unsigned-big,
- $�:8/integer-unit:1-unsigned-big,
+ $¤:8/integer-unit:1-unsigned-big,
$\227:8/integer-unit:1-unsigned-big,
$\007:8/integer-unit:1-unsigned-big,
- $�:8/integer-unit:1-unsigned-big,
+ $¤:8/integer-unit:1-unsigned-big,
$\227:8/integer-unit:1-unsigned-big,
$\021:8/integer-unit:1-unsigned-big,
$.:8/integer-unit:1-unsigned-big,
- $�:8/integer-unit:1-unsigned-big,
+ $Ï:8/integer-unit:1-unsigned-big,
$\003:8/integer-unit:1-unsigned-big,
$\224:8/integer-unit:1-unsigned-big,
$\217:8/integer-unit:1-unsigned-big,
- $�:8/integer-unit:1-unsigned-big,
+ $Ì:8/integer-unit:1-unsigned-big,
$\002:8/integer-unit:1-unsigned-big,
$\000:8/integer-unit:1-unsigned-big,
$\203:8/integer-unit:1-unsigned-big,
@@ -1398,7 +1399,7 @@ lookup_handle() ->
$.:8/integer-unit:1-unsigned-big,
$x:8/integer-unit:1-unsigned-big,
$\234:8/integer-unit:1-unsigned-big,
- $�:8/integer-unit:1-unsigned-big,
+ $Ë:8/integer-unit:1-unsigned-big,
$`:8/integer-unit:1-unsigned-big,
$N:8/integer-unit:1-unsigned-big,
$a:8/integer-unit:1-unsigned-big,
@@ -1406,16 +1407,16 @@ lookup_handle() ->
$-:8/integer-unit:1-unsigned-big,
$):8/integer-unit:1-unsigned-big,
$-:8/integer-unit:1-unsigned-big,
- $�:8/integer-unit:1-unsigned-big,
+ $È:8/integer-unit:1-unsigned-big,
$I:8/integer-unit:1-unsigned-big,
$M:8/integer-unit:1-unsigned-big,
$\024:8/integer-unit:1-unsigned-big,
- $�:8/integer-unit:1-unsigned-big,
+ $Ì:8/integer-unit:1-unsigned-big,
$a:8/integer-unit:1-unsigned-big,
$`:8/integer-unit:1-unsigned-big,
$`:8/integer-unit:1-unsigned-big,
$`:8/integer-unit:1-unsigned-big,
- $�:8/integer-unit:1-unsigned-big,
+ $Ê:8/integer-unit:1-unsigned-big,
$\000:8/integer-unit:1-unsigned-big,
$\n:8/integer-unit:1-unsigned-big,
$0:8/integer-unit:1-unsigned-big,
@@ -1424,19 +1425,19 @@ lookup_handle() ->
$\026:8/integer-unit:1-unsigned-big,
$%:8/integer-unit:1-unsigned-big,
$\n:8/integer-unit:1-unsigned-big,
- $�:8/integer-unit:1-unsigned-big,
+ $¦:8/integer-unit:1-unsigned-big,
$0:8/integer-unit:1-unsigned-big,
$0:8/integer-unit:1-unsigned-big,
$F:8/integer-unit:1-unsigned-big,
- $�:8/integer-unit:1-unsigned-big,
- $�:8/integer-unit:1-unsigned-big,
+ $ :8/integer-unit:1-unsigned-big,
+ $ð:8/integer-unit:1-unsigned-big,
$":8/integer-unit:1-unsigned-big,
- $�:8/integer-unit:1-unsigned-big,
+ $³:8/integer-unit:1-unsigned-big,
$\000:8/integer-unit:1-unsigned-big,
$\000:8/integer-unit:1-unsigned-big,
$\206:8/integer-unit:1-unsigned-big,
$\n:8/integer-unit:1-unsigned-big,
- $�:8/integer-unit:1-unsigned-big>>,
+ $Þ:8/integer-unit:1-unsigned-big>>,
<<$\203:8/integer-unit:1-unsigned-big,
$P:8/integer-unit:1-unsigned-big,
$\000:8/integer-unit:1-unsigned-big,
@@ -1445,7 +1446,7 @@ lookup_handle() ->
$.:8/integer-unit:1-unsigned-big,
$x:8/integer-unit:1-unsigned-big,
$\234:8/integer-unit:1-unsigned-big,
- $�:8/integer-unit:1-unsigned-big,
+ $Ë:8/integer-unit:1-unsigned-big,
$`:8/integer-unit:1-unsigned-big,
$N:8/integer-unit:1-unsigned-big,
$a:8/integer-unit:1-unsigned-big,
@@ -1453,16 +1454,16 @@ lookup_handle() ->
$-:8/integer-unit:1-unsigned-big,
$):8/integer-unit:1-unsigned-big,
$-:8/integer-unit:1-unsigned-big,
- $�:8/integer-unit:1-unsigned-big,
+ $È:8/integer-unit:1-unsigned-big,
$I:8/integer-unit:1-unsigned-big,
$M:8/integer-unit:1-unsigned-big,
$\024:8/integer-unit:1-unsigned-big,
- $�:8/integer-unit:1-unsigned-big,
+ $Ì:8/integer-unit:1-unsigned-big,
$a:8/integer-unit:1-unsigned-big,
$`:8/integer-unit:1-unsigned-big,
$`:8/integer-unit:1-unsigned-big,
$`:8/integer-unit:1-unsigned-big,
- $�:8/integer-unit:1-unsigned-big,
+ $Ê:8/integer-unit:1-unsigned-big,
$\000:8/integer-unit:1-unsigned-big,
$\n:8/integer-unit:1-unsigned-big,
$0:8/integer-unit:1-unsigned-big,
@@ -1471,19 +1472,19 @@ lookup_handle() ->
$\026:8/integer-unit:1-unsigned-big,
$%:8/integer-unit:1-unsigned-big,
$\n:8/integer-unit:1-unsigned-big,
- $�:8/integer-unit:1-unsigned-big,
+ $¦:8/integer-unit:1-unsigned-big,
$0:8/integer-unit:1-unsigned-big,
$0:8/integer-unit:1-unsigned-big,
$F:8/integer-unit:1-unsigned-big,
- $�:8/integer-unit:1-unsigned-big,
- $�:8/integer-unit:1-unsigned-big,
- $�:8/integer-unit:1-unsigned-big,
- $�:8/integer-unit:1-unsigned-big,
+ $ :8/integer-unit:1-unsigned-big,
+ $ð:8/integer-unit:1-unsigned-big,
+ $â:8/integer-unit:1-unsigned-big,
+ $³:8/integer-unit:1-unsigned-big,
$\000:8/integer-unit:1-unsigned-big,
$\000:8/integer-unit:1-unsigned-big,
$\222:8/integer-unit:1-unsigned-big,
$\n:8/integer-unit:1-unsigned-big,
- $�:8/integer-unit:1-unsigned-big>>,
+ $ä:8/integer-unit:1-unsigned-big>>,
<<$\203:8/integer-unit:1-unsigned-big,
$h:8/integer-unit:1-unsigned-big,
$\003:8/integer-unit:1-unsigned-big,
@@ -1525,25 +1526,25 @@ lookup_handle() ->
$+:8/integer-unit:1-unsigned-big,
$x:8/integer-unit:1-unsigned-big,
$\234:8/integer-unit:1-unsigned-big,
- $�:8/integer-unit:1-unsigned-big,
+ $Ë:8/integer-unit:1-unsigned-big,
$`:8/integer-unit:1-unsigned-big,
$M:8/integer-unit:1-unsigned-big,
$a:8/integer-unit:1-unsigned-big,
$`:8/integer-unit:1-unsigned-big,
- $�:8/integer-unit:1-unsigned-big,
+ $Ê:8/integer-unit:1-unsigned-big,
$/:8/integer-unit:1-unsigned-big,
$H:8/integer-unit:1-unsigned-big,
$\024:8/integer-unit:1-unsigned-big,
$N:8/integer-unit:1-unsigned-big,
$a:8/integer-unit:1-unsigned-big,
$`:8/integer-unit:1-unsigned-big,
- $�:8/integer-unit:1-unsigned-big,
- $�:8/integer-unit:1-unsigned-big,
- $�:8/integer-unit:1-unsigned-big,
- $�:8/integer-unit:1-unsigned-big,
+ $¶:8/integer-unit:1-unsigned-big,
+ $µ:8/integer-unit:1-unsigned-big,
+ $²:8/integer-unit:1-unsigned-big,
+ $Í:8/integer-unit:1-unsigned-big,
$`:8/integer-unit:1-unsigned-big,
$\006:8/integer-unit:1-unsigned-big,
- $�:8/integer-unit:1-unsigned-big,
+ $Ò:8/integer-unit:1-unsigned-big,
$e:8/integer-unit:1-unsigned-big,
$\211:8/integer-unit:1-unsigned-big,
$E:8/integer-unit:1-unsigned-big,
@@ -1555,10 +1556,10 @@ lookup_handle() ->
$/:8/integer-unit:1-unsigned-big,
$\022:8/integer-unit:1-unsigned-big,
$\000:8/integer-unit:1-unsigned-big,
- $�:8/integer-unit:1-unsigned-big,
+ $×:8/integer-unit:1-unsigned-big,
$\227:8/integer-unit:1-unsigned-big,
$\t:8/integer-unit:1-unsigned-big,
- $�:8/integer-unit:1-unsigned-big>>,
+ $Û:8/integer-unit:1-unsigned-big>>,
<<$\203:8/integer-unit:1-unsigned-big,
$P:8/integer-unit:1-unsigned-big,
$\000:8/integer-unit:1-unsigned-big,
@@ -1567,33 +1568,33 @@ lookup_handle() ->
$\\:8/integer-unit:1-unsigned-big,
$x:8/integer-unit:1-unsigned-big,
$\234:8/integer-unit:1-unsigned-big,
- $�:8/integer-unit:1-unsigned-big,
+ $Ë:8/integer-unit:1-unsigned-big,
$`:8/integer-unit:1-unsigned-big,
$I:8/integer-unit:1-unsigned-big,
$a:8/integer-unit:1-unsigned-big,
$`:8/integer-unit:1-unsigned-big,
$I:8/integer-unit:1-unsigned-big,
- $�:8/integer-unit:1-unsigned-big,
- $�:8/integer-unit:1-unsigned-big,
+ $Î:8/integer-unit:1-unsigned-big,
+ $Ï:8/integer-unit:1-unsigned-big,
$+:8/integer-unit:1-unsigned-big,
$N:8/integer-unit:1-unsigned-big,
- $�:8/integer-unit:1-unsigned-big,
- $�:8/integer-unit:1-unsigned-big,
- $�:8/integer-unit:1-unsigned-big,
- $�:8/integer-unit:1-unsigned-big,
- $�:8/integer-unit:1-unsigned-big,
+ $ú:8/integer-unit:1-unsigned-big,
+ $ÿ:8/integer-unit:1-unsigned-big,
+ $ÿ:8/integer-unit:1-unsigned-big,
+ $ÿ:8/integer-unit:1-unsigned-big,
+ $û:8/integer-unit:1-unsigned-big,
$\f:8/integer-unit:1-unsigned-big,
- $�:8/integer-unit:1-unsigned-big,
+ $æ:8/integer-unit:1-unsigned-big,
$\024:8/integer-unit:1-unsigned-big,
$\006:8/integer-unit:1-unsigned-big,
- $�:8/integer-unit:1-unsigned-big,
+ $Ö:8/integer-unit:1-unsigned-big,
$\222:8/integer-unit:1-unsigned-big,
- $�:8/integer-unit:1-unsigned-big,
+ $Ò:8/integer-unit:1-unsigned-big,
$\202:8/integer-unit:1-unsigned-big,
$\234:8/integer-unit:1-unsigned-big,
- $�:8/integer-unit:1-unsigned-big,
+ $Ô:8/integer-unit:1-unsigned-big,
$D:8/integer-unit:1-unsigned-big,
- $�:8/integer-unit:1-unsigned-big,
+ $Á:8/integer-unit:1-unsigned-big,
$\034:8/integer-unit:1-unsigned-big,
$\006:8/integer-unit:1-unsigned-big,
$\006:8/integer-unit:1-unsigned-big,
@@ -1605,7 +1606,7 @@ lookup_handle() ->
$Y:8/integer-unit:1-unsigned-big,
$b:8/integer-unit:1-unsigned-big,
$Q:8/integer-unit:1-unsigned-big,
- $�:8/integer-unit:1-unsigned-big,
+ $¢:8/integer-unit:1-unsigned-big,
$`:8/integer-unit:1-unsigned-big,
$\n:8/integer-unit:1-unsigned-big,
$\003:8/integer-unit:1-unsigned-big,
@@ -1616,7 +1617,7 @@ lookup_handle() ->
$>:8/integer-unit:1-unsigned-big,
$\v:8/integer-unit:1-unsigned-big,
$I:8/integer-unit:1-unsigned-big,
- $�:8/integer-unit:1-unsigned-big,
+ $µ:8/integer-unit:1-unsigned-big,
$\020:8/integer-unit:1-unsigned-big,
$H:8/integer-unit:1-unsigned-big,
$5:8/integer-unit:1-unsigned-big,
@@ -1630,7 +1631,7 @@ lookup_handle() ->
$\005:8/integer-unit:1-unsigned-big,
$\000:8/integer-unit:1-unsigned-big,
$\024:8/integer-unit:1-unsigned-big,
- $�:8/integer-unit:1-unsigned-big,
+ $Ù:8/integer-unit:1-unsigned-big,
$\031:8/integer-unit:1-unsigned-big,
$M:8/integer-unit:1-unsigned-big>>}
end,
diff --git a/lib/stdlib/test/shell_SUITE.erl b/lib/stdlib/test/shell_SUITE.erl
index 681c154463..3c49aaa103 100644
--- a/lib/stdlib/test/shell_SUITE.erl
+++ b/lib/stdlib/test/shell_SUITE.erl
@@ -1,3 +1,4 @@
+%% -*- coding: utf-8 -*-
%%
%% %CopyrightBegin%
%%
@@ -2820,7 +2821,7 @@ otp_10302(Config) when is_list(Config) ->
"ok.\n** exception error: an error occurred when evaluating"
" an arithmetic expression\n in operator '/'/2\n"
- " called as <<\"�\">> / <<\"�\">>.\n" = t({Node,Test7}),
+ " called as <<\"ª\">> / <<\"ª\">>.\n" = t({Node,Test7}),
Test8 =
<<"begin
A = [1089],
diff --git a/lib/stdlib/test/supervisor_3.erl b/lib/stdlib/test/supervisor_3.erl
new file mode 100644
index 0000000000..31b3037d6f
--- /dev/null
+++ b/lib/stdlib/test/supervisor_3.erl
@@ -0,0 +1,45 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 1996-2011. 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%
+%%
+%% Description: Simulates the behaviour that a child process may have.
+%% Is used by the supervisor_SUITE test suite.
+-module(supervisor_3).
+
+-export([start_child/2, init/1]).
+
+-export([handle_call/3, handle_info/2, terminate/2]).
+
+start_child(Name, Caller) ->
+ gen_server:start_link(?MODULE, [Name, Caller], []).
+
+init([Name, Caller]) ->
+ Caller ! {Name, self()},
+ receive
+ {Result, Caller} ->
+ Result
+ end.
+
+handle_call(Req, _From, State) ->
+ {reply, Req, State}.
+
+handle_info(_, State) ->
+ {noreply, State}.
+
+terminate(_Reason, Time) ->
+ timer:sleep(Time),
+ ok.
diff --git a/lib/stdlib/test/supervisor_SUITE.erl b/lib/stdlib/test/supervisor_SUITE.erl
index 569c66959e..ff5be6bb95 100644
--- a/lib/stdlib/test/supervisor_SUITE.erl
+++ b/lib/stdlib/test/supervisor_SUITE.erl
@@ -53,9 +53,10 @@
%% Restart strategy tests
-export([ one_for_one/1,
one_for_one_escalation/1, one_for_all/1,
- one_for_all_escalation/1,
+ one_for_all_escalation/1, one_for_all_other_child_fails_restart/1,
simple_one_for_one/1, simple_one_for_one_escalation/1,
rest_for_one/1, rest_for_one_escalation/1,
+ rest_for_one_other_child_fails_restart/1,
simple_one_for_one_extra/1, simple_one_for_one_shutdown/1]).
%% Misc tests
@@ -107,12 +108,14 @@ groups() ->
{restart_one_for_one, [],
[one_for_one, one_for_one_escalation]},
{restart_one_for_all, [],
- [one_for_all, one_for_all_escalation]},
+ [one_for_all, one_for_all_escalation,
+ one_for_all_other_child_fails_restart]},
{restart_simple_one_for_one, [],
[simple_one_for_one, simple_one_for_one_shutdown,
simple_one_for_one_extra, simple_one_for_one_escalation]},
{restart_rest_for_one, [],
- [rest_for_one, rest_for_one_escalation]}].
+ [rest_for_one, rest_for_one_escalation,
+ rest_for_one_other_child_fails_restart]}].
init_per_suite(Config) ->
Config.
@@ -879,6 +882,57 @@ one_for_all_escalation(Config) when is_list(Config) ->
%%-------------------------------------------------------------------------
+%% Test that the supervisor terminates a restarted child when a different
+%% child fails to start.
+one_for_all_other_child_fails_restart(Config) when is_list(Config) ->
+ process_flag(trap_exit, true),
+ Self = self(),
+ Child1 = {child1, {supervisor_3, start_child, [child1, Self]},
+ permanent, 1000, worker, []},
+ Child2 = {child2, {supervisor_3, start_child, [child2, Self]},
+ permanent, 1000, worker, []},
+ Children = [Child1, Child2],
+ StarterFun = fun() ->
+ {ok, SupPid} = start_link({ok, {{one_for_all, 3, 3600}, Children}}),
+ Self ! {sup_pid, SupPid},
+ receive {stop, Self} -> ok end
+ end,
+ StarterPid = spawn_link(StarterFun),
+ Ok = {{ok, undefined}, Self},
+ %% Let the children start.
+ Child1Pid = receive {child1, Pid1} -> Pid1 end,
+ Child1Pid ! Ok,
+ Child2Pid = receive {child2, Pid2} -> Pid2 end,
+ Child2Pid ! Ok,
+ %% Supervisor started.
+ SupPid = receive {sup_pid, Pid} -> Pid end,
+ link(SupPid),
+ exit(Child1Pid, die),
+ %% Let child1 restart but don't let child2.
+ Child1Pid2 = receive {child1, Pid3} -> Pid3 end,
+ Child1Pid2Ref = erlang:monitor(process, Child1Pid2),
+ Child1Pid2 ! Ok,
+ Child2Pid2 = receive {child2, Pid4} -> Pid4 end,
+ Child2Pid2 ! {{stop, normal}, Self},
+ %% Check child1 is terminated.
+ receive
+ {'DOWN', Child1Pid2Ref, _, _, shutdown} ->
+ ok;
+ {_childName, _Pid} ->
+ exit(SupPid, kill),
+ check_exit([StarterPid, SupPid]),
+ test_server:fail({restarting_child_not_terminated, Child1Pid2})
+ end,
+ %% Let the restart complete.
+ Child1Pid3 = receive {child1, Pid5} -> Pid5 end,
+ Child1Pid3 ! Ok,
+ Child2Pid3 = receive {child2, Pid6} -> Pid6 end,
+ Child2Pid3 ! Ok,
+ StarterPid ! {stop, Self},
+ check_exit([StarterPid, SupPid]).
+
+
+%%-------------------------------------------------------------------------
%% Test the simple_one_for_one base case.
simple_one_for_one(Config) when is_list(Config) ->
process_flag(trap_exit, true),
@@ -1044,6 +1098,52 @@ rest_for_one_escalation(Config) when is_list(Config) ->
terminate(SupPid, CPid1, child1, abnormal),
check_exit([CPid2, SupPid]).
+
+%%-------------------------------------------------------------------------
+%% Test that the supervisor terminates a restarted child when a different
+%% child fails to start.
+rest_for_one_other_child_fails_restart(Config) when is_list(Config) ->
+ process_flag(trap_exit, true),
+ Self = self(),
+ Child1 = {child1, {supervisor_3, start_child, [child1, Self]},
+ permanent, 1000, worker, []},
+ Child2 = {child2, {supervisor_3, start_child, [child2, Self]},
+ permanent, 1000, worker, []},
+ Children = [Child1, Child2],
+ StarterFun = fun() ->
+ {ok, SupPid} = start_link({ok, {{rest_for_one, 3, 3600}, Children}}),
+ Self ! {sup_pid, SupPid},
+ receive {stop, Self} -> ok end
+ end,
+ StarterPid = spawn_link(StarterFun),
+ Ok = {{ok, undefined}, Self},
+ %% Let the children start.
+ Child1Pid = receive {child1, Pid1} -> Pid1 end,
+ Child1Pid ! Ok,
+ Child2Pid = receive {child2, Pid2} -> Pid2 end,
+ Child2Pid ! Ok,
+ %% Supervisor started.
+ SupPid = receive {sup_pid, Pid} -> Pid end,
+ link(SupPid),
+ exit(Child1Pid, die),
+ %% Let child1 restart but don't let child2.
+ Child1Pid2 = receive {child1, Pid3} -> Pid3 end,
+ Child1Pid2 ! Ok,
+ Child2Pid2 = receive {child2, Pid4} -> Pid4 end,
+ Child2Pid2 ! {{stop, normal}, Self},
+ %% Let child2 restart.
+ receive
+ {child2, Child2Pid3} ->
+ Child2Pid3 ! Ok;
+ {child1, _Child1Pid3} ->
+ exit(SupPid, kill),
+ check_exit([StarterPid, SupPid]),
+ test_server:fail({restarting_started_child, Child1Pid2})
+ end,
+ StarterPid ! {stop, Self},
+ check_exit([StarterPid, SupPid]).
+
+
%%-------------------------------------------------------------------------
%% Test that the supervisor does not hang forever if the child unliks
%% and then is terminated by the supervisor.
diff --git a/lib/test_server/src/erl2html2.erl b/lib/test_server/src/erl2html2.erl
index 5584c1e50c..d0f40c47a7 100644
--- a/lib/test_server/src/erl2html2.erl
+++ b/lib/test_server/src/erl2html2.erl
@@ -1,3 +1,4 @@
+%% -*- coding: utf-8 -*-
%%
%% %CopyrightBegin%
%%
@@ -214,7 +215,7 @@ html_encoding(utf8) ->
%%% from the source.
%%%
%%% Example: if the encoding of the file is utf8, and we have a string
-%%% containing "�" = [229], then we need to convert this to [195,165]
+%%% containing "å" = [229], then we need to convert this to [195,165]
%%% before writing. Note that this conversion is only necessary
%%% because the destination file is not (necessarily) opened with utf8
%%% encoding - it is opened with default encoding in order to allow
diff --git a/lib/test_server/src/test_server_ctrl.erl b/lib/test_server/src/test_server_ctrl.erl
index 21c10adccb..ffa21d054c 100644
--- a/lib/test_server/src/test_server_ctrl.erl
+++ b/lib/test_server/src/test_server_ctrl.erl
@@ -1183,7 +1183,7 @@ init_tester(Mod, Func, Args, Dir, Name, {_,_,MinLev}=Levels,
"<td>~.3fs</td><td><b>~ts</b></td><td>~w Ok, ~w Failed~ts of ~w</td></tr>\n"
"</tfoot>\n",
[Time,SuccessStr,OkN,FailedN,SkipStr,OkN+FailedN+SkippedN]),
- test_server_io:stop().
+ test_server_io:stop([major,html,unexpected_io]).
report_severe_error(Reason) ->
test_server_sup:framework_call(report, [severe_error,Reason]).
@@ -1588,7 +1588,7 @@ do_test_cases(TopCases, SkipCases,
print(major, "=started ~s",
[lists:flatten(timestamp_get(""))]),
- put(test_server_html_footer, Footer),
+ test_server_io:set_footer(Footer),
run_test_cases(TestSpec, Config, TimetrapData)
end;
diff --git a/lib/test_server/src/test_server_io.erl b/lib/test_server/src/test_server_io.erl
index a979deffc3..73d4468bda 100644
--- a/lib/test_server/src/test_server_io.erl
+++ b/lib/test_server/src/test_server_io.erl
@@ -29,7 +29,7 @@
%%
-module(test_server_io).
--export([start_link/0,stop/0,get_gl/1,set_fd/2,
+-export([start_link/0,stop/1,get_gl/1,set_fd/2,
start_transaction/0,end_transaction/0,
print_buffered/1,print/3,print_unexpected/1,
set_footer/1,set_job_name/1,set_gl_props/1]).
@@ -55,10 +55,10 @@ start_link() ->
Other
end.
-stop() ->
+stop(FilesToClose) ->
OldGL = group_leader(),
group_leader(self(), self()),
- req(stop),
+ req({stop,FilesToClose}),
group_leader(OldGL, self()),
ok.
@@ -213,12 +213,21 @@ handle_call({set_job_name,Name}, _From, St) ->
handle_call({set_gl_props,Props}, _From, #st{shared_gl=Shared}=St) ->
test_server_gl:set_props(Shared, Props),
{reply,ok,St#st{gl_props=Props}};
-handle_call(stop, From, #st{shared_gl=SGL,gls=Gls0}=St0) ->
+handle_call({stop,FdTags}, From, #st{fds=Fds,shared_gl=SGL,gls=Gls0}=St0) ->
St = St0#st{gls=gb_sets:insert(SGL, Gls0),stopping=From},
gc(St),
%% Give the users of the surviving group leaders some
%% time to finish.
erlang:send_after(2000, self(), stop_group_leaders),
+ %% close open log files
+ lists:foreach(fun(Tag) ->
+ case gb_trees:lookup(Tag, Fds) of
+ none ->
+ ok;
+ {value,Fd} ->
+ file:close(Fd)
+ end
+ end, FdTags),
{noreply,St}.
handle_info({'EXIT',Pid,normal}, #st{gls=Gls0,stopping=From}=St) ->
diff --git a/lib/test_server/test/test_server_SUITE.erl b/lib/test_server/test/test_server_SUITE.erl
index 3db2f5f9f1..8ad5fcfb5c 100644
--- a/lib/test_server/test/test_server_SUITE.erl
+++ b/lib/test_server/test/test_server_SUITE.erl
@@ -1,3 +1,4 @@
+%% -*- coding: utf-8 -*-
%%
%% %CopyrightBegin%
%%
@@ -187,7 +188,7 @@ test_server_unicode(Config) ->
%% Create and run two test suites - one with filename and content
%% in latin1 (if the default filename mode is latin1) and one with
%% filename and content in utf8. Both have name and content
- %% including letters ���. Check that all logs are generated with
+ %% including letters äöå. Check that all logs are generated with
%% utf8 encoded filenames.
case file:native_name_encoding() of
utf8 ->
@@ -348,7 +349,7 @@ generate_and_run_unicode_test(Config0,Encoding) ->
SuiteHtml = translate_filename(LowerModStr++".src.html",Encoding),
true = filelib:is_regular(filename:join(RunDir,SuiteHtml)),
- TCLog = translate_filename(LowerModStr++".tc_���.html",Encoding),
+ TCLog = translate_filename(LowerModStr++".tc_äöå.html",Encoding),
true = filelib:is_regular(filename:join(RunDir,TCLog)),
ok.
@@ -370,7 +371,7 @@ start_node(Config,Name,Args) ->
end.
create_unicode_test_suite(Dir,Encoding) ->
- ModStr = "test_server_"++atom_to_list(Encoding)++"_���_SUITE",
+ ModStr = "test_server_"++atom_to_list(Encoding)++"_äöå_SUITE",
File = filename:join(Dir,ModStr++".erl"),
Suite =
["%% -*- ",epp:encoding_to_string(Encoding)," -*-\n",
@@ -378,12 +379,12 @@ create_unicode_test_suite(Dir,Encoding) ->
"\n"
"-export([all/1, init_per_suite/1, end_per_suite/1]).\n"
"-export([init_per_testcase/2, end_per_testcase/2]).\n"
- "-export([tc_���/1]).\n"
+ "-export([tc_äöå/1]).\n"
"\n"
"-include_lib(\"test_server/include/test_server.hrl\").\n"
"\n"
"all(suite) ->\n"
- " [tc_���].\n"
+ " [tc_äöå].\n"
"\n"
"init_per_suite(Config) ->\n"
" Config.\n"
@@ -406,7 +407,7 @@ create_unicode_test_suite(Dir,Encoding) ->
" ?t:timetrap_cancel(Dog),\n"
" ok.\n"
"\n"
- "tc_���(Config) when is_list(Config) ->\n"
+ "tc_äöå(Config) when is_list(Config) ->\n"
" true = filelib:is_dir(?config(priv_dir,Config)),\n"
" ok.\n"],
{ok,Fd} = file:open(raw_filename(File,Encoding),[write,{encoding,Encoding}]),
diff --git a/lib/tools/src/fprof.erl b/lib/tools/src/fprof.erl
index 4cbb910f11..877218bda0 100644
--- a/lib/tools/src/fprof.erl
+++ b/lib/tools/src/fprof.erl
@@ -1226,10 +1226,7 @@ spawn_3step(Spawn, FunPrelude, FunAck, FunBody)
MRef = erlang:monitor(process, Parent),
receive
{Parent, Ref, Go} ->
- erlang:demonitor(MRef),
- receive {'DOWN', MRef, _, _, _} -> ok
- after 0 -> ok
- end,
+ erlang:demonitor(MRef, [flush]),
FunBody(Go);
{'DOWN', MRef, _, _, _} ->
ok
@@ -1238,8 +1235,7 @@ spawn_3step(Spawn, FunPrelude, FunAck, FunBody)
MRef = erlang:monitor(process, Child),
receive
{Child, Ref, Ack} ->
- erlang:demonitor(MRef),
- receive {'DOWN', MRef, _, _, _} -> ok after 0 -> ok end,
+ erlang:demonitor(MRef, [flush]),
try FunAck(Ack) of
{Result, Go} ->
catch Child ! {Parent, Ref, Go},