aboutsummaryrefslogtreecommitdiffstats
path: root/lib
diff options
context:
space:
mode:
Diffstat (limited to 'lib')
-rw-r--r--lib/common_test/src/ct_hooks.erl11
-rw-r--r--lib/common_test/test/ct_hooks_SUITE.erl10
-rw-r--r--lib/compiler/src/v3_core.erl3
-rw-r--r--lib/compiler/test/fun_SUITE.erl20
-rw-r--r--lib/erl_interface/src/decode/decode_fun.c13
-rw-r--r--lib/erl_interface/src/decode/decode_skip.c1
-rw-r--r--lib/erl_interface/src/misc/ei_printterm.c37
-rw-r--r--lib/erl_interface/test/ei_decode_encode_SUITE.erl8
-rw-r--r--lib/erl_interface/test/ei_decode_encode_SUITE_data/ei_decode_encode_test.c1
-rw-r--r--lib/erl_interface/test/ei_print_SUITE.erl27
-rw-r--r--lib/erl_interface/test/ei_print_SUITE_data/ei_print_test.c141
-rw-r--r--lib/kernel/doc/src/notes.xml16
-rw-r--r--lib/kernel/src/code.erl18
-rw-r--r--lib/kernel/src/gen_sctp.erl17
-rw-r--r--lib/kernel/src/kernel.erl4
-rw-r--r--lib/kernel/src/logger_std_h.erl8
-rw-r--r--lib/kernel/src/seq_trace.erl2
-rw-r--r--lib/kernel/test/code_SUITE.erl29
-rw-r--r--lib/kernel/test/gen_tcp_misc_SUITE.erl43
-rw-r--r--lib/kernel/test/logger_std_h_SUITE.erl49
-rw-r--r--lib/kernel/test/seq_trace_SUITE.erl32
-rw-r--r--lib/public_key/asn1/CMSAesRsaesOaep.asn139
-rw-r--r--lib/public_key/asn1/Makefile2
-rw-r--r--lib/public_key/asn1/OTP-PUB-KEY.set.asn2
-rw-r--r--lib/public_key/doc/src/public_key_app.xml3
-rw-r--r--lib/public_key/src/pubkey_pbe.erl105
-rw-r--r--lib/public_key/test/pbe_SUITE.erl6
-rw-r--r--lib/public_key/test/pbe_SUITE_data/pbes2_aes_128_enc_key.pem30
-rw-r--r--lib/public_key/test/pbe_SUITE_data/pbes2_aes_192_enc_key.pem30
-rw-r--r--lib/public_key/test/pbe_SUITE_data/pbes2_aes_256_enc_key.pem30
-rw-r--r--lib/snmp/src/agent/snmp_community_mib.erl10
-rw-r--r--lib/snmp/src/agent/snmp_generic.erl18
-rw-r--r--lib/snmp/src/agent/snmp_standard_mib.erl13
-rw-r--r--lib/snmp/src/agent/snmp_target_mib.erl13
-rw-r--r--lib/snmp/src/agent/snmp_user_based_sm_mib.erl12
-rw-r--r--lib/snmp/src/agent/snmp_view_based_acm_mib.erl11
-rw-r--r--lib/snmp/src/agent/snmpa_mpd.erl10
-rw-r--r--lib/snmp/src/agent/snmpa_trap.erl17
-rw-r--r--lib/snmp/src/agent/snmpa_usm.erl22
-rw-r--r--lib/snmp/src/app/snmp_internal.hrl11
-rw-r--r--lib/snmp/src/compile/Makefile4
-rw-r--r--lib/snmp/src/compile/snmpc.erl11
-rw-r--r--lib/snmp/src/manager/snmpm_config.erl33
-rw-r--r--lib/snmp/src/manager/snmpm_mpd.erl14
-rw-r--r--lib/snmp/src/manager/snmpm_net_if.erl17
-rw-r--r--lib/snmp/src/manager/snmpm_server.erl35
-rw-r--r--lib/snmp/src/misc/snmp_conf.erl19
-rw-r--r--lib/snmp/src/misc/snmp_config.erl91
-rw-r--r--lib/snmp/test/snmp_manager_config_test.erl13
-rw-r--r--lib/snmp/test/snmp_test_mgr.erl14
-rw-r--r--lib/ssh/src/Makefile2
-rw-r--r--lib/ssh/src/ssh.hrl19
-rw-r--r--lib/ssh/src/ssh_message.erl18
-rw-r--r--lib/ssh/src/ssh_transport.erl8
-rw-r--r--lib/ssh/src/ssh_userauth.hrl78
-rw-r--r--lib/ssh/test/ssh_bench_SUITE.erl2
-rw-r--r--lib/ssl/doc/src/notes.xml33
-rw-r--r--lib/ssl/doc/src/standards_compliance.xml408
-rw-r--r--lib/ssl/src/dtls_connection.erl9
-rw-r--r--lib/ssl/src/dtls_record.erl87
-rw-r--r--lib/ssl/src/ssl.erl14
-rw-r--r--lib/ssl/src/ssl_connection.erl2
-rw-r--r--lib/ssl/src/ssl_connection.hrl3
-rw-r--r--lib/ssl/src/ssl_handshake.erl15
-rw-r--r--lib/ssl/src/ssl_logger.erl5
-rw-r--r--lib/ssl/src/tls_connection.erl22
-rw-r--r--lib/ssl/src/tls_connection_1_3.erl61
-rw-r--r--lib/ssl/src/tls_handshake.erl39
-rw-r--r--lib/ssl/src/tls_handshake_1_3.erl802
-rw-r--r--lib/ssl/test/ssl_basic_SUITE.erl593
-rw-r--r--lib/ssl/test/ssl_certificate_verify_SUITE.erl11
-rw-r--r--lib/ssl/test/ssl_test_lib.erl41
-rw-r--r--lib/stdlib/doc/src/binary.xml15
-rw-r--r--lib/stdlib/doc/src/gen_statem.xml2
-rw-r--r--lib/stdlib/doc/src/notes.xml17
-rw-r--r--lib/tools/doc/src/notes.xml15
-rw-r--r--lib/tools/src/cover.erl40
-rw-r--r--lib/tools/test/cover_SUITE.erl27
-rw-r--r--lib/xmerl/doc/src/notes.xml17
-rw-r--r--lib/xmerl/src/xmerl_sax_parser.erl12
80 files changed, 2677 insertions, 865 deletions
diff --git a/lib/common_test/src/ct_hooks.erl b/lib/common_test/src/ct_hooks.erl
index 97c349578f..94551d6815 100644
--- a/lib/common_test/src/ct_hooks.erl
+++ b/lib/common_test/src/ct_hooks.erl
@@ -363,7 +363,16 @@ terminate_if_scope_ends(HookId, Function0, Hooks) ->
Function = strip_config(Function0),
case lists:keyfind(HookId, #ct_hook_config.id, Hooks) of
#ct_hook_config{ id = HookId, scope = Function} = Hook ->
- terminate([Hook]),
+ case Function of
+ [AllOrGroup,_] when AllOrGroup=:=post_all;
+ AllOrGroup=:=post_groups ->
+ %% The scope only contains one function (post_all
+ %% or post_groups), and init has not been called,
+ %% so skip terminate as well.
+ ok;
+ _ ->
+ terminate([Hook])
+ end,
lists:keydelete(HookId, #ct_hook_config.id, Hooks);
_ ->
Hooks
diff --git a/lib/common_test/test/ct_hooks_SUITE.erl b/lib/common_test/test/ct_hooks_SUITE.erl
index 340b8f3d52..08c18d91e2 100644
--- a/lib/common_test/test/ct_hooks_SUITE.erl
+++ b/lib/common_test/test/ct_hooks_SUITE.erl
@@ -671,9 +671,15 @@ test_events(scope_suite_cth) ->
{?eh,test_start,{'DEF',{'START_TIME','LOGDIR'}}},
%% check that post_groups and post_all comes before init when hook
%% is installed in suite/0
+ %% And there should be no terminate after these, since init is
+ %% not yet called.
{?eh,cth,{'_',post_groups,['_',[]]}},
- {?eh,cth,{'_',post_all,['_','_',[]]}},
- {?eh,tc_start,{ct_scope_suite_cth_SUITE,init_per_suite}},
+ {negative,
+ {?eh,cth,{'_',terminate,['_']}},
+ {?eh,cth,{'_',post_all,['_','_',[]]}}},
+ {negative,
+ {?eh,cth,{'_',terminate,['_']}},
+ {?eh,tc_start,{ct_scope_suite_cth_SUITE,init_per_suite}}},
{?eh,cth,{'_',id,[[]]}},
{?eh,cth,{'_',init,['_',[]]}},
{?eh,cth,{'_',pre_init_per_suite,[ct_scope_suite_cth_SUITE,'$proplist',[]]}},
diff --git a/lib/compiler/src/v3_core.erl b/lib/compiler/src/v3_core.erl
index 3699c9d22e..007a0247f4 100644
--- a/lib/compiler/src/v3_core.erl
+++ b/lib/compiler/src/v3_core.erl
@@ -1811,7 +1811,8 @@ force_safe(Ce, St0) ->
is_safe(#c_cons{}) -> true;
is_safe(#c_tuple{}) -> true;
-is_safe(#c_var{}) -> true;
+is_safe(#c_var{name={_,_}}) -> false; %Fun. Not safe.
+is_safe(#c_var{name=_}) -> true; %Ordinary variable.
is_safe(#c_literal{}) -> true;
is_safe(_) -> false.
diff --git a/lib/compiler/test/fun_SUITE.erl b/lib/compiler/test/fun_SUITE.erl
index 1df0a05275..7fc6195e31 100644
--- a/lib/compiler/test/fun_SUITE.erl
+++ b/lib/compiler/test/fun_SUITE.erl
@@ -22,7 +22,8 @@
-export([all/0, suite/0,groups/0,init_per_suite/1, end_per_suite/1,
init_per_group/2,end_per_group/2,
test1/1,overwritten_fun/1,otp_7202/1,bif_fun/1,
- external/1,eep37/1,eep37_dup/1,badarity/1,badfun/1]).
+ external/1,eep37/1,eep37_dup/1,badarity/1,badfun/1,
+ duplicated_fun/1]).
%% Internal exports.
-export([call_me/1,dup1/0,dup2/0]).
@@ -37,7 +38,7 @@ all() ->
groups() ->
[{p,[parallel],
[test1,overwritten_fun,otp_7202,bif_fun,external,eep37,
- eep37_dup,badarity,badfun]}].
+ eep37_dup,badarity,badfun,duplicated_fun]}].
init_per_suite(Config) ->
test_lib:recompile(?MODULE),
@@ -261,5 +262,20 @@ badfun(_Config) ->
expect_badfun(Term, Exit) ->
{'EXIT',{{badfun,Term},_}} = Exit.
+duplicated_fun(_Config) ->
+ try
+ %% The following code used to crash the compiler before
+ %% v3_core:is_safe/1 was corrected to consider fun variables
+ %% unsafe.
+ id([print_result_paths_fun = fun duplicated_fun_helper/1]),
+ ct:error(should_fail)
+ catch
+ error:{badmatch,F} when is_function(F, 1) ->
+ ok
+ end.
+
+duplicated_fun_helper(_) ->
+ ok.
+
id(I) ->
I.
diff --git a/lib/erl_interface/src/decode/decode_fun.c b/lib/erl_interface/src/decode/decode_fun.c
index 3a7a2b01c1..db71007505 100644
--- a/lib/erl_interface/src/decode/decode_fun.c
+++ b/lib/erl_interface/src/decode/decode_fun.c
@@ -77,10 +77,12 @@ int ei_decode_fun(const char *buf, int *index, erlang_fun *p)
}
if (p != NULL) {
p->u.closure.n_free_vars = n;
- p->u.closure.free_var_len = ix - ix0;
- p->u.closure.free_vars = ei_malloc(ix - ix0);
- if (!(p->u.closure.free_vars)) return -1;
- memcpy(p->u.closure.free_vars, s + ix0, ix - ix0);
+ p->u.closure.free_var_len = ix - ix0;
+ if (p->u.closure.free_var_len > 0) {
+ p->u.closure.free_vars = ei_malloc(p->u.closure.free_var_len);
+ if (!(p->u.closure.free_vars)) return -1;
+ memcpy(p->u.closure.free_vars, s + ix0, p->u.closure.free_var_len);
+ }
}
s += ix;
*index += s-s0;
@@ -146,6 +148,7 @@ int ei_decode_fun(const char *buf, int *index, erlang_fun *p)
else {
p_arity = NULL;
}
+ ix = 0;
if (ei_decode_atom_as(s, &ix, p_module, MAXATOMLEN_UTF8, ERLANG_UTF8,
NULL, NULL) < 0)
return -1;
@@ -171,6 +174,8 @@ int ei_decode_fun(const char *buf, int *index, erlang_fun *p)
}
if (ei_decode_long(s, &ix, p_arity) < 0)
return -1;
+ s += ix;
+ *index += s - s0;
return 0;
}
default:
diff --git a/lib/erl_interface/src/decode/decode_skip.c b/lib/erl_interface/src/decode/decode_skip.c
index 736c00e074..0622ce7d59 100644
--- a/lib/erl_interface/src/decode/decode_skip.c
+++ b/lib/erl_interface/src/decode/decode_skip.c
@@ -97,6 +97,7 @@ int ei_skip_term(const char* buf, int* index)
break;
case ERL_FUN_EXT:
case ERL_NEW_FUN_EXT:
+ case ERL_EXPORT_EXT:
if (ei_decode_fun(buf, index, NULL) < 0) return -1;
break;
default:
diff --git a/lib/erl_interface/src/misc/ei_printterm.c b/lib/erl_interface/src/misc/ei_printterm.c
index 5c40fb7747..a94d6e2ad8 100644
--- a/lib/erl_interface/src/misc/ei_printterm.c
+++ b/lib/erl_interface/src/misc/ei_printterm.c
@@ -121,6 +121,7 @@ static int print_term(FILE* fp, ei_x_buff* x,
erlang_pid pid;
erlang_port port;
erlang_ref ref;
+ erlang_fun fun;
double d;
long l;
@@ -306,12 +307,46 @@ static int print_term(FILE* fp, ei_x_buff* x,
}
break;
-
case ERL_FLOAT_EXT:
case NEW_FLOAT_EXT:
if (ei_decode_double(buf, index, &d) < 0) goto err;
ch_written += xprintf(fp, x, "%f", d);
break;
+ case ERL_MAP_EXT:
+ if (ei_decode_map_header(buf, &tindex, &n) < 0) goto err;
+ ch_written += xprintf(fp, x, "#{");
+ for (i = 0; i < n; ++i) {
+ r = print_term(fp, x, buf, &tindex);
+ if (r < 0) goto err;
+ ch_written += r;
+ ch_written += xprintf(fp, x, " => ");
+ r = print_term(fp, x, buf, &tindex);
+ if (r < 0) goto err;
+ ch_written += r;
+ if (i < n-1) {
+ xputs(", ", fp, x); ch_written += 2;
+ }
+ }
+ *index = tindex;
+ xputc('}', fp, x); ch_written++;
+ break;
+ case ERL_FUN_EXT:
+ case ERL_NEW_FUN_EXT:
+ case ERL_EXPORT_EXT:
+ if (ei_decode_fun(buf, &tindex, &fun) < 0) goto err;
+ if (fun.type == EI_FUN_EXPORT) {
+ ch_written += xprintf(fp, x, "fun %s:%s/%ld",
+ fun.module,
+ fun.u.exprt.func,
+ fun.arity);
+ } else {
+ ch_written += xprintf(fp, x, "#Fun{%s.%ld.%lu}",
+ fun.module,
+ fun.u.closure.index,
+ fun.u.closure.uniq);
+ }
+ *index = tindex;
+ break;
default:
goto err;
}
diff --git a/lib/erl_interface/test/ei_decode_encode_SUITE.erl b/lib/erl_interface/test/ei_decode_encode_SUITE.erl
index 3451d9f503..0204b4cfd6 100644
--- a/lib/erl_interface/test/ei_decode_encode_SUITE.erl
+++ b/lib/erl_interface/test/ei_decode_encode_SUITE.erl
@@ -48,7 +48,8 @@ init_per_testcase(Case, Config) ->
test_ei_decode_encode(Config) when is_list(Config) ->
P = runner:start(Config, ?test_ei_decode_encode),
- Fun = fun (X) -> {X,true} end,
+ Fun1 = fun (X) -> {X,true} end,
+ Fun2 = fun runner:init_per_testcase/3,
Pid = self(),
Port = case os:type() of
{win32,_} ->
@@ -70,7 +71,8 @@ test_ei_decode_encode(Config) when is_list(Config) ->
BigLargeB = 1 bsl 11112 + BigSmallB,
BigLargeC = BigSmallA * BigSmallB * BigSmallC * BigSmallA,
- send_rec(P, Fun),
+ send_rec(P, Fun1),
+ send_rec(P, Fun2),
send_rec(P, Pid),
send_rec(P, Port),
send_rec(P, Ref),
@@ -115,7 +117,7 @@ test_ei_decode_encode(Config) when is_list(Config) ->
send_rec(P, {}),
send_rec(P, {atom, Pid, Port, Ref}),
send_rec(P, [atom, Pid, Port, Ref]),
- send_rec(P, [atom | Fun]),
+ send_rec(P, [atom | Fun1]),
send_rec(P, #{}),
send_rec(P, #{key => value}),
send_rec(P, maps:put(Port, Ref, #{key => value, key2 => Pid})),
diff --git a/lib/erl_interface/test/ei_decode_encode_SUITE_data/ei_decode_encode_test.c b/lib/erl_interface/test/ei_decode_encode_SUITE_data/ei_decode_encode_test.c
index 85ca6c56e9..512f9ed0c7 100644
--- a/lib/erl_interface/test/ei_decode_encode_SUITE_data/ei_decode_encode_test.c
+++ b/lib/erl_interface/test/ei_decode_encode_SUITE_data/ei_decode_encode_test.c
@@ -564,6 +564,7 @@ TESTCASE(test_ei_decode_encode)
ei_init();
decode_encode_one(&fun_type);
+ decode_encode_one(&fun_type);
decode_encode_one(&pid_type);
decode_encode_one(&port_type);
decode_encode_one(&ref_type);
diff --git a/lib/erl_interface/test/ei_print_SUITE.erl b/lib/erl_interface/test/ei_print_SUITE.erl
index c75ce55a7d..f2a2548183 100644
--- a/lib/erl_interface/test/ei_print_SUITE.erl
+++ b/lib/erl_interface/test/ei_print_SUITE.erl
@@ -26,7 +26,8 @@
-export([all/0, suite/0,
init_per_testcase/2,
- atoms/1, tuples/1, lists/1, strings/1]).
+ atoms/1, tuples/1, lists/1, strings/1,
+ maps/1, funs/1]).
-import(runner, [get_term/1]).
@@ -36,8 +37,8 @@
suite() ->
[{ct_hooks,[ts_install_cth]}].
-all() ->
- [atoms, tuples, lists, strings].
+all() ->
+ [atoms, tuples, lists, strings, maps, funs].
init_per_testcase(Case, Config) ->
runner:init_per_testcase(?MODULE, Case, Config).
@@ -142,3 +143,23 @@ strings(Config) when is_list(Config) ->
runner:recv_eot(P),
ok.
+
+maps(Config) ->
+ P = runner:start(Config, ?maps),
+
+ {term, "#{}"} = get_term(P),
+ {term, "#{key => value}"} = get_term(P),
+ {term, "#{key => value, another_key => {ok, 42}}"} = get_term(P),
+
+ runner:recv_eot(P),
+ ok.
+
+funs(Config) ->
+ P = runner:start(Config, ?funs),
+
+ {term, "#Fun{some_module.42.3735928559}"} = get_term(P),
+ {term, "#Fun{some_module.37.195935983}"} = get_term(P),
+ {term, "fun erlang:abs/1"} = get_term(P),
+
+ runner:recv_eot(P),
+ ok.
diff --git a/lib/erl_interface/test/ei_print_SUITE_data/ei_print_test.c b/lib/erl_interface/test/ei_print_SUITE_data/ei_print_test.c
index 80be3016e6..0e2b24e45a 100644
--- a/lib/erl_interface/test/ei_print_SUITE_data/ei_print_test.c
+++ b/lib/erl_interface/test/ei_print_SUITE_data/ei_print_test.c
@@ -29,6 +29,46 @@
*/
static void
+send_printed_buf(ei_x_buff* x)
+{
+ char* b = NULL;
+ char fn[256];
+ char *tmp = getenv("temp");
+ FILE* f;
+ int n, index = 0, ver;
+
+#ifdef VXWORKS
+ tmp = ".";
+#else
+ if (tmp == NULL) {
+ tmp = "/tmp";
+ }
+#endif
+ strcpy(fn, tmp);
+ strcat(fn, "/ei_print_test.txt");
+ f = fopen(fn, "w+");
+ ei_decode_version(x->buff, &index, &ver);
+ n = ei_print_term(f, x->buff, &index);
+ if (n < 0) {
+ fclose(f);
+ x->index = 0;
+ ei_x_format(x, "~s", "ERROR: term decoding failed");
+ send_bin_term(x);
+ } else {
+ fseek(f, 0, SEEK_SET);
+ b = malloc(n+1);
+ fread(b, 1, n, f);
+ b[n] = '\0';
+ fclose(f);
+ x->index = 0;
+ ei_x_format(x, "~s", b);
+ send_bin_term(x);
+ free(b);
+ }
+}
+
+
+static void
send_printed3(char* format, char* p1, char* p2, int fl)
{
char* b = NULL;
@@ -43,25 +83,7 @@ send_printed3(char* format, char* p1, char* p2, int fl)
} else {
ei_x_format(&x, format, p1, p2);
}
-#ifdef VXWORKS
- tmp = ".";
-#else
- if (tmp == NULL) tmp = "/tmp";
-#endif
- strcpy(fn, tmp);
- strcat(fn, "/ei_print_test.txt");
- f = fopen(fn, "w+");
- ei_decode_version(x.buff, &index, &ver);
- n = ei_print_term(f, x.buff, &index);
- fseek(f, 0, SEEK_SET);
- b = malloc(n+1);
- fread(b, 1, n, f);
- b[n] = '\0';
- fclose(f);
- x.index = 0;
- ei_x_format(&x, "~s", b);
- send_bin_term(&x);
- free(b);
+ send_printed_buf(&x);
ei_x_free(&x);
}
@@ -184,4 +206,85 @@ TESTCASE(strings)
report(1);
}
+TESTCASE(maps)
+{
+ ei_x_buff x;
+
+ ei_init();
+
+ ei_x_new_with_version(&x);
+ ei_x_encode_map_header(&x, 0);
+ send_printed_buf(&x);
+ ei_x_free(&x);
+
+ ei_x_new_with_version(&x);
+ ei_x_encode_map_header(&x, 1);
+ ei_x_encode_atom(&x, "key");
+ ei_x_encode_atom(&x, "value");
+ send_printed_buf(&x);
+ ei_x_free(&x);
+
+ ei_x_new_with_version(&x);
+ ei_x_encode_map_header(&x, 2);
+ ei_x_encode_atom(&x, "key");
+ ei_x_encode_atom(&x, "value");
+ ei_x_encode_atom(&x, "another_key");
+ ei_x_encode_tuple_header(&x, 2);
+ ei_x_encode_atom(&x, "ok");
+ ei_x_encode_long(&x, 42L);
+ send_printed_buf(&x);
+ ei_x_free(&x);
+
+ report(1);
+}
+
+TESTCASE(funs)
+{
+ ei_x_buff x;
+ erlang_pid self;
+ erlang_fun fun;
+
+ strcpy(self.node, "node@host");
+ self.num = 9;
+ self.serial = 99;
+ self.creation = 1;
+
+ ei_init();
+
+ ei_x_new_with_version(&x);
+ fun.arity = -1; /* Will encode as FUN_EXT */
+ strcpy(fun.module, "some_module");
+ fun.type = EI_FUN_CLOSURE;
+ fun.u.closure.pid = self;
+ fun.u.closure.index = fun.u.closure.old_index = 42;
+ fun.u.closure.uniq = 0xDEADBEEF;
+ fun.u.closure.n_free_vars = 0;
+ fun.u.closure.free_var_len = 0;
+ ei_x_encode_fun(&x, &fun);
+ send_printed_buf(&x);
+ ei_x_free(&x);
+ ei_x_new_with_version(&x);
+ fun.arity = 0; /* Will encode as NEW_FUN_EXT */
+ strcpy(fun.module, "some_module");
+ fun.type = EI_FUN_CLOSURE;
+ fun.u.closure.pid = self;
+ fun.u.closure.index = fun.u.closure.old_index = 37;
+ fun.u.closure.uniq = 0xBADBEEF;
+ fun.u.closure.n_free_vars = 0;
+ fun.u.closure.free_var_len = 0;
+ ei_x_encode_fun(&x, &fun);
+ send_printed_buf(&x);
+ ei_x_free(&x);
+
+ ei_x_new_with_version(&x);
+ fun.arity = 1;
+ strcpy(fun.module, "erlang");
+ fun.type = EI_FUN_EXPORT;
+ fun.u.exprt.func = "abs";
+ ei_x_encode_fun(&x, &fun);
+ send_printed_buf(&x);
+ ei_x_free(&x);
+
+ report(1);
+}
diff --git a/lib/kernel/doc/src/notes.xml b/lib/kernel/doc/src/notes.xml
index 6f68a67174..f1ff8d97f7 100644
--- a/lib/kernel/doc/src/notes.xml
+++ b/lib/kernel/doc/src/notes.xml
@@ -129,6 +129,21 @@
</section>
+<section><title>Kernel 6.3.1.1</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>
+ Fix type spec for <c>seq_trace:set_token/2</c>.</p>
+ <p>
+ Own Id: OTP-15858 Aux Id: ERL-700 </p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
<section><title>Kernel 6.3.1</title>
<section><title>Fixed Bugs and Malfunctions</title>
@@ -6027,4 +6042,3 @@
</section>
</section>
</chapter>
-
diff --git a/lib/kernel/src/code.erl b/lib/kernel/src/code.erl
index 7faef93609..964ede9bc9 100644
--- a/lib/kernel/src/code.erl
+++ b/lib/kernel/src/code.erl
@@ -19,6 +19,8 @@
%%
-module(code).
+-include_lib("kernel/include/logger.hrl").
+
%% This is the interface module to the code server. It also contains
%% some implementation details. See also related modules: code_*.erl
%% in this directory.
@@ -707,8 +709,20 @@ do_s(Lib) ->
start_get_mode() ->
case init:get_argument(mode) of
- {ok,[["embedded"]]} ->
- embedded;
+ {ok, [FirstMode | Rest]} ->
+ case Rest of
+ [] ->
+ ok;
+ _ ->
+ ?LOG_WARNING("Multiple -mode given to erl, using the first, ~p",
+ [FirstMode])
+ end,
+ case FirstMode of
+ ["embedded"] ->
+ embedded;
+ _ ->
+ interactive
+ end;
_ ->
interactive
end.
diff --git a/lib/kernel/src/gen_sctp.erl b/lib/kernel/src/gen_sctp.erl
index d893d44079..a63df54ff9 100644
--- a/lib/kernel/src/gen_sctp.erl
+++ b/lib/kernel/src/gen_sctp.erl
@@ -217,24 +217,29 @@ peeloff(S, AssocId) when is_port(S), is_integer(AssocId) ->
Error -> Error
end.
--spec connect(Socket, Addr, Port, Opts) -> {ok, Assoc} | {error, inet:posix()} when
+-spec connect(Socket, Addr, Port, Opts) ->
+ {ok, #sctp_assoc_change{state :: 'comm_up'}} |
+ {error, #sctp_assoc_change{state :: 'cant_assoc'}} |
+ {error, inet:posix()}
+ when
Socket :: sctp_socket(),
Addr :: inet:ip_address() | inet:hostname(),
Port :: inet:port_number(),
- Opts :: [Opt :: option()],
- Assoc :: #sctp_assoc_change{}.
+ Opts :: [Opt :: option()].
connect(S, Addr, Port, Opts) ->
connect(S, Addr, Port, Opts, infinity).
-spec connect(Socket, Addr, Port, Opts, Timeout) ->
- {ok, Assoc} | {error, inet:posix()} when
+ {ok, #sctp_assoc_change{state :: 'comm_up'}} |
+ {error, #sctp_assoc_change{state :: 'cant_assoc'}} |
+ {error, inet:posix()}
+ when
Socket :: sctp_socket(),
Addr :: inet:ip_address() | inet:hostname(),
Port :: inet:port_number(),
Opts :: [Opt :: option()],
- Timeout :: timeout(),
- Assoc :: #sctp_assoc_change{}.
+ Timeout :: timeout().
connect(S, Addr, Port, Opts, Timeout) ->
case do_connect(S, Addr, Port, Opts, Timeout, true) of
diff --git a/lib/kernel/src/kernel.erl b/lib/kernel/src/kernel.erl
index bfa091a036..c8c631ab23 100644
--- a/lib/kernel/src/kernel.erl
+++ b/lib/kernel/src/kernel.erl
@@ -116,7 +116,7 @@ init([]) ->
restart => temporary,
shutdown => 2000,
type => supervisor,
- modules => [user_sup]},
+ modules => [standard_error]},
User = #{id => user,
start => {user_sup, start, []},
@@ -141,7 +141,7 @@ init([]) ->
modules => [logger_sup]},
case init:get_argument(mode) of
- {ok, [["minimal"]]} ->
+ {ok, [["minimal"]|_]} ->
{ok, {SupFlags,
[Code, File, StdError, User, LoggerSup, Config, RefC, SafeSup]}};
_ ->
diff --git a/lib/kernel/src/logger_std_h.erl b/lib/kernel/src/logger_std_h.erl
index c8f1acfca4..2b078ef091 100644
--- a/lib/kernel/src/logger_std_h.erl
+++ b/lib/kernel/src/logger_std_h.erl
@@ -170,9 +170,11 @@ check_h_config(_Type,[]) ->
ok.
normalize_config(#{type:={file,File}}=HConfig) ->
- HConfig#{type=>file,file=>File};
+ normalize_config(HConfig#{type=>file,file=>File});
normalize_config(#{type:={file,File,Modes}}=HConfig) ->
- HConfig#{type=>file,file=>File,modes=>Modes};
+ normalize_config(HConfig#{type=>file,file=>File,modes=>Modes});
+normalize_config(#{file:=File}=HConfig) ->
+ HConfig#{file=>filename:absname(File)};
normalize_config(HConfig) ->
HConfig.
@@ -188,7 +190,7 @@ merge_default_config(Name,Type,HConfig) ->
get_default_config(Name,file) ->
#{type => file,
- file => atom_to_list(Name),
+ file => filename:absname(atom_to_list(Name)),
modes => [raw,append],
file_check => 0,
max_no_bytes => infinity,
diff --git a/lib/kernel/src/seq_trace.erl b/lib/kernel/src/seq_trace.erl
index 4f9d7b3e5c..f0bd1fabe9 100644
--- a/lib/kernel/src/seq_trace.erl
+++ b/lib/kernel/src/seq_trace.erl
@@ -59,7 +59,7 @@ set_token({Flags,Label,Serial,_From,Lastcnt}) ->
F = decode_flags(Flags),
set_token2([{label,Label},{serial,{Lastcnt, Serial}} | F]).
--spec set_token(Component, Val) -> {Component, OldVal} when
+-spec set_token(Component, Val) -> OldVal when
Component :: component(),
Val :: value(),
OldVal :: value().
diff --git a/lib/kernel/test/code_SUITE.erl b/lib/kernel/test/code_SUITE.erl
index 4f0847084f..6b133f8d6b 100644
--- a/lib/kernel/test/code_SUITE.erl
+++ b/lib/kernel/test/code_SUITE.erl
@@ -41,7 +41,7 @@
big_boot_embedded/1,
module_status/1,
native_early_modules/1, get_mode/1,
- normalized_paths/1]).
+ normalized_paths/1, mult_embedded_flags/1]).
-export([init_per_testcase/2, end_per_testcase/2,
init_per_suite/1, end_per_suite/1]).
@@ -72,7 +72,8 @@ all() ->
on_load_purge, on_load_self_call, on_load_pending,
on_load_deleted,
module_status,
- big_boot_embedded, native_early_modules, get_mode, normalized_paths].
+ big_boot_embedded, native_early_modules, get_mode, normalized_paths,
+ mult_embedded_flags].
%% These need to run in order
groups() -> [{sequence, [sequence], [on_load_update,
@@ -354,7 +355,7 @@ load_abs(Config) when is_list(Config) ->
ensure_loaded(Config) when is_list(Config) ->
{module, lists} = code:ensure_loaded(lists),
case init:get_argument(mode) of
- {ok, [["embedded"]]} ->
+ {ok, [["embedded"] | _]} ->
{error, embedded} = code:ensure_loaded(code_b_test),
{error, badarg} = code:ensure_loaded(34),
ok;
@@ -1836,6 +1837,28 @@ do_normalized_paths([M|Ms]) ->
do_normalized_paths([]) ->
ok.
+%% Make sure that the extra -mode flags are ignored
+mult_embedded_flags(_Config) ->
+ Modes = [{" -mode embedded", embedded},
+ {" -mode interactive", interactive},
+ {" -mode invalid", interactive}],
+
+ [ begin
+ {ArgMode, ExpectedMode} = Mode,
+ {ok, Node} = start_node(mode_test, ArgMode),
+ ExpectedMode = rpc:call(Node, code, get_mode, []),
+ true = stop_node(Node)
+ end || Mode <- Modes],
+
+ [ begin
+ {ArgIgnoredMode, _} = IgnoredMode,
+ {ArgRelevantMode, ExpectedMode} = RelevantMode,
+ {ok, Node} = start_node(mode_test, ArgRelevantMode ++ ArgIgnoredMode),
+ ExpectedMode = rpc:call(Node, code, get_mode, []),
+ true = stop_node(Node)
+ end || IgnoredMode <- Modes, RelevantMode <- Modes],
+ ok.
+
%% Test that module_status/1 behaves as expected
module_status(_Config) ->
case test_server:is_cover() of
diff --git a/lib/kernel/test/gen_tcp_misc_SUITE.erl b/lib/kernel/test/gen_tcp_misc_SUITE.erl
index edf30448c4..c91808d4ae 100644
--- a/lib/kernel/test/gen_tcp_misc_SUITE.erl
+++ b/lib/kernel/test/gen_tcp_misc_SUITE.erl
@@ -36,7 +36,8 @@
show_econnreset_passive/1, econnreset_after_sync_send/1,
econnreset_after_async_send_active/1,
econnreset_after_async_send_active_once/1,
- econnreset_after_async_send_passive/1, linger_zero/1,
+ econnreset_after_async_send_passive/1,
+ linger_zero/1, linger_zero_sndbuf/1,
default_options/1, http_bad_packet/1,
busy_send/1, busy_disconnect_passive/1, busy_disconnect_active/1,
fill_sendq/1, partial_recv_and_close/1,
@@ -80,7 +81,8 @@ all() ->
show_econnreset_passive, econnreset_after_sync_send,
econnreset_after_async_send_active,
econnreset_after_async_send_active_once,
- econnreset_after_async_send_passive, linger_zero,
+ econnreset_after_async_send_passive,
+ linger_zero, linger_zero_sndbuf,
default_options, http_bad_packet, busy_send,
busy_disconnect_passive, busy_disconnect_active,
fill_sendq, partial_recv_and_close,
@@ -1356,7 +1358,42 @@ linger_zero(Config) when is_list(Config) ->
ok = gen_tcp:close(Client),
ok = ct:sleep(1),
undefined = erlang:port_info(Client, connected),
- {error, econnreset} = gen_tcp:recv(S, PayloadSize).
+ {error, econnreset} = gen_tcp:recv(S, PayloadSize),
+ ok.
+
+
+linger_zero_sndbuf(Config) when is_list(Config) ->
+ %% All the econnreset tests will prove that {linger, {true, 0}} aborts
+ %% a connection when the driver queue is empty. We will test here
+ %% that it also works when the driver queue is not empty
+ %% and the linger zero option is set on the listen socket.
+ {OS, _} = os:type(),
+ {ok, Listen} =
+ gen_tcp:listen(0, [{active, false},
+ {recbuf, 4096},
+ {show_econnreset, true},
+ {linger, {true, 0}}]),
+ {ok, Port} = inet:port(Listen),
+ {ok, Client} =
+ gen_tcp:connect(localhost, Port,
+ [{active, false},
+ {sndbuf, 4096}]),
+ {ok, Server} = gen_tcp:accept(Listen),
+ ok = gen_tcp:close(Listen),
+ PayloadSize = 1024 * 1024,
+ Payload = binary:copy(<<"0123456789ABCDEF">>, 256 * 1024), % 1 MB
+ ok = gen_tcp:send(Server, Payload),
+ case erlang:port_info(Server, queue_size) of
+ {queue_size, N} when N > 0 -> ok;
+ {queue_size, 0} when OS =:= win32 -> ok;
+ {queue_size, 0} = T -> ct:fail(T)
+ end,
+ {ok, [{linger, {true, 0}}]} = inet:getopts(Server, [linger]),
+ ok = gen_tcp:close(Server),
+ ok = ct:sleep(1),
+ undefined = erlang:port_info(Server, connected),
+ {error, closed} = gen_tcp:recv(Client, PayloadSize),
+ ok.
%% Thanks to Luke Gorrie. Tests for a very specific problem with
diff --git a/lib/kernel/test/logger_std_h_SUITE.erl b/lib/kernel/test/logger_std_h_SUITE.erl
index 16ab0e97fc..2b2d509860 100644
--- a/lib/kernel/test/logger_std_h_SUITE.erl
+++ b/lib/kernel/test/logger_std_h_SUITE.erl
@@ -132,6 +132,7 @@ all() ->
bad_input,
reconfig,
file_opts,
+ relative_file_path,
sync,
write_failure,
sync_failure,
@@ -693,6 +694,54 @@ file_opts(Config) ->
file_opts(cleanup, _Config) ->
logger:remove_handler(?MODULE).
+relative_file_path(_Config) ->
+ {ok,Dir} = file:get_cwd(),
+ AbsName1 = filename:join(Dir,?MODULE),
+ ok = logger:add_handler(?MODULE,
+ logger_std_h,
+ #{config => #{type=>file},
+ filter_default=>log,
+ filters=>?DEFAULT_HANDLER_FILTERS([?MODULE]),
+ formatter=>{?MODULE,self()}}),
+ #{cb_state := #{handler_state := #{file:=AbsName1}}} =
+ logger_olp:info(h_proc_name()),
+ {ok,#{config := #{file:=AbsName1}}} =
+ logger:get_handler_config(?MODULE),
+ ok = logger:remove_handler(?MODULE),
+
+ RelName2 = filename:join(atom_to_list(?FUNCTION_NAME),
+ lists:concat([?FUNCTION_NAME,".log"])),
+ AbsName2 = filename:join(Dir,RelName2),
+ ok = logger:add_handler(?MODULE,
+ logger_std_h,
+ #{config => #{file => RelName2},
+ filter_default=>log,
+ filters=>?DEFAULT_HANDLER_FILTERS([?MODULE]),
+ formatter=>{?MODULE,self()}}),
+ #{cb_state := #{handler_state := #{file:=AbsName2}}} =
+ logger_olp:info(h_proc_name()),
+ {ok,#{config := #{file:=AbsName2}}} =
+ logger:get_handler_config(?MODULE),
+ logger:notice(M1=?msg,?domain),
+ ?check(M1),
+ B1 = ?bin(M1),
+ try_read_file(AbsName2, {ok,B1}, filesync_rep_int()),
+
+ ok = file:set_cwd(".."),
+ logger:notice(M2=?msg,?domain),
+ ?check(M2),
+ B20 = ?bin(M2),
+ B2 = <<B1/binary,B20/binary>>,
+ try_read_file(AbsName2, {ok,B2}, filesync_rep_int()),
+
+ {error,_} = logger:update_handler_config(?MODULE,config,#{file=>RelName2}),
+ ok = logger:update_handler_config(?MODULE,config,#{file=>AbsName2}),
+ ok = file:set_cwd(Dir),
+ ok = logger:update_handler_config(?MODULE,config,#{file=>RelName2}),
+ ok.
+relative_file_path(cleanup,_Config) ->
+ logger:remove_handler(?MODULE).
+
sync(Config) ->
Dir = ?config(priv_dir,Config),
diff --git a/lib/kernel/test/seq_trace_SUITE.erl b/lib/kernel/test/seq_trace_SUITE.erl
index 663f910751..83a94ab087 100644
--- a/lib/kernel/test/seq_trace_SUITE.erl
+++ b/lib/kernel/test/seq_trace_SUITE.erl
@@ -26,6 +26,7 @@
init_per_group/2,end_per_group/2,
init_per_testcase/2,end_per_testcase/2]).
-export([token_set_get/1, tracer_set_get/1, print/1,
+ old_heap_token/1,
send/1, distributed_send/1, recv/1, distributed_recv/1,
trace_exit/1, distributed_exit/1, call/1, port/1,
match_set_seq_token/1, gc_seq_token/1, label_capability_mismatch/1,
@@ -50,6 +51,7 @@ suite() ->
all() ->
[token_set_get, tracer_set_get, print, send, send_literal,
distributed_send, recv, distributed_recv, trace_exit,
+ old_heap_token,
distributed_exit, call, port, match_set_seq_token,
gc_seq_token, label_capability_mismatch].
@@ -149,17 +151,19 @@ tracer_set_get(Config) when is_list(Config) ->
ok.
print(Config) when is_list(Config) ->
- lists:foreach(fun do_print/1, ?TIMESTAMP_MODES).
+ [do_print(TsType, Label) || TsType <- ?TIMESTAMP_MODES,
+ Label <- [17, "label"]].
-do_print(TsType) ->
+do_print(TsType, Label) ->
start_tracer(),
+ seq_trace:set_token(label, Label),
set_token_flags([print, TsType]),
- seq_trace:print(0,print1),
+ seq_trace:print(Label,print1),
seq_trace:print(1,print2),
seq_trace:print(print3),
seq_trace:reset_trace(),
- [{0,{print,_,_,[],print1}, Ts0},
- {0,{print,_,_,[],print3}, Ts1}] = stop_tracer(2),
+ [{Label,{print,_,_,[],print1}, Ts0},
+ {Label,{print,_,_,[],print3}, Ts1}] = stop_tracer(2),
check_ts(TsType, Ts0),
check_ts(TsType, Ts1).
@@ -563,6 +567,24 @@ get_port_message(Port) ->
end.
+%% OTP-15849 ERL-700
+%% Verify changing label on existing token when it resides on old heap.
+%% Bug caused faulty ref from old to new heap.
+old_heap_token(Config) when is_list(Config) ->
+ seq_trace:set_token(label, 1),
+ erlang:garbage_collect(self(), [{type, minor}]),
+ erlang:garbage_collect(self(), [{type, minor}]),
+ %% Now token tuple should be on old-heap.
+ %% Set a new non-literal label which should reside on new-heap.
+ NewLabel = {self(), "new label"},
+ 1 = seq_trace:set_token(label, NewLabel),
+
+ %% If bug, we now have a ref from old to new heap. Yet another minor gc
+ %% will make that a ref to deallocated memory.
+ erlang:garbage_collect(self(), [{type, minor}]),
+ {label,NewLabel} = seq_trace:get_token(label),
+ ok.
+
match_set_seq_token(doc) ->
["Tests that match spec function set_seq_token does not "
diff --git a/lib/public_key/asn1/CMSAesRsaesOaep.asn1 b/lib/public_key/asn1/CMSAesRsaesOaep.asn1
new file mode 100644
index 0000000000..ca8c7b7f92
--- /dev/null
+++ b/lib/public_key/asn1/CMSAesRsaesOaep.asn1
@@ -0,0 +1,39 @@
+CMSAesRsaesOaep {iso(1) member-body(2) us(840) rsadsi(113549)
+ pkcs(1) pkcs-9(9) smime(16) modules(0) id-mod-cms-aes(19) }
+
+
+DEFINITIONS IMPLICIT TAGS ::=
+BEGIN
+
+-- EXPORTS ALL --
+IMPORTS
+ -- PKIX
+ AlgorithmIdentifier
+ FROM PKIX1Explicit88 {iso(1) identified-organization(3) dod(6)
+ internet(1) security(5) mechanisms(5) pkix(7) id-mod(0)
+ id-pkix1-explicit(18)};
+
+-- AES information object identifiers --
+
+aes OBJECT IDENTIFIER ::= { joint-iso-itu-t(2) country(16) us(840)
+ organization(1) gov(101) csor(3) nistAlgorithms(4) 1 }
+
+-- AES using CBC-chaining mode for key sizes of 128, 192, 256
+
+id-aes128-CBC OBJECT IDENTIFIER ::= { aes 2 }
+id-aes192-CBC OBJECT IDENTIFIER ::= { aes 22 }
+id-aes256-CBC OBJECT IDENTIFIER ::= { aes 42 }
+
+-- AES-IV is a the parameter for all the above object identifiers.
+
+AES-IV ::= OCTET STRING (SIZE(16))
+
+
+-- AES Key Wrap Algorithm Identifiers - Parameter is absent
+
+id-aes128-wrap OBJECT IDENTIFIER ::= { aes 5 }
+id-aes192-wrap OBJECT IDENTIFIER ::= { aes 25 }
+id-aes256-wrap OBJECT IDENTIFIER ::= { aes 45 }
+
+
+END
diff --git a/lib/public_key/asn1/Makefile b/lib/public_key/asn1/Makefile
index a920ea87ea..10952106c6 100644
--- a/lib/public_key/asn1/Makefile
+++ b/lib/public_key/asn1/Makefile
@@ -42,7 +42,7 @@ RELSYSDIR = $(RELEASE_PATH)/lib/public_key-$(VSN)
ASN_TOP = OTP-PUB-KEY PKCS-FRAME
ASN_MODULES = PKIX1Explicit88 PKIX1Implicit88 PKIX1Algorithms88 \
PKIXAttributeCertificate PKCS-1 PKCS-3 PKCS-7 PKCS-8 PKCS-10 PKCS5v2-0 OTP-PKIX \
- InformationFramework RFC5639
+ InformationFramework RFC5639 CMSAesRsaesOaep
ASN_ASNS = $(ASN_MODULES:%=%.asn1)
ASN_ERLS = $(ASN_TOP:%=%.erl)
ASN_HRLS = $(ASN_TOP:%=%.hrl)
diff --git a/lib/public_key/asn1/OTP-PUB-KEY.set.asn b/lib/public_key/asn1/OTP-PUB-KEY.set.asn
index b3f3ccdb77..7ab1684ff3 100644
--- a/lib/public_key/asn1/OTP-PUB-KEY.set.asn
+++ b/lib/public_key/asn1/OTP-PUB-KEY.set.asn
@@ -10,3 +10,5 @@ ECPrivateKey.asn1
PKCS-7.asn1
PKCS-10.asn1
RFC5639.asn1
+CMSAesRsaesOaep.asn1
+
diff --git a/lib/public_key/doc/src/public_key_app.xml b/lib/public_key/doc/src/public_key_app.xml
index 923a9f1dfb..5f2c50711a 100644
--- a/lib/public_key/doc/src/public_key_app.xml
+++ b/lib/public_key/doc/src/public_key_app.xml
@@ -51,6 +51,9 @@
Diffie-Hellman Key Agreement Standard </item>
<item>Supports <url href="http://www.ietf.org/rfc/rfc2898.txt"> PKCS-5</url> -
Password-Based Cryptography Standard </item>
+ <item>Supports <url href="http://www.ietf.org/rfc/fc3565.txt"> AES </url> -
+ Use of the Advanced Encryption Standard (AES) Algorithm in Cryptographic Message Syntax (CMS)
+ </item>
<item>Supports <url href="http://www.ietf.org/rfc/rfc5208.txt"> PKCS-8</url> -
Private-Key Information Syntax Standard</item>
<item>Supports <url href="http://www.ietf.org/rfc/rfc5967.txt"> PKCS-10</url> -
diff --git a/lib/public_key/src/pubkey_pbe.erl b/lib/public_key/src/pubkey_pbe.erl
index e6bcedd1b1..6003bf21d0 100644
--- a/lib/public_key/src/pubkey_pbe.erl
+++ b/lib/public_key/src/pubkey_pbe.erl
@@ -26,9 +26,7 @@
-export([encode/4, decode/4, decrypt_parameters/1, encrypt_parameters/1]).
-export([pbdkdf1/4, pbdkdf2/7]).
--define(DEFAULT_SHA_MAC_KEYLEN, 20).
-define(ASN1_OCTET_STR_TAG, 4).
--define(IV_LEN, 8).
%%====================================================================
%% Internal application API
@@ -41,14 +39,23 @@
%%--------------------------------------------------------------------
encode(Data, Password, "DES-CBC" = Cipher, KeyDevParams) ->
{Key, IV} = password_to_key_and_iv(Password, Cipher, KeyDevParams),
- crypto:block_encrypt(des_cbc, Key, IV, pbe_pad(Data, KeyDevParams));
+ crypto:block_encrypt(des_cbc, Key, IV, pbe_pad(Data, block_size(des_cbc)));
encode(Data, Password, "DES-EDE3-CBC" = Cipher, KeyDevParams) ->
{Key, IV} = password_to_key_and_iv(Password, Cipher, KeyDevParams),
<<Key1:8/binary, Key2:8/binary, Key3:8/binary>> = Key,
- crypto:block_encrypt(des3_cbc, [Key1, Key2, Key3], IV, pbe_pad(Data));
+ crypto:block_encrypt(des3_cbc, [Key1, Key2, Key3], IV, pbe_pad(Data, block_size(des_3ede)));
encode(Data, Password, "RC2-CBC" = Cipher, KeyDevParams) ->
{Key, IV} = password_to_key_and_iv(Password, Cipher, KeyDevParams),
- crypto:block_encrypt(rc2_cbc, Key, IV, pbe_pad(Data, KeyDevParams)).
+ crypto:block_encrypt(rc2_cbc, Key, IV, pbe_pad(Data, block_size(rc2_cbc)));
+encode(Data, Password, "AES-128-CBC" = Cipher, KeyDevParams) ->
+ {Key, IV} = password_to_key_and_iv(Password, Cipher, KeyDevParams),
+ crypto:block_encrypt(aes_128_cbc, Key, IV, pbe_pad(Data, block_size(aes_128_cbc)));
+encode(Data, Password, "AES-192-CBC" = Cipher, KeyDevParams) ->
+ {Key, IV} = password_to_key_and_iv(Password, Cipher, KeyDevParams),
+ crypto:block_encrypt(aes_192_cbc, Key, IV, pbe_pad(Data, block_size(aes_192_cbc)));
+encode(Data, Password, "AES-256-CBC"= Cipher, KeyDevParams) ->
+ {Key, IV} = password_to_key_and_iv(Password, Cipher, KeyDevParams),
+ crypto:block_encrypt(aes_256_cbc, Key, IV, pbe_pad(Data, block_size(aes_256_cbc))).
%%--------------------------------------------------------------------
-spec decode(binary(), string(), string(), term()) -> binary().
@@ -67,14 +74,16 @@ decode(Data, Password,"RC2-CBC"= Cipher, KeyDevParams) ->
crypto:block_decrypt(rc2_cbc, Key, IV, Data);
decode(Data, Password,"AES-128-CBC"= Cipher, KeyDevParams) ->
{Key, IV} = password_to_key_and_iv(Password, Cipher, KeyDevParams),
- crypto:block_decrypt(aes_cbc128, Key, IV, Data);
-decode(Data, Password,"AES-256-CBC"= Cipher, KeyDevParams) ->
+ crypto:block_decrypt(aes_128_cbc, Key, IV, Data);
+decode(Data, Password,"AES-192-CBC"= Cipher, KeyDevParams) ->
+ {Key, IV} = password_to_key_and_iv(Password, Cipher, KeyDevParams),
+ crypto:block_decrypt(aes_192_cbc, Key, IV, Data);
+decode(Data, Password,"AES-256-CBC"= Cipher, KeyDevParams) ->
{Key, IV} = password_to_key_and_iv(Password, Cipher, KeyDevParams),
- crypto:block_decrypt(aes_cbc256, Key, IV, Data).
-
+ crypto:block_decrypt(aes_256_cbc, Key, IV, Data).
%%--------------------------------------------------------------------
--spec pbdkdf1(string(), iodata(), integer(), atom()) -> binary().
+-spec pbdkdf1(iodata(), iodata(), integer(), atom()) -> binary().
%%
%% Description: Implements password based decryption key derive function 1.
%% Exported mainly for testing purposes.
@@ -86,7 +95,7 @@ pbdkdf1(Password, Salt, Count, Hash) ->
do_pbdkdf1(Result, Count-1, Result, Hash).
%%--------------------------------------------------------------------
--spec pbdkdf2(string(), iodata(), integer(), integer(), fun(), atom(), integer())
+-spec pbdkdf2(iodata(), iodata(), integer(), integer(), fun(), atom(), integer())
-> binary().
%%
%% Description: Implements password based decryption key derive function 2.
@@ -150,17 +159,15 @@ do_pbdkdf1(Prev, Count, Acc, Hash) ->
Result = crypto:hash(Hash, Prev),
do_pbdkdf1(Result, Count-1 , <<Result/binary, Acc/binary>>, Hash).
-iv(#'PBES2-params_encryptionScheme'{algorithm = Algo,
- parameters = ASN1IV})
- when (Algo == ?'desCBC') or
- (Algo == ?'des-EDE3-CBC') ->
- <<?ASN1_OCTET_STR_TAG, ?IV_LEN, IV:?IV_LEN/binary>> = decode_handle_open_type_wrapper(ASN1IV),
- IV;
iv(#'PBES2-params_encryptionScheme'{algorithm = ?'rc2CBC',
parameters = ASN1IV}) ->
{ok, #'RC2-CBC-Parameter'{iv = IV}}
= 'PKCS-FRAME':decode('RC2-CBC-Parameter', decode_handle_open_type_wrapper(ASN1IV)),
- iolist_to_binary(IV).
+ iolist_to_binary(IV);
+iv(#'PBES2-params_encryptionScheme'{algorithm = _Algo,
+ parameters = ASN1IV}) ->
+ <<?ASN1_OCTET_STR_TAG, Len:8/unsigned-big-integer, IV:Len/binary>> = decode_handle_open_type_wrapper(ASN1IV),
+ IV.
blocks(1, N, Index, Password, Salt, Count, Prf, PrfHash, PrfLen, Acc) ->
<<XorSum:N/binary, _/binary>> = xor_sum(Password, Salt, Count, Index, Prf, PrfHash, PrfLen),
@@ -217,17 +224,9 @@ pbe1_oid("RC2-CBC", md5) ->
pbe1_oid("DES-CBC", md5) ->
?'pbeWithMD5AndDES-CBC'.
-pbe_pad(Data, {#'PBEParameter'{}, _}) ->
- pbe_pad(Data);
-pbe_pad(Data, #'PBES2-params'{}) ->
- pbe_pad(Data);
-pbe_pad(Data, _) ->
-pbe_pad(Data).%% Data.
-
-
-pbe_pad(Data) ->
- N = 8 - (erlang:byte_size(Data) rem 8),
- Pad = list_to_binary(lists:duplicate(N, N)),
+pbe_pad(Data, BlockSize) ->
+ N = BlockSize - (erlang:byte_size(Data) rem BlockSize),
+ Pad = binary:copy(<<N>>, N),
<<Data/binary, Pad/binary>>.
key_derivation_params(#'PBES2-params'{keyDerivationFunc = KeyDerivationFunc,
@@ -249,11 +248,27 @@ key_derivation_params(#'PBES2-params'{keyDerivationFunc = KeyDerivationFunc,
pseudo_random_function(#'PBKDF2-params_prf'{algorithm =
{_,_, _,'id-hmacWithSHA1'}}) ->
{fun crypto:hmac/4, sha, pseudo_output_length(?'id-hmacWithSHA1')};
-pseudo_random_function(#'PBKDF2-params_prf'{algorithm = ?'id-hmacWithSHA1'}) ->
- {fun crypto:hmac/4, sha, pseudo_output_length(?'id-hmacWithSHA1')}.
+pseudo_random_function(#'PBKDF2-params_prf'{algorithm = ?'id-hmacWithSHA1' = Algo}) ->
+ {fun crypto:hmac/4, sha, pseudo_output_length(Algo)};
+pseudo_random_function(#'PBKDF2-params_prf'{algorithm = ?'id-hmacWithSHA224'= Algo}) ->
+ {fun crypto:hmac/4, sha224, pseudo_output_length(Algo)};
+pseudo_random_function(#'PBKDF2-params_prf'{algorithm = ?'id-hmacWithSHA256' = Algo}) ->
+ {fun crypto:hmac/4, sha256, pseudo_output_length(Algo)};
+pseudo_random_function(#'PBKDF2-params_prf'{algorithm = ?'id-hmacWithSHA384' = Algo}) ->
+ {fun crypto:hmac/4, sha384, pseudo_output_length(Algo)};
+pseudo_random_function(#'PBKDF2-params_prf'{algorithm = ?'id-hmacWithSHA512' = Algo}) ->
+ {fun crypto:hmac/4, sha512, pseudo_output_length(Algo)}.
pseudo_output_length(?'id-hmacWithSHA1') ->
- ?DEFAULT_SHA_MAC_KEYLEN.
+ 20; %%160/8
+pseudo_output_length(?'id-hmacWithSHA224') ->
+ 28; %%%224/8
+pseudo_output_length(?'id-hmacWithSHA256') ->
+ 32; %%256/8
+pseudo_output_length(?'id-hmacWithSHA384') ->
+ 48; %%384/8
+pseudo_output_length(?'id-hmacWithSHA512') ->
+ 64. %%512/8
derived_key_length(_, Len) when is_integer(Len) ->
Len;
@@ -266,11 +281,33 @@ derived_key_length(Cipher,_) when (Cipher == ?'rc2CBC') or
derived_key_length(Cipher,_) when (Cipher == ?'des-EDE3-CBC') or
(Cipher == "DES-EDE3-CBC") ->
24;
-derived_key_length(Cipher,_) when (Cipher == "AES-128-CBC") ->
+
+derived_key_length(Cipher,_) when (Cipher == "AES-128-CBC");
+ (Cipher == ?'id-aes128-CBC') ->
16;
-derived_key_length(Cipher,_) when (Cipher == "AES-256-CBC") ->
+derived_key_length(Cipher,_) when (Cipher == "AES-192-CBC");
+ (Cipher == ?'id-aes192-CBC') ->
+ 24;
+
+derived_key_length(Cipher,_) when (Cipher == "AES-256-CBC");
+ (Cipher == ?'id-aes256-CBC') ->
32.
+block_size(Cipher) when Cipher == rc2_cbc;
+ Cipher == des_cbc;
+ Cipher == des_3ede ->
+ 8;
+block_size(Cipher) when Cipher == aes_128_cbc;
+ Cipher == aes_192_cbc;
+ Cipher == aes_256_cbc ->
+ 16.
+
+cipher(#'PBES2-params_encryptionScheme'{algorithm = ?'id-aes128-CBC'}) ->
+ "AES-128-CBC";
+cipher(#'PBES2-params_encryptionScheme'{algorithm = ?'id-aes192-CBC'}) ->
+ "AES-192-CBC";
+cipher(#'PBES2-params_encryptionScheme'{algorithm = ?'id-aes256-CBC'}) ->
+ "AES-256-CBC";
cipher(#'PBES2-params_encryptionScheme'{algorithm = ?'desCBC'}) ->
"DES-CBC";
cipher(#'PBES2-params_encryptionScheme'{algorithm = ?'des-EDE3-CBC'}) ->
diff --git a/lib/public_key/test/pbe_SUITE.erl b/lib/public_key/test/pbe_SUITE.erl
index 1136267411..61db282dfa 100644
--- a/lib/public_key/test/pbe_SUITE.erl
+++ b/lib/public_key/test/pbe_SUITE.erl
@@ -206,7 +206,10 @@ pbes2() ->
[{doc,"Tests encode/decode EncryptedPrivateKeyInfo encrypted with different ciphers using PBES2"}].
pbes2(Config) when is_list(Config) ->
decode_encode_key_file("pbes2_des_cbc_enc_key.pem", "password", "DES-CBC", Config),
- decode_encode_key_file("pbes2_des_ede3_cbc_enc_key.pem", "password", "DES-EDE3-CBC", Config),
+ decode_encode_key_file("pbes2_des_ede3_cbc_enc_key.pem", "password", "DES-EDE3-CBC", Config),
+ decode_encode_key_file("pbes2_aes_128_enc_key.pem", "password", "AES-128-CBC", Config),
+ decode_encode_key_file("pbes2_aes_192_enc_key.pem", "password", "AES-192-CBC", Config),
+ decode_encode_key_file("pbes2_aes_256_enc_key.pem", "password", "AES-256-CBC", Config),
case lists:member(rc2_cbc, proplists:get_value(ciphers, crypto:supports())) of
true ->
decode_encode_key_file("pbes2_rc2_cbc_enc_key.pem", "password", "RC2-CBC", Config);
@@ -239,7 +242,6 @@ decode_encode_key_file(File, Password, Cipher, Config) ->
{ok, PemKey} = file:read_file(filename:join(Datadir, File)),
PemEntry = public_key:pem_decode(PemKey),
- ct:pal("Pem entry: ~p" , [PemEntry]),
[{Asn1Type, _, {Cipher,_} = CipherInfo} = PubEntry] = PemEntry,
#'RSAPrivateKey'{} = KeyInfo = public_key:pem_entry_decode(PubEntry, Password),
PemKey1 = public_key:pem_encode([public_key:pem_entry_encode(Asn1Type, KeyInfo, {CipherInfo, Password})]),
diff --git a/lib/public_key/test/pbe_SUITE_data/pbes2_aes_128_enc_key.pem b/lib/public_key/test/pbe_SUITE_data/pbes2_aes_128_enc_key.pem
new file mode 100644
index 0000000000..5702119ad6
--- /dev/null
+++ b/lib/public_key/test/pbe_SUITE_data/pbes2_aes_128_enc_key.pem
@@ -0,0 +1,30 @@
+-----BEGIN ENCRYPTED PRIVATE KEY-----
+MIIFLTBXBgkqhkiG9w0BBQ0wSjApBgkqhkiG9w0BBQwwHAQIWrPgmqJqNpICAggA
+MAwGCCqGSIb3DQIJBQAwHQYJYIZIAWUDBAECBBA/bbIMYqQMUDxMk9ifPR7ABIIE
+0Drfqke1/ccFxk786hTh36yjVo48Xx7B3Scb92KtmyQpNaR6GbR+jhP9cxIcvmGN
+YroCB896VJSIx8PraqGgIJ1hblZXyfLanB0mUnZvaaQ4xp3UJT53a0yOm5Lfd+fB
+0TyaoEzca2jA5EVVh3yH6gzNsvQJRw6cQP5CAptLjiUv2jrwVGnO8x8X4egJDLZS
+Sb8B5AW8h1sGsyKEEFto6gpBjVqnVn5veMoI/Cfs9qDr071+dhbps/m6pseKKp0z
+8qeFM7+9Y4npD1VYg2gqOFi19QAI3gwq6tC8grOzRA8dPFUgpV9eMToVsI2OFQc1
+xnFZEV7NZVymh5HjKM1jwFy6es+5TFoMtRu6vDxKS6Y13lIlZ4oQSh8aXtG5Ylt2
+CqsKNHyDbZUpvKe/k19TBmVXQBCYFuN733jI9/4JBtpygnxwt1aXCvq/PFFGsTS4
+p1JOQvr/jaD7b4JO6IMXH1kSVxiMXKXNG7wPUNr6OWJvc7OqdclsZa7ibEx4L52x
+DuFmsxQo4a3iibhbcjr436OmR5Uw2UAstB5qxWfMhkt+e7rRhCOh/3O7SAYEpt+f
+Zr2VFXdGme4kR6uMCzgGiSh0qCseQXpJUZVufn/Go9r+601OJTJIQ9a2VoqlMR8o
+Dd14D0gBXXaZkY60Mh8iXR/MjKDuv0KBUyBzfcpk3fLmv0PhGSkbn6j+q1jZbogm
+EhI0AL5s2EoofuBdvgdusBhCrrwCMonprqR7BuaKPD0GEw5utnT5ovcUg/sjMJox
+10100QwAzQScU4iG/xic/TsN+ZMumhUcYs003MsZkRLvCEFxZurEMx7819CqfhIc
+NGd7ETTBSwoNf5pXRTHaTbW6pPiIeWunLUUVsRcNoBtL/cXmg+mu1zdsD7nD51mJ
+vG9A7LPW7XVl2Jv2NgQoKkHYO7cVozmcz6AE2z1q+XN4LGto8JEZktb6E7UIyXXg
+Ls4Tv0sn5TLgtaJ31w4+9iybNiGoVYOc4h0s5DoNR4ivcZ6n/Qnf8PTrNzejEJY6
+R/UnDbc24u0palGc1kei99d0BYodnq4OlAj7M7ML0GncftInhgA0Dp81YG5PujMa
+irhvwtnD5Xysfh1YrroAEN7Qxc8+2JlpgNSFlFFkMgfibc6jvTX6/C6MaFz8hiOq
+W43ZBEzjMIs23ZrJKOJGsuTdHSob+VbvqIMgS2PeGb/6g3/GjdipCbynNhX3zUOM
+3j/lpZOiAwE/Bftr5FOSfTFpnyorIIeyWgROEZTTL4eSYvnBjzf+tUdXY7ltxJie
+q0rpQ42X7+B4gTo8Qj/xC7LXSCldERK57cCwwITvjcHwxPyOiJ9BMI1HlRQ/Fo3C
+lPYIst1xjJ67qrTm6mWkor2hUOZcg4MOOzXWuijWRGJ/Wz0H+GKWtoE2X536D6sy
+a4Nwwj09oFY4Fph/SUNwy0MLpTSzikpUx6mxjbs3Odvo6tWWVcicp/dCWYCqLpGU
+3axEb/qlsaRNtKJg9O3Fq7hh1BTyLNGB2ET5wSKtlSD0bDeF15bBvkHB3z2/lDls
+YQ2hEHMjeSEZZyGTPqEHwtBuUwiWBBXwOIhT8nfYXbHWR0CLBLth2+E/JCaO9hD2
+V277arqNFa8nugZMwS+ragi6vbgIX4BiS/rnfYXgqaxD
+-----END ENCRYPTED PRIVATE KEY-----
diff --git a/lib/public_key/test/pbe_SUITE_data/pbes2_aes_192_enc_key.pem b/lib/public_key/test/pbe_SUITE_data/pbes2_aes_192_enc_key.pem
new file mode 100644
index 0000000000..ee82e9f667
--- /dev/null
+++ b/lib/public_key/test/pbe_SUITE_data/pbes2_aes_192_enc_key.pem
@@ -0,0 +1,30 @@
+-----BEGIN ENCRYPTED PRIVATE KEY-----
+MIIFLTBXBgkqhkiG9w0BBQ0wSjApBgkqhkiG9w0BBQwwHAQIcqBCM7v+ZlkCAggA
+MAwGCCqGSIb3DQIJBQAwHQYJYIZIAWUDBAEWBBD93r4IWBhvry+cdfwIDOKeBIIE
+0DXM8S70sMsUmwxRZQtKwGfYddEWIc9lrEdsgEEuonF6NrseRq7QdXnBSPwq5f0O
+ofMZ/0OCun3Qg1ls1EdsyKdijSOq27ZhHCnmWi1Rw1ApJIAq5i/jY8U17+lUakvG
+VtcsuRzlKmFxbBW44kLK7vK6xiA76HPx0I4ZXcdywR0pbLT1ubbhbQ9djLnBiYkT
+odszGTyxNceEse1Hu/RhFK17tnwov0fdioKY2i9F7qfq8lYLPrusEKTY7tOVjFOh
+bXeCry1BL0KTt65JVGR9xQCI0qokEU0QrCgD6skq7Vx2C/Ho1sW6h8FBFVIm6ozO
+bEUtVk3Xgs5yieetha1GxJAang1VxAPemnXfOmVapoSgSv1BQyDdnk3067Sfkh64
+A5yf44BUjvJsSd/ViCVmCryoXU7KOMAdFkyRSiDDLQus6bZGEhc6f+VEikG+TZ2L
+xxY4OucE2Bz67S6ycyOUpXKo0+FW0juE6NTJdlYSXWOvfciZKA83h6yAej6MfUEu
+4orIvnCTVO7i3+hHybnSgftj42jrqqZzeXll8rkGHg4syrKRVaDD6qfJjgAHBJkJ
+pZT4zZwuJ1puWfBykI25S4mKUnk0erq4N5jpGqdm7U14fWBWCjZN85jY4WgZZOJx
+kBNO2NbmZKzZEzRGyMJ563z4l7MNfzZBHv+FeBNkX146J4ZhMbT8IXPGV9peNWqu
+mY2B9RhN4hlDrd3Hfz5uiiF3UGrFkDcsPRBHWGqQ20YpuOQNno7iL8N0FWauERw1
+dvxAGVwFfUznR3wc/eyGcnRhqQhlYPspukh0IVIyEbre3yVFSG/41GQYQfg08XYd
+LYiiDUu1i515/GeDvYN5VcnZ4nMhPgqfxW4rEUZjI86p++bqwqGy8eOCivkzGV3A
+IFWQwlvKKzU7tSdi3uHUq5v7xQsJrALdf67JVjCCGfUZa17O41vmm58L/vKhhL2Y
+mLz/H004DPsB+CtWoLwqZ8Jmb1EHwqNbna3tGHn3n63j2cV7gykZFa/zXeuBbbJ/
+t4ZIojIEzwAVKA9Xzcl3wyGCRr62WJPEcOqe4kBYREuKd22juPEm9RQgciIIj0tP
+eJVpD0QarGGzERsaq7pheAiWisO+Q4cLjF8Mb3/r89abnd4AQk6meabFJIE2dXWp
+LZy3I6FkNQ7L7LxNOILhnaWzWGdOBVwHeAAxfbLOzM22ewj7oUwBCRpsBJ8zl2PL
+VhUjX6N26YoiR9gE1RBaVrwRkYLmkyGvrowCDoZVPxvJqbfIESQE42zGB9DbEPNp
+WXCnzAg5cIjNC31We274yLE7dpNPVRXPJCRhtp7noorWVzDdKB+dFvg08bIir6Vj
+1gxy8DvuZE1Gq9vqx38V7Cy2MrSpsgapw5mli4n5cMafE7Ty3j5pBJFF2f3jUn6B
+7MjCrKp1d8v6MEy18J/Ugu1Lytb92LMcNtWBKmqyCSxekrUB9/FC2hWqOpdwRI6q
+QMWkwshjyEhmlr2PAkBPM4uVzUFc9lBw1GzOUChkr9jiINdbsUSRJrwZ32Nc3gRY
+yKzWbEELPSgRcXwXgH3QqZukvmk2tBMTIxilXqKTLmd7t/AEnIhkbqC0pfnyChyU
+YlFkme0RpAXpgbDJgv+Vk+1/1s6gyaNSzT4s2Q340WIO
+-----END ENCRYPTED PRIVATE KEY-----
diff --git a/lib/public_key/test/pbe_SUITE_data/pbes2_aes_256_enc_key.pem b/lib/public_key/test/pbe_SUITE_data/pbes2_aes_256_enc_key.pem
new file mode 100644
index 0000000000..050337aead
--- /dev/null
+++ b/lib/public_key/test/pbe_SUITE_data/pbes2_aes_256_enc_key.pem
@@ -0,0 +1,30 @@
+-----BEGIN ENCRYPTED PRIVATE KEY-----
+MIIFLTBXBgkqhkiG9w0BBQ0wSjApBgkqhkiG9w0BBQwwHAQI4MxgpDiHxQcCAggA
+MAwGCCqGSIb3DQIJBQAwHQYJYIZIAWUDBAEqBBA2g/L8XmlK2axDkeYJCltnBIIE
+0C3+NQ93DzEK/9qicy1sj0Vag1M7AeJjTGGpatETCxM+eHjk4kNNeDeMV5+EmCSu
+Db4P48uvHOBGGCcqdjnQovfQsAh81GWxgF3yqpd4OKn2RubMLO4/Qu+zGtt/XRKz
+T0pyHHBu6hyPSOhad2SIjKWuaHepwxGYaejLP83sy6yhm0sEmyBUn4nGSTOROcqR
+wd7EbwU2PYUcrRGGxtChU7MUNt48wBO50Xmri1ssPPtZV6MHio4IoIz4hqzCjvAc
+VE1BqAvNIJ7icpdnL8Jqq0lfwEmGjFCkAjgov5fNW9I1b44jE2Tv5LM2urMH8InQ
+9qNjTHozYQhHAk9nX4cmMgHsIhkOd7Z2M+nz8Hd1tj9DmBNOr5XbfyctgVntaMB4
+GGnThuNlX8d5giOKOcaNPMpLU1jtfDcb73mEhwCYcdo1PM0rjrYZ7qetjXJW/oHs
+Nl/hIZIRpMuCRVuXHml4G+ziKbMnXUN8sbtvgkQatYFHFQOhAqZeyzWp8SlDcfqb
+Zt0LlZVJEhKUYzZgKoe7SmR1rXTTCfYeB75PddyYwVgf/IkT6HJ/y1apGOP6/UJ8
+7UV6zssQA35gMsYDT36sH2hAQvA/cOFxSxrip0gm0xXOeFF0gbyZWbFqk0aULaeF
+rbBoMe28akxdE4eD06b+TP2NguUGP72l3TPOlG4PQVScweMw9L3oPXOVj4Vbbd0y
+DenNvRHlWIwOh/y7ADTHSWq9CE45QDBvFaTcn43JQWD8xCmhAhI/9H+fhAQUhABm
+P5QoJLE2IGo8A+Gi7rfgYQb3fCgqcn8azsRJzozhE+oXxMvxEESejYTtm26FNmLg
+ONTWysF9BiaKHt2IXwRX97691wZqv5wJEaxeeJxfVQ6MlAHoEDXe49VxGN4zFXuq
+Yb71JdQDgM94jwc/PoUwFH2ALSkIciiKwU0xfFpptycl4qWpy9m7QTIKw0DjgCfg
+MuySPRGM5jn3yVg72ux2Qf9MKNEybWjZ+Se9MJ1IZmZK5eOo6L2JsFCc0nRn908E
+vn4gAgUfMxyCZ1ygXfxINVAixR+6KPHsz1QTIxTZkrlnXRsuEu1ZfBSHzmXESvJo
+3I9PkP/Iekg1FBpB5xxd7mXwCj17EWqYXWsLnfd8SblMjRYd64q7hfx0oU/MJ1wi
+KadkGcyAGVRyleJRBR0LleYj/2sDihrRQY4zu5UtzSMFMH0XWjSWk5+ZQb+z3iDc
+Ud4GHcHiuTMH+i03ApZGWLN9v93za/15fsnZogstgJkaHxizTz5JuCkRf15xd8+O
+EH77Tsfizjp+h2NF/wcr4OSD0i+H0mwZWajpZ3UmSeJ0BFK6ODEbmVycrInpHo3n
+zyMJnEDTJXL3HUwZSLjO5e5cNaB+75tdHrj2yJtRLuaJFr02b0EO1MUYfuUuqlK4
+7mg7FkBsimW+CXkoLRjHYK88ibT3G+rZ/STf4S/jxiRjBi06FAql3H02K5i1umgB
+0BaaQei0Z8wQxMeTEnGzL+OcJeqDA1ZRFeXe7DNGsX1jeTYKPHA/Dr2IdZqyiCr2
+xh6e7RJuUe4D2liXW8LlMdwhN/7xSinA031PgBmb8XzSRmfdHhytFkA8PiM5T2ew
+NR3qXBJ/G7BuRa/t26RuKI3BMVoBQPhGx80ds10uJjxq
+-----END ENCRYPTED PRIVATE KEY-----
diff --git a/lib/snmp/src/agent/snmp_community_mib.erl b/lib/snmp/src/agent/snmp_community_mib.erl
index 9fd7b30f9f..984b0bcee1 100644
--- a/lib/snmp/src/agent/snmp_community_mib.erl
+++ b/lib/snmp/src/agent/snmp_community_mib.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1999-2016. All Rights Reserved.
+%% Copyright Ericsson AB 1999-2019. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -206,10 +206,10 @@ do_add_community(Community) ->
{error, create_failed}
end
catch
- {error, Reason} ->
- {error, Reason};
- Class:Reason ->
- {error, {Class, Reason, erlang:get_stacktrace()}}
+ throw:{error, _} = ERROR ->
+ ERROR;
+ C:E:S ->
+ {error, {C, E, S}}
end.
%% FIXME: does not work with mnesia
diff --git a/lib/snmp/src/agent/snmp_generic.erl b/lib/snmp/src/agent/snmp_generic.erl
index e67a1b3c80..26a0dd0648 100644
--- a/lib/snmp/src/agent/snmp_generic.erl
+++ b/lib/snmp/src/agent/snmp_generic.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1996-2017. All Rights Reserved.
+%% Copyright Ericsson AB 1996-2019. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -421,12 +421,12 @@ table_check_status(NameDb, Col, ?'RowStatus_createAndGo', RowIndex, Cols) ->
_Found -> {inconsistentValue, Col}
end
catch
- _:_Reason ->
+ _:_E:_S ->
?vtrace(
"failed construct row (createAndGo): "
- " n Reason: ~p"
- " n Stack: ~p",
- [_Reason, erlang:get_stacktrace()]),
+ " n Error: ~p"
+ " n Stack: ~p",
+ [_E, _S]),
{noCreation, Col} % Bad RowIndex
end;
true -> {inconsistentValue, Col}
@@ -441,12 +441,12 @@ table_check_status(NameDb, Col, ?'RowStatus_createAndWait', RowIndex, Cols) ->
_Row ->
{noError, 0}
catch
- _:_Reason ->
+ _:_E:_S ->
?vtrace(
"failed construct row (createAndWait): "
- " n Reason: ~p"
- " n Stack: ~p",
- [_Reason, erlang:get_stacktrace()]),
+ " n Error: ~p"
+ " n Stack: ~p",
+ [_E, _S]),
{noCreation, Col} % Bad RowIndex
end;
true -> {inconsistentValue, Col}
diff --git a/lib/snmp/src/agent/snmp_standard_mib.erl b/lib/snmp/src/agent/snmp_standard_mib.erl
index bfe471178d..679d2657c6 100644
--- a/lib/snmp/src/agent/snmp_standard_mib.erl
+++ b/lib/snmp/src/agent/snmp_standard_mib.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1996-2015. All Rights Reserved.
+%% Copyright Ericsson AB 1996-2019. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -27,6 +27,7 @@
-include("snmp_types.hrl").
-include("STANDARD-MIB.hrl").
+-include("snmpa_internal.hrl").
-define(VMODULE,"STANDARD-MIB").
-include("snmp_verbosity.hrl").
@@ -547,10 +548,12 @@ dummy(_Op) -> ok.
%%-----------------------------------------------------------------
snmp_set_serial_no(new) ->
snmp_generic:variable_func(new, {snmpSetSerialNo, volatile}),
- random:seed(erlang:phash2([node()]),
- erlang:monotonic_time(),
- erlang:unique_integer()),
- Val = random:uniform(2147483648) - 1,
+ ?SNMP_RAND_SEED(),
+ %% rand:seed(exrop,
+ %% {erlang:phash2([node()]),
+ %% erlang:monotonic_time(),
+ %% erlang:unique_integer()}),
+ Val = rand:uniform(2147483648) - 1,
snmp_generic:variable_func(set, Val, {snmpSetSerialNo, volatile});
snmp_set_serial_no(delete) ->
diff --git a/lib/snmp/src/agent/snmp_target_mib.erl b/lib/snmp/src/agent/snmp_target_mib.erl
index e65fa7f340..22fd3acb84 100644
--- a/lib/snmp/src/agent/snmp_target_mib.erl
+++ b/lib/snmp/src/agent/snmp_target_mib.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1998-2015. All Rights Reserved.
+%% Copyright Ericsson AB 1998-2019. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -42,6 +42,7 @@
-define(VMODULE,"TARGET-MIB").
-include("snmp_verbosity.hrl").
+-include("snmpa_internal.hrl").
%% Column not accessible via SNMP - needed when the agent sends informs
@@ -673,10 +674,12 @@ snmpTargetSpinLock(print) ->
snmpTargetSpinLock(new) ->
snmp_generic:variable_func(new, {snmpTargetSpinLock, volatile}),
- random:seed(erlang:phash2([node()]),
- erlang:monotonic_time(),
- erlang:unique_integer()),
- Val = random:uniform(2147483648) - 1,
+ ?SNMP_RAND_SEED(),
+ %% rand:seed(exrop,
+ %% {erlang:phash2([node()]),
+ %% erlang:monotonic_time(),
+ %% erlang:unique_integer()}),
+ Val = rand:uniform(2147483648) - 1,
snmp_generic:variable_func(set, Val, {snmpTargetSpinLock, volatile});
snmpTargetSpinLock(delete) ->
diff --git a/lib/snmp/src/agent/snmp_user_based_sm_mib.erl b/lib/snmp/src/agent/snmp_user_based_sm_mib.erl
index f6e4fd3951..4842669fa4 100644
--- a/lib/snmp/src/agent/snmp_user_based_sm_mib.erl
+++ b/lib/snmp/src/agent/snmp_user_based_sm_mib.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1999-2015. All Rights Reserved.
+%% Copyright Ericsson AB 1999-2019. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -440,10 +440,12 @@ usmUserSpinLock(print) ->
usmUserSpinLock(new) ->
snmp_generic:variable_func(new, {usmUserSpinLock, volatile}),
- random:seed(erlang:phash2([node()]),
- erlang:monotonic_time(),
- erlang:unique_integer()),
- Val = random:uniform(2147483648) - 1,
+ ?SNMP_RAND_SEED(),
+ %% rand:seed(exrop,
+ %% {erlang:phash2([node()]),
+ %% erlang:monotonic_time(),
+ %% erlang:unique_integer()}),
+ Val = rand:uniform(2147483648) - 1,
snmp_generic:variable_func(set, Val, {usmUserSpinLock, volatile});
usmUserSpinLock(delete) ->
diff --git a/lib/snmp/src/agent/snmp_view_based_acm_mib.erl b/lib/snmp/src/agent/snmp_view_based_acm_mib.erl
index c6eeb7cea2..56b5d96142 100644
--- a/lib/snmp/src/agent/snmp_view_based_acm_mib.erl
+++ b/lib/snmp/src/agent/snmp_view_based_acm_mib.erl
@@ -48,6 +48,7 @@
-include("SNMPv2-TC.hrl").
-include("SNMP-VIEW-BASED-ACM-MIB.hrl").
-include("snmpa_vacm.hrl").
+-include("snmpa_internal.hrl").
-define(VMODULE,"VACM-MIB").
@@ -860,10 +861,12 @@ vacmViewSpinLock(print) ->
vacmViewSpinLock(new) ->
snmp_generic:variable_func(new, volatile_db(vacmViewSpinLock)),
- random:seed(erlang:phash2([node()]),
- erlang:monotonic_time(),
- erlang:unique_integer()),
- Val = random:uniform(2147483648) - 1,
+ ?SNMP_RAND_SEED(),
+ %% rand:seed(exrop,
+ %% {erlang:phash2([node()]),
+ %% erlang:monotonic_time(),
+ %% erlang:unique_integer()}),
+ Val = rand:uniform(2147483648) - 1,
snmp_generic:variable_func(set, Val, volatile_db(vacmViewSpinLock));
vacmViewSpinLock(delete) ->
diff --git a/lib/snmp/src/agent/snmpa_mpd.erl b/lib/snmp/src/agent/snmpa_mpd.erl
index b440d57d03..2ec5dcb5e6 100644
--- a/lib/snmp/src/agent/snmpa_mpd.erl
+++ b/lib/snmp/src/agent/snmpa_mpd.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1997-2015. All Rights Reserved.
+%% Copyright Ericsson AB 1997-2019. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -76,11 +76,9 @@
init(Vsns) ->
?vlog("init -> entry with"
"~n Vsns: ~p", [Vsns]),
- random:seed(erlang:phash2([node()]),
- erlang:monotonic_time(),
- erlang:unique_integer()),
- ets:insert(snmp_agent_table, {msg_id, random:uniform(2147483647)}),
- ets:insert(snmp_agent_table, {req_id, random:uniform(2147483647)}),
+ ?SNMP_RAND_SEED(),
+ ets:insert(snmp_agent_table, {msg_id, rand:uniform(2147483647)}),
+ ets:insert(snmp_agent_table, {req_id, rand:uniform(2147483647)}),
init_counters(),
init_versions(Vsns, #state{}).
diff --git a/lib/snmp/src/agent/snmpa_trap.erl b/lib/snmp/src/agent/snmpa_trap.erl
index d04b6a206e..f741c3aaa9 100644
--- a/lib/snmp/src/agent/snmpa_trap.erl
+++ b/lib/snmp/src/agent/snmpa_trap.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1996-2016. All Rights Reserved.
+%% Copyright Ericsson AB 1996-2019. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -364,13 +364,14 @@ send_trap(TrapRec, NotifyName, ContextName, Recv, Vbs, LocalEngineID,
LocalEngineID, ExtraInfo, NetIf)
end
catch
- T:E ->
- Info = [{args, [TrapRec, NotifyName, ContextName,
- Recv, Vbs, LocalEngineID, ExtraInfo, NetIf]},
- {tag, T},
- {err, E},
- {stacktrace, erlang:get_stacktrace()}],
- ?vlog("snmpa_trap:send_trap exception: ~p", [Info]),
+ C:E:S ->
+ Info = [{args, [TrapRec, NotifyName, ContextName,
+ Recv, Vbs, LocalEngineID, ExtraInfo, NetIf]},
+ {class, C},
+ {err, E},
+ {stacktrace, S}],
+ ?vlog("snmpa_trap:send_trap exception: "
+ "~n ~p", [Info]),
{error, {failed_sending_trap, Info}}
end.
diff --git a/lib/snmp/src/agent/snmpa_usm.erl b/lib/snmp/src/agent/snmpa_usm.erl
index fb616cd9ef..1debceae98 100644
--- a/lib/snmp/src/agent/snmpa_usm.erl
+++ b/lib/snmp/src/agent/snmpa_usm.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1999-2015. All Rights Reserved.
+%% Copyright Ericsson AB 1999-2019. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -646,10 +646,12 @@ get_des_salt() ->
ets:insert(snmp_agent_table, {usm_des_salt, 0}),
0;
_ -> % it doesn't exist, initialize
- random:seed(erlang:phash2([node()]),
- erlang:monotonic_time(),
- erlang:unique_integer()),
- R = random:uniform(4294967295),
+ ?SNMP_RAND_SEED(),
+ %% rand:seed(exrop,
+ %% {erlang:phash2([node()]),
+ %% erlang:monotonic_time(),
+ %% erlang:unique_integer()}),
+ R = rand:uniform(4294967295),
ets:insert(snmp_agent_table, {usm_des_salt, R}),
R
end,
@@ -679,10 +681,12 @@ get_aes_salt() ->
ets:insert(snmp_agent_table, {usm_aes_salt, 0}),
0;
_ -> % it doesn't exist, initialize
- random:seed(erlang:phash2([node()]),
- erlang:monotonic_time(),
- erlang:unique_integer()),
- R = random:uniform(36893488147419103231),
+ ?SNMP_RAND_SEED(),
+ %% rand:seed(exrop,
+ %% {erlang:phash2([node()]),
+ %% erlang:monotonic_time(),
+ %% erlang:unique_integer()}),
+ R = rand:uniform(36893488147419103231),
ets:insert(snmp_agent_table, {usm_aes_salt, R}),
R
end,
diff --git a/lib/snmp/src/app/snmp_internal.hrl b/lib/snmp/src/app/snmp_internal.hrl
index 374767df15..f9a758ab7b 100644
--- a/lib/snmp/src/app/snmp_internal.hrl
+++ b/lib/snmp/src/app/snmp_internal.hrl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2006-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2006-2019. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -25,7 +25,12 @@
-define(APPLICATION, snmp).
-endif.
--define(STACK(), erlang:get_stacktrace()).
+
+-define(SNMP_RAND_SEED_ALG, exrop).
+-define(SNMP_RAND_SEED(), rand:seed(?SNMP_RAND_SEED_ALG,
+ {erlang:phash2([node()]),
+ erlang:monotonic_time(),
+ erlang:unique_integer()})).
-define(snmp_info(C, F, A), ?snmp_msg(info_msg, C, F, A)).
-define(snmp_warning(C, F, A), ?snmp_msg(warning_msg, C, F, A)).
@@ -39,5 +44,3 @@
-endif. % -ifdef(snmp_internal).
-
-
diff --git a/lib/snmp/src/compile/Makefile b/lib/snmp/src/compile/Makefile
index 4093ffa9ca..d9678669a5 100644
--- a/lib/snmp/src/compile/Makefile
+++ b/lib/snmp/src/compile/Makefile
@@ -2,7 +2,7 @@
# %CopyrightBegin%
#
-# Copyright Ericsson AB 1997-2016. All Rights Reserved.
+# Copyright Ericsson AB 1997-2019. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
@@ -59,6 +59,8 @@ PARSER_TARGET = $(PARSER_MODULE).$(EMULATOR)
# ----------------------------------------------------
# FLAGS
# ----------------------------------------------------
+ERL_COMPILE_FLAGS += -pa $(ERL_TOP)/lib/snmp/ebin
+
ifeq ($(WARN_UNUSED_VARS),true)
ERL_COMPILE_FLAGS += +warn_unused_vars
endif
diff --git a/lib/snmp/src/compile/snmpc.erl b/lib/snmp/src/compile/snmpc.erl
index c810bfcd41..4249799195 100644
--- a/lib/snmp/src/compile/snmpc.erl
+++ b/lib/snmp/src/compile/snmpc.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1997-2018. All Rights Reserved.
+%% Copyright Ericsson AB 1997-2019. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -31,6 +31,7 @@
-export([init/3]).
-include_lib("stdlib/include/erl_compile.hrl").
+-include_lib("snmp/src/app/snmp_internal.hrl").
-include("snmp_types.hrl").
-include("snmpc.hrl").
-include("snmpc_lib.hrl").
@@ -413,9 +414,11 @@ get_verbosity(Options) ->
%%----------------------------------------------------------------------
init(From, MibFileName, Options) ->
- random:seed(erlang:phash2([node()]),
- erlang:monotonic_time(),
- erlang:unique_integer()),
+ ?SNMP_RAND_SEED(),
+ %% rand:seed(exrop,
+ %% {erlang:phash2([node()]),
+ %% erlang:monotonic_time(),
+ %% erlang:unique_integer()}),
put(options, Options),
put(verbosity, get_verbosity(Options)),
put(description, get_description(Options)),
diff --git a/lib/snmp/src/manager/snmpm_config.erl b/lib/snmp/src/manager/snmpm_config.erl
index 118cdcd1df..cd9fecd4d4 100644
--- a/lib/snmp/src/manager/snmpm_config.erl
+++ b/lib/snmp/src/manager/snmpm_config.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2004-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2004-2019. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -479,10 +479,7 @@ agent_info(Domain, Address, Item) when is_atom(Domain) ->
NAddress ->
do_agent_info(Domain, NAddress, Item)
catch
- _Thrown ->
- %% p(?MODULE_STRING":agent_info(~p, ~p, ~p) throwed ~p at.~n"
- %% " ~p",
- %% [Domain, Address, Item, _Thrown, erlang:get_stacktrace()]),
+ _C:_E:_S ->
{error, not_found}
end;
agent_info(Ip, Port, Item) when is_integer(Port) ->
@@ -493,10 +490,7 @@ agent_info(Ip, Port, Item) when is_integer(Port) ->
Address ->
do_agent_info(Domain, Address, Item)
catch
- _Thrown ->
- %% p(?MODULE_STRING":agent_info(~p, ~p, ~p) throwed ~p at.~n"
- %% " ~p",
- %% [Ip, Port, Item, _Thrown, erlang:get_stacktrace()]),
+ _C:_E:_S ->
{error, not_found}
end.
@@ -1688,9 +1682,10 @@ read_agents_config_file(Dir) ->
Check = fun check_agent_config/2,
try read_file(Dir, "agents.conf", Order, Check, [])
catch
- throw:Error ->
- ?vlog("agent config error: ~p", [Error]),
- erlang:raise(throw, Error, erlang:get_stacktrace())
+ throw:E:S ->
+ ?vlog("agent config error: "
+ "~n ~p", [E]),
+ erlang:raise(throw, E, S)
end.
check_agent_config(Agent, State) ->
@@ -1935,9 +1930,10 @@ read_users_config_file(Dir) ->
Check = fun (User, State) -> {check_user_config(User), State} end,
try read_file(Dir, "users.conf", Order, Check, [])
catch
- throw:Error ->
- ?vlog("failure reading users config file: ~n ~p", [Error]),
- erlang:raise(throw, Error, erlang:get_stacktrace())
+ throw:E:S ->
+ ?vlog("failure reading users config file: "
+ "~n ~p", [E]),
+ erlang:raise(throw, E, S)
end.
check_user_config({Id, Mod, Data}) ->
@@ -2351,10 +2347,11 @@ read_file(Dir, FileName, Order, Check, Default) ->
read_file(Dir, FileName, Order, Check) ->
try snmp_conf:read(filename:join(Dir, FileName), Order, Check)
catch
- throw:{error, Reason} = Error
+ throw:{error, Reason} = E:S
when element(1, Reason) =:= failed_open ->
- error_msg("failed reading config from ~s: ~p", [FileName, Reason]),
- erlang:raise(throw, Error, erlang:get_stacktrace())
+ error_msg("failed reading config from ~s: "
+ "~n ~p", [FileName, Reason]),
+ erlang:raise(throw, E, S)
end.
%%--------------------------------------------------------------------
diff --git a/lib/snmp/src/manager/snmpm_mpd.erl b/lib/snmp/src/manager/snmpm_mpd.erl
index 191dc2c281..8d0a7918a6 100644
--- a/lib/snmp/src/manager/snmpm_mpd.erl
+++ b/lib/snmp/src/manager/snmpm_mpd.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2004-2015. All Rights Reserved.
+%% Copyright Ericsson AB 2004-2019. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -68,11 +68,13 @@
%%%-----------------------------------------------------------------
init(Vsns) ->
?vdebug("init -> entry with ~p", [Vsns]),
- random:seed(erlang:phash2([node()]),
- erlang:monotonic_time(),
- erlang:unique_integer()),
- snmpm_config:cre_counter(msg_id, random:uniform(2147483647)),
- snmpm_config:cre_counter(req_id, random:uniform(2147483647)),
+ ?SNMP_RAND_SEED(),
+ %% rand:seed(exrop,
+ %% {erlang:phash2([node()]),
+ %% erlang:monotonic_time(),
+ %% erlang:unique_integer()}),
+ snmpm_config:cre_counter(msg_id, rand:uniform(2147483647)),
+ snmpm_config:cre_counter(req_id, rand:uniform(2147483647)),
init_counters(),
State = init_versions(Vsns, #state{}),
init_usm(State#state.v3),
diff --git a/lib/snmp/src/manager/snmpm_net_if.erl b/lib/snmp/src/manager/snmpm_net_if.erl
index 29216f9d6a..184f782860 100644
--- a/lib/snmp/src/manager/snmpm_net_if.erl
+++ b/lib/snmp/src/manager/snmpm_net_if.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2004-2017. All Rights Reserved.
+%% Copyright Ericsson AB 2004-2019. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -182,11 +182,9 @@ worker(Worker, Failer, #state{log = Log} = State) ->
%% Winds up in handle_info {'DOWN', ...}
erlang:exit({net_if_worker, Result})
catch
- Class:Reason ->
+ C:E:S ->
%% Winds up in handle_info {'DOWN', ...}
- erlang:exit(
- {net_if_worker, Failer,
- Class, Reason, erlang:get_stacktrace()})
+ erlang:exit({net_if_worker, Failer, C, E, S})
end
end,
[monitor]).
@@ -983,11 +981,10 @@ udp_send(Sock, To, Msg) ->
error_msg("failed sending message to ~p:~p:~n"
" ~p",[IpAddr, IpPort, Reason])
catch
- error:Error ->
- error_msg("failed sending message to ~p:~p:~n"
- " error:~p~n"
- " ~p",
- [IpAddr, IpPort, Error, erlang:get_stacktrace()])
+ error:E:S ->
+ error_msg("failed sending message to ~p:~p:"
+ "~n ~p"
+ "~n ~p", [IpAddr, IpPort, E, S])
end.
sz(B) when is_binary(B) ->
diff --git a/lib/snmp/src/manager/snmpm_server.erl b/lib/snmp/src/manager/snmpm_server.erl
index c8d7fa1e8b..a6ca2b2b14 100644
--- a/lib/snmp/src/manager/snmpm_server.erl
+++ b/lib/snmp/src/manager/snmpm_server.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2004-2015. All Rights Reserved.
+%% Copyright Ericsson AB 2004-2019. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -1755,9 +1755,10 @@ handle_error(_UserId, Mod, Reason, ReqId, Data, _State) ->
Mod:handle_error(ReqId, Reason, Data)
end
catch
- T:E ->
+ C:E:S ->
CallbackArgs = [ReqId, Reason, Data],
- handle_invalid_result(handle_error, CallbackArgs, T, E)
+ handle_invalid_result(handle_error, CallbackArgs,
+ C, E, S)
end
end,
handle_callback(F),
@@ -1948,9 +1949,10 @@ handle_pdu(
Mod:handle_pdu(TargetName, ReqId, SnmpResponse, Data)
end
catch
- T:E ->
+ C:E:S ->
CallbackArgs = [TargetName, ReqId, SnmpResponse, Data],
- handle_invalid_result(handle_pdu, CallbackArgs, T, E)
+ handle_invalid_result(handle_pdu, CallbackArgs,
+ C, E, S)
end
end,
handle_callback(F),
@@ -2119,10 +2121,10 @@ do_handle_agent(DefUserId, DefMod,
"<~p,~p>: ~n~w", [Type, Domain, Addr, SnmpInfo])
end;
- T:E ->
+ C:E:S ->
CallbackArgs =
[Domain_or_Ip, Addr_or_Port, Type, SnmpInfo, DefData],
- handle_invalid_result(handle_agent, CallbackArgs, T, E)
+ handle_invalid_result(handle_agent, CallbackArgs, C, E, S)
end.
@@ -2331,8 +2333,8 @@ do_handle_trap(
handle_invalid_result(handle_trap, CallbackArgs, InvalidResult)
catch
- T:E ->
- handle_invalid_result(handle_trap, CallbackArgs, T, E)
+ C:E:S ->
+ handle_invalid_result(handle_trap, CallbackArgs, C, E, S)
end.
@@ -2523,8 +2525,8 @@ do_handle_inform(
reply
catch
- T:E ->
- handle_invalid_result(handle_inform, CallbackArgs, T, E),
+ C:E:S ->
+ handle_invalid_result(handle_inform, CallbackArgs, C, E, S),
reply
end,
@@ -2837,8 +2839,8 @@ do_handle_report(
reply
catch
- T:E ->
- handle_invalid_result(handle_report, CallbackArgs, T, E),
+ C:E:S ->
+ handle_invalid_result(handle_report, CallbackArgs, C, E, S),
reply
end.
@@ -2855,15 +2857,14 @@ handle_callback(F) ->
-handle_invalid_result(Func, Args, T, E) ->
- Stacktrace = ?STACK(),
+handle_invalid_result(Func, Args, C, E, S) ->
error_msg("Callback function failed: "
"~n Function: ~p"
"~n Args: ~p"
- "~n Error Type: ~p"
+ "~n Class: ~p"
"~n Error: ~p"
"~n Stacktrace: ~p",
- [Func, Args, T, E, Stacktrace]).
+ [Func, Args, C, E, S]).
handle_invalid_result(Func, Args, InvalidResult) ->
error_msg("Callback function returned invalid result: "
diff --git a/lib/snmp/src/misc/snmp_conf.erl b/lib/snmp/src/misc/snmp_conf.erl
index 513616a285..d73291764d 100644
--- a/lib/snmp/src/misc/snmp_conf.erl
+++ b/lib/snmp/src/misc/snmp_conf.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1996-2016. All Rights Reserved.
+%% Copyright Ericsson AB 1996-2019. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -236,15 +236,16 @@ read_check(File, Check, [{StartLine, Row, EndLine}|Lines], State, Res) ->
" NewRow: ~p~n", [NewRow]),
read_check(File, Check, Lines, NewState, [NewRow | Res])
catch
- {error, Reason} ->
- ?vtrace("read_check -> error:~n"
- " Reason: ~p", [Reason]),
+ throw:{error, Reason} ->
+ ?vtrace("read_check -> error:"
+ "~n Reason: ~p", [Reason]),
error({failed_check, File, StartLine, EndLine, Reason});
- Class:Reason ->
- Error = {Class,Reason,erlang:get_stacktrace()},
- ?vtrace("read_check -> failure:~n"
- " Error: ~p", [Error]),
- error({failed_check, File, StartLine, EndLine, Error})
+ C:E:S ->
+ ?vtrace("read_check -> failure:"
+ "~n Class: ~p"
+ "~n Error: ~p"
+ "~n Stack: ~p", [C, E, S]),
+ error({failed_check, File, StartLine, EndLine, {C, E, S}})
end.
open_file(File) ->
diff --git a/lib/snmp/src/misc/snmp_config.erl b/lib/snmp/src/misc/snmp_config.erl
index 45661b71a7..26e85897f4 100644
--- a/lib/snmp/src/misc/snmp_config.erl
+++ b/lib/snmp/src/misc/snmp_config.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1996-2016. All Rights Reserved.
+%% Copyright Ericsson AB 1996-2019. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -2573,15 +2573,17 @@ write_config_file(Dir, FileName, Order, Check, Write, Entries)
Error
end
catch
- Error ->
- S = erlang:get_stacktrace(),
- d("File write of ~s throwed: ~p~n ~p~n",
- [FileName, Error, S]),
- Error;
- C:E ->
- S = erlang:get_stacktrace(),
- d("File write of ~s exception: ~p:~p~n ~p~n",
- [FileName,C,E,S]),
+ throw:E:S ->
+ d("File write of ~s throwed: "
+ "~n ~p"
+ "~n ~p"
+ "~n", [FileName, E, S]),
+ E;
+ C:E:S ->
+ d("File write of ~s exception: "
+ "~n ~p:~p"
+ "~n ~p"
+ "~n", [FileName, C, E, S]),
{error, {failed_write, Dir, FileName, {C, E, S}}}
end.
@@ -2590,16 +2592,18 @@ write_config_file(Dir, FileName, Write, Entries, Fd) ->
ok ->
close_config_file(Dir, FileName, Fd)
catch
- Error ->
- S = erlang:get_stacktrace(),
- d("File write of ~s throwed: ~p~n ~p~n",
- [FileName, Error, S]),
+ throw:E:S ->
+ d("File write of ~s throwed: "
+ "~n ~p"
+ "~n ~p"
+ "~n", [FileName, E, S]),
close_config_file(Dir, FileName, Fd),
- Error;
- C:E ->
- S = erlang:get_stacktrace(),
- d("File write of ~s exception: ~p:~p~n ~p~n",
- [FileName,C,E,S]),
+ E;
+ C:E:S ->
+ d("File write of ~s exception: "
+ "~n ~p:~p"
+ "~n ~p"
+ "~n", [FileName, C, E, S]),
close_config_file(Dir, FileName, Fd),
{error, {failed_write, Dir, FileName, {C, E, S}}}
end.
@@ -2661,16 +2665,18 @@ append_config_file(Dir, FileName, Order, Check, Write, Entries, Fd) ->
ok ->
close_config_file(Dir, FileName, Fd)
catch
- Error ->
- S = erlang:get_stacktrace(),
- d("File append of ~s throwed: ~p~n ~p~n",
- [FileName, Error, S]),
+ throw:E:S ->
+ d("File append of ~s throwed: "
+ "~n ~p"
+ "~n ~p"
+ "~n", [FileName, E, S]),
close_config_file(Dir, FileName, Fd),
- Error;
- C:E ->
- S = erlang:get_stacktrace(),
- d("File append of ~s exception: ~p:~p~n ~p~n",
- [FileName,C,E,S]),
+ E;
+ C:E:S ->
+ d("File append of ~s exception: "
+ "~n ~p:~p"
+ "~n ~p"
+ "~n", [FileName, C, E, S]),
close_config_file(Dir, FileName, Fd),
{error, {failed_append, Dir, FileName, {C, E, S}}}
end.
@@ -2702,16 +2708,18 @@ read_config_file(Dir, FileName, Order, Check)
SortedLines = sort_lines(Lines, Order),
{ok, verify_lines(SortedLines, Check, undefined, [])}
catch
- Error ->
- S = erlang:get_stacktrace(),
- d("File read of ~s throwed: ~p~n ~p~n",
- [FileName, Error, S]),
- {error, Error};
- T:E ->
- S = erlang:get_stacktrace(),
- d("File read of ~s exception: ~p:~p~n ~p~n",
- [FileName,T,E,S]),
- {error, {failed_read, Dir, FileName, {T, E, S}}}
+ throw:E:S ->
+ d("File read of ~s throwed: "
+ "~n ~p"
+ "~n ~p"
+ "~n", [FileName, E, S]),
+ {error, E};
+ C:E:S ->
+ d("File read of ~s exception: "
+ "~n ~p:~p"
+ "~n ~p"
+ "~n", [FileName, C, E, S]),
+ {error, {failed_read, Dir, FileName, {C, E, S}}}
after
file:close(Fd)
end;
@@ -2760,11 +2768,10 @@ verify_lines(
{{ok, NewTerm}, NewState} ->
verify_lines(Lines, Check, NewState, [NewTerm|Acc])
catch
- {error, Reason} ->
+ throw:{error, Reason}:_ ->
throw({failed_check, StartLine, EndLine, Reason});
- C:R ->
- S = erlang:get_stacktrace(),
- throw({failed_check, StartLine, EndLine, {C, R, S}})
+ C:E:S ->
+ throw({failed_check, StartLine, EndLine, {C, E, S}})
end.
diff --git a/lib/snmp/test/snmp_manager_config_test.erl b/lib/snmp/test/snmp_manager_config_test.erl
index 64d3134055..ccbdd77629 100644
--- a/lib/snmp/test/snmp_manager_config_test.erl
+++ b/lib/snmp/test/snmp_manager_config_test.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2004-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2004-2019. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -35,6 +35,7 @@
-include_lib("common_test/include/ct.hrl").
-include("snmp_test_lib.hrl").
-include_lib("snmp/src/manager/snmpm_usm.hrl").
+-include_lib("snmp/src/app/snmp_internal.hrl").
%%----------------------------------------------------------------------
@@ -2259,11 +2260,13 @@ create_and_increment(Conf) when is_list(Conf) ->
?line {ok, _Pid} = snmpm_config:start_link(Opts),
%% Random init
- random:seed(erlang:phash2([node()]),
- erlang:monotonic_time(),
- erlang:unique_integer()),
+ ?SNMP_RAND_SEED(),
+ %% rand:seed(exrop,
+ %% {erlang:phash2([node()]),
+ %% erlang:monotonic_time(),
+ %% erlang:unique_integer()}),
- StartVal = random:uniform(2147483647),
+ StartVal = rand:uniform(2147483647),
IncVal = 42,
EndVal = StartVal + IncVal,
diff --git a/lib/snmp/test/snmp_test_mgr.erl b/lib/snmp/test/snmp_test_mgr.erl
index 73a4d56084..9190c07e6d 100644
--- a/lib/snmp/test/snmp_test_mgr.erl
+++ b/lib/snmp/test/snmp_test_mgr.erl
@@ -52,6 +52,7 @@
-include_lib("snmp/include/snmp_types.hrl").
-include_lib("snmp/include/STANDARD-MIB.hrl").
-include("snmp_test_lib.hrl").
+-include_lib("snmp/src/app/snmp_internal.hrl").
-record(state, {dbg = true,
quiet,
@@ -192,9 +193,11 @@ receive_trap(Timeout) ->
init({Options, CallerPid}) ->
put(sname, mgr),
put(verbosity, debug),
- random:seed(erlang:phash2([node()]),
- erlang:monotonic_time(),
- erlang:unique_integer()),
+ ?SNMP_RAND_SEED(),
+ %% rand:seed(exrop,
+ %% {erlang:phash2([node()]),
+ %% erlang:monotonic_time(),
+ %% erlang:unique_integer()}),
case (catch is_options_ok(Options)) of
true ->
put(debug, get_value(debug, Options, false)),
@@ -668,7 +671,6 @@ make_vb(Oid) ->
#varbind{oid = Oid, variabletype = 'NULL', value = 'NULL'}.
make_request_id() ->
- %% random:uniform(16#FFFFFFF-1).
snmp_test_mgr_counter_server:increment(mgr_request_id, 1, 1, 2147483647).
echo_pdu(PDU, MiniMIB) ->
@@ -1141,5 +1143,5 @@ d(_,_F,_A) ->
print(F, A) ->
?PRINT2("MGR " ++ F, A).
-formated_timestamp() ->
- snmp_test_lib:formated_timestamp().
+%% formated_timestamp() ->
+%% snmp_test_lib:formated_timestamp().
diff --git a/lib/ssh/src/Makefile b/lib/ssh/src/Makefile
index 6d64a45112..9627b70eeb 100644
--- a/lib/ssh/src/Makefile
+++ b/lib/ssh/src/Makefile
@@ -99,7 +99,7 @@ APP_TARGET= $(EBIN)/$(APP_FILE)
APPUP_SRC= $(APPUP_FILE).src
APPUP_TARGET= $(EBIN)/$(APPUP_FILE)
-INTERNAL_HRL_FILES = ssh_auth.hrl ssh_connect.hrl ssh_transport.hrl ssh.hrl ssh_userauth.hrl ssh_xfer.hrl
+INTERNAL_HRL_FILES = ssh_auth.hrl ssh_connect.hrl ssh_transport.hrl ssh.hrl ssh_xfer.hrl
# ----------------------------------------------------
# FLAGS
diff --git a/lib/ssh/src/ssh.hrl b/lib/ssh/src/ssh.hrl
index 04453e6ef0..54e98ee10e 100644
--- a/lib/ssh/src/ssh.hrl
+++ b/lib/ssh/src/ssh.hrl
@@ -68,6 +68,25 @@
-define(string(X), ?string_utf8(X)).
-define(binary(X), << ?STRING(X) >>).
+-define('2bin'(X), (if is_binary(X) -> X;
+ is_list(X) -> list_to_binary(X);
+ X==undefined -> <<>>
+ end) ).
+
+%% encoding macros
+-define('E...'(X), ?'2bin'(X)/binary ).
+-define(Eboolean(X), ?BOOLEAN(case X of
+ true -> ?TRUE;
+ false -> ?FALSE
+ end) ).
+-define(Ebyte(X), ?BYTE(X) ).
+-define(Euint32(X), ?UINT32(X) ).
+-define(Estring(X), ?STRING(?'2bin'(X)) ).
+-define(Estring_utf8(X), ?string_utf8(X)/binary ).
+-define(Ename_list(X), ?STRING(ssh_bits:name_list(X)) ).
+-define(Empint(X), (ssh_bits:mpint(X))/binary ).
+-define(Ebinary(X), ?STRING(X) ).
+
%% Cipher details
-define(SSH_CIPHER_NONE, 0).
-define(SSH_CIPHER_3DES, 3).
diff --git a/lib/ssh/src/ssh_message.erl b/lib/ssh/src/ssh_message.erl
index d95e58c1bb..7c86a81108 100644
--- a/lib/ssh/src/ssh_message.erl
+++ b/lib/ssh/src/ssh_message.erl
@@ -34,24 +34,6 @@
-export([dbg_trace/3]).
--define('2bin'(X), (if is_binary(X) -> X;
- is_list(X) -> list_to_binary(X);
- X==undefined -> <<>>
- end) ).
-
--define('E...'(X), ?'2bin'(X)/binary ).
--define(Eboolean(X), ?BOOLEAN(case X of
- true -> ?TRUE;
- false -> ?FALSE
- end) ).
--define(Ebyte(X), ?BYTE(X) ).
--define(Euint32(X), ?UINT32(X) ).
--define(Estring(X), ?STRING(?'2bin'(X)) ).
--define(Estring_utf8(X), ?string_utf8(X)/binary ).
--define(Ename_list(X), ?STRING(ssh_bits:name_list(X)) ).
--define(Empint(X), (ssh_bits:mpint(X))/binary ).
--define(Ebinary(X), ?STRING(X) ).
-
ucl(B) ->
try unicode:characters_to_list(B) of
L when is_list(L) -> L;
diff --git a/lib/ssh/src/ssh_transport.erl b/lib/ssh/src/ssh_transport.erl
index eaab13433a..a85926354e 100644
--- a/lib/ssh/src/ssh_transport.erl
+++ b/lib/ssh/src/ssh_transport.erl
@@ -61,14 +61,6 @@
-export([pack/3, adjust_algs_for_peer_version/2]).
-export([decompress/2, decrypt_blocks/3, is_valid_mac/3 ]). % FIXME: remove
--define(Estring(X), ?STRING((if is_binary(X) -> X;
- is_list(X) -> list_to_binary(X);
- X==undefined -> <<>>
- end))).
--define(Empint(X), (ssh_bits:mpint(X))/binary ).
--define(Ebinary(X), ?STRING(X) ).
--define(Euint32(X), ?UINT32(X) ).
-
%%%----------------------------------------------------------------------------
%%%
%%% There is a difference between supported and default algorithms. The
diff --git a/lib/ssh/src/ssh_userauth.hrl b/lib/ssh/src/ssh_userauth.hrl
deleted file mode 100644
index 2cfc1f0f83..0000000000
--- a/lib/ssh/src/ssh_userauth.hrl
+++ /dev/null
@@ -1,78 +0,0 @@
-%%
-%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 2005-2016. All Rights Reserved.
-%%
-%% Licensed under the Apache License, Version 2.0 (the "License");
-%% you may not use this file except in compliance with the License.
-%% You may obtain a copy of the License at
-%%
-%% http://www.apache.org/licenses/LICENSE-2.0
-%%
-%% Unless required by applicable law or agreed to in writing, software
-%% distributed under the License is distributed on an "AS IS" BASIS,
-%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%% See the License for the specific language governing permissions and
-%% limitations under the License.
-%%
-%% %CopyrightEnd%
-%%
-
-%%
-
-%%% Description: user authentication protocol
-
--define(SSH_MSG_USERAUTH_REQUEST, 50).
--define(SSH_MSG_USERAUTH_FAILURE, 51).
--define(SSH_MSG_USERAUTH_SUCCESS, 52).
--define(SSH_MSG_USERAUTH_BANNER, 53).
--define(SSH_MSG_USERAUTH_PK_OK, 60).
--define(SSH_MSG_USERAUTH_PASSWD_CHANGEREQ, 60).
--define(SSH_MSG_USERAUTH_INFO_REQUEST, 60).
--define(SSH_MSG_USERAUTH_INFO_RESPONSE, 61).
-
--record(ssh_msg_userauth_request,
- {
- user, %% string
- service, %% string
- method, %% string "publickey", "password"
- data %% opaque
- }).
-
--record(ssh_msg_userauth_failure,
- {
- authentications, %% string
- partial_success %% boolean
- }).
-
--record(ssh_msg_userauth_success,
- {
- }).
-
--record(ssh_msg_userauth_banner,
- {
- message, %% string
- language %% string
- }).
-
--record(ssh_msg_userauth_passwd_changereq,
- {
- prompt, %% string
- languge %% string
- }).
-
--record(ssh_msg_userauth_pk_ok,
- {
- algorithm_name, % string
- key_blob % string
- }).
-
--record(ssh_msg_userauth_info_request,
- {name,
- instruction,
- language_tag,
- num_prompts,
- data}).
--record(ssh_msg_userauth_info_response,
- {num_responses,
- data}).
diff --git a/lib/ssh/test/ssh_bench_SUITE.erl b/lib/ssh/test/ssh_bench_SUITE.erl
index 880c519a5e..5ff7a71c45 100644
--- a/lib/ssh/test/ssh_bench_SUITE.erl
+++ b/lib/ssh/test/ssh_bench_SUITE.erl
@@ -26,7 +26,7 @@
-include_lib("ssh/src/ssh.hrl").
-include_lib("ssh/src/ssh_transport.hrl").
-include_lib("ssh/src/ssh_connect.hrl").
--include_lib("ssh/src/ssh_userauth.hrl").
+-include_lib("ssh/src/ssh_auth.hrl").
%%%================================================================
%%%
diff --git a/lib/ssl/doc/src/notes.xml b/lib/ssl/doc/src/notes.xml
index 5c213402f4..6af5a500b5 100644
--- a/lib/ssl/doc/src/notes.xml
+++ b/lib/ssl/doc/src/notes.xml
@@ -149,6 +149,39 @@
</section>
+<section><title>SSL 9.2.3.2</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>
+ Returned "alert error string" is now same as logged alert
+ string</p>
+ <p>
+ Own Id: OTP-15844</p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
+<section><title>SSL 9.2.3.1</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>
+ Correct solution for retaining tcp flow control OTP-15802
+ (ERL-934) as to not break ssl:recv as reported in
+ (ERL-938)</p>
+ <p>
+ Own Id: OTP-15823 Aux Id: ERL-934, ERL-938 </p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
<section><title>SSL 9.2.3</title>
<section><title>Fixed Bugs and Malfunctions</title>
diff --git a/lib/ssl/doc/src/standards_compliance.xml b/lib/ssl/doc/src/standards_compliance.xml
index ca98385f85..3a472d4776 100644
--- a/lib/ssl/doc/src/standards_compliance.xml
+++ b/lib/ssl/doc/src/standards_compliance.xml
@@ -126,10 +126,10 @@
<section>
<title>TLS 1.3</title>
- <p>OTP-22 introduces basic support for TLS 1.3 on the server side. Basic functionality
+ <p>OTP-22 introduces basic support for TLS 1.3. Basic functionality
covers a simple TLS 1.3 handshake with support of the mandatory extensions
(supported_groups, signature_algorithms, key_share, supported_versions and
- signature_algorithms_cert). The server supports a selective set of cryptographic algorithms:</p>
+ signature_algorithms_cert). The current implementation supports a selective set of cryptographic algorithms:</p>
<list type="bulleted">
<item>Key Exchange: ECDHE</item>
<item>Groups: all standard groups supported for the Diffie-Hellman key exchange</item>
@@ -140,15 +140,12 @@
</list>
<p>Other notable features:</p>
<list type="bulleted">
- <item>The server supports the HelloRetryRequest mechanism</item>
<item>PSK and session resumption not supported</item>
<item>Early data and 0-RTT not supported</item>
<item>Key and Initialization Vector Update not supported</item>
</list>
<p>For more detailed information see the
<seealso marker="#soc_table">Standards Compliance</seealso> below.</p>
- <warning><p>Note that the client side is not yet functional. It is planned to be released
- later in OTP-22.</p></warning>
<p> The following table describes the current state of standards compliance for TLS 1.3.</p>
<p>(<em>C</em> = Compliant, <em>NC</em> = Non-Compliant, <em>PC</em> = Partially-Compliant,
@@ -176,25 +173,25 @@
<cell align="left" valign="middle"></cell>
<cell align="left" valign="middle">Version downgrade protection mechanism</cell>
<cell align="left" valign="middle"><em>C</em></cell>
- <cell align="left" valign="middle">22</cell>
+ <cell align="left" valign="middle"><em>22</em></cell>
</row>
<row>
<cell align="left" valign="middle"></cell>
<cell align="left" valign="middle">RSASSA-PSS signature schemes</cell>
<cell align="left" valign="middle"><em>PC</em></cell>
- <cell align="left" valign="middle">22</cell>
+ <cell align="left" valign="middle"><em>22</em></cell>
</row>
<row>
<cell align="left" valign="middle"></cell>
<cell align="left" valign="middle">supported_versions (ClientHello) extension</cell>
<cell align="left" valign="middle"><em>C</em></cell>
- <cell align="left" valign="middle">22</cell>
+ <cell align="left" valign="middle"><em>22</em></cell>
</row>
<row>
<cell align="left" valign="middle"></cell>
<cell align="left" valign="middle">signature_algorithms_cert extension</cell>
<cell align="left" valign="middle"><em>C</em></cell>
- <cell align="left" valign="middle">22</cell>
+ <cell align="left" valign="middle"><em>22</em></cell>
</row>
<row>
@@ -211,7 +208,7 @@
<cell align="left" valign="middle"></cell>
<cell align="left" valign="middle">(EC)DHE</cell>
<cell align="left" valign="middle"><em>C</em></cell>
- <cell align="left" valign="middle">22</cell>
+ <cell align="left" valign="middle"><em>22</em></cell>
</row>
<row>
<cell align="left" valign="middle"></cell>
@@ -295,8 +292,8 @@
</url>
</cell>
<cell align="left" valign="middle"><em>Client</em></cell>
- <cell align="left" valign="middle"><em>NC</em></cell>
- <cell align="left" valign="middle"></cell>
+ <cell align="left" valign="middle"><em>PC</em></cell>
+ <cell align="left" valign="middle"><em>22.1</em></cell>
</row>
<row>
<cell align="left" valign="middle"></cell>
@@ -319,14 +316,14 @@
<row>
<cell align="left" valign="middle"></cell>
<cell align="left" valign="middle">supported_groups (RFC7919)</cell>
- <cell align="left" valign="middle"><em>NC</em></cell>
- <cell align="left" valign="middle"></cell>
+ <cell align="left" valign="middle"><em>C</em></cell>
+ <cell align="left" valign="middle"><em>22.1</em></cell>
</row>
<row>
<cell align="left" valign="middle"></cell>
<cell align="left" valign="middle">signature_algorithms (RFC8446)</cell>
- <cell align="left" valign="middle"><em>NC</em></cell>
- <cell align="left" valign="middle"></cell>
+ <cell align="left" valign="middle"><em>C</em></cell>
+ <cell align="left" valign="middle"><em>22.1</em></cell>
</row>
<row>
<cell align="left" valign="middle"></cell>
@@ -343,8 +340,8 @@
<row>
<cell align="left" valign="middle"></cell>
<cell align="left" valign="middle">application_layer_protocol_negotiation (RFC7301)</cell>
- <cell align="left" valign="middle"><em>NC</em></cell>
- <cell align="left" valign="middle"></cell>
+ <cell align="left" valign="middle"><em>C</em></cell>
+ <cell align="left" valign="middle"><em>22.1</em></cell>
</row>
<row>
<cell align="left" valign="middle"></cell>
@@ -373,8 +370,8 @@
<row>
<cell align="left" valign="middle"></cell>
<cell align="left" valign="middle">key_share (RFC8446)</cell>
- <cell align="left" valign="middle"><em>NC</em></cell>
- <cell align="left" valign="middle"></cell>
+ <cell align="left" valign="middle"><em>C</em></cell>
+ <cell align="left" valign="middle"><em>22.1</em></cell>
</row>
<row>
<cell align="left" valign="middle"></cell>
@@ -403,8 +400,8 @@
<row>
<cell align="left" valign="middle"></cell>
<cell align="left" valign="middle">supported_versions (RFC8446)</cell>
- <cell align="left" valign="middle"><em>NC</em></cell>
- <cell align="left" valign="middle"></cell>
+ <cell align="left" valign="middle"><em>C</em></cell>
+ <cell align="left" valign="middle"><em>22.1</em></cell>
</row>
<row>
<cell align="left" valign="middle"></cell>
@@ -427,8 +424,8 @@
<row>
<cell align="left" valign="middle"></cell>
<cell align="left" valign="middle">signature_algorithms_cert (RFC8446)</cell>
- <cell align="left" valign="middle"><em>NC</em></cell>
- <cell align="left" valign="middle"></cell>
+ <cell align="left" valign="middle"><em>C</em></cell>
+ <cell align="left" valign="middle"><em>22.1</em></cell>
</row>
<row>
@@ -459,13 +456,13 @@
<cell align="left" valign="middle"></cell>
<cell align="left" valign="middle">supported_groups (RFC7919)</cell>
<cell align="left" valign="middle"><em>C</em></cell>
- <cell align="left" valign="middle">22</cell>
+ <cell align="left" valign="middle"><em>22</em></cell>
</row>
<row>
<cell align="left" valign="middle"></cell>
<cell align="left" valign="middle">signature_algorithms (RFC8446)</cell>
<cell align="left" valign="middle"><em>C</em></cell>
- <cell align="left" valign="middle">22</cell>
+ <cell align="left" valign="middle"><em>22</em></cell>
</row>
<row>
<cell align="left" valign="middle"></cell>
@@ -482,8 +479,8 @@
<row>
<cell align="left" valign="middle"></cell>
<cell align="left" valign="middle">application_layer_protocol_negotiation (RFC7301)</cell>
- <cell align="left" valign="middle"><em>NC</em></cell>
- <cell align="left" valign="middle"></cell>
+ <cell align="left" valign="middle"><em>C</em></cell>
+ <cell align="left" valign="middle"><em>22.1</em></cell>
</row>
<row>
<cell align="left" valign="middle"></cell>
@@ -513,7 +510,7 @@
<cell align="left" valign="middle"></cell>
<cell align="left" valign="middle">key_share (RFC8446)</cell>
<cell align="left" valign="middle"><em>C</em></cell>
- <cell align="left" valign="middle">22</cell>
+ <cell align="left" valign="middle"><em>22</em></cell>
</row>
<row>
<cell align="left" valign="middle"></cell>
@@ -543,7 +540,7 @@
<cell align="left" valign="middle"></cell>
<cell align="left" valign="middle">supported_versions (RFC8446)</cell>
<cell align="left" valign="middle"><em>C</em></cell>
- <cell align="left" valign="middle">22</cell>
+ <cell align="left" valign="middle"><em>22</em></cell>
</row>
<row>
<cell align="left" valign="middle"></cell>
@@ -567,7 +564,7 @@
<cell align="left" valign="middle"></cell>
<cell align="left" valign="middle">signature_algorithms_cert (RFC8446)</cell>
<cell align="left" valign="middle"><em>C</em></cell>
- <cell align="left" valign="middle">22</cell>
+ <cell align="left" valign="middle"><em>22</em></cell>
</row>
<row>
@@ -577,20 +574,20 @@
</url>
</cell>
<cell align="left" valign="middle"><em>Client</em></cell>
- <cell align="left" valign="middle"><em>NC</em></cell>
- <cell align="left" valign="middle"></cell>
+ <cell align="left" valign="middle"><em>PC</em></cell>
+ <cell align="left" valign="middle"><em>22.1</em></cell>
</row>
<row>
<cell align="left" valign="middle"></cell>
<cell align="left" valign="middle">Version downgrade protection</cell>
- <cell align="left" valign="middle"><em>NC</em></cell>
- <cell align="left" valign="middle"></cell>
+ <cell align="left" valign="middle"><em>C</em></cell>
+ <cell align="left" valign="middle"><em>22.1</em></cell>
</row>
<row>
<cell align="left" valign="middle"></cell>
<cell align="left" valign="middle">key_share (RFC8446)</cell>
- <cell align="left" valign="middle"><em>NC</em></cell>
- <cell align="left" valign="middle"></cell>
+ <cell align="left" valign="middle"><em>C</em></cell>
+ <cell align="left" valign="middle"><em>22.1</em></cell>
</row>
<row>
<cell align="left" valign="middle"></cell>
@@ -601,8 +598,8 @@
<row>
<cell align="left" valign="middle"></cell>
<cell align="left" valign="middle">supported_versions (RFC8446)</cell>
- <cell align="left" valign="middle"><em>NC</em></cell>
- <cell align="left" valign="middle"></cell>
+ <cell align="left" valign="middle"><em>C</em></cell>
+ <cell align="left" valign="middle"><em>22.1</em></cell>
</row>
<row>
@@ -615,13 +612,13 @@
<cell align="left" valign="middle"></cell>
<cell align="left" valign="middle">Version downgrade protection</cell>
<cell align="left" valign="middle"><em>C</em></cell>
- <cell align="left" valign="middle">22</cell>
+ <cell align="left" valign="middle"><em>22</em></cell>
</row>
<row>
<cell align="left" valign="middle"></cell>
<cell align="left" valign="middle">key_share (RFC8446)</cell>
<cell align="left" valign="middle"><em>C</em></cell>
- <cell align="left" valign="middle">22</cell>
+ <cell align="left" valign="middle"><em>22</em></cell>
</row>
<row>
<cell align="left" valign="middle"></cell>
@@ -633,7 +630,7 @@
<cell align="left" valign="middle"></cell>
<cell align="left" valign="middle">supported_versions (RFC8446)</cell>
<cell align="left" valign="middle"><em>C</em></cell>
- <cell align="left" valign="middle">22</cell>
+ <cell align="left" valign="middle"><em>22</em></cell>
</row>
<row>
@@ -650,7 +647,7 @@
<cell align="left" valign="middle"></cell>
<cell align="left" valign="middle">key_share (RFC8446)</cell>
<cell align="left" valign="middle"><em>C</em></cell>
- <cell align="left" valign="middle">22</cell>
+ <cell align="left" valign="middle"><em>22</em></cell>
</row>
<row>
<cell align="left" valign="middle"></cell>
@@ -662,7 +659,7 @@
<cell align="left" valign="middle"></cell>
<cell align="left" valign="middle">supported_versions (RFC8446)</cell>
<cell align="left" valign="middle"><em>C</em></cell>
- <cell align="left" valign="middle">22</cell>
+ <cell align="left" valign="middle"><em>22</em></cell>
</row>
<row>
@@ -672,8 +669,8 @@
</url>
</cell>
<cell align="left" valign="middle"><em>Client</em></cell>
- <cell align="left" valign="middle"><em>NC</em></cell>
- <cell align="left" valign="middle"></cell>
+ <cell align="left" valign="middle"><em>C</em></cell>
+ <cell align="left" valign="middle"><em>22.1</em></cell>
</row>
<row>
<cell align="left" valign="middle"></cell>
@@ -706,26 +703,26 @@
</url>
</cell>
<cell align="left" valign="middle"><em>Client</em></cell>
- <cell align="left" valign="middle"><em>NC</em></cell>
- <cell align="left" valign="middle"></cell>
+ <cell align="left" valign="middle"><em>PC</em></cell>
+ <cell align="left" valign="middle"><em>22.1</em></cell>
</row>
<row>
<cell align="left" valign="middle"></cell>
<cell align="left" valign="middle">rsa_pkcs1_sha256</cell>
- <cell align="left" valign="middle"><em>NC</em></cell>
- <cell align="left" valign="middle"></cell>
+ <cell align="left" valign="middle"><em>C</em></cell>
+ <cell align="left" valign="middle"><em>22.1</em></cell>
</row>
<row>
<cell align="left" valign="middle"></cell>
<cell align="left" valign="middle">rsa_pkcs1_sha384</cell>
- <cell align="left" valign="middle"><em>NC</em></cell>
- <cell align="left" valign="middle"></cell>
+ <cell align="left" valign="middle"><em>C</em></cell>
+ <cell align="left" valign="middle"><em>22.1</em></cell>
</row>
<row>
<cell align="left" valign="middle"></cell>
<cell align="left" valign="middle">rsa_pkcs1_sha512</cell>
- <cell align="left" valign="middle"><em>NC</em></cell>
- <cell align="left" valign="middle"></cell>
+ <cell align="left" valign="middle"><em>C</em></cell>
+ <cell align="left" valign="middle"><em>22.1</em></cell>
</row>
<row>
<cell align="left" valign="middle"></cell>
@@ -748,20 +745,20 @@
<row>
<cell align="left" valign="middle"></cell>
<cell align="left" valign="middle">rsa_pss_rsae_sha256</cell>
- <cell align="left" valign="middle"><em>NC</em></cell>
- <cell align="left" valign="middle"></cell>
+ <cell align="left" valign="middle"><em>C</em></cell>
+ <cell align="left" valign="middle"><em>22.1</em></cell>
</row>
<row>
<cell align="left" valign="middle"></cell>
<cell align="left" valign="middle">rsa_pss_rsae_sha384</cell>
- <cell align="left" valign="middle"><em>NC</em></cell>
- <cell align="left" valign="middle"></cell>
+ <cell align="left" valign="middle"><em>C</em></cell>
+ <cell align="left" valign="middle"><em>22.1</em></cell>
</row>
<row>
<cell align="left" valign="middle"></cell>
<cell align="left" valign="middle">rsa_pss_rsae_sha512</cell>
- <cell align="left" valign="middle"><em>NC</em></cell>
- <cell align="left" valign="middle"></cell>
+ <cell align="left" valign="middle"><em>C</em></cell>
+ <cell align="left" valign="middle"><em>22.1</em></cell>
</row>
<row>
<cell align="left" valign="middle"></cell>
@@ -796,14 +793,14 @@
<row>
<cell align="left" valign="middle"></cell>
<cell align="left" valign="middle">rsa_pkcs1_sha1</cell>
- <cell align="left" valign="middle"><em>NC</em></cell>
- <cell align="left" valign="middle"></cell>
+ <cell align="left" valign="middle"><em>C</em></cell>
+ <cell align="left" valign="middle"><em>22.1</em></cell>
</row>
<row>
<cell align="left" valign="middle"></cell>
<cell align="left" valign="middle">ecdsa_sha1</cell>
- <cell align="left" valign="middle"><em>NC</em></cell>
- <cell align="left" valign="middle"></cell>
+ <cell align="left" valign="middle"><em>C</em></cell>
+ <cell align="left" valign="middle"><em>22.1</em></cell>
</row>
<row>
@@ -816,19 +813,19 @@
<cell align="left" valign="middle"></cell>
<cell align="left" valign="middle">rsa_pkcs1_sha256</cell>
<cell align="left" valign="middle"><em>C</em></cell>
- <cell align="left" valign="middle">22</cell>
+ <cell align="left" valign="middle"><em>22</em></cell>
</row>
<row>
<cell align="left" valign="middle"></cell>
<cell align="left" valign="middle">rsa_pkcs1_sha384</cell>
<cell align="left" valign="middle"><em>C</em></cell>
- <cell align="left" valign="middle">22</cell>
+ <cell align="left" valign="middle"><em>22</em></cell>
</row>
<row>
<cell align="left" valign="middle"></cell>
<cell align="left" valign="middle">rsa_pkcs1_sha512</cell>
<cell align="left" valign="middle"><em>C</em></cell>
- <cell align="left" valign="middle">22</cell>
+ <cell align="left" valign="middle"><em>22</em></cell>
</row>
<row>
<cell align="left" valign="middle"></cell>
@@ -852,19 +849,19 @@
<cell align="left" valign="middle"></cell>
<cell align="left" valign="middle">rsa_pss_rsae_sha256</cell>
<cell align="left" valign="middle"><em>C</em></cell>
- <cell align="left" valign="middle">22</cell>
+ <cell align="left" valign="middle"><em>22</em></cell>
</row>
<row>
<cell align="left" valign="middle"></cell>
<cell align="left" valign="middle">rsa_pss_rsae_sha384</cell>
<cell align="left" valign="middle"><em>C</em></cell>
- <cell align="left" valign="middle">22</cell>
+ <cell align="left" valign="middle"><em>22</em></cell>
</row>
<row>
<cell align="left" valign="middle"></cell>
<cell align="left" valign="middle">rsa_pss_rsae_sha512</cell>
<cell align="left" valign="middle"><em>C</em></cell>
- <cell align="left" valign="middle">22</cell>
+ <cell align="left" valign="middle"><em>22</em></cell>
</row>
<row>
<cell align="left" valign="middle"></cell>
@@ -900,13 +897,13 @@
<cell align="left" valign="middle"></cell>
<cell align="left" valign="middle">rsa_pkcs1_sha1</cell>
<cell align="left" valign="middle"><em>C</em></cell>
- <cell align="left" valign="middle">22</cell>
+ <cell align="left" valign="middle"><em>22</em></cell>
</row>
<row>
<cell align="left" valign="middle"></cell>
<cell align="left" valign="middle">ecdsa_sha1</cell>
<cell align="left" valign="middle"><em>C</em></cell>
- <cell align="left" valign="middle">22</cell>
+ <cell align="left" valign="middle"><em>22</em></cell>
</row>
<row>
@@ -967,68 +964,68 @@
</url>
</cell>
<cell align="left" valign="middle"><em>Client</em></cell>
- <cell align="left" valign="middle"><em>NC</em></cell>
- <cell align="left" valign="middle"></cell>
+ <cell align="left" valign="middle"><em>C</em></cell>
+ <cell align="left" valign="middle"><em>22.1</em></cell>
</row>
<row>
<cell align="left" valign="middle"></cell>
<cell align="left" valign="middle">secp256r1</cell>
- <cell align="left" valign="middle"><em>NC</em></cell>
- <cell align="left" valign="middle"></cell>
+ <cell align="left" valign="middle"><em>C</em></cell>
+ <cell align="left" valign="middle"><em>22.1</em></cell>
</row>
<row>
<cell align="left" valign="middle"></cell>
<cell align="left" valign="middle">secp384r1</cell>
- <cell align="left" valign="middle"><em>NC</em></cell>
- <cell align="left" valign="middle"></cell>
+ <cell align="left" valign="middle"><em>C</em></cell>
+ <cell align="left" valign="middle"><em>22.1</em></cell>
</row>
<row>
<cell align="left" valign="middle"></cell>
<cell align="left" valign="middle">secp521r1</cell>
- <cell align="left" valign="middle"><em>NC</em></cell>
- <cell align="left" valign="middle"></cell>
+ <cell align="left" valign="middle"><em>C</em></cell>
+ <cell align="left" valign="middle"><em>22.1</em></cell>
</row>
<row>
<cell align="left" valign="middle"></cell>
<cell align="left" valign="middle">x25519</cell>
- <cell align="left" valign="middle"><em>NC</em></cell>
- <cell align="left" valign="middle"></cell>
+ <cell align="left" valign="middle"><em>C</em></cell>
+ <cell align="left" valign="middle"><em>22.1</em></cell>
</row>
<row>
<cell align="left" valign="middle"></cell>
<cell align="left" valign="middle">x448</cell>
- <cell align="left" valign="middle"><em>NC</em></cell>
- <cell align="left" valign="middle"></cell>
+ <cell align="left" valign="middle"><em>C</em></cell>
+ <cell align="left" valign="middle"><em>22.1</em></cell>
</row>
<row>
<cell align="left" valign="middle"></cell>
<cell align="left" valign="middle">ffdhe2048</cell>
- <cell align="left" valign="middle"><em>NC</em></cell>
- <cell align="left" valign="middle"></cell>
+ <cell align="left" valign="middle"><em>C</em></cell>
+ <cell align="left" valign="middle"><em>22.1</em></cell>
</row>
<row>
<cell align="left" valign="middle"></cell>
<cell align="left" valign="middle">ffdhe3072</cell>
- <cell align="left" valign="middle"><em>NC</em></cell>
- <cell align="left" valign="middle"></cell>
+ <cell align="left" valign="middle"><em>C</em></cell>
+ <cell align="left" valign="middle"><em>22.1</em></cell>
</row>
<row>
<cell align="left" valign="middle"></cell>
<cell align="left" valign="middle">ffdhe4096</cell>
- <cell align="left" valign="middle"><em>NC</em></cell>
- <cell align="left" valign="middle"></cell>
+ <cell align="left" valign="middle"><em>C</em></cell>
+ <cell align="left" valign="middle"><em>22.1</em></cell>
</row>
<row>
<cell align="left" valign="middle"></cell>
<cell align="left" valign="middle">ffdhe6144</cell>
- <cell align="left" valign="middle"><em>NC</em></cell>
- <cell align="left" valign="middle"></cell>
+ <cell align="left" valign="middle"><em>C</em></cell>
+ <cell align="left" valign="middle"><em>22.1</em></cell>
</row>
<row>
<cell align="left" valign="middle"></cell>
<cell align="left" valign="middle">ffdhe8192</cell>
- <cell align="left" valign="middle"><em>NC</em></cell>
- <cell align="left" valign="middle"></cell>
+ <cell align="left" valign="middle"><em>C</em></cell>
+ <cell align="left" valign="middle"><em>22.1</em></cell>
</row>
<row>
@@ -1105,8 +1102,8 @@
</url>
</cell>
<cell align="left" valign="middle"><em>Client</em></cell>
- <cell align="left" valign="middle"><em>NC</em></cell>
- <cell align="left" valign="middle"></cell>
+ <cell align="left" valign="middle"><em>C</em></cell>
+ <cell align="left" valign="middle"><em>22.1</em></cell>
</row>
<row>
<cell align="left" valign="middle"></cell>
@@ -1224,8 +1221,8 @@
</url>
</cell>
<cell align="left" valign="middle"><em>Client</em></cell>
- <cell align="left" valign="middle"><em>NC</em></cell>
- <cell align="left" valign="middle"></cell>
+ <cell align="left" valign="middle"><em>PC</em></cell>
+ <cell align="left" valign="middle"><em>22.1</em></cell>
</row>
<row>
<cell align="left" valign="middle"></cell>
@@ -1362,8 +1359,8 @@
</url>
</cell>
<cell align="left" valign="middle"><em>Client</em></cell>
- <cell align="left" valign="middle"><em>NC</em></cell>
- <cell align="left" valign="middle"></cell>
+ <cell align="left" valign="middle"><em>PC</em></cell>
+ <cell align="left" valign="middle"><em>22.1</em></cell>
</row>
<row>
<cell align="left" valign="middle"></cell>
@@ -1374,8 +1371,8 @@
<row>
<cell align="left" valign="middle"></cell>
<cell align="left" valign="middle">signature_algorithms (RFC8446)</cell>
- <cell align="left" valign="middle"><em>NC</em></cell>
- <cell align="left" valign="middle"></cell>
+ <cell align="left" valign="middle"><em>C</em></cell>
+ <cell align="left" valign="middle"><em>22.1</em></cell>
</row>
<row>
<cell align="left" valign="middle"></cell>
@@ -1398,8 +1395,8 @@
<row>
<cell align="left" valign="middle"></cell>
<cell align="left" valign="middle">signature_algorithms_cert (RFC8446)</cell>
- <cell align="left" valign="middle"><em>NC</em></cell>
- <cell align="left" valign="middle"></cell>
+ <cell align="left" valign="middle"><em>C</em></cell>
+ <cell align="left" valign="middle"><em>22.1</em></cell>
</row>
<row>
@@ -1417,8 +1414,8 @@
<row>
<cell align="left" valign="middle"></cell>
<cell align="left" valign="middle">signature_algorithms (RFC8446)</cell>
- <cell align="left" valign="middle"><em>NC</em></cell>
- <cell align="left" valign="middle"></cell>
+ <cell align="left" valign="middle"><em>C</em></cell>
+ <cell align="left" valign="middle"><em>22</em></cell>
</row>
<row>
<cell align="left" valign="middle"></cell>
@@ -1441,8 +1438,8 @@
<row>
<cell align="left" valign="middle"></cell>
<cell align="left" valign="middle">signature_algorithms_cert (RFC8446)</cell>
- <cell align="left" valign="middle"><em>NC</em></cell>
- <cell align="left" valign="middle"></cell>
+ <cell align="left" valign="middle"><em>C</em></cell>
+ <cell align="left" valign="middle"><em>22</em></cell>
</row>
<row>
@@ -1463,8 +1460,8 @@
</url>
</cell>
<cell align="left" valign="middle"><em>Client</em></cell>
- <cell align="left" valign="middle"><em>NC</em></cell>
- <cell align="left" valign="middle"></cell>
+ <cell align="left" valign="middle"><em>PC</em></cell>
+ <cell align="left" valign="middle"><em>22.1</em></cell>
</row>
<row>
<cell align="left" valign="middle"></cell>
@@ -1521,73 +1518,82 @@
4.4.2.2. Server Certificate Selection
</url>
</cell>
- <cell align="left" valign="middle"><em>Client</em></cell>
- <cell align="left" valign="middle"><em>NC</em></cell>
- <cell align="left" valign="middle"><em></em></cell>
+ <cell align="left" valign="middle"><em></em></cell>
+ <cell align="left" valign="middle"><em>PC</em></cell>
+ <cell align="left" valign="middle"><em>22</em></cell>
</row>
<row>
<cell align="left" valign="middle"></cell>
- <cell align="left" valign="middle">certificate type MUST be X.509v3</cell>
- <cell align="left" valign="middle"><em>NC</em></cell>
- <cell align="left" valign="middle"><em></em></cell>
+ <cell align="left" valign="middle">The certificate type MUST be X.509v3, unless explicitly
+ negotiated otherwise</cell>
+ <cell align="left" valign="middle"><em>C</em></cell>
+ <cell align="left" valign="middle"><em>22</em></cell>
</row>
<row>
<cell align="left" valign="middle"></cell>
- <cell align="left" valign="middle">certificate's public key is compatible</cell>
- <cell align="left" valign="middle"><em>NC</em></cell>
- <cell align="left" valign="middle"><em></em></cell>
+ <cell align="left" valign="middle">The server's end-entity certificate's public key (and associated
+ restrictions) MUST be compatible with the selected authentication
+ algorithm from the client's "signature_algorithms" extension
+ (currently RSA, ECDSA, or EdDSA).</cell>
+ <cell align="left" valign="middle"><em>C</em></cell>
+ <cell align="left" valign="middle"><em>22</em></cell>
</row>
<row>
<cell align="left" valign="middle"></cell>
- <cell align="left" valign="middle">The certificate MUST allow the key to be used for signing</cell>
- <cell align="left" valign="middle"><em>NC</em></cell>
- <cell align="left" valign="middle"><em></em></cell>
+ <cell align="left" valign="middle">The certificate MUST allow the key to be used for signing
+ with a signature scheme indicated in the client's "signature_algorithms"/"signature_algorithms_cert"
+ extensions</cell>
+ <cell align="left" valign="middle"><em>C</em></cell>
+ <cell align="left" valign="middle"><em>22</em></cell>
</row>
<row>
<cell align="left" valign="middle"></cell>
- <cell align="left" valign="middle">server_name and certificate_authorities are used</cell>
+ <cell align="left" valign="middle">The "server_name" and "certificate_authorities"
+ extensions are used to guide certificate selection. As servers
+ MAY require the presence of the "server_name" extension, clients
+ SHOULD send this extension, when applicable.</cell>
<cell align="left" valign="middle"><em>NC</em></cell>
- <cell align="left" valign="middle"><em></em></cell>
+ <cell align="left" valign="middle"></cell>
</row>
<row>
- <cell align="left" valign="middle"></cell>
- <cell align="left" valign="middle"><em>Server</em></cell>
+ <cell align="left" valign="middle">
+ <url href="https://tools.ietf.org/html/rfc8446#section-4.4.2.3">
+ 4.4.2.3. Client Certificate Selection
+ </url>
+ </cell>
+ <cell align="left" valign="middle"><em></em></cell>
<cell align="left" valign="middle"><em>PC</em></cell>
- <cell align="left" valign="middle"><em></em></cell>
+ <cell align="left" valign="middle"><em>22.1</em></cell>
</row>
<row>
<cell align="left" valign="middle"></cell>
- <cell align="left" valign="middle">certificate type MUST be X.509v3</cell>
+ <cell align="left" valign="middle">The certificate type MUST be X.509v3, unless explicitly
+ negotiated otherwise</cell>
<cell align="left" valign="middle"><em>C</em></cell>
- <cell align="left" valign="middle"><em>22</em></cell>
+ <cell align="left" valign="middle"><em>22.1</em></cell>
</row>
<row>
<cell align="left" valign="middle"></cell>
- <cell align="left" valign="middle">certificate's public key is compatible</cell>
- <cell align="left" valign="middle"><em>C</em></cell>
- <cell align="left" valign="middle"><em>22</em></cell>
+ <cell align="left" valign="middle">If the "certificate_authorities" extension in the
+ CertificateRequest message was present, at least one of the
+ certificates in the certificate chain SHOULD be issued by one of
+ the listed CAs.</cell>
+ <cell align="left" valign="middle"><em>NC</em></cell>
+ <cell align="left" valign="middle"><em></em></cell>
</row>
<row>
<cell align="left" valign="middle"></cell>
- <cell align="left" valign="middle">The certificate MUST allow the key to be used for signing</cell>
+ <cell align="left" valign="middle">The certificates MUST be signed using an acceptable signature
+ algorithm</cell>
<cell align="left" valign="middle"><em>C</em></cell>
- <cell align="left" valign="middle"><em>22</em></cell>
+ <cell align="left" valign="middle"><em>22.1</em></cell>
</row>
<row>
<cell align="left" valign="middle"></cell>
- <cell align="left" valign="middle">server_name and certificate_authorities are used</cell>
- <cell align="left" valign="middle"><em>NC</em></cell>
- <cell align="left" valign="middle"></cell>
- </row>
-
- <row>
- <cell align="left" valign="middle">
- <url href="https://tools.ietf.org/html/rfc8446#section-4.4.2.3">
- 4.4.2.3. Client Certificate Selection
- </url>
- </cell>
- <cell align="left" valign="middle"><em></em></cell>
+ <cell align="left" valign="middle">If the CertificateRequest message contained a non-empty
+ "oid_filters" extension, the end-entity certificate MUST match the
+ extension OIDs that are recognized by the client</cell>
<cell align="left" valign="middle"><em>NC</em></cell>
<cell align="left" valign="middle"><em></em></cell>
</row>
@@ -1599,8 +1605,8 @@
</url>
</cell>
<cell align="left" valign="middle"><em>Client</em></cell>
- <cell align="left" valign="middle"><em>NC</em></cell>
- <cell align="left" valign="middle"></cell>
+ <cell align="left" valign="middle"><em>C</em></cell>
+ <cell align="left" valign="middle"><em>22.1</em></cell>
</row>
<row>
<cell align="left" valign="middle"></cell>
@@ -1616,8 +1622,8 @@
</url>
</cell>
<cell align="left" valign="middle"><em>Client</em></cell>
- <cell align="left" valign="middle"><em>NC</em></cell>
- <cell align="left" valign="middle"></cell>
+ <cell align="left" valign="middle"><em>C</em></cell>
+ <cell align="left" valign="middle"><em>22.1</em></cell>
</row>
<row>
<cell align="left" valign="middle"></cell>
@@ -1633,8 +1639,8 @@
</url>
</cell>
<cell align="left" valign="middle"><em>Client</em></cell>
- <cell align="left" valign="middle"><em>NC</em></cell>
- <cell align="left" valign="middle"></cell>
+ <cell align="left" valign="middle"><em>C</em></cell>
+ <cell align="left" valign="middle"><em>22.1</em></cell>
</row>
<row>
<cell align="left" valign="middle"></cell>
@@ -1738,25 +1744,25 @@
<cell align="left" valign="middle"></cell>
<cell align="left" valign="middle">MUST NOT be interleaved with other record types</cell>
<cell align="left" valign="middle"><em>C</em></cell>
- <cell align="left" valign="middle">22</cell>
+ <cell align="left" valign="middle"><em>22</em></cell>
</row>
<row>
<cell align="left" valign="middle"></cell>
<cell align="left" valign="middle">MUST NOT span key changes</cell>
<cell align="left" valign="middle"><em>C</em></cell>
- <cell align="left" valign="middle">22</cell>
+ <cell align="left" valign="middle"><em>22</em></cell>
</row>
<row>
<cell align="left" valign="middle"></cell>
<cell align="left" valign="middle">MUST NOT send zero-length fragments</cell>
<cell align="left" valign="middle"><em>C</em></cell>
- <cell align="left" valign="middle">22</cell>
+ <cell align="left" valign="middle"><em>22</em></cell>
</row>
<row>
<cell align="left" valign="middle"></cell>
<cell align="left" valign="middle">Alert messages MUST NOT be fragmented</cell>
<cell align="left" valign="middle"><em>C</em></cell>
- <cell align="left" valign="middle">22</cell>
+ <cell align="left" valign="middle"><em>22</em></cell>
</row>
<row>
@@ -1807,7 +1813,7 @@
<cell align="left" valign="middle"></cell>
<cell align="left" valign="middle">The padding sent is automatically verified</cell>
<cell align="left" valign="middle"><em>C</em></cell>
- <cell align="left" valign="middle">22</cell>
+ <cell align="left" valign="middle"><em>22</em></cell>
</row>
<row>
@@ -1957,19 +1963,19 @@
<cell align="left" valign="middle"></cell>
<cell align="left" valign="middle">MUST implement the TLS_AES_128_GCM_SHA256</cell>
<cell align="left" valign="middle"><em>C</em></cell>
- <cell align="left" valign="middle">22</cell>
+ <cell align="left" valign="middle"><em>22</em></cell>
</row>
<row>
<cell align="left" valign="middle"></cell>
<cell align="left" valign="middle">SHOULD implement the TLS_AES_256_GCM_SHA384</cell>
<cell align="left" valign="middle"><em>C</em></cell>
- <cell align="left" valign="middle">22</cell>
+ <cell align="left" valign="middle"><em>22</em></cell>
</row>
<row>
<cell align="left" valign="middle"></cell>
<cell align="left" valign="middle">SHOULD implement the TLS_CHACHA20_POLY1305_SHA256</cell>
<cell align="left" valign="middle"><em>C</em></cell>
- <cell align="left" valign="middle">22</cell>
+ <cell align="left" valign="middle"><em>22</em></cell>
</row>
<row>
@@ -1982,13 +1988,13 @@
<cell align="left" valign="middle"></cell>
<cell align="left" valign="middle">MUST support rsa_pkcs1_sha256 (for certificates)</cell>
<cell align="left" valign="middle"><em>C</em></cell>
- <cell align="left" valign="middle">22</cell>
+ <cell align="left" valign="middle"><em>22</em></cell>
</row>
<row>
<cell align="left" valign="middle"></cell>
<cell align="left" valign="middle">MUST support rsa_pss_rsae_sha256 (for CertificateVerify and certificates)</cell>
<cell align="left" valign="middle"><em>C</em></cell>
- <cell align="left" valign="middle">22</cell>
+ <cell align="left" valign="middle"><em>22</em></cell>
</row>
<row>
<cell align="left" valign="middle"></cell>
@@ -2007,13 +2013,13 @@
<cell align="left" valign="middle"></cell>
<cell align="left" valign="middle">MUST support key exchange with secp256r1</cell>
<cell align="left" valign="middle"><em>C</em></cell>
- <cell align="left" valign="middle">22</cell>
+ <cell align="left" valign="middle"><em>22</em></cell>
</row>
<row>
<cell align="left" valign="middle"></cell>
<cell align="left" valign="middle">SHOULD support key exchange with X25519</cell>
<cell align="left" valign="middle"><em>C</em></cell>
- <cell align="left" valign="middle">22</cell>
+ <cell align="left" valign="middle"><em>22</em></cell>
</row>
<row>
@@ -2030,7 +2036,7 @@
<cell align="left" valign="middle"></cell>
<cell align="left" valign="middle">Supported Versions</cell>
<cell align="left" valign="middle"><em>C</em></cell>
- <cell align="left" valign="middle">22</cell>
+ <cell align="left" valign="middle"><em>22</em></cell>
</row>
<row>
<cell align="left" valign="middle"></cell>
@@ -2042,25 +2048,25 @@
<cell align="left" valign="middle"></cell>
<cell align="left" valign="middle">Signature Algorithms</cell>
<cell align="left" valign="middle"><em>C</em></cell>
- <cell align="left" valign="middle">22</cell>
+ <cell align="left" valign="middle"><em>22</em></cell>
</row>
<row>
<cell align="left" valign="middle"></cell>
<cell align="left" valign="middle">Signature Algorithms Certificate</cell>
<cell align="left" valign="middle"><em>C</em></cell>
- <cell align="left" valign="middle">22</cell>
+ <cell align="left" valign="middle"><em>22</em></cell>
</row>
<row>
<cell align="left" valign="middle"></cell>
<cell align="left" valign="middle">Negotiated Groups</cell>
<cell align="left" valign="middle"><em>C</em></cell>
- <cell align="left" valign="middle">22</cell>
+ <cell align="left" valign="middle"><em>22</em></cell>
</row>
<row>
<cell align="left" valign="middle"></cell>
<cell align="left" valign="middle">Key Share</cell>
<cell align="left" valign="middle"><em>C</em></cell>
- <cell align="left" valign="middle">22</cell>
+ <cell align="left" valign="middle"><em>22</em></cell>
</row>
<row>
<cell align="left" valign="middle"></cell>
@@ -2072,32 +2078,32 @@
<row>
<cell align="left" valign="middle"></cell>
<cell align="left" valign="middle"><em>MUST send and use these extensions</em></cell>
- <cell align="left" valign="middle"><em>C</em></cell>
+ <cell align="left" valign="middle"><em>PC</em></cell>
<cell align="left" valign="middle"><em>22</em></cell>
</row>
<row>
<cell align="left" valign="middle"></cell>
<cell align="left" valign="middle">"supported_versions" is REQUIRED for ClientHello, ServerHello and HelloRetryRequest</cell>
- <cell align="left" valign="middle"><em>PC</em></cell>
- <cell align="left" valign="middle">22</cell>
+ <cell align="left" valign="middle"><em>C</em></cell>
+ <cell align="left" valign="middle"><em>22.1</em></cell>
</row>
<row>
<cell align="left" valign="middle"></cell>
<cell align="left" valign="middle">"signature_algorithms" is REQUIRED for certificate authentication</cell>
<cell align="left" valign="middle"><em>C</em></cell>
- <cell align="left" valign="middle">22</cell>
+ <cell align="left" valign="middle"><em>22</em></cell>
</row>
<row>
<cell align="left" valign="middle"></cell>
<cell align="left" valign="middle">"supported_groups" is REQUIRED for ClientHello messages using (EC)DHE key exchange</cell>
<cell align="left" valign="middle"><em>C</em></cell>
- <cell align="left" valign="middle">22</cell>
+ <cell align="left" valign="middle"><em>22</em></cell>
</row>
<row>
<cell align="left" valign="middle"></cell>
<cell align="left" valign="middle">"key_share" is REQUIRED for (EC)DHE key exchange</cell>
<cell align="left" valign="middle"><em>C</em></cell>
- <cell align="left" valign="middle">22</cell>
+ <cell align="left" valign="middle"><em>22</em></cell>
</row>
<row>
<cell align="left" valign="middle"></cell>
@@ -2115,20 +2121,20 @@
<row>
<cell align="left" valign="middle"></cell>
<cell align="left" valign="middle"><em>TLS 1.3 ClientHello</em></cell>
- <cell align="left" valign="middle"><em>NC</em></cell>
- <cell align="left" valign="middle"><em></em></cell>
+ <cell align="left" valign="middle"><em>C</em></cell>
+ <cell align="left" valign="middle"><em>22.1</em></cell>
</row>
<row>
<cell align="left" valign="middle"></cell>
<cell align="left" valign="middle">If not containing a "pre_shared_key" extension, it MUST contain both a "signature_algorithms" extension and a "supported_groups" extension.</cell>
- <cell align="left" valign="middle"><em>NC</em></cell>
- <cell align="left" valign="middle"></cell>
+ <cell align="left" valign="middle"><em>C</em></cell>
+ <cell align="left" valign="middle"><em>22.1</em></cell>
</row>
<row>
<cell align="left" valign="middle"></cell>
<cell align="left" valign="middle">If containing a "supported_groups" extension, it MUST also contain a "key_share" extension, and vice versa. An empty KeyShare.client_shares vector is permitted.</cell>
- <cell align="left" valign="middle"><em>NC</em></cell>
- <cell align="left" valign="middle"></cell>
+ <cell align="left" valign="middle"><em>C</em></cell>
+ <cell align="left" valign="middle"><em>22.1</em></cell>
</row>
<row>
@@ -2151,30 +2157,44 @@
</url>
</cell>
<cell align="left" valign="middle"><em></em></cell>
- <cell align="left" valign="middle"><em>NC</em></cell>
- <cell align="left" valign="middle"><em></em></cell>
+ <cell align="left" valign="middle"><em>C</em></cell>
+ <cell align="left" valign="middle"><em>22.1</em></cell>
</row>
<row>
<cell align="left" valign="middle"></cell>
<cell align="left" valign="middle"><em>MUST correctly handle extensible fields</em></cell>
- <cell align="left" valign="middle"><em>NC</em></cell>
- <cell align="left" valign="middle"><em></em></cell>
+ <cell align="left" valign="middle"><em>C</em></cell>
+ <cell align="left" valign="middle"><em>22.1</em></cell>
</row>
<row>
<cell align="left" valign="middle"></cell>
- <cell align="left" valign="middle">A client sending a ClientHello MUST support all parameters advertised in it.</cell>
- <cell align="left" valign="middle"><em>NC</em></cell>
- <cell align="left" valign="middle"></cell>
+ <cell align="left" valign="middle">A client sending a ClientHello MUST support all parameters
+ advertised in it. Otherwise, the server may fail to interoperate by selecting one of those parameters.</cell>
+ <cell align="left" valign="middle"><em>C</em></cell>
+ <cell align="left" valign="middle"><em>22.1</em></cell>
</row>
<row>
<cell align="left" valign="middle"></cell>
- <cell align="left" valign="middle">A middlebox which terminates a TLS connection MUST behave as a compliant TLS server</cell>
+ <cell align="left" valign="middle">A server receiving a ClientHello MUST correctly ignore all
+ unrecognized cipher suites, extensions, and other parameters. Otherwise, it may fail to
+ interoperate with newer clients. In TLS 1.3, a client receiving a CertificateRequest or
+ NewSessionTicket MUST also ignore all unrecognized extensions.</cell>
+ <cell align="left" valign="middle"><em>C</em></cell>
+ <cell align="left" valign="middle"><em>22.1</em></cell>
+ </row>
+
+ <row>
+ <cell align="left" valign="middle"></cell>
+ <cell align="left" valign="middle">A middlebox which terminates a TLS connection MUST behave as a
+ compliant TLS server</cell>
<cell align="left" valign="middle"><em>NA</em></cell>
<cell align="left" valign="middle"></cell>
</row>
<row>
<cell align="left" valign="middle"></cell>
- <cell align="left" valign="middle">A middlebox which forwards ClientHello parameters it does not understand MUST NOT process any messages beyond that ClientHello.</cell>
+ <cell align="left" valign="middle">A middlebox which forwards ClientHello parameters it does not
+ understand MUST NOT process any messages beyond that ClientHello. It MUST forward all subsequent
+ traffic unmodified. Otherwise, it may fail to interoperate with newer clients and servers.</cell>
<cell align="left" valign="middle"><em>NA</em></cell>
<cell align="left" valign="middle"></cell>
</row>
@@ -2193,25 +2213,25 @@
<cell align="left" valign="middle"></cell>
<cell align="left" valign="middle">TLS_AES_128_GCM_SHA256</cell>
<cell align="left" valign="middle"><em>C</em></cell>
- <cell align="left" valign="middle">22</cell>
+ <cell align="left" valign="middle"><em>22</em></cell>
</row>
<row>
<cell align="left" valign="middle"></cell>
<cell align="left" valign="middle">TLS_AES_256_GCM_SHA384</cell>
<cell align="left" valign="middle"><em>C</em></cell>
- <cell align="left" valign="middle">22</cell>
+ <cell align="left" valign="middle"><em>22</em></cell>
</row>
<row>
<cell align="left" valign="middle"></cell>
<cell align="left" valign="middle">TLS_CHACHA20_POLY1305_SHA256</cell>
<cell align="left" valign="middle"><em>C</em></cell>
- <cell align="left" valign="middle">22</cell>
+ <cell align="left" valign="middle"><em>22</em></cell>
</row>
<row>
<cell align="left" valign="middle"></cell>
<cell align="left" valign="middle">TLS_AES_128_CCM_SHA256</cell>
<cell align="left" valign="middle"><em>C</em></cell>
- <cell align="left" valign="middle">22</cell>
+ <cell align="left" valign="middle"><em>22</em></cell>
</row>
<row>
<cell align="left" valign="middle"></cell>
diff --git a/lib/ssl/src/dtls_connection.erl b/lib/ssl/src/dtls_connection.erl
index 6928d7a93d..b220691e79 100644
--- a/lib/ssl/src/dtls_connection.erl
+++ b/lib/ssl/src/dtls_connection.erl
@@ -836,9 +836,12 @@ initial_flight_state(_) ->
next_dtls_record(Data, StateName, #state{protocol_buffers = #protocol_buffers{
dtls_record_buffer = Buf0,
dtls_cipher_texts = CT0} = Buffers,
+ connection_env = #connection_env{negotiated_version = Version},
+ static_env = #static_env{data_tag = DataTag},
ssl_options = SslOpts} = State0) ->
case dtls_record:get_dtls_records(Data,
- acceptable_record_versions(StateName, State0),
+ {DataTag, StateName, Version,
+ [dtls_record:protocol_version(Vsn) || Vsn <- ?ALL_AVAILABLE_DATAGRAM_VERSIONS]},
Buf0, SslOpts) of
{Records, Buf1} ->
CT1 = CT0 ++ Records,
@@ -849,10 +852,6 @@ next_dtls_record(Data, StateName, #state{protocol_buffers = #protocol_buffers{
Alert
end.
-acceptable_record_versions(hello, _) ->
- [dtls_record:protocol_version(Vsn) || Vsn <- ?ALL_AVAILABLE_DATAGRAM_VERSIONS];
-acceptable_record_versions(_, #state{connection_env = #connection_env{negotiated_version = Version}}) ->
- [Version].
dtls_handshake_events(Packets) ->
lists:map(fun(Packet) ->
diff --git a/lib/ssl/src/dtls_record.erl b/lib/ssl/src/dtls_record.erl
index a4846f42c5..8b8db7b2de 100644
--- a/lib/ssl/src/dtls_record.erl
+++ b/lib/ssl/src/dtls_record.erl
@@ -162,26 +162,16 @@ current_connection_state_epoch(#{current_write := #{epoch := Epoch}},
Epoch.
%%--------------------------------------------------------------------
--spec get_dtls_records(binary(), [ssl_record:ssl_version()], binary(),
+-spec get_dtls_records(binary(), {atom(), atom(), ssl_record:ssl_version(), [ssl_record:ssl_version()]}, binary(),
#ssl_options{}) -> {[binary()], binary()} | #alert{}.
%%
%% Description: Given old buffer and new data from UDP/SCTP, packs up a records
%% and returns it as a list of tls_compressed binaries also returns leftover
%% data
%%--------------------------------------------------------------------
-get_dtls_records(Data, Versions, Buffer, SslOpts) ->
+get_dtls_records(Data, Vinfo, Buffer, SslOpts) ->
BinData = list_to_binary([Buffer, Data]),
- case erlang:byte_size(BinData) of
- N when N >= 3 ->
- case assert_version(BinData, Versions) of
- true ->
- get_dtls_records_aux(BinData, [], SslOpts);
- false ->
- ?ALERT_REC(?FATAL, ?BAD_RECORD_MAC)
- end;
- _ ->
- get_dtls_records_aux(BinData, [], SslOpts)
- end.
+ get_dtls_records_aux(Vinfo, BinData, [], SslOpts).
%%====================================================================
%% Encoding DTLS records
@@ -405,52 +395,49 @@ initial_connection_state(ConnectionEnd, BeastMitigation) ->
client_verify_data => undefined,
server_verify_data => undefined
}.
-assert_version(<<?BYTE(_), ?BYTE(MajVer), ?BYTE(MinVer), _/binary>>, Versions) ->
- is_acceptable_version({MajVer, MinVer}, Versions).
-get_dtls_records_aux(<<?BYTE(?APPLICATION_DATA),?BYTE(MajVer),?BYTE(MinVer),
- ?UINT16(Epoch), ?UINT48(SequenceNumber),
- ?UINT16(Length), Data:Length/binary, Rest/binary>> = RawDTLSRecord,
- Acc, SslOpts) ->
- ssl_logger:debug(SslOpts#ssl_options.log_level, inbound, 'record', [RawDTLSRecord]),
- get_dtls_records_aux(Rest, [#ssl_tls{type = ?APPLICATION_DATA,
- version = {MajVer, MinVer},
- epoch = Epoch, sequence_number = SequenceNumber,
- fragment = Data} | Acc], SslOpts);
-get_dtls_records_aux(<<?BYTE(?HANDSHAKE),?BYTE(MajVer),?BYTE(MinVer),
- ?UINT16(Epoch), ?UINT48(SequenceNumber),
- ?UINT16(Length),
- Data:Length/binary, Rest/binary>> = RawDTLSRecord,
- Acc, SslOpts) when MajVer >= 128 ->
- ssl_logger:debug(SslOpts#ssl_options.log_level, inbound, 'record', [RawDTLSRecord]),
- get_dtls_records_aux(Rest, [#ssl_tls{type = ?HANDSHAKE,
- version = {MajVer, MinVer},
- epoch = Epoch, sequence_number = SequenceNumber,
- fragment = Data} | Acc], SslOpts);
-get_dtls_records_aux(<<?BYTE(?ALERT),?BYTE(MajVer),?BYTE(MinVer),
- ?UINT16(Epoch), ?UINT48(SequenceNumber),
- ?UINT16(Length), Data:Length/binary,
- Rest/binary>> = RawDTLSRecord, Acc, SslOpts) ->
+get_dtls_records_aux({DataTag, StateName, _, Versions} = Vinfo, <<?BYTE(Type),?BYTE(MajVer),?BYTE(MinVer),
+ ?UINT16(Epoch), ?UINT48(SequenceNumber),
+ ?UINT16(Length), Data:Length/binary, Rest/binary>> = RawDTLSRecord,
+ Acc, SslOpts) when ((StateName == hello) orelse
+ ((StateName == certify) andalso (DataTag == udp)) orelse
+ ((StateName == abbreviated) andalso(DataTag == udp)))
+ andalso
+ ((Type == ?HANDSHAKE) orelse
+ (Type == ?ALERT)) ->
ssl_logger:debug(SslOpts#ssl_options.log_level, inbound, 'record', [RawDTLSRecord]),
- get_dtls_records_aux(Rest, [#ssl_tls{type = ?ALERT,
- version = {MajVer, MinVer},
- epoch = Epoch, sequence_number = SequenceNumber,
- fragment = Data} | Acc], SslOpts);
-get_dtls_records_aux(<<?BYTE(?CHANGE_CIPHER_SPEC),?BYTE(MajVer),?BYTE(MinVer),
+ case is_acceptable_version({MajVer, MinVer}, Versions) of
+ true ->
+ get_dtls_records_aux(Vinfo, Rest, [#ssl_tls{type = Type,
+ version = {MajVer, MinVer},
+ epoch = Epoch, sequence_number = SequenceNumber,
+ fragment = Data} | Acc], SslOpts);
+ false ->
+ ?ALERT_REC(?FATAL, ?BAD_RECORD_MAC)
+ end;
+get_dtls_records_aux({_, _, Version, _} = Vinfo, <<?BYTE(Type),?BYTE(MajVer),?BYTE(MinVer),
?UINT16(Epoch), ?UINT48(SequenceNumber),
?UINT16(Length), Data:Length/binary, Rest/binary>> = RawDTLSRecord,
- Acc, SslOpts) ->
+ Acc, SslOpts) when (Type == ?APPLICATION_DATA) orelse
+ (Type == ?HANDSHAKE) orelse
+ (Type == ?ALERT) orelse
+ (Type == ?CHANGE_CIPHER_SPEC) ->
ssl_logger:debug(SslOpts#ssl_options.log_level, inbound, 'record', [RawDTLSRecord]),
- get_dtls_records_aux(Rest, [#ssl_tls{type = ?CHANGE_CIPHER_SPEC,
- version = {MajVer, MinVer},
- epoch = Epoch, sequence_number = SequenceNumber,
- fragment = Data} | Acc], SslOpts);
-get_dtls_records_aux(<<?BYTE(_), ?BYTE(_MajVer), ?BYTE(_MinVer),
+ case {MajVer, MinVer} of
+ Version ->
+ get_dtls_records_aux(Vinfo, Rest, [#ssl_tls{type = Type,
+ version = {MajVer, MinVer},
+ epoch = Epoch, sequence_number = SequenceNumber,
+ fragment = Data} | Acc], SslOpts);
+ _ ->
+ ?ALERT_REC(?FATAL, ?BAD_RECORD_MAC)
+ end;
+get_dtls_records_aux(_, <<?BYTE(_), ?BYTE(_MajVer), ?BYTE(_MinVer),
?UINT16(Length), _/binary>>,
_Acc, _) when Length > ?MAX_CIPHER_TEXT_LENGTH ->
?ALERT_REC(?FATAL, ?RECORD_OVERFLOW);
-get_dtls_records_aux(Data, Acc, _) ->
+get_dtls_records_aux(_, Data, Acc, _) ->
case size(Data) =< ?MAX_CIPHER_TEXT_LENGTH + ?INITIAL_BYTES of
true ->
{lists:reverse(Acc), Data};
diff --git a/lib/ssl/src/ssl.erl b/lib/ssl/src/ssl.erl
index 6af65e09f2..20b1e85ceb 100644
--- a/lib/ssl/src/ssl.erl
+++ b/lib/ssl/src/ssl.erl
@@ -125,7 +125,10 @@
protocol_extensions/0,
session_id/0,
error_alert/0,
- srp_param_type/0]).
+ tls_alert/0,
+ srp_param_type/0,
+ named_curve/0,
+ sign_scheme/0]).
%% -------------------------------------------------------------------------------------------------------
@@ -191,7 +194,8 @@
| rsa_pss_pss_sha384
| rsa_pss_pss_sha512
| rsa_pkcs1_sha1
- | ecdsa_sha1.
+ | ecdsa_sha1. % exported
+
-type kex_algo() :: rsa |
dhe_rsa | dhe_dss |
ecdhe_ecdsa | ecdh_ecdsa | ecdh_rsa |
@@ -236,7 +240,7 @@
sect163r2 |
secp160k1 |
secp160r1 |
- secp160r2.
+ secp160r2. % exported
-type group() :: secp256r1 | secp384r1 | secp521r1 | ffdhe2048 |
ffdhe3072 | ffdhe4096 | ffdhe6144 | ffdhe8192.
@@ -279,7 +283,7 @@
bad_certificate_status_response |
bad_certificate_hash_value |
unknown_psk_identity |
- no_application_protocol.
+ no_application_protocol. % exported
%% -------------------------------------------------------------------------------------------------------
-type common_option() :: {protocol, protocol()} |
@@ -1909,7 +1913,7 @@ validate_option(Opt, Value) ->
throw({error, {options, {Opt, Value}}}).
handle_cb_info({V1, V2, V3, V4}, {_,_,_,_,_}) ->
- {V1,V2,V3,V4, list_to_atom(atom_to_list(V2) ++ "passive")};
+ {V1,V2,V3,V4, list_to_atom(atom_to_list(V2) ++ "_passive")};
handle_cb_info(CbInfo, _) ->
CbInfo.
diff --git a/lib/ssl/src/ssl_connection.erl b/lib/ssl/src/ssl_connection.erl
index a8cb9ea815..cc4d60389e 100644
--- a/lib/ssl/src/ssl_connection.erl
+++ b/lib/ssl/src/ssl_connection.erl
@@ -1195,7 +1195,7 @@ cipher(internal, #next_protocol{selected_protocol = SelectedProtocol},
#state{static_env = #static_env{role = server},
handshake_env = #handshake_env{expecting_finished = true,
expecting_next_protocol_negotiation = true} = HsEnv} = State, Connection) ->
- Connection:next_event(?FUNCTION_NAME, no_record,
+ Connection:next_event(?FUNCTION_NAME, no_record,
State#state{handshake_env = HsEnv#handshake_env{negotiated_protocol = SelectedProtocol,
expecting_next_protocol_negotiation = false}});
cipher(internal, #change_cipher_spec{type = <<1>>}, #state{handshake_env = HsEnv, connection_states = ConnectionStates0} =
diff --git a/lib/ssl/src/ssl_connection.hrl b/lib/ssl/src/ssl_connection.hrl
index ff7207a8ce..844368c761 100644
--- a/lib/ssl/src/ssl_connection.hrl
+++ b/lib/ssl/src/ssl_connection.hrl
@@ -66,6 +66,7 @@
sni_hostname = undefined,
expecting_next_protocol_negotiation = false ::boolean(),
next_protocol = undefined :: undefined | binary(),
+ alpn = undefined, %% Used in TLS 1.3
negotiated_protocol,
hashsign_algorithm = {undefined, undefined},
cert_hashsign_algorithm = {undefined, undefined},
@@ -76,7 +77,7 @@
srp_params :: #srp_user{} | secret_printout() | 'undefined',
public_key_info :: ssl_handshake:public_key_info() | 'undefined',
premaster_secret :: binary() | secret_printout() | 'undefined',
- server_psk_identity :: binary() | 'undefined' % server psk identity hint
+ server_psk_identity :: binary() | 'undefined' % server psk identity hint
}).
-record(connection_env, {
diff --git a/lib/ssl/src/ssl_handshake.erl b/lib/ssl/src/ssl_handshake.erl
index f68d3e9b26..53676ab355 100644
--- a/lib/ssl/src/ssl_handshake.erl
+++ b/lib/ssl/src/ssl_handshake.erl
@@ -76,7 +76,8 @@
handle_client_hello_extensions/9, %% Returns server hello extensions
handle_server_hello_extensions/9, select_curve/2, select_curve/3,
select_hashsign/4, select_hashsign/5,
- select_hashsign_algs/3, empty_extensions/2, add_server_share/3
+ select_hashsign_algs/3, empty_extensions/2, add_server_share/3,
+ add_alpn/2, add_selected_version/1, decode_alpn/1
]).
-export([get_cert_params/1,
@@ -1165,6 +1166,13 @@ add_server_share(hello_retry_request, Extensions,
Extensions#{key_share => #key_share_hello_retry_request{
selected_group = Group}}.
+add_alpn(Extensions, ALPN0) ->
+ ALPN = encode_alpn([ALPN0], false),
+ Extensions#{alpn => ALPN}.
+
+add_selected_version(Extensions) ->
+ SupportedVersions = #server_hello_selected_version{selected_version = {3,4}},
+ Extensions#{server_hello_selected_version => SupportedVersions}.
kse_remove_private_key(#key_share_entry{
group = Group,
@@ -3046,6 +3054,11 @@ empty_extensions({3,4}, server_hello) ->
key_share => undefined,
pre_shared_key => undefined
};
+empty_extensions({3,4}, hello_retry_request) ->
+ #{server_hello_selected_version => undefined,
+ key_share => undefined,
+ pre_shared_key => undefined
+ };
empty_extensions(_, server_hello) ->
#{renegotiation_info => undefined,
alpn => undefined,
diff --git a/lib/ssl/src/ssl_logger.erl b/lib/ssl/src/ssl_logger.erl
index 987693b96b..514a4464bc 100644
--- a/lib/ssl/src/ssl_logger.erl
+++ b/lib/ssl/src/ssl_logger.erl
@@ -200,6 +200,11 @@ parse_handshake(Direction, #encrypted_extensions{} = EncryptedExtensions) ->
Header = io_lib:format("~s Handshake, EncryptedExtensions",
[header_prefix(Direction)]),
Message = io_lib:format("~p", [?rec_info(encrypted_extensions, EncryptedExtensions)]),
+ {Header, Message};
+parse_handshake(Direction, #new_session_ticket{} = NewSessionTicket) ->
+ Header = io_lib:format("~s Post-Handshake, NewSessionTicket",
+ [header_prefix(Direction)]),
+ Message = io_lib:format("~p", [?rec_info(new_session_ticket, NewSessionTicket)]),
{Header, Message}.
diff --git a/lib/ssl/src/tls_connection.erl b/lib/ssl/src/tls_connection.erl
index 61281a3fb2..2651fc09bd 100644
--- a/lib/ssl/src/tls_connection.erl
+++ b/lib/ssl/src/tls_connection.erl
@@ -31,6 +31,7 @@
-include("tls_connection.hrl").
-include("tls_handshake.hrl").
+-include("tls_handshake_1_3.hrl").
-include("ssl_alert.hrl").
-include("tls_record.hrl").
-include("ssl_cipher.hrl").
@@ -394,6 +395,7 @@ queue_handshake(Handshake, #state{handshake_env = #handshake_env{tls_handshake_h
handshake_env = HsEnv#handshake_env{tls_handshake_history = Hist},
flight_buffer = Flight0 ++ [BinHandshake]}.
+
send_handshake_flight(#state{static_env = #static_env{socket = Socket,
transport_cb = Transport},
flight_buffer = Flight} = State0) ->
@@ -659,10 +661,16 @@ hello(internal, #server_hello{} = Hello,
case tls_handshake:hello(Hello, SslOptions, ConnectionStates0, Renegotiation) of
#alert{} = Alert -> %%TODO
ssl_connection:handle_own_alert(Alert, ReqVersion, hello,
- State#state{connection_env = CEnv#connection_env{negotiated_version = ReqVersion}});
+ State#state{connection_env =
+ CEnv#connection_env{negotiated_version = ReqVersion}});
+ %% Legacy TLS 1.2 and older
{Version, NewId, ConnectionStates, ProtoExt, Protocol} ->
ssl_connection:handle_session(Hello,
- Version, NewId, ConnectionStates, ProtoExt, Protocol, State)
+ Version, NewId, ConnectionStates, ProtoExt, Protocol, State);
+ %% TLS 1.3
+ {next_state, wait_sh} ->
+ %% Continue in TLS 1.3 'wait_sh' state
+ {next_state, wait_sh, State, [{next_event, internal, Hello}]}
end;
hello(info, Event, State) ->
gen_info(Event, ?FUNCTION_NAME, State);
@@ -803,6 +811,11 @@ connection(internal, #client_hello{},
State = reinit_handshake_data(State0),
next_event(?FUNCTION_NAME, no_record, State);
+connection(internal, #new_session_ticket{}, State) ->
+ %% TLS 1.3
+ %% Drop NewSessionTicket (currently not supported)
+ next_event(?FUNCTION_NAME, no_record, State);
+
connection(Type, Event, State) ->
ssl_connection:?FUNCTION_NAME(Type, Event, State, ?MODULE).
@@ -1286,9 +1299,10 @@ maybe_generate_client_shares(#ssl_options{
versions = [Version|_],
supported_groups =
#supported_groups{
- supported_groups = Groups}})
+ supported_groups = [Group|_]}})
when Version =:= {3,4} ->
- ssl_cipher:generate_client_shares(Groups);
+ %% Generate only key_share entry for the most preferred group
+ ssl_cipher:generate_client_shares([Group]);
maybe_generate_client_shares(_) ->
undefined.
diff --git a/lib/ssl/src/tls_connection_1_3.erl b/lib/ssl/src/tls_connection_1_3.erl
index 76cdebc76f..117e4f059d 100644
--- a/lib/ssl/src/tls_connection_1_3.erl
+++ b/lib/ssl/src/tls_connection_1_3.erl
@@ -112,7 +112,10 @@
negotiated/4,
wait_cert/4,
wait_cv/4,
- wait_finished/4
+ wait_finished/4,
+ wait_sh/4,
+ wait_ee/4,
+ wait_cert_cr/4
]).
@@ -127,6 +130,13 @@ start(internal, #client_hello{} = Hello, State0, _Module) ->
{State, negotiated} ->
{next_state, negotiated, State, [{next_event, internal, start_handshake}]}
end;
+start(internal, #server_hello{} = ServerHello, State0, _Module) ->
+ case tls_handshake_1_3:do_start(ServerHello, State0) of
+ #alert{} = Alert ->
+ ssl_connection:handle_own_alert(Alert, {3,4}, start, State0);
+ {State, NextState} ->
+ {next_state, NextState, State, []}
+ end;
start(Type, Msg, State, Connection) ->
ssl_connection:handle_common_event(Type, Msg, ?FUNCTION_NAME, State, Connection).
@@ -183,3 +193,52 @@ wait_finished(internal,
end;
wait_finished(Type, Msg, State, Connection) ->
ssl_connection:handle_common_event(Type, Msg, ?FUNCTION_NAME, State, Connection).
+
+
+wait_sh(internal, #change_cipher_spec{}, State, _Module) ->
+ tls_connection:next_event(?FUNCTION_NAME, no_record, State);
+wait_sh(internal, #server_hello{} = Hello, State0, _Module) ->
+ case tls_handshake_1_3:do_wait_sh(Hello, State0) of
+ #alert{} = Alert ->
+ ssl_connection:handle_own_alert(Alert, {3,4}, wait_sh, State0);
+ {State1, start, ServerHello} ->
+ %% hello_retry_request: go to start
+ {next_state, start, State1, [{next_event, internal, ServerHello}]};
+ {State1, wait_ee} ->
+ tls_connection:next_event(wait_ee, no_record, State1)
+ end;
+wait_sh(Type, Msg, State, Connection) ->
+ ssl_connection:handle_common_event(Type, Msg, ?FUNCTION_NAME, State, Connection).
+
+
+wait_ee(internal, #change_cipher_spec{}, State, _Module) ->
+ tls_connection:next_event(?FUNCTION_NAME, no_record, State);
+wait_ee(internal, #encrypted_extensions{} = EE, State0, _Module) ->
+ case tls_handshake_1_3:do_wait_ee(EE, State0) of
+ #alert{} = Alert ->
+ ssl_connection:handle_own_alert(Alert, {3,4}, wait_ee, State0);
+ {State1, NextState} ->
+ tls_connection:next_event(NextState, no_record, State1)
+ end;
+wait_ee(Type, Msg, State, Connection) ->
+ ssl_connection:handle_common_event(Type, Msg, ?FUNCTION_NAME, State, Connection).
+
+
+wait_cert_cr(internal, #change_cipher_spec{}, State, _Module) ->
+ tls_connection:next_event(?FUNCTION_NAME, no_record, State);
+wait_cert_cr(internal, #certificate_1_3{} = Certificate, State0, _Module) ->
+ case tls_handshake_1_3:do_wait_cert_cr(Certificate, State0) of
+ {#alert{} = Alert, State} ->
+ ssl_connection:handle_own_alert(Alert, {3,4}, wait_cert_cr, State);
+ {State1, NextState} ->
+ tls_connection:next_event(NextState, no_record, State1)
+ end;
+wait_cert_cr(internal, #certificate_request_1_3{} = CertificateRequest, State0, _Module) ->
+ case tls_handshake_1_3:do_wait_cert_cr(CertificateRequest, State0) of
+ #alert{} = Alert ->
+ ssl_connection:handle_own_alert(Alert, {3,4}, wait_cert_cr, State0);
+ {State1, NextState} ->
+ tls_connection:next_event(NextState, no_record, State1)
+ end;
+wait_cert_cr(Type, Msg, State, Connection) ->
+ ssl_connection:handle_common_event(Type, Msg, ?FUNCTION_NAME, State, Connection).
diff --git a/lib/ssl/src/tls_handshake.erl b/lib/ssl/src/tls_handshake.erl
index 2480e05097..c132f75eae 100644
--- a/lib/ssl/src/tls_handshake.erl
+++ b/lib/ssl/src/tls_handshake.erl
@@ -105,7 +105,7 @@ client_hello(Host, Port, ConnectionStates,
{tls_record:tls_version(), {resumed | new, #session{}},
ssl_record:connection_states(), binary() | undefined,
HelloExt::map(), {ssl:hash(), ssl:sign_algo()} |
- undefined} | #alert{}.
+ undefined} | {atom(), atom()} |#alert{}.
%%
%% Description: Handles a received hello message
%%--------------------------------------------------------------------
@@ -148,29 +148,48 @@ hello(#server_hello{server_version = {Major, Minor},
%%
%% - If "supported_version" is present (ServerHello):
%% - Abort handshake with an "illegal_parameter" alert
-hello(#server_hello{server_version = Version,
+hello(#server_hello{server_version = LegacyVersion,
+ random = Random,
+ cipher_suite = CipherSuite,
+ compression_method = Compression,
+ session_id = SessionId,
extensions = #{server_hello_selected_version :=
- #server_hello_selected_version{selected_version = Version}}
+ #server_hello_selected_version{selected_version = Version} = HelloExt}
},
- #ssl_options{versions = SupportedVersions},
- _ConnectionStates0, _Renegotiation) ->
- case tls_record:is_higher({3,4}, Version) of
+ #ssl_options{versions = SupportedVersions} = SslOpt,
+ ConnectionStates0, Renegotiation) ->
+ %% In TLS 1.3, the TLS server indicates its version using the "supported_versions" extension
+ %% (Section 4.2.1), and the legacy_version field MUST be set to 0x0303, which is the version
+ %% number for TLS 1.2.
+ %% The "supported_versions" extension is supported from TLS 1.2.
+ case LegacyVersion > {3,3} orelse
+ LegacyVersion =:= {3,3} andalso Version < {3,3} of
true ->
?ALERT_REC(?FATAL, ?ILLEGAL_PARAMETER);
false ->
case tls_record:is_acceptable_version(Version, SupportedVersions) of
true ->
- %% Implement TLS 1.3 statem ???
- ?ALERT_REC(?FATAL, ?PROTOCOL_VERSION);
+ case Version of
+ {3,3} ->
+ %% TLS 1.2 ServerHello with "supported_versions" (special case)
+ handle_server_hello_extensions(Version, SessionId, Random, CipherSuite,
+ Compression, HelloExt, SslOpt,
+ ConnectionStates0, Renegotiation);
+ {3,4} ->
+ %% TLS 1.3
+ {next_state, wait_sh}
+ end;
false ->
?ALERT_REC(?FATAL, ?ILLEGAL_PARAMETER)
end
end;
-hello(#server_hello{server_version = Version, random = Random,
+hello(#server_hello{server_version = Version,
+ random = Random,
cipher_suite = CipherSuite,
compression_method = Compression,
- session_id = SessionId, extensions = HelloExt},
+ session_id = SessionId,
+ extensions = HelloExt},
#ssl_options{versions = SupportedVersions} = SslOpt,
ConnectionStates0, Renegotiation) ->
case tls_record:is_acceptable_version(Version, SupportedVersions) of
diff --git a/lib/ssl/src/tls_handshake_1_3.erl b/lib/ssl/src/tls_handshake_1_3.erl
index 8a4ad922e1..4de51c9a35 100644
--- a/lib/ssl/src/tls_handshake_1_3.erl
+++ b/lib/ssl/src/tls_handshake_1_3.erl
@@ -39,23 +39,32 @@
%% Create handshake messages
-export([certificate/5,
certificate_verify/4,
- encrypted_extensions/0,
- server_hello/4]).
+ encrypted_extensions/0]).
-export([do_start/2,
do_negotiated/2,
do_wait_cert/2,
do_wait_cv/2,
- do_wait_finished/2]).
+ do_wait_finished/2,
+ do_wait_sh/2,
+ do_wait_ee/2,
+ do_wait_cert_cr/2]).
+
+
+%% crypto:hash(sha256, "HelloRetryRequest").
+-define(HELLO_RETRY_REQUEST_RANDOM, <<207,33,173,116,229,154,97,17,
+ 190,29,140,2,30,101,184,145,
+ 194,162,17,22,122,187,140,94,
+ 7,158,9,226,200,168,51,156>>).
%%====================================================================
%% Create handshake messages
%%====================================================================
-server_hello(MsgType, SessionId, KeyShare, ConnectionStates) ->
+server_hello(MsgType, SessionId, KeyShare, ConnectionStates, ALPN) ->
#{security_parameters := SecParams} =
ssl_record:pending_connection_state(ConnectionStates, read),
- Extensions = server_hello_extensions(MsgType, KeyShare),
+ Extensions = server_hello_extensions(MsgType, KeyShare, ALPN),
#server_hello{server_version = {3,3}, %% legacy_version
cipher_suite = SecParams#security_parameters.cipher_suite,
compression_method = 0, %% legacy attribute
@@ -64,10 +73,26 @@ server_hello(MsgType, SessionId, KeyShare, ConnectionStates) ->
extensions = Extensions
}.
-server_hello_extensions(MsgType, KeyShare) ->
+%% The server's extensions MUST contain "supported_versions".
+%% Additionally, it SHOULD contain the minimal set of extensions
+%% necessary for the client to generate a correct ClientHello pair. As
+%% with the ServerHello, a HelloRetryRequest MUST NOT contain any
+%% extensions that were not first offered by the client in its
+%% ClientHello, with the exception of optionally the "cookie" (see
+%% Section 4.2.2) extension.
+server_hello_extensions(hello_retry_request = MsgType, KeyShare, _) ->
+ SupportedVersions = #server_hello_selected_version{selected_version = {3,4}},
+ Extensions = #{server_hello_selected_version => SupportedVersions},
+ ssl_handshake:add_server_share(MsgType, Extensions, KeyShare);
+server_hello_extensions(MsgType, KeyShare, undefined) ->
SupportedVersions = #server_hello_selected_version{selected_version = {3,4}},
Extensions = #{server_hello_selected_version => SupportedVersions},
- ssl_handshake:add_server_share(MsgType, Extensions, KeyShare).
+ ssl_handshake:add_server_share(MsgType, Extensions, KeyShare);
+server_hello_extensions(MsgType, KeyShare, ALPN0) ->
+ Extensions0 = ssl_handshake:add_selected_version(#{}), %% {3,4} (TLS 1.3)
+ Extensions1 = ssl_handshake:add_alpn(Extensions0, ALPN0),
+ ssl_handshake:add_server_share(MsgType, Extensions1, KeyShare).
+
server_hello_random(server_hello, #security_parameters{server_random = Random}) ->
Random;
@@ -79,7 +104,7 @@ server_hello_random(server_hello, #security_parameters{server_random = Random})
%% CF 21 AD 74 E5 9A 61 11 BE 1D 8C 02 1E 65 B8 91
%% C2 A2 11 16 7A BB 8C 5E 07 9E 09 E2 C8 A8 33 9C
server_hello_random(hello_retry_request, _) ->
- crypto:hash(sha256, "HelloRetryRequest").
+ ?HELLO_RETRY_REQUEST_RANDOM.
%% TODO: implement support for encrypted_extensions
@@ -111,7 +136,7 @@ add_signature_algorithms_cert(Extensions, undefined) ->
Extensions;
add_signature_algorithms_cert(Extensions, SignAlgsCert) ->
Extensions#{signature_algorithms_cert =>
- #signature_algorithms{signature_scheme_list = SignAlgsCert}}.
+ #signature_algorithms_cert{signature_scheme_list = SignAlgsCert}}.
filter_tls13_algs(undefined) -> undefined;
@@ -119,7 +144,6 @@ filter_tls13_algs(Algo) ->
lists:filter(fun is_atom/1, Algo).
-%% TODO: use maybe monad for error handling!
%% enum {
%% X509(0),
%% RawPublicKey(2),
@@ -142,18 +166,28 @@ filter_tls13_algs(Algo) ->
%% opaque certificate_request_context<0..2^8-1>;
%% CertificateEntry certificate_list<0..2^24-1>;
%% } Certificate;
-certificate(OwnCert, CertDbHandle, CertDbRef, _CRContext, server) ->
+certificate(OwnCert, CertDbHandle, CertDbRef, _CRContext, Role) ->
case ssl_certificate:certificate_chain(OwnCert, CertDbHandle, CertDbRef) of
{ok, _, Chain} ->
CertList = chain_to_cert_list(Chain),
%% If this message is in response to a CertificateRequest, the value of
%% certificate_request_context in that message. Otherwise (in the case
%%of server authentication), this field SHALL be zero length.
- #certificate_1_3{
- certificate_request_context = <<>>,
- certificate_list = CertList};
- {error, Error} ->
- ?ALERT_REC(?FATAL, ?INTERNAL_ERROR, {server_has_no_suitable_certificates, Error})
+ {ok, #certificate_1_3{
+ certificate_request_context = <<>>,
+ certificate_list = CertList}};
+ {error, Error} when Role =:= server ->
+ {error, {no_suitable_certificates, Error}};
+ {error, _Error} when Role =:= client ->
+ %% The client MUST send a Certificate message if and only if the server
+ %% has requested client authentication via a CertificateRequest message
+ %% (Section 4.3.2). If the server requests client authentication but no
+ %% suitable certificate is available, the client MUST send a Certificate
+ %% message containing no certificates (i.e., with the "certificate_list"
+ %% field having length 0).
+ {ok, #certificate_1_3{
+ certificate_request_context = <<>>,
+ certificate_list = []}}
end.
@@ -161,7 +195,7 @@ certificate_verify(PrivateKey, SignatureScheme,
#state{connection_states = ConnectionStates,
handshake_env =
#handshake_env{
- tls_handshake_history = {Messages, _}}}, server) ->
+ tls_handshake_history = {Messages, _}}}, Role) ->
#{security_parameters := SecParamsR} =
ssl_record:pending_connection_state(ConnectionStates, write),
#security_parameters{prf_algorithm = HKDFAlgo} = SecParamsR,
@@ -173,11 +207,11 @@ certificate_verify(PrivateKey, SignatureScheme,
%% Transcript-Hash uses the HKDF hash function defined by the cipher suite.
THash = tls_v1:transcript_hash(Context, HKDFAlgo),
+ ContextString = context_string(Role),
%% Digital signatures use the hash function defined by the selected signature
%% scheme.
- case sign(THash, <<"TLS 1.3, server CertificateVerify">>,
- HashAlgo, PrivateKey) of
+ case sign(THash, ContextString, HashAlgo, PrivateKey) of
{ok, Signature} ->
{ok, #certificate_verify_1_3{
algorithm = SignatureScheme,
@@ -252,6 +286,21 @@ encode_handshake(HandshakeMsg) ->
%% Decode handshake
%%====================================================================
+
+decode_handshake(?SERVER_HELLO, <<?BYTE(Major), ?BYTE(Minor), Random:32/binary,
+ ?BYTE(SID_length), Session_ID:SID_length/binary,
+ Cipher_suite:2/binary, ?BYTE(Comp_method),
+ ?UINT16(ExtLen), Extensions:ExtLen/binary>>)
+ when Random =:= ?HELLO_RETRY_REQUEST_RANDOM ->
+ HelloExtensions = ssl_handshake:decode_hello_extensions(Extensions, {3,4}, {Major, Minor},
+ hello_retry_request),
+ #server_hello{
+ server_version = {Major,Minor},
+ random = Random,
+ session_id = Session_ID,
+ cipher_suite = Cipher_suite,
+ compression_method = Comp_method,
+ extensions = HelloExtensions};
decode_handshake(?CERTIFICATE_REQUEST, <<?BYTE(0), ?UINT16(Size), EncExts:Size/binary>>) ->
Exts = decode_extensions(EncExts, certificate_request),
#certificate_request_1_3{
@@ -428,15 +477,16 @@ build_content(Context, THash) ->
%%====================================================================
+%% TLS Server
do_start(#client_hello{cipher_suites = ClientCiphers,
session_id = SessionId,
extensions = Extensions} = _Hello,
#state{connection_states = _ConnectionStates0,
ssl_options = #ssl_options{ciphers = ServerCiphers,
signature_algs = ServerSignAlgs,
- supported_groups = ServerGroups0},
+ supported_groups = ServerGroups0,
+ alpn_preferred_protocols = ALPNPreferredProtocols},
session = #session{own_certificate = Cert}} = State0) ->
-
ClientGroups0 = maps:get(elliptic_curves, Extensions, undefined),
ClientGroups = get_supported_groups(ClientGroups0),
ServerGroups = get_supported_groups(ServerGroups0),
@@ -444,23 +494,27 @@ do_start(#client_hello{cipher_suites = ClientCiphers,
ClientShares0 = maps:get(key_share, Extensions, undefined),
ClientShares = get_key_shares(ClientShares0),
+ ClientALPN0 = maps:get(alpn, Extensions, undefined),
+ ClientALPN = ssl_handshake:decode_alpn(ClientALPN0),
+
ClientSignAlgs = get_signature_scheme_list(
maps:get(signature_algs, Extensions, undefined)),
ClientSignAlgsCert = get_signature_scheme_list(
maps:get(signature_algs_cert, Extensions, undefined)),
- %% TODO: use library function if it exists
- %% Init the maybe "monad"
{Ref,Maybe} = maybe(),
try
+ %% Handle ALPN extension if ALPN is configured
+ ALPNProtocol = Maybe(handle_alpn(ALPNPreferredProtocols, ClientALPN)),
+
%% If the server does not select a PSK, then the server independently selects a
%% cipher suite, an (EC)DHE group and key share for key establishment,
%% and a signature algorithm/certificate pair to authenticate itself to
%% the client.
Cipher = Maybe(select_cipher_suite(ClientCiphers, ServerCiphers)),
Groups = Maybe(select_common_groups(ServerGroups, ClientGroups)),
- Maybe(validate_key_share(ClientGroups, ClientShares)),
+ Maybe(validate_client_key_share(ClientGroups, ClientShares)),
{PublicKeyAlgo, SignAlgo, SignHash} = get_certificate_params(Cert),
@@ -479,8 +533,14 @@ do_start(#client_hello{cipher_suites = ClientCiphers,
%% Generate server_share
KeyShare = ssl_cipher:generate_server_share(Group),
- State1 = update_start_state(State0, Cipher, KeyShare, SessionId,
- Group, SelectedSignAlg, ClientPubKey),
+ State1 = update_start_state(State0,
+ #{cipher => Cipher,
+ key_share => KeyShare,
+ session_id => SessionId,
+ group => Group,
+ sign_alg => SelectedSignAlg,
+ peer_public_key => ClientPubKey,
+ alpn => ALPNProtocol}),
%% 4.1.4. Hello Retry Request
%%
@@ -490,10 +550,7 @@ do_start(#client_hello{cipher_suites = ClientCiphers,
%% the handshake.
Maybe(send_hello_retry_request(State1, ClientPubKey, KeyShare, SessionId))
- %% TODO:
- %% - session handling
- %% - handle extensions: ALPN
- %% (do not handle: NPN, srp, renegotiation_info, ec_point_formats)
+ %% TODO: session handling
catch
{Ref, {insufficient_security, no_suitable_groups}} ->
@@ -505,7 +562,87 @@ do_start(#client_hello{cipher_suites = ClientCiphers,
{Ref, {insufficient_security, no_suitable_signature_algorithm}} ->
?ALERT_REC(?FATAL, ?INSUFFICIENT_SECURITY, "No suitable signature algorithm");
{Ref, {insufficient_security, no_suitable_public_key}} ->
- ?ALERT_REC(?FATAL, ?INSUFFICIENT_SECURITY, no_suitable_public_key)
+ ?ALERT_REC(?FATAL, ?INSUFFICIENT_SECURITY, no_suitable_public_key);
+ {Ref, no_application_protocol} ->
+ ?ALERT_REC(?FATAL, ?NO_APPLICATION_PROTOCOL)
+ end;
+%% TLS Client
+do_start(#server_hello{cipher_suite = SelectedCipherSuite,
+ session_id = SessionId,
+ extensions = Extensions} = _ServerHello,
+ #state{static_env = #static_env{role = client,
+ host = Host,
+ port = Port,
+ transport_cb = Transport,
+ socket = Socket,
+ session_cache = Cache,
+ session_cache_cb = CacheCb},
+ handshake_env = #handshake_env{renegotiation = {Renegotiation, _},
+ tls_handshake_history = _HHistory} = HsEnv,
+ connection_env = CEnv,
+ ssl_options = #ssl_options{ciphers = ClientCiphers,
+ supported_groups = ClientGroups0} = SslOpts,
+ session = #session{own_certificate = Cert} = Session0,
+ connection_states = ConnectionStates0
+ } = State0) ->
+ ClientGroups = get_supported_groups(ClientGroups0),
+
+ {Ref,Maybe} = maybe(),
+ try
+ ServerKeyShare = maps:get(key_share, Extensions, undefined),
+ SelectedGroup = get_selected_group(ServerKeyShare),
+
+ %% Upon receipt of this extension in a HelloRetryRequest, the client
+ %% MUST verify that (1) the selected_group field corresponds to a group
+ %% which was provided in the "supported_groups" extension in the
+ %% original ClientHello and (2) the selected_group field does not
+ %% correspond to a group which was provided in the "key_share" extension
+ %% in the original ClientHello. If either of these checks fails, then
+ %% the client MUST abort the handshake with an "illegal_parameter"
+ %% alert.
+ Maybe(validate_selected_group(SelectedGroup, ClientGroups)),
+
+ Maybe(validate_cipher_suite(SelectedCipherSuite, ClientCiphers)),
+
+ %% Otherwise, when sending the new ClientHello, the client MUST
+ %% replace the original "key_share" extension with one containing only a
+ %% new KeyShareEntry for the group indicated in the selected_group field
+ %% of the triggering HelloRetryRequest.
+ ClientKeyShare = ssl_cipher:generate_client_shares([SelectedGroup]),
+ Hello = tls_handshake:client_hello(Host, Port, ConnectionStates0, SslOpts,
+ Cache, CacheCb, Renegotiation, Cert, ClientKeyShare),
+
+ HelloVersion = tls_record:hello_version(SslOpts#ssl_options.versions),
+
+ %% Update state
+ State1 = update_start_state(State0,
+ #{cipher => SelectedCipherSuite,
+ key_share => ClientKeyShare,
+ session_id => SessionId,
+ group => SelectedGroup}),
+
+ %% Replace ClientHello1 with a special synthetic handshake message
+ State2 = replace_ch1_with_message_hash(State1),
+ #state{handshake_env = #handshake_env{tls_handshake_history = HHistory}} = State2,
+
+ {BinMsg, ConnectionStates, Handshake} =
+ tls_connection:encode_handshake(Hello, HelloVersion, ConnectionStates0, HHistory),
+ tls_socket:send(Transport, Socket, BinMsg),
+ ssl_logger:debug(SslOpts#ssl_options.log_level, outbound, 'handshake', Hello),
+ ssl_logger:debug(SslOpts#ssl_options.log_level, outbound, 'record', BinMsg),
+
+ State = State2#state{
+ connection_states = ConnectionStates,
+ connection_env = CEnv#connection_env{negotiated_version = HelloVersion}, %% Requested version
+ session = Session0#session{session_id = Hello#client_hello.session_id},
+ handshake_env = HsEnv#handshake_env{tls_handshake_history = Handshake},
+ key_share = ClientKeyShare},
+
+ {State, wait_sh}
+
+ catch
+ {Ref, {illegal_parameter, Reason}} ->
+ ?ALERT_REC(?FATAL, ?ILLEGAL_PARAMETER, Reason)
end.
@@ -515,10 +652,11 @@ do_negotiated(start_handshake,
own_certificate = OwnCert,
ecc = SelectedGroup,
sign_alg = SignatureScheme,
- dh_public_value = ClientKey},
+ dh_public_value = ClientPublicKey},
ssl_options = #ssl_options{} = SslOpts,
key_share = KeyShare,
- handshake_env = #handshake_env{tls_handshake_history = _HHistory0},
+ handshake_env = #handshake_env{tls_handshake_history = _HHistory0,
+ alpn = ALPN},
connection_env = #connection_env{private_key = CertPrivateKey},
static_env = #static_env{
cert_db = CertDbHandle,
@@ -526,17 +664,19 @@ do_negotiated(start_handshake,
socket = _Socket,
transport_cb = _Transport}
} = State0) ->
+ ServerPrivateKey = get_server_private_key(KeyShare),
+
{Ref,Maybe} = maybe(),
try
%% Create server_hello
%% Extensions: supported_versions, key_share, (pre_shared_key)
- ServerHello = server_hello(server_hello, SessionId, KeyShare, ConnectionStates0),
+ ServerHello = server_hello(server_hello, SessionId, KeyShare, ConnectionStates0, ALPN),
{State1, _} = tls_connection:send_handshake(ServerHello, State0),
State2 =
- calculate_handshake_secrets(ClientKey, SelectedGroup, KeyShare, State1),
+ calculate_handshake_secrets(ClientPublicKey, ServerPrivateKey, SelectedGroup, State1),
State3 = ssl_record:step_encryption_state(State2),
@@ -550,7 +690,7 @@ do_negotiated(start_handshake,
{State5, NextState} = maybe_send_certificate_request(State4, SslOpts),
%% Create Certificate
- Certificate = certificate(OwnCert, CertDbHandle, CertDbRef, <<>>, server),
+ Certificate = Maybe(certificate(OwnCert, CertDbHandle, CertDbRef, <<>>, server)),
%% Encode Certificate
State6 = tls_connection:queue_handshake(Certificate, State5),
@@ -574,14 +714,16 @@ do_negotiated(start_handshake,
catch
{Ref, badarg} ->
- ?ALERT_REC(?FATAL, ?INTERNAL_ERROR, {digitally_sign, badarg})
+ ?ALERT_REC(?FATAL, ?INTERNAL_ERROR, {digitally_sign, badarg});
+ {Ref, {no_suitable_certificates, Reason}} ->
+ ?ALERT_REC(?FATAL, ?INTERNAL_ERROR, {no_suitable_certificates, Reason})
end.
do_wait_cert(#certificate_1_3{} = Certificate, State0) ->
{Ref,Maybe} = maybe(),
try
- Maybe(process_client_certificate(Certificate, State0))
+ Maybe(process_certificate(Certificate, State0))
catch
{Ref, {certificate_required, State}} ->
{?ALERT_REC(?FATAL, ?CERTIFICATE_REQUIRED, certificate_required), State};
@@ -591,6 +733,8 @@ do_wait_cert(#certificate_1_3{} = Certificate, State0) ->
{?ALERT_REC(?FATAL, ?INTERNAL_ERROR, Reason), State};
{Ref, {{handshake_failure, Reason}, State}} ->
{?ALERT_REC(?FATAL, ?HANDSHAKE_FAILURE, Reason), State};
+ {Ref, {#alert{} = Alert, State}} ->
+ {Alert, State};
{#alert{} = Alert, State} ->
{Alert, State}
end.
@@ -599,8 +743,8 @@ do_wait_cert(#certificate_1_3{} = Certificate, State0) ->
do_wait_cv(#certificate_verify_1_3{} = CertificateVerify, State0) ->
{Ref,Maybe} = maybe(),
try
- Maybe(verify_signature_algorithm(State0, CertificateVerify)),
- Maybe(verify_certificate_verify(State0, CertificateVerify))
+ State1 = Maybe(verify_signature_algorithm(State0, CertificateVerify)),
+ Maybe(verify_certificate_verify(State1, CertificateVerify))
catch
{Ref, {{bad_certificate, Reason}, State}} ->
{?ALERT_REC(?FATAL, ?BAD_CERTIFICATE, {bad_certificate, Reason}), State};
@@ -610,20 +754,9 @@ do_wait_cv(#certificate_verify_1_3{} = CertificateVerify, State0) ->
{?ALERT_REC(?FATAL, ?HANDSHAKE_FAILURE, {handshake_failure, Reason}), State}
end.
-
+%% TLS Server
do_wait_finished(#finished{verify_data = VerifyData},
- #state{connection_states = _ConnectionStates0,
- session = #session{session_id = _SessionId,
- own_certificate = _OwnCert},
- ssl_options = #ssl_options{} = _SslOpts,
- key_share = _KeyShare,
- handshake_env = #handshake_env{tls_handshake_history = _HHistory0},
- static_env = #static_env{
- cert_db = _CertDbHandle,
- cert_db_ref = _CertDbRef,
- socket = _Socket,
- transport_cb = _Transport}
- } = State0) ->
+ #state{static_env = #static_env{role = server}} = State0) ->
{Ref,Maybe} = maybe(),
@@ -639,19 +772,230 @@ do_wait_finished(#finished{verify_data = VerifyData},
catch
{Ref, decrypt_error} ->
?ALERT_REC(?FATAL, ?DECRYPT_ERROR, decrypt_error)
+ end;
+%% TLS Client
+do_wait_finished(#finished{verify_data = _VerifyData},
+ #state{static_env = #static_env{role = client}} = State0) ->
+
+ {Ref,Maybe} = maybe(),
+
+ try
+ %% Maybe(validate_client_finished(State0, VerifyData)),
+
+ %% Maybe send Certificate + CertificateVerify
+ State1 = Maybe(maybe_queue_cert_cert_cv(State0)),
+
+ Finished = finished(State1),
+
+ %% Encode Finished
+ State2 = tls_connection:queue_handshake(Finished, State1),
+
+ %% Send first flight
+ {State3, _} = tls_connection:send_handshake_flight(State2),
+
+ State4 = calculate_traffic_secrets(State3),
+
+ %% Configure traffic keys
+ ssl_record:step_encryption_state(State4)
+
+ catch
+ {Ref, decrypt_error} ->
+ ?ALERT_REC(?FATAL, ?DECRYPT_ERROR, decrypt_error);
+ {Ref, badarg} ->
+ ?ALERT_REC(?FATAL, ?INTERNAL_ERROR, {digitally_sign, badarg});
+ {Ref, {no_suitable_certificates, Reason}} ->
+ ?ALERT_REC(?FATAL, ?INTERNAL_ERROR, {no_suitable_certificates, Reason})
end.
+do_wait_sh(#server_hello{cipher_suite = SelectedCipherSuite,
+ session_id = SessionId,
+ extensions = Extensions} = ServerHello,
+ #state{key_share = ClientKeyShare0,
+ ssl_options = #ssl_options{ciphers = ClientCiphers,
+ supported_groups = ClientGroups0}} = State0) ->
+ ClientGroups = get_supported_groups(ClientGroups0),
+ ServerKeyShare0 = maps:get(key_share, Extensions, undefined),
+ ClientKeyShare = get_key_shares(ClientKeyShare0),
+
+ {Ref,Maybe} = maybe(),
+ try
+ %% Go to state 'start' if server replies with 'HelloRetryRequest'.
+ Maybe(maybe_hello_retry_request(ServerHello, State0)),
+
+ ServerKeyShare = get_key_shares(ServerKeyShare0),
+
+ Maybe(validate_cipher_suite(SelectedCipherSuite, ClientCiphers)),
+ Maybe(validate_server_key_share(ClientGroups, ServerKeyShare)),
+
+ %% Get server public key
+ {SelectedGroup, ServerPublicKey} = get_server_public_key(ServerKeyShare),
+
+ {_, ClientPrivateKey} = get_client_private_key([SelectedGroup], ClientKeyShare),
+
+ %% Update state
+ State1 = update_start_state(State0,
+ #{cipher => SelectedCipherSuite,
+ key_share => ClientKeyShare0,
+ session_id => SessionId,
+ group => SelectedGroup,
+ peer_public_key => ServerPublicKey}),
+
+ State2 = calculate_handshake_secrets(ServerPublicKey, ClientPrivateKey, SelectedGroup, State1),
+
+ State3 = ssl_record:step_encryption_state(State2),
+
+ {State3, wait_ee}
+
+ catch
+ {Ref, {State, StateName, ServerHello}} ->
+ {State, StateName, ServerHello};
+ {Ref, {insufficient_security, no_suitable_groups}} ->
+ ?ALERT_REC(?FATAL, ?INSUFFICIENT_SECURITY, no_suitable_groups);
+ {Ref, illegal_parameter} ->
+ ?ALERT_REC(?FATAL, ?ILLEGAL_PARAMETER);
+ {Ref, no_suitable_cipher} ->
+ ?ALERT_REC(?FATAL, ?INSUFFICIENT_SECURITY, no_suitable_cipher);
+ {Ref, {insufficient_security, no_suitable_signature_algorithm}} ->
+ ?ALERT_REC(?FATAL, ?INSUFFICIENT_SECURITY, "No suitable signature algorithm");
+ {Ref, {insufficient_security, no_suitable_public_key}} ->
+ ?ALERT_REC(?FATAL, ?INSUFFICIENT_SECURITY, no_suitable_public_key)
+ end.
+
+
+do_wait_ee(#encrypted_extensions{extensions = _Extensions}, State0) ->
+
+ {Ref,_Maybe} = maybe(),
+
+ try
+ {State0, wait_cert_cr}
+ catch
+ {Ref, {insufficient_security, no_suitable_groups}} ->
+ ?ALERT_REC(?FATAL, ?INSUFFICIENT_SECURITY, no_suitable_groups);
+ {Ref, illegal_parameter} ->
+ ?ALERT_REC(?FATAL, ?ILLEGAL_PARAMETER);
+ {Ref, no_suitable_cipher} ->
+ ?ALERT_REC(?FATAL, ?INSUFFICIENT_SECURITY, no_suitable_cipher);
+ {Ref, {insufficient_security, no_suitable_signature_algorithm}} ->
+ ?ALERT_REC(?FATAL, ?INSUFFICIENT_SECURITY, "No suitable signature algorithm");
+ {Ref, {insufficient_security, no_suitable_public_key}} ->
+ ?ALERT_REC(?FATAL, ?INSUFFICIENT_SECURITY, no_suitable_public_key)
+ end.
+
+
+do_wait_cert_cr(#certificate_1_3{} = Certificate, State0) ->
+ {Ref,Maybe} = maybe(),
+ try
+ Maybe(process_certificate(Certificate, State0))
+ catch
+ {Ref, {certificate_required, _State}} ->
+ ?ALERT_REC(?FATAL, ?CERTIFICATE_REQUIRED, certificate_required);
+ {Ref, {{certificate_unknown, Reason}, _State}} ->
+ ?ALERT_REC(?FATAL, ?CERTIFICATE_UNKNOWN, Reason);
+ {Ref, {{internal_error, Reason}, _State}} ->
+ ?ALERT_REC(?FATAL, ?INTERNAL_ERROR, Reason);
+ {Ref, {{handshake_failure, Reason}, _State}} ->
+ ?ALERT_REC(?FATAL, ?HANDSHAKE_FAILURE, Reason);
+ {Ref, {#alert{} = Alert, State}} ->
+ {Alert, State}
+ end;
+do_wait_cert_cr(#certificate_request_1_3{} = CertificateRequest, State0) ->
+ {Ref,Maybe} = maybe(),
+ try
+ Maybe(process_certificate_request(CertificateRequest, State0))
+ catch
+ {Ref, {certificate_required, _State}} ->
+ ?ALERT_REC(?FATAL, ?CERTIFICATE_REQUIRED, certificate_required);
+ {Ref, {{certificate_unknown, Reason}, _State}} ->
+ ?ALERT_REC(?FATAL, ?CERTIFICATE_UNKNOWN, Reason);
+ {Ref, {illegal_parameter, Reason}} ->
+ ?ALERT_REC(?FATAL, ?ILLEGAL_PARAMETER, Reason);
+ {Ref, {{internal_error, Reason}, _State}} ->
+ ?ALERT_REC(?FATAL, ?INTERNAL_ERROR, Reason);
+ {Ref, {{handshake_failure, Reason}, _State}} ->
+ ?ALERT_REC(?FATAL, ?HANDSHAKE_FAILURE, Reason)
+ end.
+
+
+
%% TODO: Remove this function!
%% not_implemented(State, Reason) ->
%% {error, {not_implemented, State, Reason}}.
-%%
+
%% not_implemented(update_secrets, State0, Reason) ->
%% State1 = calculate_traffic_secrets(State0),
%% State = ssl_record:step_encryption_state(State1),
%% {error, {not_implemented, State, Reason}}.
+%% For reasons of backward compatibility with middleboxes (see
+%% Appendix D.4), the HelloRetryRequest message uses the same structure
+%% as the ServerHello, but with Random set to the special value of the
+%% SHA-256 of "HelloRetryRequest":
+%%
+%% CF 21 AD 74 E5 9A 61 11 BE 1D 8C 02 1E 65 B8 91
+%% C2 A2 11 16 7A BB 8C 5E 07 9E 09 E2 C8 A8 33 9C
+%%
+%% Upon receiving a message with type server_hello, implementations MUST
+%% first examine the Random value and, if it matches this value, process
+%% it as described in Section 4.1.4).
+maybe_hello_retry_request(#server_hello{random = ?HELLO_RETRY_REQUEST_RANDOM} = ServerHello, State0) ->
+ {error, {State0, start, ServerHello}};
+maybe_hello_retry_request(_, _) ->
+ ok.
+
+
+maybe_queue_cert_cert_cv(#state{client_certificate_requested = false} = State) ->
+ {ok, State};
+maybe_queue_cert_cert_cv(#state{connection_states = _ConnectionStates0,
+ session = #session{session_id = _SessionId,
+ own_certificate = OwnCert},
+ ssl_options = #ssl_options{} = _SslOpts,
+ key_share = _KeyShare,
+ handshake_env = #handshake_env{tls_handshake_history = _HHistory0},
+ static_env = #static_env{
+ role = client,
+ cert_db = CertDbHandle,
+ cert_db_ref = CertDbRef,
+ socket = _Socket,
+ transport_cb = _Transport}
+ } = State0) ->
+ {Ref,Maybe} = maybe(),
+ try
+ %% Create Certificate
+ Certificate = Maybe(certificate(OwnCert, CertDbHandle, CertDbRef, <<>>, client)),
+
+ %% Encode Certificate
+ State1 = tls_connection:queue_handshake(Certificate, State0),
+
+ %% Maybe create and queue CertificateVerify
+ State = Maybe(maybe_queue_cert_verify(Certificate, State1)),
+ {ok, State}
+ catch
+ {Ref, badarg} ->
+ {error, badarg}
+ end.
+
+
+%% Clients MUST send this message whenever authenticating via a certificate
+%% (i.e., when the Certificate message is non-empty).
+maybe_queue_cert_verify(#certificate_1_3{certificate_list = []}, State) ->
+ {ok, State};
+maybe_queue_cert_verify(_Certificate,
+ #state{connection_states = _ConnectionStates0,
+ session = #session{sign_alg = SignatureScheme},
+ connection_env = #connection_env{private_key = CertPrivateKey},
+ static_env = #static_env{role = client}
+ } = State) ->
+ {Ref,Maybe} = maybe(),
+ try
+ CertificateVerify = Maybe(certificate_verify(CertPrivateKey, SignatureScheme, State, client)),
+ {ok, tls_connection:queue_handshake(CertificateVerify, State)}
+ catch
+ {Ref, badarg} ->
+ {error, badarg}
+ end.
+
%% Recipients of Finished messages MUST verify that the contents are
%% correct and if incorrect MUST terminate the connection with a
@@ -679,12 +1023,13 @@ compare_verify_data(_, _) ->
{error, decrypt_error}.
-send_hello_retry_request(#state{connection_states = ConnectionStates0} = State0,
+send_hello_retry_request(#state{connection_states = ConnectionStates0,
+ handshake_env = #handshake_env{alpn = ALPN}} = State0,
no_suitable_key, KeyShare, SessionId) ->
- ServerHello = server_hello(hello_retry_request, SessionId, KeyShare, ConnectionStates0),
+ ServerHello = server_hello(hello_retry_request, SessionId, KeyShare, ConnectionStates0, ALPN),
{State1, _} = tls_connection:send_handshake(ServerHello, State0),
- %% TODO: Fix handshake history!
+ %% Update handshake history
State2 = replace_ch1_with_message_hash(State1),
{ok, {State2, start}};
@@ -703,19 +1048,44 @@ maybe_send_certificate_request(State, #ssl_options{
{tls_connection:queue_handshake(CertificateRequest, State), wait_cert}.
-process_client_certificate(#certificate_1_3{
- certificate_request_context = <<>>,
- certificate_list = []},
- #state{ssl_options =
- #ssl_options{
- fail_if_no_peer_cert = false}} = State) ->
+process_certificate_request(#certificate_request_1_3{},
+ #state{session = #session{own_certificate = undefined}} = State) ->
+ {ok, {State#state{client_certificate_requested = true}, wait_cert}};
+
+process_certificate_request(#certificate_request_1_3{
+ extensions = Extensions},
+ #state{session = #session{own_certificate = Cert} = Session} = State) ->
+ ServerSignAlgs = get_signature_scheme_list(
+ maps:get(signature_algs, Extensions, undefined)),
+ ServerSignAlgsCert = get_signature_scheme_list(
+ maps:get(signature_algs_cert, Extensions, undefined)),
+
+ {_PublicKeyAlgo, SignAlgo, SignHash} = get_certificate_params(Cert),
+
+ %% Check if server supports signature algorithm of client certificate
+ case check_cert_sign_algo(SignAlgo, SignHash, ServerSignAlgs, ServerSignAlgsCert) of
+ ok ->
+ {ok, {State#state{client_certificate_requested = true}, wait_cert}};
+ {error, _} ->
+ %% Certificate not supported: send empty certificate in state 'wait_finished'
+ {ok, {State#state{client_certificate_requested = true,
+ session = Session#session{own_certificate = undefined}}, wait_cert}}
+ end.
+
+
+process_certificate(#certificate_1_3{
+ certificate_request_context = <<>>,
+ certificate_list = []},
+ #state{ssl_options =
+ #ssl_options{
+ fail_if_no_peer_cert = false}} = State) ->
{ok, {State, wait_finished}};
-process_client_certificate(#certificate_1_3{
- certificate_request_context = <<>>,
- certificate_list = []},
- #state{ssl_options =
- #ssl_options{
- fail_if_no_peer_cert = true}} = State0) ->
+process_certificate(#certificate_1_3{
+ certificate_request_context = <<>>,
+ certificate_list = []},
+ #state{ssl_options =
+ #ssl_options{
+ fail_if_no_peer_cert = true}} = State0) ->
%% At this point the client believes that the connection is up and starts using
%% its traffic secrets. In order to be able send an proper Alert to the client
@@ -724,19 +1094,18 @@ process_client_certificate(#certificate_1_3{
State1 = calculate_traffic_secrets(State0),
State = ssl_record:step_encryption_state(State1),
{error, {certificate_required, State}};
-process_client_certificate(#certificate_1_3{certificate_list = Certs0},
- #state{ssl_options =
- #ssl_options{signature_algs = SignAlgs,
- signature_algs_cert = SignAlgsCert} = SslOptions,
- static_env =
- #static_env{
- role = Role,
- host = Host,
- cert_db = CertDbHandle,
- cert_db_ref = CertDbRef,
- crl_db = CRLDbHandle}} = State0) ->
+process_certificate(#certificate_1_3{certificate_list = Certs0},
+ #state{ssl_options =
+ #ssl_options{signature_algs = SignAlgs,
+ signature_algs_cert = SignAlgsCert} = SslOptions,
+ static_env =
+ #static_env{
+ role = Role,
+ host = Host,
+ cert_db = CertDbHandle,
+ cert_db_ref = CertDbRef,
+ crl_db = CRLDbHandle}} = State0) ->
%% TODO: handle extensions!
-
%% Remove extensions from list of certificates!
Certs = convert_certificate_chain(Certs0),
case is_supported_signature_algorithm(Certs, SignAlgs, SignAlgsCert) of
@@ -747,13 +1116,11 @@ process_client_certificate(#certificate_1_3{certificate_list = Certs0},
State = store_peer_cert(State0, PeerCert, PublicKeyInfo),
{ok, {State, wait_cv}};
{error, Reason} ->
- State1 = calculate_traffic_secrets(State0),
- State = ssl_record:step_encryption_state(State1),
+ State = update_encryption_state(Role, State0),
{error, {Reason, State}};
- #alert{} = Alert ->
- State1 = calculate_traffic_secrets(State0),
- State = ssl_record:step_encryption_state(State1),
- {Alert, State}
+ {ok, #alert{} = Alert} ->
+ State = update_encryption_state(Role, State0),
+ {error, {Alert, State}}
end;
false ->
State1 = calculate_traffic_secrets(State0),
@@ -777,6 +1144,17 @@ is_supported_signature_algorithm([BinCert|_], SignAlgs0) ->
lists:member(Scheme, SignAlgs).
+%% Sets correct encryption state when sending Alerts in shared states that use different secrets.
+%% - If client: use handshake secrets.
+%% - If server: use traffic secrets as by this time the client's state machine
+%% already stepped into the 'connection' state.
+update_encryption_state(server, State0) ->
+ State1 = calculate_traffic_secrets(State0),
+ ssl_record:step_encryption_state(State1);
+update_encryption_state(client, State) ->
+ State.
+
+
validate_certificate_chain(Certs, CertDbHandle, CertDbRef, SslOptions, CRLDbHandle, Role, Host) ->
ServerName = ssl_handshake:server_name(SslOptions#ssl_options.server_name_indication, Host, Role),
[PeerCert | ChainCerts ] = Certs,
@@ -797,9 +1175,9 @@ validate_certificate_chain(Certs, CertDbHandle, CertDbRef, SslOptions, CRLDbHand
{ok, {PublicKeyInfo,_}} ->
{ok, {PeerCert, PublicKeyInfo}};
{error, Reason} ->
- ssl_handshake:handle_path_validation_error(Reason, PeerCert, ChainCerts,
- SslOptions, Options,
- CertDbHandle, CertDbRef)
+ {ok, ssl_handshake:handle_path_validation_error(Reason, PeerCert, ChainCerts,
+ SslOptions, Options,
+ CertDbHandle, CertDbRef)}
end
catch
error:{badmatch,{asn1, Asn1Reason}} ->
@@ -861,7 +1239,7 @@ message_hash(ClientHello1, HKDFAlgo) ->
crypto:hash(HKDFAlgo, ClientHello1)].
-calculate_handshake_secrets(ClientKey, SelectedGroup, KeyShare,
+calculate_handshake_secrets(PublicKey, PrivateKey, SelectedGroup,
#state{connection_states = ConnectionStates,
handshake_env =
#handshake_env{
@@ -874,13 +1252,13 @@ calculate_handshake_secrets(ClientKey, SelectedGroup, KeyShare,
%% Calculate handshake_secret
PSK = binary:copy(<<0>>, ssl_cipher:hash_size(HKDFAlgo)),
EarlySecret = tls_v1:key_schedule(early_secret, HKDFAlgo , {psk, PSK}),
- PrivateKey = get_server_private_key(KeyShare), %% #'ECPrivateKey'{}
- IKM = calculate_shared_secret(ClientKey, PrivateKey, SelectedGroup),
+ IKM = calculate_shared_secret(PublicKey, PrivateKey, SelectedGroup),
HandshakeSecret = tls_v1:key_schedule(handshake_secret, HKDFAlgo, IKM, EarlySecret),
%% Calculate [sender]_handshake_traffic_secret
{Messages, _} = HHistory,
+
ClientHSTrafficSecret =
tls_v1:client_handshake_traffic_secret(HKDFAlgo, HandshakeSecret, lists:reverse(Messages)),
ServerHSTrafficSecret =
@@ -899,10 +1277,13 @@ calculate_handshake_secrets(ClientKey, SelectedGroup, KeyShare,
ReadKey, ReadIV, ReadFinishedKey,
WriteKey, WriteIV, WriteFinishedKey).
-calculate_traffic_secrets(#state{connection_states = ConnectionStates,
- handshake_env =
- #handshake_env{
- tls_handshake_history = HHistory}} = State0) ->
+
+calculate_traffic_secrets(#state{
+ static_env = #static_env{role = Role},
+ connection_states = ConnectionStates,
+ handshake_env =
+ #handshake_env{
+ tls_handshake_history = HHistory}} = State0) ->
#{security_parameters := SecParamsR} =
ssl_record:pending_connection_state(ConnectionStates, read),
#security_parameters{prf_algorithm = HKDFAlgo,
@@ -913,7 +1294,7 @@ calculate_traffic_secrets(#state{connection_states = ConnectionStates,
tls_v1:key_schedule(master_secret, HKDFAlgo, HandshakeSecret),
%% Get the correct list messages for the handshake context.
- Messages = get_handshake_context(HHistory),
+ Messages = get_handshake_context(Role, HHistory),
%% Calculate [sender]_application_traffic_secret_0
ClientAppTrafficSecret0 =
@@ -966,9 +1347,11 @@ calculate_shared_secret(OthersKey, MyKey = #'ECPrivateKey'{}, _Group)
public_key:compute_key(Point, MyKey).
-update_pending_connection_states(#state{connection_states =
- CS = #{pending_read := PendingRead0,
- pending_write := PendingWrite0}} = State,
+update_pending_connection_states(#state{
+ static_env = #static_env{role = server},
+ connection_states =
+ CS = #{pending_read := PendingRead0,
+ pending_write := PendingWrite0}} = State,
HandshakeSecret,
ReadKey, ReadIV, ReadFinishedKey,
WriteKey, WriteIV, WriteFinishedKey) ->
@@ -977,8 +1360,23 @@ update_pending_connection_states(#state{connection_states =
PendingWrite = update_connection_state(PendingWrite0, HandshakeSecret,
WriteKey, WriteIV, WriteFinishedKey),
State#state{connection_states = CS#{pending_read => PendingRead,
+ pending_write => PendingWrite}};
+update_pending_connection_states(#state{
+ static_env = #static_env{role = client},
+ connection_states =
+ CS = #{pending_read := PendingRead0,
+ pending_write := PendingWrite0}} = State,
+ HandshakeSecret,
+ ReadKey, ReadIV, ReadFinishedKey,
+ WriteKey, WriteIV, WriteFinishedKey) ->
+ PendingRead = update_connection_state(PendingRead0, HandshakeSecret,
+ WriteKey, WriteIV, WriteFinishedKey),
+ PendingWrite = update_connection_state(PendingWrite0, HandshakeSecret,
+ ReadKey, ReadIV, ReadFinishedKey),
+ State#state{connection_states = CS#{pending_read => PendingRead,
pending_write => PendingWrite}}.
+
update_connection_state(ConnectionState = #{security_parameters := SecurityParameters0},
HandshakeSecret, Key, IV, FinishedKey) ->
%% Store secret
@@ -988,11 +1386,24 @@ update_connection_state(ConnectionState = #{security_parameters := SecurityParam
cipher_state => cipher_init(Key, IV, FinishedKey)}.
+update_start_state(State, Map) ->
+ Cipher = maps:get(cipher, Map, undefined),
+ KeyShare = maps:get(key_share, Map, undefined),
+ SessionId = maps:get(session_id, Map, undefined),
+ Group = maps:get(group, Map, undefined),
+ SelectedSignAlg = maps:get(sign_alg, Map, undefined),
+ PeerPublicKey = maps:get(peer_public_key, Map, undefined),
+ ALPNProtocol = maps:get(alpn, Map, undefined),
+ update_start_state(State, Cipher, KeyShare, SessionId,
+ Group, SelectedSignAlg, PeerPublicKey,
+ ALPNProtocol).
+%%
update_start_state(#state{connection_states = ConnectionStates0,
+ handshake_env = #handshake_env{} = HsEnv,
connection_env = CEnv,
session = Session} = State,
Cipher, KeyShare, SessionId,
- Group, SelectedSignAlg, ClientPubKey) ->
+ Group, SelectedSignAlg, PeerPublicKey, ALPNProtocol) ->
#{security_parameters := SecParamsR0} = PendingRead =
maps:get(pending_read, ConnectionStates0),
#{security_parameters := SecParamsW0} = PendingWrite =
@@ -1003,11 +1414,12 @@ update_start_state(#state{connection_states = ConnectionStates0,
ConnectionStates0#{pending_read => PendingRead#{security_parameters => SecParamsR},
pending_write => PendingWrite#{security_parameters => SecParamsW}},
State#state{connection_states = ConnectionStates,
+ handshake_env = HsEnv#handshake_env{alpn = ALPNProtocol},
key_share = KeyShare,
session = Session#session{session_id = SessionId,
ecc = Group,
sign_alg = SelectedSignAlg,
- dh_public_value = ClientPubKey,
+ dh_public_value = PeerPublicKey,
cipher_suite = Cipher},
connection_env = CEnv#connection_env{negotiated_version = {3,4}}}.
@@ -1071,25 +1483,41 @@ get_handshake_context_cv({[<<15,_/binary>>|Messages], _}) ->
%%
%% Drop all client messages from the front of the iolist using the property that
%% incoming messages are binaries.
-get_handshake_context({Messages, _}) ->
- get_handshake_context(Messages);
-get_handshake_context([H|T]) when is_binary(H) ->
- get_handshake_context(T);
-get_handshake_context(L) ->
+get_handshake_context(server, {Messages, _}) ->
+ get_handshake_context_server(Messages);
+get_handshake_context(client, {Messages, _}) ->
+ get_handshake_context_client(Messages).
+
+get_handshake_context_server([H|T]) when is_binary(H) ->
+ get_handshake_context_server(T);
+get_handshake_context_server(L) ->
+ L.
+
+
+get_handshake_context_client([H|T]) when is_list(H) ->
+ get_handshake_context_client(T);
+get_handshake_context_client(L) ->
L.
+%% If the CertificateVerify message is sent by a server, the signature
+%% algorithm MUST be one offered in the client's "signature_algorithms"
+%% extension unless no valid certificate chain can be produced without
+%% unsupported algorithms
+%%
%% If sent by a client, the signature algorithm used in the signature
%% MUST be one of those present in the supported_signature_algorithms
%% field of the "signature_algorithms" extension in the
%% CertificateRequest message.
-verify_signature_algorithm(#state{ssl_options =
- #ssl_options{
- signature_algs = ServerSignAlgs}} = State0,
- #certificate_verify_1_3{algorithm = ClientSignAlg}) ->
- case lists:member(ClientSignAlg, ServerSignAlgs) of
+verify_signature_algorithm(#state{
+ static_env = #static_env{role = Role},
+ ssl_options =
+ #ssl_options{
+ signature_algs = LocalSignAlgs}} = State0,
+ #certificate_verify_1_3{algorithm = PeerSignAlg}) ->
+ case lists:member(PeerSignAlg, LocalSignAlgs) of
true ->
- ok;
+ {ok, maybe_update_selected_sign_alg(State0, PeerSignAlg, Role)};
false ->
State1 = calculate_traffic_secrets(State0),
State = ssl_record:step_encryption_state(State1),
@@ -1098,11 +1526,19 @@ verify_signature_algorithm(#state{ssl_options =
end.
-verify_certificate_verify(#state{connection_states = ConnectionStates,
- handshake_env =
- #handshake_env{
- public_key_info = PublicKeyInfo,
- tls_handshake_history = HHistory}} = State0,
+maybe_update_selected_sign_alg(#state{session = Session} = State, SignAlg, client) ->
+ State#state{session = Session#session{sign_alg = SignAlg}};
+maybe_update_selected_sign_alg(State, _, _) ->
+ State.
+
+
+verify_certificate_verify(#state{
+ static_env = #static_env{role = Role},
+ connection_states = ConnectionStates,
+ handshake_env =
+ #handshake_env{
+ public_key_info = PublicKeyInfo,
+ tls_handshake_history = HHistory}} = State0,
#certificate_verify_1_3{
algorithm = SignatureScheme,
signature = Signature}) ->
@@ -1122,10 +1558,11 @@ verify_certificate_verify(#state{connection_states = ConnectionStates,
PublicKey = get_public_key(PublicKeyInfo),
+ ContextString = peer_context_string(Role),
+
%% Digital signatures use the hash function defined by the selected signature
%% scheme.
- case verify(THash, <<"TLS 1.3, client CertificateVerify">>,
- HashAlgo, Signature, PublicKey) of
+ case verify(THash, ContextString, HashAlgo, Signature, PublicKey) of
{ok, true} ->
{ok, {State0, wait_finished}};
{ok, false} ->
@@ -1139,6 +1576,19 @@ verify_certificate_verify(#state{connection_states = ConnectionStates,
end.
+context_string(server) ->
+ <<"TLS 1.3, server CertificateVerify">>;
+context_string(client) ->
+ <<"TLS 1.3, client CertificateVerify">>.
+
+
+%% Return context string for verifing peer signature
+peer_context_string(server) ->
+ <<"TLS 1.3, client CertificateVerify">>;
+peer_context_string(client) ->
+ <<"TLS 1.3, server CertificateVerify">>.
+
+
%% If there is no overlap between the received
%% "supported_groups" and the groups supported by the server, then the
%% server MUST abort the handshake with a "handshake_failure" or an
@@ -1172,14 +1622,36 @@ select_common_groups(ServerGroups, ClientGroups) ->
%% for groups not listed in the client's "supported_groups" extension.
%% Servers MAY check for violations of these rules and abort the
%% handshake with an "illegal_parameter" alert if one is violated.
-validate_key_share(_ ,[]) ->
+validate_client_key_share(_ ,[]) ->
ok;
-validate_key_share([], _) ->
+validate_client_key_share([], _) ->
{error, illegal_parameter};
-validate_key_share([G|ClientGroups], [{_, G, _}|ClientShares]) ->
- validate_key_share(ClientGroups, ClientShares);
-validate_key_share([_|ClientGroups], [_|_] = ClientShares) ->
- validate_key_share(ClientGroups, ClientShares).
+validate_client_key_share([G|ClientGroups], [{_, G, _}|ClientShares]) ->
+ validate_client_key_share(ClientGroups, ClientShares);
+validate_client_key_share([_|ClientGroups], [_|_] = ClientShares) ->
+ validate_client_key_share(ClientGroups, ClientShares).
+
+
+%% Verify that selected group is offered by the client.
+validate_server_key_share([G|_ClientGroups], {_, G, _}) ->
+ ok;
+validate_server_key_share([_|ClientGroups], {_, _, _} = ServerKeyShare) ->
+ validate_server_key_share(ClientGroups, ServerKeyShare).
+
+
+validate_selected_group(SelectedGroup, [SelectedGroup|_]) ->
+ {error, {illegal_parameter,
+ "Selected group sent by the server shall not correspond to a group"
+ " which was provided in the key_share extension"}};
+validate_selected_group(SelectedGroup, ClientGroups) ->
+ case lists:member(SelectedGroup, ClientGroups) of
+ true ->
+ ok;
+ false ->
+ {error, {illegal_parameter,
+ "Selected group sent by the server shall correspond to a group"
+ " which was provided in the supported_groups extension"}}
+ end.
get_client_public_key([Group|_] = Groups, ClientShares) ->
@@ -1197,20 +1669,50 @@ get_client_public_key([Group|Groups], ClientShares, PreferredGroup) ->
get_client_public_key(Groups, ClientShares, PreferredGroup)
end.
+get_client_private_key([Group|_] = Groups, ClientShares) ->
+ get_client_private_key(Groups, ClientShares, Group).
+%%
+get_client_private_key(_, [], PreferredGroup) ->
+ {PreferredGroup, no_suitable_key};
+get_client_private_key([], _, PreferredGroup) ->
+ {PreferredGroup, no_suitable_key};
+get_client_private_key([Group|Groups], ClientShares, PreferredGroup) ->
+ case lists:keysearch(Group, 2, ClientShares) of
+ {value, {_, _, {_, ClientPrivateKey}}} ->
+ {Group, ClientPrivateKey};
+ {value, {_, _, #'ECPrivateKey'{} = ClientPrivateKey}} ->
+ {Group, ClientPrivateKey};
+ false ->
+ get_client_private_key(Groups, ClientShares, PreferredGroup)
+ end.
+
+
+get_server_public_key({key_share_entry, Group, PublicKey}) ->
+ {Group, PublicKey}.
+
+
+%% RFC 7301 - Application-Layer Protocol Negotiation Extension
+%% It is expected that a server will have a list of protocols that it
+%% supports, in preference order, and will only select a protocol if the
+%% client supports it. In that case, the server SHOULD select the most
+%% highly preferred protocol that it supports and that is also
+%% advertised by the client. In the event that the server supports no
+%% protocols that the client advertises, then the server SHALL respond
+%% with a fatal "no_application_protocol" alert.
+handle_alpn(undefined, _) ->
+ {ok, undefined};
+handle_alpn([], _) ->
+ {error, no_application_protocol};
+handle_alpn([_|_], undefined) ->
+ {ok, undefined};
+handle_alpn([ServerProtocol|T], ClientProtocols) ->
+ case lists:member(ServerProtocol, ClientProtocols) of
+ true ->
+ {ok, ServerProtocol};
+ false ->
+ handle_alpn(T, ClientProtocols)
+ end.
-%% get_client_public_key(Group, ClientShares) ->
-%% case lists:keysearch(Group, 2, ClientShares) of
-%% {value, {_, _, ClientPublicKey}} ->
-%% ClientPublicKey;
-%% false ->
-%% %% 4.1.4. Hello Retry Request
-%% %%
-%% %% The server will send this message in response to a ClientHello
-%% %% message if it is able to find an acceptable set of parameters but the
-%% %% ClientHello does not contain sufficient information to proceed with
-%% %% the handshake.
-%% no_suitable_key
-%% end.
select_cipher_suite([], _) ->
{error, no_suitable_cipher};
@@ -1223,6 +1725,19 @@ select_cipher_suite([Cipher|ClientCiphers], ServerCiphers) ->
select_cipher_suite(ClientCiphers, ServerCiphers)
end.
+
+%% RFC 8446 4.1.3 ServerHello
+%% A client which receives a cipher suite that was not offered MUST abort the
+%% handshake with an "illegal_parameter" alert.
+validate_cipher_suite(Cipher, ClientCiphers) ->
+ case lists:member(Cipher, ClientCiphers) of
+ true ->
+ ok;
+ false ->
+ {error, illegal_parameter}
+ end.
+
+
%% RFC 8446 (TLS 1.3)
%% TLS 1.3 provides two extensions for indicating which signature
%% algorithms may be used in digital signatures. The
@@ -1331,7 +1846,12 @@ get_supported_groups(#supported_groups{supported_groups = Groups}) ->
Groups.
get_key_shares(#key_share_client_hello{client_shares = ClientShares}) ->
- ClientShares.
+ ClientShares;
+get_key_shares(#key_share_server_hello{server_share = ServerShare}) ->
+ ServerShare.
+
+get_selected_group(#key_share_hello_retry_request{selected_group = SelectedGroup}) ->
+ SelectedGroup.
maybe() ->
Ref = erlang:make_ref(),
diff --git a/lib/ssl/test/ssl_basic_SUITE.erl b/lib/ssl/test/ssl_basic_SUITE.erl
index 785ea98fa0..ce4479020e 100644
--- a/lib/ssl/test/ssl_basic_SUITE.erl
+++ b/lib/ssl/test/ssl_basic_SUITE.erl
@@ -250,17 +250,33 @@ tls13_test_group() ->
tls13_finished_verify_data,
tls13_1_RTT_handshake,
tls13_basic_ssl_server_openssl_client,
+ tls13_basic_ssl_server_ssl_client,
+ tls13_basic_openssl_server_ssl_client,
tls13_custom_groups_ssl_server_openssl_client,
+ tls13_custom_groups_ssl_server_ssl_client,
tls13_hello_retry_request_ssl_server_openssl_client,
+ tls13_hello_retry_request_ssl_server_ssl_client,
tls13_client_auth_empty_cert_alert_ssl_server_openssl_client,
+ tls13_client_auth_empty_cert_alert_ssl_server_ssl_client,
tls13_client_auth_empty_cert_ssl_server_openssl_client,
+ tls13_client_auth_empty_cert_ssl_server_ssl_client,
tls13_client_auth_ssl_server_openssl_client,
+ tls13_client_auth_ssl_server_ssl_client,
tls13_hrr_client_auth_empty_cert_alert_ssl_server_openssl_client,
+ tls13_hrr_client_auth_empty_cert_alert_ssl_server_ssl_client,
tls13_hrr_client_auth_empty_cert_ssl_server_openssl_client,
+ tls13_hrr_client_auth_empty_cert_ssl_server_ssl_client,
tls13_hrr_client_auth_ssl_server_openssl_client,
+ tls13_hrr_client_auth_ssl_server_ssl_client,
tls13_unsupported_sign_algo_client_auth_ssl_server_openssl_client,
+ tls13_unsupported_sign_algo_client_auth_ssl_server_ssl_client,
tls13_unsupported_sign_algo_cert_client_auth_ssl_server_openssl_client,
- tls13_connection_information].
+ tls13_unsupported_sign_algo_cert_client_auth_ssl_server_ssl_client,
+ tls13_connection_information,
+ tls13_ssl_server_with_alpn_ssl_client,
+ tls13_ssl_server_with_alpn_ssl_client_empty_alpn,
+ tls13_ssl_server_with_alpn_ssl_client_bad_alpn,
+ tls13_ssl_server_with_alpn_ssl_client_alpn].
%%--------------------------------------------------------------------
init_per_suite(Config0) ->
@@ -5373,6 +5389,80 @@ tls13_basic_ssl_server_openssl_client(Config) ->
ssl_test_lib:close(Server),
ssl_test_lib:close_port(Client).
+tls13_basic_ssl_server_ssl_client() ->
+ [{doc,"Test TLS 1.3 basic connection between ssl server and ssl client"}].
+
+tls13_basic_ssl_server_ssl_client(Config) ->
+ ClientOpts0 = ssl_test_lib:ssl_options(client_rsa_opts, Config),
+ ServerOpts0 = ssl_test_lib:ssl_options(server_rsa_opts, Config),
+ {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
+
+ %% Set versions
+ ServerOpts = [{versions, ['tlsv1.2','tlsv1.3']}|ServerOpts0],
+ ClientOpts = [{versions, ['tlsv1.2','tlsv1.3']}|ClientOpts0],
+
+ Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0},
+ {from, self()},
+ {mfa, {ssl_test_lib, send_recv_result_active, []}},
+ {options, ServerOpts}]),
+ Port = ssl_test_lib:inet_port(Server),
+
+ Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port},
+ {host, Hostname},
+ {from, self()},
+ {mfa, {ssl_test_lib, send_recv_result_active, []}},
+ {options, ClientOpts}]),
+
+ ssl_test_lib:check_result(Server, ok, Client, ok),
+
+ ssl_test_lib:close(Server),
+ ssl_test_lib:close_port(Client).
+
+
+tls13_basic_openssl_server_ssl_client() ->
+ [{doc,"Test TLS 1.3 basic connection between openssl server and ssl client"}].
+
+tls13_basic_openssl_server_ssl_client(Config) ->
+ process_flag(trap_exit, true),
+ ServerOpts = ssl_test_lib:ssl_options(server_rsa_verify_opts, Config),
+ ClientOpts0 = ssl_test_lib:ssl_options(client_rsa_verify_opts, Config),
+
+ ClientOpts = [{versions, ['tlsv1.2','tlsv1.3']}|ClientOpts0],
+
+ {ClientNode, _, Hostname} = ssl_test_lib:run_where(Config),
+
+ Data = "From openssl to erlang",
+
+ Port = ssl_test_lib:inet_port(node()),
+ CertFile = proplists:get_value(certfile, ServerOpts),
+ CaCertFile = proplists:get_value(cacertfile, ServerOpts),
+ KeyFile = proplists:get_value(keyfile, ServerOpts),
+ Exe = "openssl",
+ Args = ["s_server", "-accept", integer_to_list(Port),
+ "-tls1_3",
+ "-cert", CertFile, "-CAfile", CaCertFile,
+ "-key", KeyFile, "-Verify", "2"],
+
+ OpensslPort = ssl_test_lib:portable_open_port(Exe, Args),
+
+ ssl_test_lib:wait_for_openssl_server(Port, tls),
+
+ Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port},
+ {host, Hostname},
+ {from, self()},
+ {mfa, {?MODULE,
+ erlang_ssl_receive, [Data]}},
+ {options, ClientOpts}]),
+ true = port_command(OpensslPort, Data),
+
+ ssl_test_lib:check_result(Client, ok),
+
+ %% Clean close down! Server needs to be closed first !!
+ ssl_test_lib:close_port(OpensslPort),
+ ssl_test_lib:close(Client),
+ process_flag(trap_exit, false).
+
+
tls13_custom_groups_ssl_server_openssl_client() ->
[{doc,"Test that ssl server can select a common group for key-exchange"}].
@@ -5397,6 +5487,39 @@ tls13_custom_groups_ssl_server_openssl_client(Config) ->
ssl_test_lib:close(Server),
ssl_test_lib:close_port(Client).
+
+tls13_custom_groups_ssl_server_ssl_client() ->
+ [{doc,"Test that ssl server can select a common group for key-exchange"}].
+
+tls13_custom_groups_ssl_server_ssl_client(Config) ->
+ ClientOpts0 = ssl_test_lib:ssl_options(client_rsa_opts, Config),
+ ServerOpts0 = ssl_test_lib:ssl_options(server_rsa_opts, Config),
+
+ %% Set versions
+ ServerOpts = [{versions, ['tlsv1.2','tlsv1.3']},
+ {supported_groups, [x448, secp256r1, secp384r1]}|ServerOpts0],
+ ClientOpts1 = [{versions, ['tlsv1.2','tlsv1.3']}|ClientOpts0],
+ {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
+
+ Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0},
+ {from, self()},
+ {mfa, {ssl_test_lib, send_recv_result_active, []}},
+ {options, ServerOpts}]),
+ Port = ssl_test_lib:inet_port(Server),
+
+ ClientOpts = [{supported_groups,[secp384r1, secp256r1, x25519]}|ClientOpts1],
+
+ Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port},
+ {host, Hostname},
+ {from, self()},
+ {mfa, {ssl_test_lib, send_recv_result_active, []}},
+ {options, ClientOpts}]),
+
+ ssl_test_lib:check_result(Server, ok, Client, ok),
+ ssl_test_lib:close(Server),
+ ssl_test_lib:close_port(Client).
+
+
tls13_hello_retry_request_ssl_server_openssl_client() ->
[{doc,"Test that ssl server can request a new group when the client's first key share"
"is not supported"}].
@@ -5422,6 +5545,38 @@ tls13_hello_retry_request_ssl_server_openssl_client(Config) ->
ssl_test_lib:close(Server),
ssl_test_lib:close_port(Client).
+
+tls13_hello_retry_request_ssl_server_ssl_client() ->
+ [{doc,"Test that ssl server can request a new group when the client's first key share"
+ "is not supported"}].
+
+tls13_hello_retry_request_ssl_server_ssl_client(Config) ->
+ ClientOpts0 = ssl_test_lib:ssl_options(client_rsa_opts, Config),
+ ServerOpts0 = ssl_test_lib:ssl_options(server_rsa_opts, Config),
+ %% Set versions
+ ServerOpts = [{versions, ['tlsv1.2','tlsv1.3']},
+ {supported_groups, [x448, x25519]}|ServerOpts0],
+ ClientOpts = [{versions, ['tlsv1.2','tlsv1.3']},
+ {supported_groups, [secp256r1, x25519]}|ClientOpts0],
+ {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
+
+ Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0},
+ {from, self()},
+ {mfa, {ssl_test_lib, send_recv_result_active, []}},
+ {options, ServerOpts}]),
+ Port = ssl_test_lib:inet_port(Server),
+
+ Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port},
+ {host, Hostname},
+ {from, self()},
+ {mfa, {ssl_test_lib, send_recv_result_active, []}},
+ {options, ClientOpts}]),
+
+
+ ssl_test_lib:check_result(Server, ok, Client, ok),
+ ssl_test_lib:close(Server),
+ ssl_test_lib:close_port(Client).
+
tls13_client_auth_empty_cert_alert_ssl_server_openssl_client() ->
[{doc,"TLS 1.3: Test client authentication when client sends an empty certificate and fail_if_no_peer_cert is set to true."}].
@@ -5446,14 +5601,45 @@ tls13_client_auth_empty_cert_alert_ssl_server_openssl_client(Config) ->
Client = ssl_test_lib:start_basic_client(openssl, 'tlsv1.3', Port, ClientOpts),
- ssl_test_lib:check_result(Server,
- {error,
- {tls_alert,
- {certificate_required,
- "received SERVER ALERT: Fatal - Certificate required - certificate_required"}}}),
+ ssl_test_lib:check_server_alert(Server, certificate_required),
+ ssl_test_lib:close(Server),
+ ssl_test_lib:close_port(Client).
+
+
+tls13_client_auth_empty_cert_alert_ssl_server_ssl_client() ->
+ [{doc,"TLS 1.3: Test client authentication when client sends an empty certificate and fail_if_no_peer_cert is set to true."}].
+
+tls13_client_auth_empty_cert_alert_ssl_server_ssl_client(Config) ->
+ ClientOpts0 = ssl_test_lib:ssl_options(client_rsa_opts, Config),
+ %% Delete Client Cert and Key
+ ClientOpts1 = proplists:delete(certfile, ClientOpts0),
+ ClientOpts2 = proplists:delete(keyfile, ClientOpts1),
+
+ ServerOpts0 = ssl_test_lib:ssl_options(server_rsa_opts, Config),
+ %% Set versions
+ ServerOpts = [{versions, ['tlsv1.2','tlsv1.3']},
+ {verify, verify_peer},
+ {fail_if_no_peer_cert, true}|ServerOpts0],
+ ClientOpts = [{versions, ['tlsv1.2','tlsv1.3']}|ClientOpts2],
+ {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
+
+ Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0},
+ {from, self()},
+ {mfa, {ssl_test_lib, send_recv_result_active, []}},
+ {options, ServerOpts}]),
+ Port = ssl_test_lib:inet_port(Server),
+
+ Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port},
+ {host, Hostname},
+ {from, self()},
+ {mfa, {ssl_test_lib, send_recv_result_active, []}},
+ {options, ClientOpts}]),
+
+ ssl_test_lib:check_server_alert(Server, certificate_required),
ssl_test_lib:close(Server),
ssl_test_lib:close_port(Client).
+
tls13_client_auth_empty_cert_ssl_server_openssl_client() ->
[{doc,"TLS 1.3: Test client authentication when client sends an empty certificate and fail_if_no_peer_cert is set to false."}].
@@ -5483,13 +5669,47 @@ tls13_client_auth_empty_cert_ssl_server_openssl_client(Config) ->
ssl_test_lib:close_port(Client).
+tls13_client_auth_empty_cert_ssl_server_ssl_client() ->
+ [{doc,"TLS 1.3: Test client authentication when client sends an empty certificate and fail_if_no_peer_cert is set to false."}].
+
+tls13_client_auth_empty_cert_ssl_server_ssl_client(Config) ->
+ ClientOpts0 = ssl_test_lib:ssl_options(client_rsa_opts, Config),
+ %% Delete Client Cert and Key
+ ClientOpts1 = proplists:delete(certfile, ClientOpts0),
+ ClientOpts2 = proplists:delete(keyfile, ClientOpts1),
+
+ ServerOpts0 = ssl_test_lib:ssl_options(server_rsa_opts, Config),
+ %% Set versions
+ ServerOpts = [{versions, ['tlsv1.2','tlsv1.3']},
+ {verify, verify_peer},
+ {fail_if_no_peer_cert, false}|ServerOpts0],
+ ClientOpts = [{versions, ['tlsv1.2','tlsv1.3']}|ClientOpts2],
+ {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
+
+ Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0},
+ {from, self()},
+ {mfa, {ssl_test_lib, send_recv_result_active, []}},
+ {options, ServerOpts}]),
+ Port = ssl_test_lib:inet_port(Server),
+
+ Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port},
+ {host, Hostname},
+ {from, self()},
+ {mfa, {ssl_test_lib, send_recv_result_active, []}},
+ {options, ClientOpts}]),
+
+ ssl_test_lib:check_result(Server, ok, Client, ok),
+ ssl_test_lib:close(Server),
+ ssl_test_lib:close_port(Client).
+
+
tls13_client_auth_ssl_server_openssl_client() ->
[{doc,"TLS 1.3: Test client authentication."}].
tls13_client_auth_ssl_server_openssl_client(Config) ->
ClientOpts = ssl_test_lib:ssl_options(client_rsa_opts, Config),
-
ServerOpts0 = ssl_test_lib:ssl_options(server_rsa_opts, Config),
+
%% Set versions
ServerOpts = [{versions, ['tlsv1.2','tlsv1.3']},
{verify, verify_peer},
@@ -5509,6 +5729,38 @@ tls13_client_auth_ssl_server_openssl_client(Config) ->
ssl_test_lib:close_port(Client).
+tls13_client_auth_ssl_server_ssl_client() ->
+ [{doc,"TLS 1.3: Test client authentication."}].
+
+tls13_client_auth_ssl_server_ssl_client(Config) ->
+ ClientOpts0 = ssl_test_lib:ssl_options(client_rsa_opts, Config),
+ ServerOpts0 = ssl_test_lib:ssl_options(server_rsa_opts, Config),
+
+ %% Set versions
+ ServerOpts = [{versions, ['tlsv1.2','tlsv1.3']},
+ {verify, verify_peer},
+ {fail_if_no_peer_cert, true}|ServerOpts0],
+ ClientOpts = [{versions, ['tlsv1.2','tlsv1.3']}|ClientOpts0],
+ {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
+
+ Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0},
+ {from, self()},
+ {mfa, {ssl_test_lib, send_recv_result_active, []}},
+ {options, ServerOpts}]),
+ Port = ssl_test_lib:inet_port(Server),
+
+ %%Client = ssl_test_lib:start_basic_client(openssl, 'tlsv1.3', Port, ClientOpts),
+ Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port},
+ {host, Hostname},
+ {from, self()},
+ {mfa, {ssl_test_lib, send_recv_result_active, []}},
+ {options, ClientOpts}]),
+
+ ssl_test_lib:check_result(Server, ok, Client, ok),
+ ssl_test_lib:close(Server),
+ ssl_test_lib:close_port(Client).
+
+
tls13_hrr_client_auth_empty_cert_alert_ssl_server_openssl_client() ->
[{doc,"TLS 1.3 (HelloRetryRequest): Test client authentication when client sends an empty certificate and fail_if_no_peer_cert is set to true."}].
@@ -5535,11 +5787,43 @@ tls13_hrr_client_auth_empty_cert_alert_ssl_server_openssl_client(Config) ->
Client = ssl_test_lib:start_basic_client(openssl, 'tlsv1.3', Port, ClientOpts),
- ssl_test_lib:check_result(Server,
- {error,
- {tls_alert,
- {certificate_required,
- "received SERVER ALERT: Fatal - Certificate required - certificate_required"}}}),
+ ssl_test_lib:check_server_alert(Server, certificate_required),
+ ssl_test_lib:close(Server),
+ ssl_test_lib:close_port(Client).
+
+
+tls13_hrr_client_auth_empty_cert_alert_ssl_server_ssl_client() ->
+ [{doc,"TLS 1.3 (HelloRetryRequest): Test client authentication when client sends an empty certificate and fail_if_no_peer_cert is set to true."}].
+
+tls13_hrr_client_auth_empty_cert_alert_ssl_server_ssl_client(Config) ->
+ ClientOpts0 = ssl_test_lib:ssl_options(client_rsa_opts, Config),
+ %% Delete Client Cert and Key
+ ClientOpts1 = proplists:delete(certfile, ClientOpts0),
+ ClientOpts2 = proplists:delete(keyfile, ClientOpts1),
+
+ ServerOpts0 = ssl_test_lib:ssl_options(server_rsa_opts, Config),
+ %% Set versions
+ ServerOpts = [{versions, ['tlsv1.2','tlsv1.3']},
+ {verify, verify_peer},
+ {fail_if_no_peer_cert, true},
+ {supported_groups, [x448, x25519]}|ServerOpts0],
+ ClientOpts = [{versions, ['tlsv1.2','tlsv1.3']},
+ {supported_groups, [secp256r1, x25519]}|ClientOpts2],
+ {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
+
+ Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0},
+ {from, self()},
+ {mfa, {ssl_test_lib, send_recv_result_active, []}},
+ {options, ServerOpts}]),
+ Port = ssl_test_lib:inet_port(Server),
+
+ Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port},
+ {host, Hostname},
+ {from, self()},
+ {mfa, {ssl_test_lib, send_recv_result_active, []}},
+ {options, ClientOpts}]),
+
+ ssl_test_lib:check_server_alert(Server, certificate_required),
ssl_test_lib:close(Server),
ssl_test_lib:close_port(Client).
@@ -5575,6 +5859,42 @@ tls13_hrr_client_auth_empty_cert_ssl_server_openssl_client(Config) ->
ssl_test_lib:close_port(Client).
+tls13_hrr_client_auth_empty_cert_ssl_server_ssl_client() ->
+ [{doc,"TLS 1.3 (HelloRetryRequest): Test client authentication when client sends an empty certificate and fail_if_no_peer_cert is set to false."}].
+
+tls13_hrr_client_auth_empty_cert_ssl_server_ssl_client(Config) ->
+ ClientOpts0 = ssl_test_lib:ssl_options(client_rsa_opts, Config),
+ %% Delete Client Cert and Key
+ ClientOpts1 = proplists:delete(certfile, ClientOpts0),
+ ClientOpts2 = proplists:delete(keyfile, ClientOpts1),
+
+ ServerOpts0 = ssl_test_lib:ssl_options(server_rsa_opts, Config),
+ %% Set versions
+ ServerOpts = [{versions, ['tlsv1.2','tlsv1.3']},
+ {verify, verify_peer},
+ {fail_if_no_peer_cert, false},
+ {supported_groups, [x448, x25519]}|ServerOpts0],
+ ClientOpts = [{versions, ['tlsv1.2','tlsv1.3']},
+ {supported_groups, [secp256r1, x25519]}|ClientOpts2],
+ {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
+
+ Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0},
+ {from, self()},
+ {mfa, {ssl_test_lib, send_recv_result_active, []}},
+ {options, ServerOpts}]),
+ Port = ssl_test_lib:inet_port(Server),
+
+ Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port},
+ {host, Hostname},
+ {from, self()},
+ {mfa, {ssl_test_lib, send_recv_result_active, []}},
+ {options, ClientOpts}]),
+
+ ssl_test_lib:check_result(Server, ok, Client, ok),
+ ssl_test_lib:close(Server),
+ ssl_test_lib:close_port(Client).
+
+
tls13_hrr_client_auth_ssl_server_openssl_client() ->
[{doc,"TLS 1.3 (HelloRetryRequest): Test client authentication."}].
@@ -5603,6 +5923,39 @@ tls13_hrr_client_auth_ssl_server_openssl_client(Config) ->
ssl_test_lib:close_port(Client).
+tls13_hrr_client_auth_ssl_server_ssl_client() ->
+ [{doc,"TLS 1.3 (HelloRetryRequest): Test client authentication."}].
+
+tls13_hrr_client_auth_ssl_server_ssl_client(Config) ->
+ ClientOpts0 = ssl_test_lib:ssl_options(client_rsa_opts, Config),
+
+ ServerOpts0 = ssl_test_lib:ssl_options(server_rsa_opts, Config),
+ %% Set versions
+ ServerOpts = [{versions, ['tlsv1.2','tlsv1.3']},
+ {verify, verify_peer},
+ {fail_if_no_peer_cert, true},
+ {supported_groups, [x448, x25519]}|ServerOpts0],
+ ClientOpts = [{versions, ['tlsv1.2','tlsv1.3']},
+ {supported_groups, [secp256r1, x25519]}|ClientOpts0],
+ {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
+
+ Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0},
+ {from, self()},
+ {mfa, {ssl_test_lib, send_recv_result_active, []}},
+ {options, ServerOpts}]),
+ Port = ssl_test_lib:inet_port(Server),
+
+ Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port},
+ {host, Hostname},
+ {from, self()},
+ {mfa, {ssl_test_lib, send_recv_result_active, []}},
+ {options, ClientOpts}]),
+
+ ssl_test_lib:check_result(Server, ok, Client, ok),
+ ssl_test_lib:close(Server),
+ ssl_test_lib:close_port(Client).
+
+
tls13_unsupported_sign_algo_client_auth_ssl_server_openssl_client() ->
[{doc,"TLS 1.3: Test client authentication with unsupported signature_algorithm"}].
@@ -5626,20 +5979,48 @@ tls13_unsupported_sign_algo_client_auth_ssl_server_openssl_client(Config) ->
Client = ssl_test_lib:start_basic_client(openssl, 'tlsv1.3', Port, ClientOpts),
- ssl_test_lib:check_result(
- Server,
- {error,
- {tls_alert,
- {insufficient_security,
- "received SERVER ALERT: Fatal - Insufficient Security - "
- "\"No suitable signature algorithm\""}}}),
+ ssl_test_lib:check_server_alert(Server, insufficient_security),
+ ssl_test_lib:close(Server),
+ ssl_test_lib:close_port(Client).
+
+
+tls13_unsupported_sign_algo_client_auth_ssl_server_ssl_client() ->
+ [{doc,"TLS 1.3: Test client authentication with unsupported signature_algorithm"}].
+
+tls13_unsupported_sign_algo_client_auth_ssl_server_ssl_client(Config) ->
+ ClientOpts0 = ssl_test_lib:ssl_options(client_rsa_opts, Config),
+
+ ServerOpts0 = ssl_test_lib:ssl_options(server_rsa_opts, Config),
+ %% Set versions
+ ServerOpts = [{versions, ['tlsv1.2','tlsv1.3']},
+ {verify, verify_peer},
+ %% Skip rsa_pkcs1_sha256!
+ {signature_algs, [rsa_pkcs1_sha384, rsa_pkcs1_sha512]},
+ {fail_if_no_peer_cert, true}|ServerOpts0],
+ ClientOpts = [{versions, ['tlsv1.2','tlsv1.3']}|ClientOpts0],
+ {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
+
+ Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0},
+ {from, self()},
+ {mfa, {ssl_test_lib, send_recv_result_active, []}},
+ {options, ServerOpts}]),
+ Port = ssl_test_lib:inet_port(Server),
+
+ Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port},
+ {host, Hostname},
+ {from, self()},
+ {mfa, {ssl_test_lib, send_recv_result_active, []}},
+ {options, ClientOpts}]),
+
+ ssl_test_lib:check_server_alert(Server, insufficient_security),
ssl_test_lib:close(Server),
ssl_test_lib:close_port(Client).
-%% Triggers Client Alert as openssl s_client does not have a certificate with a
+%% Triggers a Server Alert as openssl s_client does not have a certificate with a
%% signature algorithm supported by the server (signature_algorithms_cert extension
%% of CertificateRequest does not contain the algorithm of the client certificate).
+%% openssl s_client sends an empty certificate.
tls13_unsupported_sign_algo_cert_client_auth_ssl_server_openssl_client() ->
[{doc,"TLS 1.3: Test client authentication with unsupported signature_algorithm_cert"}].
@@ -5665,12 +6046,46 @@ tls13_unsupported_sign_algo_cert_client_auth_ssl_server_openssl_client(Config) -
Client = ssl_test_lib:start_basic_client(openssl, 'tlsv1.3', Port, ClientOpts),
- ssl_test_lib:check_result(
- Server,
- {error,
- {tls_alert,
- {illegal_parameter,
- "received CLIENT ALERT: Fatal - Illegal Parameter"}}}),
+ ssl_test_lib:check_server_alert(Server, certificate_required),
+ ssl_test_lib:close(Server),
+ ssl_test_lib:close_port(Client).
+
+
+%% Triggers a Server Alert as ssl client does not have a certificate with a
+%% signature algorithm supported by the server (signature_algorithms_cert extension
+%% of CertificateRequest does not contain the algorithm of the client certificate).
+%% ssl client sends an empty certificate.
+tls13_unsupported_sign_algo_cert_client_auth_ssl_server_ssl_client() ->
+ [{doc,"TLS 1.3: Test client authentication with unsupported signature_algorithm_cert"}].
+
+tls13_unsupported_sign_algo_cert_client_auth_ssl_server_ssl_client(Config) ->
+ ClientOpts0 = ssl_test_lib:ssl_options(client_rsa_opts, Config),
+
+ ServerOpts0 = ssl_test_lib:ssl_options(server_rsa_opts, Config),
+ %% Set versions
+ ServerOpts = [{versions, ['tlsv1.2','tlsv1.3']},
+ {log_level, debug},
+ {verify, verify_peer},
+ {signature_algs, [rsa_pkcs1_sha256, rsa_pkcs1_sha384, rsa_pss_rsae_sha256]},
+ %% Skip rsa_pkcs1_sha256!
+ {signature_algs_cert, [rsa_pkcs1_sha384, rsa_pkcs1_sha512]},
+ {fail_if_no_peer_cert, true}|ServerOpts0],
+ ClientOpts = [{versions, ['tlsv1.2','tlsv1.3']}|ClientOpts0],
+ {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
+
+ Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0},
+ {from, self()},
+ {mfa, {ssl_test_lib, send_recv_result_active, []}},
+ {options, ServerOpts}]),
+ Port = ssl_test_lib:inet_port(Server),
+
+ Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port},
+ {host, Hostname},
+ {from, self()},
+ {mfa, {ssl_test_lib, send_recv_result_active, []}},
+ {options, ClientOpts}]),
+
+ ssl_test_lib:check_server_alert(Server, certificate_required),
ssl_test_lib:close(Server),
ssl_test_lib:close_port(Client).
@@ -5698,6 +6113,132 @@ tls13_connection_information(Config) ->
ssl_test_lib:close_port(Client).
+tls13_ssl_server_with_alpn_ssl_client() ->
+ [{doc,"Test TLS 1.3 between ssl server with ALPN configured and ssl client"}].
+
+tls13_ssl_server_with_alpn_ssl_client(Config) ->
+ ClientOpts0 = ssl_test_lib:ssl_options(client_rsa_opts, Config),
+ ServerOpts0 = ssl_test_lib:ssl_options(server_rsa_opts, Config),
+ {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
+
+ %% Set versions
+ ServerOpts = [{versions, ['tlsv1.2','tlsv1.3']},
+ {alpn_preferred_protocols, [<<5,6>>, <<1>>]}|ServerOpts0],
+ ClientOpts = [{versions, ['tlsv1.2','tlsv1.3']}|ClientOpts0],
+
+ Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0},
+ {from, self()},
+ {mfa, {ssl_test_lib, send_recv_result_active, []}},
+ {options, ServerOpts}]),
+ Port = ssl_test_lib:inet_port(Server),
+
+ Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port},
+ {host, Hostname},
+ {from, self()},
+ {mfa, {ssl_test_lib, send_recv_result_active, []}},
+ {options, ClientOpts}]),
+
+ ssl_test_lib:check_result(Server, ok, Client, ok),
+
+ ssl_test_lib:close(Server),
+ ssl_test_lib:close_port(Client).
+
+
+tls13_ssl_server_with_alpn_ssl_client_empty_alpn() ->
+ [{doc,"Test TLS 1.3 between ssl server with ALPN configured and ssl client with empty ALPN"}].
+
+tls13_ssl_server_with_alpn_ssl_client_empty_alpn(Config) ->
+ ClientOpts0 = ssl_test_lib:ssl_options(client_rsa_opts, Config),
+ ServerOpts0 = ssl_test_lib:ssl_options(server_rsa_opts, Config),
+ {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
+
+ %% Set versions
+ ServerOpts = [{versions, ['tlsv1.2','tlsv1.3']},
+ {alpn_preferred_protocols, [<<5,6>>, <<1>>]}|ServerOpts0],
+ ClientOpts = [{versions, ['tlsv1.2','tlsv1.3']},
+ {alpn_advertised_protocols, []}|ClientOpts0],
+
+ Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0},
+ {from, self()},
+ {mfa, {ssl_test_lib, send_recv_result_active, []}},
+ {options, ServerOpts}]),
+ Port = ssl_test_lib:inet_port(Server),
+
+ Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port},
+ {host, Hostname},
+ {from, self()},
+ {mfa, {ssl_test_lib, send_recv_result_active, []}},
+ {options, ClientOpts}]),
+
+ ssl_test_lib:check_server_alert(Server, no_application_protocol),
+
+ ssl_test_lib:close(Server),
+ ssl_test_lib:close_port(Client).
+
+
+tls13_ssl_server_with_alpn_ssl_client_bad_alpn() ->
+ [{doc,"Test TLS 1.3 between ssl server with ALPN configured and ssl client with bad ALPN"}].
+
+tls13_ssl_server_with_alpn_ssl_client_bad_alpn(Config) ->
+ ClientOpts0 = ssl_test_lib:ssl_options(client_rsa_opts, Config),
+ ServerOpts0 = ssl_test_lib:ssl_options(server_rsa_opts, Config),
+ {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
+
+ %% Set versions
+ ServerOpts = [{versions, ['tlsv1.2','tlsv1.3']},
+ {alpn_preferred_protocols, [<<5,6>>, <<1>>]}|ServerOpts0],
+ ClientOpts = [{versions, ['tlsv1.2','tlsv1.3']},
+ {alpn_advertised_protocols, [<<1,2,3,4>>]}|ClientOpts0],
+
+ Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0},
+ {from, self()},
+ {mfa, {ssl_test_lib, send_recv_result_active, []}},
+ {options, ServerOpts}]),
+ Port = ssl_test_lib:inet_port(Server),
+
+ Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port},
+ {host, Hostname},
+ {from, self()},
+ {mfa, {ssl_test_lib, send_recv_result_active, []}},
+ {options, ClientOpts}]),
+
+ ssl_test_lib:check_server_alert(Server, no_application_protocol),
+
+ ssl_test_lib:close(Server),
+ ssl_test_lib:close_port(Client).
+
+tls13_ssl_server_with_alpn_ssl_client_alpn() ->
+ [{doc,"Test TLS 1.3 between ssl server with ALPN configured and ssl client with correct ALPN"}].
+
+tls13_ssl_server_with_alpn_ssl_client_alpn(Config) ->
+ ClientOpts0 = ssl_test_lib:ssl_options(client_rsa_opts, Config),
+ ServerOpts0 = ssl_test_lib:ssl_options(server_rsa_opts, Config),
+ {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
+
+ %% Set versions
+ ServerOpts = [{versions, ['tlsv1.2','tlsv1.3']},
+ {alpn_preferred_protocols, [<<5,6>>, <<1>>]}|ServerOpts0],
+ ClientOpts = [{versions, ['tlsv1.2','tlsv1.3']},
+ {alpn_advertised_protocols, [<<1,2,3,4>>, <<5,6>>]}|ClientOpts0],
+
+ Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0},
+ {from, self()},
+ {mfa, {ssl_test_lib, send_recv_result_active, []}},
+ {options, ServerOpts}]),
+ Port = ssl_test_lib:inet_port(Server),
+
+ Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port},
+ {host, Hostname},
+ {from, self()},
+ {mfa, {ssl_test_lib, send_recv_result_active, []}},
+ {options, ClientOpts}]),
+
+ ssl_test_lib:check_result(Server, ok, Client, ok),
+
+ ssl_test_lib:close(Server),
+ ssl_test_lib:close_port(Client).
+
+
%%--------------------------------------------------------------------
%% Internal functions ------------------------------------------------
%%--------------------------------------------------------------------
diff --git a/lib/ssl/test/ssl_certificate_verify_SUITE.erl b/lib/ssl/test/ssl_certificate_verify_SUITE.erl
index 55dee9a48f..c6982bb928 100644
--- a/lib/ssl/test/ssl_certificate_verify_SUITE.erl
+++ b/lib/ssl/test/ssl_certificate_verify_SUITE.erl
@@ -40,6 +40,7 @@
%%--------------------------------------------------------------------
all() ->
[
+ {group, 'tlsv1.3'},
{group, 'tlsv1.2'},
{group, 'tlsv1.1'},
{group, 'tlsv1'},
@@ -50,6 +51,7 @@ all() ->
groups() ->
[
+ {'tlsv1.3', [], all_protocol_groups()},
{'tlsv1.2', [], all_protocol_groups()},
{'tlsv1.1', [], all_protocol_groups()},
{'tlsv1', [], all_protocol_groups()},
@@ -300,7 +302,13 @@ server_require_peer_cert_fail(Config) when is_list(Config) ->
{from, self()},
{options, [{active, Active} | BadClientOpts]}]),
- ssl_test_lib:check_server_alert(Server, Client, handshake_failure).
+ Version = proplists:get_value(version,Config),
+ case Version of
+ 'tlsv1.3' ->
+ ssl_test_lib:check_server_alert(Server, Client, certificate_required);
+ _ ->
+ ssl_test_lib:check_server_alert(Server, Client, handshake_failure)
+ end.
%%--------------------------------------------------------------------
server_require_peer_cert_empty_ok() ->
@@ -853,6 +861,7 @@ invalid_signature_server(Config) when is_list(Config) ->
{from, self()},
{options, [{verify, verify_peer} | ClientOpts]}]),
ssl_test_lib:check_server_alert(Server, Client, unknown_ca).
+
%%--------------------------------------------------------------------
invalid_signature_client() ->
diff --git a/lib/ssl/test/ssl_test_lib.erl b/lib/ssl/test/ssl_test_lib.erl
index 832f8494c6..15f6a04862 100644
--- a/lib/ssl/test/ssl_test_lib.erl
+++ b/lib/ssl/test/ssl_test_lib.erl
@@ -428,41 +428,42 @@ check_result(Pid, Msg) ->
{got, Unexpected}},
ct:fail(Reason)
end.
+
check_server_alert(Pid, Alert) ->
receive
{Pid, {error, {tls_alert, {Alert, STxt}}}} ->
check_server_txt(STxt),
+ ok;
+ {Pid, {error, closed}} ->
ok
end.
check_server_alert(Server, Client, Alert) ->
receive
{Server, {error, {tls_alert, {Alert, STxt}}}} ->
check_server_txt(STxt),
- receive
- {Client, {error, {tls_alert, {Alert, CTxt}}}} ->
- check_client_txt(CTxt),
- ok;
- {Client, {error, closed}} ->
- ok
- end
+ check_client_alert(Client, Alert)
end.
check_client_alert(Pid, Alert) ->
receive
{Pid, {error, {tls_alert, {Alert, CTxt}}}} ->
check_client_txt(CTxt),
+ ok;
+ {Pid, {ssl_error, _, {tls_alert, {Alert, CTxt}}}} ->
+ check_client_txt(CTxt),
+ ok;
+ {Pid, {error, closed}} ->
ok
end.
check_client_alert(Server, Client, Alert) ->
receive
{Client, {error, {tls_alert, {Alert, CTxt}}}} ->
check_client_txt(CTxt),
- receive
- {Server, {error, {tls_alert, {Alert, STxt}}}} ->
- check_server_txt(STxt),
- ok;
- {Server, {error, closed}} ->
- ok
- end
+ check_server_alert(Server, Alert);
+ {Client, {ssl_error, _, {tls_alert, {Alert, CTxt}}}} ->
+ check_client_txt(CTxt),
+ ok;
+ {Client, {error, closed}} ->
+ ok
end.
check_server_txt("TLS server" ++ _) ->
ok;
@@ -1103,7 +1104,15 @@ run_client_error(Opts) ->
Options = proplists:get_value(options, Opts),
ct:log("~p:~p~nssl:connect(~p, ~p, ~p)~n", [?MODULE,?LINE, Host, Port, Options]),
Error = Transport:connect(Host, Port, Options),
- Pid ! {self(), Error}.
+ case Error of
+ {error, {tls_alert, _}} ->
+ Pid ! {self(), Error};
+ {ok, _Socket} ->
+ receive
+ {ssl_error, _, {tls_alert, _}} = SslError ->
+ Pid ! {self(), SslError}
+ end
+ end.
accepters(N) ->
accepters([], N).
@@ -1642,6 +1651,8 @@ is_tls_version('dtlsv1.2') ->
true;
is_tls_version('dtlsv1') ->
true;
+is_tls_version('tlsv1.3') ->
+ true;
is_tls_version('tlsv1.2') ->
true;
is_tls_version('tlsv1.1') ->
diff --git a/lib/stdlib/doc/src/binary.xml b/lib/stdlib/doc/src/binary.xml
index f3d4edd30f..fd991f258b 100644
--- a/lib/stdlib/doc/src/binary.xml
+++ b/lib/stdlib/doc/src/binary.xml
@@ -505,15 +505,16 @@ store(Binary, GBSet) ->
&lt;&lt;1,1,1,1,1 ...
2> byte_size(A).
100
-3> binary:referenced_byte_size(A)
+3> binary:referenced_byte_size(A).
100
-4> &lt;&lt;_:10/binary,B:10/binary,_/binary&gt;&gt; = A.
+4> &lt;&lt;B:10/binary, C:90/binary&gt;&gt; = A.
&lt;&lt;1,1,1,1,1 ...
-5> byte_size(B).
-10
-6> binary:referenced_byte_size(B)
-100</code>
-
+5> {byte_size(B), binary:referenced_byte_size(B)}.
+{10,10}
+6> {byte_size(C), binary:referenced_byte_size(C)}.
+{90,100}</code>
+ <p>In the above example, the small binary <c>B</c> was copied while the
+ larger binary <c>C</c> references binary <c>A</c>.</p>
<note>
<p>Binary data is shared among processes. If another process
still references the larger binary, copying the part this
diff --git a/lib/stdlib/doc/src/gen_statem.xml b/lib/stdlib/doc/src/gen_statem.xml
index 6f6849a19d..ef548ad643 100644
--- a/lib/stdlib/doc/src/gen_statem.xml
+++ b/lib/stdlib/doc/src/gen_statem.xml
@@ -40,7 +40,7 @@
<p>
This reference manual describes types generated from the types
in the <c>gen_statem</c> source code, so they are correct.
- However, the generated descriptions also reflect the type hiearchy,
+ However, the generated descriptions also reflect the type hierarchy,
which makes them kind of hard to read.
</p>
<p>
diff --git a/lib/stdlib/doc/src/notes.xml b/lib/stdlib/doc/src/notes.xml
index 092056ffde..5c07dd2ee6 100644
--- a/lib/stdlib/doc/src/notes.xml
+++ b/lib/stdlib/doc/src/notes.xml
@@ -306,6 +306,23 @@
</section>
+<section><title>STDLIB 3.8.2.1</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p> Fix a bug that could cause a failure when formatting
+ binaries using the control sequences <c>p</c> or <c>P</c>
+ and limiting the output with the option
+ <c>chars_limit</c>. </p>
+ <p>
+ Own Id: OTP-15847 Aux Id: ERL-957 </p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
<section><title>STDLIB 3.8.2</title>
<section><title>Fixed Bugs and Malfunctions</title>
diff --git a/lib/tools/doc/src/notes.xml b/lib/tools/doc/src/notes.xml
index fd41e2cbeb..000c6e1ce7 100644
--- a/lib/tools/doc/src/notes.xml
+++ b/lib/tools/doc/src/notes.xml
@@ -74,6 +74,21 @@
</section>
+<section><title>Tools 3.1.0.1</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p><c>cover</c> would fail to start if two processes
+ tried to start it at the exact same time.</p>
+ <p>
+ Own Id: OTP-15813 Aux Id: ERL-943 </p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
<section><title>Tools 3.1</title>
<section><title>Fixed Bugs and Malfunctions</title>
diff --git a/lib/tools/src/cover.erl b/lib/tools/src/cover.erl
index 8fe866cb69..2b3af417b6 100644
--- a/lib/tools/src/cover.erl
+++ b/lib/tools/src/cover.erl
@@ -196,6 +196,8 @@ start() ->
receive
{?SERVER,started} ->
{ok,Pid};
+ {?SERVER,{error,Error}} ->
+ {error,Error};
{'DOWN', Ref, _Type, _Object, Info} ->
{error,Info}
end,
@@ -645,19 +647,31 @@ remote_reply(MainNode,Reply) ->
%%%----------------------------------------------------------------------
init_main(Starter) ->
- register(?SERVER,self()),
- ?COVER_MAPPING_TABLE = ets:new(?COVER_MAPPING_TABLE,
- [ordered_set, public, named_table]),
- ?COVER_CLAUSE_TABLE = ets:new(?COVER_CLAUSE_TABLE, [set, public,
- named_table]),
- ?BINARY_TABLE = ets:new(?BINARY_TABLE, [set, public, named_table]),
- ?COLLECTION_TABLE = ets:new(?COLLECTION_TABLE, [set, public,
- named_table]),
- ?COLLECTION_CLAUSE_TABLE = ets:new(?COLLECTION_CLAUSE_TABLE, [set, public,
- named_table]),
- ok = net_kernel:monitor_nodes(true),
- Starter ! {?SERVER,started},
- main_process_loop(#main_state{}).
+ try register(?SERVER,self()) of
+ true ->
+ ?COVER_MAPPING_TABLE = ets:new(?COVER_MAPPING_TABLE,
+ [ordered_set, public, named_table]),
+ ?COVER_CLAUSE_TABLE = ets:new(?COVER_CLAUSE_TABLE, [set, public,
+ named_table]),
+ ?BINARY_TABLE = ets:new(?BINARY_TABLE, [set, public, named_table]),
+ ?COLLECTION_TABLE = ets:new(?COLLECTION_TABLE, [set, public,
+ named_table]),
+ ?COLLECTION_CLAUSE_TABLE = ets:new(?COLLECTION_CLAUSE_TABLE,
+ [set, public, named_table]),
+ ok = net_kernel:monitor_nodes(true),
+ Starter ! {?SERVER,started},
+ main_process_loop(#main_state{})
+ catch
+ error:badarg ->
+ %% The server's already registered; either report that it's already
+ %% started or try again if it died before we could find its pid.
+ case whereis(?SERVER) of
+ undefined ->
+ init_main(Starter);
+ Pid ->
+ Starter ! {?SERVER, {error, {already_started, Pid}}}
+ end
+ end.
main_process_loop(State) ->
receive
diff --git a/lib/tools/test/cover_SUITE.erl b/lib/tools/test/cover_SUITE.erl
index ee58fd7a10..462767f430 100644
--- a/lib/tools/test/cover_SUITE.erl
+++ b/lib/tools/test/cover_SUITE.erl
@@ -37,7 +37,7 @@ all() ->
dont_reconnect_after_stop, stop_node_after_disconnect,
export_import, otp_5031, otp_6115,
otp_8270, otp_10979_hanging_node, otp_14817,
- local_only],
+ local_only, startup_race],
case whereis(cover_server) of
undefined ->
[coverage,StartStop ++ NoStartStop];
@@ -1775,7 +1775,32 @@ local_only(Config) ->
{ok,Name} = test_server:start_node(?FUNCTION_NAME, slave, []),
{error,local_only} = cover:start([Name]),
test_server:stop_node(Name),
+ ok.
+%% ERL-943; We should not crash on startup when multiple servers race to
+%% register the server name.
+startup_race(Config) when is_list(Config) ->
+ PidRefs = [spawn_monitor(fun() ->
+ case cover:start() of
+ {error, {already_started, _Pid}} ->
+ ok;
+ {ok, _Pid} ->
+ ok
+ end
+ end) || _<- lists:seq(1,8)],
+ startup_race_1(PidRefs).
+
+startup_race_1([{Pid, Ref} | PidRefs]) ->
+ receive
+ {'DOWN', Ref, process, Pid, normal} ->
+ startup_race_1(PidRefs);
+ {'DOWN', Ref, process, Pid, _Other} ->
+ ct:fail("Cover server crashed on startup.")
+ after 5000 ->
+ ct:fail("Timed out.")
+ end;
+startup_race_1([]) ->
+ cover:stop(),
ok.
%%--Auxiliary------------------------------------------------------------
diff --git a/lib/xmerl/doc/src/notes.xml b/lib/xmerl/doc/src/notes.xml
index 37973d0dba..9fb4a430e5 100644
--- a/lib/xmerl/doc/src/notes.xml
+++ b/lib/xmerl/doc/src/notes.xml
@@ -47,6 +47,23 @@
</section>
+<section><title>Xmerl 1.3.20.1</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>
+ <c>xmerl_sax_parser</c> crashed during charset detection
+ when the xml declarations attribute values was missing
+ the closing quotation (&apos; or &quot;).</p>
+ <p>
+ Own Id: OTP-15826</p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
<section><title>Xmerl 1.3.20</title>
<section><title>Fixed Bugs and Malfunctions</title>
diff --git a/lib/xmerl/src/xmerl_sax_parser.erl b/lib/xmerl/src/xmerl_sax_parser.erl
index fe836fd8cd..2767d02552 100644
--- a/lib/xmerl/src/xmerl_sax_parser.erl
+++ b/lib/xmerl/src/xmerl_sax_parser.erl
@@ -369,8 +369,8 @@ parse_eq(_, State) ->
%%----------------------------------------------------------------------
parse_value(<<C, Rest/binary>>, State) when ?is_whitespace(C) ->
parse_value(Rest, State);
-parse_value(<<C, Rest/binary>>, _State) when C == $'; C == $" ->
- parse_value_1(Rest, C, []);
+parse_value(<<C, Rest/binary>>, State) when C == $'; C == $" ->
+ parse_value_1(Rest, C, [], State);
parse_value(_, State) ->
?fatal_error(State, "\', \" or whitespace expected").
@@ -383,10 +383,12 @@ parse_value(_, State) ->
%% Rest = binary()
%% Description: Parsing an attribute value from the stream.
%%----------------------------------------------------------------------
-parse_value_1(<<Stop, Rest/binary>>, Stop, Acc) ->
+parse_value_1(<<Stop, Rest/binary>>, Stop, Acc, _State) ->
{lists:reverse(Acc), Rest};
-parse_value_1(<<C, Rest/binary>>, Stop, Acc) ->
- parse_value_1(Rest, Stop, [C |Acc]).
+parse_value_1(<<C, Rest/binary>>, Stop, Acc, State) ->
+ parse_value_1(Rest, Stop, [C |Acc], State);
+parse_value_1(_, _Stop, _Acc, State) ->
+ ?fatal_error(State, "end of input and no \' or \" found").
%%======================================================================
%% Default functions