diff options
Diffstat (limited to 'lib')
59 files changed, 2132 insertions, 671 deletions
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/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/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/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/src/pubkey_pbe.erl b/lib/public_key/src/pubkey_pbe.erl index e6bcedd1b1..38b5c93521 100644 --- a/lib/public_key/src/pubkey_pbe.erl +++ b/lib/public_key/src/pubkey_pbe.erl @@ -74,7 +74,7 @@ decode(Data, Password,"AES-256-CBC"= Cipher, KeyDevParams) -> %%-------------------------------------------------------------------- --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 +86,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. 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/ssl/doc/src/notes.xml b/lib/ssl/doc/src/notes.xml index b86c9e8798..b0473ff7d7 100644 --- a/lib/ssl/doc/src/notes.xml +++ b/lib/ssl/doc/src/notes.xml @@ -119,6 +119,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..3bd86178c8 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> @@ -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> @@ -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..1e36a0591b 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()} | diff --git a/lib/ssl/src/ssl_alert.erl b/lib/ssl/src/ssl_alert.erl index 06b1b005a5..2d57b72f7b 100644 --- a/lib/ssl/src/ssl_alert.erl +++ b/lib/ssl/src/ssl_alert.erl @@ -32,7 +32,11 @@ -include("ssl_record.hrl"). -include("ssl_internal.hrl"). --export([decode/1, own_alert_txt/1, alert_txt/1, reason_code/2]). +-export([decode/1, + own_alert_txt/1, + alert_txt/1, + alert_txt/4, + reason_code/4]). %%==================================================================== %% Internal application API @@ -48,20 +52,29 @@ decode(Bin) -> decode(Bin, [], 0). %%-------------------------------------------------------------------- -%% -spec reason_code(#alert{}, client | server) -> -%% {tls_alert, unicode:chardata()} | closed. -%-spec reason_code(#alert{}, client | server) -> closed | {essl, string()}. +-spec reason_code(#alert{}, client | server, ProtocolName::string(), StateName::atom()) -> + {tls_alert, {atom(), unicode:chardata()}} | closed. %% %% Description: Returns the error reason that will be returned to the %% user. %%-------------------------------------------------------------------- -reason_code(#alert{description = ?CLOSE_NOTIFY}, _) -> +reason_code(#alert{description = ?CLOSE_NOTIFY}, _, _, _) -> closed; -reason_code(#alert{description = Description, role = Role} = Alert, Role) -> - {tls_alert, {description_atom(Description), own_alert_txt(Alert)}}; -reason_code(#alert{description = Description} = Alert, Role) -> - {tls_alert, {description_atom(Description), alert_txt(Alert#alert{role = Role})}}. +reason_code(#alert{description = Description, role = Role} = Alert, Role, ProtocolName, StateName) -> + Txt = lists:flatten(alert_txt(ProtocolName, Role, StateName, own_alert_txt(Alert))), + {tls_alert, {description_atom(Description), Txt}}; +reason_code(#alert{description = Description} = Alert, Role, ProtocolName, StateName) -> + Txt = lists:flatten(alert_txt(ProtocolName, Role, StateName, alert_txt(Alert))), + {tls_alert, {description_atom(Description), Txt}}. + +%%-------------------------------------------------------------------- +-spec alert_txt(string(), server | client, StateNam::atom(), string()) -> string(). +%% +%% Description: Generates alert text for log or string part of error return. +%%-------------------------------------------------------------------- +alert_txt(ProtocolName, Role, StateName, Txt) -> + io_lib:format("~s ~p: In state ~p ~s\n", [ProtocolName, Role, StateName, Txt]). %%-------------------------------------------------------------------- -spec own_alert_txt(#alert{}) -> string(). diff --git a/lib/ssl/src/ssl_connection.erl b/lib/ssl/src/ssl_connection.erl index a5f754d2e3..cc4d60389e 100644 --- a/lib/ssl/src/ssl_connection.erl +++ b/lib/ssl/src/ssl_connection.erl @@ -124,7 +124,7 @@ handshake(#sslsocket{pid = [Pid|_]} = Socket, Timeout) -> connected -> {ok, Socket}; {ok, Ext} -> - {ok, Socket, Ext}; + {ok, Socket, no_records(Ext)}; Error -> Error end. @@ -328,34 +328,33 @@ prf(ConnectionPid, Secret, Label, Seed, WantedLength) -> %%==================================================================== %% Alert and close handling %%==================================================================== -handle_own_alert(Alert, _, StateName, +handle_own_alert(Alert0, _, StateName, #state{static_env = #static_env{role = Role, protocol_cb = Connection}, ssl_options = SslOpts} = State) -> try %% Try to tell the other side - send_alert(Alert, StateName, State) + send_alert(Alert0, StateName, State) catch _:_ -> %% Can crash if we are in a uninitialized state ignore end, try %% Try to tell the local user - log_alert(SslOpts#ssl_options.log_level, Role, - Connection:protocol_name(), StateName, - Alert#alert{role = Role}), + Alert = Alert0#alert{role = Role}, + log_alert(SslOpts#ssl_options.log_level, Role, Connection:protocol_name(), StateName, Alert), handle_normal_shutdown(Alert,StateName, State) catch _:_ -> ok end, {stop, {shutdown, own_alert}, State}. -handle_normal_shutdown(Alert, _, #state{static_env = #static_env{role = Role, - socket = Socket, - transport_cb = Transport, - protocol_cb = Connection, - tracker = Tracker}, - handshake_env = #handshake_env{renegotiation = {false, first}}, - start_or_recv_from = StartFrom} = State) -> +handle_normal_shutdown(Alert, StateName, #state{static_env = #static_env{role = Role, + socket = Socket, + transport_cb = Transport, + protocol_cb = Connection, + tracker = Tracker}, + handshake_env = #handshake_env{renegotiation = {false, first}}, + start_or_recv_from = StartFrom} = State) -> Pids = Connection:pids(State), - alert_user(Pids, Transport, Tracker,Socket, StartFrom, Alert, Role, Connection); + alert_user(Pids, Transport, Tracker,Socket, StartFrom, Alert, Role, StateName, Connection); handle_normal_shutdown(Alert, StateName, #state{static_env = #static_env{role = Role, socket = Socket, @@ -366,9 +365,9 @@ handle_normal_shutdown(Alert, StateName, #state{static_env = #static_env{role = socket_options = Opts, start_or_recv_from = RecvFrom} = State) -> Pids = Connection:pids(State), - alert_user(Pids, Transport, Tracker, Socket, StateName, Opts, Pid, RecvFrom, Alert, Role, Connection). + alert_user(Pids, Transport, Tracker, Socket, StateName, Opts, Pid, RecvFrom, Alert, Role, StateName, Connection). -handle_alert(#alert{level = ?FATAL} = Alert, StateName, +handle_alert(#alert{level = ?FATAL} = Alert0, StateName, #state{static_env = #static_env{role = Role, socket = Socket, host = Host, @@ -382,11 +381,11 @@ handle_alert(#alert{level = ?FATAL} = Alert, StateName, session = Session, socket_options = Opts} = State) -> invalidate_session(Role, Host, Port, Session), + Alert = Alert0#alert{role = opposite_role(Role)}, log_alert(SslOpts#ssl_options.log_level, Role, Connection:protocol_name(), - StateName, Alert#alert{role = opposite_role(Role)}), + StateName, Alert), Pids = Connection:pids(State), - alert_user(Pids, Transport, Tracker, Socket, StateName, Opts, Pid, From, Alert, - opposite_role(Role), Connection), + alert_user(Pids, Transport, Tracker, Socket, StateName, Opts, Pid, From, Alert, Role, StateName, Connection), {stop, {shutdown, normal}, State}; handle_alert(#alert{level = ?WARNING, description = ?CLOSE_NOTIFY} = Alert, @@ -396,13 +395,14 @@ handle_alert(#alert{level = ?WARNING, description = ?CLOSE_NOTIFY} = Alert, StateName, State) -> handle_normal_shutdown(Alert, StateName, State), {stop,{shutdown, peer_close}, State}; -handle_alert(#alert{level = ?WARNING, description = ?NO_RENEGOTIATION} = Alert, StateName, +handle_alert(#alert{level = ?WARNING, description = ?NO_RENEGOTIATION} = Alert0, StateName, #state{static_env = #static_env{role = Role, protocol_cb = Connection}, handshake_env = #handshake_env{renegotiation = {true, internal}}, ssl_options = SslOpts} = State) -> + Alert = Alert0#alert{role = opposite_role(Role)}, log_alert(SslOpts#ssl_options.log_level, Role, - Connection:protocol_name(), StateName, Alert#alert{role = opposite_role(Role)}), + Connection:protocol_name(), StateName, Alert), handle_normal_shutdown(Alert, StateName, State), {stop,{shutdown, peer_close}, State}; @@ -709,6 +709,7 @@ handle_session(#server_hello{cipher_suite = CipherSuite, {ExpectNPN, Protocol} = case Protocol0 of undefined -> + {false, CurrentProtocol}; _ -> {ProtoExt =:= npn, Protocol0} @@ -1194,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} = @@ -1445,7 +1446,7 @@ handle_info({ErrorTag, Socket, econnaborted}, StateName, } = State) when StateName =/= connection -> Pids = Connection:pids(State), alert_user(Pids, Transport, Tracker,Socket, - StartFrom, ?ALERT_REC(?FATAL, ?CLOSE_NOTIFY), Role, Connection), + StartFrom, ?ALERT_REC(?FATAL, ?CLOSE_NOTIFY), Role, StateName, Connection), {stop, {shutdown, normal}, State}; handle_info({ErrorTag, Socket, Reason}, StateName, #state{static_env = #static_env{socket = Socket, @@ -2907,22 +2908,22 @@ send_user(Pid, Msg) -> Pid ! Msg, ok. -alert_user(Pids, Transport, Tracker, Socket, connection, Opts, Pid, From, Alert, Role, Connection) -> - alert_user(Pids, Transport, Tracker, Socket, Opts#socket_options.active, Pid, From, Alert, Role, Connection); -alert_user(Pids, Transport, Tracker, Socket,_, _, _, From, Alert, Role, Connection) -> - alert_user(Pids, Transport, Tracker, Socket, From, Alert, Role, Connection). +alert_user(Pids, Transport, Tracker, Socket, connection, Opts, Pid, From, Alert, Role, StateName, Connection) -> + alert_user(Pids, Transport, Tracker, Socket, Opts#socket_options.active, Pid, From, Alert, Role, StateName, Connection); +alert_user(Pids, Transport, Tracker, Socket,_, _, _, From, Alert, Role, StateName, Connection) -> + alert_user(Pids, Transport, Tracker, Socket, From, Alert, Role, StateName, Connection). -alert_user(Pids, Transport, Tracker, Socket, From, Alert, Role, Connection) -> - alert_user(Pids, Transport, Tracker, Socket, false, no_pid, From, Alert, Role, Connection). +alert_user(Pids, Transport, Tracker, Socket, From, Alert, Role, StateName, Connection) -> + alert_user(Pids, Transport, Tracker, Socket, false, no_pid, From, Alert, Role, StateName, Connection). -alert_user(_, _, _, _, false = Active, Pid, From, Alert, Role, _) when From =/= undefined -> +alert_user(_, _, _, _, false = Active, Pid, From, Alert, Role, StateName, Connection) when From =/= undefined -> %% If there is an outstanding ssl_accept | recv %% From will be defined and send_or_reply will %% send the appropriate error message. - ReasonCode = ssl_alert:reason_code(Alert, Role), + ReasonCode = ssl_alert:reason_code(Alert, Role, Connection:protocol_name(), StateName), send_or_reply(Active, Pid, From, {error, ReasonCode}); -alert_user(Pids, Transport, Tracker, Socket, Active, Pid, From, Alert, Role, Connection) -> - case ssl_alert:reason_code(Alert, Role) of +alert_user(Pids, Transport, Tracker, Socket, Active, Pid, From, Alert, Role, StateName, Connection) -> + case ssl_alert:reason_code(Alert, Role, Connection:protocol_name(), StateName) of closed -> send_or_reply(Active, Pid, From, {ssl_closed, Connection:socket(Pids, Transport, Socket, Tracker)}); @@ -2933,11 +2934,11 @@ alert_user(Pids, Transport, Tracker, Socket, Active, Pid, From, Alert, Role, Con log_alert(Level, Role, ProtocolName, StateName, #alert{role = Role} = Alert) -> Txt = ssl_alert:own_alert_txt(Alert), - Report = io_lib:format("~s ~p: In state ~p ~s\n", [ProtocolName, Role, StateName, Txt]), + Report = ssl_alert:alert_txt(ProtocolName, Role, StateName, Txt), ssl_logger:notice(Level, Report); log_alert(Level, Role, ProtocolName, StateName, Alert) -> Txt = ssl_alert:alert_txt(Alert), - Report = io_lib:format("~s ~p: In state ~p ~s\n", [ProtocolName, Role, StateName, Txt]), + Report = ssl_alert:alert_txt(ProtocolName, Role, StateName, Txt), ssl_logger:notice(Level, Report). invalidate_session(client, Host, Port, Session) -> @@ -3000,3 +3001,8 @@ new_emulated([], EmOpts) -> EmOpts; new_emulated(NewEmOpts, _) -> NewEmOpts. + +no_records(Extensions) -> + maps:map(fun(_, Value) -> + ssl_handshake:extension_value(Value) + end, Extensions). diff --git a/lib/ssl/src/ssl_handshake.erl b/lib/ssl/src/ssl_handshake.erl index f68d3e9b26..b51ba0fa2d 100644 --- a/lib/ssl/src/ssl_handshake.erl +++ b/lib/ssl/src/ssl_handshake.erl @@ -3046,6 +3046,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..821b7000cc 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 -> + 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(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..12ab2015aa 100644 --- a/lib/ssl/src/tls_handshake_1_3.erl +++ b/lib/ssl/src/tls_handshake_1_3.erl @@ -46,7 +46,17 @@ 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 @@ -79,7 +89,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 +121,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 +129,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 +151,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 +180,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 +192,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 +271,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,6 +462,7 @@ build_content(Context, THash) -> %%==================================================================== +%% TLS Server do_start(#client_hello{cipher_suites = ClientCiphers, session_id = SessionId, extensions = Extensions} = _Hello, @@ -436,7 +471,6 @@ do_start(#client_hello{cipher_suites = ClientCiphers, signature_algs = ServerSignAlgs, supported_groups = ServerGroups0}, session = #session{own_certificate = Cert}} = State0) -> - ClientGroups0 = maps:get(elliptic_curves, Extensions, undefined), ClientGroups = get_supported_groups(ClientGroups0), ServerGroups = get_supported_groups(ServerGroups0), @@ -449,8 +483,6 @@ do_start(#client_hello{cipher_suites = ClientCiphers, 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 @@ -460,7 +492,7 @@ do_start(#client_hello{cipher_suites = ClientCiphers, %% 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), @@ -506,6 +538,81 @@ do_start(#client_hello{cipher_suites = ClientCiphers, ?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; +%% 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, SelectedCipherSuite, ClientKeyShare, SessionId, + SelectedGroup, undefined, undefined), + + %% 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,7 +622,7 @@ 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}, @@ -526,6 +633,8 @@ do_negotiated(start_handshake, socket = _Socket, transport_cb = _Transport} } = State0) -> + ServerPrivateKey = get_server_private_key(KeyShare), + {Ref,Maybe} = maybe(), try @@ -536,7 +645,7 @@ do_negotiated(start_handshake, {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 +659,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 +683,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}; @@ -599,8 +710,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 +721,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 +739,224 @@ 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, SelectedCipherSuite, ClientKeyShare0, SessionId, + SelectedGroup, undefined, 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) + 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 @@ -684,7 +989,7 @@ send_hello_retry_request(#state{connection_states = ConnectionStates0} = State0, ServerHello = server_hello(hello_retry_request, SessionId, KeyShare, ConnectionStates0), {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 +1008,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 +1054,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 @@ -861,7 +1190,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 +1203,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 +1228,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 +1245,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 +1298,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 +1311,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 @@ -1071,25 +1420,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 +1463,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 +1495,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 +1513,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 +1559,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,6 +1606,27 @@ 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}. + %% get_client_public_key(Group, ClientShares) -> %% case lists:keysearch(Group, 2, ClientShares) of @@ -1223,6 +1653,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 +1774,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 20d9f28512..8cb98e7fa6 100644 --- a/lib/ssl/test/ssl_basic_SUITE.erl +++ b/lib/ssl/test/ssl_basic_SUITE.erl @@ -249,16 +249,28 @@ 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_unsupported_sign_algo_cert_client_auth_ssl_server_ssl_client, tls13_connection_information]. %%-------------------------------------------------------------------- @@ -5327,6 +5339,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"}]. @@ -5351,6 +5437,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"}]. @@ -5376,6 +5495,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."}]. @@ -5408,6 +5559,45 @@ tls13_client_auth_empty_cert_alert_ssl_server_openssl_client(Config) -> 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_result(Server, + {error, + {tls_alert, + {certificate_required, + "received SERVER ALERT: Fatal - Certificate required - 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."}]. @@ -5437,13 +5627,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}, @@ -5463,6 +5687,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."}]. @@ -5498,6 +5754,46 @@ tls13_hrr_client_auth_empty_cert_alert_ssl_server_openssl_client(Config) -> 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_result(Server, + {error, + {tls_alert, + {certificate_required, + "received SERVER ALERT: Fatal - Certificate required - certificate_required"}}}), + ssl_test_lib:close(Server), + ssl_test_lib:close_port(Client). + + tls13_hrr_client_auth_empty_cert_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 false."}]. @@ -5529,6 +5825,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."}]. @@ -5557,6 +5889,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"}]. @@ -5591,9 +5956,49 @@ tls13_unsupported_sign_algo_client_auth_ssl_server_openssl_client(Config) -> ssl_test_lib:close_port(Client). -%% Triggers Client Alert as openssl s_client does not have a certificate with a +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_result( + Server, + {error, + {tls_alert, + {insufficient_security, + "received SERVER ALERT: Fatal - Insufficient Security - " + "\"No suitable signature algorithm\""}}}), + ssl_test_lib:close(Server), + ssl_test_lib:close_port(Client). + + +%% 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"}]. @@ -5623,8 +6028,52 @@ tls13_unsupported_sign_algo_cert_client_auth_ssl_server_openssl_client(Config) - Server, {error, {tls_alert, - {illegal_parameter, - "received CLIENT ALERT: Fatal - Illegal Parameter"}}}), + {certificate_required, + "received SERVER ALERT: Fatal - Certificate required - 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_result( + Server, + {error, + {tls_alert, + {certificate_required, + "received SERVER ALERT: Fatal - Certificate required - certificate_required"}}}), ssl_test_lib:close(Server), ssl_test_lib:close_port(Client). diff --git a/lib/ssl/test/ssl_test_lib.erl b/lib/ssl/test/ssl_test_lib.erl index 3b161a0c8a..6294ce3739 100644 --- a/lib/ssl/test/ssl_test_lib.erl +++ b/lib/ssl/test/ssl_test_lib.erl @@ -159,6 +159,7 @@ connect(ListenSocket, Node, N, _, Timeout, SslOpts, [_|_] =ContOpts) -> case ssl:handshake(AcceptSocket, SslOpts, Timeout) of {ok, Socket0, Ext} -> + [_|_] = maps:get(sni, Ext), ct:log("Ext ~p:~n", [Ext]), ct:log("~p:~p~nssl:handshake_continue(~p,~p,~p)~n", [?MODULE,?LINE, Socket0, ContOpts,Timeout]), case ssl:handshake_continue(Socket0, ContOpts, Timeout) of @@ -429,14 +430,17 @@ check_result(Pid, Msg) -> end. check_server_alert(Pid, Alert) -> receive - {Pid, {error, {tls_alert, {Alert, _}}}} -> + {Pid, {error, {tls_alert, {Alert, STxt}}}} -> + check_server_txt(STxt), ok end. check_server_alert(Server, Client, Alert) -> receive - {Server, {error, {tls_alert, {Alert, _}}}} -> + {Server, {error, {tls_alert, {Alert, STxt}}}} -> + check_server_txt(STxt), receive - {Client, {error, {tls_alert, {Alert, _}}}} -> + {Client, {error, {tls_alert, {Alert, CTxt}}}} -> + check_client_txt(CTxt), ok; {Client, {error, closed}} -> ok @@ -444,20 +448,35 @@ check_server_alert(Server, Client, Alert) -> end. check_client_alert(Pid, Alert) -> receive - {Pid, {error, {tls_alert, {Alert, _}}}} -> + {Pid, {error, {tls_alert, {Alert, CTxt}}}} -> + check_client_txt(CTxt), ok end. check_client_alert(Server, Client, Alert) -> receive - {Client, {error, {tls_alert, {Alert, _}}}} -> + {Client, {error, {tls_alert, {Alert, CTxt}}}} -> + check_client_txt(CTxt), receive - {Server, {error, {tls_alert, {Alert, _}}}} -> + {Server, {error, {tls_alert, {Alert, STxt}}}} -> + check_server_txt(STxt), ok; {Server, {error, closed}} -> ok end end. +check_server_txt("TLS server" ++ _) -> + ok; +check_server_txt("DTLS server" ++ _) -> + ok; +check_server_txt(Txt) -> + ct:fail({expected_server, {got, Txt}}). +check_client_txt("TLS client" ++ _) -> + ok; +check_client_txt("DTLS client" ++ _) -> + ok; +check_client_txt(Txt) -> + ct:fail({expected_server, {got, Txt}}). wait_for_result(Server, ServerMsg, Client, ClientMsg) -> receive 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) -> <<1,1,1,1,1 ... 2> byte_size(A). 100 -3> binary:referenced_byte_size(A) +3> binary:referenced_byte_size(A). 100 -4> <<_:10/binary,B:10/binary,_/binary>> = A. +4> <<B:10/binary, C:90/binary>> = A. <<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 385f092069..2bea75ef9f 100644 --- a/lib/stdlib/doc/src/notes.xml +++ b/lib/stdlib/doc/src/notes.xml @@ -289,6 +289,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 (' or ").</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 |