aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--.gitignore6
-rw-r--r--Makefile.in23
-rw-r--r--OTP_VERSION2
-rw-r--r--erts/Makefile4
-rw-r--r--erts/doc/src/tty.xml4
-rw-r--r--erts/emulator/beam/beam_emu.c34
-rw-r--r--erts/emulator/beam/beam_load.c26
-rw-r--r--erts/emulator/beam/bif.c7
-rw-r--r--erts/emulator/beam/big.c18
-rw-r--r--erts/emulator/beam/big.h2
-rw-r--r--erts/emulator/beam/break.c42
-rw-r--r--erts/emulator/beam/bs_instrs.tab11
-rw-r--r--erts/emulator/beam/dist.c173
-rw-r--r--erts/emulator/beam/dist.h7
-rw-r--r--erts/emulator/beam/erl_bif_info.c6
-rw-r--r--erts/emulator/beam/erl_gc.c24
-rw-r--r--erts/emulator/beam/erl_init.c5
-rw-r--r--erts/emulator/beam/erl_lock_check.c3
-rw-r--r--erts/emulator/beam/erl_message.c24
-rw-r--r--erts/emulator/beam/erl_message.h2
-rw-r--r--erts/emulator/beam/erl_nif.h13
-rw-r--r--erts/emulator/beam/erl_node_tables.c6
-rw-r--r--erts/emulator/beam/erl_node_tables.h2
-rw-r--r--erts/emulator/beam/erl_proc_sig_queue.c11
-rw-r--r--erts/emulator/beam/erl_process.c45
-rw-r--r--erts/emulator/beam/erl_process.h3
-rw-r--r--erts/emulator/beam/erl_process_dump.c14
-rw-r--r--erts/emulator/beam/erl_utils.h1
-rw-r--r--erts/emulator/beam/erl_vm.h7
-rw-r--r--erts/emulator/beam/external.c93
-rw-r--r--erts/emulator/beam/msg_instrs.tab1
-rw-r--r--erts/emulator/beam/ops.tab3
-rw-r--r--erts/emulator/beam/utils.c8
-rw-r--r--erts/emulator/sys/common/erl_poll.c4
-rw-r--r--erts/emulator/test/binary_SUITE.erl11
-rw-r--r--erts/emulator/test/bs_match_misc_SUITE.erl21
-rw-r--r--erts/emulator/test/distribution_SUITE.erl38
-rw-r--r--erts/emulator/test/dump_SUITE.erl98
-rw-r--r--erts/emulator/test/efile_SUITE.erl7
-rw-r--r--erts/emulator/test/erts_test_utils.erl1
-rw-r--r--erts/emulator/test/fun_SUITE.erl4
-rw-r--r--erts/emulator/test/map_SUITE.erl92
-rw-r--r--erts/emulator/test/process_SUITE.erl51
-rw-r--r--erts/epmd/epmd.mk2
-rw-r--r--erts/epmd/src/epmd.h1
-rw-r--r--erts/epmd/src/epmd_int.h10
-rw-r--r--erts/epmd/src/epmd_srv.c139
-rw-r--r--erts/etc/unix/etp-commands.in6
-rw-r--r--erts/test/erl_print_SUITE.erl41
-rw-r--r--lib/asn1/src/asn1ct_check.erl35
-rw-r--r--lib/asn1/test/Makefile2
-rw-r--r--lib/asn1/test/asn1_SUITE.erl12
-rw-r--r--lib/asn1/test/asn1_SUITE_data/ChoExtension.asn12
-rw-r--r--lib/asn1/test/asn1_SUITE_data/DefaultOctetString.asn15
-rw-r--r--lib/asn1/test/asn1_SUITE_data/SeqOfChoExt.asn127
-rw-r--r--lib/asn1/test/testChoExtension.erl1
-rw-r--r--lib/asn1/test/testDefaultOctetString.erl34
-rw-r--r--lib/asn1/test/testSeqOfChoExt.erl15
-rw-r--r--lib/common_test/test_server/configure.in25
-rw-r--r--lib/compiler/src/beam_ssa_type.erl23
-rw-r--r--lib/compiler/src/beam_validator.erl10
-rw-r--r--lib/compiler/src/sys_core_fold.erl45
-rw-r--r--lib/compiler/test/beam_type_SUITE.erl18
-rw-r--r--lib/compiler/test/bs_construct_SUITE.erl18
-rw-r--r--lib/compiler/test/bs_match_SUITE.erl18
-rw-r--r--lib/compiler/test/compile_SUITE.erl4
-rw-r--r--lib/compiler/test/test_lib.erl11
-rw-r--r--lib/compiler/test/trycatch_SUITE.erl27
-rw-r--r--lib/crypto/c_src/aead.c109
-rw-r--r--lib/crypto/c_src/api_ng.c12
-rw-r--r--lib/crypto/c_src/atoms.c12
-rw-r--r--lib/crypto/c_src/atoms.h6
-rw-r--r--lib/crypto/c_src/cipher.c36
-rw-r--r--lib/crypto/c_src/common.h11
-rw-r--r--lib/crypto/doc/src/crypto.xml134
-rw-r--r--lib/crypto/src/crypto.erl306
-rw-r--r--lib/crypto/test/crypto_SUITE.erl6
-rw-r--r--lib/erl_interface/src/encode/encode_pid.c11
-rw-r--r--lib/erl_interface/src/encode/encode_port.c11
-rw-r--r--lib/erl_interface/src/encode/encode_ref.c10
-rw-r--r--lib/erl_interface/test/erl_eterm_SUITE.erl10
-rw-r--r--lib/inets/test/httpc_SUITE.erl20
-rw-r--r--lib/kernel/doc/src/logger_disk_log_h.xml8
-rw-r--r--lib/kernel/doc/src/logger_std_h.xml8
-rw-r--r--lib/kernel/src/erl_epmd.erl11
-rw-r--r--lib/kernel/src/raw_file_io_inflate.erl2
-rw-r--r--lib/kernel/test/code_SUITE.erl9
-rw-r--r--lib/kernel/test/erl_distribution_wb_SUITE.erl58
-rw-r--r--lib/kernel/test/logger_disk_log_h_SUITE.erl8
-rw-r--r--lib/observer/test/observer_SUITE.erl3
-rw-r--r--lib/ssl/doc/src/Makefile1
-rw-r--r--lib/ssl/doc/src/ssl_app.xml41
-rw-r--r--lib/ssl/doc/src/standards_compliance.xml2312
-rw-r--r--lib/ssl/doc/src/usersguide.xml1
-rw-r--r--lib/ssl/src/dtls_connection.erl6
-rw-r--r--lib/ssl/src/ssl.erl4
-rw-r--r--lib/ssl/src/ssl_cipher.erl86
-rw-r--r--lib/ssl/src/ssl_cipher.hrl52
-rw-r--r--lib/ssl/src/ssl_cipher_format.erl187
-rw-r--r--lib/ssl/src/ssl_record.erl23
-rw-r--r--lib/ssl/src/ssl_record.hrl5
-rw-r--r--lib/ssl/src/tls_connection.erl4
-rw-r--r--lib/ssl/src/tls_record_1_3.erl2
-rw-r--r--lib/ssl/test/Makefile1
-rw-r--r--lib/ssl/test/ssl_basic_SUITE.erl363
-rw-r--r--lib/ssl/test/ssl_cipher_suite_SUITE.erl772
-rw-r--r--lib/ssl/test/ssl_test_lib.erl26
-rw-r--r--lib/ssl/test/ssl_to_openssl_SUITE.erl98
-rw-r--r--lib/stdlib/doc/src/gen_statem.xml2
-rw-r--r--lib/stdlib/src/erl_tar.erl4
-rw-r--r--lib/syntax_tools/test/syntax_tools_SUITE.erl12
-rw-r--r--lib/tools/emacs/erldoc.el38
-rw-r--r--lib/wx/src/Makefile4
-rw-r--r--system/doc/design_principles/statem.xml2
-rw-r--r--system/doc/reference_manual/expressions.xml8
115 files changed, 5016 insertions, 1337 deletions
diff --git a/.gitignore b/.gitignore
index 4a6aaab6f3..bd0e9615f7 100644
--- a/.gitignore
+++ b/.gitignore
@@ -230,12 +230,6 @@ JAVADOC-GENERATED
/erts/test/install_SUITE_data/install_bin
/erts/test/autoimport_SUITE_data/erlang.xml
-# asn1
-
-/lib/asn1/test/asn1_SUITE.erl
-/lib/asn1/test/asn1_bin_SUITE.erl
-/lib/asn1/test/asn1_bin_v2_SUITE.erl
-
# common_test
/lib/common_test/priv/install.sh
diff --git a/Makefile.in b/Makefile.in
index 49a0d9f8af..6cbd92a55b 100644
--- a/Makefile.in
+++ b/Makefile.in
@@ -492,31 +492,14 @@ else
$(MAKE) opt BUILD_ALL=true
$(V_at)test -f $(ERL_TOP)/make/otp_built || echo "OTP built" > $(ERL_TOP)/make/otp_built
endif
-kernel:
- $(make_verbose)cd lib/kernel && \
- ERL_TOP=$(ERL_TOP) PATH=$(BOOT_PREFIX)"$${PATH}" \
- $(MAKE) opt BUILD_ALL=true
-stdlib:
- $(make_verbose)cd lib/stdlib && \
- ERL_TOP=$(ERL_TOP) PATH=$(BOOT_PREFIX)"$${PATH}" \
- $(MAKE) opt BUILD_ALL=true
+APPS=$(patsubst $(ERL_TOP)/lib/%/doc,%,$(wildcard $(ERL_TOP)/lib/*/doc))
-compiler:
- $(make_verbose)cd lib/compiler && \
+$(APPS):
+ $(make_verbose)cd lib/$@ && \
ERL_TOP=$(ERL_TOP) PATH=$(BOOT_PREFIX)"$${PATH}" \
$(MAKE) opt BUILD_ALL=true
-hipe:
- $(make_verbose)cd lib/hipe && \
- ERL_TOP=$(ERL_TOP) PATH=$(BOOT_PREFIX)"$${PATH}" \
- $(MAKE) opt BUILD_ALL=true
-
-syntax_tools:
- $(make_verbose)cd lib/syntax_tools && \
- ERL_TOP=$(ERL_TOP) PATH=$(BOOT_PREFIX)"$${PATH}" \
- $(MAKE) opt BUILD_ALL=true
-
preloaded:
$(make_verbose)cd erts/preloaded/src && \
ERL_TOP=$(ERL_TOP) PATH=$(BOOT_PREFIX)"$${PATH}" \
diff --git a/OTP_VERSION b/OTP_VERSION
index da0a41680b..a5a30a3cfe 100644
--- a/OTP_VERSION
+++ b/OTP_VERSION
@@ -1 +1 @@
-22.0-rc1
+22.0-rc2
diff --git a/erts/Makefile b/erts/Makefile
index 60c70b6a2c..e62c896170 100644
--- a/erts/Makefile
+++ b/erts/Makefile
@@ -129,9 +129,13 @@ makefiles:
.PHONY: release
release:
+ifeq ($(TYPE),)
for t in $(TYPES); do \
( cd emulator && $(MAKE) release TYPE=$$t ) || exit $$?; \
done
+else
+ ( cd emulator && $(MAKE) release TYPE=$(TYPE) ) || exit $$?;
+endif
$(V_at)for d in $(ERTSDIRS) $(XINSTDIRS); do \
if test -d $$d; then \
( cd $$d && $(MAKE) $@ ) || exit $$? ; \
diff --git a/erts/doc/src/tty.xml b/erts/doc/src/tty.xml
index 51db1ba8e2..c33e082f4f 100644
--- a/erts/doc/src/tty.xml
+++ b/erts/doc/src/tty.xml
@@ -165,6 +165,10 @@ erl</pre>
<cell align="left" valign="middle">C-y</cell>
<cell align="left" valign="middle">Insert previously killed text</cell>
</row>
+ <row>
+ <cell align="left" valign="middle">C-]</cell>
+ <cell align="left" valign="middle">Insert matching closing bracket</cell>
+ </row>
<tcaption>tty Text Editing</tcaption>
</table>
</section>
diff --git a/erts/emulator/beam/beam_emu.c b/erts/emulator/beam/beam_emu.c
index d68d021679..ea01ce597d 100644
--- a/erts/emulator/beam/beam_emu.c
+++ b/erts/emulator/beam/beam_emu.c
@@ -1479,9 +1479,24 @@ next_catch(Process* c_p, Eterm *reg) {
BeamInstr i_return_time_trace = beam_return_time_trace[0];
ptr = prev = c_p->stop;
- ASSERT(is_CP(*ptr));
ASSERT(ptr <= STACK_START(c_p));
- if (ptr == STACK_START(c_p)) return NULL;
+
+ /* This function is only called if we have active catch tags or have
+ * previously called a function that was exception-traced. As the exception
+ * trace flag isn't cleared after the traced function returns (and the
+ * catch tag inserted by it is gone), it's possible to land here with an
+ * empty stack, and the process should simply die when that happens. */
+ if (ptr == STACK_START(c_p)) {
+ ASSERT(!active_catches && IS_TRACED_FL(c_p, F_EXCEPTION_TRACE));
+ return NULL;
+ }
+
+ /*
+ * Better safe than sorry here. In debug builds, produce a core
+ * dump if the top of the stack doesn't point to a continuation
+ * pointer. In other builds, ignore a non-CP at the top of stack.
+ */
+ ASSERT(is_CP(*ptr));
if ((is_not_CP(*ptr) || (*cp_val(*ptr) != i_return_trace &&
*cp_val(*ptr) != i_return_to_trace &&
*cp_val(*ptr) != i_return_time_trace ))
@@ -3252,20 +3267,23 @@ erts_is_builtin(Eterm Mod, Eterm Name, int arity)
/*
- * Return the current number of reductions for the given process.
+ * Return the current number of reductions consumed by the given process.
* To get the total number of reductions, p->reds must be added.
*/
Uint
-erts_current_reductions(Process *current, Process *p)
+erts_current_reductions(Process *c_p, Process *p)
{
- if (current != p) {
+ Sint reds_left;
+ if (c_p != p || !(erts_atomic32_read_nob(&c_p->state)
+ & ERTS_PSFLG_RUNNING)) {
return 0;
- } else if (current->fcalls < 0 && ERTS_PROC_GET_SAVED_CALLS_BUF(current)) {
- return current->fcalls + CONTEXT_REDS;
+ } else if (c_p->fcalls < 0 && ERTS_PROC_GET_SAVED_CALLS_BUF(c_p)) {
+ reds_left = c_p->fcalls + CONTEXT_REDS;
} else {
- return REDS_IN(current) - current->fcalls;
+ reds_left = c_p->fcalls;
}
+ return REDS_IN(c_p) - reds_left;
}
int
diff --git a/erts/emulator/beam/beam_load.c b/erts/emulator/beam/beam_load.c
index 21740caa2c..941c3ebbbe 100644
--- a/erts/emulator/beam/beam_load.c
+++ b/erts/emulator/beam/beam_load.c
@@ -3145,6 +3145,13 @@ is_killed(LoaderState* stp, GenOpArg Reg, GenOpArg Live)
Live.val <= Reg.val;
}
+static int
+is_killed_by_call_fun(LoaderState* stp, GenOpArg Reg, GenOpArg Live)
+{
+ return Reg.type == TAG_x && Live.type == TAG_u &&
+ Live.val+1 <= Reg.val;
+}
+
/*
* Test whether register Reg is killed by make_fun instruction that
* creates the fun given by index idx.
@@ -3347,19 +3354,12 @@ gen_get_binary2(LoaderState* stp, GenOpArg Fail, GenOpArg Ms, GenOpArg Live,
NATIVE_ENDIAN(Flags);
if (Size.type == TAG_a && Size.val == am_all) {
- if (Ms.type == Dst.type && Ms.val == Dst.val) {
- GENOP_NAME_ARITY(op, i_bs_get_binary_all_reuse, 3);
- op->a[0] = Ms;
- op->a[1] = Fail;
- op->a[2] = Unit;
- } else {
- GENOP_NAME_ARITY(op, i_bs_get_binary_all2, 5);
- op->a[0] = Ms;
- op->a[1] = Fail;
- op->a[2] = Live;
- op->a[3] = Unit;
- op->a[4] = Dst;
- }
+ GENOP_NAME_ARITY(op, i_bs_get_binary_all2, 5);
+ op->a[0] = Ms;
+ op->a[1] = Fail;
+ op->a[2] = Live;
+ op->a[3] = Unit;
+ op->a[4] = Dst;
} else if (Size.type == TAG_i) {
GENOP_NAME_ARITY(op, i_bs_get_binary_imm2, 6);
op->a[0] = Ms;
diff --git a/erts/emulator/beam/bif.c b/erts/emulator/beam/bif.c
index c102ddbee6..d0e2d9afc2 100644
--- a/erts/emulator/beam/bif.c
+++ b/erts/emulator/beam/bif.c
@@ -1915,7 +1915,7 @@ do_send(Process *p, Eterm to, Eterm msg, Eterm return_term, Eterm *refp,
erts_dsprintf_buf_t *dsbufp = erts_create_logger_dsbuf();
erts_dsprintf(dsbufp,
"Discarding message %T from %T to %T in an old "
- "incarnation (%d) of this node (%d)\n",
+ "incarnation (%u) of this node (%u)\n",
msg,
p->common.id,
to,
@@ -1959,7 +1959,7 @@ do_send(Process *p, Eterm to, Eterm msg, Eterm return_term, Eterm *refp,
erts_dsprintf_buf_t *dsbufp = erts_create_logger_dsbuf();
erts_dsprintf(dsbufp,
"Discarding message %T from %T to %T in an old "
- "incarnation (%d) of this node (%d)\n",
+ "incarnation (%u) of this node (%u)\n",
msg,
p->common.id,
to,
@@ -2463,6 +2463,7 @@ BIF_RETTYPE iolist_size_1(BIF_ALIST_1)
ErtsIOListSizeContext* context = NULL;
Eterm state_mref;
int is_trap_at_L_iter_list;
+ ERTS_UNDEF(state_mref, THE_NON_VALUE);
ESTACK_CHANGE_ALLOCATOR(s, ERTS_ALC_T_SAVED_ESTACK);
#ifdef DEBUG
iterations_until_trap = iterations_until_trap / 10;
@@ -4313,7 +4314,7 @@ BIF_RETTYPE list_to_ref_1(BIF_ALIST_1)
if(dep == erts_this_dist_entry) {
ErtsMagicBinary *mb;
Uint32 sid;
- if (refn[0] > MAX_REFERENCE) goto bad;
+ if (refn[0] >= MAX_REFERENCE) goto bad;
if (n != ERTS_REF_NUMBERS) goto bad;
sid = erts_get_ref_numbers_thr_id(refn);
if (sid > erts_no_schedulers) goto bad;
diff --git a/erts/emulator/beam/big.c b/erts/emulator/beam/big.c
index 522f50287a..7666f23a4f 100644
--- a/erts/emulator/beam/big.c
+++ b/erts/emulator/beam/big.c
@@ -2176,6 +2176,24 @@ term_to_Uint64(Eterm term, Uint64 *up)
#endif
}
+int
+term_to_Uint32(Eterm term, Uint32 *up)
+{
+#if ERTS_SIZEOF_ETERM == 4
+ return term_to_Uint(term,up);
+#else
+ if (is_small(term)) {
+ Sint i = signed_val(term);
+ if (i >= 0) {
+ *up = (Uint32) i;
+ return 1;
+ }
+ }
+ *up = BADARG;
+ return 0;
+#endif
+}
+
int term_to_Sint(Eterm term, Sint *sp)
{
diff --git a/erts/emulator/beam/big.h b/erts/emulator/beam/big.h
index ad19cce395..3fed076419 100644
--- a/erts/emulator/beam/big.h
+++ b/erts/emulator/beam/big.h
@@ -168,6 +168,8 @@ Eterm erts_uint64_array_to_big(Uint **, int, int, Uint64 *);
int term_to_Uint64(Eterm, Uint64*);
int term_to_Sint64(Eterm, Sint64*);
#endif
+int term_to_Uint32(Eterm, Uint32*);
+
Uint32 big_to_uint32(Eterm b);
int term_equals_2pow32(Eterm);
diff --git a/erts/emulator/beam/break.c b/erts/emulator/beam/break.c
index 27bf2187c2..06d8c7cda8 100644
--- a/erts/emulator/beam/break.c
+++ b/erts/emulator/beam/break.c
@@ -39,6 +39,7 @@
#include "erl_hl_timer.h"
#include "erl_thr_progress.h"
#include "erl_proc_sig_queue.h"
+#include "dist.h"
/* Forward declarations -- should really appear somewhere else */
static void process_killer(void);
@@ -74,6 +75,7 @@ port_info(fmtfn_t to, void *to_arg)
void
process_info(fmtfn_t to, void *to_arg)
{
+ ErtsSchedulerData *esdp = erts_get_scheduler_data();
int i, max = erts_ptab_max(&erts_proc);
for (i = 0; i < max; i++) {
Process *p = erts_pix2proc(i);
@@ -81,11 +83,35 @@ process_info(fmtfn_t to, void *to_arg)
/* Do not include processes with no heap,
* they are most likely just created and has invalid data
*/
- if (!ERTS_PROC_IS_EXITING(p) && p->heap != NULL)
- print_process_info(to, to_arg, p, 0);
+ if (p->heap != NULL) {
+ ErtsProcLocks locks = (p == esdp->current_process ||
+ p == esdp->free_process) ? ERTS_PROC_LOCK_MAIN : 0;
+ print_process_info(to, to_arg, p, locks);
+ }
}
}
+ /* Look for FREE processes in the run-queues and dist entries.
+ These have been removed from the ptab but we still want them
+ in the crash dump for debugging. */
+
+ /* First loop through all run-queues */
+ for (i = 0; i < erts_no_schedulers + ERTS_NUM_DIRTY_RUNQS; i++) {
+ ErtsRunQueue *rq = ERTS_RUNQ_IX(i);
+ int j;
+ for (j = 0; j < ERTS_NO_PROC_PRIO_QUEUES; j++) {
+ Process *p = rq->procs.prio[j].first;
+ while (p) {
+ if (ERTS_PSFLG_FREE & erts_atomic32_read_acqb(&p->state))
+ print_process_info(to, to_arg, p, 0);
+ p = p->next;
+ }
+ }
+ }
+
+ /* Then check all dist entries */
+ erts_dist_print_procs_suspended_on_de(to, to_arg);
+
port_info(to, to_arg);
}
@@ -199,13 +225,14 @@ static int doit_print_monitor(ErtsMonitor *mon, void *vpcontext, Sint reds)
}
return 1;
}
-
+
/* Display info about an individual Erlang process */
void
print_process_info(fmtfn_t to, void *to_arg, Process *p, ErtsProcLocks orig_locks)
{
int garbing = 0;
int running = 0;
+ int exiting = 0;
Sint len;
struct saved_calls *scb;
erts_aint32_t state;
@@ -226,9 +253,12 @@ print_process_info(fmtfn_t to, void *to_arg, Process *p, ErtsProcLocks orig_lock
| ERTS_PSFLG_DIRTY_RUNNING))
running = 1;
+ if (state & ERTS_PSFLG_EXITING)
+ exiting = 1;
+
if (!(locks & ERTS_PROC_LOCK_MAIN)) {
locks |= ERTS_PROC_LOCK_MAIN;
- if (ERTS_IS_CRASH_DUMPING && running) {
+ if (ERTS_IS_CRASH_DUMPING) {
if (erts_proc_trylock(p, locks)) {
/* crash dumping and main lock taken, this probably means that
the process is doing a GC on a dirty-scheduler... so we cannot
@@ -246,7 +276,7 @@ print_process_info(fmtfn_t to, void *to_arg, Process *p, ErtsProcLocks orig_lock
* If the process is registered as a global process, display the
* registered name
*/
- if (p->common.u.alive.reg)
+ if (!ERTS_PROC_IS_EXITING(p) && p->common.u.alive.reg)
erts_print(to, to_arg, "Name: %T\n", p->common.u.alive.reg->name);
/*
@@ -332,7 +362,7 @@ print_process_info(fmtfn_t to, void *to_arg, Process *p, ErtsProcLocks orig_lock
}
/* display the links only if there are any*/
- if (ERTS_P_LINKS(p) || ERTS_P_MONITORS(p) || ERTS_P_LT_MONITORS(p)) {
+ if (!exiting && (ERTS_P_LINKS(p) || ERTS_P_MONITORS(p) || ERTS_P_LT_MONITORS(p))) {
PrintMonitorContext context = {1, to, to_arg};
erts_print(to, to_arg,"Link list: [");
erts_link_tree_foreach(ERTS_P_LINKS(p), doit_print_link, &context);
diff --git a/erts/emulator/beam/bs_instrs.tab b/erts/emulator/beam/bs_instrs.tab
index 652460a66d..9cad2b03c5 100644
--- a/erts/emulator/beam/bs_instrs.tab
+++ b/erts/emulator/beam/bs_instrs.tab
@@ -1136,7 +1136,6 @@ i_bs_get_utf16.execute(Fail, Flags, Dst) {
}
bs_context_to_binary := ctx_to_bin.fetch.execute;
-i_bs_get_binary_all_reuse := ctx_to_bin.fetch_bin.execute;
ctx_to_bin.head() {
Eterm context;
@@ -1159,16 +1158,6 @@ ctx_to_bin.fetch(Src) {
}
}
-ctx_to_bin.fetch_bin(Src, Fail, Unit) {
- context = $Src;
- mb = ms_matchbuffer(context);
- size = mb->size - mb->offset;
- if (size % $Unit != 0) {
- $FAIL($Fail);
- }
- offs = mb->offset;
-}
-
ctx_to_bin.execute() {
Uint hole_size;
Uint orig = mb->orig;
diff --git a/erts/emulator/beam/dist.c b/erts/emulator/beam/dist.c
index ff5f766de7..8bbe6450eb 100644
--- a/erts/emulator/beam/dist.c
+++ b/erts/emulator/beam/dist.c
@@ -772,77 +772,25 @@ void init_dist(void)
#define ErtsDistOutputBuf2Binary(OB) OB->bin
-#ifdef DEBUG
-
-struct obuf_list;
-struct obuf_list {
- erts_refc_t refc;
- struct obuf_list *next;
- struct obuf_list *prev;
-};
-#define obuf_list_size sizeof(struct obuf_list)
-static struct obuf_list *erts_obuf_list = NULL;
-static erts_mtx_t erts_obuf_list_mtx;
-
-static void
-insert_obuf(struct obuf_list *obuf, erts_aint_t initial) {
- erts_mtx_lock(&erts_obuf_list_mtx);
- obuf->next = erts_obuf_list;
- obuf->prev = NULL;
- erts_refc_init(&obuf->refc, initial);
- if (erts_obuf_list)
- erts_obuf_list->prev = obuf;
- erts_obuf_list = obuf;
- erts_mtx_unlock(&erts_obuf_list_mtx);
-}
-
-static void
-remove_obuf(struct obuf_list *obuf) {
- if (erts_refc_dectest(&obuf->refc, 0) == 0) {
- erts_mtx_lock(&erts_obuf_list_mtx);
- if (obuf->prev) {
- obuf->prev->next = obuf->next;
- } else {
- erts_obuf_list = obuf->next;
- }
- if (obuf->next) obuf->next->prev = obuf->prev;
- erts_mtx_unlock(&erts_obuf_list_mtx);
- }
-}
-
-void check_obuf(void);
-void check_obuf(void) {
- erts_mtx_lock(&erts_obuf_list_mtx);
- ERTS_ASSERT(erts_obuf_list == NULL);
- erts_mtx_unlock(&erts_obuf_list_mtx);
-}
-#else
-#define insert_obuf(...)
-#define remove_obuf(...)
-#define obuf_list_size 0
-#endif
-
static ERTS_INLINE ErtsDistOutputBuf *
alloc_dist_obuf(Uint size, Uint headers)
{
int i;
ErtsDistOutputBuf *obuf;
Uint obuf_size = sizeof(ErtsDistOutputBuf)*(headers) +
- sizeof(byte)*size + obuf_list_size;
+ sizeof(byte)*size;
Binary *bin = erts_bin_drv_alloc(obuf_size);
- size += obuf_list_size;
obuf = (ErtsDistOutputBuf *) &bin->orig_bytes[size];
erts_refc_add(&bin->intern.refc, headers - 1, 1);
for (i = 0; i < headers; i++) {
obuf[i].bin = bin;
- obuf[i].extp = (byte *)&bin->orig_bytes[0] + obuf_list_size;
+ obuf[i].extp = (byte *)&bin->orig_bytes[0];
#ifdef DEBUG
obuf[i].dbg_pattern = ERTS_DIST_OUTPUT_BUF_DBG_PATTERN;
obuf[i].alloc_endp = obuf->extp + size;
ASSERT(bin == ErtsDistOutputBuf2Binary(obuf));
#endif
}
- insert_obuf((struct obuf_list*)&bin->orig_bytes[0], headers);
return obuf;
}
@@ -851,10 +799,7 @@ free_dist_obuf(ErtsDistOutputBuf *obuf)
{
Binary *bin = ErtsDistOutputBuf2Binary(obuf);
ASSERT(obuf->dbg_pattern == ERTS_DIST_OUTPUT_BUF_DBG_PATTERN);
- remove_obuf((struct obuf_list*)&bin->orig_bytes[0]);
- if (erts_refc_dectest(&bin->intern.refc, 0) == 0) {
- erts_bin_free(bin);
- }
+ erts_bin_release(bin);
}
static ERTS_INLINE Sint
@@ -1968,6 +1913,7 @@ int erts_net_message(Port *prt,
goto invalid_message;
}
reason = tuple[5];
+ edep = NULL;
}
if (is_not_ref(ref))
@@ -2014,12 +1960,14 @@ int erts_net_message(Port *prt,
}
token = NIL;
reason = tuple[4];
+ edep = NULL;
} else if (type == DOP_EXIT_TT){
if (tuple_arity != 5) {
goto invalid_message;
}
token = tuple[4];
reason = tuple[5];
+ edep = NULL;
} else if (type == DOP_PAYLOAD_EXIT) {
if (tuple_arity != 3) {
goto invalid_message;
@@ -2067,12 +2015,14 @@ int erts_net_message(Port *prt,
}
reason = tuple[4];
token = NIL;
+ edep = NULL;
} else if (type == DOP_EXIT2_TT) {
if (tuple_arity != 5) {
goto invalid_message;
}
token = tuple[4];
reason = tuple[5];
+ edep = NULL;
} else if (type == DOP_PAYLOAD_EXIT2) {
if (tuple_arity != 3) {
goto invalid_message;
@@ -2430,8 +2380,8 @@ erts_dsig_send(ErtsDSigSendContext *ctx)
case ERTS_DSIG_SEND_PHASE_FIN: {
ASSERT(ctx->obuf->extp < ctx->obuf->ext_endp);
- ASSERT(((byte*)&ctx->obuf->bin->orig_bytes[0]+obuf_list_size) <= ctx->obuf->extp - ctx->max_finalize_prepend);
- ASSERT(ctx->obuf->ext_endp <= ((byte*)ctx->obuf->bin->orig_bytes+obuf_list_size) + ctx->data_size + ctx->dhdr_ext_size);
+ ASSERT(((byte*)&ctx->obuf->bin->orig_bytes[0]) <= ctx->obuf->extp - ctx->max_finalize_prepend);
+ ASSERT(ctx->obuf->ext_endp <= ((byte*)ctx->obuf->bin->orig_bytes) + ctx->data_size + ctx->dhdr_ext_size);
ctx->data_size = ctx->obuf->ext_endp - ctx->obuf->extp;
@@ -2935,7 +2885,9 @@ erts_dist_command(Port *prt, int initial_reds)
ob = oq.first;
ASSERT(ob);
do {
+ obufsize += size_obuf(ob);
reds = erts_encode_ext_dist_header_finalize(ob, dep, flags, reds);
+ obufsize -= size_obuf(ob);
if (reds < 0)
break;
last_finalized = ob;
@@ -2974,7 +2926,9 @@ erts_dist_command(Port *prt, int initial_reds)
while (oq.first && !preempt) {
ErtsDistOutputBuf *fob;
Uint size;
+ obufsize += size_obuf(oq.first);
reds = erts_encode_ext_dist_header_finalize(oq.first, dep, flags, reds);
+ obufsize -= size_obuf(oq.first);
if (reds < 0) {
preempt = 1;
break;
@@ -3407,14 +3361,13 @@ dist_ctrl_get_data_1(BIF_ALIST_1)
{
DistEntry *dep = ERTS_PROC_GET_DIST_ENTRY(BIF_P);
const Sint initial_reds = ERTS_BIF_REDS_LEFT(BIF_P);
- Sint reds = initial_reds;
+ Sint reds = initial_reds, obufsize = 0;
ErtsDistOutputBuf *obuf;
- Eterm *hp;
+ Eterm *hp, res;
ProcBin *pb;
erts_aint_t qsize;
Uint32 conn_id, get_size;
- Eterm res;
- Uint hsz, bin_sz;
+ Uint hsz = 0, bin_sz;
if (!dep)
BIF_ERROR(BIF_P, EXC_NOTSUP);
@@ -3466,7 +3419,9 @@ dist_ctrl_get_data_1(BIF_ALIST_1)
}
obuf = dep->tmp_out_queue.first;
+ obufsize += size_obuf(obuf);
reds = erts_encode_ext_dist_header_finalize(obuf, dep, dep->flags, reds);
+ obufsize -= size_obuf(obuf);
if (reds < 0) {
erts_de_runlock(dep);
ERTS_BIF_YIELD1(bif_export[BIF_dist_ctrl_get_data_1],
@@ -3482,8 +3437,7 @@ dist_ctrl_get_data_1(BIF_ALIST_1)
erts_de_runlock(dep);
- bin_sz = obuf->ext_endp - obuf->extp;
- hsz = PROC_BIN_SIZE;
+ bin_sz = obuf->ext_endp - obuf->extp + obuf->hdr_endp - obuf->hdrp;
get_size = dep->opts & ERTS_DIST_CTRL_OPT_GET_SIZE;
if (get_size) {
@@ -3492,18 +3446,50 @@ dist_ctrl_get_data_1(BIF_ALIST_1)
hsz += BIG_UINT_HEAP_SIZE;
}
- hp = HAlloc(BIF_P, hsz);
- pb = (ProcBin *) (char *) hp;
- pb->thing_word = HEADER_PROC_BIN;
- pb->size = bin_sz;
- pb->next = MSO(BIF_P).first;
- MSO(BIF_P).first = (struct erl_off_heap_header*) pb;
- pb->val = ErtsDistOutputBuf2Binary(obuf);
- pb->bytes = (byte*) obuf->extp;
- pb->flags = 0;
- hp += PROC_BIN_SIZE;
+ if (!obuf->hdrp) {
+ hp = HAlloc(BIF_P, PROC_BIN_SIZE + hsz);
+ pb = (ProcBin *) (char *) hp;
+ pb->thing_word = HEADER_PROC_BIN;
+ pb->size = obuf->ext_endp - obuf->extp;
+ pb->next = MSO(BIF_P).first;
+ MSO(BIF_P).first = (struct erl_off_heap_header*) pb;
+ pb->val = ErtsDistOutputBuf2Binary(obuf);
+ pb->bytes = (byte*) obuf->extp;
+ pb->flags = 0;
+ res = make_binary(pb);
+ } else {
+ hp = HAlloc(BIF_P, PROC_BIN_SIZE * 2 + 4 + hsz);
+ pb = (ProcBin *) (char *) hp;
+ pb->thing_word = HEADER_PROC_BIN;
+ pb->size = obuf->ext_endp - obuf->extp;
+ pb->next = MSO(BIF_P).first;
+ MSO(BIF_P).first = (struct erl_off_heap_header*) pb;
+ pb->val = ErtsDistOutputBuf2Binary(obuf);
+ pb->bytes = (byte*) obuf->extp;
+ pb->flags = 0;
+ hp += PROC_BIN_SIZE;
+
+ res = CONS(hp, make_binary(pb), NIL);
+ hp += 2;
+
+ pb = (ProcBin *) (char *) hp;
+ pb->thing_word = HEADER_PROC_BIN;
+ pb->size = obuf->hdr_endp - obuf->hdrp;
+ pb->next = MSO(BIF_P).first;
+ MSO(BIF_P).first = (struct erl_off_heap_header*) pb;
+ pb->val = ErtsDistOutputBuf2Binary(obuf);
+ erts_refc_inc(&pb->val->intern.refc, 1);
+ pb->bytes = (byte*) obuf->hdrp;
+ pb->flags = 0;
+ hp += PROC_BIN_SIZE;
+ res = CONS(hp, make_binary(pb), res);
+ hp += 2;
+ }
+
+ obufsize += size_obuf(obuf);
+
+ qsize = erts_atomic_add_read_nob(&dep->qsize, (erts_aint_t) -obufsize);
- qsize = erts_atomic_add_read_nob(&dep->qsize, -size_obuf(obuf));
ASSERT(qsize >= 0);
if (qsize < erts_dist_buf_busy_limit/2
@@ -3518,8 +3504,6 @@ dist_ctrl_get_data_1(BIF_ALIST_1)
}
}
- res = make_binary(pb);
-
if (get_size) {
Eterm sz_term;
if (IS_USMALL(0, bin_sz))
@@ -3764,12 +3748,10 @@ int distribution_info(fmtfn_t to, void *arg) /* Called by break handler */
BIF_RETTYPE setnode_2(BIF_ALIST_2)
{
Process *net_kernel;
- Uint creation;
+ Uint32 creation;
/* valid creation ? */
- if(!term_to_Uint(BIF_ARG_2, &creation))
- goto error;
- if(creation > 3)
+ if(!term_to_Uint32(BIF_ARG_2, &creation))
goto error;
/* valid node name ? */
@@ -3813,7 +3795,7 @@ BIF_RETTYPE setnode_2(BIF_ALIST_2)
erts_proc_unlock(BIF_P, ERTS_PROC_LOCK_MAIN);
erts_thr_progress_block();
inc_no_nodes();
- erts_set_this_node(BIF_ARG_1, (Uint32) creation);
+ erts_set_this_node(BIF_ARG_1, creation);
erts_is_alive = 1;
send_nodes_mon_msgs(NULL, am_nodeup, BIF_ARG_1, am_visible, NIL);
erts_thr_progress_unblock();
@@ -4713,10 +4695,6 @@ init_nodes_monitors(void)
{
erts_mtx_init(&nodes_monitors_mtx, "nodes_monitors", NIL,
ERTS_LOCK_FLAGS_PROPERTY_STATIC | ERTS_LOCK_FLAGS_CATEGORY_DISTRIBUTION);
-#ifdef DEBUG
- erts_mtx_init(&erts_obuf_list_mtx, "sad", NIL,
- ERTS_LOCK_FLAGS_PROPERTY_STATIC | ERTS_LOCK_FLAGS_CATEGORY_DISTRIBUTION);
-#endif
nodes_monitors = NULL;
no_nodes_monitors = 0;
}
@@ -5107,3 +5085,22 @@ erts_processes_monitoring_nodes(Process *c_p)
return ctxt.res;
}
+
+static void
+print_suspended_on_de(fmtfn_t to, void *to_arg, DistEntry *dep)
+{
+ for (; dep; dep = dep->next) {
+ ErtsProcList *curr = erts_proclist_peek_first(dep->suspended);
+ while (curr) {
+ if (!is_internal_pid(curr->u.pid))
+ print_process_info(to, to_arg, curr->u.p, 0);
+ curr = erts_proclist_peek_next(dep->suspended, curr);
+ }
+ }
+}
+
+void
+erts_dist_print_procs_suspended_on_de(fmtfn_t to, void *to_arg) {
+ print_suspended_on_de(to, to_arg, erts_hidden_dist_entries);
+ print_suspended_on_de(to, to_arg, erts_visible_dist_entries);
+}
diff --git a/erts/emulator/beam/dist.h b/erts/emulator/beam/dist.h
index 5bd22cc31f..f953a2ab8c 100644
--- a/erts/emulator/beam/dist.h
+++ b/erts/emulator/beam/dist.h
@@ -54,11 +54,12 @@
#define DFLAG_DIST_MANDATORY (DFLAG_EXTENDED_REFERENCES \
| DFLAG_EXTENDED_PIDS_PORTS \
| DFLAG_UTF8_ATOMS \
- | DFLAG_NEW_FUN_TAGS)
+ | DFLAG_NEW_FUN_TAGS \
+ | DFLAG_BIG_CREATION)
/*
* Additional optimistic flags when encoding toward pending connection.
- * If remote node (erl_interface) does not supporting these then we may need
+ * If remote node (erl_interface) does not support these then we may need
* to transcode messages enqueued before connection setup was finished.
*/
#define DFLAG_DIST_HOPEFULLY (DFLAG_EXPORT_PTR_TAG \
@@ -75,7 +76,6 @@
| DFLAG_SMALL_ATOM_TAGS \
| DFLAG_UTF8_ATOMS \
| DFLAG_MAP_TAG \
- | DFLAG_BIG_CREATION \
| DFLAG_SEND_SENDER \
| DFLAG_BIG_SEQTRACE_LABELS \
| DFLAG_EXIT_PAYLOAD \
@@ -319,5 +319,6 @@ extern int erts_dsig_prepare(ErtsDSigSendContext *,
int,
int);
+void erts_dist_print_procs_suspended_on_de(fmtfn_t to, void *to_arg);
int erts_auto_connect(DistEntry* dep, Process *proc, ErtsProcLocks proc_locks);
#endif
diff --git a/erts/emulator/beam/erl_bif_info.c b/erts/emulator/beam/erl_bif_info.c
index de64f09a02..a7424bbcb8 100644
--- a/erts/emulator/beam/erl_bif_info.c
+++ b/erts/emulator/beam/erl_bif_info.c
@@ -2797,7 +2797,10 @@ BIF_RETTYPE system_info_1(BIF_ALIST_1)
} else if (BIF_ARG_1 == am_threads) {
return am_true;
} else if (BIF_ARG_1 == am_creation) {
- return make_small(erts_this_node->creation);
+ Uint hsz = 0;
+ erts_bld_uint(NULL, &hsz, erts_this_node->creation);
+ hp = hsz ? HAlloc(BIF_P, hsz) : NULL;
+ BIF_RET(erts_bld_uint(&hp, NULL, erts_this_node->creation));
} else if (BIF_ARG_1 == am_break_ignored) {
extern int ignore_break;
if (ignore_break)
@@ -4439,6 +4442,7 @@ BIF_RETTYPE erts_debug_set_internal_state_2(BIF_ALIST_2)
BIF_P->fcalls = reds;
else
BIF_P->fcalls = reds - CONTEXT_REDS;
+ BIF_P->scheduler_data->virtual_reds = 0;
}
BIF_RET(am_true);
}
diff --git a/erts/emulator/beam/erl_gc.c b/erts/emulator/beam/erl_gc.c
index 9317850d96..67a73e4d57 100644
--- a/erts/emulator/beam/erl_gc.c
+++ b/erts/emulator/beam/erl_gc.c
@@ -577,7 +577,7 @@ force_reschedule:
}
static ERTS_FORCE_INLINE Uint
-young_gen_usage(Process *p)
+young_gen_usage(Process *p, Uint *ext_msg_usage)
{
Uint hsz;
Eterm *aheap;
@@ -604,7 +604,10 @@ young_gen_usage(Process *p)
if (ERTS_SIG_IS_MSG(mp)
&& mp->data.attached
&& mp->data.attached != ERTS_MSG_COMBINED_HFRAG) {
- hsz += erts_msg_attached_data_size(mp);
+ Uint sz = erts_msg_attached_data_size(mp);
+ if (ERTS_SIG_IS_EXTERNAL_MSG(mp))
+ *ext_msg_usage += sz;
+ hsz += sz;
}
});
}
@@ -676,6 +679,7 @@ garbage_collect(Process* p, ErlHeapFragment *live_hf_end,
{
Uint reclaimed_now = 0;
Uint ygen_usage;
+ Uint ext_msg_usage = 0;
Eterm gc_trace_end_tag;
int reds;
ErtsMonotonicTime start_time;
@@ -698,7 +702,7 @@ garbage_collect(Process* p, ErlHeapFragment *live_hf_end,
return delay_garbage_collection(p, live_hf_end, need, fcalls);
}
- ygen_usage = max_young_gen_usage ? max_young_gen_usage : young_gen_usage(p);
+ ygen_usage = max_young_gen_usage ? max_young_gen_usage : young_gen_usage(p, &ext_msg_usage);
if (!ERTS_SCHEDULER_IS_DIRTY(esdp)) {
check_for_possibly_long_gc(p, ygen_usage);
@@ -739,7 +743,7 @@ garbage_collect(Process* p, ErlHeapFragment *live_hf_end,
trace_gc(p, am_gc_minor_start, need, THE_NON_VALUE);
}
DTRACE2(gc_minor_start, pidbuf, need);
- reds = minor_collection(p, live_hf_end, need, objv, nobj,
+ reds = minor_collection(p, live_hf_end, need + ext_msg_usage, objv, nobj,
ygen_usage, &reclaimed_now);
DTRACE2(gc_minor_end, pidbuf, reclaimed_now);
if (reds == -1) {
@@ -764,7 +768,7 @@ do_major_collection:
trace_gc(p, am_gc_major_start, need, THE_NON_VALUE);
}
DTRACE2(gc_major_start, pidbuf, need);
- reds = major_collection(p, live_hf_end, need, objv, nobj,
+ reds = major_collection(p, live_hf_end, need + ext_msg_usage, objv, nobj,
ygen_usage, &reclaimed_now);
if (ERTS_SCHEDULER_IS_DIRTY(esdp))
p->flags &= ~(F_DIRTY_MAJOR_GC|F_DIRTY_MINOR_GC);
@@ -1101,6 +1105,7 @@ erts_garbage_collect_literals(Process* p, Eterm* literals,
Eterm* old_htop;
Uint n;
Uint ygen_usage = 0;
+ Uint ext_msg_usage = 0;
struct erl_off_heap_header** prev = NULL;
Sint64 reds;
int hibernated = !!(p->flags & F_HIBERNATED);
@@ -1118,7 +1123,7 @@ erts_garbage_collect_literals(Process* p, Eterm* literals,
p->flags &= ~F_DIRTY_CLA;
else {
Uint size = byte_lit_size/sizeof(Uint);
- ygen_usage = young_gen_usage(p);
+ ygen_usage = young_gen_usage(p, &ext_msg_usage);
if (hibernated)
size = size*2 + 3*ygen_usage;
else
@@ -1130,7 +1135,7 @@ erts_garbage_collect_literals(Process* p, Eterm* literals,
}
}
- reds = (Sint64) garbage_collect(p, ERTS_INVALID_HFRAG_PTR, 0,
+ reds = (Sint64) garbage_collect(p, ERTS_INVALID_HFRAG_PTR, ext_msg_usage,
p->arg_reg, p->arity, fcalls,
ygen_usage);
if (ERTS_PROC_IS_EXITING(p)) {
@@ -1348,6 +1353,9 @@ minor_collection(Process* p, ErlHeapFragment *live_hf_end,
Eterm *mature = p->abandoned_heap ? p->abandoned_heap : p->heap;
Uint mature_size = p->high_water - mature;
Uint size_before = ygen_usage;
+#ifdef DEBUG
+ Uint debug_tmp = 0;
+#endif
/*
* Check if we have gone past the max heap size limit
@@ -1484,7 +1492,7 @@ minor_collection(Process* p, ErlHeapFragment *live_hf_end,
process from there */
ASSERT(!MAX_HEAP_SIZE_GET(p) ||
!(MAX_HEAP_SIZE_FLAGS_GET(p) & MAX_HEAP_SIZE_KILL) ||
- MAX_HEAP_SIZE_GET(p) > (young_gen_usage(p) +
+ MAX_HEAP_SIZE_GET(p) > (young_gen_usage(p, &debug_tmp) +
(OLD_HEND(p) - OLD_HEAP(p)) +
(HEAP_END(p) - HEAP_TOP(p))));
diff --git a/erts/emulator/beam/erl_init.c b/erts/emulator/beam/erl_init.c
index 82d5140d1c..12750b9aa6 100644
--- a/erts/emulator/beam/erl_init.c
+++ b/erts/emulator/beam/erl_init.c
@@ -2417,17 +2417,12 @@ erts_exit_vv(int n, int flush_async, char *fmt, va_list args1, va_list args2)
erts_exit_epilogue();
}
-void check_obuf(void);
__decl_noreturn void __noreturn erts_exit_epilogue(void)
{
int n = erts_exit_code;
sys_tty_reset(n);
-#ifdef DEBUG
- check_obuf();
-#endif
-
if (n == ERTS_INTR_EXIT)
exit(0);
else if (n == ERTS_DUMP_EXIT)
diff --git a/erts/emulator/beam/erl_lock_check.c b/erts/emulator/beam/erl_lock_check.c
index 39eabb6710..3aab4828cc 100644
--- a/erts/emulator/beam/erl_lock_check.c
+++ b/erts/emulator/beam/erl_lock_check.c
@@ -164,8 +164,7 @@ static erts_lc_lock_order_t erts_lock_order[] = {
{ "os_monotonic_time", NULL },
{ "erts_alloc_hard_debug", NULL },
{ "hard_dbg_mseg", NULL },
- { "erts_mmap", NULL },
- { "sad", NULL}
+ { "erts_mmap", NULL }
};
#define ERTS_LOCK_ORDER_SIZE \
diff --git a/erts/emulator/beam/erl_message.c b/erts/emulator/beam/erl_message.c
index e350a20339..2a0fb9e2aa 100644
--- a/erts/emulator/beam/erl_message.c
+++ b/erts/emulator/beam/erl_message.c
@@ -1137,10 +1137,28 @@ change_to_off_heap:
return res;
}
-void erts_factory_proc_init(ErtsHeapFactory* factory,
- Process* p)
+void erts_factory_proc_init(ErtsHeapFactory* factory, Process* p)
{
- erts_factory_proc_prealloc_init(factory, p, HEAP_LIMIT(p) - HEAP_TOP(p));
+ /* This function does not use HAlloc to allocate on the heap
+ as we do not want to use INIT_HEAP_MEM on the allocated
+ heap as that completely destroys the DEBUG emulators
+ performance. */
+ ErlHeapFragment *bp = p->mbuf;
+ factory->mode = FACTORY_HALLOC;
+ factory->p = p;
+ factory->hp_start = HEAP_TOP(p);
+ factory->hp = factory->hp_start;
+ factory->hp_end = HEAP_LIMIT(p);
+ factory->off_heap = &p->off_heap;
+ factory->message = NULL;
+ factory->off_heap_saved.first = p->off_heap.first;
+ factory->off_heap_saved.overhead = p->off_heap.overhead;
+ factory->heap_frags_saved = bp;
+ factory->heap_frags_saved_used = bp ? bp->used_size : 0;
+ factory->heap_frags = NULL; /* not used */
+ factory->alloc_type = 0; /* not used */
+
+ HEAP_TOP(p) = HEAP_LIMIT(p);
}
void erts_factory_proc_prealloc_init(ErtsHeapFactory* factory,
diff --git a/erts/emulator/beam/erl_message.h b/erts/emulator/beam/erl_message.h
index e5f623a370..5bd25737a7 100644
--- a/erts/emulator/beam/erl_message.h
+++ b/erts/emulator/beam/erl_message.h
@@ -22,6 +22,7 @@
#define __ERL_MESSAGE_H__
#include "sys.h"
+#include "erl_vm.h"
#define ERTS_PROC_SIG_QUEUE_TYPE_ONLY
#include "erl_proc_sig_queue.h"
#undef ERTS_PROC_SIG_QUEUE_TYPE_ONLY
@@ -117,6 +118,7 @@ erts_produce_heap(ErtsHeapFactory* factory, Uint need, Uint xtra)
}
res = factory->hp;
factory->hp += need;
+ INIT_HEAP_MEM(res, need);
return res;
}
diff --git a/erts/emulator/beam/erl_nif.h b/erts/emulator/beam/erl_nif.h
index a599511c78..cc389a093f 100644
--- a/erts/emulator/beam/erl_nif.h
+++ b/erts/emulator/beam/erl_nif.h
@@ -59,12 +59,17 @@
*/
#define ERL_NIF_MAJOR_VERSION 2
#define ERL_NIF_MINOR_VERSION 15
+
/*
- * WHEN CHANGING INTERFACE VERSION, also replace erts version below
- * with ticket syntax like "erts-@OTP-12345@", or a temporary placeholder
- * between two @ like "erts-@MyName@", if you don't know what a ticket is.
+ * WHEN CHANGING INTERFACE VERSION, also replace erts version below with
+ * a ticket number e.g. "erts-@OTP-12345@". The syntax is the same as for
+ * runtime dependencies so multiple tickets should be separated with ":", e.g.
+ * "erts-@OTP-12345:OTP-54321@".
+ *
+ * If you're not on the OTP team, you should use a placeholder like
+ * erts-@MyName@ instead.
*/
-#define ERL_NIF_MIN_ERTS_VERSION "erts-@OTP-15095 OTP-15640@ (OTP-22)"
+#define ERL_NIF_MIN_ERTS_VERSION "erts-@OTP-15095:OTP-15640@"
/*
* The emulator will refuse to load a nif-lib with a major version
diff --git a/erts/emulator/beam/erl_node_tables.c b/erts/emulator/beam/erl_node_tables.c
index 1adb101e30..49dea8919b 100644
--- a/erts/emulator/beam/erl_node_tables.c
+++ b/erts/emulator/beam/erl_node_tables.c
@@ -977,7 +977,7 @@ static void print_node(void *venp, void *vpndp)
if(pndp->sysname == NIL) {
erts_print(pndp->to, pndp->to_arg, "Name: %T ", enp->sysname);
}
- erts_print(pndp->to, pndp->to_arg, " %d", enp->creation);
+ erts_print(pndp->to, pndp->to_arg, " %u", enp->creation);
#ifdef DEBUG
erts_print(pndp->to, pndp->to_arg, " (refc=%ld)",
erts_refc_read(&enp->refc, 0));
@@ -1020,7 +1020,7 @@ void erts_print_node_info(fmtfn_t to,
/* ----------------------------------------------------------------------- */
void
-erts_set_this_node(Eterm sysname, Uint creation)
+erts_set_this_node(Eterm sysname, Uint32 creation)
{
ERTS_LC_ASSERT(erts_thr_progress_is_blocking());
ASSERT(2 <= de_refc_read(erts_this_dist_entry, 2));
@@ -2295,7 +2295,7 @@ reference_table_term(Uint **hpp, ErlOffHeap *ohp, Uint *szp)
tup = MK_2TUP(AM_ets, drp->id);
}
else {
- ASSERT(!drp->ctrl_ref && drp->node_ref && !drp->signal_ref);
+ ASSERT(!drp->ctrl_ref && (drp->node_ref || drp->sequence_ref) && !drp->signal_ref);
ASSERT(is_atom(drp->id));
tup = MK_2TUP(drp->id, MK_UINT(drp->creation));
tup = MK_2TUP(AM_node, tup);
diff --git a/erts/emulator/beam/erl_node_tables.h b/erts/emulator/beam/erl_node_tables.h
index 8153699596..c434926142 100644
--- a/erts/emulator/beam/erl_node_tables.h
+++ b/erts/emulator/beam/erl_node_tables.h
@@ -258,7 +258,7 @@ void erts_set_dist_entry_pending(DistEntry *);
void erts_set_dist_entry_connected(DistEntry *, Eterm, Uint);
ErlNode *erts_find_or_insert_node(Eterm, Uint32, Eterm);
void erts_schedule_delete_node(ErlNode *);
-void erts_set_this_node(Eterm, Uint);
+void erts_set_this_node(Eterm, Uint32);
Uint erts_node_table_size(void);
void erts_init_node_tables(int);
void erts_node_table_info(fmtfn_t, void *);
diff --git a/erts/emulator/beam/erl_proc_sig_queue.c b/erts/emulator/beam/erl_proc_sig_queue.c
index bd59c4afa3..4e9f177e51 100644
--- a/erts/emulator/beam/erl_proc_sig_queue.c
+++ b/erts/emulator/beam/erl_proc_sig_queue.c
@@ -611,7 +611,8 @@ proc_queue_signal(Process *c_p, Eterm pid, ErtsSignal *sig, int op)
#endif
return 1;
}
- ASSERT(esdp->pending_signal.dbg_from == esdp->current_process);
+ ASSERT(esdp->pending_signal.dbg_from == esdp->current_process ||
+ esdp->pending_signal.dbg_from == esdp->free_process);
if (pend_sig != sig) {
/* Switch them and send previously pending signal instead */
Eterm pend_to = esdp->pending_signal.to;
@@ -3973,6 +3974,9 @@ clear_seq_trace_token(ErtsMessage *sig)
case ERTS_MON_TYPE_PROC:
case ERTS_MON_TYPE_DIST_PROC:
case ERTS_MON_TYPE_NODE:
+ case ERTS_MON_TYPE_NODES:
+ case ERTS_MON_TYPE_SUSPEND:
+ case ERTS_MON_TYPE_TIME_OFFSET:
break;
default:
ERTS_INTERNAL_ERROR("Unexpected sig type");
@@ -3989,6 +3993,11 @@ clear_seq_trace_token(ErtsMessage *sig)
case ERTS_SIG_Q_OP_LINK:
case ERTS_SIG_Q_OP_UNLINK:
case ERTS_SIG_Q_OP_TRACE_CHANGE_STATE:
+ case ERTS_SIG_Q_OP_GROUP_LEADER:
+ case ERTS_SIG_Q_OP_IS_ALIVE:
+ case ERTS_SIG_Q_OP_PROCESS_INFO:
+ case ERTS_SIG_Q_OP_SYNC_SUSPEND:
+ case ERTS_SIG_Q_OP_RPC:
break;
default:
diff --git a/erts/emulator/beam/erl_process.c b/erts/emulator/beam/erl_process.c
index f34289339f..9e662632b4 100644
--- a/erts/emulator/beam/erl_process.c
+++ b/erts/emulator/beam/erl_process.c
@@ -12090,9 +12090,11 @@ erts_proc_exit_handle_dist_monitor(ErtsMonitor *mon, void *vctxt, Sint reds)
ErtsDSigSendContext ctx;
ErtsMonLnkDist *dist;
DistEntry *dep;
- Eterm watcher;
+ Eterm watcher, ref, *hp;
ErtsMonitorData *mdp = NULL;
Eterm watched;
+ Uint watcher_sz, ref_sz;
+ ErtsHeapFactory factory;
ASSERT(erts_monitor_is_target(mon) && mon->type == ERTS_MON_TYPE_DIST_PROC);
@@ -12124,10 +12126,18 @@ erts_proc_exit_handle_dist_monitor(ErtsMonitor *mon, void *vctxt, Sint reds)
case ERTS_DSIG_PREP_CONNECTED:
if (dist->connection_id != ctx.connection_id)
break;
+ erts_factory_proc_init(&factory, c_p);
+ watcher_sz = size_object(watcher);
+ hp = erts_produce_heap(&factory, watcher_sz, 0);
+ watcher = copy_struct(watcher, watcher_sz, &hp, factory.off_heap);
+ ref_sz = size_object(mdp->ref);
+ hp = erts_produce_heap(&factory, ref_sz, 0);
+ ref = copy_struct(mdp->ref, ref_sz, &hp, factory.off_heap);
+ erts_factory_close(&factory);
code = erts_dsig_send_m_exit(&ctx,
watcher,
watched,
- mdp->ref,
+ ref,
reason);
switch (code) {
case ERTS_DSIG_SEND_CONTINUE:
@@ -12332,13 +12342,15 @@ erts_proc_exit_handle_dist_link(ErtsLink *lnk, void *vctxt, Sint reds)
{
ErtsProcExitContext *ctxt = (ErtsProcExitContext *) vctxt;
Process *c_p = ctxt->c_p;
- Eterm reason = ctxt->reason;
+ Eterm reason = ctxt->reason, item, *hp;
+ Uint item_sz;
int code;
ErtsDSigSendContext ctx;
ErtsMonLnkDist *dist;
DistEntry *dep;
ErtsLink *dlnk;
ErtsLinkData *ldp = NULL;
+ ErtsHeapFactory factory;
ASSERT(lnk->type == ERTS_LNK_TYPE_DIST_PROC);
dlnk = erts_link_to_other(lnk, &ldp);
@@ -12365,9 +12377,14 @@ erts_proc_exit_handle_dist_link(ErtsLink *lnk, void *vctxt, Sint reds)
case ERTS_DSIG_PREP_CONNECTED:
if (dist->connection_id != ctx.connection_id)
break;
+ erts_factory_proc_init(&factory, c_p);
+ item_sz = size_object(lnk->other.item);
+ hp = erts_produce_heap(&factory, item_sz, 0);
+ item = copy_struct(lnk->other.item, item_sz, &hp, factory.off_heap);
+ erts_factory_close(&factory);
code = erts_dsig_send_exit_tt(&ctx,
c_p->common.id,
- lnk->other.item,
+ item,
reason,
SEQ_TRACE_TOKEN(c_p));
switch (code) {
@@ -12584,6 +12601,8 @@ erts_continue_exit_process(Process *p)
if (p->u.terminate) {
trap_state = p->u.terminate;
+ /* Re-set the reason as it may have been gc:ed */
+ trap_state->reason = p->fvalue;
} else {
trap_state->phase = ERTS_CONTINUE_EXIT_TIMERS;
trap_state->reason = p->fvalue;
@@ -12661,11 +12680,11 @@ restart:
p->flags &= ~F_USING_DB;
}
- erts_set_gc_state(p, 1);
-
trap_state->phase = ERTS_CONTINUE_EXIT_CLEAN_SYS_TASKS;
case ERTS_CONTINUE_EXIT_CLEAN_SYS_TASKS:
-
+
+ /* We enable GC again as it can produce more sys-tasks */
+ erts_set_gc_state(p, 1);
state = erts_atomic32_read_acqb(&p->state);
if ((state & ERTS_PSFLG_SYS_TASKS) || p->dirty_sys_tasks) {
reds -= cleanup_sys_tasks(p, state, reds);
@@ -12788,6 +12807,9 @@ restart:
erts_deref_dist_entry(trap_state->dep);
}
+ /* Disable GC so that reason does not get moved */
+ erts_set_gc_state(p, 0);
+
trap_state->pectxt.c_p = p;
trap_state->pectxt.reason = trap_state->reason;
trap_state->pectxt.dist_links = NULL;
@@ -12872,13 +12894,13 @@ restart:
switch (result) {
case ERTS_DSIG_SEND_OK:
case ERTS_DSIG_SEND_TOO_LRG: /*SEND_SYSTEM_LIMIT*/
- case ERTS_DSIG_SEND_YIELD: /*SEND_YIELD_RETURN*/
break;
+ case ERTS_DSIG_SEND_YIELD: /*SEND_YIELD_RETURN*/
case ERTS_DSIG_SEND_CONTINUE: { /*SEND_YIELD_CONTINUE*/
goto yield;
}
}
- erts_set_gc_state(p, 1);
+
trap_state->pectxt.dist_state = NIL;
if (reds <= 0)
goto yield;
@@ -12917,11 +12939,12 @@ restart:
* From this point on we are no longer allowed to yield
* this process.
*/
-
#ifdef DEBUG
yield_allowed = 0;
#endif
+ erts_set_gc_state(p, 1);
+
/* Set state to not active as we don't want this process
to be scheduled in again after this. */
state = erts_atomic32_read_band_relb(&p->state,
@@ -12960,7 +12983,7 @@ restart:
erts_free(ERTS_ALC_T_CONT_EXIT_TRAP, trap_state);
p->u.terminate = NULL;
}
-
+
ERTS_CHK_HAVE_ONLY_MAIN_PROC_LOCK(p);
if (IS_TRACED_FL(p, F_TRACE_SCHED_EXIT))
diff --git a/erts/emulator/beam/erl_process.h b/erts/emulator/beam/erl_process.h
index 4ffa022d5c..711b73417d 100644
--- a/erts/emulator/beam/erl_process.h
+++ b/erts/emulator/beam/erl_process.h
@@ -1322,9 +1322,6 @@ ERTS_GLB_INLINE void erts_heap_frag_shrink(Process* p, Eterm* hp)
#endif /* inline */
Eterm* erts_heap_alloc(Process* p, Uint need, Uint xtra);
-#ifdef CHECK_FOR_HOLES
-Eterm* erts_set_hole_marker(Eterm* ptr, Uint sz);
-#endif
extern erts_rwmtx_t erts_cpu_bind_rwmtx;
/* If any of the erts_system_monitor_* variables are set (enabled),
diff --git a/erts/emulator/beam/erl_process_dump.c b/erts/emulator/beam/erl_process_dump.c
index a164ed543e..71262061dd 100644
--- a/erts/emulator/beam/erl_process_dump.c
+++ b/erts/emulator/beam/erl_process_dump.c
@@ -121,12 +121,14 @@ Uint erts_process_memory(Process *p, int include_sigs_in_transit)
size += sizeof(Process);
- erts_link_tree_foreach(ERTS_P_LINKS(p),
- link_size, (void *) &size);
- erts_monitor_tree_foreach(ERTS_P_MONITORS(p),
- monitor_size, (void *) &size);
- erts_monitor_list_foreach(ERTS_P_LT_MONITORS(p),
- monitor_size, (void *) &size);
+ if ((erts_atomic32_read_nob(&p->state) & ERTS_PSFLG_EXITING) == 0) {
+ erts_link_tree_foreach(ERTS_P_LINKS(p),
+ link_size, (void *) &size);
+ erts_monitor_tree_foreach(ERTS_P_MONITORS(p),
+ monitor_size, (void *) &size);
+ erts_monitor_list_foreach(ERTS_P_LT_MONITORS(p),
+ monitor_size, (void *) &size);
+ }
size += (p->heap_sz + p->mbuf_sz) * sizeof(Eterm);
if (p->abandoned_heap)
size += (p->hend - p->heap) * sizeof(Eterm);
diff --git a/erts/emulator/beam/erl_utils.h b/erts/emulator/beam/erl_utils.h
index 880febba8b..430ac305c5 100644
--- a/erts/emulator/beam/erl_utils.h
+++ b/erts/emulator/beam/erl_utils.h
@@ -69,7 +69,6 @@ int erts_fit_in_bits_int32(Sint32);
int erts_fit_in_bits_uint(Uint);
Sint erts_list_length(Eterm);
int erts_is_builtin(Eterm, Eterm, int);
-Uint32 block_hash(byte *, unsigned, Uint32);
Uint32 make_hash2(Eterm);
Uint32 make_hash(Eterm);
Uint32 make_internal_hash(Eterm, Uint32 salt);
diff --git a/erts/emulator/beam/erl_vm.h b/erts/emulator/beam/erl_vm.h
index 35eae18394..e623148587 100644
--- a/erts/emulator/beam/erl_vm.h
+++ b/erts/emulator/beam/erl_vm.h
@@ -67,9 +67,10 @@
(unsigned long)HEAP_TOP(p),(sz),__FILE__,__LINE__)), \
*/
# ifdef CHECK_FOR_HOLES
-# define INIT_HEAP_MEM(p,sz) erts_set_hole_marker(HEAP_TOP(p), (sz))
+Eterm* erts_set_hole_marker(Eterm* ptr, Uint sz);
+# define INIT_HEAP_MEM(p,sz) erts_set_hole_marker(p, (sz))
# else
-# define INIT_HEAP_MEM(p,sz) sys_memset(HEAP_TOP(p),0x01,(sz)*sizeof(Eterm*))
+# define INIT_HEAP_MEM(p,sz) sys_memset(p,0x01,(sz)*sizeof(Eterm*))
# endif
#else
# define INIT_HEAP_MEM(p,sz) ((void)0)
@@ -91,7 +92,7 @@
ErtsHAllocLockCheck(p), \
(IS_FORCE_HEAP_FRAGS || (((HEAP_LIMIT(p) - HEAP_TOP(p)) < (sz))) \
? erts_heap_alloc((p),(sz),(xtra)) \
- : (INIT_HEAP_MEM(p,sz), \
+ : (INIT_HEAP_MEM(HEAP_TOP(p),sz), \
HEAP_TOP(p) = HEAP_TOP(p) + (sz), HEAP_TOP(p) - (sz))))
#define HAlloc(P, SZ) HAllocX(P,SZ,0)
diff --git a/erts/emulator/beam/external.c b/erts/emulator/beam/external.c
index 73eae614fa..471c1c3938 100644
--- a/erts/emulator/beam/external.c
+++ b/erts/emulator/beam/external.c
@@ -51,18 +51,17 @@
#define MAX_STRING_LEN 0xffff
-/* MAX value for the creation field in pid, port and reference
- for the local node and for the current external format.
-
- Larger creation values than this are allowed in external pid, port and refs
- encoded with NEW_PID_EXT, NEW_PORT_EXT and NEWER_REFERENCE_EXT.
- The point here is to prepare for future upgrade to 32-bit creation.
- OTP-19 (erts-8.0) can handle big creation values from other (newer) nodes,
- but do not use big creation values for the local node yet,
- as we still may have to communicate with older nodes.
+/*
+ * MAX value for the creation field in pid, port and reference
+ * for the old PID_EXT, PORT_EXT, REFERENCE_EXT and NEW_REFERENCE_EXT.
+ * Older nodes (OTP 19-21) will send us these so we must be able to decode them.
+ *
+ * From OTP 22 DFLAG_BIG_CREATION is mandatory so this node will always
+ * encode with new big 32-bit creations using NEW_PID_EXT, NEW_PORT_EXT
+ * and NEWER_REFERENCE_EXT.
*/
-#define ERTS_MAX_LOCAL_CREATION (3)
-#define is_valid_creation(Cre) ((unsigned)(Cre) <= ERTS_MAX_LOCAL_CREATION)
+#define ERTS_MAX_TINY_CREATION (3)
+#define is_tiny_creation(Cre) ((unsigned)(Cre) <= ERTS_MAX_TINY_CREATION)
#undef ERTS_DEBUG_USE_DIST_SEP
#ifdef DEBUG
@@ -2380,7 +2379,8 @@ enc_pid(ErtsAtomCacheMap *acmp, Eterm pid, byte* ep, Uint32 dflags)
Eterm sysname = ((is_internal_pid(pid) && (dflags & DFLAG_INTERNAL_TAGS))
? INTERNAL_LOCAL_SYSNAME : pid_node_name(pid));
Uint32 creation = pid_creation(pid);
- byte* tagp = ep++;
+
+ *ep++ = NEW_PID_EXT;
/* insert atom here containing host and sysname */
ep = enc_atom(acmp, sysname, ep, dflags);
@@ -2392,15 +2392,8 @@ enc_pid(ErtsAtomCacheMap *acmp, Eterm pid, byte* ep, Uint32 dflags)
ep += 4;
put_int32(os, ep);
ep += 4;
- if (creation <= ERTS_MAX_LOCAL_CREATION) {
- *tagp = PID_EXT;
- *ep++ = creation;
- } else {
- ASSERT(is_external_pid(pid));
- *tagp = NEW_PID_EXT;
- put_int32(creation, ep);
- ep += 4;
- }
+ put_int32(creation, ep);
+ ep += 4;
return ep;
}
@@ -2520,7 +2513,7 @@ dec_pid(ErtsDistExternal *edep, ErtsHeapFactory* factory, byte* ep,
if (tag == PID_EXT) {
cre = get_int8(ep);
ep += 1;
- if (!is_valid_creation(cre)) {
+ if (!is_tiny_creation(cre)) {
return NULL;
}
} else {
@@ -2781,25 +2774,18 @@ enc_term_int(TTBEncodeContext* ctx, ErtsAtomCacheMap *acmp, Eterm obj, byte* ep,
Eterm sysname = (((dflags & DFLAG_INTERNAL_TAGS) && is_internal_ref(obj))
? INTERNAL_LOCAL_SYSNAME : ref_node_name(obj));
Uint32 creation = ref_creation(obj);
- byte* tagp = ep++;
ASSERT(dflags & DFLAG_EXTENDED_REFERENCES);
erts_magic_ref_save_bin(obj);
+ *ep++ = NEWER_REFERENCE_EXT;
i = ref_no_numbers(obj);
put_int16(i, ep);
ep += 2;
ep = enc_atom(acmp, sysname, ep, dflags);
- if (creation <= ERTS_MAX_LOCAL_CREATION) {
- *tagp = NEW_REFERENCE_EXT;
- *ep++ = creation;
- } else {
- ASSERT(is_external_ref(obj));
- *tagp = NEWER_REFERENCE_EXT;
- put_int32(creation, ep);
- ep += 4;
- }
+ put_int32(creation, ep);
+ ep += 4;
ref_num = ref_numbers(obj);
for (j = 0; j < i; j++) {
put_int32(ref_num[j], ep);
@@ -2812,21 +2798,14 @@ enc_term_int(TTBEncodeContext* ctx, ErtsAtomCacheMap *acmp, Eterm obj, byte* ep,
Eterm sysname = (((dflags & DFLAG_INTERNAL_TAGS) && is_internal_port(obj))
? INTERNAL_LOCAL_SYSNAME : port_node_name(obj));
Uint32 creation = port_creation(obj);
- byte* tagp = ep++;
+ *ep++ = NEW_PORT_EXT;
ep = enc_atom(acmp, sysname, ep, dflags);
j = port_number(obj);
put_int32(j, ep);
ep += 4;
- if (creation <= ERTS_MAX_LOCAL_CREATION) {
- *tagp = PORT_EXT;
- *ep++ = creation;
- } else {
- ASSERT(is_external_port(obj));
- *tagp = NEW_PORT_EXT;
- put_int32(creation, ep);
- ep += 4;
- }
+ put_int32(creation, ep);
+ ep += 4;
break;
}
case LIST_DEF:
@@ -3521,7 +3500,7 @@ dec_term_atom_common:
if (tag == PORT_EXT) {
cre = get_int8(ep);
ep++;
- if (!is_valid_creation(cre)) {
+ if (!is_tiny_creation(cre)) {
goto error;
}
}
@@ -3568,7 +3547,7 @@ dec_term_atom_common:
cre = get_int8(ep);
ep += 1;
- if (!is_valid_creation(cre)) {
+ if (!is_tiny_creation(cre)) {
goto error;
}
goto ref_ext_common;
@@ -3582,7 +3561,7 @@ dec_term_atom_common:
cre = get_int8(ep);
ep += 1;
- if (!is_valid_creation(cre)) {
+ if (!is_tiny_creation(cre)) {
goto error;
}
r0 = get_int32(ep);
@@ -3600,7 +3579,7 @@ dec_term_atom_common:
cre = get_int32(ep);
ep += 4;
- r0 = get_int32(ep); /* allow full word */
+ r0 = get_int32(ep);
ep += 4;
ref_ext_common: {
@@ -3611,6 +3590,13 @@ dec_term_atom_common:
node = dec_get_node(sysname, cre, make_boxed(hp));
if(node == erts_this_node) {
+ if (r0 >= MAX_REFERENCE) {
+ /*
+ * Must reject local refs with more than 18 bits
+ * in first word as magic ref table relies on it.
+ */
+ goto error;
+ }
rtp = (ErtsORefThing *) hp;
ref_num = &rtp->num[0];
@@ -4273,30 +4259,21 @@ encode_size_struct_int(TTBSizeContext* ctx, ErtsAtomCacheMap *acmp, Eterm obj,
result += 1 + 4 + 1 + i; /* tag,size,sign,digits */
break;
case EXTERNAL_PID_DEF:
- if (external_pid_creation(obj) > ERTS_MAX_LOCAL_CREATION)
- result += 3;
- /*fall through*/
case PID_DEF:
result += (1 + encode_size_struct2(acmp, pid_node_name(obj), dflags) +
- 4 + 4 + 1);
+ 4 + 4 + 4);
break;
case EXTERNAL_REF_DEF:
- if (external_ref_creation(obj) > ERTS_MAX_LOCAL_CREATION)
- result += 3;
- /*fall through*/
case REF_DEF:
ASSERT(dflags & DFLAG_EXTENDED_REFERENCES);
i = ref_no_numbers(obj);
result += (1 + 2 + encode_size_struct2(acmp, ref_node_name(obj), dflags) +
- 1 + 4*i);
+ 4 + 4*i);
break;
case EXTERNAL_PORT_DEF:
- if (external_port_creation(obj) > ERTS_MAX_LOCAL_CREATION)
- result += 3;
- /*fall through*/
case PORT_DEF:
result += (1 + encode_size_struct2(acmp, port_node_name(obj), dflags) +
- 4 + 1);
+ 4 + 4);
break;
case LIST_DEF: {
int is_str = is_external_string(obj, &m);
diff --git a/erts/emulator/beam/msg_instrs.tab b/erts/emulator/beam/msg_instrs.tab
index 6f8d1469ef..b08466c830 100644
--- a/erts/emulator/beam/msg_instrs.tab
+++ b/erts/emulator/beam/msg_instrs.tab
@@ -105,6 +105,7 @@ i_loop_rec(Dest) {
$SET_CP_I_ABS(I);
c_p->arity = 0;
c_p->current = NULL;
+ c_p->fcalls = FCALLS;
FCALLS -= erts_proc_sig_receive_helper(c_p, FCALLS, neg_o_reds,
&msgp, &get_out);
SWAPIN;
diff --git a/erts/emulator/beam/ops.tab b/erts/emulator/beam/ops.tab
index 6832e65b1b..7a125b0f67 100644
--- a/erts/emulator/beam/ops.tab
+++ b/erts/emulator/beam/ops.tab
@@ -338,7 +338,7 @@ swap_temp R1 R2 Tmp | line Loc | apply Live | is_killed_apply(Tmp, Live) => \
swap_temp R1 R2 Tmp | line Loc | apply_last Live D | is_killed_apply(Tmp, Live) => \
swap R1 R2 | line Loc | apply_last Live D
-swap_temp R1 R2 Tmp | line Loc | call_fun Live | is_killed(Tmp, Live) => \
+swap_temp R1 R2 Tmp | line Loc | call_fun Live | is_killed_by_call_fun(Tmp, Live) => \
swap R1 R2 | line Loc | call_fun Live
swap_temp R1 R2 Tmp | make_fun2 OldIndex=u | is_killed_by_make_fun(Tmp, OldIndex) => \
swap R1 R2 | make_fun2 OldIndex
@@ -1262,7 +1262,6 @@ bs_get_binary2 Fail=f Ms=xy Live=u Sz=sq Unit=u Flags=u Dst=d => \
i_bs_get_binary_imm2 xy f? t W t d
i_bs_get_binary2 xy f t? s t d
i_bs_get_binary_all2 xy f? t t d
-i_bs_get_binary_all_reuse xy f? t
# Fetching float from binaries.
bs_get_float2 Fail=f Ms=xy Live=u Sz=s Unit=u Flags=u Dst=d => \
diff --git a/erts/emulator/beam/utils.c b/erts/emulator/beam/utils.c
index 36cfe0548e..0bbae65e28 100644
--- a/erts/emulator/beam/utils.c
+++ b/erts/emulator/beam/utils.c
@@ -1069,11 +1069,11 @@ do { \
#define HCONST 0x9e3779b9UL /* the golden ratio; an arbitrary value */
-Uint32
-block_hash(byte *k, unsigned length, Uint32 initval)
+static Uint32
+block_hash(byte *k, Uint length, Uint32 initval)
{
Uint32 a,b,c;
- unsigned len;
+ Uint len;
/* Set up the internal state */
len = length;
@@ -1749,7 +1749,7 @@ make_internal_hash(Eterm term, Uint32 salt)
case SUB_BINARY_SUBTAG:
{
byte* bptr;
- unsigned sz = binary_size(term);
+ Uint sz = binary_size(term);
Uint32 con = HCONST_13 + hash;
Uint bitoffs;
Uint bitsize;
diff --git a/erts/emulator/sys/common/erl_poll.c b/erts/emulator/sys/common/erl_poll.c
index c71d23f58c..9662996039 100644
--- a/erts/emulator/sys/common/erl_poll.c
+++ b/erts/emulator/sys/common/erl_poll.c
@@ -2354,6 +2354,7 @@ uint32_t epoll_events(int kp_fd, int fd)
fprintf(stderr,"failed to parse file %s on line %d, errno = %d\n", fname,
line,
errno);
+ fclose(f);
return 0;
}
if (fd == ev_fd) {
@@ -2408,6 +2409,7 @@ ERTS_POLL_EXPORT(erts_poll_get_selected_events)(ErtsPollSet *ps,
if (fscanf(f,"pos:\t%x\nflags:\t%x", &pos, &flags) != 2) {
fprintf(stderr,"failed to parse file %s, errno = %d\n", fname, errno);
ASSERT(0);
+ fclose(f);
return;
}
if (fscanf(f,"\nmnt_id:\t%x\n", &mnt_id));
@@ -2422,6 +2424,7 @@ ERTS_POLL_EXPORT(erts_poll_get_selected_events)(ErtsPollSet *ps,
fprintf(stderr,"failed to parse file %s on line %d, errno = %d\n",
fname, line, errno);
ASSERT(0);
+ fclose(f);
return;
}
if (fd == ps->wake_fds[0] || fd == ps->wake_fds[1])
@@ -2437,6 +2440,7 @@ ERTS_POLL_EXPORT(erts_poll_get_selected_events)(ErtsPollSet *ps,
ev[fd] = (ERTS_POLL_EV_IN|ERTS_POLL_EV_OUT) & ERTS_POLL_EV_N2E(events);
line++;
}
+ fclose(f);
#else
for (fd = 0; fd < len; fd++)
ev[fd] = ERTS_POLL_EV_NONE;
diff --git a/erts/emulator/test/binary_SUITE.erl b/erts/emulator/test/binary_SUITE.erl
index 1406ddc9dc..563d60cc3f 100644
--- a/erts/emulator/test/binary_SUITE.erl
+++ b/erts/emulator/test/binary_SUITE.erl
@@ -1703,13 +1703,16 @@ error_after_yield_bad_ext_term() ->
BadAtomExt]). %% Invalid atom at the end
cmp_old_impl(Config) when is_list(Config) ->
- %% Compare results from new yielding implementations with
- %% old non yielding implementations
+ %% This test was originally a comparison with the non yielding
+ %% implementation in R16B. Since OTP 22 we can't talk distribution with such
+ %% old nodes (< 19). The test case it kept but compares with previous major
+ %% version for semantic regression test.
Cookie = atom_to_list(erlang:get_cookie()),
- Rel = "r16b_latest",
+ Rel = (integer_to_list(list_to_integer(erlang:system_info(otp_release)) - 1)
+ ++ "_latest"),
case test_server:is_release_available(Rel) of
false ->
- {skipped, "No "++Rel++" available"};
+ {skipped, "No OTP "++Rel++" available"};
true ->
{ok, Node} = test_server:start_node(list_to_atom(atom_to_list(?MODULE)++"_"++Rel),
peer,
diff --git a/erts/emulator/test/bs_match_misc_SUITE.erl b/erts/emulator/test/bs_match_misc_SUITE.erl
index 17759d78f3..cae4eb54d2 100644
--- a/erts/emulator/test/bs_match_misc_SUITE.erl
+++ b/erts/emulator/test/bs_match_misc_SUITE.erl
@@ -24,7 +24,7 @@
kenneth/1,encode_binary/1,native/1,happi/1,
size_var/1,wiger/1,x0_context/1,huge_float_field/1,
writable_binary_matched/1,otp_7198/1,unordered_bindings/1,
- float_middle_endian/1]).
+ float_middle_endian/1,unsafe_get_binary_reuse/1]).
-include_lib("common_test/include/ct.hrl").
@@ -36,7 +36,8 @@ all() ->
[bound_var, bound_tail, t_float, little_float, sean,
kenneth, encode_binary, native, happi, size_var, wiger,
x0_context, huge_float_field, writable_binary_matched,
- otp_7198, unordered_bindings, float_middle_endian].
+ otp_7198, unordered_bindings, float_middle_endian,
+ unsafe_get_binary_reuse].
%% Test matching of bound variables.
@@ -556,5 +557,21 @@ unordered_bindings(CompressedLength, HashSize, PadLength, T) ->
Padding:PadLength/binary,PadLength>> = T,
{Content,Mac,Padding}.
+%% ERL-901: A load-time optimization assumed that match contexts had no further
+%% uses when a bs_get_binary2 overwrote the match context's register, and
+%% figured it would be safe to reuse the match context's memory for the
+%% resulting binary.
+%%
+%% This is no longer safe as of OTP 22, as a match context may be reused after
+%% being passed to another function.
+unsafe_get_binary_reuse(Config) when is_list(Config) ->
+ <<_First, Rest/binary>> = <<"hello">>,
+ ubgr_1(Rest),
+ <<Second,_/bits>> = Rest,
+ $e = Second,
+ ok.
+
+ubgr_1(<<_CP/utf8, Rest/binary>>) -> id(Rest);
+ubgr_1(_) -> false.
id(I) -> I.
diff --git a/erts/emulator/test/distribution_SUITE.erl b/erts/emulator/test/distribution_SUITE.erl
index 4f70b51aa0..449821e5ad 100644
--- a/erts/emulator/test/distribution_SUITE.erl
+++ b/erts/emulator/test/distribution_SUITE.erl
@@ -744,6 +744,7 @@ link_to_dead_new_node(Config) when is_list(Config) ->
{'EXIT', Pid, noproc} ->
ok;
Other ->
+ stop_node(Node),
ct:fail({unexpected_message, Other})
after 5000 ->
ct:fail(nothing_received)
@@ -1421,7 +1422,7 @@ message_latency_large_exit(Nodename, ReasonFun) ->
FlushTrace = fun F() ->
receive
- {trace, Pid, _, _} = M ->
+ {trace, Pid, _, _} ->
F()
after 0 ->
ok
@@ -1455,8 +1456,14 @@ measure_latency_large_message(Nodename, DataFun) ->
Echo = spawn(N, fun F() -> receive {From, Msg} -> From ! Msg, F() end end),
- %% Test 32 MB and 320 MB and test the latency difference of sent messages
- Payloads = [{I, <<0:(I * 32 * 1024 * 1024 * 8)>>} || I <- [1,10]],
+ case erlang:system_info(build_type) of
+ debug ->
+ %% Test 3.2 MB and 32 MB and test the latency difference of sent messages
+ Payloads = [{I, <<0:(I * 32 * 1024 * 8)>>} || I <- [1,10]];
+ _ ->
+ %% Test 32 MB and 320 MB and test the latency difference of sent messages
+ Payloads = [{I, <<0:(I * 32 * 1024 * 1024 * 8)>>} || I <- [1,10]]
+ end,
IndexTimes = [{I, measure_latency(DataFun, Dropper, Echo, P)}
|| {I, P} <- Payloads],
@@ -1465,6 +1472,8 @@ measure_latency_large_message(Nodename, DataFun) ->
ct:pal("~p",[IndexTimes]),
+ stop_node(N),
+
case {lists:max(Times), lists:min(Times)} of
{Max, Min} when Max * 0.25 > Min ->
ct:fail({incorrect_latency, IndexTimes});
@@ -1487,7 +1496,7 @@ measure_latency(DataFun, Dropper, Echo, Payload) ->
end) || _ <- lists:seq(1,2)],
[receive
- {monitor, _Sender, busy_dist_port, _Info} = M ->
+ {monitor, _Sender, busy_dist_port, _Info} ->
ok
end || _ <- lists:seq(1,10)],
@@ -1733,7 +1742,7 @@ bad_dist_fragments(Config) when is_list(Config) ->
start_monitor(Offender,P),
Exit2Victim = spawn(Victim, fun() -> receive ok -> ok end end),
- send_bad_fragments(Offender, Victim, P,{?DOP_PAYLOAD_EXIT2,P,ExitVictim},2,
+ send_bad_fragments(Offender, Victim, P,{?DOP_PAYLOAD_EXIT2,P,Exit2Victim},2,
[{hdr, 1, [132]}]),
start_monitor(Offender,P),
@@ -2428,17 +2437,22 @@ stop_node(Node) ->
verify_nc(Node) ->
P = self(),
Ref = make_ref(),
- spawn(Node,
- fun() ->
- R = erts_test_utils:check_node_dist(fun(E) -> E end),
- P ! {Ref, R}
- end),
+ Pid = spawn(Node,
+ fun() ->
+ R = erts_test_utils:check_node_dist(fun(E) -> E end),
+ P ! {Ref, R}
+ end),
+ MonRef = monitor(process, Pid),
receive
{Ref, ok} ->
+ demonitor(MonRef,[flush]),
ok;
{Ref, Error} ->
- ct:log("~s",[Error]),
- ct:fail(failed_nc_refc_check)
+ ct:log("~p",[Error]),
+ ct:fail(failed_nc_refc_check);
+ {'DOWN', MonRef, _, _, _} = Down ->
+ ct:log("~p",[Down]),
+ ct:fail(crashed_nc_refc_check)
end.
freeze_node(Node, MS) ->
diff --git a/erts/emulator/test/dump_SUITE.erl b/erts/emulator/test/dump_SUITE.erl
index d0237b78cc..3b860ebdf6 100644
--- a/erts/emulator/test/dump_SUITE.erl
+++ b/erts/emulator/test/dump_SUITE.erl
@@ -24,7 +24,7 @@
-export([all/0, suite/0, init_per_testcase/2, end_per_testcase/2]).
--export([signal_abort/1]).
+-export([signal_abort/1, exiting_dump/1, free_dump/1]).
-export([load/0]).
@@ -35,7 +35,7 @@ suite() ->
{timetrap, {minutes, 2}}].
all() ->
- [signal_abort].
+ [signal_abort, exiting_dump, free_dump].
init_per_testcase(signal_abort, Config) ->
SO = erlang:system_info(schedulers_online),
@@ -48,7 +48,10 @@ init_per_testcase(signal_abort, Config) ->
{skip, "the platform does not support scheduler dump"};
Dump ->
Config
- end.
+ end;
+init_per_testcase(_, Config) ->
+ Config.
+
end_per_testcase(_, Config) ->
Config.
@@ -79,8 +82,6 @@ signal_abort(Config) ->
{ok, Bin} = get_dump_when_done(Dump),
- ct:log("~s",[Bin]),
-
{match, Matches} = re:run(Bin,"Current Process: <",[global]),
ct:log("Found ~p",[Matches]),
@@ -91,6 +92,85 @@ signal_abort(Config) ->
ok.
+load() ->
+ lists:seq(1,10000),
+ load().
+
+
+%% Test that crash dumping when a process is in the state EXITING works
+exiting_dump(Config) when is_list(Config) ->
+ Dump = filename:join(proplists:get_value(priv_dir, Config),"signal_abort.dump"),
+
+ {ok, Node} = start_node(Config),
+
+ Self = self(),
+
+ Pid = spawn_link(Node,
+ fun() ->
+ [begin
+ T = ets:new(hej,[]),
+ [ets:insert(T,{I,I}) || I <- lists:seq(1,1000)]
+ end || _ <- lists:seq(1,1000)],
+ Self ! ready,
+ receive ok -> ok end
+ end),
+
+ true = rpc:call(Node, os, putenv, ["ERL_CRASH_DUMP",Dump]),
+
+ receive ready -> unlink(Pid), Pid ! ok end,
+
+ rpc:call(Node, erlang, halt, ["dump"]),
+
+ {ok, Bin} = get_dump_when_done(Dump),
+
+ {match, Matches} = re:run(Bin,"^State: Exiting", [global, multiline]),
+
+ ct:log("Found ~p",[Matches]),
+
+ true = length(Matches) == 1,
+
+ file:delete(Dump),
+
+ ok.
+
+%% Test that crash dumping when a process is in the state FREE works
+free_dump(Config) when is_list(Config) ->
+ Dump = filename:join(proplists:get_value(priv_dir, Config),"signal_abort.dump"),
+
+ {ok, Node} = start_node(Config),
+
+ Self = self(),
+
+ Pid = spawn_link(Node,
+ fun() ->
+ Self ! ready,
+ receive
+ ok ->
+ unlink(Self),
+ exit(lists:duplicate(1000,1000))
+ end
+ end),
+
+ true = rpc:call(Node, os, putenv, ["ERL_CRASH_DUMP",Dump]),
+
+ [erlang:monitor(process, Pid) || _ <- lists:seq(1,10000)],
+ receive ready -> unlink(Pid), Pid ! ok end,
+
+ rpc:call(Node, erlang, halt, ["dump"]),
+
+ {ok, Bin} = get_dump_when_done(Dump),
+
+ {match, Matches} = re:run(Bin,"^State: Non Existing", [global, multiline]),
+
+ ct:log("Found ~p",[Matches]),
+
+ true = length(Matches) == 1,
+
+ file:delete(Dump),
+
+ ok.
+
+
get_dump_when_done(Dump) ->
case file:read_file_info(Dump) of
{ok, #file_info{ size = Sz }} ->
@@ -104,15 +184,13 @@ get_dump_when_done(Dump, Sz) ->
timer:sleep(1000),
case file:read_file_info(Dump) of
{ok, #file_info{ size = Sz }} ->
- file:read_file(Dump);
+ {ok, Bin} = file:read_file(Dump),
+ ct:log("~s",[Bin]),
+ {ok, Bin};
{ok, #file_info{ size = NewSz }} ->
get_dump_when_done(Dump, NewSz)
end.
-load() ->
- lists:seq(1,10000),
- load().
-
start_node(Config) when is_list(Config) ->
Pa = filename:dirname(code:which(?MODULE)),
Name = list_to_atom(atom_to_list(?MODULE)
diff --git a/erts/emulator/test/efile_SUITE.erl b/erts/emulator/test/efile_SUITE.erl
index 7dcf302742..55c5343739 100644
--- a/erts/emulator/test/efile_SUITE.erl
+++ b/erts/emulator/test/efile_SUITE.erl
@@ -45,7 +45,12 @@ iter_max_files(Config) when is_list(Config) ->
iter_max_files_1(Config) ->
DataDir = proplists:get_value(data_dir,Config),
TestFile = filename:join(DataDir, "existing_file"),
- N = 10,
+ case erlang:system_info(debug_compiled) of
+ true ->
+ N = 5;
+ false ->
+ N = 10
+ end,
%% Run on a different node in order to make the test more stable.
Dir = filename:dirname(code:which(?MODULE)),
{ok,Node} = test_server:start_node(test_iter_max_files,slave,
diff --git a/erts/emulator/test/erts_test_utils.erl b/erts/emulator/test/erts_test_utils.erl
index 0c3ef3e0fc..e4e00a0a16 100644
--- a/erts/emulator/test/erts_test_utils.erl
+++ b/erts/emulator/test/erts_test_utils.erl
@@ -19,6 +19,7 @@
%%
-module(erts_test_utils).
+-compile(r16).
%%
%% THIS MODULE IS ALSO USED BY *OTHER* APPLICATIONS TEST CODE
diff --git a/erts/emulator/test/fun_SUITE.erl b/erts/emulator/test/fun_SUITE.erl
index 4042b58ff2..7f6caa08f1 100644
--- a/erts/emulator/test/fun_SUITE.erl
+++ b/erts/emulator/test/fun_SUITE.erl
@@ -592,7 +592,8 @@ refc_dist(Config) when is_list(Config) ->
3 = fun_refc(F2),
true = erlang:garbage_collect(),
2 = fun_refc(F),
- refc_dist_send(Node, F).
+ refc_dist_send(Node, F),
+ test_server:stop_node(Node).
refc_dist_send(Node, F) ->
Pid = spawn_link(Node, fun() -> receive
@@ -682,6 +683,7 @@ t_arity(Config) when is_list(Config) ->
43 = spawn_call(Node, fun(X, Y) -> A+X+Y end),
1 = spawn_call(Node, fun(X, Y) -> X+Y end),
45 = spawn_call(Node, fun(X, Y, Z) -> A+X+Y+Z end),
+ test_server:stop_node(Node),
ok.
t_is_function2(Config) when is_list(Config) ->
diff --git a/erts/emulator/test/map_SUITE.erl b/erts/emulator/test/map_SUITE.erl
index d0a6763fe5..9ea59e1084 100644
--- a/erts/emulator/test/map_SUITE.erl
+++ b/erts/emulator/test/map_SUITE.erl
@@ -17,7 +17,7 @@
%% %CopyrightEnd%
%%
-module(map_SUITE).
--export([all/0, suite/0]).
+-export([all/0, suite/0, init_per_suite/1, end_per_suite/1]).
-export([t_build_and_match_literals/1, t_build_and_match_literals_large/1,
t_update_literals/1, t_update_literals_large/1,
@@ -84,7 +84,10 @@
%% instruction-level tests
t_has_map_fields/1,
y_regs/1,
- badmap_17/1]).
+ badmap_17/1,
+
+ %%Bugs
+ t_large_unequal_bins_same_hash_bug/1]).
-include_lib("stdlib/include/ms_transform.hrl").
@@ -149,7 +152,26 @@ all() -> [t_build_and_match_literals, t_build_and_match_literals_large,
%% instruction-level tests
t_has_map_fields,
y_regs,
- badmap_17].
+ badmap_17,
+
+ %% Bugs
+ t_large_unequal_bins_same_hash_bug].
+
+init_per_suite(Config) ->
+ A0 = case application:start(sasl) of
+ ok -> [sasl];
+ _ -> []
+ end,
+ A = case application:start(os_mon) of
+ ok -> [os_mon|A0];
+ _ -> A0
+ end,
+ [{started_apps, A}|Config].
+
+end_per_suite(Config) ->
+ As = proplists:get_value(started_apps, Config),
+ lists:foreach(fun (A) -> application:stop(A) end, As),
+ Config.
%% tests
@@ -3374,3 +3396,67 @@ fannerl() ->
104,2,97,9,97,16,70,63,184,100,97,32,0,0,0,104,2,97,10,97,16,70,63,169,174,
254,64,0,0,0,104,2,97,11,97,16,70,191,119,121,234,0,0,0,0,104,2,97,12,97,
16,70,63,149,12,170,128,0,0,0,104,2,97,13,97,16,70,191,144,193,191,0,0,0,0>>.
+
+%% This test case checks that the bug with ticket number OTP-15707 is
+%% fixed. The bug could cause a crash or memory usage to grow until
+%% the machine ran out of memory.
+t_large_unequal_bins_same_hash_bug(Config) when is_list(Config) ->
+ run_when_enough_resources(
+ fun() ->
+ K1 = get_4GB_bin(1),
+ K2 = get_4GB_bin(2),
+ Map = make_map(500),
+ Map2 = maps:put(K1, 42, Map),
+ %% The map needed to contain at least 32 key-value pairs
+ %% at this point to get the crash or out of memory
+ %% problem on the next line
+ Map3 = maps:put(K2, 43, Map2),
+ %% The following line should avoid that the compiler
+ %% optimizes away the above
+ io:format("~p ~p~n", [erlang:phash2(Map3), maps:size(Map3)])
+ end).
+
+make_map(0) ->
+ #{};
+make_map(Size) ->
+ maps:put(Size, Size, make_map(Size-1)).
+
+get_4GB_bin(Value) ->
+ List = lists:duplicate(65536, Value),
+ Bin = erlang:iolist_to_binary(List),
+ IOList4GB = duplicate_iolist(Bin, 16),
+ Bin4GB = erlang:iolist_to_binary(IOList4GB),
+ 4294967296 = size(Bin4GB),
+ Bin4GB.
+
+duplicate_iolist(IOList, 0) ->
+ IOList;
+duplicate_iolist(IOList, NrOfTimes) ->
+ duplicate_iolist([IOList, IOList], NrOfTimes - 1).
+
+run_when_enough_resources(Fun) ->
+ case {total_memory(), erlang:system_info(wordsize)} of
+ {Mem, 8} when is_integer(Mem) andalso Mem >= 31 ->
+ Fun();
+ {Mem, WordSize} ->
+ {skipped,
+ io_lib:format("Not enough resources (System Memory >= ~p, Word Size = ~p)",
+ [Mem, WordSize])}
+ end.
+
+total_memory() ->
+ %% Total memory in GB.
+ try
+ MemoryData = memsup:get_system_memory_data(),
+ case lists:keysearch(total_memory, 1, MemoryData) of
+ {value, {total_memory, TM}} ->
+ TM div (1024*1024*1024);
+ false ->
+ {value, {system_total_memory, STM}} =
+ lists:keysearch(system_total_memory, 1, MemoryData),
+ STM div (1024*1024*1024)
+ end
+ catch
+ _ : _ ->
+ undefined
+ end.
diff --git a/erts/emulator/test/process_SUITE.erl b/erts/emulator/test/process_SUITE.erl
index edf08ce0bd..b530ced566 100644
--- a/erts/emulator/test/process_SUITE.erl
+++ b/erts/emulator/test/process_SUITE.erl
@@ -44,6 +44,7 @@
process_info_garbage_collection/1,
process_info_smoke_all/1,
process_info_status_handled_signal/1,
+ process_info_reductions/1,
bump_reductions/1, low_prio/1, binary_owner/1, yield/1, yield2/1,
otp_4725/1, bad_register/1, garbage_collect/1, otp_6237/1,
process_info_messages/1, process_flag_badarg/1, process_flag_heap_size/1,
@@ -84,6 +85,7 @@ all() ->
process_info_garbage_collection,
process_info_smoke_all,
process_info_status_handled_signal,
+ process_info_reductions,
bump_reductions, low_prio, yield, yield2, otp_4725,
bad_register, garbage_collect, process_info_messages,
process_flag_badarg, process_flag_heap_size,
@@ -133,6 +135,15 @@ init_per_group(_GroupName, Config) ->
end_per_group(_GroupName, Config) ->
Config.
+init_per_testcase(Func, Config)
+ when Func =:= processes_default_tab;
+ Func =:= processes_this_tab ->
+ case erlang:system_info(debug_compiled) of
+ true ->
+ {skip, "Don't run in debug"};
+ false ->
+ [{testcase, Func} | Config]
+ end;
init_per_testcase(Func, Config) when is_atom(Func), is_list(Config) ->
[{testcase, Func}|Config].
@@ -1084,6 +1095,46 @@ process_info_status_handled_signal(Config) when is_list(Config) ->
false = erlang:is_process_alive(P),
ok.
+%% OTP-15709
+%% Provoke a bug where process_info(reductions) returned wrong result
+%% because REDS_IN (def_arg_reg[5]) is read when the process in not running.
+process_info_reductions(Config) when is_list(Config) ->
+ pi_reductions_tester(spawn_link(fun() -> pi_reductions_spinnloop() end)),
+ pi_reductions_tester(spawn_link(fun() -> pi_reductions_recvloop() end)),
+ ok.
+
+pi_reductions_tester(Pid) ->
+ {_, DiffList} =
+ lists:foldl(fun(_, {Prev, Acc}) ->
+ %% Add another item that force sending the request
+ %% as a signal, like 'current_function'.
+ PI = process_info(Pid, [reductions, current_function]),
+ [{reductions,Reds}, {current_function,_}] = PI,
+ Diff = Reds - Prev,
+ {Diff, true} = {Diff, (Diff >= 0)},
+ {Diff, true} = {Diff, (Diff =< 1000*1000)},
+ {Reds, [Diff | Acc]}
+ end,
+ {0, []},
+ lists:seq(1,10)),
+ unlink(Pid),
+ exit(Pid,kill),
+ io:format("Reduction diffs: ~p\n", [DiffList]),
+ ok.
+
+pi_reductions_spinnloop() ->
+ %% 6 args to make use of def_arg_reg[5] which is also used as REDS_IN
+ pi_reductions_spinnloop(1, atom, "hej", self(), make_ref(), 3.14).
+
+pi_reductions_spinnloop(A,B,C,D,E,F) ->
+ pi_reductions_spinnloop(B,C,D,E,F,A).
+
+pi_reductions_recvloop() ->
+ receive
+ "a free lunch" -> false
+ end.
+
+
%% Tests erlang:bump_reductions/1.
bump_reductions(Config) when is_list(Config) ->
erlang:garbage_collect(),
diff --git a/erts/epmd/epmd.mk b/erts/epmd/epmd.mk
index b1fd04dc04..f6889a7ff1 100644
--- a/erts/epmd/epmd.mk
+++ b/erts/epmd/epmd.mk
@@ -67,5 +67,5 @@ EPMD_NODE_TYPE=110
# Distribution format 5 contains the new md5 based handshake.
EPMD_DIST_LOW=5
-EPMD_DIST_HIGH=5
+EPMD_DIST_HIGH=6
diff --git a/erts/epmd/src/epmd.h b/erts/epmd/src/epmd.h
index cffcd4ae7a..7332294d3d 100644
--- a/erts/epmd/src/epmd.h
+++ b/erts/epmd/src/epmd.h
@@ -26,6 +26,7 @@
#define EPMD_ALIVE2_REQ 'x'
#define EPMD_PORT2_REQ 'z'
#define EPMD_ALIVE2_RESP 'y'
+#define EPMD_ALIVE2_X_RESP 'v'
#define EPMD_PORT2_RESP 'w'
#define EPMD_NAMES_REQ 'n'
diff --git a/erts/epmd/src/epmd_int.h b/erts/epmd/src/epmd_int.h
index ed9bbdb8cd..a5156a142e 100644
--- a/erts/epmd/src/epmd_int.h
+++ b/erts/epmd/src/epmd_int.h
@@ -277,6 +277,12 @@ static const struct in6_addr in6addr_loopback =
#define put_int16(i, s) {((unsigned char*)(s))[0] = ((i) >> 8) & 0xff; \
((unsigned char*)(s))[1] = (i) & 0xff;}
+#define put_int32(i, s) do {((char*)(s))[0] = (char)((i) >> 24) & 0xff; \
+ ((char*)(s))[1] = (char)((i) >> 16) & 0xff; \
+ ((char*)(s))[2] = (char)((i) >> 8) & 0xff; \
+ ((char*)(s))[3] = (char)(i) & 0xff;} \
+ while (0)
+
#if defined(__GNUC__)
# define EPMD_INLINE __inline__
#elif defined(__WIN32__)
@@ -307,10 +313,10 @@ struct enode {
int fd; /* The socket in use */
unsigned short port; /* Port number of Erlang node */
char symname[MAXSYMLEN+1]; /* Name of the Erlang node */
- short creation; /* Started as a random number 1..3 */
+ unsigned int cr_counter; /* Used to generate 'creation' numbers */
char nodetype; /* 77 = normal erlang node 72 = hidden (c-node */
char protocol; /* 0 = tcp/ipv4 */
- unsigned short highvsn; /* 0 = OTP-R3 erts-4.6.x, 1 = OTP-R4 erts-4.7.x*/
+ unsigned short highvsn; /* 5: creation=1..3, 6: creation=1..(2^32-1)*/
unsigned short lowvsn;
int extralen;
char extra[MAXSYMLEN+1];
diff --git a/erts/epmd/src/epmd_srv.c b/erts/epmd/src/epmd_srv.c
index 66c10a65bc..633ec71e5f 100644
--- a/erts/epmd/src/epmd_srv.c
+++ b/erts/epmd/src/epmd_srv.c
@@ -665,6 +665,21 @@ static int do_accept(EpmdVars *g,int listensock)
return conn_open(g,msgsock);
}
+static void bump_creation(Node* node)
+{
+ if (++node->cr_counter == 0)
+ node->cr_counter = 1;
+}
+static unsigned int get_creation(Node* node)
+{
+ if (node->highvsn >= 6) {
+ return node->cr_counter; /* 1..(2^32-1)*/
+ }
+ else {
+ return (node->cr_counter - 1) % 3 + 1; /* 1..3 */
+ }
+}
+
/* buf is actually one byte larger than bsize,
giving place for null termination */
static void do_request(g, fd, s, buf, bsize)
@@ -706,8 +721,10 @@ static void do_request(g, fd, s, buf, bsize)
unsigned char protocol;
unsigned short highvsn;
unsigned short lowvsn;
+ unsigned int creation;
int namelen;
int extralen;
+ int replylen;
char *name;
char *extra;
eport = get_int16(&buf[1]);
@@ -737,17 +754,22 @@ static void do_request(g, fd, s, buf, bsize)
extra = &buf[11+namelen+2];
extra[extralen]='\000';
- wbuf[0] = EPMD_ALIVE2_RESP;
- if ((node = node_reg2(g, namelen, name, fd, eport, nodetype, protocol,
- highvsn, lowvsn, extralen, extra)) == NULL) {
- wbuf[1] = 1; /* error */
- put_int16(99, wbuf+2);
- } else {
- wbuf[1] = 0; /* ok */
- put_int16(node->creation, wbuf+2);
- }
+ node = node_reg2(g, namelen, name, fd, eport, nodetype, protocol,
+ highvsn, lowvsn, extralen, extra);
+ creation = node ? get_creation(node) : 99;
+ wbuf[1] = node ? 0 : 1; /* ok | error */
+ if (highvsn >= 6) {
+ wbuf[0] = EPMD_ALIVE2_X_RESP;
+ put_int32(creation, wbuf+2);
+ replylen = 6;
+ }
+ else {
+ wbuf[0] = EPMD_ALIVE2_RESP;
+ put_int16(creation, wbuf+2);
+ replylen = 4;
+ }
- if (reply(g, fd, wbuf, 4) != 4)
+ if (!reply(g, fd, wbuf, replylen))
{
node_unreg(g, name);
dbg_tty_printf(g,1,"** failed to send ALIVE2_RESP for \"%s\"",
@@ -807,7 +829,7 @@ static void do_request(g, fd, s, buf, bsize)
offset += 2;
memcpy(wbuf + offset,node->extra,node->extralen);
offset += node->extralen;
- if (reply(g, fd, wbuf, offset) != offset)
+ if (!reply(g, fd, wbuf, offset))
{
dbg_tty_printf(g,1,"** failed to send PORT2_RESP (ok) for \"%s\"",name);
return;
@@ -817,7 +839,7 @@ static void do_request(g, fd, s, buf, bsize)
}
}
wbuf[1] = 1; /* error */
- if (reply(g, fd, wbuf, 2) != 2)
+ if (!reply(g, fd, wbuf, 2))
{
dbg_tty_printf(g,1,"** failed to send PORT2_RESP (error) for \"%s\"",name);
return;
@@ -835,7 +857,7 @@ static void do_request(g, fd, s, buf, bsize)
i = htonl(g->port);
memcpy(wbuf,&i,4);
- if (reply(g, fd,wbuf,4) != 4)
+ if (!reply(g, fd,wbuf,4))
{
dbg_tty_printf(g,1,"failed to send NAMES_RESP");
return;
@@ -856,7 +878,7 @@ static void do_request(g, fd, s, buf, bsize)
if (r < 0)
goto failed_names_resp;
len += r;
- if (reply(g, fd, wbuf, len) != len)
+ if (!reply(g, fd, wbuf, len))
{
failed_names_resp:
dbg_tty_printf(g,1,"failed to send NAMES_RESP");
@@ -878,7 +900,7 @@ static void do_request(g, fd, s, buf, bsize)
i = htonl(g->port);
memcpy(wbuf,&i,4);
- if (reply(g, fd,wbuf,4) != 4)
+ if (!reply(g, fd,wbuf,4))
{
dbg_tty_printf(g,1,"failed to send DUMP_RESP");
return;
@@ -899,7 +921,7 @@ static void do_request(g, fd, s, buf, bsize)
if (r < 0)
goto failed_dump_resp;
len += r + 1;
- if (reply(g, fd,wbuf,len) != len)
+ if (!reply(g, fd,wbuf,len))
{
failed_dump_resp:
dbg_tty_printf(g,1,"failed to send DUMP_RESP");
@@ -922,7 +944,7 @@ static void do_request(g, fd, s, buf, bsize)
if (r < 0)
goto failed_dump_resp2;
len += r + 1;
- if (reply(g, fd,wbuf,len) != len)
+ if (!reply(g, fd,wbuf,len))
{
failed_dump_resp2:
dbg_tty_printf(g,1,"failed to send DUMP_RESP");
@@ -942,12 +964,12 @@ static void do_request(g, fd, s, buf, bsize)
if (!g->brutal_kill && (g->nodes.reg != NULL)) {
dbg_printf(g,0,"Disallowed KILL_REQ, live nodes");
- if (reply(g, fd,"NO",2) != 2)
+ if (!reply(g, fd,"NO",2))
dbg_printf(g,0,"failed to send reply to KILL_REQ");
return;
}
- if (reply(g, fd,"OK",2) != 2)
+ if (!reply(g, fd,"OK",2))
dbg_printf(g,0,"failed to send reply to KILL_REQ");
dbg_tty_printf(g,1,"epmd killed");
conn_close_fd(g,fd); /* We never return to caller so close here */
@@ -977,7 +999,7 @@ static void do_request(g, fd, s, buf, bsize)
if ((node_fd = node_unreg(g,name)) < 0)
{
- if (reply(g, fd,"NOEXIST",7) != 7)
+ if (!reply(g, fd,"NOEXIST",7))
{
dbg_tty_printf(g,1,"failed to send STOP_RESP NOEXIST");
return;
@@ -988,7 +1010,7 @@ static void do_request(g, fd, s, buf, bsize)
conn_close_fd(g,node_fd);
dbg_tty_printf(g,1,"epmd connection stopped");
- if (reply(g, fd,"STOPPED",7) != 7)
+ if (!reply(g, fd,"STOPPED",7))
{
dbg_tty_printf(g,1,"failed to send STOP_RESP STOPPED");
return;
@@ -1200,8 +1222,8 @@ static int node_unreg(EpmdVars *g,char *name)
for (; node; prev = &node->next, node = node->next)
if (is_same_str(node->symname, name))
{
- dbg_tty_printf(g,1,"unregistering '%s:%d', port %d",
- node->symname, node->creation, node->port);
+ dbg_tty_printf(g,1,"unregistering '%s:%u', port %d",
+ node->symname, get_creation(node), node->port);
*prev = node->next; /* Link out from "reg" list */
@@ -1235,8 +1257,8 @@ static int node_unreg_sock(EpmdVars *g,int fd)
for (; node; prev = &node->next, node = node->next)
if (node->fd == fd)
{
- dbg_tty_printf(g,1,"unregistering '%s:%d', port %d",
- node->symname, node->creation, node->port);
+ dbg_tty_printf(g,1,"unregistering '%s:%u', port %d",
+ node->symname, get_creation(node), node->port);
*prev = node->next; /* Link out from "reg" list */
@@ -1264,19 +1286,8 @@ static int node_unreg_sock(EpmdVars *g,int fd)
}
/*
- * Finding a node slot and a (name,creation) name is a bit tricky.
- * We try in order
- *
- * 1. If the name was used before and we can reuse that slot but use
- * a new "creation" digit in the range 1..3.
- *
- * 2. We try to find a new unused slot.
- *
- * 3. We try to use an used slot this isn't used any longer.
- * FIXME: The criteria for *what* slot to steal should be improved.
- * Perhaps use the oldest or something.
+ * Register a new node
*/
-
static Node *node_reg2(EpmdVars *g,
int namelen,
char* name,
@@ -1346,7 +1357,7 @@ static Node *node_reg2(EpmdVars *g,
}
/* Try to find the name in the used queue so that we
- can change "creation" number 1..3 */
+ can change "creation" number */
prev = NULL;
@@ -1375,9 +1386,8 @@ static Node *node_reg2(EpmdVars *g,
g->nodes.unreg_count--;
- /* When reusing we change the "creation" number 1..3 */
-
- node->creation = node->creation % 3 + 1;
+ /* When reusing we change the "creation" number */
+ bump_creation(node);
break;
}
@@ -1404,7 +1414,8 @@ static Node *node_reg2(EpmdVars *g,
exit(1);
}
- node->creation = (current_time(g) % 3) + 1; /* "random" 1-3 */
+ node->cr_counter = current_time(g); /* "random" */
+ bump_creation(node);
}
}
@@ -1423,11 +1434,11 @@ static Node *node_reg2(EpmdVars *g,
select_fd_set(g, fd);
if (highvsn == 0) {
- dbg_tty_printf(g,1,"registering '%s:%d', port %d",
- node->symname, node->creation, node->port);
+ dbg_tty_printf(g,1,"registering '%s:%u', port %d",
+ node->symname, get_creation(node), node->port);
} else {
- dbg_tty_printf(g,1,"registering '%s:%d', port %d",
- node->symname, node->creation, node->port);
+ dbg_tty_printf(g,1,"registering '%s:%u', port %d",
+ node->symname, get_creation(node), node->port);
dbg_tty_printf(g,1,"type %d proto %d highvsn %d lowvsn %d",
nodetype, protocol, highvsn, lowvsn);
}
@@ -1448,7 +1459,9 @@ static time_t current_time(EpmdVars *g)
static int reply(EpmdVars *g,int fd,char *buf,int len)
{
- int val;
+ char* p = buf;
+ int nbytes = len;
+ int val, ret;
if (len < 0)
{
@@ -1459,15 +1472,27 @@ static int reply(EpmdVars *g,int fd,char *buf,int len)
if (g->delay_write) /* Test of busy server */
sleep(g->delay_write);
- val = write(fd,buf,len);
- if (val < 0)
- dbg_perror(g,"error in write");
- else if (val != len)
- dbg_printf(g,0,"could only send %d bytes out of %d to fd %d",val,len,fd);
+ for (;;) {
+ val = write(fd, p, nbytes);
+ if (val == nbytes) {
+ ret = 1;
+ break;
+ }
+ if (val < 0) {
+ if (errno == EINTR)
+ continue;
+ dbg_perror(g,"error in write, errno=%d", errno);
+ ret = 0;
+ break;
+ }
+ dbg_printf(g,0,"could only send %d bytes out of %d to fd %d",val,nbytes,fd);
+ p += val;
+ nbytes -= val;
+ }
dbg_print_buf(g,buf,len);
- return val;
+ return ret;
}
@@ -1547,8 +1572,8 @@ static void print_names(EpmdVars *g)
for (node = g->nodes.reg; node; node = node->next)
{
- fprintf(stderr,"***** active name \"%s#%d\" at port %d, fd = %d\r\n",
- node->symname, node->creation, node->port, node->fd);
+ fprintf(stderr,"***** active name \"%s#%u\" at port %d, fd = %d\r\n",
+ node->symname, get_creation(node), node->port, node->fd);
count ++;
}
@@ -1558,8 +1583,8 @@ static void print_names(EpmdVars *g)
for (node = g->nodes.unreg; node; node = node->next)
{
- fprintf(stderr,"***** old/unused name \"%s#%d\"\r\n",
- node->symname, node->creation);
+ fprintf(stderr,"***** old/unused name \"%s#%u\"\r\n",
+ node->symname, get_creation(node));
count ++;
}
diff --git a/erts/etc/unix/etp-commands.in b/erts/etc/unix/etp-commands.in
index e8dc59156f..dc28107ef5 100644
--- a/erts/etc/unix/etp-commands.in
+++ b/erts/etc/unix/etp-commands.in
@@ -1453,8 +1453,10 @@ define etp-stack-preamble
set $etp_stack_p = ($arg0)->stop
set $etp_stack_end = ($arg0)->hend
printf "%% Stacktrace (%u)\n", $etp_stack_end-$etp_stack_p
- etp-1 ((Eterm)($arg0)->i) 0
- printf " (I)\n"
+ if ($arg0)->i != 0
+ etp-1 ((Eterm)($arg0)->i) 0
+ printf " (I)\n"
+ end
if ($arg0)->cp != 0
etp-1 ((Eterm)($arg0)->cp) 0
printf " (cp)\n"
diff --git a/erts/test/erl_print_SUITE.erl b/erts/test/erl_print_SUITE.erl
index 463d890688..0a5987df88 100644
--- a/erts/test/erl_print_SUITE.erl
+++ b/erts/test/erl_print_SUITE.erl
@@ -324,6 +324,9 @@ run_case(Config, TestArgs, Fun) ->
-define(PORT_EXT, 102).
-define(PID_EXT, 103).
-define(NEW_REFERENCE_EXT, 114).
+-define(NEW_PID_EXT, $X).
+-define(NEW_PORT_EXT, $Y).
+-define(NEWER_REFERENCE_EXT, $Z).
uint32_be(Uint) when is_integer(Uint), 0 =< Uint, Uint < 1 bsl 32 ->
[(Uint bsr 24) band 16#ff,
@@ -351,13 +354,13 @@ mk_pid({NodeName, Creation}, Number, Serial) when is_atom(NodeName) ->
mk_pid({atom_to_list(NodeName), Creation}, Number, Serial);
mk_pid({NodeName, Creation}, Number, Serial) ->
case catch binary_to_term(list_to_binary([?VERSION_MAGIC,
- ?PID_EXT,
+ ?NEW_PID_EXT,
?ATOM_EXT,
uint16_be(length(NodeName)),
NodeName,
uint32_be(Number),
uint32_be(Serial),
- uint8(Creation)])) of
+ uint32_be(Creation)])) of
Pid when is_pid(Pid) ->
Pid;
{'EXIT', {badarg, _}} ->
@@ -370,12 +373,12 @@ mk_port({NodeName, Creation}, Number) when is_atom(NodeName) ->
mk_port({atom_to_list(NodeName), Creation}, Number);
mk_port({NodeName, Creation}, Number) ->
case catch binary_to_term(list_to_binary([?VERSION_MAGIC,
- ?PORT_EXT,
+ ?NEW_PORT_EXT,
?ATOM_EXT,
uint16_be(length(NodeName)),
NodeName,
uint32_be(Number),
- uint8(Creation)])) of
+ uint32_be(Creation)])) of
Port when is_port(Port) ->
Port;
{'EXIT', {badarg, _}} ->
@@ -388,33 +391,16 @@ mk_ref({NodeName, Creation}, Numbers) when is_atom(NodeName),
is_integer(Creation),
is_list(Numbers) ->
mk_ref({atom_to_list(NodeName), Creation}, Numbers);
-mk_ref({NodeName, Creation}, [Number]) when is_list(NodeName),
- is_integer(Creation),
- is_integer(Number) ->
- case catch binary_to_term(list_to_binary([?VERSION_MAGIC,
- ?REFERENCE_EXT,
- ?ATOM_EXT,
- uint16_be(length(NodeName)),
- NodeName,
- uint32_be(Number),
- uint8(Creation)])) of
- Ref when is_reference(Ref) ->
- Ref;
- {'EXIT', {badarg, _}} ->
- exit({badarg, mk_ref, [{NodeName, Creation}, [Number]]});
- Other ->
- exit({unexpected_binary_to_term_result, Other})
- end;
mk_ref({NodeName, Creation}, Numbers) when is_list(NodeName),
is_integer(Creation),
is_list(Numbers) ->
case catch binary_to_term(list_to_binary([?VERSION_MAGIC,
- ?NEW_REFERENCE_EXT,
+ ?NEWER_REFERENCE_EXT,
uint16_be(length(Numbers)),
?ATOM_EXT,
uint16_be(length(NodeName)),
NodeName,
- uint8(Creation),
+ uint32_be(Creation),
lists:map(fun (N) ->
uint32_be(N)
end,
@@ -429,11 +415,10 @@ mk_ref({NodeName, Creation}, Numbers) when is_list(NodeName),
my_cre() -> erlang:system_info(creation).
-oth_cre(0) -> 1;
-oth_cre(1) -> 2;
-oth_cre(2) -> 3;
-oth_cre(3) -> 1;
-oth_cre(N) -> exit({invalid_creation, N}).
+oth_cre(N) when N >= 0, N < (1 bsl 32) ->
+ (N rem ((1 bsl 32) - 1)) + 1;
+oth_cre(N) ->
+ exit({invalid_creation, N}).
str_1_bsl_10000() ->
"19950631168807583848837421626835850838234968318861924548520089498529438830221946631919961684036194597899331129423209124271556491349413781117593785932096323957855730046793794526765246551266059895520550086918193311542508608460618104685509074866089624888090489894838009253941633257850621568309473902556912388065225096643874441046759871626985453222868538161694315775629640762836880760732228535091641476183956381458969463899410840960536267821064621427333394036525565649530603142680234969400335934316651459297773279665775606172582031407994198179607378245683762280037302885487251900834464581454650557929601414833921615734588139257095379769119277800826957735674444123062018757836325502728323789270710373802866393031428133241401624195671690574061419654342324638801248856147305207431992259611796250130992860241708340807605932320161268492288496255841312844061536738951487114256315111089745514203313820202931640957596464756010405845841566072044962867016515061920631004186422275908670900574606417856951911456055068251250406007519842261898059237118054444788072906395242548339221982707404473162376760846613033778706039803413197133493654622700563169937455508241780972810983291314403571877524768509857276937926433221599399876886660808368837838027643282775172273657572744784112294389733810861607423253291974813120197604178281965697475898164531258434135959862784130128185406283476649088690521047580882615823961985770122407044330583075869039319604603404973156583208672105913300903752823415539745394397715257455290510212310947321610753474825740775273986348298498340756937955646638621874569499279016572103701364433135817214311791398222983845847334440270964182851005072927748364550578634501100852987812389473928699540834346158807043959118985815145779177143619698728131459483783202081474982171858011389071228250905826817436220577475921417653715687725614904582904992461028630081535583308130101987675856234343538955409175623400844887526162643568648833519463720377293240094456246923254350400678027273837755376406726898636241037491410966718557050759098100246789880178271925953381282421954028302759408448955014676668389697996886241636313376393903373455801407636741877711055384225739499110186468219696581651485130494222369947714763069155468217682876200362777257723781365331611196811280792669481887201298643660768551639860534602297871557517947385246369446923087894265948217008051120322365496288169035739121368338393591756418733850510970271613915439590991598154654417336311656936031122249937969999226781732358023111862644575299135758175008199839236284615249881088960232244362173771618086357015468484058622329792853875623486556440536962622018963571028812361567512543338303270029097668650568557157505516727518899194129711337690149916181315171544007728650573189557450920330185304847113818315407324053319038462084036421763703911550639789000742853672196280903477974533320468368795868580237952218629120080742819551317948157624448298518461509704888027274721574688131594750409732115080498190455803416826949787141316063210686391511681774304792596709376".
diff --git a/lib/asn1/src/asn1ct_check.erl b/lib/asn1/src/asn1ct_check.erl
index 9ec0d93e93..9eec05abd1 100644
--- a/lib/asn1/src/asn1ct_check.erl
+++ b/lib/asn1/src/asn1ct_check.erl
@@ -1710,7 +1710,7 @@ check_value(S,#valuedef{pos=Pos,name=Name,type=Type,
{valueset,
check_type(S,#typedef{pos=Pos,name=Name,typespec=NewType},NewType)};
check_value(S, #valuedef{}=V) ->
- ?dbg("check_value, V: ~p~n",[V0]),
+ ?dbg("check_value, V: ~p~n",[V]),
case V of
#valuedef{checked=true} ->
V;
@@ -1721,7 +1721,8 @@ check_value(S, #valuedef{}=V) ->
check_valuedef(#state{recordtopname=TopName}=S0, V0) ->
#valuedef{name=Name,type=Vtype0,value=Value,module=ModName} = V0,
V = V0#valuedef{checked=true},
- Vtype = check_type(S0, #typedef{name=Name,typespec=Vtype0},Vtype0),
+ Vtype1 = expand_valuedef_type(Vtype0),
+ Vtype = check_type(S0, #typedef{name=Name,typespec=Vtype1},Vtype1),
Def = Vtype#type.def,
S1 = S0#state{tname=Def},
SVal = update_state(S1, ModName),
@@ -1767,6 +1768,27 @@ check_valuedef(#state{recordtopname=TopName}=S0, V0) ->
V#valuedef{value=normalize_value(SVal, Vtype, Value, TopName)}
end.
+expand_valuedef_type(#type{def=Seq}=Type)
+ when is_record(Seq,'SEQUENCE') ->
+ NewComponents = case Seq#'SEQUENCE'.components of
+ {R1,_Ext,R2} -> R1 ++ R2;
+ {Root,_Ext} -> Root;
+ Root -> take_only_rootset(Root)
+ end,
+ NewSeq = Seq#'SEQUENCE'{components = NewComponents},
+ Type#type{def=NewSeq};
+expand_valuedef_type(#type{def=Set}=Type)
+ when is_record(Set,'SET') ->
+ NewComponents = case Set#'SET'.components of
+ {R1,_Ext,R2} -> R1 ++ R2;
+ {Root,_Ext} -> Root;
+ Root -> take_only_rootset(Root)
+ end,
+ NewSet = Set#'SET'{components = NewComponents},
+ Type#type{def=NewSet};
+expand_valuedef_type(Type) ->
+ Type.
+
is_contextswitchtype(#typedef{name='EXTERNAL'})->
true;
is_contextswitchtype(#typedef{name='EMBEDDED PDV'}) ->
@@ -1998,7 +2020,8 @@ normalize_value(S, Type, {'DEFAULT',Value}, NameList) ->
{'ENUMERATED',CType,_} ->
normalize_enumerated(S,Value,CType);
{'CHOICE',CType,NewNameList} ->
- normalize_choice(S,Value,CType,NewNameList);
+ ChoiceComponents = get_choice_components(S, {'CHOICE',CType}),
+ normalize_choice(S,Value,ChoiceComponents,NewNameList);
{'SEQUENCE',CType,NewNameList} ->
normalize_sequence(S,Value,CType,NewNameList);
{'SEQUENCE OF',CType,NewNameList} ->
@@ -2140,6 +2163,9 @@ normalize_octetstring(S, Value) ->
_ ->
asn1_error(S, illegal_octet_string_value)
end;
+ Val when is_binary(Val) ->
+ %% constant default value
+ Val;
_ ->
asn1_error(S, illegal_octet_string_value)
end.
@@ -2751,8 +2777,9 @@ check_type(S=#state{recordtopname=TopName},Type,Ts) when is_record(Ts,type) ->
TempNewDef#newt{type={'SEQUENCE OF',check_sequenceof(S,Type,Components)},
tag=
merge_tags(Tag,?TAG_CONSTRUCTED(?N_SEQUENCE))};
- {'CHOICE',Components} ->
+ {'CHOICE',_} = Choice->
Ct = maybe_illicit_implicit_tag(S, choice, Tag),
+ Components = get_choice_components(S, Choice),
TempNewDef#newt{type={'CHOICE',check_choice(S,Type,Components)},tag=Ct};
Set when is_record(Set,'SET') ->
RecordName=
diff --git a/lib/asn1/test/Makefile b/lib/asn1/test/Makefile
index c38d1c6ebd..6ff4aa8d0f 100644
--- a/lib/asn1/test/Makefile
+++ b/lib/asn1/test/Makefile
@@ -60,6 +60,7 @@ MODULES= \
testSeqOf \
testSeqOfIndefinite \
testSeqOfCho \
+ testSeqOfChoExt \
testSeqOfExternal \
testSeqOfTag \
testSetDefault \
@@ -72,6 +73,7 @@ MODULES= \
testSetTypeRefPrim \
testSetTypeRefSeq \
testSetTypeRefSet \
+ testDefaultOctetString \
testChoiceIndefinite \
testSetOf \
testSetOfCho \
diff --git a/lib/asn1/test/asn1_SUITE.erl b/lib/asn1/test/asn1_SUITE.erl
index ab78678110..a88e464996 100644
--- a/lib/asn1/test/asn1_SUITE.erl
+++ b/lib/asn1/test/asn1_SUITE.erl
@@ -99,6 +99,7 @@ groups() ->
testChoTypeRefPrim,
testChoTypeRefSeq,
testChoTypeRefSet,
+ testDefaultOctetString,
testMultipleLevels,
testOpt,
testSeqDefault,
@@ -118,6 +119,7 @@ groups() ->
{group, [], [testSeqOf,
testSeqOfIndefinite]}, % Uses 'Mvrasn*'
testSeqOfCho,
+ testSeqOfChoExt,
testSetDefault,
testExtensionAdditionGroup,
testSetOptional,
@@ -430,6 +432,11 @@ testChoTypeRefSet(Config, Rule, Opts) ->
asn1_test_lib:compile("ChoTypeRefSet", Config, [Rule|Opts]),
testChoTypeRefSet:set(Rule).
+testDefaultOctetString(Config) -> test(Config, fun testDefaultOctetString/3).
+testDefaultOctetString(Config, Rule, Opts) ->
+ asn1_test_lib:compile("DefaultOctetString", Config, [Rule|Opts]),
+ testDefaultOctetString:dos(Rule).
+
testMultipleLevels(Config) -> test(Config, fun testMultipleLevels/3).
testMultipleLevels(Config, Rule, Opts) ->
asn1_test_lib:compile("MultipleLevels", Config, [Rule|Opts]),
@@ -535,6 +542,11 @@ testSeqOfCho(Config, Rule, Opts) ->
asn1_test_lib:compile("SeqOfCho", Config, [Rule|Opts]),
testSeqOfCho:main(Rule).
+testSeqOfChoExt(Config) -> test(Config, fun testSeqOfChoExt/3).
+testSeqOfChoExt(Config, Rule, Opts) ->
+ asn1_test_lib:compile("SeqOfChoExt", Config, [Rule|Opts]),
+ testSeqOfChoExt:main(Rule).
+
testSeqOfIndefinite(Config) ->
test(Config, fun testSeqOfIndefinite/3, [ber]).
testSeqOfIndefinite(Config, Rule, Opts) ->
diff --git a/lib/asn1/test/asn1_SUITE_data/ChoExtension.asn1 b/lib/asn1/test/asn1_SUITE_data/ChoExtension.asn1
index 18473bae30..c488704196 100644
--- a/lib/asn1/test/asn1_SUITE_data/ChoExtension.asn1
+++ b/lib/asn1/test/asn1_SUITE_data/ChoExtension.asn1
@@ -41,4 +41,6 @@ ChoExt4 ::= CHOICE
str OCTET STRING
}
+choExt1 ChoExt1 ::= int : 1
+
END
diff --git a/lib/asn1/test/asn1_SUITE_data/DefaultOctetString.asn b/lib/asn1/test/asn1_SUITE_data/DefaultOctetString.asn
new file mode 100644
index 0000000000..076e965d58
--- /dev/null
+++ b/lib/asn1/test/asn1_SUITE_data/DefaultOctetString.asn
@@ -0,0 +1,15 @@
+DefaultOctetString
+DEFINITIONS
+AUTOMATIC TAGS
+ ::=
+BEGIN
+Dos ::= SEQUENCE {
+ opt [2] OCTET STRING (SIZE(2..4)) OPTIONAL,
+ def [10] OCTET STRING (SIZE (1)) DEFAULT '05'H
+}
+
+dos Dos ::= {
+ opt '1234'H
+}
+
+END
diff --git a/lib/asn1/test/asn1_SUITE_data/SeqOfChoExt.asn1 b/lib/asn1/test/asn1_SUITE_data/SeqOfChoExt.asn1
new file mode 100644
index 0000000000..51077754fd
--- /dev/null
+++ b/lib/asn1/test/asn1_SUITE_data/SeqOfChoExt.asn1
@@ -0,0 +1,27 @@
+SeqOfChoExt DEFINITIONS AUTOMATIC TAGS EXTENSIBILITY IMPLIED ::=
+BEGIN
+
+Seq2 ::= SEQUENCE {
+ octstr [PRIVATE 6] OCTET STRING OPTIONAL
+}
+
+SeqOfCho ::= SEQUENCE OF CHOICE {
+ nullable NULL,
+ seq2 Seq2
+}
+
+Seq1 ::= SEQUENCE {
+ int INTEGER,
+ soc SeqOfCho
+}
+
+seq1 Seq1 ::= {
+ int 10,
+ soc {
+ seq2 : {
+ octstr '01020A'H
+ }
+ }
+}
+
+END
diff --git a/lib/asn1/test/testChoExtension.erl b/lib/asn1/test/testChoExtension.erl
index 4c632aab81..cfb28be5c7 100644
--- a/lib/asn1/test/testChoExtension.erl
+++ b/lib/asn1/test/testChoExtension.erl
@@ -28,6 +28,7 @@
extension(_Rules) ->
roundtrip('ChoExt1', {bool,true}),
roundtrip('ChoExt1', {int,33}),
+ {int, 1} = 'ChoExtension':choExt1(),
%% A trick to encode with another compatible CHOICE type to test reception
%% extension alternative
diff --git a/lib/asn1/test/testDefaultOctetString.erl b/lib/asn1/test/testDefaultOctetString.erl
new file mode 100644
index 0000000000..82cd5810e5
--- /dev/null
+++ b/lib/asn1/test/testDefaultOctetString.erl
@@ -0,0 +1,34 @@
+-module(testDefaultOctetString).
+
+-export([dos/1]).
+
+-include_lib("common_test/include/ct.hrl").
+
+-record('Dos', {
+ opt = asn1_NOVALUE,
+ def = asn1_DEFAULT
+}).
+
+-define(def_DEFAULT, <<5>>).
+
+dos(Rules) ->
+ %% test roundtrip default
+ E1 = roundtrip(#'Dos'{}, #'Dos'{def = ?def_DEFAULT}),
+ %% test the value dos defined in the .asn file
+ E2 = roundtrip('DefaultOctetString':dos()),
+ %% sanity test a fully specified SEQUENCE
+ E3 = roundtrip(#'Dos'{opt = <<1,2,3>>, def = <<6>>}),
+ %% test def is/isn't encoded according to the value
+ if Rules == ber ->
+ <<48, 0>> = E1,
+ <<48, 4, 16#82, 2, 16#12, 16#34>> = E2,
+ <<48, 8, 16#82, 3, 1, 2, 3, 16#8A, 1, 6>> = E3;
+ true ->
+ ignore
+ end,
+ ok.
+
+roundtrip(Value) ->
+ roundtrip(Value, Value).
+roundtrip(Value, Exp) ->
+ asn1_test_lib:roundtrip('DefaultOctetString', 'Dos', Value, Exp).
diff --git a/lib/asn1/test/testSeqOfChoExt.erl b/lib/asn1/test/testSeqOfChoExt.erl
new file mode 100644
index 0000000000..1e72c60841
--- /dev/null
+++ b/lib/asn1/test/testSeqOfChoExt.erl
@@ -0,0 +1,15 @@
+-module(testSeqOfChoExt).
+
+-export([main/1]).
+
+%-record('Seq2', { octstr = asn1_NOVALUE }).
+%-record('Seq1', { int, soc }).
+
+main(_Rules) ->
+ roundtrip('SeqOfChoExt':seq1()).
+
+roundtrip(Value) ->
+ roundtrip(Value, Value).
+roundtrip(Value, Exp) ->
+ Type = element(1,Value),
+ asn1_test_lib:roundtrip('SeqOfChoExt', Type, Value, Exp).
diff --git a/lib/common_test/test_server/configure.in b/lib/common_test/test_server/configure.in
index e07bd4c2aa..a32d050081 100644
--- a/lib/common_test/test_server/configure.in
+++ b/lib/common_test/test_server/configure.in
@@ -171,7 +171,7 @@ case $system in
fi
SHLIB_EXTRACT_ALL=""
;;
- *-openbsd*)
+ *-openbsd*|*-netbsd*|*-freebsd*|*-dragonfly*)
# Not available on all versions: check for include file.
AC_CHECK_HEADER(dlfcn.h, [
SHLIB_CFLAGS="-fpic"
@@ -194,29 +194,6 @@ case $system in
])
SHLIB_EXTRACT_ALL=""
;;
- *-netbsd*|*-freebsd*|*-dragonfly*)
- # Not available on all versions: check for include file.
- AC_CHECK_HEADER(dlfcn.h, [
- SHLIB_CFLAGS="-fpic"
- SHLIB_LD="ld"
- SHLIB_LDFLAGS="$LDFLAGS -Bshareable -x"
- SHLIB_SUFFIX=".so"
- if test X${enable_m64_build} = Xyes; then
- AC_MSG_ERROR(don't know how to link 64-bit dynamic drivers)
- fi
- if test X${enable_m32_build} = Xyes; then
- AC_MSG_ERROR(don't know how to link 32-bit dynamic drivers)
- fi
- ], [
- # No dynamic loading.
- SHLIB_CFLAGS=""
- SHLIB_LD="ld"
- SHLIB_LDFLAGS=""
- SHLIB_SUFFIX=""
- AC_MSG_ERROR(don't know how to compile and link dynamic drivers)
- ])
- SHLIB_EXTRACT_ALL=""
- ;;
*-solaris2*|*-sysv4*)
SHLIB_CFLAGS="-KPIC"
SHLIB_LD="/usr/ccs/bin/ld"
diff --git a/lib/compiler/src/beam_ssa_type.erl b/lib/compiler/src/beam_ssa_type.erl
index c01ea4af91..06b42f1928 100644
--- a/lib/compiler/src/beam_ssa_type.erl
+++ b/lib/compiler/src/beam_ssa_type.erl
@@ -267,10 +267,29 @@ opt_is([#b_set{op=call,args=Args0,dst=Dst}=I0|Is],
I1 = beam_ssa:normalize(I0#b_set{args=Args}),
{Ts1,Ds,Fdb,I2} = opt_call(I1, D, Ts0, Ds0, Fdb0),
case {map_get(Dst, Ts1),Is} of
- {_,[#b_set{op=succeeded}]} ->
+ {Type,[#b_set{op=succeeded}]} when Type =/= none ->
%% This call instruction is inside a try/catch
- %% block. Don't attempt to optimize it.
+ %% block. Don't attempt to simplify it.
opt_is(Is, Ts1, Ds, Fdb, D, Sub0, [I2|Acc]);
+ {none,[#b_set{op=succeeded}]} ->
+ %% This call instruction is inside a try/catch
+ %% block, but we know it will never return and
+ %% later optimizations may try to exploit that.
+ %%
+ %% For example, if we have an expression that
+ %% either returns this call or a tuple, we know
+ %% that the expression always returns a tuple
+ %% and can turn a later element/3 into
+ %% get_tuple_element.
+ %%
+ %% This is sound but difficult to validate in a
+ %% meaningful way as try/catch currently forces
+ %% us to maintain the illusion that the success
+ %% block is reachable even when its not, so we
+ %% disable the optimization to keep things
+ %% simple.
+ Ts = Ts1#{ Dst := any },
+ opt_is(Is, Ts, Ds, Fdb, D, Sub0, [I2|Acc]);
{none,_} ->
%% This call never returns. The rest of the
%% instructions will not be executed.
diff --git a/lib/compiler/src/beam_validator.erl b/lib/compiler/src/beam_validator.erl
index 4fba3fa1c6..efd2be94cb 100644
--- a/lib/compiler/src/beam_validator.erl
+++ b/lib/compiler/src/beam_validator.erl
@@ -2899,8 +2899,6 @@ lists_mod_return_type(filter, 2, _Vst) ->
list;
lists_mod_return_type(flatten, 1, _Vst) ->
list;
-lists_mod_return_type(flatten, 2, _Vst) ->
- list;
lists_mod_return_type(map, 2, Vst) ->
same_length_type({x,1}, Vst);
lists_mod_return_type(MF, 3, Vst) when MF =:= mapfoldl; MF =:= mapfoldr ->
@@ -2912,8 +2910,6 @@ lists_mod_return_type(reverse, 1, Vst) ->
same_length_type({x,0}, Vst);
lists_mod_return_type(seq, 2, _Vst) ->
list;
-lists_mod_return_type(seq, 3, _Vst) ->
- list;
lists_mod_return_type(sort, 1, Vst) ->
same_length_type({x,0}, Vst);
lists_mod_return_type(sort, 2, Vst) ->
@@ -2927,16 +2923,10 @@ lists_mod_return_type(unzip, 1, Vst) ->
two_tuple(ListType, ListType);
lists_mod_return_type(usort, 1, Vst) ->
same_length_type({x,0}, Vst);
-lists_mod_return_type(usort, 2, Vst) ->
- same_length_type({x,1}, Vst);
lists_mod_return_type(zip, 2, _Vst) ->
list;
-lists_mod_return_type(zip3, 3, _Vst) ->
- list;
lists_mod_return_type(zipwith, 3, _Vst) ->
list;
-lists_mod_return_type(zipwith3, 4, _Vst) ->
- list;
lists_mod_return_type(_, _, _) ->
term.
diff --git a/lib/compiler/src/sys_core_fold.erl b/lib/compiler/src/sys_core_fold.erl
index 7e219da0af..4939a94a92 100644
--- a/lib/compiler/src/sys_core_fold.erl
+++ b/lib/compiler/src/sys_core_fold.erl
@@ -1997,53 +1997,22 @@ case_opt_compiler_generated(Core) ->
%% case_expand_var(Expr0, Sub) -> Expr
-%% If Expr0 is a variable that has been previously matched and
-%% is known to be a tuple, return the tuple instead. Otherwise
+%% If Expr0 is a variable that is known to be bound to a
+%% constructed tuple, return the tuple instead. Otherwise
%% return Expr0 unchanged.
-%%
+
case_expand_var(E, #sub{t=Tdb}) ->
Key = cerl:var_name(E),
case Tdb of
- #{Key:=T0} ->
- case cerl:is_c_tuple(T0) of
- false ->
- E;
- true ->
- %% The pattern was a tuple. Now we must make sure
- %% that the elements of the tuple are suitable. In
- %% particular, we don't want binary or map
- %% construction here, since that means that the
- %% binary or map will be constructed in the 'case'
- %% argument. That is wasteful for binaries. Even
- %% worse is that any map pattern that use the ':='
- %% operator will fail when used in map
- %% construction (only the '=>' operator is allowed
- %% when constructing a map from scratch).
- try
- cerl_trees:map(fun coerce_to_data/1, T0)
- catch
- throw:impossible ->
- %% Something unsuitable was found (map or
- %% or binary). Keep the variable.
- E
- end
+ #{Key:=T} ->
+ case cerl:is_c_tuple(T) of
+ false -> E;
+ true -> T
end;
_ ->
E
end.
-%% coerce_to_data(Core) -> Core'
-%% Coerce an element originally from a pattern to an data item or or
-%% variable. Throw an 'impossible' exception if non-data Core Erlang
-%% terms such as binary construction or map construction are
-%% encountered.
-
-coerce_to_data(C) ->
- case cerl:is_data(C) orelse cerl:is_c_var(C) of
- true -> C;
- false -> throw(impossible)
- end.
-
%% case_opt_nomatch(E, Clauses, LitExpr) -> Clauses'
%% Remove all clauses that cannot possibly match.
diff --git a/lib/compiler/test/beam_type_SUITE.erl b/lib/compiler/test/beam_type_SUITE.erl
index a7ffc3f60a..882e281a44 100644
--- a/lib/compiler/test/beam_type_SUITE.erl
+++ b/lib/compiler/test/beam_type_SUITE.erl
@@ -24,7 +24,7 @@
integers/1,numbers/1,coverage/1,booleans/1,setelement/1,
cons/1,tuple/1,record_float/1,binary_float/1,float_compare/1,
arity_checks/1,elixir_binaries/1,find_best/1,
- test_size/1]).
+ test_size/1,cover_lists_functions/1]).
suite() -> [{ct_hooks,[ts_install_cth]}].
@@ -46,7 +46,8 @@ groups() ->
arity_checks,
elixir_binaries,
find_best,
- test_size
+ test_size,
+ cover_lists_functions
]}].
init_per_suite(Config) ->
@@ -473,5 +474,18 @@ do_test_size(Term) when is_tuple(Term) ->
do_test_size(Term) when is_binary(Term) ->
size(Term).
+cover_lists_functions(Config) ->
+ case lists:suffix([no|Config], Config) of
+ true ->
+ ct:fail(should_be_false);
+ false ->
+ ok
+ end,
+ Zipped = lists:zipwith(fun(A, B) -> {A,B} end,
+ lists:duplicate(length(Config), zip),
+ Config),
+ true = is_list(Zipped),
+ ok.
+
id(I) ->
I.
diff --git a/lib/compiler/test/bs_construct_SUITE.erl b/lib/compiler/test/bs_construct_SUITE.erl
index 69017d87e7..bccd70d6cb 100644
--- a/lib/compiler/test/bs_construct_SUITE.erl
+++ b/lib/compiler/test/bs_construct_SUITE.erl
@@ -27,6 +27,7 @@
-export([all/0, suite/0,groups/0,init_per_suite/1, end_per_suite/1,
init_per_group/2,end_per_group/2,
init_per_testcase/2,end_per_testcase/2,
+ verify_highest_opcode/1,
two/1,test1/1,fail/1,float_bin/1,in_guard/1,in_catch/1,
nasty_literals/1,coerce_to_float/1,side_effect/1,
opt/1,otp_7556/1,float_arith/1,otp_8054/1,
@@ -43,7 +44,8 @@ all() ->
groups() ->
[{p,[parallel],
- [two,test1,fail,float_bin,in_guard,in_catch,
+ [verify_highest_opcode,
+ two,test1,fail,float_bin,in_guard,in_catch,
nasty_literals,side_effect,opt,otp_7556,float_arith,
otp_8054,cover]}].
@@ -68,6 +70,20 @@ init_per_testcase(Case, Config) when is_atom(Case), is_list(Config) ->
end_per_testcase(Case, Config) when is_atom(Case), is_list(Config) ->
ok.
+verify_highest_opcode(_Config) ->
+ case ?MODULE of
+ bs_construct_r21_SUITE ->
+ {ok,Beam} = file:read_file(code:which(?MODULE)),
+ case test_lib:highest_opcode(Beam) of
+ Highest when Highest =< 163 ->
+ ok;
+ TooHigh ->
+ ct:fail({too_high_opcode_for_21,TooHigh})
+ end;
+ _ ->
+ ok
+ end.
+
two(Config) when is_list(Config) ->
<<0,1,2,3,4,6,7,8,9>> = two_1([0], [<<1,2,3,4>>,<<6,7,8,9>>]),
ok.
diff --git a/lib/compiler/test/bs_match_SUITE.erl b/lib/compiler/test/bs_match_SUITE.erl
index 2cfcb841a7..41e4918b1e 100644
--- a/lib/compiler/test/bs_match_SUITE.erl
+++ b/lib/compiler/test/bs_match_SUITE.erl
@@ -24,6 +24,7 @@
-export([all/0, suite/0,groups/0,init_per_suite/1, end_per_suite/1,
init_per_group/2,end_per_group/2,
init_per_testcase/2,end_per_testcase/2,
+ verify_highest_opcode/1,
size_shadow/1,int_float/1,otp_5269/1,null_fields/1,wiger/1,
bin_tail/1,save_restore/1,
partitioned_bs_match/1,function_clause/1,
@@ -60,7 +61,8 @@ all() ->
groups() ->
[{p,[],
- [size_shadow,int_float,otp_5269,null_fields,wiger,
+ [verify_highest_opcode,
+ size_shadow,int_float,otp_5269,null_fields,wiger,
bin_tail,save_restore,
partitioned_bs_match,function_clause,unit,
shared_sub_bins,bin_and_float,dec_subidentifiers,
@@ -101,6 +103,20 @@ init_per_testcase(Case, Config) when is_atom(Case), is_list(Config) ->
end_per_testcase(Case, Config) when is_atom(Case), is_list(Config) ->
ok.
+verify_highest_opcode(_Config) ->
+ case ?MODULE of
+ bs_match_r21_SUITE ->
+ {ok,Beam} = file:read_file(code:which(?MODULE)),
+ case test_lib:highest_opcode(Beam) of
+ Highest when Highest =< 163 ->
+ ok;
+ TooHigh ->
+ ct:fail({too_high_opcode_for_21,TooHigh})
+ end;
+ _ ->
+ ok
+ end.
+
size_shadow(Config) when is_list(Config) ->
%% Originally OTP-5270.
7 = size_shadow_1(),
diff --git a/lib/compiler/test/compile_SUITE.erl b/lib/compiler/test/compile_SUITE.erl
index 408af80dd9..53627b9d81 100644
--- a/lib/compiler/test/compile_SUITE.erl
+++ b/lib/compiler/test/compile_SUITE.erl
@@ -1431,9 +1431,7 @@ bc_options(Config) ->
highest_opcode(DataDir, Mod, Opt) ->
Src = filename:join(DataDir, atom_to_list(Mod)++".erl"),
{ok,Mod,Beam} = compile:file(Src, [binary|Opt]),
- {ok,{Mod,[{"Code",Code}]}} = beam_lib:chunks(Beam, ["Code"]),
- <<16:32,0:32,HighestOpcode:32,_/binary>> = Code,
- HighestOpcode.
+ test_lib:highest_opcode(Beam).
deterministic_include(Config) when is_list(Config) ->
DataDir = proplists:get_value(data_dir, Config),
diff --git a/lib/compiler/test/test_lib.erl b/lib/compiler/test/test_lib.erl
index 39c26c6142..3348c6e9ea 100644
--- a/lib/compiler/test/test_lib.erl
+++ b/lib/compiler/test/test_lib.erl
@@ -22,7 +22,8 @@
-include_lib("common_test/include/ct.hrl").
-compile({no_auto_import,[binary_part/2]}).
-export([id/1,recompile/1,parallel/0,uniq/0,opt_opts/1,get_data_dir/1,
- is_cloned_mod/1,smoke_disasm/1,p_run/2]).
+ is_cloned_mod/1,smoke_disasm/1,p_run/2,
+ highest_opcode/1]).
%% Used by test case that override BIFs.
-export([binary_part/2,binary/1]).
@@ -113,6 +114,14 @@ is_cloned_mod_1("_no_module_opt_SUITE") -> true;
is_cloned_mod_1([_|T]) -> is_cloned_mod_1(T);
is_cloned_mod_1([]) -> false.
+%% Return the highest opcode use in the BEAM module.
+
+highest_opcode(Beam) ->
+ {ok,{_Mod,[{"Code",Code}]}} = beam_lib:chunks(Beam, ["Code"]),
+ FormatNumber = 0,
+ <<16:32,FormatNumber:32,HighestOpcode:32,_/binary>> = Code,
+ HighestOpcode.
+
%% p_run(fun(Data) -> ok|error, List) -> ok
%% Will fail the test case if there were any errors.
diff --git a/lib/compiler/test/trycatch_SUITE.erl b/lib/compiler/test/trycatch_SUITE.erl
index 8f9cd9ab1e..539f9d69fa 100644
--- a/lib/compiler/test/trycatch_SUITE.erl
+++ b/lib/compiler/test/trycatch_SUITE.erl
@@ -27,7 +27,8 @@
nested_horrid/1,last_call_optimization/1,bool/1,
plain_catch_coverage/1,andalso_orelse/1,get_in_try/1,
hockey/1,handle_info/1,catch_in_catch/1,grab_bag/1,
- stacktrace/1,nested_stacktrace/1,raise/1]).
+ stacktrace/1,nested_stacktrace/1,raise/1,
+ no_return_in_try_block/1]).
-include_lib("common_test/include/ct.hrl").
@@ -43,7 +44,8 @@ groups() ->
nested_after,nested_horrid,last_call_optimization,
bool,plain_catch_coverage,andalso_orelse,get_in_try,
hockey,handle_info,catch_in_catch,grab_bag,
- stacktrace,nested_stacktrace,raise]}].
+ stacktrace,nested_stacktrace,raise,
+ no_return_in_try_block]}].
init_per_suite(Config) ->
@@ -1287,5 +1289,26 @@ do_test_raise_4(Expr) ->
erlang:raise(exit, {exception,C,E,Stk}, Stk)
end.
+no_return_in_try_block(Config) when is_list(Config) ->
+ 1.0 = no_return_in_try_block_1(0),
+ 1.0 = no_return_in_try_block_1(0.0),
+
+ gurka = no_return_in_try_block_1(gurka),
+ [] = no_return_in_try_block_1([]),
+
+ ok.
+
+no_return_in_try_block_1(H) ->
+ try
+ Float = if
+ is_number(H) -> float(H);
+ true -> no_return()
+ end,
+ Float + 1
+ catch
+ throw:no_return -> H
+ end.
+
+no_return() -> throw(no_return).
id(I) -> I.
diff --git a/lib/crypto/c_src/aead.c b/lib/crypto/c_src/aead.c
index 3ee04f1be9..4ed16615a5 100644
--- a/lib/crypto/c_src/aead.c
+++ b/lib/crypto/c_src/aead.c
@@ -39,87 +39,79 @@ ERL_NIF_TERM aead_encrypt(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
ASSERT(argc == 6);
if (!enif_is_atom(env, type))
- goto bad_arg;
+ {ret = EXCP_BADARG(env, "non-atom cipher type"); goto done;}
if (!enif_inspect_iolist_as_binary(env, argv[1], &key))
- goto bad_arg;
+ {ret = EXCP_BADARG(env, "non-binary key"); goto done;}
if (!enif_inspect_binary(env, argv[2], &iv))
- goto bad_arg;
+ {ret = EXCP_BADARG(env, "non-binary iv"); goto done;}
if (!enif_inspect_iolist_as_binary(env, argv[3], &aad))
- goto bad_arg;
+ {ret = EXCP_BADARG(env, "non-binary AAD"); goto done;}
if (!enif_inspect_iolist_as_binary(env, argv[4], &in))
- goto bad_arg;
+ {ret = EXCP_BADARG(env, "non-binary text"); goto done;}
if (!enif_get_uint(env, argv[5], &tag_len))
- goto bad_arg;
+ {ret = EXCP_BADARG(env, ""); goto done;}
if (tag_len > INT_MAX
|| iv.size > INT_MAX
|| in.size > INT_MAX
|| aad.size > INT_MAX)
- goto bad_arg;
+ {ret = EXCP_BADARG(env, "binary too long"); goto done;}
if ((cipherp = get_cipher_type(type, key.size)) == NULL)
- goto bad_arg;
+ {ret = EXCP_BADARG(env, "Unknown cipher"); goto done;}
if (cipherp->flags & NON_EVP_CIPHER)
- goto bad_arg;
+ {ret = EXCP_BADARG(env, "Bad cipher"); goto done;}
if (! (cipherp->flags & AEAD_CIPHER) )
- goto bad_arg;
+ {ret = EXCP_BADARG(env, "Not aead cipher"); goto done;}
if ((cipher = cipherp->cipher.p) == NULL)
- return enif_raise_exception(env, atom_notsup);
+ {ret = EXCP_NOTSUP(env, "Cipher not supported in this libcrypto version"); goto done;}
ctx_ctrl_set_ivlen = cipherp->extra.aead.ctx_ctrl_set_ivlen;
ctx_ctrl_get_tag = cipherp->extra.aead.ctx_ctrl_get_tag;
ctx_ctrl_set_tag = cipherp->extra.aead.ctx_ctrl_set_tag;
if ((ctx = EVP_CIPHER_CTX_new()) == NULL)
- goto err;
+ {ret = EXCP_ERROR(env, ""); goto done;}
if (EVP_EncryptInit_ex(ctx, cipher, NULL, NULL, NULL) != 1)
- goto err;
+ {ret = EXCP_ERROR(env, ""); goto done;}
if (EVP_CIPHER_CTX_ctrl(ctx, ctx_ctrl_set_ivlen, (int)iv.size, NULL) != 1)
- goto err;
+ {ret = EXCP_ERROR(env, ""); goto done;}
#if defined(HAVE_CCM)
if (type == atom_aes_ccm) {
if (EVP_CIPHER_CTX_ctrl(ctx, ctx_ctrl_set_tag, (int)tag_len, NULL) != 1)
- goto err;
+ {ret = EXCP_ERROR(env, ""); goto done;}
if (EVP_EncryptInit_ex(ctx, NULL, NULL, key.data, iv.data) != 1)
- goto err;
+ {ret = EXCP_ERROR(env, ""); goto done;}
if (EVP_EncryptUpdate(ctx, NULL, &len, NULL, (int)in.size) != 1)
- goto err;
+ {ret = EXCP_ERROR(env, ""); goto done;}
} else
#endif
{
if (EVP_EncryptInit_ex(ctx, NULL, NULL, key.data, iv.data) != 1)
- goto err;
+ {ret = EXCP_ERROR(env, ""); goto done;}
}
if (EVP_EncryptUpdate(ctx, NULL, &len, aad.data, (int)aad.size) != 1)
- goto err;
+ {ret = EXCP_ERROR(env, ""); goto done;}
if ((outp = enif_make_new_binary(env, in.size, &out)) == NULL)
- goto err;
+ {ret = EXCP_ERROR(env, ""); goto done;}
if (EVP_EncryptUpdate(ctx, outp, &len, in.data, (int)in.size) != 1)
- goto err;
+ {ret = EXCP_ERROR(env, ""); goto done;}
if (EVP_EncryptFinal_ex(ctx, outp/*+len*/, &len) != 1)
- goto err;
+ {ret = EXCP_ERROR(env, ""); goto done;}
if ((tagp = enif_make_new_binary(env, tag_len, &out_tag)) == NULL)
- goto err;
+ {ret = EXCP_ERROR(env, ""); goto done;}
if (EVP_CIPHER_CTX_ctrl(ctx, ctx_ctrl_get_tag, (int)tag_len, tagp) != 1)
- goto err;
+ {ret = EXCP_ERROR(env, ""); goto done;}
CONSUME_REDS(env, in);
ret = enif_make_tuple2(env, out, out_tag);
- goto done;
-
- bad_arg:
- ret = enif_make_badarg(env);
- goto done;
-
- err:
- ret = atom_error;
done:
if (ctx)
@@ -127,7 +119,7 @@ ERL_NIF_TERM aead_encrypt(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
return ret;
#else
- return enif_raise_exception(env, atom_notsup);
+ return EXCP_NOTSUP(env, "");
#endif
}
@@ -151,72 +143,72 @@ ERL_NIF_TERM aead_decrypt(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
#endif
if (!enif_is_atom(env, type))
- goto bad_arg;
+ {ret = EXCP_BADARG(env, "non-atom cipher type"); goto done;}
if (!enif_inspect_iolist_as_binary(env, argv[1], &key))
- goto bad_arg;
+ {ret = EXCP_BADARG(env, "non-binary key"); goto done;}
if (!enif_inspect_binary(env, argv[2], &iv))
- goto bad_arg;
+ {ret = EXCP_BADARG(env, "non-binary iv"); goto done;}
if (!enif_inspect_iolist_as_binary(env, argv[3], &aad))
- goto bad_arg;
+ {ret = EXCP_BADARG(env, "non-binary AAD"); goto done;}
if (!enif_inspect_iolist_as_binary(env, argv[4], &in))
- goto bad_arg;
+ {ret = EXCP_BADARG(env, ""); goto done;}
if (!enif_inspect_iolist_as_binary(env, argv[5], &tag))
- goto bad_arg;
+ {ret = EXCP_BADARG(env, "non-binary text"); goto done;}
if (tag.size > INT_MAX
|| key.size > INT_MAX
|| iv.size > INT_MAX
|| in.size > INT_MAX
|| aad.size > INT_MAX)
- goto bad_arg;
+ {ret = EXCP_BADARG(env, "binary too long"); goto done;}
if ((cipherp = get_cipher_type(type, key.size)) == NULL)
- goto bad_arg;
+ {ret = EXCP_BADARG(env, "Unknown cipher"); goto done;}
if (cipherp->flags & NON_EVP_CIPHER)
- goto bad_arg;
+ {ret = EXCP_BADARG(env, "Bad cipher"); goto done;}
if ( !(cipherp->flags & AEAD_CIPHER) )
- goto bad_arg;
+ {ret = EXCP_BADARG(env, "Not aead cipher"); goto done;}
if ((cipher = cipherp->cipher.p) == NULL)
- return enif_raise_exception(env, atom_notsup);
+ {ret = EXCP_NOTSUP(env, "Cipher not supported in this libcrypto version"); goto done;}
ctx_ctrl_set_ivlen = cipherp->extra.aead.ctx_ctrl_set_ivlen;
ctx_ctrl_set_tag = cipherp->extra.aead.ctx_ctrl_set_tag;
if ((outp = enif_make_new_binary(env, in.size, &out)) == NULL)
- goto err;
+ {ret = EXCP_ERROR(env, ""); goto done;}
if ((ctx = EVP_CIPHER_CTX_new()) == NULL)
- goto err;
+ {ret = EXCP_ERROR(env, ""); goto done;}
if (EVP_DecryptInit_ex(ctx, cipher, NULL, NULL, NULL) != 1)
- goto err;
+ {ret = EXCP_ERROR(env, ""); goto done;}
if (EVP_CIPHER_CTX_ctrl(ctx, ctx_ctrl_set_ivlen, (int)iv.size, NULL) != 1)
- goto err;
+ {ret = EXCP_ERROR(env, ""); goto done;}
#if defined(HAVE_CCM)
if (type == atom_aes_ccm) {
if (EVP_CIPHER_CTX_ctrl(ctx, ctx_ctrl_set_tag, (int)tag.size, tag.data) != 1)
- goto err;
+ {ret = EXCP_ERROR(env, ""); goto done;}
if (EVP_DecryptInit_ex(ctx, NULL, NULL, key.data, iv.data) != 1)
- goto err;
+ {ret = EXCP_ERROR(env, ""); goto done;}
if (EVP_DecryptUpdate(ctx, NULL, &len, NULL, (int)in.size) != 1)
- goto err;
+ {ret = EXCP_ERROR(env, ""); goto done;}
}
else
#endif
{
if (EVP_DecryptInit_ex(ctx, NULL, NULL, key.data, iv.data) != 1)
- goto err;
+ {ret = EXCP_ERROR(env, ""); goto done;}
}
if (EVP_DecryptUpdate(ctx, NULL, &len, aad.data, (int)aad.size) != 1)
- goto err;
+ {ret = EXCP_ERROR(env, ""); goto done;}
if (EVP_DecryptUpdate(ctx, outp, &len, in.data, (int)in.size) != 1)
- goto err;
+ {ret = EXCP_ERROR(env, ""); goto done;}
#if defined(HAVE_GCM)
if (type == atom_aes_gcm) {
if (EVP_CIPHER_CTX_ctrl(ctx, ctx_ctrl_set_tag, (int)tag.size, tag.data) != 1)
- goto err;
+ goto err;
if (EVP_DecryptFinal_ex(ctx, outp+len, &len) != 1)
goto err;
}
@@ -225,11 +217,8 @@ ERL_NIF_TERM aead_decrypt(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
ret = out;
goto done;
- bad_arg:
- ret = enif_make_badarg(env);
- goto done;
-
err:
+ /* Decrypt failed, that is, wrong tag */
ret = atom_error;
done:
@@ -238,6 +227,6 @@ ERL_NIF_TERM aead_decrypt(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
return ret;
#else
- return enif_raise_exception(env, atom_notsup);
+ return EXCP_NOTSUP(env, "");
#endif
}
diff --git a/lib/crypto/c_src/api_ng.c b/lib/crypto/c_src/api_ng.c
index f4312114ed..5d063c3ae4 100644
--- a/lib/crypto/c_src/api_ng.c
+++ b/lib/crypto/c_src/api_ng.c
@@ -29,18 +29,6 @@
ERL_NIF_TERM ng_crypto_update(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
ERL_NIF_TERM ng_crypto_one_shot(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
-
-
-/* All nif functions return a valid value or throws an exception */
-#define EXCP(Env, Class, Str) enif_raise_exception((Env), \
- enif_make_tuple2((Env), (Class), \
- enif_make_string((Env),(Str),(ERL_NIF_LATIN1)) ))
-
-#define EXCP_NOTSUP(Env, Str) EXCP((Env), atom_notsup, (Str))
-#define EXCP_BADARG(Env, Str) EXCP((Env), atom_badarg, (Str))
-#define EXCP_ERROR(Env, Str) EXCP((Env), atom_error, (Str))
-
-
#ifdef HAVE_ECB_IVEC_BUG
/* <= 0.9.8l returns faulty ivec length */
# define GET_IV_LEN(Ciph) ((Ciph)->flags & ECB_BUG_0_9_8L) ? 0 : EVP_CIPHER_iv_length((Ciph)->cipher.p)
diff --git a/lib/crypto/c_src/atoms.c b/lib/crypto/c_src/atoms.c
index 114e3c1985..0793ffa6ca 100644
--- a/lib/crypto/c_src/atoms.c
+++ b/lib/crypto/c_src/atoms.c
@@ -52,6 +52,12 @@ ERL_NIF_TERM atom_ecb_mode;
ERL_NIF_TERM atom_cbc_mode;
ERL_NIF_TERM atom_cfb_mode;
ERL_NIF_TERM atom_ofb_mode;
+ERL_NIF_TERM atom_ctr_mode;
+ERL_NIF_TERM atom_gcm_mode;
+ERL_NIF_TERM atom_ccm_mode;
+ERL_NIF_TERM atom_xts_mode;
+ERL_NIF_TERM atom_wrap_mode;
+ERL_NIF_TERM atom_ocb_mode;
ERL_NIF_TERM atom_stream_cipher;
#if defined(HAVE_EC)
@@ -164,6 +170,12 @@ int init_atoms(ErlNifEnv *env, const ERL_NIF_TERM fips_mode, const ERL_NIF_TERM
atom_cbc_mode = enif_make_atom(env,"cbc_mode");
atom_cfb_mode = enif_make_atom(env,"cfb_mode");
atom_ofb_mode = enif_make_atom(env,"ofb_mode");
+ atom_ctr_mode = enif_make_atom(env,"ctr_mode");
+ atom_gcm_mode = enif_make_atom(env,"gcm_mode");
+ atom_ccm_mode = enif_make_atom(env,"ccm_mode");
+ atom_xts_mode = enif_make_atom(env,"xts_mode");
+ atom_wrap_mode = enif_make_atom(env,"wrap_mode");
+ atom_ocb_mode = enif_make_atom(env,"ocb_mode");
atom_stream_cipher = enif_make_atom(env,"stream_cipher");
#if defined(HAVE_EC)
diff --git a/lib/crypto/c_src/atoms.h b/lib/crypto/c_src/atoms.h
index fc46d838aa..24f6dc26fd 100644
--- a/lib/crypto/c_src/atoms.h
+++ b/lib/crypto/c_src/atoms.h
@@ -56,6 +56,12 @@ extern ERL_NIF_TERM atom_ecb_mode;
extern ERL_NIF_TERM atom_cbc_mode;
extern ERL_NIF_TERM atom_cfb_mode;
extern ERL_NIF_TERM atom_ofb_mode;
+extern ERL_NIF_TERM atom_ctr_mode;
+extern ERL_NIF_TERM atom_gcm_mode;
+extern ERL_NIF_TERM atom_ccm_mode;
+extern ERL_NIF_TERM atom_xts_mode;
+extern ERL_NIF_TERM atom_wrap_mode;
+extern ERL_NIF_TERM atom_ocb_mode;
extern ERL_NIF_TERM atom_stream_cipher;
#if defined(HAVE_EC)
diff --git a/lib/crypto/c_src/cipher.c b/lib/crypto/c_src/cipher.c
index 9d60254a3c..2652e1db4e 100644
--- a/lib/crypto/c_src/cipher.c
+++ b/lib/crypto/c_src/cipher.c
@@ -274,6 +274,42 @@ ERL_NIF_TERM cipher_info_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]
ret_mode = atom_ofb_mode;
break;
+#ifdef EVP_CIPH_CTR_MODE
+ case EVP_CIPH_CTR_MODE:
+ ret_mode = atom_ctr_mode;
+ break;
+#endif
+
+#ifdef EVP_CIPH_GCM_MODE
+ case EVP_CIPH_GCM_MODE:
+ ret_mode = atom_gcm_mode;
+ break;
+#endif
+
+#ifdef EVP_CIPH_CCM_MODE
+ case EVP_CIPH_CCM_MODE:
+ ret_mode = atom_ccm_mode;
+ break;
+#endif
+
+#ifdef EVP_CIPH_XTS_MODE
+ case EVP_CIPH_XTS_MODE:
+ ret_mode = atom_xts_mode;
+ break;
+#endif
+
+#ifdef EVP_CIPH_WRAP_MODE
+ case EVP_CIPH_WRAP_MODE:
+ ret_mode = atom_wrap_mode;
+ break;
+#endif
+
+#ifdef EVP_CIPH_OCB_MODE
+ case EVP_CIPH_OCB_MODE:
+ ret_mode = atom_ocb_mode;
+ break;
+#endif
+
case EVP_CIPH_STREAM_CIPHER:
ret_mode = atom_stream_cipher;
break;
diff --git a/lib/crypto/c_src/common.h b/lib/crypto/c_src/common.h
index 2bc8bdd73c..0bf7f09f4f 100644
--- a/lib/crypto/c_src/common.h
+++ b/lib/crypto/c_src/common.h
@@ -35,4 +35,15 @@
#include "openssl_config.h"
#include "atoms.h"
+
+/* All nif functions return a valid value or throws an exception */
+#define EXCP(Env, Id, Str) enif_raise_exception((Env), \
+ enif_make_tuple2((Env), \
+ (Id), \
+ enif_make_string((Env),(Str),(ERL_NIF_LATIN1)) ))
+
+#define EXCP_NOTSUP(Env, Str) EXCP((Env), atom_notsup, (Str))
+#define EXCP_BADARG(Env, Str) EXCP((Env), atom_badarg, (Str))
+#define EXCP_ERROR(Env, Str) EXCP((Env), atom_error, (Str))
+
#endif /* E_COMMON_H__ */
diff --git a/lib/crypto/doc/src/crypto.xml b/lib/crypto/doc/src/crypto.xml
index 83e10c4c78..8a4fad67de 100644
--- a/lib/crypto/doc/src/crypto.xml
+++ b/lib/crypto/doc/src/crypto.xml
@@ -192,7 +192,16 @@
<datatypes>
<datatype_title>Ciphers</datatype_title>
<datatype>
+ <name name="cipher"/>
<name name="stream_cipher"/>
+ <name name="block_cipher"/>
+ <desc>
+ <p>Ciphers known byt the CRYPTO application. Note that this list might be reduced if the
+ underlying libcrypto does not support all of them.</p>
+ </desc>
+ </datatype>
+
+ <datatype>
<name name="stream_cipher_iv"/>
<name name="stream_cipher_no_iv"/>
<desc>
@@ -204,7 +213,7 @@
</datatype>
<datatype>
- <name name="block_cipher_with_iv"/>
+ <name name="block_cipher_iv"/>
<name name="cbc_cipher"/>
<name name="cfb_cipher"/>
<desc>
@@ -228,7 +237,7 @@
</datatype>
<datatype>
- <name name="block_cipher_without_iv"/>
+ <name name="block_cipher_no_iv"/>
<name name="ecb_cipher"/>
<desc>
<p>Block ciphers without initialization vector for
@@ -248,20 +257,16 @@
</desc>
</datatype>
- <datatype_title>Digests</datatype_title>
+ <datatype_title>Digests and hash</datatype_title>
<datatype>
- <name name="sha1"/>
- <name name="sha2"/>
- <name name="sha3"/>
- <name name="blake2"/>
+ <name name="hash_algorithm"/>
<desc>
</desc>
</datatype>
<datatype>
- <name name="compatibility_only_hash"/>
+ <name name="hmac_hash_algorithm"/>
<desc>
- <p>The <c>compatibility_only_hash()</c> algorithms are recommended only for compatibility with existing applications.</p>
</desc>
</datatype>
@@ -283,6 +288,17 @@
</desc>
</datatype>
+ <datatype>
+ <name name="sha1"/>
+ <name name="sha2"/>
+ <name name="sha3"/>
+ <name name="blake2"/>
+ <name name="compatibility_only_hash"/>
+ <desc>
+ <p>The <c>compatibility_only_hash()</c> algorithms are recommended only for compatibility with existing applications.</p>
+ </desc>
+ </datatype>
+
<datatype_title>Elliptic Curves</datatype_title>
<datatype>
<name name="ec_named_curve"/>
@@ -537,6 +553,52 @@
</desc>
</datatype>
+ <datatype_title>Error types</datatype_title>
+
+ <datatype>
+ <name name="run_time_error"/>
+ <desc>
+ <p>The exception <c>error:badarg</c> signifies that one or more arguments are of wrong data type,
+ or are otherwise badly formed.
+ </p>
+ <p>The exception <c>error:notsup</c> signifies that the algorithm is known but is not supported
+ by current underlying libcrypto or explicitly disabled when building that.
+ </p>
+ <p>For a list of supported algorithms, see <seealso marker="#supports-0">supports/0</seealso>.
+ </p>
+ </desc>
+ </datatype>
+
+ <datatype>
+ <name name="descriptive_error"/>
+ <desc>
+ <p>This is a more developed variant of the older
+ <seealso marker="#type-run_time_error">run_time_error()</seealso>.
+ </p>
+ <p>It is like the older type an exception of the <c>error</c> class. In addition they contain
+ a descriptive text in English. That text is targeted to a developer. Examples are "Bad key size"
+ or "Cipher id is not an atom".
+ </p>
+ <p>The exceptions are:</p>
+ <taglist>
+ <tag><c>{badarg, Description::string()}</c></tag>
+ <item><p>Signifies that one or more arguments are of wrong data type or are otherwise badly formed.</p>
+ </item>
+
+ <tag><c>{notsup, Description::string()}</c></tag>
+ <item><p>Signifies that the algorithm is known but is not supported by current underlying libcrypto
+ or explicitly disabled when building that one.</p>
+ </item>
+
+ <tag><c>{error, Description::string()}</c></tag>
+ <item><p>An error condition that should not occur, for example a memory allocation failed or
+ the underlying cryptolib returned an error code, for example "Can't initialize context, step 1".
+ Thoose text usually needs searching the C-code to be understood.</p>
+ </item>
+ </taglist>
+ </desc>
+ </datatype>
+
</datatypes>
<!--================ FUNCTIONS ================-->
@@ -568,17 +630,18 @@
</func>
<func>
- <name since="OTP R16B01">block_encrypt(Type, Key, Ivec, PlainText) -> CipherText</name>
- <name since="OTP R16B01">block_encrypt(AeadType, Key, Ivec, {AAD, PlainText}) -> {CipherText, CipherTag}</name>
- <name since="OTP R16B01">block_encrypt(aes_gcm | aes_ccm, Key, Ivec, {AAD, PlainText, TagLength}) -> {CipherText, CipherTag}</name>
+ <name since="OTP R16B01">block_encrypt(Type, Key, Ivec, PlainText) -> CipherText | Error</name>
+ <name since="OTP R16B01">block_encrypt(AeadType, Key, Ivec, {AAD, PlainText}) -> {CipherText, CipherTag} | Error</name>
+ <name since="OTP R16B01">block_encrypt(aes_gcm | aes_ccm, Key, Ivec, {AAD, PlainText, TagLength}) -> {CipherText, CipherTag} | Error </name>
<fsummary>Encrypt <c>PlainText</c> according to <c>Type</c> block cipher</fsummary>
<type>
- <v>Type = <seealso marker="#type-block_cipher_with_iv">block_cipher_with_iv()</seealso></v>
+ <v>Type = <seealso marker="#type-block_cipher_iv">block_cipher_iv()</seealso></v>
<v>AeadType = <seealso marker="#type-aead_cipher">aead_cipher()</seealso></v>
<v>Key = <seealso marker="#type-key">key()</seealso> | <seealso marker="#type-des3_key">des3_key()</seealso></v>
<v>PlainText = iodata()</v>
<v>AAD = IVec = CipherText = CipherTag = binary()</v>
<v>TagLength = 1..16</v>
+ <v>Error = <seealso marker="#type-run_time_error">run_time_error()</seealso></v>
</type>
<desc>
<p>Encrypt <c>PlainText</c> according to <c>Type</c> block cipher.
@@ -595,15 +658,17 @@
</func>
<func>
- <name since="OTP R16B01">block_decrypt(Type, Key, Ivec, CipherText) -> PlainText</name>
- <name since="OTP R16B01">block_decrypt(AeadType, Key, Ivec, {AAD, CipherText, CipherTag}) -> PlainText | error</name>
+ <name since="OTP R16B01">block_decrypt(Type, Key, Ivec, CipherText) -> PlainText | Error</name>
+ <name since="OTP R16B01">block_decrypt(AeadType, Key, Ivec, {AAD, CipherText, CipherTag}) -> PlainText | Error</name>
<fsummary>Decrypt <c>CipherText</c> according to <c>Type</c> block cipher</fsummary>
<type>
- <v>Type = <seealso marker="#type-block_cipher_with_iv">block_cipher_with_iv()</seealso></v>
+ <v>Type = <seealso marker="#type-block_cipher_iv">block_cipher_iv()</seealso></v>
<v>AeadType = <seealso marker="#type-aead_cipher">aead_cipher()</seealso></v>
<v>Key = <seealso marker="#type-key">key()</seealso> | <seealso marker="#type-des3_key">des3_key()</seealso></v>
<v>PlainText = iodata()</v>
<v>AAD = IVec = CipherText = CipherTag = binary()</v>
+ <v>Error = BadTag | <seealso marker="#type-run_time_error">run_time_error()</seealso></v>
+ <v>BadTag = error</v>
</type>
<desc>
<p>Decrypt <c>CipherText</c> according to <c>Type</c> block cipher.
@@ -844,6 +909,39 @@
</func>
<func>
+ <name name="hash_info" arity="1" since="OTP 22.0"/>
+ <fsummary>Information about supported hash algorithms.</fsummary>
+ <desc>
+ <p>Provides a map with information about block_size, size and possibly other properties of the
+ hash algorithm in question.
+ </p>
+ <p>For a list of supported hash algorithms, see <seealso marker="#supports-0">supports/0</seealso>.
+ </p>
+ </desc>
+ </func>
+
+ <func>
+ <name name="cipher_info" arity="1" since="OTP 22.0"/>
+ <fsummary>Information about supported ciphers.</fsummary>
+ <desc>
+ <p>Provides a map with information about block_size, key_length, iv_length and possibly other properties of the
+ cipher algorithm in question.
+ </p>
+ <note>
+ <p>The ciphers <c>aes_cbc</c>, <c>aes_cfb8</c>, <c>aes_cfb128</c>, <c>aes_ctr</c>,
+ <c>aes_ecb</c>, <c>aes_gcm</c> and <c>aes_ccm</c>
+ has no keylength in the <c>Type</c> as opposed to for example <c>aes_128_ctr</c>. They adapt to the length of
+ the key provided in the encrypt and decrypt function. Therefor it is impossible to return a valid keylength
+ in the map.</p>
+ <p>Always use a <c>Type</c> with an explicit key length,
+ </p>
+ </note>
+ <p>For a list of supported cipher algorithms, see <seealso marker="#supports-0">supports/0</seealso>.
+ </p>
+ </desc>
+ </func>
+
+ <func>
<name name="mod_pow" arity="3" since="OTP R16B01"/>
<fsummary>Computes the function: N^P mod M</fsummary>
<desc>
@@ -1289,8 +1387,8 @@ FloatValue = rand:uniform(). % again
<desc>
<p> Can be used to determine which crypto algorithms that are supported
by the underlying libcrypto library</p>
- <p>Note: the <c>rsa_opts</c> entry is in an experimental state and may change or be removed without notice.
- No guarantee for the accuarcy of the rsa option's value list should be assumed.
+ <p>See <seealso marker="#hash_info-1">hash_info/1</seealso> and <seealso marker="#cipher_info-1">cipher_info/1</seealso>
+ for information about the hash and cipher algorithms.
</p>
</desc>
</func>
diff --git a/lib/crypto/src/crypto.erl b/lib/crypto/src/crypto.erl
index 5cf34f8069..fd13481951 100644
--- a/lib/crypto/src/crypto.erl
+++ b/lib/crypto/src/crypto.erl
@@ -277,7 +277,13 @@
-type edwards_curve_ed() :: ed25519 | ed448 .
%%%
--type block_cipher_with_iv() :: cbc_cipher()
+-type cipher() :: block_cipher()
+ | stream_cipher()
+ | aead_cipher() .
+
+-type block_cipher() :: block_cipher_iv() | block_cipher_no_iv() .
+
+-type block_cipher_iv() :: cbc_cipher()
| cfb_cipher()
| aes_ige256
| blowfish_ofb64
@@ -310,7 +316,7 @@
| des3_cfb .
--type block_cipher_without_iv() :: ecb_cipher() .
+-type block_cipher_no_iv() :: ecb_cipher() .
-type ecb_cipher() :: des_ecb | blowfish_ecb | aes_ecb .
-type key() :: iodata().
@@ -330,6 +336,20 @@
-type crypto_integer() :: binary() | integer().
+%%%
+%% Exceptions
+%% error:badarg
+%% error:notsup
+-type run_time_error() :: no_return().
+
+%% Exceptions
+%% error:{badarg,Reason::term()}
+%% error:{notsup,Reason::term()}
+%% error:{error,Reason::term()}
+-type descriptive_error() :: no_return() .
+
+
+%%--------------------------------------------------------------------
-compile(no_native).
-on_load(on_load/0).
-define(CRYPTO_NIF_VSN,302).
@@ -368,10 +388,7 @@ stop() ->
| {curves, Curves}
| {rsa_opts, RSAopts},
Hashs :: [sha1() | sha2() | sha3() | blake2() | ripemd160 | compatibility_only_hash()],
- Ciphers :: [stream_cipher()
- | block_cipher_with_iv() | block_cipher_without_iv()
- | aead_cipher()
- ],
+ Ciphers :: [cipher()],
PKs :: [rsa | dss | ecdsa | dh | ecdh | ec_gf2m],
Macs :: [hmac | cmac | poly1305],
Curves :: [ec_named_curve() | edwards_curve_dh() | edwards_curve_ed()],
@@ -405,14 +422,18 @@ enable_fips_mode(_) -> ?nif_stub.
%%%
%%%================================================================
--define(HASH_HASH_ALGORITHM, sha1() | sha2() | sha3() | blake2() | ripemd160 | compatibility_only_hash() ).
-
--spec hash_info(Type) -> map() when Type :: ?HASH_HASH_ALGORITHM.
+-type hash_algorithm() :: sha1() | sha2() | sha3() | blake2() | ripemd160 | compatibility_only_hash() .
+-spec hash_info(Type) -> Result | run_time_error()
+ when Type :: hash_algorithm(),
+ Result :: #{size := integer(),
+ block_size := integer(),
+ type := integer()
+ } .
hash_info(Type) ->
notsup_to_error(hash_info_nif(Type)).
--spec hash(Type, Data) -> Digest when Type :: ?HASH_HASH_ALGORITHM,
+-spec hash(Type, Data) -> Digest when Type :: hash_algorithm(),
Data :: iodata(),
Digest :: binary().
hash(Type, Data) ->
@@ -422,7 +443,7 @@ hash(Type, Data) ->
-opaque hash_state() :: reference().
--spec hash_init(Type) -> State when Type :: ?HASH_HASH_ALGORITHM,
+-spec hash_init(Type) -> State when Type :: hash_algorithm(),
State :: hash_state().
hash_init(Type) ->
notsup_to_error(hash_init_nif(Type)).
@@ -448,12 +469,12 @@ hash_final(Context) ->
%%%---- HMAC
--define(HMAC_HASH_ALGORITHM, sha1() | sha2() | sha3() | compatibility_only_hash()).
+-type hmac_hash_algorithm() :: sha1() | sha2() | sha3() | compatibility_only_hash().
%%%---- hmac/3,4
-spec hmac(Type, Key, Data) ->
- Mac when Type :: ?HMAC_HASH_ALGORITHM,
+ Mac when Type :: hmac_hash_algorithm(),
Key :: iodata(),
Data :: iodata(),
Mac :: binary() .
@@ -462,7 +483,7 @@ hmac(Type, Key, Data) ->
hmac(Type, Key, Data1, undefined, erlang:byte_size(Data1), max_bytes()).
-spec hmac(Type, Key, Data, MacLength) ->
- Mac when Type :: ?HMAC_HASH_ALGORITHM,
+ Mac when Type :: hmac_hash_algorithm(),
Key :: iodata(),
Data :: iodata(),
MacLength :: integer(),
@@ -477,7 +498,7 @@ hmac(Type, Key, Data, MacLength) ->
-opaque hmac_state() :: binary().
-spec hmac_init(Type, Key) ->
- State when Type :: ?HMAC_HASH_ALGORITHM,
+ State when Type :: hmac_hash_algorithm(),
Key :: iodata(),
State :: hmac_state() .
hmac_init(Type, Key) ->
@@ -541,79 +562,124 @@ poly1305(Key, Data) ->
%%%================================================================
-define(COMPAT(CALL),
- try CALL
+ try begin CALL end
catch
+ error:{error,_} ->
+ error(badarg);
error:{E,_Reason} when E==notsup ; E==badarg ->
error(E)
end).
--spec cipher_info(Type) -> map() when Type :: block_cipher_with_iv()
- | aead_cipher()
- | block_cipher_without_iv().
+%%%---- Cipher info
+%%%----------------------------------------------------------------
+-spec cipher_info(Type) -> Result | run_time_error()
+ when Type :: cipher(),
+ Result :: #{key_length := integer(),
+ iv_length := integer(),
+ block_size := integer(),
+ mode := CipherModes,
+ type := undefined | integer()
+ },
+ CipherModes :: undefined
+ | cbc_mode
+ | ccm_mode
+ | cfb_mode
+ | ctr_mode
+ | ecb_mode
+ | gcm_mode
+ | ige_mode
+ | ocb_mode
+ | ofb_mode
+ | wrap_mode
+ | xts_mode
+ .
+
+%% These ciphers are not available via the EVP interface on older cryptolibs.
+cipher_info(aes_ctr) ->
+ #{block_size => 1,iv_length => 16,key_length => 32,mode => ctr_mode,type => undefined};
+cipher_info(aes_128_ctr) ->
+ #{block_size => 1,iv_length => 16,key_length => 16,mode => ctr_mode,type => undefined};
+cipher_info(aes_192_ctr) ->
+ #{block_size => 1,iv_length => 16,key_length => 24,mode => ctr_mode,type => undefined};
+cipher_info(aes_256_ctr) ->
+ #{block_size => 1,iv_length => 16,key_length => 32,mode => ctr_mode,type => undefined};
+%% This cipher is handled specialy.
+cipher_info(aes_ige256) ->
+ #{block_size => 16,iv_length => 32,key_length => 16,mode => ige_mode,type => undefined};
cipher_info(Type) ->
- cipher_info_nif(Type).
+ cipher_info_nif(alias(Type)).
%%%---- Block ciphers
%%%----------------------------------------------------------------
--spec block_encrypt(Type::block_cipher_with_iv(), Key::key()|des3_key(), Ivec::binary(), PlainText::iodata()) -> binary();
+-spec block_encrypt(Type::block_cipher_iv(), Key::key()|des3_key(), Ivec::binary(), PlainText::iodata()) ->
+ binary() | run_time_error();
(Type::aead_cipher(), Key::iodata(), Ivec::binary(), {AAD::binary(), PlainText::iodata()}) ->
- {binary(), binary()};
+ {binary(), binary()} | run_time_error();
(aes_gcm | aes_ccm, Key::iodata(), Ivec::binary(), {AAD::binary(), PlainText::iodata(), TagLength::1..16}) ->
- {binary(), binary()}.
+ {binary(), binary()} | run_time_error().
-block_encrypt(Type, Key, Ivec, Data) ->
- do_block_encrypt(alias(Type), Key, Ivec, Data).
-
-do_block_encrypt(Type, Key, Ivec, PlainText) when Type =:= aes_ige256 ->
+block_encrypt(aes_ige256, Key, Ivec, PlainText) ->
notsup_to_error(aes_ige_crypt_nif(Key, Ivec, PlainText, true));
-do_block_encrypt(Type, Key, Ivec, {AAD, PlainText}) when Type =:= chacha20_poly1305 ->
- aead_encrypt(Type, Key, Ivec, AAD, PlainText, 16);
-
-do_block_encrypt(Type, Key, Ivec, Data) when Type =:= aes_gcm;
- Type =:= aes_ccm ->
- case Data of
- {AAD, PlainText} ->
- aead_encrypt(Type, Key, Ivec, AAD, PlainText);
- {AAD, PlainText, TagLength} ->
- aead_encrypt(Type, Key, Ivec, AAD, PlainText, TagLength)
- end;
-
-do_block_encrypt(Type, Key, Ivec, PlainText) ->
- ?COMPAT(crypto_one_shot(Type, Key, Ivec, PlainText, true)).
-
-
--spec block_encrypt(Type::block_cipher_without_iv(), Key::key(), PlainText::iodata()) -> binary().
-
-block_encrypt(Type, Key, PlainText) ->
- ?COMPAT(crypto_one_shot(Type, Key, <<>>, PlainText, true)).
+block_encrypt(Type, Key0, Ivec, Data) ->
+ Key = iolist_to_binary(Key0),
+ ?COMPAT(
+ case Data of
+ {AAD, PlainText} ->
+ aead_encrypt(alias(Type,Key), Key, Ivec, AAD, PlainText, aead_tag_len(Type));
+ {AAD, PlainText, TagLength} ->
+ aead_encrypt(alias(Type,Key), Key, Ivec, AAD, PlainText, TagLength);
+ PlainText ->
+ crypto_one_shot(alias(Type,Key), Key, Ivec, PlainText, true)
+ end).
+
+-spec block_encrypt(Type::block_cipher_no_iv(), Key::key(), PlainText::iodata()) ->
+ binary() | run_time_error().
+
+block_encrypt(Type, Key0, PlainText) ->
+ Key = iolist_to_binary(Key0),
+ ?COMPAT(crypto_one_shot(alias(Type,Key), Key, <<>>, PlainText, true)).
+
+
+aead_tag_len(chacha20_poly1305) -> 16;
+aead_tag_len(aes_ccm) -> 12;
+aead_tag_len(aes_128_ccm) -> 12;
+aead_tag_len(aes_192_ccm) -> 12;
+aead_tag_len(aes_256_ccm) -> 12;
+aead_tag_len(aes_gcm) -> 16;
+aead_tag_len(aes_128_gcm) -> 16;
+aead_tag_len(aes_192_gcm) -> 16;
+aead_tag_len(aes_256_gcm) -> 16.
%%%----------------------------------------------------------------
%%%----------------------------------------------------------------
--spec block_decrypt(Type::block_cipher_with_iv(), Key::key()|des3_key(), Ivec::binary(), Data::iodata()) -> binary();
+-spec block_decrypt(Type::block_cipher_iv(), Key::key()|des3_key(), Ivec::binary(), Data::iodata()) ->
+ binary() | run_time_error();
(Type::aead_cipher(), Key::iodata(), Ivec::binary(),
- {AAD::binary(), Data::iodata(), Tag::binary()}) -> binary() | error.
-
-block_decrypt(Type, Key, Ivec, Data) ->
- do_block_decrypt(alias(Type), Key, Ivec, Data).
+ {AAD::binary(), Data::iodata(), Tag::binary()}) ->
+ binary() | error | run_time_error() .
-do_block_decrypt(aes_ige256, Key, Ivec, Data) ->
+block_decrypt(aes_ige256, Key, Ivec, Data) ->
notsup_to_error(aes_ige_crypt_nif(Key, Ivec, Data, false));
-do_block_decrypt(Type, Key, Ivec, {AAD, Data, Tag}) when Type =:= aes_gcm;
- Type =:= aes_ccm;
- Type =:= chacha20_poly1305 ->
- aead_decrypt(Type, Key, Ivec, AAD, Data, Tag);
+block_decrypt(Type, Key0, Ivec, Data) ->
+ Key = iolist_to_binary(Key0),
+ ?COMPAT(
+ case Data of
+ {AAD, CryptoText, Tag} ->
+ aead_decrypt(alias(Type,Key), Key, Ivec, AAD, CryptoText, Tag);
+ CryptoText ->
+ crypto_one_shot(alias(Type,Key), Key, Ivec, CryptoText, false)
+ end).
-do_block_decrypt(Type, Key, Ivec, Data) ->
- ?COMPAT(crypto_one_shot(Type, Key, Ivec, Data, false)).
+-spec block_decrypt(Type::block_cipher_no_iv(), Key::key(), Data::iodata()) ->
+ binary() | run_time_error().
--spec block_decrypt(Type::block_cipher_without_iv(), Key::key(), Data::iodata()) -> binary().
-
-block_decrypt(Type, Key, Data) ->
- ?COMPAT(crypto_one_shot(Type, Key, <<>>, Data, false)).
+block_decrypt(Type, Key0, CryptoText) ->
+ Key = iolist_to_binary(Key0),
+ ?COMPAT(crypto_one_shot(alias(Type,Key), Key, <<>>, CryptoText, false)).
%%%-------- Stream ciphers API
@@ -630,32 +696,34 @@ block_decrypt(Type, Key, Data) ->
| chacha20 .
%%%---- stream_init
--spec stream_init(Type, Key, IVec) -> State | no_return()
+-spec stream_init(Type, Key, IVec) -> State | run_time_error()
when Type :: stream_cipher_iv(),
Key :: iodata(),
IVec ::binary(),
State :: stream_state() .
-stream_init(Type, Key, IVec) when is_binary(IVec) ->
- Ref = ?COMPAT(ng_crypto_init_nif(alias(Type),
- iolist_to_binary(Key), iolist_to_binary(IVec),
+stream_init(Type, Key0, IVec) when is_binary(IVec) ->
+ Key = iolist_to_binary(Key0),
+ Ref = ?COMPAT(ng_crypto_init_nif(alias(Type,Key),
+ Key, iolist_to_binary(IVec),
undefined)
),
{Type, {Ref,flg_undefined}}.
--spec stream_init(Type, Key) -> State | no_return()
+-spec stream_init(Type, Key) -> State | run_time_error()
when Type :: stream_cipher_no_iv(),
Key :: iodata(),
State :: stream_state() .
-stream_init(rc4 = Type, Key) ->
- Ref = ?COMPAT(ng_crypto_init_nif(alias(Type),
- iolist_to_binary(Key), <<>>,
+stream_init(rc4 = Type, Key0) ->
+ Key = iolist_to_binary(Key0),
+ Ref = ?COMPAT(ng_crypto_init_nif(alias(Type,Key),
+ Key, <<>>,
undefined)
),
{Type, {Ref,flg_undefined}}.
%%%---- stream_encrypt
--spec stream_encrypt(State, PlainText) -> {NewState, CipherText} | no_return()
+-spec stream_encrypt(State, PlainText) -> {NewState, CipherText} | run_time_error()
when State :: stream_state(),
PlainText :: iodata(),
NewState :: stream_state(),
@@ -664,7 +732,7 @@ stream_encrypt(State, Data) ->
crypto_stream_emulate(State, Data, true).
%%%---- stream_decrypt
--spec stream_decrypt(State, CipherText) -> {NewState, PlainText} | no_return()
+-spec stream_decrypt(State, CipherText) -> {NewState, PlainText} | run_time_error()
when State :: stream_state(),
CipherText :: iodata(),
NewState :: stream_state(),
@@ -723,8 +791,8 @@ next_iv(Type, Data, _Ivec) ->
%%% Create and initialize a new state for encryption or decryption
%%%
--spec crypto_init(Cipher, Key, EncryptFlag) -> State | ng_crypto_error()
- when Cipher :: block_cipher_without_iv()
+-spec crypto_init(Cipher, Key, EncryptFlag) -> State | descriptive_error()
+ when Cipher :: block_cipher_no_iv()
| stream_cipher_no_iv(),
Key :: iodata(),
EncryptFlag :: boolean(),
@@ -734,9 +802,9 @@ crypto_init(Cipher, Key, EncryptFlag) ->
ng_crypto_init_nif(alias(Cipher), iolist_to_binary(Key), <<>>, EncryptFlag).
--spec crypto_init(Cipher, Key, IV, EncryptFlag) -> State | ng_crypto_error()
+-spec crypto_init(Cipher, Key, IV, EncryptFlag) -> State | descriptive_error()
when Cipher :: stream_cipher_iv()
- | block_cipher_with_iv(),
+ | block_cipher_iv(),
Key :: iodata(),
IV :: iodata(),
EncryptFlag :: boolean(),
@@ -747,9 +815,9 @@ crypto_init(Cipher, Key, IV, EncryptFlag) ->
%%%----------------------------------------------------------------
--spec crypto_init_dyn_iv(Cipher, Key, EncryptFlag) -> State | ng_crypto_error()
+-spec crypto_init_dyn_iv(Cipher, Key, EncryptFlag) -> State | descriptive_error()
when Cipher :: stream_cipher_iv()
- | block_cipher_with_iv(),
+ | block_cipher_iv(),
Key :: iodata(),
EncryptFlag :: boolean(),
State :: crypto_state() .
@@ -764,7 +832,7 @@ crypto_init_dyn_iv(Cipher, Key, EncryptFlag) ->
%%% blocksize.
%%%
--spec crypto_update(State, Data) -> Result | ng_crypto_error()
+-spec crypto_update(State, Data) -> Result | descriptive_error()
when State :: crypto_state(),
Data :: iodata(),
Result :: binary() .
@@ -778,7 +846,7 @@ crypto_update(State, Data0) ->
%%%----------------------------------------------------------------
--spec crypto_update_dyn_iv(State, Data, IV) -> Result | ng_crypto_error()
+-spec crypto_update_dyn_iv(State, Data, IV) -> Result | descriptive_error()
when State :: crypto_state(),
Data :: iodata(),
IV :: iodata(),
@@ -798,15 +866,16 @@ crypto_update_dyn_iv(State, Data0, IV) ->
%%% The size must be an integer multiple of the crypto's blocksize.
%%%
--spec crypto_one_shot(Cipher, Key, IV, Data, EncryptFlag) -> Result | ng_crypto_error()
- when Cipher :: stream_cipher()
- | block_cipher_with_iv()
- | block_cipher_without_iv(),
- Key :: iodata(),
- IV :: iodata() | undefined,
- Data :: iodata(),
- EncryptFlag :: boolean(),
- Result :: binary() .
+-spec crypto_one_shot(Cipher, Key, IV, Data, EncryptFlag) ->
+ Result | descriptive_error()
+ when Cipher :: stream_cipher()
+ | block_cipher(),
+ Key :: iodata(),
+ IV :: iodata() | undefined,
+ Data :: iodata(),
+ EncryptFlag :: boolean(),
+ Result :: binary() .
+
crypto_one_shot(Cipher, Key, undefined, Data, EncryptFlag) ->
crypto_one_shot(Cipher, Key, <<>>, Data, EncryptFlag);
@@ -823,21 +892,25 @@ crypto_one_shot(Cipher, Key, IV, Data0, EncryptFlag) ->
%%%----------------------------------------------------------------
%%% NIFs
--type ng_crypto_error() :: no_return() .
+-spec ng_crypto_init_nif(atom(), binary(), binary()|undefined, boolean()|undefined ) ->
+ crypto_state() | descriptive_error()
+ ; (crypto_state(), <<>>, <<>>, boolean())
+ -> crypto_state() | descriptive_error().
--spec ng_crypto_init_nif(atom(), binary(), binary()|undefined, boolean()|undefined ) -> crypto_state() | ng_crypto_error()
- ; (crypto_state(), <<>>, <<>>, boolean()) -> crypto_state() | ng_crypto_error().
ng_crypto_init_nif(_Cipher, _Key, _IVec, _EncryptFlg) -> ?nif_stub.
--spec ng_crypto_update_nif(crypto_state(), binary()) -> binary() | ng_crypto_error() .
+-spec ng_crypto_update_nif(crypto_state(), binary()) ->
+ binary() | descriptive_error() .
ng_crypto_update_nif(_State, _Data) -> ?nif_stub.
--spec ng_crypto_update_nif(crypto_state(), binary(), binary()) -> binary() | ng_crypto_error() .
+-spec ng_crypto_update_nif(crypto_state(), binary(), binary()) ->
+ binary() | descriptive_error() .
ng_crypto_update_nif(_State, _Data, _IV) -> ?nif_stub.
--spec ng_crypto_one_shot_nif(atom(), binary(), binary(), binary(), boolean() ) -> binary() | ng_crypto_error().
+-spec ng_crypto_one_shot_nif(atom(), binary(), binary(), binary(), boolean() ) ->
+ binary() | descriptive_error().
ng_crypto_one_shot_nif(_Cipher, _Key, _IVec, _Data, _EncryptFlg) -> ?nif_stub.
%%%----------------------------------------------------------------
@@ -859,6 +932,44 @@ alias(aes_cbc256) -> aes_256_cbc;
alias(Alg) -> Alg.
+
+%%%---- des_ede3_cbc
+alias(des3_cbc, _) -> des_ede3_cbc;
+alias(des_ede3, _) -> des_ede3_cbc;
+%%%---- des_ede3_cfb
+alias(des_ede3_cbf,_ ) -> des_ede3_cfb;
+alias(des3_cbf, _) -> des_ede3_cfb;
+alias(des3_cfb, _) -> des_ede3_cfb;
+%%%---- aes_*_cbc
+alias(aes_cbc128, _) -> aes_128_cbc;
+alias(aes_cbc256, _) -> aes_256_cbc;
+
+alias(aes_cbc, Key) when size(Key)==128 -> aes_128_cbc;
+alias(aes_cbc, Key) when size(Key)==192 -> aes_192_cbc;
+alias(aes_cbc, Key) when size(Key)==256 -> aes_256_cbc;
+
+alias(aes_cfb8, Key) when size(Key)==128 -> aes_128_cfb8;
+alias(aes_cfb8, Key) when size(Key)==192 -> aes_192_cfb8;
+alias(aes_cfb8, Key) when size(Key)==256 -> aes_256_cfb8;
+
+alias(aes_cfb128, Key) when size(Key)==128 -> aes_128_cfb128;
+alias(aes_cfb128, Key) when size(Key)==192 -> aes_192_cfb128;
+alias(aes_cfb128, Key) when size(Key)==256 -> aes_256_cfb128;
+
+alias(aes_ctr, Key) when size(Key)==128 -> aes_128_ctr;
+alias(aes_ctr, Key) when size(Key)==192 -> aes_192_ctr;
+alias(aes_ctr, Key) when size(Key)==256 -> aes_256_ctr;
+
+alias(aes_gcm, Key) when size(Key)==128 -> aes_128_gcm;
+alias(aes_gcm, Key) when size(Key)==192 -> aes_192_gcm;
+alias(aes_gcm, Key) when size(Key)==256 -> aes_256_gcm;
+
+alias(aes_ccm, Key) when size(Key)==128 -> aes_128_ccm;
+alias(aes_ccm, Key) when size(Key)==192 -> aes_192_ccm;
+alias(aes_ccm, Key) when size(Key)==256 -> aes_256_ccm;
+
+alias(Alg, _) -> Alg.
+
%%%================================================================
%%%
%%% RAND - pseudo random numbers using RN_ and BN_ functions in crypto lib
@@ -1949,9 +2060,6 @@ cipher_info_nif(_Type) -> ?nif_stub.
%% AES - in Galois/Counter Mode (GCM)
%%
%% The default tag length is EVP_GCM_TLS_TAG_LEN(16),
-aead_encrypt(Type=aes_ccm, Key, Ivec, AAD, In) -> aead_encrypt(Type, Key, Ivec, AAD, In, 12);
-aead_encrypt(Type=aes_gcm, Key, Ivec, AAD, In) -> aead_encrypt(Type, Key, Ivec, AAD, In, 16).
-
aead_encrypt(_Type, _Key, _Ivec, _AAD, _In, _TagLength) -> ?nif_stub.
aead_decrypt(_Type, _Key, _Ivec, _AAD, _In, _Tag) -> ?nif_stub.
diff --git a/lib/crypto/test/crypto_SUITE.erl b/lib/crypto/test/crypto_SUITE.erl
index 5aa19a6ae0..ce5097de47 100644
--- a/lib/crypto/test/crypto_SUITE.erl
+++ b/lib/crypto/test/crypto_SUITE.erl
@@ -847,7 +847,8 @@ cipher_info(Config) when is_list(Config) ->
#{type := _,key_length := _,iv_length := _,
block_size := _,mode := _} = crypto:cipher_info(aes_128_cbc),
{'EXIT',_} = (catch crypto:cipher_info(not_a_cipher)),
- ok.
+ lists:foreach(fun(C) -> crypto:cipher_info(C) end,
+ proplists:get_value(ciphers, crypto:supports())).
%%--------------------------------------------------------------------
hash_info() ->
@@ -855,7 +856,8 @@ hash_info() ->
hash_info(Config) when is_list(Config) ->
#{type := _,size := _,block_size := _} = crypto:hash_info(sha256),
{'EXIT',_} = (catch crypto:hash_info(not_a_hash)),
- ok.
+ lists:foreach(fun(H) -> crypto:hash_info(H) end,
+ proplists:get_value(hashs, crypto:supports())).
%%--------------------------------------------------------------------
%% Internal functions ------------------------------------------------
diff --git a/lib/erl_interface/src/encode/encode_pid.c b/lib/erl_interface/src/encode/encode_pid.c
index d14746b40f..0dfdb16372 100644
--- a/lib/erl_interface/src/encode/encode_pid.c
+++ b/lib/erl_interface/src/encode/encode_pid.c
@@ -25,7 +25,6 @@
int ei_encode_pid(char *buf, int *index, const erlang_pid *p)
{
char* s = buf + *index;
- const char tag = (p->creation > 3) ? ERL_NEW_PID_EXT : ERL_PID_EXT;
++(*index); /* skip ERL_PID_EXT */
if (ei_encode_atom_len_as(buf, index, p->node, strlen(p->node),
@@ -33,21 +32,17 @@ int ei_encode_pid(char *buf, int *index, const erlang_pid *p)
return -1;
if (buf) {
- put8(s, tag);
+ put8(s, ERL_NEW_PID_EXT);
s = buf + *index;
/* now the integers */
put32be(s,p->num & 0x7fff); /* 15 bits */
put32be(s,p->serial & 0x1fff); /* 13 bits */
- if (tag == ERL_PID_EXT) {
- put8(s,(p->creation & 0x03)); /* 2 bits */
- } else {
- put32be(s, p->creation); /* 32 bits */
- }
+ put32be(s, p->creation); /* 32 bits */
}
- *index += 4 + 4 + (tag == ERL_PID_EXT ? 1 : 4);
+ *index += 4 + 4 + 4;
return 0;
}
diff --git a/lib/erl_interface/src/encode/encode_port.c b/lib/erl_interface/src/encode/encode_port.c
index eb464380c0..0fb4018db1 100644
--- a/lib/erl_interface/src/encode/encode_port.c
+++ b/lib/erl_interface/src/encode/encode_port.c
@@ -25,7 +25,6 @@
int ei_encode_port(char *buf, int *index, const erlang_port *p)
{
char *s = buf + *index;
- const char tag = p->creation > 3 ? ERL_NEW_PORT_EXT : ERL_PORT_EXT;
++(*index); /* skip ERL_PORT_EXT */
if (ei_encode_atom_len_as(buf, index, p->node, strlen(p->node), ERLANG_UTF8,
@@ -33,19 +32,15 @@ int ei_encode_port(char *buf, int *index, const erlang_port *p)
return -1;
}
if (buf) {
- put8(s, tag);
+ put8(s, ERL_NEW_PORT_EXT);
s = buf + *index;
/* now the integers */
put32be(s,p->id & 0x0fffffff /* 28 bits */);
- if (tag == ERL_PORT_EXT) {
- put8(s,(p->creation & 0x03));
- } else {
- put32be(s, p->creation);
- }
+ put32be(s, p->creation);
}
- *index += 4 + (tag == ERL_PORT_EXT ? 1 : 4);
+ *index += 4 + 4;
return 0;
}
diff --git a/lib/erl_interface/src/encode/encode_ref.c b/lib/erl_interface/src/encode/encode_ref.c
index 5ccfc32c6d..8c2e0a25f7 100644
--- a/lib/erl_interface/src/encode/encode_ref.c
+++ b/lib/erl_interface/src/encode/encode_ref.c
@@ -24,7 +24,6 @@
int ei_encode_ref(char *buf, int *index, const erlang_ref *p)
{
- const char tag = (p->creation > 3) ? ERL_NEWER_REFERENCE_EXT : ERL_NEW_REFERENCE_EXT;
char *s = buf + *index;
int i;
@@ -37,7 +36,7 @@ int ei_encode_ref(char *buf, int *index, const erlang_ref *p)
/* Always encode as an extended reference; all participating parties
are now expected to be able to decode extended references. */
if (buf) {
- put8(s, tag);
+ put8(s, ERL_NEWER_REFERENCE_EXT);
/* first, number of integers */
put16be(s, p->len);
@@ -46,15 +45,12 @@ int ei_encode_ref(char *buf, int *index, const erlang_ref *p)
s = buf + *index;
/* now the integers */
- if (tag == ERL_NEW_REFERENCE_EXT)
- put8(s,(p->creation & 0x03));
- else
- put32be(s, p->creation);
+ put32be(s, p->creation);
for (i = 0; i < p->len; i++)
put32be(s,p->n[i]);
}
- *index += p->len*4 + (tag == ERL_NEW_REFERENCE_EXT ? 1 : 4);
+ *index += p->len*4 + 4;
return 0;
}
diff --git a/lib/erl_interface/test/erl_eterm_SUITE.erl b/lib/erl_interface/test/erl_eterm_SUITE.erl
index 77910a9fc7..4605293c74 100644
--- a/lib/erl_interface/test/erl_eterm_SUITE.erl
+++ b/lib/erl_interface/test/erl_eterm_SUITE.erl
@@ -73,6 +73,10 @@
-import(runner, [get_term/1]).
+-define(REFERENCE_EXT, $e).
+-define(NEW_REFERENCE_EXT, $r).
+-define(NEWER_REFERENCE_EXT, $Z).
+
%% This test suite controls the running of the C language functions
%% in eterm_test.c and print_term.c.
@@ -1026,9 +1030,11 @@ cnode_1(Config) when is_list(Config) ->
check_ref(Ref) ->
case bin_ext_type(Ref) of
- 101 ->
+ ?REFERENCE_EXT ->
ct:fail(oldref);
- 114 ->
+ ?NEW_REFERENCE_EXT ->
+ ok;
+ ?NEWER_REFERENCE_EXT ->
ok;
Type ->
ct:fail({type, Type})
diff --git a/lib/inets/test/httpc_SUITE.erl b/lib/inets/test/httpc_SUITE.erl
index 8357e02014..d4b33ae2c6 100644
--- a/lib/inets/test/httpc_SUITE.erl
+++ b/lib/inets/test/httpc_SUITE.erl
@@ -339,14 +339,6 @@ end_per_testcase(Case, Config)
end_per_testcase(_Case, _Config) ->
ok.
-is_ipv6_supported() ->
- case gen_udp:open(0, [inet6]) of
- {ok, Socket} ->
- gen_udp:close(Socket),
- true;
- _ ->
- false
- end.
%%--------------------------------------------------------------------
@@ -1612,7 +1604,8 @@ post_with_content_type(Config) when is_list(Config) ->
%%--------------------------------------------------------------------
request_options() ->
- [{doc, "Test http get request with socket options against local server (IPv6)"}].
+ [{require, ipv6_hosts},
+ {doc, "Test http get request with socket options against local server (IPv6)"}].
request_options(Config) when is_list(Config) ->
Request = {url(group_name(Config), "/dummy.html", Config), []},
{ok, {{_,200,_}, [_ | _], _ = [_ | _]}} = httpc:request(get, Request, [],
@@ -2945,3 +2938,12 @@ receive_stream_n(Ref, N) ->
ct:pal("Data: ~p", [Data]),
receive_stream_n(Ref, N-1)
end.
+
+is_ipv6_supported() ->
+ {ok, Hostname0} = inet:gethostname(),
+ try
+ lists:member(list_to_atom(Hostname0), ct:get_config(ipv6_hosts))
+ catch
+ _: _ ->
+ false
+ end.
diff --git a/lib/kernel/doc/src/logger_disk_log_h.xml b/lib/kernel/doc/src/logger_disk_log_h.xml
index 5b2374690e..aa577f3c62 100644
--- a/lib/kernel/doc/src/logger_disk_log_h.xml
+++ b/lib/kernel/doc/src/logger_disk_log_h.xml
@@ -66,7 +66,7 @@
corresponds to the <c>name</c> property in the
<seealso marker="disk_log#open-1"><c>dlog_option()</c></seealso>
datatype.</p>
- <p>The value is set when the handler is added, and it can not
+ <p>The value is set when the handler is added, and it cannot
be changed in runtime.</p>
<p>Defaults to the same name as the handler identity, in the
current directory.</p>
@@ -77,7 +77,7 @@
corresponds to the <c>type</c> property in the
<seealso marker="disk_log#open-1"><c>dlog_option()</c></seealso>
datatype.</p>
- <p>The value is set when the handler is added, and it can not
+ <p>The value is set when the handler is added, and it cannot
be changed in runtime.</p>
<p>Defaults to <c>wrap</c>.</p>
</item>
@@ -88,7 +88,7 @@
corresponds to the <c>MaxNoFiles</c> element in the <c>size</c> property in the
<seealso marker="disk_log#open-1"><c>dlog_option()</c></seealso>
datatype.</p>
- <p>The value is set when the handler is added, and it can not
+ <p>The value is set when the handler is added, and it cannot
be changed in runtime.</p>
<p>Defaults to <c>10</c>.</p>
<p>The setting has no effect on a halt log.</p>
@@ -101,7 +101,7 @@
corresponds to the <c>MaxNoBytes</c> element in the <c>size</c> property in the
<seealso marker="disk_log#open-1"><c>dlog_option()</c></seealso>
datatype.</p>
- <p>The value is set when the handler is added, and it can not
+ <p>The value is set when the handler is added, and it cannot
be changed in runtime.</p>
<p>Defaults to <c>1048576</c> bytes for a wrap log, and
<c>infinity</c> for a halt log.</p>
diff --git a/lib/kernel/doc/src/logger_std_h.xml b/lib/kernel/doc/src/logger_std_h.xml
index 5ed1a2f210..5ac4f58d12 100644
--- a/lib/kernel/doc/src/logger_std_h.xml
+++ b/lib/kernel/doc/src/logger_std_h.xml
@@ -58,7 +58,7 @@
<tag><marker id="type"/><c>type = standard_io | standard_error | file</c></tag>
<item>
<p>Specifies the log destination.</p>
- <p>The value is set when the handler is added, and it can not
+ <p>The value is set when the handler is added, and it cannot
be changed in runtime.</p>
<p>Defaults to <c>standard_io</c>, unless
parameter <seealso marker="#file"><c>file</c></seealso> is
@@ -68,7 +68,7 @@
<item>
<p>This specifies the name of the log file when the handler is
of type <c>file</c>.</p>
- <p>The value is set when the handler is added, and it can not
+ <p>The value is set when the handler is added, and it cannot
be changed in runtime.</p>
<p>Defaults to the same name as the handler identity, in the
current directory.</p>
@@ -93,9 +93,9 @@
or <c>{delayed_write,Size,Delay}</c> is found in the
list, <c>delayed_write</c> is added.</item>
</list>
- <p>Log files are always UTF-8 encoded. The encoding can not be
+ <p>Log files are always UTF-8 encoded. The encoding cannot be
changed by setting the mode <c>{encoding,Encoding}</c>.</p>
- <p>The value is set when the handler is added, and it can not
+ <p>The value is set when the handler is added, and it cannot
be changed in runtime.</p>
<p>Defaults to <c>[raw,append,delayed_write]</c>.</p>
</item>
diff --git a/lib/kernel/src/erl_epmd.erl b/lib/kernel/src/erl_epmd.erl
index 7a14e2635c..f31a1722ce 100644
--- a/lib/kernel/src/erl_epmd.erl
+++ b/lib/kernel/src/erl_epmd.erl
@@ -33,10 +33,10 @@
-define(erlang_daemon_port, 4369).
-endif.
-ifndef(epmd_dist_high).
--define(epmd_dist_high, 4370).
+-define(epmd_dist_high, 6).
-endif.
-ifndef(epmd_dist_low).
--define(epmd_dist_low, 4370).
+-define(epmd_dist_low, 5).
-endif.
%% External exports
@@ -342,6 +342,13 @@ wait_for_reg_reply(Socket, SoFar) ->
receive
{tcp, Socket, Data0} ->
case SoFar ++ Data0 of
+ [$v, Result, A, B, C, D] ->
+ case Result of
+ 0 ->
+ {alive, Socket, ?u32(A, B, C, D)};
+ _ ->
+ {error, duplicate_name}
+ end;
[$y, Result, A, B] ->
case Result of
0 ->
diff --git a/lib/kernel/src/raw_file_io_inflate.erl b/lib/kernel/src/raw_file_io_inflate.erl
index 7e9780310c..d3ed02dd03 100644
--- a/lib/kernel/src/raw_file_io_inflate.erl
+++ b/lib/kernel/src/raw_file_io_inflate.erl
@@ -26,7 +26,7 @@
-include("file_int.hrl").
--define(INFLATE_CHUNK_SIZE, (1 bsl 10)).
+-define(INFLATE_CHUNK_SIZE, (8 bsl 10)).
-define(GZIP_WBITS, (16 + 15)).
callback_mode() -> state_functions.
diff --git a/lib/kernel/test/code_SUITE.erl b/lib/kernel/test/code_SUITE.erl
index 99fecbe970..4f0847084f 100644
--- a/lib/kernel/test/code_SUITE.erl
+++ b/lib/kernel/test/code_SUITE.erl
@@ -25,8 +25,8 @@
-export([all/0, suite/0,groups/0,init_per_group/2,end_per_group/2]).
-export([set_path/1, get_path/1, add_path/1, add_paths/1, del_path/1,
replace_path/1, load_file/1, load_abs/1, ensure_loaded/1,
- delete/1, purge/1, purge_many_exits/1, soft_purge/1, is_loaded/1,
- all_loaded/1,
+ delete/1, purge/1, purge_many_exits/0, purge_many_exits/1,
+ soft_purge/1, is_loaded/1, all_loaded/1,
load_binary/1, dir_req/1, object_code/1, set_path_file/1,
upgrade/1,
sticky_dir/1, pa_pz_option/1, add_del_path/1,
@@ -55,7 +55,7 @@
suite() ->
[{ct_hooks,[ts_install_cth]},
- {timetrap,{minutes,5}}].
+ {timetrap,{seconds,30}}].
all() ->
[set_path, get_path, add_path, add_paths, del_path,
@@ -396,6 +396,9 @@ purge(Config) when is_list(Config) ->
process_flag(trap_exit, OldFlag),
ok.
+purge_many_exits() ->
+ [{timetrap, {minutes, 2}}].
+
purge_many_exits(Config) when is_list(Config) ->
OldFlag = process_flag(trap_exit, true),
diff --git a/lib/kernel/test/erl_distribution_wb_SUITE.erl b/lib/kernel/test/erl_distribution_wb_SUITE.erl
index 8256444bdc..f3db6705a2 100644
--- a/lib/kernel/test/erl_distribution_wb_SUITE.erl
+++ b/lib/kernel/test/erl_distribution_wb_SUITE.erl
@@ -47,6 +47,9 @@
R
end).
+-define(EPMD_DIST_HIGH, 6).
+-define(EPMD_DIST_LOW, 5).
+
-define(DFLAG_PUBLISHED,1).
-define(DFLAG_ATOM_CACHE,2).
-define(DFLAG_EXTENDED_REFERENCES,4).
@@ -57,15 +60,18 @@
-define(DFLAG_NEW_FUN_TAGS,16#80).
-define(DFLAG_EXTENDED_PIDS_PORTS,16#100).
-define(DFLAG_UTF8_ATOMS, 16#10000).
+-define(DFLAG_BIG_CREATION, 16#40000).
%% From R9 and forward extended references is compulsory
%% From R10 and forward extended pids and ports are compulsory
%% From R20 and forward UTF8 atoms are compulsory
%% From R21 and forward NEW_FUN_TAGS is compulsory (no more tuple fallback {fun, ...})
+%% From R22 and forward BIG_CREATION is compulsory
-define(COMPULSORY_DFLAGS, (?DFLAG_EXTENDED_REFERENCES bor
?DFLAG_EXTENDED_PIDS_PORTS bor
?DFLAG_UTF8_ATOMS bor
- ?DFLAG_NEW_FUN_TAGS)).
+ ?DFLAG_NEW_FUN_TAGS bor
+ ?DFLAG_BIG_CREATION)).
-define(PASS_THROUGH, $p).
@@ -208,9 +214,9 @@ pending_up_md5(Node,OurName,Cookie) ->
{ok, SocketA} = gen_tcp:connect(atom_to_list(NB),PortNo,
[{active,false},
{packet,2}]),
- send_name(SocketA,OurName,5),
+ send_name(SocketA,OurName, ?EPMD_DIST_HIGH),
ok = recv_status(SocketA),
- {hidden,Node,5,HisChallengeA} = recv_challenge(SocketA), % See 1)
+ {hidden,Node,?EPMD_DIST_HIGH,HisChallengeA} = recv_challenge(SocketA), % See 1)
OurChallengeA = gen_challenge(),
OurDigestA = gen_digest(HisChallengeA, Cookie),
send_challenge_reply(SocketA, OurChallengeA, OurDigestA),
@@ -224,11 +230,11 @@ pending_up_md5(Node,OurName,Cookie) ->
{ok, SocketB} = gen_tcp:connect(atom_to_list(NB),PortNo,
[{active,false},
{packet,2}]),
- send_name(SocketB,OurName,5),
+ send_name(SocketB,OurName, ?EPMD_DIST_HIGH),
alive = recv_status(SocketB),
send_status(SocketB, true),
gen_tcp:close(SocketA),
- {hidden,Node,5,HisChallengeB} = recv_challenge(SocketB), % See 1)
+ {hidden,Node,?EPMD_DIST_HIGH,HisChallengeB} = recv_challenge(SocketB), % See 1)
OurChallengeB = gen_challenge(),
OurDigestB = gen_digest(HisChallengeB, Cookie),
send_challenge_reply(SocketB, OurChallengeB, OurDigestB),
@@ -254,7 +260,7 @@ simultaneous_md5(Node, OurName, Cookie) when OurName < Node ->
Else ->
exit(Else)
end,
- EpmdSocket = register(OurName, LSocket, 1, 5),
+ EpmdSocket = register_node(OurName, LSocket, ?EPMD_DIST_LOW, ?EPMD_DIST_HIGH),
{NA, NB} = split(Node),
rpc:cast(Node, net_adm, ping, [OurName]),
receive after 1000 -> ok end,
@@ -262,7 +268,7 @@ simultaneous_md5(Node, OurName, Cookie) when OurName < Node ->
{ok, SocketA} = gen_tcp:connect(atom_to_list(NB),PortNo,
[{active,false},
{packet,2}]),
- send_name(SocketA,OurName,5),
+ send_name(SocketA,OurName, ?EPMD_DIST_HIGH),
%% We are still not marked up on the other side, as our first message
%% is not sent.
SocketB = case gen_tcp:accept(LSocket) of
@@ -275,11 +281,11 @@ simultaneous_md5(Node, OurName, Cookie) when OurName < Node ->
%% Now we are expected to close A
gen_tcp:close(SocketA),
%% But still Socket B will continue
- {normal,Node,5} = recv_name(SocketB), % See 1)
+ {normal,Node,?EPMD_DIST_HIGH} = recv_name(SocketB), % See 1)
send_status(SocketB, ok_simultaneous),
MyChallengeB = gen_challenge(),
- send_challenge(SocketB, OurName, MyChallengeB,5),
- HisChallengeB = recv_challenge_reply(SocketB, MyChallengeB, Cookie),
+ send_challenge(SocketB, OurName, MyChallengeB, ?EPMD_DIST_HIGH),
+ {ok,HisChallengeB} = recv_challenge_reply(SocketB, MyChallengeB, Cookie),
DigestB = gen_digest(HisChallengeB,Cookie),
send_challenge_ack(SocketB, DigestB),
inet:setopts(SocketB, [{active, false},
@@ -301,7 +307,8 @@ simultaneous_md5(Node, OurName, Cookie) when OurName > Node ->
Else ->
exit(Else)
end,
- EpmdSocket = register(OurName, LSocket, 1, 5),
+ EpmdSocket = register_node(OurName, LSocket,
+ ?EPMD_DIST_LOW, ?EPMD_DIST_HIGH),
{NA, NB} = split(Node),
rpc:cast(Node, net_adm, ping, [OurName]),
receive after 1000 -> ok end,
@@ -315,16 +322,16 @@ simultaneous_md5(Node, OurName, Cookie) when OurName > Node ->
Else2 ->
exit(Else2)
end,
- send_name(SocketA,OurName,5),
+ send_name(SocketA,OurName, ?EPMD_DIST_HIGH),
ok_simultaneous = recv_status(SocketA),
%% Socket B should die during this
case catch begin
- {normal,Node,5} = recv_name(SocketB), % See 1)
+ {normal,Node,?EPMD_DIST_HIGH} = recv_name(SocketB), % See 1)
send_status(SocketB, ok_simultaneous),
MyChallengeB = gen_challenge(),
send_challenge(SocketB, OurName, MyChallengeB,
5),
- HisChallengeB = recv_challenge_reply(
+ {ok,HisChallengeB} = recv_challenge_reply(
SocketB,
MyChallengeB,
Cookie),
@@ -346,7 +353,7 @@ simultaneous_md5(Node, OurName, Cookie) when OurName > Node ->
end,
gen_tcp:close(SocketB),
%% But still Socket A will continue
- {hidden,Node,5,HisChallengeA} = recv_challenge(SocketA), % See 1)
+ {hidden,Node,?EPMD_DIST_HIGH,HisChallengeA} = recv_challenge(SocketA), % See 1)
OurChallengeA = gen_challenge(),
OurDigestA = gen_digest(HisChallengeA, Cookie),
send_challenge_reply(SocketA, OurChallengeA, OurDigestA),
@@ -372,7 +379,7 @@ missing_compulsory_dflags(Config) when is_list(Config) ->
[{active,false},
{packet,2}]),
BadNode = list_to_atom(atom_to_list(Name2)++"@"++atom_to_list(NB)),
- send_name(SocketA,BadNode,5,0),
+ send_name(SocketA,BadNode, ?EPMD_DIST_HIGH, 0),
not_allowed = recv_status(SocketA),
gen_tcp:close(SocketA),
stop_node(Node),
@@ -516,16 +523,16 @@ send_challenge_reply(Socket, Challenge, Digest) ->
recv_challenge_reply(Socket, ChallengeA, Cookie) ->
case gen_tcp:recv(Socket, 0) of
- {ok,[$r,CB3,CB2,CB1,CB0 | SumB]} when length(SumB) == 16 ->
+ {ok,[$r,CB3,CB2,CB1,CB0 | SumB]=Data} when length(SumB) == 16 ->
SumA = gen_digest(ChallengeA, Cookie),
ChallengeB = ?u32(CB3,CB2,CB1,CB0),
if SumB == SumA ->
- ChallengeB;
+ {ok,ChallengeB};
true ->
- ?shutdown(bad_challenge_reply)
+ {error,Data}
end;
- _ ->
- ?shutdown(no_node)
+ Err ->
+ {error,Err}
end.
send_challenge_ack(Socket, Digest) ->
@@ -620,6 +627,13 @@ wait_for_reg_reply(Socket, SoFar) ->
receive
{tcp, Socket, Data0} ->
case SoFar ++ Data0 of
+ [$v, Result, A, B, C, D] ->
+ case Result of
+ 0 ->
+ {alive, Socket, ?u32(A, B, C, D)};
+ _ ->
+ {error, duplicate_name}
+ end;
[$y, Result, A, B] ->
case Result of
0 ->
@@ -640,7 +654,7 @@ wait_for_reg_reply(Socket, SoFar) ->
end.
-register(NodeName, ListenSocket, VLow, VHigh) ->
+register_node(NodeName, ListenSocket, VLow, VHigh) ->
{ok,{_,TcpPort}} = inet:sockname(ListenSocket),
case do_register_node(NodeName, TcpPort, VLow, VHigh) of
{alive, Socket, _Creation} ->
diff --git a/lib/kernel/test/logger_disk_log_h_SUITE.erl b/lib/kernel/test/logger_disk_log_h_SUITE.erl
index 13b30835a1..36d98eaa25 100644
--- a/lib/kernel/test/logger_disk_log_h_SUITE.erl
+++ b/lib/kernel/test/logger_disk_log_h_SUITE.erl
@@ -1243,12 +1243,12 @@ restart_after(Config) ->
{Log,HConfig,DLHConfig} = start_handler(?MODULE, ?FUNCTION_NAME, Config),
NewHConfig1 =
HConfig#{config=>DLHConfig#{overload_kill_enable=>true,
- overload_kill_qlen=>10,
+ overload_kill_qlen=>4,
overload_kill_restart_after=>infinity}},
ok = logger:update_handler_config(?MODULE, NewHConfig1),
MRef1 = erlang:monitor(process, whereis(h_proc_name())),
%% kill handler
- send_burst({n,100}, {spawn,4,0}, {chars,79}, notice),
+ send_burst({n,100}, {spawn,5,0}, {chars,79}, notice),
receive
{'DOWN', MRef1, _, _, _Reason1} ->
file_delete(Log),
@@ -1265,13 +1265,13 @@ restart_after(Config) ->
RestartAfter = ?OVERLOAD_KILL_RESTART_AFTER,
NewHConfig2 =
HConfig#{config=>DLHConfig#{overload_kill_enable=>true,
- overload_kill_qlen=>10,
+ overload_kill_qlen=>4,
overload_kill_restart_after=>RestartAfter}},
ok = logger:update_handler_config(?MODULE, NewHConfig2),
Pid0 = whereis(h_proc_name()),
MRef2 = erlang:monitor(process, Pid0),
%% kill handler
- send_burst({n,100}, {spawn,4,0}, {chars,79}, notice),
+ send_burst({n,100}, {spawn,5,0}, {chars,79}, notice),
receive
{'DOWN', MRef2, _, _, _Reason2} ->
file_delete(Log),
diff --git a/lib/observer/test/observer_SUITE.erl b/lib/observer/test/observer_SUITE.erl
index 75336cedcc..7d54bb9b3b 100644
--- a/lib/observer/test/observer_SUITE.erl
+++ b/lib/observer/test/observer_SUITE.erl
@@ -41,7 +41,8 @@
%% Default timetrap timeout (set in init_per_testcase)
-define(default_timeout, ?t:minutes(2)).
-suite() -> [{ct_hooks,[ts_install_cth]}].
+suite() -> [{timetrap, {minutes, 5}},
+ {ct_hooks,[ts_install_cth]}].
all() ->
[app_file, appup_file, {group, gui}].
diff --git a/lib/ssl/doc/src/Makefile b/lib/ssl/doc/src/Makefile
index 7cf251d8f9..064131944c 100644
--- a/lib/ssl/doc/src/Makefile
+++ b/lib/ssl/doc/src/Makefile
@@ -47,6 +47,7 @@ XML_CHAPTER_FILES = \
ssl_protocol.xml \
using_ssl.xml \
ssl_distribution.xml \
+ standards_compliance.xml \
notes.xml
BOOK_FILES = book.xml
diff --git a/lib/ssl/doc/src/ssl_app.xml b/lib/ssl/doc/src/ssl_app.xml
index 893919aeb4..b05caf44ea 100644
--- a/lib/ssl/doc/src/ssl_app.xml
+++ b/lib/ssl/doc/src/ssl_app.xml
@@ -35,45 +35,10 @@
<description>
<p>
- The ssl application is an implementation of the SSL/TLS/DTLS protocol in Erlang.
+ The ssl application is an implementation of the SSL, TLS and DTLS protocols in Erlang.
</p>
- <list type="bulleted">
- <item>Supported SSL/TLS/DTLS-versions are SSL-3.0, TLS-1.0,
- TLS-1.1, TLS-1.2, DTLS-1.0 (based on TLS-1.1), DTLS-1.2 (based on TLS-1.2)</item>
- <item>For security reasons SSL-2.0 is not supported.
- Interoperability with SSL-2.0 enabled clients dropped. (OTP 21) </item>
- <item>For security reasons SSL-3.0 is no longer supported by default,
- but can be configured. (OTP 19) </item>
- <item>For security reasons RSA key exchange cipher suites are no longer supported by default,
- but can be configured. (OTP 21) </item>
- <item>For security reasons DES cipher suites are no longer supported by default,
- but can be configured. (OTP 20) </item>
- <item>For security reasons 3DES cipher suites are no longer supported by default,
- but can be configured. (OTP 21) </item>
- <item> Renegotiation Indication Extension <url href="http://www.ietf.org/rfc/rfc5746.txt">RFC 5746</url> is supported
- </item>
- <item>Ephemeral Diffie-Hellman cipher suites are supported,
- but not Diffie Hellman Certificates cipher suites.</item>
- <item>Elliptic Curve cipher suites are supported if the Crypto
- application supports it and named curves are used.
- </item>
- <item>Export cipher suites are not supported as the
- U.S. lifted its export restrictions in early 2000.</item>
- <item>IDEA cipher suites are not supported as they have
- become deprecated by the latest TLS specification so it is not
- motivated to implement them.</item>
- <item>Compression is not supported.</item>
- <item>CRL validation is supported.</item>
- <item>Policy certificate extensions are not supported.</item>
- <item>'Server Name Indication' extension
- (<url href="http://www.ietf.org/rfc/rfc6066.txt">RFC 6066</url>) is supported.</item>
- <item>Application Layer Protocol Negotiation (ALPN) and its successor Next Protocol Negotiation (NPN)
- are supported. </item>
- <item>It is possible to use Pre-Shared Key (PSK) and Secure Remote Password (SRP)
- cipher suites, but they are not enabled by default.
- </item>
- </list>
- </description>
+ <p>For current statement of standards compliance see the <seealso marker="standards_compliance">User's Guide</seealso>.</p>
+ </description>
<section>
<title>DEPENDENCIES</title>
diff --git a/lib/ssl/doc/src/standards_compliance.xml b/lib/ssl/doc/src/standards_compliance.xml
new file mode 100644
index 0000000000..c20bab4e50
--- /dev/null
+++ b/lib/ssl/doc/src/standards_compliance.xml
@@ -0,0 +1,2312 @@
+<?xml version="1.0" encoding="utf-8" ?>
+<!DOCTYPE chapter SYSTEM "chapter.dtd">
+
+<chapter>
+ <header>
+ <copyright>
+ <year>2015</year>
+ <year>2019</year>
+ <holder>Ericsson AB, All Rights Reserved</holder>
+ </copyright>
+ <legalnotice>
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+
+ The Initial Developer of the Original Code is Ericsson AB.
+ </legalnotice>
+
+ <title>Standards Compliance</title>
+ <prepared>OTP team</prepared>
+ <docno></docno>
+ <date>2019-03-20</date>
+ <rev>A</rev>
+ <file>standards_compliance.xml</file>
+ </header>
+
+ <section>
+ <title>Purpose</title>
+ <p>This section describes the current state of standards compliance of the ssl application.</p>
+ </section>
+
+ <section>
+ <title>Common (pre TLS 1.3)</title>
+ <list type="bulleted">
+ <item>For security reasons RSA key exchange cipher suites are no longer supported by default,
+ but can be configured. (OTP 21)
+ </item>
+ <item>For security reasons DES cipher suites are no longer supported by default,
+ but can be configured. (OTP 20)
+ </item>
+ <item>For security reasons 3DES cipher suites are no longer supported by default,
+ but can be configured. (OTP 21)
+ </item>
+ <item>Renegotiation Indication Extension <url href="http://www.ietf.org/rfc/rfc5746.txt">RFC 5746</url> is supported
+ </item>
+ <item>Ephemeral Diffie-Hellman cipher suites are supported,
+ but not Diffie Hellman Certificates cipher suites.
+ </item>
+ <item>Elliptic Curve cipher suites are supported if the Crypto
+ application supports it and named curves are used.
+ </item>
+ <item>Export cipher suites are not supported as the
+ U.S. lifted its export restrictions in early 2000.
+ </item>
+ <item>IDEA cipher suites are not supported as they have
+ become deprecated by the TLS 1.2 specification so it is not
+ motivated to implement them.
+ </item>
+ <item>Compression is not supported.
+ </item>
+ </list>
+ </section>
+
+ <section>
+ <title>Common</title>
+ <list type="bulleted">
+ <item>CRL validation is supported.</item>
+ <item>Policy certificate extensions are not supported.</item>
+ <item>'Server Name Indication' extension
+ (<url href="http://www.ietf.org/rfc/rfc6066.txt">RFC 6066</url>) is supported.</item>
+ <item>Application Layer Protocol Negotiation (ALPN) and its successor Next Protocol Negotiation (NPN) are supported. </item>
+ <item>It is possible to use Pre-Shared Key (PSK) and Secure Remote Password (SRP)
+ cipher suites, but they are not enabled by default.
+ </item>
+ </list>
+ </section>
+
+
+ <section>
+ <title>SSL 2.0</title>
+ <p>For security reasons SSL-2.0 is not supported. Interoperability with SSL-2.0 enabled clients dropped. (OTP 21)</p>
+ </section>
+
+ <section>
+ <title>SSL 3.0</title>
+ <p>For security reasons SSL-3.0 is no longer supported by default, but can be configured. (OTP 19)</p>
+ </section>
+
+ <section>
+ <title>TLS 1.0</title>
+ <p>For security reasons TLS-1.0 is no longer supported by default, but can be configured. (OTP 22)</p>
+ </section>
+
+ <section>
+ <title>TLS 1.1</title>
+ <p>For security reasons TLS-1.1 is no longer supported by default, but can be configured. (OTP 22)</p>
+ </section>
+
+ <section>
+ <title>TLS 1.2</title>
+ <p>Supported</p>
+ </section>
+
+ <section>
+ <title>DTLS 1.0</title>
+ <p>For security reasons DTLS-1.0 (based on TLS 1.1) is no longer supported by default, but can be configured. (OTP 22)</p>
+ </section>
+
+ <section>
+ <title>DTLS 1.2</title>
+ <p>Supported (based on TLS 1.2)</p>
+ </section>
+
+ <section>
+ <title>DTLS 1.3</title>
+ <p>Not yet supported</p>
+ </section>
+
+ <section>
+ <title>TLS 1.3</title>
+ <p> This section describes the current state of standards compliance for TLS 1.3.</p>
+ <p>(C = Compliant, NC = Non-Compliant, P = Partially-Compliant, NA = Not Applicable)</p>
+ <table>
+ <row>
+ <cell align="left" valign="middle"><em>Section</em></cell>
+ <cell align="left" valign="middle"><em>Feature</em></cell>
+ <cell align="left" valign="middle"><em>State</em></cell>
+ <cell align="left" valign="middle"><em>Since</em></cell>
+ </row>
+
+ <row>
+ <cell align="left" valign="middle">
+ <url href="https://tools.ietf.org/html/rfc8446#section-1.2">
+ 1.3. Updates Affecting TLS 1.2
+ </url>
+ </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>
+ <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>
+ </row>
+ <row>
+ <cell align="left" valign="middle"></cell>
+ <cell align="left" valign="middle">RSASSA-PSS signature schemes</cell>
+ <cell align="left" valign="middle"><em>P</em></cell>
+ <cell align="left" valign="middle">22</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>
+ </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>
+ </row>
+
+ <row>
+ <cell align="left" valign="middle">
+ <url href="https://tools.ietf.org/html/rfc8446#section-2">
+ 2. Protocol Overview
+ </url>
+ </cell>
+ <cell align="left" valign="middle"></cell>
+ <cell align="left" valign="middle"><em>P</em></cell>
+ <cell align="left" valign="middle"><em>22</em></cell>
+ </row>
+ <row>
+ <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>
+ </row>
+ <row>
+ <cell align="left" valign="middle"></cell>
+ <cell align="left" valign="middle">PSK-only</cell>
+ <cell align="left" valign="middle"><em>NC</em></cell>
+ <cell align="left" valign="middle"></cell>
+ </row>
+ <row>
+ <cell align="left" valign="middle"></cell>
+ <cell align="left" valign="middle">PSK with (EC)DHE</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-2.1">
+ 2.1. Incorrect DHE share
+ </url>
+ </cell>
+ <cell align="left" valign="middle">HelloRetryRequest</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">
+ <url href="https://tools.ietf.org/html/rfc8446#section-2.2">
+ 2.2. Resumption and Pre-Shared Key (PSK)
+ </url>
+ </cell>
+ <cell align="left" valign="middle"></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-2.3">
+ 2.3. 0-RTT Data
+ </url>
+ </cell>
+ <cell align="left" valign="middle"></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.1.1">
+ 4.1.1. Cryptographic Negotiation
+ </url>
+ </cell>
+ <cell align="left" valign="middle"></cell>
+ <cell align="left" valign="middle"><em>P</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_groups extension</cell>
+ <cell align="left" valign="middle"><em>C</em></cell>
+ <cell align="left" valign="middle"></cell>
+ </row>
+ <row>
+ <cell align="left" valign="middle"></cell>
+ <cell align="left" valign="middle">signature_algorithms extension</cell>
+ <cell align="left" valign="middle"><em>C</em></cell>
+ <cell align="left" valign="middle"></cell>
+ </row>
+ <row>
+ <cell align="left" valign="middle"></cell>
+ <cell align="left" valign="middle">pre_shared_key extension</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.1.2">
+ 4.1.2. Client Hello
+ </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>
+ </row>
+ <row>
+ <cell align="left" valign="middle"></cell>
+ <cell align="left" valign="middle">server_name (RFC6066)</cell>
+ <cell align="left" valign="middle"><em>NC</em></cell>
+ <cell align="left" valign="middle"></cell>
+ </row>
+ <row>
+ <cell align="left" valign="middle"></cell>
+ <cell align="left" valign="middle">max_fragment_length (RFC6066)</cell>
+ <cell align="left" valign="middle"><em>NC</em></cell>
+ <cell align="left" valign="middle"></cell>
+ </row>
+ <row>
+ <cell align="left" valign="middle"></cell>
+ <cell align="left" valign="middle">status_request (RFC6066)</cell>
+ <cell align="left" valign="middle"><em>NC</em></cell>
+ <cell align="left" valign="middle"></cell>
+ </row>
+ <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>
+ </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>
+ </row>
+ <row>
+ <cell align="left" valign="middle"></cell>
+ <cell align="left" valign="middle">use_srtp (RFC5764)</cell>
+ <cell align="left" valign="middle"><em>NC</em></cell>
+ <cell align="left" valign="middle"></cell>
+ </row>
+ <row>
+ <cell align="left" valign="middle"></cell>
+ <cell align="left" valign="middle">heartbeat (RFC6520)</cell>
+ <cell align="left" valign="middle"><em>NC</em></cell>
+ <cell align="left" valign="middle"></cell>
+ </row>
+ <row>
+ <cell align="left" valign="middle"></cell>
+ <cell align="left" valign="middle">application_layer_protocol_negotiation (RFC7301)</cell>
+ <cell align="left" valign="middle"><em>NC</em></cell>
+ <cell align="left" valign="middle"></cell>
+ </row>
+ <row>
+ <cell align="left" valign="middle"></cell>
+ <cell align="left" valign="middle">signed_certificate_timestamp (RFC6962)</cell>
+ <cell align="left" valign="middle"><em>NC</em></cell>
+ <cell align="left" valign="middle"></cell>
+ </row>
+ <row>
+ <cell align="left" valign="middle"></cell>
+ <cell align="left" valign="middle">client_certificate_type (RFC7250)</cell>
+ <cell align="left" valign="middle"><em>NC</em></cell>
+ <cell align="left" valign="middle"></cell>
+ </row>
+ <row>
+ <cell align="left" valign="middle"></cell>
+ <cell align="left" valign="middle">server_certificate_type (RFC7250)</cell>
+ <cell align="left" valign="middle"><em>NC</em></cell>
+ <cell align="left" valign="middle"></cell>
+ </row>
+ <row>
+ <cell align="left" valign="middle"></cell>
+ <cell align="left" valign="middle">padding (RFC7685)</cell>
+ <cell align="left" valign="middle"><em>NC</em></cell>
+ <cell align="left" valign="middle"></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>
+ </row>
+ <row>
+ <cell align="left" valign="middle"></cell>
+ <cell align="left" valign="middle">pre_shared_key (RFC8446)</cell>
+ <cell align="left" valign="middle"><em>NC</em></cell>
+ <cell align="left" valign="middle"></cell>
+ </row>
+ <row>
+ <cell align="left" valign="middle"></cell>
+ <cell align="left" valign="middle">psk_key_exchange_modes (RFC8446)</cell>
+ <cell align="left" valign="middle"><em>NC</em></cell>
+ <cell align="left" valign="middle"></cell>
+ </row>
+ <row>
+ <cell align="left" valign="middle"></cell>
+ <cell align="left" valign="middle">early_data (RFC8446)</cell>
+ <cell align="left" valign="middle"><em>NC</em></cell>
+ <cell align="left" valign="middle"></cell>
+ </row>
+ <row>
+ <cell align="left" valign="middle"></cell>
+ <cell align="left" valign="middle">cookie (RFC8446) </cell>
+ <cell align="left" valign="middle"><em>NC</em></cell>
+ <cell align="left" valign="middle"></cell>
+ </row>
+ <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>
+ </row>
+ <row>
+ <cell align="left" valign="middle"></cell>
+ <cell align="left" valign="middle">certificate_authorities (RFC8446)</cell>
+ <cell align="left" valign="middle"><em>NC</em></cell>
+ <cell align="left" valign="middle"></cell>
+ </row>
+ <row>
+ <cell align="left" valign="middle"></cell>
+ <cell align="left" valign="middle">oid_filters (RFC8446)</cell>
+ <cell align="left" valign="middle"><em>NC</em></cell>
+ <cell align="left" valign="middle"></cell>
+ </row>
+ <row>
+ <cell align="left" valign="middle"></cell>
+ <cell align="left" valign="middle">post_handshake_auth (RFC8446)</cell>
+ <cell align="left" valign="middle"><em>NC</em></cell>
+ <cell align="left" valign="middle"></cell>
+ </row>
+ <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>
+ </row>
+
+ <row>
+ <cell align="left" valign="middle"></cell>
+ <cell align="left" valign="middle"><em>Server</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">server_name (RFC6066)</cell>
+ <cell align="left" valign="middle"><em>NC</em></cell>
+ <cell align="left" valign="middle"></cell>
+ </row>
+ <row>
+ <cell align="left" valign="middle"></cell>
+ <cell align="left" valign="middle">max_fragment_length (RFC6066)</cell>
+ <cell align="left" valign="middle"><em>NC</em></cell>
+ <cell align="left" valign="middle"></cell>
+ </row>
+ <row>
+ <cell align="left" valign="middle"></cell>
+ <cell align="left" valign="middle">status_request (RFC6066)</cell>
+ <cell align="left" valign="middle"><em>NC</em></cell>
+ <cell align="left" valign="middle"></cell>
+ </row>
+ <row>
+ <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>
+ </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>
+ </row>
+ <row>
+ <cell align="left" valign="middle"></cell>
+ <cell align="left" valign="middle">use_srtp (RFC5764)</cell>
+ <cell align="left" valign="middle"><em>NC</em></cell>
+ <cell align="left" valign="middle"></cell>
+ </row>
+ <row>
+ <cell align="left" valign="middle"></cell>
+ <cell align="left" valign="middle">heartbeat (RFC6520)</cell>
+ <cell align="left" valign="middle"><em>NC</em></cell>
+ <cell align="left" valign="middle"></cell>
+ </row>
+ <row>
+ <cell align="left" valign="middle"></cell>
+ <cell align="left" valign="middle">application_layer_protocol_negotiation (RFC7301)</cell>
+ <cell align="left" valign="middle"><em>NC</em></cell>
+ <cell align="left" valign="middle"></cell>
+ </row>
+ <row>
+ <cell align="left" valign="middle"></cell>
+ <cell align="left" valign="middle">signed_certificate_timestamp (RFC6962)</cell>
+ <cell align="left" valign="middle"><em>NC</em></cell>
+ <cell align="left" valign="middle"></cell>
+ </row>
+ <row>
+ <cell align="left" valign="middle"></cell>
+ <cell align="left" valign="middle">client_certificate_type (RFC7250)</cell>
+ <cell align="left" valign="middle"><em>NC</em></cell>
+ <cell align="left" valign="middle"></cell>
+ </row>
+ <row>
+ <cell align="left" valign="middle"></cell>
+ <cell align="left" valign="middle">server_certificate_type (RFC7250)</cell>
+ <cell align="left" valign="middle"><em>NC</em></cell>
+ <cell align="left" valign="middle"></cell>
+ </row>
+ <row>
+ <cell align="left" valign="middle"></cell>
+ <cell align="left" valign="middle">padding (RFC7685)</cell>
+ <cell align="left" valign="middle"><em>NC</em></cell>
+ <cell align="left" valign="middle"></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>
+ </row>
+ <row>
+ <cell align="left" valign="middle"></cell>
+ <cell align="left" valign="middle">pre_shared_key (RFC8446)</cell>
+ <cell align="left" valign="middle"><em>NC</em></cell>
+ <cell align="left" valign="middle"></cell>
+ </row>
+ <row>
+ <cell align="left" valign="middle"></cell>
+ <cell align="left" valign="middle">psk_key_exchange_modes (RFC8446)</cell>
+ <cell align="left" valign="middle"><em>NC</em></cell>
+ <cell align="left" valign="middle"></cell>
+ </row>
+ <row>
+ <cell align="left" valign="middle"></cell>
+ <cell align="left" valign="middle">early_data (RFC8446)</cell>
+ <cell align="left" valign="middle"><em>NC</em></cell>
+ <cell align="left" valign="middle"></cell>
+ </row>
+ <row>
+ <cell align="left" valign="middle"></cell>
+ <cell align="left" valign="middle">cookie (RFC8446) </cell>
+ <cell align="left" valign="middle"><em>NC</em></cell>
+ <cell align="left" valign="middle"></cell>
+ </row>
+ <row>
+ <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>
+ </row>
+ <row>
+ <cell align="left" valign="middle"></cell>
+ <cell align="left" valign="middle">certificate_authorities (RFC8446)</cell>
+ <cell align="left" valign="middle"><em>NC</em></cell>
+ <cell align="left" valign="middle"></cell>
+ </row>
+ <row>
+ <cell align="left" valign="middle"></cell>
+ <cell align="left" valign="middle">oid_filters (RFC8446)</cell>
+ <cell align="left" valign="middle"><em>NC</em></cell>
+ <cell align="left" valign="middle"></cell>
+ </row>
+ <row>
+ <cell align="left" valign="middle"></cell>
+ <cell align="left" valign="middle">post_handshake_auth (RFC8446)</cell>
+ <cell align="left" valign="middle"><em>NC</em></cell>
+ <cell align="left" valign="middle"></cell>
+ </row>
+ <row>
+ <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>
+ </row>
+
+ <row>
+ <cell align="left" valign="middle">
+ <url href="https://tools.ietf.org/html/rfc8446#section-4.1.3">
+ 4.1.3. Server Hello
+ </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>
+ </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>
+ </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>
+ </row>
+ <row>
+ <cell align="left" valign="middle"></cell>
+ <cell align="left" valign="middle">pre_shared_key (RFC8446)</cell>
+ <cell align="left" valign="middle"><em>NC</em></cell>
+ <cell align="left" valign="middle"></cell>
+ </row>
+ <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>
+ </row>
+
+ <row>
+ <cell align="left" valign="middle"></cell>
+ <cell align="left" valign="middle"><em>Server</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">Version downgrade protection</cell>
+ <cell align="left" valign="middle"><em>C</em></cell>
+ <cell align="left" valign="middle">22</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>
+ </row>
+ <row>
+ <cell align="left" valign="middle"></cell>
+ <cell align="left" valign="middle">pre_shared_key (RFC8446)</cell>
+ <cell align="left" valign="middle"><em>NC</em></cell>
+ <cell align="left" valign="middle"></cell>
+ </row>
+ <row>
+ <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>
+ </row>
+
+ <row>
+ <cell align="left" valign="middle">
+ <url href="https://tools.ietf.org/html/rfc8446#section-4.1.4">
+ 4.1.4. Hello Retry Request
+ </url>
+ </cell>
+ <cell align="left" valign="middle"><em>Server</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">key_share (RFC8446)</cell>
+ <cell align="left" valign="middle"><em>C</em></cell>
+ <cell align="left" valign="middle">22</cell>
+ </row>
+ <row>
+ <cell align="left" valign="middle"></cell>
+ <cell align="left" valign="middle">cookie (RFC8446)</cell>
+ <cell align="left" valign="middle"><em>NC</em></cell>
+ <cell align="left" valign="middle"></cell>
+ </row>
+ <row>
+ <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>
+ </row>
+
+ <row>
+ <cell align="left" valign="middle">
+ <url href="https://tools.ietf.org/html/rfc8446#section-4.2.1">
+ 4.2.1. Supported Versions
+ </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>
+ </row>
+ <row>
+ <cell align="left" valign="middle"></cell>
+ <cell align="left" valign="middle"><em>Server</em></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">
+ <url href="https://tools.ietf.org/html/rfc8446#section-4.2.2">
+ 4.2.2. Cookie
+ </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>
+ </row>
+ <row>
+ <cell align="left" valign="middle"></cell>
+ <cell align="left" valign="middle"><em>Server</em></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">
+ <url href="https://tools.ietf.org/html/rfc8446#section-4.2.3">
+ 4.2.3. Signature Algorithms
+ </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>
+ </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>
+ </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>
+ </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>
+ </row>
+ <row>
+ <cell align="left" valign="middle"></cell>
+ <cell align="left" valign="middle">ecdsa_secp256r1_sha256</cell>
+ <cell align="left" valign="middle"><em>NC</em></cell>
+ <cell align="left" valign="middle"></cell>
+ </row>
+ <row>
+ <cell align="left" valign="middle"></cell>
+ <cell align="left" valign="middle">ecdsa_secp384r1_sha384</cell>
+ <cell align="left" valign="middle"><em>NC</em></cell>
+ <cell align="left" valign="middle"></cell>
+ </row>
+ <row>
+ <cell align="left" valign="middle"></cell>
+ <cell align="left" valign="middle">ecdsa_secp521r1_sha512</cell>
+ <cell align="left" valign="middle"><em>NC</em></cell>
+ <cell align="left" valign="middle"></cell>
+ </row>
+ <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>
+ </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>
+ </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>
+ </row>
+ <row>
+ <cell align="left" valign="middle"></cell>
+ <cell align="left" valign="middle">ed25519</cell>
+ <cell align="left" valign="middle"><em>NC</em></cell>
+ <cell align="left" valign="middle"></cell>
+ </row>
+ <row>
+ <cell align="left" valign="middle"></cell>
+ <cell align="left" valign="middle">ed448</cell>
+ <cell align="left" valign="middle"><em>NC</em></cell>
+ <cell align="left" valign="middle"></cell>
+ </row>
+ <row>
+ <cell align="left" valign="middle"></cell>
+ <cell align="left" valign="middle">rsa_pss_pss_sha256</cell>
+ <cell align="left" valign="middle"><em>NC</em></cell>
+ <cell align="left" valign="middle"></cell>
+ </row>
+ <row>
+ <cell align="left" valign="middle"></cell>
+ <cell align="left" valign="middle">rsa_pss_pss_sha384</cell>
+ <cell align="left" valign="middle"><em>NC</em></cell>
+ <cell align="left" valign="middle"></cell>
+ </row>
+ <row>
+ <cell align="left" valign="middle"></cell>
+ <cell align="left" valign="middle">rsa_pss_pss_sha512</cell>
+ <cell align="left" valign="middle"><em>NC</em></cell>
+ <cell align="left" valign="middle"></cell>
+ </row>
+ <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>
+ </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>
+ </row>
+
+ <row>
+ <cell align="left" valign="middle"></cell>
+ <cell align="left" valign="middle"><em>Server</em></cell>
+ <cell align="left" valign="middle"><em>P</em></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_sha256</cell>
+ <cell align="left" valign="middle"><em>C</em></cell>
+ <cell align="left" valign="middle">22</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>
+ </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>
+ </row>
+ <row>
+ <cell align="left" valign="middle"></cell>
+ <cell align="left" valign="middle">ecdsa_secp256r1_sha256</cell>
+ <cell align="left" valign="middle"><em>NC</em></cell>
+ <cell align="left" valign="middle"></cell>
+ </row>
+ <row>
+ <cell align="left" valign="middle"></cell>
+ <cell align="left" valign="middle">ecdsa_secp384r1_sha384</cell>
+ <cell align="left" valign="middle"><em>NC</em></cell>
+ <cell align="left" valign="middle"></cell>
+ </row>
+ <row>
+ <cell align="left" valign="middle"></cell>
+ <cell align="left" valign="middle">ecdsa_secp521r1_sha512</cell>
+ <cell align="left" valign="middle"><em>NC</em></cell>
+ <cell align="left" valign="middle"></cell>
+ </row>
+ <row>
+ <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>
+ </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>
+ </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>
+ </row>
+ <row>
+ <cell align="left" valign="middle"></cell>
+ <cell align="left" valign="middle">ed25519</cell>
+ <cell align="left" valign="middle"><em>NC</em></cell>
+ <cell align="left" valign="middle"></cell>
+ </row>
+ <row>
+ <cell align="left" valign="middle"></cell>
+ <cell align="left" valign="middle">ed448</cell>
+ <cell align="left" valign="middle"><em>NC</em></cell>
+ <cell align="left" valign="middle"></cell>
+ </row>
+ <row>
+ <cell align="left" valign="middle"></cell>
+ <cell align="left" valign="middle">rsa_pss_pss_sha256</cell>
+ <cell align="left" valign="middle"><em>NC</em></cell>
+ <cell align="left" valign="middle"></cell>
+ </row>
+ <row>
+ <cell align="left" valign="middle"></cell>
+ <cell align="left" valign="middle">rsa_pss_pss_sha384</cell>
+ <cell align="left" valign="middle"><em>NC</em></cell>
+ <cell align="left" valign="middle"></cell>
+ </row>
+ <row>
+ <cell align="left" valign="middle"></cell>
+ <cell align="left" valign="middle">rsa_pss_pss_sha512</cell>
+ <cell align="left" valign="middle"><em>NC</em></cell>
+ <cell align="left" valign="middle"></cell>
+ </row>
+ <row>
+ <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>
+ </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>
+ </row>
+
+ <row>
+ <cell align="left" valign="middle">
+ <url href="https://tools.ietf.org/html/rfc8446#section-4.2.4">
+ 4.2.4. Certificate Authorities
+ </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>
+ </row>
+ <row>
+ <cell align="left" valign="middle"></cell>
+ <cell align="left" valign="middle"><em>Server</em></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">
+ <url href="https://tools.ietf.org/html/rfc8446#section-4.2.5">
+ 4.2.5. OID Filters
+ </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>
+ </row>
+ <row>
+ <cell align="left" valign="middle"></cell>
+ <cell align="left" valign="middle"><em>Server</em></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">
+ <url href="https://tools.ietf.org/html/rfc8446#section-4.2.6">
+ 4.2.6. Post-Handshake Client Authentication
+ </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>
+ </row>
+ <row>
+ <cell align="left" valign="middle"></cell>
+ <cell align="left" valign="middle"><em>Server</em></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">
+ <url href="https://tools.ietf.org/html/rfc8446#section-4.2.7">
+ 4.2.7. Supported Groups
+ </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>
+ </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>
+ </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>
+ </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>
+ </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>
+ </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>
+ </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>
+ </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>
+ </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>
+ </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>
+ </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>
+ </row>
+
+ <row>
+ <cell align="left" valign="middle"></cell>
+ <cell align="left" valign="middle"><em>Server</em></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">secp256r1</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">secp384r1</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">secp521r1</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">x25519</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">x448</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">ffdhe2048</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">ffdhe3072</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">ffdhe4096</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">ffdhe6144</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">ffdhe8192</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">
+ <url href="https://tools.ietf.org/html/rfc8446#section-4.2.8">
+ 4.2.8. Key Share
+ </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>
+ </row>
+ <row>
+ <cell align="left" valign="middle"></cell>
+ <cell align="left" valign="middle"><em>Server</em></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">
+ <url href="https://tools.ietf.org/html/rfc8446#section-4.2.9">
+ 4.2.9. Pre-Shared Key Exchange Modes
+ </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>
+ </row>
+ <row>
+ <cell align="left" valign="middle"></cell>
+ <cell align="left" valign="middle"><em>Server</em></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">
+ <url href="https://tools.ietf.org/html/rfc8446#section-4.2.10">
+ 4.2.10. Early Data Indication
+ </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>
+ </row>
+ <row>
+ <cell align="left" valign="middle"></cell>
+ <cell align="left" valign="middle"><em>Server</em></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">
+ <url href="https://tools.ietf.org/html/rfc8446#section-4.2.11">
+ 4.2.11. Pre-Shared Key Extension
+ </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>
+ </row>
+ <row>
+ <cell align="left" valign="middle"></cell>
+ <cell align="left" valign="middle"><em>Server</em></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">
+ <url href="https://tools.ietf.org/html/rfc8446#section-4.2.11.1">
+ 4.2.11.1. Ticket Age
+ </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>
+ </row>
+ <row>
+ <cell align="left" valign="middle"></cell>
+ <cell align="left" valign="middle"><em>Server</em></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">
+ <url href="https://tools.ietf.org/html/rfc8446#section-4.2.11.2">
+ 4.2.11.2. PSK Binder
+ </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>
+ </row>
+ <row>
+ <cell align="left" valign="middle"></cell>
+ <cell align="left" valign="middle"><em>Server</em></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">
+ <url href="https://tools.ietf.org/html/rfc8446#section-4.2.11.3">
+ 4.2.11.3. Processing Order
+ </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>
+ </row>
+ <row>
+ <cell align="left" valign="middle"></cell>
+ <cell align="left" valign="middle"><em>Server</em></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">
+ <url href="https://tools.ietf.org/html/rfc8446#section-4.3.1">
+ 4.3.1. Encrypted Extensions
+ </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>
+ </row>
+ <row>
+ <cell align="left" valign="middle"></cell>
+ <cell align="left" valign="middle">server_name (RFC6066)</cell>
+ <cell align="left" valign="middle"><em>NC</em></cell>
+ <cell align="left" valign="middle"></cell>
+ </row>
+ <row>
+ <cell align="left" valign="middle"></cell>
+ <cell align="left" valign="middle">max_fragment_length (RFC6066)</cell>
+ <cell align="left" valign="middle"><em>NC</em></cell>
+ <cell align="left" valign="middle"></cell>
+ </row>
+ <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>
+ </row>
+ <row>
+ <cell align="left" valign="middle"></cell>
+ <cell align="left" valign="middle">use_srtp (RFC5764)</cell>
+ <cell align="left" valign="middle"><em>NC</em></cell>
+ <cell align="left" valign="middle"></cell>
+ </row>
+ <row>
+ <cell align="left" valign="middle"></cell>
+ <cell align="left" valign="middle">heartbeat (RFC6520)</cell>
+ <cell align="left" valign="middle"><em>NC</em></cell>
+ <cell align="left" valign="middle"></cell>
+ </row>
+ <row>
+ <cell align="left" valign="middle"></cell>
+ <cell align="left" valign="middle">application_layer_protocol_negotiation (RFC7301)</cell>
+ <cell align="left" valign="middle"><em>NC</em></cell>
+ <cell align="left" valign="middle"></cell>
+ </row>
+ <row>
+ <cell align="left" valign="middle"></cell>
+ <cell align="left" valign="middle">client_certificate_type (RFC7250)</cell>
+ <cell align="left" valign="middle"><em>NC</em></cell>
+ <cell align="left" valign="middle"></cell>
+ </row>
+ <row>
+ <cell align="left" valign="middle"></cell>
+ <cell align="left" valign="middle">server_certificate_type (RFC7250)</cell>
+ <cell align="left" valign="middle"><em>NC</em></cell>
+ <cell align="left" valign="middle"></cell>
+ </row>
+ <row>
+ <cell align="left" valign="middle"></cell>
+ <cell align="left" valign="middle">early_data (RFC8446)</cell>
+ <cell align="left" valign="middle"><em>NC</em></cell>
+ <cell align="left" valign="middle"></cell>
+ </row>
+ <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>
+ </row>
+
+ <row>
+ <cell align="left" valign="middle"></cell>
+ <cell align="left" valign="middle"><em>Server</em></cell>
+ <cell align="left" valign="middle"><em>P</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 (RFC6066)</cell>
+ <cell align="left" valign="middle"><em>NC</em></cell>
+ <cell align="left" valign="middle"></cell>
+ </row>
+ <row>
+ <cell align="left" valign="middle"></cell>
+ <cell align="left" valign="middle">max_fragment_length (RFC6066)</cell>
+ <cell align="left" valign="middle"><em>NC</em></cell>
+ <cell align="left" valign="middle"></cell>
+ </row>
+ <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>
+ </row>
+ <row>
+ <cell align="left" valign="middle"></cell>
+ <cell align="left" valign="middle">use_srtp (RFC5764)</cell>
+ <cell align="left" valign="middle"><em>NC</em></cell>
+ <cell align="left" valign="middle"></cell>
+ </row>
+ <row>
+ <cell align="left" valign="middle"></cell>
+ <cell align="left" valign="middle">heartbeat (RFC6520)</cell>
+ <cell align="left" valign="middle"><em>NC</em></cell>
+ <cell align="left" valign="middle"></cell>
+ </row>
+ <row>
+ <cell align="left" valign="middle"></cell>
+ <cell align="left" valign="middle">application_layer_protocol_negotiation (RFC7301)</cell>
+ <cell align="left" valign="middle"><em>NC</em></cell>
+ <cell align="left" valign="middle"></cell>
+ </row>
+ <row>
+ <cell align="left" valign="middle"></cell>
+ <cell align="left" valign="middle">client_certificate_type (RFC7250)</cell>
+ <cell align="left" valign="middle"><em>NC</em></cell>
+ <cell align="left" valign="middle"></cell>
+ </row>
+ <row>
+ <cell align="left" valign="middle"></cell>
+ <cell align="left" valign="middle">server_certificate_type (RFC7250)</cell>
+ <cell align="left" valign="middle"><em>NC</em></cell>
+ <cell align="left" valign="middle"></cell>
+ </row>
+ <row>
+ <cell align="left" valign="middle"></cell>
+ <cell align="left" valign="middle">early_data (RFC8446)</cell>
+ <cell align="left" valign="middle"><em>NC</em></cell>
+ <cell align="left" valign="middle"></cell>
+ </row>
+ <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>
+ </row>
+
+ <row>
+ <cell align="left" valign="middle">
+ <url href="https://tools.ietf.org/html/rfc8446#section-4.3.2">
+ 4.3.2. Certificate Request
+ </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>
+ </row>
+ <row>
+ <cell align="left" valign="middle"></cell>
+ <cell align="left" valign="middle">status_request (RFC6066)</cell>
+ <cell align="left" valign="middle"><em>NC</em></cell>
+ <cell align="left" valign="middle"></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>
+ </row>
+ <row>
+ <cell align="left" valign="middle"></cell>
+ <cell align="left" valign="middle">signed_certificate_timestamp (RFC6962)</cell>
+ <cell align="left" valign="middle"><em>NC</em></cell>
+ <cell align="left" valign="middle"></cell>
+ </row>
+ <row>
+ <cell align="left" valign="middle"></cell>
+ <cell align="left" valign="middle">certificate_authorities (RFC8446)</cell>
+ <cell align="left" valign="middle"><em>NC</em></cell>
+ <cell align="left" valign="middle"></cell>
+ </row>
+ <row>
+ <cell align="left" valign="middle"></cell>
+ <cell align="left" valign="middle">oid_filters (RFC8446)</cell>
+ <cell align="left" valign="middle"><em>NC</em></cell>
+ <cell align="left" valign="middle"></cell>
+ </row>
+ <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>
+ </row>
+
+ <row>
+ <cell align="left" valign="middle"></cell>
+ <cell align="left" valign="middle"><em>Server</em></cell>
+ <cell align="left" valign="middle"><em>P</em></cell>
+ <cell align="left" valign="middle"><em>22</em></cell>
+ </row>
+ <row>
+ <cell align="left" valign="middle"></cell>
+ <cell align="left" valign="middle">status_request (RFC6066)</cell>
+ <cell align="left" valign="middle"><em>NC</em></cell>
+ <cell align="left" valign="middle"></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>
+ </row>
+ <row>
+ <cell align="left" valign="middle"></cell>
+ <cell align="left" valign="middle">signed_certificate_timestamp (RFC6962)</cell>
+ <cell align="left" valign="middle"><em>NC</em></cell>
+ <cell align="left" valign="middle"></cell>
+ </row>
+ <row>
+ <cell align="left" valign="middle"></cell>
+ <cell align="left" valign="middle">certificate_authorities (RFC8446)</cell>
+ <cell align="left" valign="middle"><em>NC</em></cell>
+ <cell align="left" valign="middle"></cell>
+ </row>
+ <row>
+ <cell align="left" valign="middle"></cell>
+ <cell align="left" valign="middle">oid_filters (RFC8446)</cell>
+ <cell align="left" valign="middle"><em>NC</em></cell>
+ <cell align="left" valign="middle"></cell>
+ </row>
+ <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>
+ </row>
+
+ <row>
+ <cell align="left" valign="middle">
+ <url href="https://tools.ietf.org/html/rfc8446#section-4.4.1">
+ 4.4.1. The Transcript Hash
+ </url>
+ </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</em></cell>
+ </row>
+
+ <row>
+ <cell align="left" valign="middle">
+ <url href="https://tools.ietf.org/html/rfc8446#section-4.4.2">
+ 4.4.2. Certificate
+ </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>
+ </row>
+ <row>
+ <cell align="left" valign="middle"></cell>
+ <cell align="left" valign="middle">status_request (RFC6066)</cell>
+ <cell align="left" valign="middle"><em>NC</em></cell>
+ <cell align="left" valign="middle"></cell>
+ </row>
+ <row>
+ <cell align="left" valign="middle"></cell>
+ <cell align="left" valign="middle">signed_certificate_timestamp (RFC6962)</cell>
+ <cell align="left" valign="middle"><em>NC</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"><em>P</em></cell>
+ <cell align="left" valign="middle"><em>22</em></cell>
+ </row>
+ <row>
+ <cell align="left" valign="middle"></cell>
+ <cell align="left" valign="middle">status_request (RFC6066)</cell>
+ <cell align="left" valign="middle"><em>NC</em></cell>
+ <cell align="left" valign="middle"></cell>
+ </row>
+ <row>
+ <cell align="left" valign="middle"></cell>
+ <cell align="left" valign="middle">signed_certificate_timestamp (RFC6962)</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.1">
+ 4.4.2.1. OCSP Status and SCT Extensions
+ </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>
+ </row>
+ <row>
+ <cell align="left" valign="middle"></cell>
+ <cell align="left" valign="middle"><em>Server</em></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">
+ <url href="https://tools.ietf.org/html/rfc8446#section-4.4.2.2">
+ 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>
+ </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>
+ </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>
+ </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>
+ </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"><em></em></cell>
+ </row>
+
+ <row>
+ <cell align="left" valign="middle"></cell>
+ <cell align="left" valign="middle"><em>Server</em></cell>
+ <cell align="left" valign="middle"><em>P</em></cell>
+ <cell align="left" valign="middle"><em></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>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>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>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"><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"><em>NC</em></cell>
+ <cell align="left" valign="middle"><em></em></cell>
+ </row>
+
+ <row>
+ <cell align="left" valign="middle">
+ <url href="https://tools.ietf.org/html/rfc8446#section-4.4.2.4">
+ 4.4.2.4. Receiving a Certificate Message
+ </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>
+ </row>
+ <row>
+ <cell align="left" valign="middle"></cell>
+ <cell align="left" valign="middle"><em>Server</em></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">
+ <url href="https://tools.ietf.org/html/rfc8446#section-4.4.3">
+ 4.4.3. Certificate Verify
+ </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>
+ </row>
+ <row>
+ <cell align="left" valign="middle"></cell>
+ <cell align="left" valign="middle"><em>Server</em></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">
+ <url href="https://tools.ietf.org/html/rfc8446#section-4.4.4">
+ 4.4.4. Finished
+ </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>
+ </row>
+ <row>
+ <cell align="left" valign="middle"></cell>
+ <cell align="left" valign="middle"><em>Server</em></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">
+ <url href="https://tools.ietf.org/html/rfc8446#section-4.5">
+ 4.5. End of Early Data
+ </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>
+ </row>
+ <row>
+ <cell align="left" valign="middle"></cell>
+ <cell align="left" valign="middle"><em>Server</em></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">
+ <url href="https://tools.ietf.org/html/rfc8446#section-4.6.1">
+ 4.6.1. New Session Ticket Message
+ </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>
+ </row>
+ <row>
+ <cell align="left" valign="middle"></cell>
+ <cell align="left" valign="middle">early_data (RFC8446)</cell>
+ <cell align="left" valign="middle"><em>NC</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"><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">early_data (RFC8446)</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.6.2">
+ 4.6.2. Post-Handshake Authentication
+ </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>
+ </row>
+ <row>
+ <cell align="left" valign="middle"></cell>
+ <cell align="left" valign="middle"><em>Server</em></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">
+ <url href="https://tools.ietf.org/html/rfc8446#section-4.6.3">
+ 4.6.3. Key and Initialization Vector Update
+ </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>
+ </row>
+ <row>
+ <cell align="left" valign="middle"></cell>
+ <cell align="left" valign="middle"><em>Server</em></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">
+ <url href="https://tools.ietf.org/html/rfc8446#section-5.1">
+ 5.1. Record Layer
+ </url>
+ </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</em></cell>
+ </row>
+ <row>
+ <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>
+ </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>
+ </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>
+ </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>
+ </row>
+
+ <row>
+ <cell align="left" valign="middle">
+ <url href="https://tools.ietf.org/html/rfc8446#section-5.2">
+ 5.2. Record Payload Protection
+ </url>
+ </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</em></cell>
+ </row>
+
+ <row>
+ <cell align="left" valign="middle">
+ <url href="https://tools.ietf.org/html/rfc8446#section-5.3">
+ 5.3. Per-Record Nonce
+ </url>
+ </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</em></cell>
+ </row>
+
+ <row>
+ <cell align="left" valign="middle">
+ <url href="https://tools.ietf.org/html/rfc8446#section-5.4">
+ 5.4. Record Padding
+ </url>
+ </cell>
+ <cell align="left" valign="middle"><em></em></cell>
+ <cell align="left" valign="middle"><em>P</em></cell>
+ <cell align="left" valign="middle"><em>22</em></cell>
+ </row>
+ <row>
+ <cell align="left" valign="middle"></cell>
+ <cell align="left" valign="middle">MAY choose to pad</cell>
+ <cell align="left" valign="middle"><em>NC</em></cell>
+ <cell align="left" valign="middle"></cell>
+ </row>
+ <row>
+ <cell align="left" valign="middle"></cell>
+ <cell align="left" valign="middle">MUST NOT send Handshake and Alert records that have a zero-length TLSInnerPlaintext.content</cell>
+ <cell align="left" valign="middle"><em>NC</em></cell>
+ <cell align="left" valign="middle"></cell>
+ </row>
+ <row>
+ <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>
+ </row>
+
+ <row>
+ <cell align="left" valign="middle">
+ <url href="https://tools.ietf.org/html/rfc8446#section-5.5">
+ 5.5. Limits on Key Usage
+ </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>
+ </row>
+
+ <row>
+ <cell align="left" valign="middle">
+ <url href="https://tools.ietf.org/html/rfc8446#section-6.1">
+ 6.1. Closure Alerts
+ </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>
+ </row>
+ <row>
+ <cell align="left" valign="middle"></cell>
+ <cell align="left" valign="middle">close_notify</cell>
+ <cell align="left" valign="middle"><em>NC</em></cell>
+ <cell align="left" valign="middle"></cell>
+ </row>
+ <row>
+ <cell align="left" valign="middle"></cell>
+ <cell align="left" valign="middle">user_cancelled</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-6.2">
+ 6.2. Error Alerts
+ </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>22</em></cell>
+ </row>
+
+ <row>
+ <cell align="left" valign="middle">
+ <url href="https://tools.ietf.org/html/rfc8446#section-7.1">
+ 7.1. Key Schedule
+ </url>
+ </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</em></cell>
+ </row>
+
+ <row>
+ <cell align="left" valign="middle">
+ <url href="https://tools.ietf.org/html/rfc8446#section-7.2">
+ 7.2. Updating Traffic Secrets
+ </url>
+ </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</em></cell>
+ </row>
+
+ <row>
+ <cell align="left" valign="middle">
+ <url href="https://tools.ietf.org/html/rfc8446#section-7.3">
+ 7.3. Traffic Key Calculation
+ </url>
+ </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</em></cell>
+ </row>
+
+ <row>
+ <cell align="left" valign="middle">
+ <url href="https://tools.ietf.org/html/rfc8446#section-7.5">
+ 7.5. Exporters
+ </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>
+ </row>
+
+ <row>
+ <cell align="left" valign="middle">
+ <url href="https://tools.ietf.org/html/rfc8446#section-8">
+ 8. 0-RTT and Anti-Replay
+ </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>
+ </row>
+
+ <row>
+ <cell align="left" valign="middle">
+ <url href="https://tools.ietf.org/html/rfc8446#section-8.1">
+ 8.1. Single-Use Tickets
+ </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>
+ </row>
+
+ <row>
+ <cell align="left" valign="middle">
+ <url href="https://tools.ietf.org/html/rfc8446#section-8.2">
+ 8.2. Client Hello Recording
+ </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>
+ </row>
+
+ <row>
+ <cell align="left" valign="middle">
+ <url href="https://tools.ietf.org/html/rfc8446#section-8.3">
+ 8.3. Freshness Checks
+ </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>
+ </row>
+
+ <row>
+ <cell align="left" valign="middle">
+ <url href="https://tools.ietf.org/html/rfc8446#section-9.1">
+ 9.1. Mandatory-to-Implement Cipher Suites
+ </url>
+ </cell>
+ <cell align="left" valign="middle"><em></em></cell>
+ <cell align="left" valign="middle"><em>P</em></cell>
+ <cell align="left" valign="middle"><em>22</em></cell>
+ </row>
+ <row>
+ <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>
+ </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>
+ </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>NC</em></cell>
+ <cell align="left" valign="middle"></cell>
+ </row>
+
+ <row>
+ <cell align="left" valign="middle"></cell>
+ <cell align="left" valign="middle"><em>Digital signatures</em></cell>
+ <cell align="left" valign="middle"><em>P</em></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_pkcs1_sha256 (for certificates)</cell>
+ <cell align="left" valign="middle"><em>C</em></cell>
+ <cell align="left" valign="middle">22</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>
+ </row>
+ <row>
+ <cell align="left" valign="middle"></cell>
+ <cell align="left" valign="middle">MUST support ecdsa_secp256r1_sha256</cell>
+ <cell align="left" valign="middle"><em>NC</em></cell>
+ <cell align="left" valign="middle"></cell>
+ </row>
+
+ <row>
+ <cell align="left" valign="middle"></cell>
+ <cell align="left" valign="middle"><em>Key Exchange</em></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">MUST support key exchange with secp256r1</cell>
+ <cell align="left" valign="middle"><em>C</em></cell>
+ <cell align="left" valign="middle">22</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>
+ </row>
+
+ <row>
+ <cell align="left" valign="middle">
+ <url href="https://tools.ietf.org/html/rfc8446#section-9.2">
+ 9.2. Mandatory-to-Implement Extensions
+ </url>
+ </cell>
+ <cell align="left" valign="middle"><em></em></cell>
+ <cell align="left" valign="middle"><em>P</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</cell>
+ <cell align="left" valign="middle"><em>C</em></cell>
+ <cell align="left" valign="middle">22</cell>
+ </row>
+ <row>
+ <cell align="left" valign="middle"></cell>
+ <cell align="left" valign="middle">Cookie</cell>
+ <cell align="left" valign="middle"><em>NC</em></cell>
+ <cell align="left" valign="middle"></cell>
+ </row>
+ <row>
+ <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>
+ </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>
+ </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>
+ </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>
+ </row>
+ <row>
+ <cell align="left" valign="middle"></cell>
+ <cell align="left" valign="middle">Server Name Indication</cell>
+ <cell align="left" valign="middle"><em>NC</em></cell>
+ <cell align="left" valign="middle"></cell>
+ </row>
+
+ <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>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>
+ </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>
+ </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>
+ </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>
+ </row>
+ <row>
+ <cell align="left" valign="middle"></cell>
+ <cell align="left" valign="middle">"pre_shared_key" is REQUIRED for PSK key agreement</cell>
+ <cell align="left" valign="middle"><em>NC</em></cell>
+ <cell align="left" valign="middle"></cell>
+ </row>
+ <row>
+ <cell align="left" valign="middle"></cell>
+ <cell align="left" valign="middle">"psk_key_exchange_modes" is REQUIRED for PSK key agreement</cell>
+ <cell align="left" valign="middle"><em>NC</em></cell>
+ <cell align="left" valign="middle"></cell>
+ </row>
+
+ <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>
+ </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>
+ </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>
+ </row>
+
+ <row>
+ <cell align="left" valign="middle"></cell>
+ <cell align="left" valign="middle"><em>TLS 1.3 ServerHello</em></cell>
+ <cell align="left" valign="middle"><em>P</em></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 the use of the "server_name" extension</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-9.3">
+ 9.3. Protocol Invariants
+ </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>
+ </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>
+ </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>
+ </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"><em>NA</em></cell>
+ <cell align="left" valign="middle"></cell>
+ </row>
+
+ <row>
+ <cell align="left" valign="middle">
+ <url href="https://tools.ietf.org/html/rfc8446#section-B.4">
+ B.4. Cipher Suites
+ </url>
+ </cell>
+ <cell align="left" valign="middle"><em></em></cell>
+ <cell align="left" valign="middle"><em>P</em></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_GCM_SHA256</cell>
+ <cell align="left" valign="middle"><em>C</em></cell>
+ <cell align="left" valign="middle">22</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>
+ </row>
+ <row>
+ <cell align="left" valign="middle"></cell>
+ <cell align="left" valign="middle">TLS_CHACHA20_POLY1305_SHA256</cell>
+ <cell align="left" valign="middle"><em>NC</em></cell>
+ <cell align="left" valign="middle"></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>NC</em></cell>
+ <cell align="left" valign="middle"></cell>
+ </row>
+ <row>
+ <cell align="left" valign="middle"></cell>
+ <cell align="left" valign="middle">TLS_AES_128_CCM_8_SHA256</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-C.1">
+ C.1. Random Number Generation and Seeding
+ </url>
+ </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</em></cell>
+ </row>
+
+ <row>
+ <cell align="left" valign="middle">
+ <url href="https://tools.ietf.org/html/rfc8446#section-C.2">
+ C.2. Certificates and Authentication
+ </url>
+ </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</em></cell>
+ </row>
+
+ <row>
+ <cell align="left" valign="middle">
+ <url href="https://tools.ietf.org/html/rfc8446#section-C.3">
+ C.3. Implementation Pitfalls
+ </url>
+ </cell>
+ <cell align="left" valign="middle"><em></em></cell>
+ <cell align="left" valign="middle"><em>P</em></cell>
+ <cell align="left" valign="middle"><em>22</em></cell>
+ </row>
+
+ <row>
+ <cell align="left" valign="middle">
+ <url href="https://tools.ietf.org/html/rfc8446#section-C.4">
+ C.4. Client Tracking Prevention
+ </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>
+ </row>
+
+ <row>
+ <cell align="left" valign="middle">
+ <url href="https://tools.ietf.org/html/rfc8446#section-C.5">
+ C.5. Unauthenticated Operation
+ </url>
+ </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</em></cell>
+ </row>
+
+ <row>
+ <cell align="left" valign="middle">
+ <url href="https://tools.ietf.org/html/rfc8446#section-D.1">
+ D.1. Negotiating with an Older Server
+ </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>
+ </row>
+
+ <row>
+ <cell align="left" valign="middle">
+ <url href="https://tools.ietf.org/html/rfc8446#section-D.2">
+ D.2. Negotiating with an Older Client
+ </url>
+ </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</em></cell>
+ </row>
+
+ <row>
+ <cell align="left" valign="middle">
+ <url href="https://tools.ietf.org/html/rfc8446#section-D.3">
+ D.3. 0-RTT Backward Compatibility
+ </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>
+ </row>
+
+ <row>
+ <cell align="left" valign="middle">
+ <url href="https://tools.ietf.org/html/rfc8446#section-D.4">
+ D.4. Middlebox Compatibility Mode
+ </url>
+ </cell>
+ <cell align="left" valign="middle"><em></em></cell>
+ <cell align="left" valign="middle"><em>P</em></cell>
+ <cell align="left" valign="middle"><em>22</em></cell>
+ </row>
+
+ <row>
+ <cell align="left" valign="middle">
+ <url href="https://tools.ietf.org/html/rfc8446#section-D.5">
+ D.5. Security Restrictions Related to Backward Compatibility
+ </url>
+ </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</em></cell>
+ </row>
+
+ <tcaption>Standards Compliance</tcaption>
+ </table>
+
+ </section>
+
+</chapter>
diff --git a/lib/ssl/doc/src/usersguide.xml b/lib/ssl/doc/src/usersguide.xml
index 23ccf668c3..b22b2456e4 100644
--- a/lib/ssl/doc/src/usersguide.xml
+++ b/lib/ssl/doc/src/usersguide.xml
@@ -38,6 +38,7 @@
<xi:include href="ssl_protocol.xml"/>
<xi:include href="using_ssl.xml"/>
<xi:include href="ssl_distribution.xml"/>
+ <xi:include href="standards_compliance.xml"/>
</part>
diff --git a/lib/ssl/src/dtls_connection.erl b/lib/ssl/src/dtls_connection.erl
index 30b2ab7c4f..a6943af164 100644
--- a/lib/ssl/src/dtls_connection.erl
+++ b/lib/ssl/src/dtls_connection.erl
@@ -193,7 +193,8 @@ next_event(StateName, no_record,
%% TODO maybe buffer later epoch
next_event(StateName, no_record, State, Actions);
{#alert{} = Alert, State} ->
- {next_state, StateName, State, [{next_event, internal, Alert} | Actions]}
+ Version = State#state.connection_env#connection_env.negotiated_version,
+ handle_own_alert(Alert, Version, StateName, State)
end;
next_event(connection = StateName, Record,
#state{connection_states = #{current_read := #{epoch := CurrentEpoch}}} = State0, Actions) ->
@@ -233,7 +234,8 @@ next_event(StateName, Record,
%% TODO maybe buffer later epoch
next_event(StateName, no_record, State0, Actions);
#alert{} = Alert ->
- {next_state, StateName, State0, [{next_event, internal, Alert} | Actions]}
+ Version = State0#state.connection_env#connection_env.negotiated_version,
+ handle_own_alert(Alert, Version, StateName, State0)
end.
%%% DTLS record protocol level application data messages
diff --git a/lib/ssl/src/ssl.erl b/lib/ssl/src/ssl.erl
index c7c96370b3..8807c575b1 100644
--- a/lib/ssl/src/ssl.erl
+++ b/lib/ssl/src/ssl.erl
@@ -112,6 +112,10 @@
aes_256_cbc |
aes_128_gcm |
aes_256_gcm |
+ aes_128_ccm |
+ aes_256_ccm |
+ aes_128_ccm_8 |
+ aes_256_ccm_8 |
chacha20_poly1305 |
legacy_cipher().
-type legacy_cipher() :: rc4_128 |
diff --git a/lib/ssl/src/ssl_cipher.erl b/lib/ssl/src/ssl_cipher.erl
index fe8736d2df..97878431a6 100644
--- a/lib/ssl/src/ssl_cipher.erl
+++ b/lib/ssl/src/ssl_cipher.erl
@@ -35,7 +35,7 @@
-include_lib("public_key/include/public_key.hrl").
-export([security_parameters/2, security_parameters/3, security_parameters_1_3/2,
- cipher_init/3, nonce_seed/2, decipher/6, cipher/5, aead_encrypt/5, aead_decrypt/6,
+ cipher_init/3, nonce_seed/2, decipher/6, cipher/5, aead_encrypt/6, aead_decrypt/6,
suites/1, all_suites/1, crypto_support_filters/0,
chacha_suites/1, anonymous_suites/1, psk_suites/1, psk_suites_anon/1,
srp_suites/0, srp_suites_anon/0,
@@ -106,9 +106,13 @@ security_parameters_1_3(SecParams, CipherSuite) ->
cipher_init(?RC4, IV, Key) ->
State = crypto:stream_init(rc4, Key),
#cipher_state{iv = IV, key = Key, state = State};
-cipher_init(?AES_GCM, IV, Key) ->
+cipher_init(Type, IV, Key) when Type == ?AES_GCM;
+ Type == ?AES_CCM ->
<<Nonce:64>> = random_bytes(8),
#cipher_state{iv = IV, key = Key, nonce = Nonce, tag_len = 16};
+cipher_init(?AES_CCM_8, IV, Key) ->
+ <<Nonce:64>> = random_bytes(8),
+ #cipher_state{iv = IV, key = Key, nonce = Nonce, tag_len = 8};
cipher_init(?CHACHA20_POLY1305, IV, Key) ->
#cipher_state{iv = IV, key = Key, tag_len = 16};
cipher_init(_BCA, IV, Key) ->
@@ -148,14 +152,18 @@ cipher(?AES_CBC, CipherState, Mac, Fragment, Version) ->
crypto:block_encrypt(aes_cbc256, Key, IV, T)
end, block_size(aes_128_cbc), CipherState, Mac, Fragment, Version).
-aead_encrypt(Type, Key, Nonce, Fragment, AdditionalData) ->
- crypto:block_encrypt(aead_type(Type), Key, Nonce, {AdditionalData, Fragment}).
+aead_encrypt(Type, Key, Nonce, Fragment, AdditionalData, TagLen) ->
+ crypto:block_encrypt(aead_type(Type), Key, Nonce, {AdditionalData, Fragment, TagLen}).
aead_decrypt(Type, Key, Nonce, CipherText, CipherTag, AdditionalData) ->
crypto:block_decrypt(aead_type(Type), Key, Nonce, {AdditionalData, CipherText, CipherTag}).
aead_type(?AES_GCM) ->
aes_gcm;
+aead_type(?AES_CCM) ->
+ aes_ccm;
+aead_type(?AES_CCM_8) ->
+ aes_ccm;
aead_type(?CHACHA20_POLY1305) ->
chacha20_poly1305.
@@ -311,8 +319,7 @@ anonymous_suites({254, _} = Version) ->
dtls_v1:anonymous_suites(Version);
anonymous_suites(4) ->
[]; %% Raw public key negotiation may be used instead
-anonymous_suites(N)
- when N >= 3 ->
+anonymous_suites( 3 = N) ->
psk_suites_anon(N) ++
[?TLS_DH_anon_WITH_AES_128_GCM_SHA256,
?TLS_DH_anon_WITH_AES_256_GCM_SHA384,
@@ -347,8 +354,7 @@ psk_suites({3, N}) ->
psk_suites(N);
psk_suites(4) ->
[]; %% TODO Add new PSK, PSK_(EC)DHE suites
-psk_suites(N)
- when N >= 3 ->
+psk_suites(3) ->
[
?TLS_RSA_PSK_WITH_AES_256_GCM_SHA384,
?TLS_RSA_PSK_WITH_AES_256_CBC_SHA384,
@@ -369,20 +375,32 @@ psk_suites(_) ->
%%--------------------------------------------------------------------
psk_suites_anon({3, N}) ->
psk_suites_anon(N);
-psk_suites_anon(N)
- when N >= 3 ->
+psk_suites_anon(3) ->
[
?TLS_DHE_PSK_WITH_AES_256_GCM_SHA384,
?TLS_PSK_WITH_AES_256_GCM_SHA384,
?TLS_ECDHE_PSK_WITH_AES_256_CBC_SHA384,
?TLS_DHE_PSK_WITH_AES_256_CBC_SHA384,
?TLS_PSK_WITH_AES_256_CBC_SHA384,
+ ?TLS_DHE_PSK_WITH_AES_256_CCM,
+ ?TLS_PSK_DHE_WITH_AES_256_CCM_8,
+ ?TLS_PSK_WITH_AES_256_CCM,
+ ?TLS_PSK_WITH_AES_256_CCM_8,
?TLS_ECDHE_PSK_WITH_AES_128_GCM_SHA256,
+ ?TLS_ECDHE_PSK_WITH_AES_128_CCM_SHA256,
+ ?TLS_ECDHE_PSK_WITH_AES_128_CCM_8_SHA256,
?TLS_DHE_PSK_WITH_AES_128_GCM_SHA256,
?TLS_PSK_WITH_AES_128_GCM_SHA256,
+ ?TLS_ECDHE_PSK_WITH_AES_128_GCM_SHA256,
+ ?TLS_ECDHE_PSK_WITH_AES_128_CCM_8_SHA256,
?TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA256,
?TLS_DHE_PSK_WITH_AES_128_CBC_SHA256,
- ?TLS_PSK_WITH_AES_128_CBC_SHA256
+ ?TLS_PSK_WITH_AES_128_CBC_SHA256,
+ ?TLS_DHE_PSK_WITH_AES_128_CCM,
+ ?TLS_PSK_DHE_WITH_AES_128_CCM_8,
+ ?TLS_PSK_WITH_AES_128_CCM,
+ ?TLS_PSK_WITH_AES_128_CCM_8,
+ ?TLS_ECDHE_PSK_WITH_RC4_128_SHA
] ++ psk_suites_anon(0);
psk_suites_anon(_) ->
[?TLS_DHE_PSK_WITH_AES_256_CBC_SHA,
@@ -589,7 +607,7 @@ is_acceptable_keyexchange(dhe_rsa, Algos) ->
proplists:get_bool(dh, Algos) andalso
proplists:get_bool(rsa, Algos);
is_acceptable_keyexchange(KeyExchange, Algos) when KeyExchange == ecdh_anon;
- KeyExchange == ecdhe_psk ->
+ KeyExchange == ecdhe_psk ->
proplists:get_bool(ecdh, Algos);
is_acceptable_keyexchange(KeyExchange, Algos) when KeyExchange == ecdh_ecdsa;
KeyExchange == ecdhe_ecdsa ->
@@ -629,6 +647,12 @@ is_acceptable_cipher(Cipher, Algos)
when Cipher == aes_128_gcm;
Cipher == aes_256_gcm ->
proplists:get_bool(aes_gcm, Algos);
+is_acceptable_cipher(Cipher, Algos)
+ when Cipher == aes_128_ccm;
+ Cipher == aes_256_ccm;
+ Cipher == aes_128_ccm_8;
+ Cipher == aes_256_ccm_8 ->
+ proplists:get_bool(aes_ccm, Algos);
is_acceptable_cipher(Cipher, Algos) ->
proplists:get_bool(Cipher, Algos).
@@ -721,6 +745,12 @@ bulk_cipher_algorithm(Cipher) when Cipher == aes_128_cbc;
bulk_cipher_algorithm(Cipher) when Cipher == aes_128_gcm;
Cipher == aes_256_gcm ->
?AES_GCM;
+bulk_cipher_algorithm(Cipher) when Cipher == aes_128_ccm;
+ Cipher == aes_256_ccm ->
+ ?AES_CCM;
+bulk_cipher_algorithm(Cipher) when Cipher == aes_128_ccm_8;
+ Cipher == aes_256_ccm_8 ->
+ ?AES_CCM_8;
bulk_cipher_algorithm(chacha20_poly1305) ->
?CHACHA20_POLY1305.
@@ -735,6 +765,10 @@ type(Cipher) when Cipher == des_cbc;
?BLOCK;
type(Cipher) when Cipher == aes_128_gcm;
Cipher == aes_256_gcm;
+ Cipher == aes_128_ccm;
+ Cipher == aes_256_ccm;
+ Cipher == aes_128_ccm_8;
+ Cipher == aes_256_ccm_8;
Cipher == chacha20_poly1305 ->
?AEAD.
@@ -752,8 +786,16 @@ key_material(aes_256_cbc) ->
32;
key_material(aes_128_gcm) ->
16;
+key_material(aes_128_ccm) ->
+ 16;
+key_material(aes_128_ccm_8) ->
+ 16;
key_material(aes_256_gcm) ->
32;
+key_material(aes_256_ccm_8) ->
+ 32;
+key_material(aes_256_ccm) ->
+ 32;
key_material(chacha20_poly1305) ->
32.
@@ -769,6 +811,10 @@ expanded_key_material(Cipher) when Cipher == aes_128_cbc;
Cipher == aes_256_cbc;
Cipher == aes_128_gcm;
Cipher == aes_256_gcm;
+ Cipher == aes_128_ccm;
+ Cipher == aes_256_ccm;
+ Cipher == aes_128_ccm_8;
+ Cipher == aes_256_ccm_8;
Cipher == chacha20_poly1305 ->
unknown.
@@ -778,12 +824,16 @@ effective_key_bits(des_cbc) ->
56;
effective_key_bits(Cipher) when Cipher == rc4_128;
Cipher == aes_128_cbc;
- Cipher == aes_128_gcm ->
+ Cipher == aes_128_gcm;
+ Cipher == aes_128_ccm;
+ Cipher == aes_128_ccm_8 ->
128;
effective_key_bits('3des_ede_cbc') ->
168;
effective_key_bits(Cipher) when Cipher == aes_256_cbc;
Cipher == aes_256_gcm;
+ Cipher == aes_256_ccm;
+ Cipher == aes_256_ccm_8;
Cipher == chacha20_poly1305 ->
256.
@@ -792,7 +842,11 @@ iv_size(Cipher) when Cipher == null;
Cipher == chacha20_poly1305->
0;
iv_size(Cipher) when Cipher == aes_128_gcm;
- Cipher == aes_256_gcm ->
+ Cipher == aes_256_gcm;
+ Cipher == aes_128_ccm;
+ Cipher == aes_256_ccm;
+ Cipher == aes_128_ccm_8;
+ Cipher == aes_256_ccm_8 ->
4;
iv_size(Cipher) ->
block_size(Cipher).
@@ -804,6 +858,10 @@ block_size(Cipher) when Cipher == aes_128_cbc;
Cipher == aes_256_cbc;
Cipher == aes_128_gcm;
Cipher == aes_256_gcm;
+ Cipher == aes_128_ccm;
+ Cipher == aes_256_ccm;
+ Cipher == aes_128_ccm_8;
+ Cipher == aes_256_ccm_8;
Cipher == chacha20_poly1305 ->
16.
diff --git a/lib/ssl/src/ssl_cipher.hrl b/lib/ssl/src/ssl_cipher.hrl
index 00822ad9de..5d2f5e2951 100644
--- a/lib/ssl/src/ssl_cipher.hrl
+++ b/lib/ssl/src/ssl_cipher.hrl
@@ -612,6 +612,58 @@
%% TLS_DHE_RSA_WITH_CHACHA20_POLY1305_SHA256 = {0xcc, 0x15}
-define(TLS_DHE_RSA_WITH_CHACHA20_POLY1305_SHA256, <<?BYTE(16#CC), ?BYTE(16#15)>>).
+
+%% RFC 6655 - TLS-1.2 cipher suites
+
+%% TLS_RSA_WITH_AES_128_CCM = {0xC0,0x9C}
+-define(TLS_RSA_WITH_AES_128_CCM, <<?BYTE(16#C0), ?BYTE(16#9C)>>).
+
+%% TLS_RSA_WITH_AES_256_CCM = {0xC0,0x9D}
+-define(TLS_RSA_WITH_AES_256_CCM, <<?BYTE(16#C0), ?BYTE(16#9D)>>).
+
+%% TLS_DHE_RSA_WITH_AES_256_CCM = {0xC0,0x9E}
+-define(TLS_DHE_RSA_WITH_AES_256_CCM, <<?BYTE(16#C0), ?BYTE(16#9E)>>).
+
+%% TLS_DHE_RSA_WITH_AES_128_CCM = {0xC0,0x9F}
+-define(TLS_DHE_RSA_WITH_AES_128_CCM, <<?BYTE(16#C0), ?BYTE(16#9F)>>).
+
+%% TLS_RSA_WITH_AES_256_CCM_8 = {0xC0,0x9A0}
+-define(TLS_RSA_WITH_AES_256_CCM_8, <<?BYTE(16#C0), ?BYTE(16#A0)>>).
+
+%% TLS_RSA_WITH_AES_128_CCM_8 = {0xC0,0xA1}
+-define(TLS_RSA_WITH_AES_128_CCM_8, <<?BYTE(16#C0), ?BYTE(16#A1)>>).
+
+%% TLS_DHE_RSA_WITH_AES_128_CCM_8 = {0xC0,0xA2}
+-define(TLS_DHE_RSA_WITH_AES_128_CCM_8, <<?BYTE(16#C0), ?BYTE(16#A2)>>).
+
+%% TLS_DHE_RSA_WITH_AES_256_CCM_8 = {0xC0,0xA3}
+-define(TLS_DHE_RSA_WITH_AES_256_CCM_8, <<?BYTE(16#C0), ?BYTE(16#A3)>>).
+
+%% TLS_PSK_WITH_AES_128_CCM = {0xC0,0xA4}
+-define(TLS_PSK_WITH_AES_128_CCM, <<?BYTE(16#C0), ?BYTE(16#A4)>>).
+
+%% TLS_PSK_WITH_AES_256_CCM = {0xC0,0xA5)
+-define(TLS_PSK_WITH_AES_256_CCM, <<?BYTE(16#C0), ?BYTE(16#A5)>>).
+
+%% TLS_DHE_PSK_WITH_AES_128_CCM = {0xC0,0xA6}
+-define(TLS_DHE_PSK_WITH_AES_128_CCM, <<?BYTE(16#C0), ?BYTE(16#A6)>>).
+
+%% TLS_DHE_PSK_WITH_AES_256_CCM = {0xC0,0xA7}
+-define(TLS_DHE_PSK_WITH_AES_256_CCM, <<?BYTE(16#C0), ?BYTE(16#A7)>>).
+
+%% TLS_PSK_WITH_AES_128_CCM_8 = {0xC0,0xA8}
+-define(TLS_PSK_WITH_AES_128_CCM_8, <<?BYTE(16#C0), ?BYTE(16#A8)>>).
+
+%% TLS_PSK_WITH_AES_256_CCM_8 = {0xC0,0xA9)
+-define(TLS_PSK_WITH_AES_256_CCM_8, <<?BYTE(16#C0), ?BYTE(16#A9)>>).
+
+%% TLS_PSK_DHE_WITH_AES_128_CCM_8 = {0xC0,0xAA}
+-define(TLS_PSK_DHE_WITH_AES_128_CCM_8, <<?BYTE(16#C0), ?BYTE(16#AA)>>).
+
+%% TLS_PSK_DHE_WITH_AES_256_CCM_8 = << ?BYTE(0xC0,0xAB}
+-define(TLS_PSK_DHE_WITH_AES_256_CCM_8, <<?BYTE(16#C0),?BYTE(16#AB)>>).
+
+
%%% TLS 1.3 cipher suites RFC8446
%% TLS_AES_128_GCM_SHA256 = {0x13,0x01}
diff --git a/lib/ssl/src/ssl_cipher_format.erl b/lib/ssl/src/ssl_cipher_format.erl
index b592295d56..8737181922 100644
--- a/lib/ssl/src/ssl_cipher_format.erl
+++ b/lib/ssl/src/ssl_cipher_format.erl
@@ -467,16 +467,16 @@ suite_definition(?TLS_ECDHE_PSK_WITH_AES_256_GCM_SHA384) ->
cipher => aes_256_gcm,
mac => null,
prf => sha384};
-%% suite_definition(?TLS_ECDHE_PSK_WITH_AES_128_CCM_8_SHA256) ->
-%% #{key_exchange => ecdhe_psk,
-%% cipher => aes_128_ccm,
-%% mac => null,
-%% prf =>sha256};
-%% suite_definition(?TLS_ECDHE_PSK_WITH_AES_128_CCM_SHA256) ->
-%% #{key_exchange => ecdhe_psk,
-%% cipher => aes_256_ccm,
-%% mac => null,
-%% prf => sha256};
+suite_definition(?TLS_ECDHE_PSK_WITH_AES_128_CCM_SHA256) ->
+ #{key_exchange => ecdhe_psk,
+ cipher => aes_128_ccm,
+ mac => null,
+ prf =>sha256};
+suite_definition(?TLS_ECDHE_PSK_WITH_AES_128_CCM_8_SHA256) ->
+ #{key_exchange => ecdhe_psk,
+ cipher => aes_128_ccm_8,
+ mac => null,
+ prf =>sha256};
%%% SRP Cipher Suites RFC 5054
suite_definition(?TLS_SRP_SHA_WITH_3DES_EDE_CBC_SHA) ->
#{key_exchange => srp_anon,
@@ -792,7 +792,53 @@ suite_definition(?TLS_ECDH_RSA_WITH_AES_256_GCM_SHA384) ->
cipher => aes_256_gcm,
mac => aead,
prf => sha384};
-%% draft-agl-tls-chacha20poly1305-04 Chacha20/Poly1305 Suites
+suite_definition(?TLS_PSK_WITH_AES_128_CCM) ->
+ #{key_exchange => psk,
+ cipher => aes_128_ccm,
+ mac => aead,
+ prf => sha256};
+suite_definition(?TLS_PSK_WITH_AES_256_CCM) ->
+ #{key_exchange => psk,
+ cipher => aes_256_ccm,
+ mac => aead,
+ prf => sha256};
+suite_definition(?TLS_DHE_PSK_WITH_AES_128_CCM) ->
+ #{key_exchange => dhe_psk,
+ cipher => aes_128_ccm,
+ mac => aead,
+ prf => sha256};
+suite_definition(?TLS_DHE_PSK_WITH_AES_256_CCM) ->
+ #{key_exchange => dhe_psk,
+ cipher => aes_256_ccm,
+ mac => aead,
+ prf => sha256};
+suite_definition(?TLS_PSK_WITH_AES_128_CCM_8) ->
+ #{key_exchange => psk,
+ cipher => aes_128_ccm_8,
+ mac => aead,
+ prf => sha256};
+suite_definition(?TLS_PSK_WITH_AES_256_CCM_8) ->
+ #{key_exchange => psk,
+ cipher => aes_256_ccm_8,
+ mac => aead,
+ prf => sha256};
+suite_definition(?TLS_PSK_DHE_WITH_AES_128_CCM_8) ->
+ #{key_exchange => dhe_psk,
+ cipher => aes_128_ccm_8,
+ mac => aead,
+ prf => sha256};
+suite_definition(?TLS_PSK_DHE_WITH_AES_256_CCM_8) ->
+ #{key_exchange => dhe_psk,
+ cipher => aes_256_ccm_8,
+ mac => aead,
+ prf => sha256};
+suite_definition(#{key_exchange := psk_dhe,
+ cipher := aes_256_ccm_8,
+ mac := aead,
+ prf := sha256}) ->
+ ?TLS_PSK_DHE_WITH_AES_256_CCM_8;
+
+% draft-agl-tls-chacha20poly1305-04 Chacha20/Poly1305 Suites
suite_definition(?TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256) ->
#{key_exchange => ecdhe_rsa,
cipher => chacha20_poly1305,
@@ -825,16 +871,15 @@ suite_definition(?TLS_CHACHA20_POLY1305_SHA256) ->
mac => aead,
prf => sha256}.
%% suite_definition(?TLS_AES_128_CCM_SHA256) ->
-%% #{key_exchange => any,
-%% cipher => aes_128_ccm,
-%% mac => aead,
-%% prf => sha256};
+%% #{key_exchange => any,
+%% cipher => aes_128_ccm,
+%% mac => aead,
+%% prf => sha256};
%% suite_definition(?TLS_AES_128_CCM_8_SHA256) ->
-%% #{key_exchange => any,
+%% #{key_exchange => any,
%% cipher => aes_128_ccm_8,
-%% mac => aead,
-%% prf => sha256}.
-
+%% mac => aead,
+%% prf => sha256}.
%%--------------------------------------------------------------------
-spec erl_suite_definition(cipher_suite() | internal_erl_cipher_suite()) -> old_erl_cipher_suite().
@@ -1154,16 +1199,16 @@ suite(#{key_exchange := ecdhe_psk,
mac := null,
prf := sha384}) ->
?TLS_ECDHE_PSK_WITH_AES_256_GCM_SHA384;
- %% suite(#{key_exchange := ecdhe_psk,
- %% cipher := aes_128_ccm,
- %% mac := null,
- %% prf := sha256}) ->
- %% ?TLS_ECDHE_PSK_WITH_AES_128_CCM_8_SHA256;
- %% suite(#{key_exchange := ecdhe_psk,
- %% cipher := aes_256_ccm,
- %% mac := null,
- %% prf := sha256}) ->
- %% ?TLS_ECDHE_PSK_WITH_AES_128_CCM_SHA256;
+suite(#{key_exchange := ecdhe_psk,
+ cipher := aes_128_ccm_8,
+ mac := null,
+ prf := sha256}) ->
+ ?TLS_ECDHE_PSK_WITH_AES_128_CCM_8_SHA256;
+suite(#{key_exchange := ecdhe_psk,
+ cipher := aes_128_ccm,
+ mac := null,
+ prf := sha256}) ->
+ ?TLS_ECDHE_PSK_WITH_AES_128_CCM_SHA256;
%%% SRP Cipher Suites RFC 5054
suite(#{key_exchange := srp_anon,
cipher := '3des_ede_cbc',
@@ -1460,6 +1505,90 @@ suite(#{key_exchange := dhe_rsa,
mac := aead,
prf := sha256}) ->
?TLS_DHE_RSA_WITH_CHACHA20_POLY1305_SHA256;
+
+%% RFC 6655 - TLS-1.2 cipher suites
+suite(#{key_exchange := psk,
+ cipher := aes_128_ccm,
+ mac := aead,
+ prf := sha256}) ->
+ ?TLS_PSK_WITH_AES_128_CCM;
+suite(#{key_exchange := psk,
+ cipher := aes_256_ccm,
+ mac := aead,
+ prf := sha256}) ->
+ ?TLS_PSK_WITH_AES_256_CCM;
+suite(#{key_exchange := dhe_psk,
+ cipher := aes_128_ccm,
+ mac := aead,
+ prf := sha256}) ->
+ ?TLS_DHE_PSK_WITH_AES_128_CCM;
+suite(#{key_exchange := dhe_psk,
+ cipher := aes_256_ccm,
+ mac := aead,
+ prf := sha256}) ->
+ ?TLS_DHE_PSK_WITH_AES_256_CCM;
+suite(#{key_exchange := rsa,
+ cipher := aes_128_ccm,
+ mac := aead,
+ prf := sha256}) ->
+ ?TLS_RSA_WITH_AES_128_CCM;
+suite(#{key_exchange := rsa,
+ cipher := aes_256_ccm,
+ mac := aead,
+ prf := sha256}) ->
+ ?TLS_RSA_WITH_AES_256_CCM;
+suite(#{key_exchange := dhe_rsa,
+ cipher := aes_128_ccm,
+ mac := aead,
+ prf := sha256}) ->
+ ?TLS_DHE_RSA_WITH_AES_128_CCM;
+suite(#{key_exchange := dhe_rsa,
+ cipher := aes_256_ccm,
+ mac := aead,
+ prf := sha256}) ->
+ ?TLS_DHE_RSA_WITH_AES_256_CCM;
+
+suite(#{key_exchange := psk,
+ cipher := aes_128_ccm_8,
+ mac := aead,
+ prf := sha256}) ->
+ ?TLS_PSK_WITH_AES_128_CCM_8;
+suite(#{key_exchange := psk,
+ cipher := aes_256_ccm_8,
+ mac := aead,
+ prf := sha256}) ->
+ ?TLS_PSK_WITH_AES_256_CCM_8;
+suite(#{key_exchange := dhe_psk,
+ cipher := aes_128_ccm_8,
+ mac := aead,
+ prf := sha256}) ->
+ ?TLS_PSK_DHE_WITH_AES_128_CCM_8;
+suite(#{key_exchange := dhe_psk,
+ cipher := aes_256_ccm_8,
+ mac := aead,
+ prf := sha256}) ->
+ ?TLS_PSK_DHE_WITH_AES_256_CCM_8;
+suite(#{key_exchange := rsa,
+ cipher := aes_128_ccm_8,
+ mac := aead,
+ prf := sha256}) ->
+ ?TLS_RSA_WITH_AES_128_CCM_8;
+suite(#{key_exchange := rsa,
+ cipher := aes_256_ccm_8,
+ mac := aead,
+ prf := sha256}) ->
+ ?TLS_RSA_WITH_AES_256_CCM_8;
+suite(#{key_exchange := dhe_rsa,
+ cipher := aes_128_ccm_8,
+ mac := aead,
+ prf := sha256}) ->
+ ?TLS_DHE_RSA_WITH_AES_128_CCM_8;
+suite(#{key_exchange := dhe_rsa,
+ cipher := aes_256_ccm_8,
+ mac := aead,
+ prf := sha256}) ->
+ ?TLS_DHE_RSA_WITH_AES_256_CCM_8;
+
%% TLS 1.3 Cipher Suites RFC8446
suite(#{key_exchange := any,
cipher := aes_128_gcm,
diff --git a/lib/ssl/src/ssl_record.erl b/lib/ssl/src/ssl_record.erl
index 91f1876980..9cc131c3cb 100644
--- a/lib/ssl/src/ssl_record.erl
+++ b/lib/ssl/src/ssl_record.erl
@@ -471,34 +471,41 @@ initial_security_params(ConnectionEnd) ->
-define(end_additional_data(AAD, Len), << (begin(AAD)end)/binary, ?UINT16(begin(Len)end) >>).
-do_cipher_aead(?CHACHA20_POLY1305 = Type, Fragment, #cipher_state{key=Key} = CipherState, AAD0) ->
+do_cipher_aead(?CHACHA20_POLY1305 = Type, Fragment, #cipher_state{key=Key, tag_len = TagLen} = CipherState, AAD0) ->
AAD = ?end_additional_data(AAD0, erlang:iolist_size(Fragment)),
Nonce = encrypt_nonce(Type, CipherState),
- {Content, CipherTag} = ssl_cipher:aead_encrypt(Type, Key, Nonce, Fragment, AAD),
+ {Content, CipherTag} = ssl_cipher:aead_encrypt(Type, Key, Nonce, Fragment, AAD, TagLen),
{<<Content/binary, CipherTag/binary>>, CipherState};
-do_cipher_aead(Type, Fragment, #cipher_state{key=Key, nonce = ExplicitNonce} = CipherState, AAD0) ->
+do_cipher_aead(Type, Fragment, #cipher_state{key=Key, tag_len = TagLen, nonce = ExplicitNonce} = CipherState, AAD0) ->
AAD = ?end_additional_data(AAD0, erlang:iolist_size(Fragment)),
Nonce = encrypt_nonce(Type, CipherState),
- {Content, CipherTag} = ssl_cipher:aead_encrypt(Type, Key, Nonce, Fragment, AAD),
+ {Content, CipherTag} = ssl_cipher:aead_encrypt(Type, Key, Nonce, Fragment, AAD, TagLen),
{<<ExplicitNonce:64/integer, Content/binary, CipherTag/binary>>, CipherState#cipher_state{nonce = ExplicitNonce + 1}}.
encrypt_nonce(?CHACHA20_POLY1305, #cipher_state{nonce = Nonce, iv = IV}) ->
crypto:exor(<<?UINT32(0), Nonce/binary>>, IV);
-encrypt_nonce(?AES_GCM, #cipher_state{iv = IV, nonce = ExplicitNonce}) ->
+encrypt_nonce(Type, #cipher_state{iv = IV, nonce = ExplicitNonce}) when Type == ?AES_GCM;
+ Type == ?AES_CCM;
+ Type == ?AES_CCM_8 ->
<<Salt:4/bytes, _/binary>> = IV,
<<Salt/binary, ExplicitNonce:64/integer>>.
decrypt_nonce(?CHACHA20_POLY1305, #cipher_state{nonce = Nonce, iv = IV}, _) ->
crypto:exor(<<Nonce:96/unsigned-big-integer>>, IV);
-decrypt_nonce(?AES_GCM, #cipher_state{iv = <<Salt:4/bytes, _/binary>>}, <<ExplicitNonce:8/bytes, _/binary>>) ->
- <<Salt/binary, ExplicitNonce/binary>>.
+decrypt_nonce(Type, #cipher_state{iv = <<Salt:4/bytes, _/binary>>}, <<ExplicitNonce:8/bytes, _/binary>>) when
+ Type == ?AES_GCM;
+ Type == ?AES_CCM;
+ Type == ?AES_CCM_8 ->
+ <<Salt/binary, ExplicitNonce/binary>>.
-compile({inline, [aead_ciphertext_split/4]}).
aead_ciphertext_split(?CHACHA20_POLY1305, #cipher_state{tag_len = Len}, CipherTextFragment, AAD) ->
CipherLen = byte_size(CipherTextFragment) - Len,
<<CipherText:CipherLen/bytes, CipherTag:Len/bytes>> = CipherTextFragment,
{?end_additional_data(AAD, CipherLen), CipherText, CipherTag};
-aead_ciphertext_split(?AES_GCM, #cipher_state{tag_len = Len}, CipherTextFragment, AAD) ->
+aead_ciphertext_split(Type, #cipher_state{tag_len = Len}, CipherTextFragment, AAD) when Type == ?AES_GCM;
+ Type == ?AES_CCM;
+ Type == ?AES_CCM_8 ->
CipherLen = byte_size(CipherTextFragment) - (Len + 8), %% 8 is length of explicit Nonce
<< _:8/bytes, CipherText:CipherLen/bytes, CipherTag:Len/bytes>> = CipherTextFragment,
{?end_additional_data(AAD, CipherLen), CipherText, CipherTag}.
diff --git a/lib/ssl/src/ssl_record.hrl b/lib/ssl/src/ssl_record.hrl
index eb718fd20c..6d4d47cedb 100644
--- a/lib/ssl/src/ssl_record.hrl
+++ b/lib/ssl/src/ssl_record.hrl
@@ -96,6 +96,11 @@
-define(AES_CBC, 7).
-define(AES_GCM, 8).
-define(CHACHA20_POLY1305, 9).
+%% Following two are not defined in any RFC but we want to have the
+%% same type of handling internaly, all of these "bulk_cipher_algorithm"
+%% enums are only used internaly anyway.
+-define(AES_CCM, 10).
+-define(AES_CCM_8, 11).
%% CipherType
-define(STREAM, 0).
diff --git a/lib/ssl/src/tls_connection.erl b/lib/ssl/src/tls_connection.erl
index fde73cdef1..a05858221a 100644
--- a/lib/ssl/src/tls_connection.erl
+++ b/lib/ssl/src/tls_connection.erl
@@ -934,7 +934,7 @@ wait_sh(Type, Event, State) ->
callback_mode() ->
state_functions.
-terminate({shutdown, sender_died, Reason}, _StateName,
+terminate({shutdown, {sender_died, Reason}}, _StateName,
#state{static_env = #static_env{socket = Socket,
transport_cb = Transport}}
= State) ->
@@ -1119,7 +1119,7 @@ handle_info({CloseTag, Socket}, StateName,
end;
handle_info({'EXIT', Sender, Reason}, _,
#state{protocol_specific = #{sender := Sender}} = State) ->
- {stop, {shutdown, sender_died, Reason}, State};
+ {stop, {shutdown, {sender_died, Reason}}, State};
handle_info(Msg, StateName, State) ->
ssl_connection:StateName(info, Msg, State, ?MODULE).
diff --git a/lib/ssl/src/tls_record_1_3.erl b/lib/ssl/src/tls_record_1_3.erl
index 97331e1510..74321a1ae2 100644
--- a/lib/ssl/src/tls_record_1_3.erl
+++ b/lib/ssl/src/tls_record_1_3.erl
@@ -252,7 +252,7 @@ cipher_aead(Fragment, BulkCipherAlgo, Key, Seq, IV, TagLen) ->
AAD = additional_data(erlang:iolist_size(Fragment) + TagLen),
Nonce = nonce(Seq, IV),
{Content, CipherTag} =
- ssl_cipher:aead_encrypt(BulkCipherAlgo, Key, Nonce, Fragment, AAD),
+ ssl_cipher:aead_encrypt(BulkCipherAlgo, Key, Nonce, Fragment, AAD, TagLen),
<<Content/binary, CipherTag/binary>>.
encode_tls_cipher_text(#tls_cipher_text{opaque_type = Type,
diff --git a/lib/ssl/test/Makefile b/lib/ssl/test/Makefile
index 57b74115ed..fc483b0a94 100644
--- a/lib/ssl/test/Makefile
+++ b/lib/ssl/test/Makefile
@@ -43,6 +43,7 @@ MODULES = \
ssl_basic_SUITE \
ssl_bench_SUITE \
ssl_cipher_SUITE \
+ ssl_cipher_suite_SUITE \
ssl_certificate_verify_SUITE\
ssl_crl_SUITE\
ssl_dist_SUITE \
diff --git a/lib/ssl/test/ssl_basic_SUITE.erl b/lib/ssl/test/ssl_basic_SUITE.erl
index 41a502b846..03ee97de5d 100644
--- a/lib/ssl/test/ssl_basic_SUITE.erl
+++ b/lib/ssl/test/ssl_basic_SUITE.erl
@@ -76,11 +76,9 @@ groups() ->
{'sslv3', [], all_versions_groups() ++ tls_versions_groups() ++ rizzo_tests() ++ [tls_ciphersuite_vs_version]},
{api,[], api_tests()},
{api_tls,[], api_tests_tls()},
- {tls_ciphers,[], tls_cipher_tests()},
{session, [], session_tests()},
{renegotiate, [], renegotiate_tests()},
{ciphers, [], cipher_tests()},
- {ciphers_ec, [], cipher_tests_ec()},
{error_handling_tests, [], error_handling_tests()},
{error_handling_tests_tls, [], error_handling_tests_tls()}
].
@@ -88,14 +86,12 @@ groups() ->
tls_versions_groups ()->
[
{group, api_tls},
- {group, tls_ciphers},
{group, error_handling_tests_tls}].
all_versions_groups ()->
[{group, api},
{group, renegotiate},
{group, ciphers},
- {group, ciphers_ec},
{group, error_handling_tests}].
@@ -211,38 +207,11 @@ renegotiate_tests() ->
renegotiate_dos_mitigate_passive,
renegotiate_dos_mitigate_absolute].
-tls_cipher_tests() ->
- [rc4_rsa_cipher_suites,
- rc4_ecdh_rsa_cipher_suites,
- rc4_ecdsa_cipher_suites].
-
cipher_tests() ->
[old_cipher_suites,
- cipher_suites_mix,
- ciphers_rsa_signed_certs,
- ciphers_rsa_signed_certs_openssl_names,
- ciphers_dsa_signed_certs,
- ciphers_dsa_signed_certs_openssl_names,
- chacha_rsa_cipher_suites,
- chacha_ecdsa_cipher_suites,
- anonymous_cipher_suites,
- psk_cipher_suites,
- psk_with_hint_cipher_suites,
- psk_anon_cipher_suites,
- psk_anon_with_hint_cipher_suites,
- srp_cipher_suites,
- srp_anon_cipher_suites,
- srp_dsa_cipher_suites,
- des_rsa_cipher_suites,
- des_ecdh_rsa_cipher_suites,
+ cipher_suites_mix,
default_reject_anonymous].
-cipher_tests_ec() ->
- [ciphers_ecdsa_signed_certs,
- ciphers_ecdsa_signed_certs_openssl_names,
- ciphers_ecdh_rsa_signed_certs,
- ciphers_ecdh_rsa_signed_certs_openssl_names].
-
error_handling_tests()->
[close_transport_accept,
recv_active,
@@ -410,26 +379,7 @@ init_per_testcase(TestCase, Config) when TestCase == client_renegotiate;
ct:timetrap({seconds, ?SEC_RENEGOTIATION_TIMEOUT + 5}),
Config;
-init_per_testcase(TestCase, Config) when TestCase == psk_cipher_suites;
- TestCase == psk_with_hint_cipher_suites;
- TestCase == ciphers_rsa_signed_certs;
- TestCase == ciphers_rsa_signed_certs_openssl_names;
- TestCase == ciphers_ecdh_rsa_signed_certs_openssl_names;
- TestCase == ciphers_ecdh_rsa_signed_certs;
- TestCase == ciphers_dsa_signed_certs;
- TestCase == ciphers_dsa_signed_certs_openssl_names;
- TestCase == anonymous_cipher_suites;
- TestCase == ciphers_ecdsa_signed_certs;
- TestCase == ciphers_ecdsa_signed_certs_openssl_names;
- TestCase == anonymous_cipher_suites;
- TestCase == psk_anon_cipher_suites;
- TestCase == psk_anon_with_hint_cipher_suites;
- TestCase == srp_cipher_suites;
- TestCase == srp_anon_cipher_suites;
- TestCase == srp_dsa_cipher_suites;
- TestCase == des_rsa_cipher_suites;
- TestCase == des_ecdh_rsa_cipher_suites;
- TestCase == versions_option;
+init_per_testcase(TestCase, Config) when TestCase == versions_option;
TestCase == tls_tcp_connect_big ->
ssl_test_lib:ct_log_supported_protocol_versions(Config),
ct:timetrap({seconds, 60}),
@@ -2709,144 +2659,6 @@ tls_shutdown_error(Config) when is_list(Config) ->
ok = ssl:close(Listen),
{error, closed} = ssl:shutdown(Listen, read_write).
-%%-------------------------------------------------------------------
-ciphers_rsa_signed_certs() ->
- [{doc,"Test all rsa ssl cipher suites in highest support ssl/tls version"}].
-
-ciphers_rsa_signed_certs(Config) when is_list(Config) ->
- Ciphers = ssl_test_lib:rsa_suites(crypto),
- run_suites(Ciphers, Config, rsa).
-%%-------------------------------------------------------------------
-ciphers_rsa_signed_certs_openssl_names() ->
- [{doc,"Test all rsa ssl cipher suites in highest support ssl/tls version"}].
-
-ciphers_rsa_signed_certs_openssl_names(Config) when is_list(Config) ->
- Ciphers = ssl_test_lib:openssl_rsa_suites(),
- run_suites(Ciphers, Config, rsa).
-
-%%-------------------------------------------------------------------
-ciphers_dsa_signed_certs() ->
- [{doc,"Test all dsa ssl cipher suites in highest support ssl/tls version"}].
-
-ciphers_dsa_signed_certs(Config) when is_list(Config) ->
- NVersion = ssl_test_lib:protocol_version(Config, tuple),
- Ciphers = ssl_test_lib:dsa_suites(NVersion),
- run_suites(Ciphers, Config, dsa).
-%%-------------------------------------------------------------------
-ciphers_dsa_signed_certs_openssl_names() ->
- [{doc,"Test all dsa ssl cipher suites in highest support ssl/tls version"}].
-
-ciphers_dsa_signed_certs_openssl_names(Config) when is_list(Config) ->
- Ciphers = ssl_test_lib:openssl_dsa_suites(),
- run_suites(Ciphers, Config, dsa).
-
-%%-------------------------------------------------------------------
-chacha_rsa_cipher_suites()->
- [{doc,"Test the cacha with ECDSA signed certs ciphersuites"}].
-chacha_rsa_cipher_suites(Config) when is_list(Config) ->
- NVersion = ssl_test_lib:protocol_version(Config, tuple),
- Ciphers = [S || {KeyEx,_,_} = S <- ssl_test_lib:chacha_suites(NVersion),
- KeyEx == ecdhe_rsa, KeyEx == dhe_rsa],
- run_suites(Ciphers, Config, chacha_ecdsa).
-
-%%-------------------------------------------------------------------
-chacha_ecdsa_cipher_suites()->
- [{doc,"Test the cacha with ECDSA signed certs ciphersuites"}].
-chacha_ecdsa_cipher_suites(Config) when is_list(Config) ->
- NVersion = ssl_test_lib:protocol_version(Config, tuple),
- Ciphers = [S || {ecdhe_ecdsa,_,_} = S <- ssl_test_lib:chacha_suites(NVersion)],
- run_suites(Ciphers, Config, chacha_rsa).
-%%-----------------------------------------------------------------
-anonymous_cipher_suites()->
- [{doc,"Test the anonymous ciphersuites"}].
-anonymous_cipher_suites(Config) when is_list(Config) ->
- NVersion = ssl_test_lib:protocol_version(Config, tuple),
- Ciphers = ssl_test_lib:ecdh_dh_anonymous_suites(NVersion),
- run_suites(Ciphers, Config, anonymous).
-%%-------------------------------------------------------------------
-psk_cipher_suites() ->
- [{doc, "Test the PSK ciphersuites WITHOUT server supplied identity hint"}].
-psk_cipher_suites(Config) when is_list(Config) ->
- NVersion = ssl_test_lib:protocol_version(Config, tuple),
- Ciphers = ssl_test_lib:psk_suites(NVersion),
- run_suites(Ciphers, Config, psk).
-%%-------------------------------------------------------------------
-psk_with_hint_cipher_suites()->
- [{doc, "Test the PSK ciphersuites WITH server supplied identity hint"}].
-psk_with_hint_cipher_suites(Config) when is_list(Config) ->
- NVersion = ssl_test_lib:protocol_version(Config, tuple),
- Ciphers = ssl_test_lib:psk_suites(NVersion),
- run_suites(Ciphers, Config, psk_with_hint).
-%%-------------------------------------------------------------------
-psk_anon_cipher_suites() ->
- [{doc, "Test the anonymous PSK ciphersuites WITHOUT server supplied identity hint"}].
-psk_anon_cipher_suites(Config) when is_list(Config) ->
- NVersion = ssl_test_lib:protocol_version(Config, tuple),
- Ciphers = ssl_test_lib:psk_anon_suites(NVersion),
- run_suites(Ciphers, Config, psk_anon).
-%%-------------------------------------------------------------------
-psk_anon_with_hint_cipher_suites()->
- [{doc, "Test the anonymous PSK ciphersuites WITH server supplied identity hint"}].
-psk_anon_with_hint_cipher_suites(Config) when is_list(Config) ->
- NVersion = ssl_test_lib:protocol_version(Config, tuple),
- Ciphers = ssl_test_lib:psk_anon_suites(NVersion),
- run_suites(Ciphers, Config, psk_anon_with_hint).
-%%-------------------------------------------------------------------
-srp_cipher_suites()->
- [{doc, "Test the SRP ciphersuites"}].
-srp_cipher_suites(Config) when is_list(Config) ->
- Ciphers = ssl_test_lib:srp_suites(),
- run_suites(Ciphers, Config, srp).
-%%-------------------------------------------------------------------
-srp_anon_cipher_suites()->
- [{doc, "Test the anonymous SRP ciphersuites"}].
-srp_anon_cipher_suites(Config) when is_list(Config) ->
- Ciphers = ssl_test_lib:srp_anon_suites(),
- run_suites(Ciphers, Config, srp_anon).
-%%-------------------------------------------------------------------
-srp_dsa_cipher_suites()->
- [{doc, "Test the SRP DSA ciphersuites"}].
-srp_dsa_cipher_suites(Config) when is_list(Config) ->
- Ciphers = ssl_test_lib:srp_dss_suites(),
- run_suites(Ciphers, Config, srp_dsa).
-%%-------------------------------------------------------------------
-rc4_rsa_cipher_suites()->
- [{doc, "Test the RC4 ciphersuites"}].
-rc4_rsa_cipher_suites(Config) when is_list(Config) ->
- NVersion = ssl_test_lib:protocol_version(Config, tuple),
- Ciphers = [S || {rsa,_,_} = S <- ssl_test_lib:rc4_suites(NVersion)],
- run_suites(Ciphers, Config, rc4_rsa).
-%-------------------------------------------------------------------
-rc4_ecdh_rsa_cipher_suites()->
- [{doc, "Test the RC4 ciphersuites"}].
-rc4_ecdh_rsa_cipher_suites(Config) when is_list(Config) ->
- NVersion = ssl_test_lib:protocol_version(Config, tuple),
- Ciphers = [S || {ecdh_rsa,_,_} = S <- ssl_test_lib:rc4_suites(NVersion)],
- run_suites(Ciphers, Config, rc4_ecdh_rsa).
-
-%%-------------------------------------------------------------------
-rc4_ecdsa_cipher_suites()->
- [{doc, "Test the RC4 ciphersuites"}].
-rc4_ecdsa_cipher_suites(Config) when is_list(Config) ->
- NVersion = tls_record:highest_protocol_version([]),
- Ciphers = [S || {ecdhe_ecdsa,_,_} = S <- ssl_test_lib:rc4_suites(NVersion)],
- run_suites(Ciphers, Config, rc4_ecdsa).
-
-%%-------------------------------------------------------------------
-des_rsa_cipher_suites()->
- [{doc, "Test the des_rsa ciphersuites"}].
-des_rsa_cipher_suites(Config) when is_list(Config) ->
- NVersion = tls_record:highest_protocol_version([]),
- Ciphers = [S || {rsa,_,_} = S <- ssl_test_lib:des_suites(NVersion)],
- run_suites(Ciphers, Config, des_rsa).
-%-------------------------------------------------------------------
-des_ecdh_rsa_cipher_suites()->
- [{doc, "Test ECDH rsa signed ciphersuites"}].
-des_ecdh_rsa_cipher_suites(Config) when is_list(Config) ->
- NVersion = ssl_test_lib:protocol_version(Config, tuple),
- Ciphers = [S || {dhe_rsa,_,_} = S <- ssl_test_lib:des_suites(NVersion)],
- run_suites(Ciphers, Config, des_dhe_rsa).
-
%%--------------------------------------------------------------------
default_reject_anonymous()->
[{doc,"Test that by default anonymous cipher suites are rejected "}].
@@ -2873,36 +2685,6 @@ default_reject_anonymous(Config) when is_list(Config) ->
ssl_test_lib:check_server_alert(Server, Client, insufficient_security).
%%--------------------------------------------------------------------
-ciphers_ecdsa_signed_certs() ->
- [{doc, "Test all ecdsa ssl cipher suites in highest support ssl/tls version"}].
-
-ciphers_ecdsa_signed_certs(Config) when is_list(Config) ->
- NVersion = ssl_test_lib:protocol_version(Config, tuple),
- Ciphers = ssl_test_lib:ecdsa_suites(NVersion),
- run_suites(Ciphers, Config, ecdsa).
-%%--------------------------------------------------------------------
-ciphers_ecdsa_signed_certs_openssl_names() ->
- [{doc, "Test all ecdsa ssl cipher suites in highest support ssl/tls version"}].
-
-ciphers_ecdsa_signed_certs_openssl_names(Config) when is_list(Config) ->
- Ciphers = ssl_test_lib:openssl_ecdsa_suites(),
- run_suites(Ciphers, Config, ecdsa).
-%%--------------------------------------------------------------------
-ciphers_ecdh_rsa_signed_certs() ->
- [{doc, "Test all ecdh_rsa ssl cipher suites in highest support ssl/tls version"}].
-
-ciphers_ecdh_rsa_signed_certs(Config) when is_list(Config) ->
- NVersion = ssl_test_lib:protocol_version(Config, tuple),
- Ciphers = ssl_test_lib:ecdh_rsa_suites(NVersion),
- run_suites(Ciphers, Config, ecdh_rsa).
-%%--------------------------------------------------------------------
-ciphers_ecdh_rsa_signed_certs_openssl_names() ->
- [{doc, "Test all ecdh_rsa ssl cipher suites in highest support ssl/tls version"}].
-
-ciphers_ecdh_rsa_signed_certs_openssl_names(Config) when is_list(Config) ->
- Ciphers = ssl_test_lib:openssl_ecdh_rsa_suites(),
- run_suites(Ciphers, Config, ecdh_rsa).
-%%--------------------------------------------------------------------
reuse_session() ->
[{doc,"Test reuse of sessions (short handshake)"}].
reuse_session(Config) when is_list(Config) ->
@@ -6356,147 +6138,6 @@ client_server_opts(#{key_exchange := KeyAlgo}, Config) when KeyAlgo == ecdh_rsa
{ssl_test_lib:ssl_options(client_opts, Config),
ssl_test_lib:ssl_options(server_ecdh_rsa_opts, Config)}.
-run_suites(Ciphers, Config, Type) ->
- Version = ssl_test_lib:protocol_version(Config),
- ct:log("Running cipher suites ~p~n", [Ciphers]),
- {ClientOpts, ServerOpts} =
- case Type of
- rsa ->
- {ssl_test_lib:ssl_options(client_rsa_verify_opts, Config),
- [{ciphers, Ciphers} |
- ssl_test_lib:ssl_options(server_rsa_opts, Config)]};
- dsa ->
- {ssl_test_lib:ssl_options(client_dsa_verify_opts, Config),
- [{ciphers, Ciphers} |
- ssl_test_lib:ssl_options(server_dsa_opts, Config)]};
- anonymous ->
- %% No certs in opts!
- {ssl_test_lib:ssl_options(client_rsa_verify_opts, Config),
- [{ciphers, Ciphers} |
- ssl_test_lib:ssl_options([], Config)]};
- psk ->
- {ssl_test_lib:ssl_options(client_psk, Config),
- [{ciphers, Ciphers} |
- ssl_test_lib:ssl_options(server_psk, Config)]};
- psk_with_hint ->
- {ssl_test_lib:ssl_options(client_psk, Config),
- [{ciphers, Ciphers} |
- ssl_test_lib:ssl_options(server_psk_hint, Config)
- ]};
- psk_anon ->
- {ssl_test_lib:ssl_options(client_psk, Config),
- [{ciphers, Ciphers} |
- ssl_test_lib:ssl_options(server_psk_anon, Config)]};
- psk_anon_with_hint ->
- {ssl_test_lib:ssl_options(client_psk, Config),
- [{ciphers, Ciphers} |
- ssl_test_lib:ssl_options(server_psk_anon_hint, Config)]};
- srp ->
- {ssl_test_lib:ssl_options(client_srp, Config),
- [{ciphers, Ciphers} |
- ssl_test_lib:ssl_options(server_srp, Config)]};
- srp_anon ->
- {ssl_test_lib:ssl_options(client_srp, Config),
- [{ciphers, Ciphers} |
- ssl_test_lib:ssl_options(server_srp_anon, Config)]};
- srp_dsa ->
- {ssl_test_lib:ssl_options(client_srp_dsa, Config),
- [{ciphers, Ciphers} |
- ssl_test_lib:ssl_options(server_srp_dsa, Config)]};
- ecdsa ->
- {ssl_test_lib:ssl_options(client_ecdsa_opts, Config),
- [{ciphers, Ciphers} |
- ssl_test_lib:ssl_options(server_ecdsa_opts, Config)]};
- ecdh_rsa ->
- {ssl_test_lib:ssl_options(client_ecdh_rsa_opts, Config),
- [{ciphers, Ciphers} |
- ssl_test_lib:ssl_options(server_ecdh_rsa_opts, Config)]};
- rc4_rsa ->
- {ssl_test_lib:ssl_options(client_rsa_verify_opts, Config),
- [{ciphers, Ciphers} |
- ssl_test_lib:ssl_options(server_rsa_verify_opts, Config)]};
- rc4_ecdh_rsa ->
- {ssl_test_lib:ssl_options(client_ecdh_rsa_opts, Config),
- [{ciphers, Ciphers} |
- ssl_test_lib:ssl_options(server_ecdh_rsa_opts, Config)]};
- rc4_ecdsa ->
- {ssl_test_lib:ssl_options(client_rsa_verify_opts, Config),
- [{ciphers, Ciphers} |
- ssl_test_lib:ssl_options(server_ecdsa_opts, Config)]};
- des_dhe_rsa ->
- {ssl_test_lib:ssl_options(client_rsa_verify_opts, Config),
- [{ciphers, Ciphers} |
- ssl_test_lib:ssl_options(server_verification_opts, Config)]};
- des_rsa ->
- {ssl_test_lib:ssl_options(client_rsa_verify_opts, Config),
- [{ciphers, Ciphers} |
- ssl_test_lib:ssl_options(server_rsa_verify_opts, Config)]};
- chacha_rsa ->
- {ssl_test_lib:ssl_options(client_rsa_verify_opts, Config),
- [{ciphers, Ciphers} |
- ssl_test_lib:ssl_options(server_rsa_verify_opts, Config)]};
- chacha_ecdsa ->
- {ssl_test_lib:ssl_options(client_ecdsa_opts, Config),
- [{ciphers, Ciphers} |
- ssl_test_lib:ssl_options(server_ecdsa_opts, Config)]}
- end,
- Suites = ssl_test_lib:filter_suites(Ciphers, Version),
- ct:pal("ssl_test_lib:filter_suites(~p ~p) -> ~p ", [Ciphers, Version, Suites]),
- Results0 = lists:map(fun(Cipher) ->
- cipher(Cipher, Version, Config, ClientOpts, ServerOpts) end,
- ssl_test_lib:filter_suites(Ciphers, Version)),
- Results = lists:flatten(Results0),
- true = length(Results) == length(Suites),
- check_cipher_result(Results).
-
-check_cipher_result([]) ->
- ok;
-check_cipher_result([ok | Rest]) ->
- check_cipher_result(Rest);
-check_cipher_result([_ |_] = Error) ->
- ct:fail(Error).
-
-erlang_cipher_suite(Suite) when is_list(Suite)->
- ssl_cipher_format:suite_definition(ssl_cipher_format:openssl_suite(Suite));
-erlang_cipher_suite(Suite) ->
- Suite.
-
-cipher(CipherSuite, Version, Config, ClientOpts, ServerOpts) ->
- %% process_flag(trap_exit, true),
- ct:log("Testing CipherSuite ~p~n", [CipherSuite]),
- ct:log("Server Opts ~p~n", [ServerOpts]),
- ct:log("Client Opts ~p~n", [ClientOpts]),
- {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
-
- ErlangCipherSuite = erlang_cipher_suite(CipherSuite),
-
- ConnectionInfo = {ok, {Version, ErlangCipherSuite}},
-
- Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0},
- {from, self()},
- {mfa, {ssl_test_lib, cipher_result, [ConnectionInfo]}},
- {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, cipher_result, [ConnectionInfo]}},
- {options,
- [{ciphers,[CipherSuite]} |
- ClientOpts]}]),
-
- Result = ssl_test_lib:wait_for_result(Server, ok, Client, ok),
-
- ssl_test_lib:close(Server),
- ssl_test_lib:close(Client),
-
- case Result of
- ok ->
- [ok];
- Error ->
- [{ErlangCipherSuite, Error}]
- end.
-
connection_information_result(Socket) ->
{ok, Info = [_ | _]} = ssl:connection_information(Socket),
case length(Info) > 3 of
diff --git a/lib/ssl/test/ssl_cipher_suite_SUITE.erl b/lib/ssl/test/ssl_cipher_suite_SUITE.erl
new file mode 100644
index 0000000000..bf1bc0e752
--- /dev/null
+++ b/lib/ssl/test/ssl_cipher_suite_SUITE.erl
@@ -0,0 +1,772 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2019-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.
+%% You may obtain a copy of the License at
+%%
+%% http://www.apache.org/licenses/LICENSE-2.0
+%%
+%% Unless required by applicable law or agreed to in writing, software
+%% distributed under the License is distributed on an "AS IS" BASIS,
+%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+%% See the License for the specific language governing permissions and
+%% limitations under the License.
+%%
+%% %CopyrightEnd%
+%%
+
+%%
+
+-module(ssl_cipher_suite_SUITE).
+
+%% Note: This directive should only be used in test suites.
+-compile(export_all).
+
+-include_lib("common_test/include/ct.hrl").
+
+%%--------------------------------------------------------------------
+%% Common Test interface functions -----------------------------------
+%%--------------------------------------------------------------------
+all() ->
+ [
+ {group, 'tlsv1.2'},
+ {group, 'tlsv1.1'},
+ {group, 'tlsv1'},
+ {group, 'sslv3'},
+ {group, 'dtlsv1.2'},
+ {group, 'dtlsv1'}
+ ].
+
+groups() ->
+ [
+ {'tlsv1.2', [], kex()},
+ {'tlsv1.1', [], kex()},
+ {'tlsv1', [], kex()},
+ {'sslv3', [], kex()},
+ {'dtlsv1.2', [], kex()},
+ {'dtlsv1', [], kex()},
+ {dhe_rsa, [],[dhe_rsa_3des_ede_cbc,
+ dhe_rsa_aes_128_cbc,
+ dhe_rsa_aes_256_cbc,
+ dhe_rsa_chacha20_poly1305
+ ]},
+ {ecdhe_rsa, [], [ecdhe_rsa_3des_ede_cbc,
+ ecdhe_rsa_aes_128_cbc,
+ ecdhe_rsa_aes_128_gcm,
+ ecdhe_rsa_aes_256_cbc,
+ ecdhe_rsa_aes_256_gcm,
+ ecdhe_rsa_chacha20_poly1305
+ ]},
+ {ecdhe_ecdsa, [],[ecdhe_ecdsa_rc4_128,
+ ecdhe_ecdsa_3des_ede_cbc,
+ ecdhe_ecdsa_aes_128_cbc,
+ ecdhe_ecdsa_aes_128_gcm,
+ ecdhe_ecdsa_aes_256_cbc,
+ ecdhe_ecdsa_aes_256_gcm,
+ ecdhe_ecdsa_chacha20_poly1305
+ ]},
+ {rsa, [], [rsa_3des_ede_cbc,
+ rsa_aes_128_cbc,
+ rsa_aes_256_cbc,
+ rsa_rc4_128
+ ]},
+ {dhe_dss, [], [dhe_dss_3des_ede_cbc,
+ dhe_dss_aes_128_cbc,
+ dhe_dss_aes_256_cbc]},
+ {srp_rsa, [], [srp_rsa_3des_ede_cbc,
+ srp_rsa_aes_128_cbc,
+ srp_rsa_aes_256_cbc]},
+ {srp_dss, [], [srp_dss_3des_ede_cbc,
+ srp_dss_aes_128_cbc,
+ srp_dss_aes_256_cbc]},
+ {rsa_psk, [], [rsa_psk_3des_ede_cbc,
+ rsa_psk_rc4_128,
+ rsa_psk_aes_128_cbc,
+ rsa_psk_aes_256_cbc
+ ]},
+ {dh_anon, [], [dh_anon_rc4_128,
+ dh_anon_3des_ede_cbc,
+ dh_anon_aes_128_cbc,
+ dh_anon_aes_128_gcm,
+ dh_anon_aes_256_cbc,
+ dh_anon_aes_256_gcm]},
+ {ecdh_anon, [], [ecdh_anon_3des_ede_cbc,
+ ecdh_anon_aes_128_cbc,
+ ecdh_anon_aes_256_cbc
+ ]},
+ {srp_anon, [], [srp_anon_3des_ede_cbc,
+ srp_anon_aes_128_cbc,
+ srp_anon_aes_256_cbc]},
+ {psk, [], [psk_3des_ede_cbc,
+ psk_rc4_128,
+ psk_aes_128_cbc,
+ psk_aes_128_ccm,
+ psk_aes_128_ccm_8,
+ psk_aes_256_cbc,
+ psk_aes_256_ccm,
+ psk_aes_256_ccm_8
+ ]},
+ {dhe_psk, [], [dhe_psk_3des_ede_cbc,
+ dhe_psk_rc4_128,
+ dhe_psk_aes_128_cbc,
+ dhe_psk_aes_128_ccm,
+ dhe_psk_aes_128_ccm_8,
+ dhe_psk_aes_256_cbc,
+ dhe_psk_aes_256_ccm,
+ dhe_psk_aes_256_ccm_8
+ ]},
+ {ecdhe_psk, [], [ecdhe_psk_3des_ede_cbc,
+ ecdhe_psk_rc4_128,
+ ecdhe_psk_aes_128_cbc,
+ ecdhe_psk_aes_128_ccm,
+ ecdhe_psk_aes_128_ccm_8,
+ ecdhe_psk_aes_256_cbc
+ ]}
+ ].
+
+
+kex() ->
+ rsa() ++ ecdsa() ++ dss() ++ anonymous().
+
+rsa() ->
+ [{group, dhe_rsa},
+ {group, ecdhe_rsa},
+ {group, rsa},
+ {group, srp_rsa},
+ {group, rsa_psk}
+ ].
+
+ecdsa() ->
+ [{group, ecdhe_ecdsa}].
+
+dss() ->
+ [{group, dhe_dss},
+ {group, srp_dss}].
+
+anonymous() ->
+ [{group, dh_anon},
+ {group, ecdh_anon},
+ {group, psk},
+ {group, dhe_psk},
+ {group, ecdhe_psk},
+ {group, srp_anon}
+ ].
+
+
+init_per_suite(Config) ->
+ catch crypto:stop(),
+ try crypto:start() of
+ ok ->
+ ssl_test_lib:clean_start(),
+ Config
+ catch _:_ ->
+ {skip, "Crypto did not start"}
+ end.
+
+end_per_suite(_Config) ->
+ ssl:stop(),
+ application:stop(crypto).
+
+%%--------------------------------------------------------------------
+init_per_group(GroupName, Config) when GroupName == ecdh_anon;
+ GroupName == ecdhe_rsa;
+ GroupName == ecdhe_psk ->
+ case proplists:get_bool(ecdh, proplists:get_value(public_keys, crypto:supports())) of
+ true ->
+ init_certs(GroupName, Config);
+ false ->
+ {skip, "Missing EC crypto support"}
+ end;
+init_per_group(ecdhe_ecdsa = GroupName, Config) ->
+ PKAlg = proplists:get_value(public_keys, crypto:supports()),
+ case lists:member(ecdh, PKAlg) andalso lists:member(ecdsa, PKAlg) of
+ true ->
+ init_certs(GroupName, Config);
+ false ->
+ {skip, "Missing EC crypto support"}
+ end;
+init_per_group(dhe_dss = GroupName, Config) ->
+ PKAlg = proplists:get_value(public_keys, crypto:supports()),
+ case lists:member(dss, PKAlg) andalso lists:member(dh, PKAlg) of
+ true ->
+ init_certs(GroupName, Config);
+ false ->
+ {skip, "Missing DSS crypto support"}
+ end;
+init_per_group(srp_dss = GroupName, Config) ->
+ PKAlg = proplists:get_value(public_keys, crypto:supports()),
+ case lists:member(dss, PKAlg) andalso lists:member(srp, PKAlg) of
+ true ->
+ init_certs(GroupName, Config);
+ false ->
+ {skip, "Missing DSS_SRP crypto support"}
+ end;
+init_per_group(GroupName, Config) when GroupName == srp_anon;
+ GroupName == srp_rsa ->
+ PKAlg = proplists:get_value(public_keys, crypto:supports()),
+ case lists:member(srp, PKAlg) of
+ true ->
+ init_certs(GroupName, Config);
+ false ->
+ {skip, "Missing SRP crypto support"}
+ end;
+init_per_group(dhe_psk = GroupName, Config) ->
+ PKAlg = proplists:get_value(public_keys, crypto:supports()),
+ case lists:member(dh, PKAlg) of
+ true ->
+ init_certs(GroupName, Config);
+ false ->
+ {skip, "Missing SRP crypto support"}
+ end;
+init_per_group(GroupName, Config0) ->
+ case ssl_test_lib:is_tls_version(GroupName) of
+ true ->
+ ssl_test_lib:init_tls_version(GroupName, end_per_group(GroupName, Config0));
+ false ->
+ init_certs(GroupName, Config0)
+ end.
+
+end_per_group(GroupName, Config) ->
+ case ssl_test_lib:is_tls_version(GroupName) of
+ true ->
+ ssl_test_lib:clean_tls_version(Config);
+ false ->
+ Config
+ end.
+init_per_testcase(TestCase, Config) when TestCase == psk_3des_ede_cbc;
+ TestCase == srp_anon_3des_ede_cbc;
+ TestCase == dhe_psk_3des_ede_cbc;
+ TestCase == ecdhe_psk_3des_ede_cbc;
+ TestCase == srp_rsa_3des_ede_cbc;
+ TestCase == srp_dss_3des_ede_cbc;
+ TestCase == rsa_psk_3des_ede_cbc;
+ TestCase == rsa_3des_ede_cbc;
+ TestCase == dhe_rsa_3des_ede_cbc;
+ TestCase == dhe_dss_3des_ede_cbc;
+ TestCase == ecdhe_rsa_3des_ede_cbc;
+ TestCase == srp_anon_dss_3des_ede_cbc;
+ TestCase == dh_anon_3des_ede_cbc;
+ TestCase == ecdh_anon_3des_ede_cbc;
+ TestCase == ecdhe_ecdsa_3des_ede_cbc ->
+ SupCiphers = proplists:get_value(ciphers, crypto:supports()),
+ case lists:member(des_ede3, SupCiphers) of
+ true ->
+ ct:timetrap({seconds, 5}),
+ Config;
+ _ ->
+ {skip, "Missing 3DES crypto support"}
+ end;
+init_per_testcase(TestCase, Config) when TestCase == psk_rc4_128;
+ TestCase == ecdhe_psk_rc4_128;
+ TestCase == dhe_psk_rc4_128;
+ TestCase == rsa_psk_rc4_128;
+ TestCase == rsa_rc4_128;
+ TestCase == ecdhe_rsa_rc4_128;
+ TestCase == ecdhe_ecdsa_rc4_128;
+ TestCase == dh_anon_rc4_128 ->
+ SupCiphers = proplists:get_value(ciphers, crypto:supports()),
+ case lists:member(rc4, SupCiphers) of
+ true ->
+ ct:timetrap({seconds, 5}),
+ Config;
+ _ ->
+ {skip, "Missing RC4 crypto support"}
+ end;
+init_per_testcase(TestCase, Config) when TestCase == psk_aes_128_ccm_8;
+ TestCase == rsa_psk_aes_128_ccm_8;
+ TestCase == psk_aes_128_ccm_8;
+ TestCase == dhe_psk_aes_128_ccm_8;
+ TestCase == ecdhe_psk_aes_128_ccm_8 ->
+ SupCiphers = proplists:get_value(ciphers, crypto:supports()),
+ case lists:member(aes_128_ccm, SupCiphers) of
+ true ->
+ ct:timetrap({seconds, 5}),
+ Config;
+ _ ->
+ {skip, "Missing AES_128_CCM crypto support"}
+ end;
+init_per_testcase(TestCase, Config) when TestCase == psk_aes_256_ccm_8;
+ TestCase == rsa_psk_aes_256_ccm_8;
+ TestCase == psk_aes_256_ccm_8;
+ TestCase == dhe_psk_aes_256_ccm_8;
+ TestCase == ecdhe_psk_aes_256_ccm_8 ->
+ SupCiphers = proplists:get_value(ciphers, crypto:supports()),
+ case lists:member(aes_256_ccm, SupCiphers) of
+ true ->
+ ct:timetrap({seconds, 5}),
+ Config;
+ _ ->
+ {skip, "Missing AES_256_CCM crypto support"}
+ end;
+init_per_testcase(TestCase, Config) ->
+ Cipher = test_cipher(TestCase, Config),
+ %%Reason = io_lib:format("Missing ~p crypto support", [Cipher]),
+ SupCiphers = proplists:get_value(ciphers, crypto:supports()),
+ case lists:member(Cipher, SupCiphers) of
+ true ->
+ ct:timetrap({seconds, 5}),
+ Config;
+ _ ->
+ {skip, {Cipher, SupCiphers}}
+ end.
+
+end_per_testcase(_TestCase, Config) ->
+ Config.
+
+init_certs(srp_rsa, Config) ->
+ DefConf = ssl_test_lib:default_cert_chain_conf(),
+ CertChainConf = ssl_test_lib:gen_conf(rsa, rsa, DefConf, DefConf),
+ #{server_config := ServerOpts,
+ client_config := ClientOpts}
+ = public_key:pkix_test_data(CertChainConf),
+ [{tls_config, #{server_config => [{user_lookup_fun, {fun user_lookup/3, undefined}} | ServerOpts],
+ client_config => [{srp_identity, {"Test-User", "secret"}} | ClientOpts]}} |
+ proplists:delete(tls_config, Config)];
+init_certs(srp_anon, Config) ->
+ [{tls_config, #{server_config => [{user_lookup_fun, {fun user_lookup/3, undefined}}],
+ client_config => [{srp_identity, {"Test-User", "secret"}}]}} |
+ proplists:delete(tls_config, Config)];
+init_certs(rsa_psk, Config) ->
+ ClientExt = x509_test:extensions([{key_usage, [digitalSignature, keyEncipherment]}]),
+ {ClientOpts, ServerOpts} = ssl_test_lib:make_rsa_cert_chains([{server_chain,
+ [[],[],[{extensions, ClientExt}]]}],
+ Config, "_peer_keyEncipherment"),
+ PskSharedSecret = <<1,2,3,4,5,6,7,8,9,10,11,12,13,14,15>>,
+ [{tls_config, #{server_config => [{user_lookup_fun, {fun user_lookup/3, PskSharedSecret}} | ServerOpts],
+ client_config => [{psk_identity, "Test-User"},
+ {user_lookup_fun, {fun user_lookup/3, PskSharedSecret}} | ClientOpts]}} |
+ proplists:delete(tls_config, Config)];
+init_certs(rsa, Config) ->
+ ClientExt = x509_test:extensions([{key_usage, [digitalSignature, keyEncipherment]}]),
+ {ClientOpts, ServerOpts} = ssl_test_lib:make_rsa_cert_chains([{server_chain,
+ [[],[],[{extensions, ClientExt}]]}],
+ Config, "_peer_keyEncipherment"),
+ [{tls_config, #{server_config => ServerOpts,
+ client_config => ClientOpts}} |
+ proplists:delete(tls_config, Config)];
+init_certs(dhe_dss, Config) ->
+ DefConf = ssl_test_lib:default_cert_chain_conf(),
+ CertChainConf = ssl_test_lib:gen_conf(dsa, dsa, DefConf, DefConf),
+ #{server_config := ServerOpts,
+ client_config := ClientOpts}
+ = public_key:pkix_test_data(CertChainConf),
+ [{tls_config, #{server_config => ServerOpts,
+ client_config => ClientOpts}} |
+ proplists:delete(tls_config, Config)];
+init_certs(srp_dss, Config) ->
+ DefConf = ssl_test_lib:default_cert_chain_conf(),
+ CertChainConf = ssl_test_lib:gen_conf(dsa, dsa, DefConf, DefConf),
+ #{server_config := ServerOpts,
+ client_config := ClientOpts}
+ = public_key:pkix_test_data(CertChainConf),
+ [{tls_config, #{server_config => [{user_lookup_fun, {fun user_lookup/3, undefined}} | ServerOpts],
+ client_config => [{srp_identity, {"Test-User", "secret"}} | ClientOpts]}} |
+ proplists:delete(tls_config, Config)];
+init_certs(GroupName, Config) when GroupName == dhe_rsa;
+ GroupName == ecdhe_rsa ->
+ DefConf = ssl_test_lib:default_cert_chain_conf(),
+ CertChainConf = ssl_test_lib:gen_conf(rsa, rsa, DefConf, DefConf),
+ #{server_config := ServerOpts,
+ client_config := ClientOpts}
+ = public_key:pkix_test_data(CertChainConf),
+ [{tls_config, #{server_config => ServerOpts,
+ client_config => ClientOpts}} |
+ proplists:delete(tls_config, Config)];
+init_certs(GroupName, Config) when GroupName == dhe_ecdsa;
+ GroupName == ecdhe_ecdsa ->
+ DefConf = ssl_test_lib:default_cert_chain_conf(),
+ CertChainConf = ssl_test_lib:gen_conf(ecdsa, ecdsa, DefConf, DefConf),
+ #{server_config := ServerOpts,
+ client_config := ClientOpts}
+ = public_key:pkix_test_data(CertChainConf),
+ [{tls_config, #{server_config => ServerOpts,
+ client_config => ClientOpts}} |
+ proplists:delete(tls_config, Config)];
+init_certs(GroupName, Config) when GroupName == psk;
+ GroupName == dhe_psk;
+ GroupName == ecdhe_psk ->
+ PskSharedSecret = <<1,2,3,4,5,6,7,8,9,10,11,12,13,14,15>>,
+ [{tls_config, #{server_config => [{user_lookup_fun, {fun user_lookup/3, PskSharedSecret}}],
+ client_config => [{psk_identity, "Test-User"},
+ {user_lookup_fun, {fun user_lookup/3, PskSharedSecret}}]}} |
+ proplists:delete(tls_config, Config)];
+init_certs(srp, Config) ->
+ [{tls_config, #{server_config => [{user_lookup_fun, {fun user_lookup/3, undefined}}],
+ client_config => [{srp_identity, {"Test-User", "secret"}}]}} |
+ proplists:delete(tls_config, Config)];
+init_certs(_GroupName, Config) ->
+ %% Anonymous does not need certs
+ [{tls_config, #{server_config => [],
+ client_config => []}} |
+ proplists:delete(tls_config, Config)].
+%%--------------------------------------------------------------------
+%% Test Cases --------------------------------------------------------
+%%--------------------------------------------------------------------
+
+%%--------------------------------------------------------------------
+%% SRP --------------------------------------------------------
+%%--------------------------------------------------------------------
+srp_rsa_3des_ede_cbc(Config) when is_list(Config) ->
+ run_ciphers_test(srp_rsa, '3des_ede_cbc', Config).
+
+srp_rsa_aes_128_cbc(Config) when is_list(Config) ->
+ run_ciphers_test(srp_rsa, 'aes_128_cbc', Config).
+
+srp_rsa_aes_256_cbc(Config) when is_list(Config) ->
+ run_ciphers_test(srp_rsa, 'aes_256_cbc', Config).
+
+srp_dss_3des_ede_cbc(Config) when is_list(Config) ->
+ run_ciphers_test(srp_dss, '3des_ede_cbc', Config).
+
+srp_dss_aes_128_cbc(Config) when is_list(Config) ->
+ run_ciphers_test(srp_dss, 'aes_128_cbc', Config).
+
+srp_dss_aes_256_cbc(Config) when is_list(Config) ->
+ run_ciphers_test(srp_dss, 'aes_256_cbc', Config).
+
+%%--------------------------------------------------------------------
+%% PSK --------------------------------------------------------
+%%--------------------------------------------------------------------
+rsa_psk_3des_ede_cbc(Config) when is_list(Config) ->
+ run_ciphers_test(rsa_psk, '3des_ede_cbc', Config).
+
+rsa_psk_aes_128_cbc(Config) when is_list(Config) ->
+ run_ciphers_test(rsa_psk, 'aes_128_cbc', Config).
+
+rsa_psk_aes_128_ccm(Config) when is_list(Config) ->
+ run_ciphers_test(rsa_psk, 'aes_128_ccm', Config).
+
+rsa_psk_aes_128_ccm_8(Config) when is_list(Config) ->
+ run_ciphers_test(rsa_psk, 'aes_128_ccm_8', Config).
+
+rsa_psk_aes_256_cbc(Config) when is_list(Config) ->
+ run_ciphers_test(rsa_psk, 'aes_256_cbc', Config).
+
+rsa_psk_aes_256_ccm(Config) when is_list(Config) ->
+ run_ciphers_test(rsa_psk, 'aes_256_ccm', Config).
+
+rsa_psk_aes_256_ccm_8(Config) when is_list(Config) ->
+ run_ciphers_test(rsa_psk, 'aes_256_ccm_8', Config).
+
+rsa_psk_rc4_128(Config) when is_list(Config) ->
+ run_ciphers_test(rsa_psk, 'rc4_128', Config).
+
+%%--------------------------------------------------------------------
+%% RSA --------------------------------------------------------
+%%--------------------------------------------------------------------
+rsa_des_cbc(Config) when is_list(Config) ->
+ run_ciphers_test(rsa, 'des_cbc', Config).
+
+rsa_3des_ede_cbc(Config) when is_list(Config) ->
+ run_ciphers_test(rsa, '3des_ede_cbc', Config).
+
+rsa_aes_128_cbc(Config) when is_list(Config) ->
+ run_ciphers_test(rsa, 'aes_128_cbc', Config).
+
+rsa_aes_256_cbc(Config) when is_list(Config) ->
+ run_ciphers_test(rsa, 'aes_256_cbc', Config).
+
+rsa_aes_128_gcm(Config) when is_list(Config) ->
+ run_ciphers_test(rsa, 'aes_128_gcm', Config).
+
+rsa_aes_256_gcm(Config) when is_list(Config) ->
+ run_ciphers_test(rsa, 'aes_256_gcm', Config).
+
+rsa_rc4_128(Config) when is_list(Config) ->
+ run_ciphers_test(rsa, 'rc4_128', Config).
+%%--------------------------------------------------------------------
+%% DHE_RSA --------------------------------------------------------
+%%--------------------------------------------------------------------
+dhe_rsa_3des_ede_cbc(Config) when is_list(Config) ->
+ run_ciphers_test(dhe_rsa, '3des_ede_cbc', Config).
+
+dhe_rsa_aes_128_cbc(Config) when is_list(Config) ->
+ run_ciphers_test(dhe_rsa, 'aes_128_cbc', Config).
+
+dhe_rsa_aes_128_gcm(Config) when is_list(Config) ->
+ run_ciphers_test(dhe_rsa, 'aes_128_gcm', Config).
+
+dhe_rsa_aes_256_cbc(Config) when is_list(Config) ->
+ run_ciphers_test(dhe_rsa, 'aes_256_cbc', Config).
+
+dhe_rsa_aes_256_gcm(Config) when is_list(Config) ->
+ run_ciphers_test(dhe_rsa, 'aes_256_gcm', Config).
+
+dhe_rsa_chacha20_poly1305(Config) when is_list(Config) ->
+ run_ciphers_test(dhe_rsa, 'chacha20_poly1305', Config).
+%%--------------------------------------------------------------------
+%% ECDHE_RSA --------------------------------------------------------
+%%--------------------------------------------------------------------
+ecdhe_rsa_3des_ede_cbc(Config) when is_list(Config) ->
+ run_ciphers_test(ecdhe_rsa, '3des_ede_cbc', Config).
+
+ecdhe_rsa_aes_128_cbc(Config) when is_list(Config) ->
+ run_ciphers_test(ecdhe_rsa, 'aes_128_cbc', Config).
+
+ecdhe_rsa_aes_128_gcm(Config) when is_list(Config) ->
+ run_ciphers_test(ecdhe_rsa, 'aes_128_gcm', Config).
+
+ecdhe_rsa_aes_256_cbc(Config) when is_list(Config) ->
+ run_ciphers_test(ecdhe_rsa, 'aes_256_cbc', Config).
+
+ecdhe_rsa_aes_256_gcm(Config) when is_list(Config) ->
+ run_ciphers_test(ecdhe_rsa, 'aes_256_gcm', Config).
+
+ecdhe_rsa_rc4_128(Config) when is_list(Config) ->
+ run_ciphers_test(ecdhe_rsa, 'rc4_128', Config).
+
+ecdhe_rsa_chacha20_poly1305(Config) when is_list(Config) ->
+ run_ciphers_test(ecdhe_rsa, 'chacha20_poly1305', Config).
+
+%%--------------------------------------------------------------------
+%% ECDHE_ECDSA --------------------------------------------------------
+%%--------------------------------------------------------------------
+ecdhe_ecdsa_rc4_128(Config) when is_list(Config) ->
+ run_ciphers_test(ecdhe_ecdsa, 'rc4_128', Config).
+
+ecdhe_ecdsa_3des_ede_cbc(Config) when is_list(Config) ->
+ run_ciphers_test(ecdhe_ecdsa, '3des_ede_cbc', Config).
+
+ecdhe_ecdsa_aes_128_cbc(Config) when is_list(Config) ->
+ run_ciphers_test(ecdhe_ecdsa, 'aes_128_cbc', Config).
+
+ecdhe_ecdsa_aes_128_gcm(Config) when is_list(Config) ->
+ run_ciphers_test(ecdhe_ecdsa, 'aes_128_gcm', Config).
+
+ecdhe_ecdsa_aes_256_cbc(Config) when is_list(Config) ->
+ run_ciphers_test(ecdhe_ecdsa, 'aes_256_cbc', Config).
+
+ecdhe_ecdsa_aes_256_gcm(Config) when is_list(Config) ->
+ run_ciphers_test(ecdhe_ecdsa, 'aes_256_gcm', Config).
+
+ecdhe_ecdsa_chacha20_poly1305(Config) when is_list(Config) ->
+ run_ciphers_test(ecdhe_ecdsa, 'chacha20_poly1305', Config).
+%%--------------------------------------------------------------------
+%% DHE_DSS --------------------------------------------------------
+%%--------------------------------------------------------------------
+dhe_dss_des_cbc(Config) when is_list(Config) ->
+ run_ciphers_test(dhe_dss, 'des_cbc', Config).
+
+dhe_dss_3des_ede_cbc(Config) when is_list(Config) ->
+ run_ciphers_test(dhe_dss, '3des_ede_cbc', Config).
+
+dhe_dss_aes_128_cbc(Config) when is_list(Config) ->
+ run_ciphers_test(dhe_dss, 'aes_128_cbc', Config).
+
+dhe_dss_aes_256_cbc(Config) when is_list(Config) ->
+ run_ciphers_test(dhe_dss, 'aes_256_cbc', Config).
+
+dhe_dss_aes_128_gcm(Config) when is_list(Config) ->
+ run_ciphers_test(dhe_dss, 'aes_128_gcm', Config).
+
+dhe_dss_aes_256_gcm(Config) when is_list(Config) ->
+ run_ciphers_test(dhe_dss, 'aes_256_gcm', Config).
+
+%%--------------------------------------------------------------------
+%% Anonymous --------------------------------------------------------
+%%--------------------------------------------------------------------
+dh_anon_3des_ede_cbc(Config) when is_list(Config) ->
+ run_ciphers_test(dh_anon, '3des_ede_cbc', Config).
+
+dh_anon_aes_128_cbc(Config) when is_list(Config) ->
+ run_ciphers_test(dh_anon, 'aes_128_cbc', Config).
+
+dh_anon_aes_128_gcm(Config) when is_list(Config) ->
+ run_ciphers_test(dh_anon, 'aes_128_gcm', Config).
+
+dh_anon_aes_256_cbc(Config) when is_list(Config) ->
+ run_ciphers_test(dh_anon, 'aes_256_cbc', Config).
+
+dh_anon_aes_256_gcm(Config) when is_list(Config) ->
+ run_ciphers_test(dh_anon, 'aes_256_gcm', Config).
+
+dh_anon_rc4_128(Config) when is_list(Config) ->
+ run_ciphers_test(dh_anon, 'rc4_128', Config).
+
+ecdh_anon_3des_ede_cbc(Config) when is_list(Config) ->
+ run_ciphers_test(ecdh_anon, '3des_ede_cbc', Config).
+
+ecdh_anon_aes_128_cbc(Config) when is_list(Config) ->
+ run_ciphers_test(ecdh_anon, 'aes_128_cbc', Config).
+
+ecdh_anon_aes_256_cbc(Config) when is_list(Config) ->
+ run_ciphers_test(ecdh_anon, 'aes_256_cbc', Config).
+
+srp_anon_3des_ede_cbc(Config) when is_list(Config) ->
+ run_ciphers_test(srp_anon, '3des_ede_cbc', Config).
+
+srp_anon_aes_128_cbc(Config) when is_list(Config) ->
+ run_ciphers_test(srp_anon, 'aes_128_cbc', Config).
+
+srp_anon_aes_256_cbc(Config) when is_list(Config) ->
+ run_ciphers_test(srp_anon, 'aes_256_cbc', Config).
+
+dhe_psk_des_cbc(Config) when is_list(Config) ->
+ run_ciphers_test(dhe_psk, 'des_cbc', Config).
+
+dhe_psk_rc4_128(Config) when is_list(Config) ->
+ run_ciphers_test(dhe_psk, 'rc4_128', Config).
+
+dhe_psk_3des_ede_cbc(Config) when is_list(Config) ->
+ run_ciphers_test(dhe_psk, '3des_ede_cbc', Config).
+
+dhe_psk_aes_128_cbc(Config) when is_list(Config) ->
+ run_ciphers_test(dhe_psk, 'aes_128_cbc', Config).
+
+dhe_psk_aes_256_cbc(Config) when is_list(Config) ->
+ run_ciphers_test(dhe_psk, 'aes_256_cbc', Config).
+
+dhe_psk_aes_128_gcm(Config) when is_list(Config) ->
+ run_ciphers_test(dhe_psk, 'aes_128_gcm', Config).
+
+dhe_psk_aes_256_gcm(Config) when is_list(Config) ->
+ run_ciphers_test(dhe_psk, 'aes_256_gcm', Config).
+
+dhe_psk_aes_128_ccm(Config) when is_list(Config) ->
+ run_ciphers_test(dhe_psk, 'aes_128_ccm', Config).
+
+dhe_psk_aes_256_ccm(Config) when is_list(Config) ->
+ run_ciphers_test(dhe_psk, 'aes_256_ccm', Config).
+
+dhe_psk_aes_128_ccm_8(Config) when is_list(Config) ->
+ run_ciphers_test(dhe_psk, 'aes_128_ccm_8', Config).
+
+dhe_psk_aes_256_ccm_8(Config) when is_list(Config) ->
+ run_ciphers_test(dhe_psk, 'aes_256_ccm_8', Config).
+
+ecdhe_psk_des_cbc(Config) when is_list(Config) ->
+ run_ciphers_test(ecdhe_psk, 'des_cbc', Config).
+
+ecdhe_psk_rc4_128(Config) when is_list(Config) ->
+ run_ciphers_test(ecdhe_psk, 'rc4_128', Config).
+
+ecdhe_psk_3des_ede_cbc(Config) when is_list(Config) ->
+ run_ciphers_test(ecdhe_psk, '3des_ede_cbc', Config).
+
+ecdhe_psk_aes_128_cbc(Config) when is_list(Config) ->
+ run_ciphers_test(ecdhe_psk, 'aes_128_cbc', Config).
+
+ecdhe_psk_aes_256_cbc(Config) when is_list(Config) ->
+ run_ciphers_test(ecdhe_psk, 'aes_256_cbc', Config).
+
+ecdhe_psk_aes_128_gcm(Config) when is_list(Config) ->
+ run_ciphers_test(ecdhe_psk, 'aes_128_gcm', Config).
+
+ecdhe_psk_aes_256_gcm(Config) when is_list(Config) ->
+ run_ciphers_test(ecdhe_psk, 'aes_256_gcm', Config).
+
+ecdhe_psk_aes_128_ccm(Config) when is_list(Config) ->
+ run_ciphers_test(ecdhe_psk, 'aes_128_ccm', Config).
+
+ecdhe_psk_aes_128_ccm_8(Config) when is_list(Config) ->
+ run_ciphers_test(ecdhe_psk, 'aes_128_ccm_8', Config).
+
+psk_des_cbc(Config) when is_list(Config) ->
+ run_ciphers_test(psk, 'des_cbc', Config).
+
+psk_rc4_128(Config) when is_list(Config) ->
+ run_ciphers_test(psk, 'rc4_128', Config).
+
+psk_3des_ede_cbc(Config) when is_list(Config) ->
+ run_ciphers_test(psk, '3des_ede_cbc', Config).
+
+psk_aes_128_cbc(Config) when is_list(Config) ->
+ run_ciphers_test(psk, 'aes_128_cbc', Config).
+
+psk_aes_256_cbc(Config) when is_list(Config) ->
+ run_ciphers_test(psk, 'aes_256_cbc', Config).
+
+psk_aes_128_gcm(Config) when is_list(Config) ->
+ run_ciphers_test(psk, 'aes_128_gcm', Config).
+
+psk_aes_256_gcm(Config) when is_list(Config) ->
+ run_ciphers_test(psk, 'aes_256_gcm', Config).
+
+psk_aes_128_ccm(Config) when is_list(Config) ->
+ run_ciphers_test(psk, 'aes_128_ccm', Config).
+
+psk_aes_256_ccm(Config) when is_list(Config) ->
+ run_ciphers_test(psk, 'aes_256_ccm', Config).
+
+psk_aes_128_ccm_8(Config) when is_list(Config) ->
+ run_ciphers_test(psk, 'aes_128_ccm_8', Config).
+
+psk_aes_256_ccm_8(Config) when is_list(Config) ->
+ run_ciphers_test(psk, 'aes_256_ccm_8', Config).
+
+%%--------------------------------------------------------------------
+%% Internal functions ----------------------------------------------
+%%--------------------------------------------------------------------
+test_cipher(TestCase, Config) ->
+ [{name, Group} |_] = proplists:get_value(tc_group_properties, Config),
+ list_to_atom(re:replace(atom_to_list(TestCase), atom_to_list(Group) ++ "_", "", [{return, list}])).
+
+run_ciphers_test(Kex, Cipher, Config) ->
+ Version = ssl_test_lib:protocol_version(Config),
+ TestCiphers = test_ciphers(Kex, Cipher, Version),
+
+ case TestCiphers of
+ [_|_] ->
+ lists:foreach(fun(TestCipher) ->
+ cipher_suite_test(TestCipher, Version, Config)
+ end, TestCiphers);
+ [] ->
+ {skip, {not_sup, Kex, Cipher, Version}}
+ end.
+
+cipher_suite_test(CipherSuite, Version, Config) ->
+ #{server_config := SOpts,
+ client_config := COpts} = proplists:get_value(tls_config, Config),
+ ServerOpts = ssl_test_lib:ssl_options(SOpts, Config),
+ ClientOpts = ssl_test_lib:ssl_options(COpts, Config),
+ ct:log("Testing CipherSuite ~p~n", [CipherSuite]),
+ ct:log("Server Opts ~p~n", [ServerOpts]),
+ ct:log("Client Opts ~p~n", [ClientOpts]),
+ {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
+
+ ErlangCipherSuite = erlang_cipher_suite(CipherSuite),
+
+ ConnectionInfo = {ok, {Version, ErlangCipherSuite}},
+
+ Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0},
+ {from, self()},
+ {mfa, {ssl_test_lib, cipher_result, [ConnectionInfo]}},
+ {options, [{versions, [Version]}, {ciphers, [CipherSuite]} | 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, cipher_result, [ConnectionInfo]}},
+ {options, [{versions, [Version]}, {ciphers, [CipherSuite]} |
+ ClientOpts]}]),
+
+ ssl_test_lib:check_result(Server, ok, Client, ok),
+
+ ssl_test_lib:close(Server),
+ ssl_test_lib:close(Client).
+
+erlang_cipher_suite(Suite) when is_list(Suite)->
+ ssl_cipher_format:suite_definition(ssl_cipher_format:openssl_suite(Suite));
+erlang_cipher_suite(Suite) ->
+ Suite.
+
+user_lookup(psk, _Identity, UserState) ->
+ {ok, UserState};
+user_lookup(srp, Username, _UserState) ->
+ Salt = ssl_cipher:random_bytes(16),
+ UserPassHash = crypto:hash(sha, [Salt, crypto:hash(sha, [Username, <<$:>>, <<"secret">>])]),
+ {ok, {srp_1024, Salt, UserPassHash}}.
+
+test_ciphers(Kex, Cipher, Version) ->
+ ssl:filter_cipher_suites(ssl:cipher_suites(all, Version) ++ ssl:cipher_suites(anonymous, Version),
+ [{key_exchange,
+ fun(Kex0) when Kex0 == Kex -> true;
+ (_) -> false
+ end},
+ {cipher,
+ fun(Cipher0) when Cipher0 == Cipher -> true;
+ (_) -> false
+ end}]).
diff --git a/lib/ssl/test/ssl_test_lib.erl b/lib/ssl/test/ssl_test_lib.erl
index 7f8e81dbd8..22169035f3 100644
--- a/lib/ssl/test/ssl_test_lib.erl
+++ b/lib/ssl/test/ssl_test_lib.erl
@@ -514,13 +514,6 @@ wait_for_result(Pid, Msg) ->
%% Unexpected
end.
-user_lookup(psk, _Identity, UserState) ->
- {ok, UserState};
-user_lookup(srp, Username, _UserState) ->
- Salt = ssl_cipher:random_bytes(16),
- UserPassHash = crypto:hash(sha, [Salt, crypto:hash(sha, [Username, <<$:>>, <<"secret">>])]),
- {ok, {srp_1024, Salt, UserPassHash}}.
-
cert_options(Config) ->
ClientCaCertFile = filename:join([proplists:get_value(priv_dir, Config),
"client", "cacerts.pem"]),
@@ -1540,10 +1533,13 @@ cipher_result(Socket, Result) ->
ct:log("~p:~p~nSuccessfull connect: ~p~n", [?MODULE,?LINE, Result]),
%% Importante to send two packets here
%% to properly test "cipher state" handling
- ssl:send(Socket, "Hello\n"),
- "Hello\n" = active_recv(Socket, length( "Hello\n")),
- ssl:send(Socket, " world\n"),
- " world\n" = active_recv(Socket, length(" world\n")),
+ Hello = "Hello\n",
+ World = " world\n",
+ ssl:send(Socket, Hello),
+ ct:sleep(500),
+ ssl:send(Socket, World),
+ Expected = Hello ++ World,
+ Expected = active_recv(Socket, length(Expected)),
ok.
session_info_result(Socket) ->
@@ -2378,4 +2374,10 @@ reuse_session(ClientOpts, ServerOpts, Config) ->
ssl_test_lib:close(Server1),
ssl_test_lib:close(Client3),
ssl_test_lib:close(Client4).
-
+
+user_lookup(psk, _Identity, UserState) ->
+ {ok, UserState};
+user_lookup(srp, Username, _UserState) ->
+ Salt = ssl_cipher:random_bytes(16),
+ UserPassHash = crypto:hash(sha, [Salt, crypto:hash(sha, [Username, <<$:>>, <<"secret">>])]),
+ {ok, {srp_1024, Salt, UserPassHash}}.
diff --git a/lib/ssl/test/ssl_to_openssl_SUITE.erl b/lib/ssl/test/ssl_to_openssl_SUITE.erl
index df84411b6d..f22eb4ecdf 100644
--- a/lib/ssl/test/ssl_to_openssl_SUITE.erl
+++ b/lib/ssl/test/ssl_to_openssl_SUITE.erl
@@ -39,16 +39,14 @@
all() ->
case ssl_test_lib:openssl_sane_dtls() of
true ->
- [{group, basic},
- {group, 'tlsv1.2'},
+ [{group, 'tlsv1.2'},
{group, 'tlsv1.1'},
{group, 'tlsv1'},
{group, 'sslv3'},
{group, 'dtlsv1.2'},
{group, 'dtlsv1'}];
false ->
- [{group, basic},
- {group, 'tlsv1.2'},
+ [{group, 'tlsv1.2'},
{group, 'tlsv1.1'},
{group, 'tlsv1'},
{group, 'sslv3'}]
@@ -57,8 +55,7 @@ all() ->
groups() ->
case ssl_test_lib:openssl_sane_dtls() of
true ->
- [{basic, [], basic_tests()},
- {'tlsv1.2', [], all_versions_tests() ++ alpn_tests() ++ npn_tests() ++ sni_server_tests()},
+ [{'tlsv1.2', [], all_versions_tests() ++ alpn_tests() ++ npn_tests() ++ sni_server_tests()},
{'tlsv1.1', [], all_versions_tests() ++ alpn_tests() ++ npn_tests() ++ sni_server_tests()},
{'tlsv1', [], all_versions_tests()++ alpn_tests() ++ npn_tests() ++ sni_server_tests()},
{'sslv3', [], all_versions_tests()},
@@ -66,20 +63,13 @@ groups() ->
{'dtlsv1', [], dtls_all_versions_tests()}
];
false ->
- [{basic, [], basic_tests()},
- {'tlsv1.2', [], all_versions_tests() ++ alpn_tests() ++ npn_tests() ++ sni_server_tests()},
+ [{'tlsv1.2', [], all_versions_tests() ++ alpn_tests() ++ npn_tests() ++ sni_server_tests()},
{'tlsv1.1', [], all_versions_tests() ++ alpn_tests() ++ npn_tests() ++ sni_server_tests()},
{'tlsv1', [], all_versions_tests()++ alpn_tests() ++ npn_tests() ++ sni_server_tests()},
{'sslv3', [], all_versions_tests()}
]
end.
-
-basic_tests() ->
- [basic_erlang_client_openssl_server,
- basic_erlang_server_openssl_client,
- expired_session
- ].
-
+
all_versions_tests() ->
[
erlang_client_openssl_server,
@@ -357,85 +347,7 @@ end_per_testcase(_, Config) ->
%%--------------------------------------------------------------------
%% Test Cases --------------------------------------------------------
%%--------------------------------------------------------------------
-basic_erlang_client_openssl_server() ->
- [{doc,"Test erlang client with openssl server"}].
-basic_erlang_client_openssl_server(Config) when is_list(Config) ->
- process_flag(trap_exit, true),
- ServerOpts = ssl_test_lib:ssl_options(server_rsa_opts, Config),
- ClientOpts = ssl_test_lib:ssl_options(client_rsa_opts, Config),
-
- {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),
- KeyFile = proplists:get_value(keyfile, ServerOpts),
-
- Exe = "openssl",
- Args = ["s_server", "-accept", integer_to_list(Port),
- "-cert", CertFile, "-key", KeyFile],
-
- 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).
-
-%%--------------------------------------------------------------------
-basic_erlang_server_openssl_client() ->
- [{doc,"Test erlang server with openssl client"}].
-basic_erlang_server_openssl_client(Config) when is_list(Config) ->
- process_flag(trap_exit, true),
- ServerOpts = ssl_test_lib:ssl_options(server_rsa_opts, Config),
-
- {_, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
-
- Data = "From openssl to erlang",
- Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0},
- {from, self()},
- {mfa, {?MODULE, erlang_ssl_receive, [Data]}},
- {options,ServerOpts}]),
-
- Port = ssl_test_lib:inet_port(Server),
-
- Exe = "openssl",
- Args = case no_low_flag("-no_ssl2") of
- [] ->
- ["s_client", "-connect", hostname_format(Hostname) ++
- ":" ++ integer_to_list(Port), no_low_flag("-no_ssl3")
- | workaround_openssl_s_clinent()];
- Flag ->
- ["s_client", "-connect", hostname_format(Hostname) ++
- ":" ++ integer_to_list(Port), no_low_flag("-no_ssl3"), Flag
- | workaround_openssl_s_clinent()]
- end,
-
- OpenSslPort = ssl_test_lib:portable_open_port(Exe, Args),
- true = port_command(OpenSslPort, Data),
-
- ssl_test_lib:check_result(Server, ok),
-
- %% Clean close down! Server needs to be closed first !!
- ssl_test_lib:close(Server),
- ssl_test_lib:close_port(OpenSslPort),
- process_flag(trap_exit, false).
-%%--------------------------------------------------------------------
erlang_client_openssl_server() ->
[{doc,"Test erlang client with openssl server"}].
erlang_client_openssl_server(Config) when is_list(Config) ->
diff --git a/lib/stdlib/doc/src/gen_statem.xml b/lib/stdlib/doc/src/gen_statem.xml
index d4a4ba268b..6f6849a19d 100644
--- a/lib/stdlib/doc/src/gen_statem.xml
+++ b/lib/stdlib/doc/src/gen_statem.xml
@@ -757,7 +757,7 @@ handle_event(_, _, State, Data) ->
right before entering the initial state even though this
actually is not a <em>state change</em>.
In this case <c>OldState =:= State</c>,
- which can not happen for a subsequent state change,
+ which cannot happen for a subsequent state change,
but will happen when repeating the <em>state enter call</em>.
</p>
</desc>
diff --git a/lib/stdlib/src/erl_tar.erl b/lib/stdlib/src/erl_tar.erl
index d8b8f466b1..7064fcacfa 100644
--- a/lib/stdlib/src/erl_tar.erl
+++ b/lib/stdlib/src/erl_tar.erl
@@ -324,7 +324,7 @@ do_open(Name, Mode) when is_list(Mode) ->
open1({binary,Bin}, read, _Raw, Opts) when is_binary(Bin) ->
case file:open(Bin, [ram,binary,read]) of
{ok,File} ->
- _ = [ram_file:uncompress(File) || Opts =:= [compressed]],
+ _ = [ram_file:uncompress(File) || lists:member(compressed, Opts)],
{ok, #reader{handle=File,access=read,func=fun file_op/2}};
Error ->
Error
@@ -357,7 +357,7 @@ open_mode([read|Rest], false, Raw, Opts) ->
open_mode([write|Rest], false, Raw, Opts) ->
open_mode(Rest, write, Raw, Opts);
open_mode([compressed|Rest], Access, Raw, Opts) ->
- open_mode(Rest, Access, Raw, [compressed|Opts]);
+ open_mode(Rest, Access, Raw, [compressed,read_ahead|Opts]);
open_mode([cooked|Rest], Access, _Raw, Opts) ->
open_mode(Rest, Access, [], Opts);
open_mode([], Access, Raw, Opts) ->
diff --git a/lib/syntax_tools/test/syntax_tools_SUITE.erl b/lib/syntax_tools/test/syntax_tools_SUITE.erl
index 6b42f7a0a1..e1dd1bd73b 100644
--- a/lib/syntax_tools/test/syntax_tools_SUITE.erl
+++ b/lib/syntax_tools/test/syntax_tools_SUITE.erl
@@ -74,7 +74,7 @@ smoke_test_file(File) ->
[print_error_markers(F, File) || F <- Forms],
ok;
{error,Reason} ->
- io:format("~s: ~p\n", [File,Reason]),
+ io:format("~ts: ~p\n", [File,Reason]),
error
end.
@@ -82,7 +82,7 @@ print_error_markers(F, File) ->
case erl_syntax:type(F) of
error_marker ->
{L,M,Info} = erl_syntax:error_marker_info(F),
- io:format("~ts:~p: ~s", [File,L,M:format_error(Info)]);
+ io:format("~ts:~p: ~ts", [File,L,M:format_error(Info)]);
_ ->
ok
end.
@@ -362,7 +362,7 @@ test_comment_scan([File|Files],DataDir) ->
end,
Fs1 = erl_recomment:recomment_forms(Fs0, Comments),
Fs2 = erl_syntax_lib:map(Fun, Fs1),
- io:format("File: ~s~n", [Filename]),
+ io:format("File: ~ts~n", [Filename]),
io:put_chars(erl_prettypr:format(Fs2, [{paper, 120},
{ribbon, 110}])),
test_comment_scan(Files,DataDir).
@@ -377,8 +377,8 @@ test_prettypr([File|Files],DataDir,PrivDir) ->
PP = erl_prettypr:format(Fs, [{paper, 120}, {ribbon, 110}]),
io:put_chars(PP),
OutFile = filename:join(PrivDir, File),
- ok = file:write_file(OutFile,iolist_to_binary(PP)),
- io:format("Parsing OutFile: ~s~n", [OutFile]),
+ ok = file:write_file(OutFile,unicode:characters_to_binary(PP)),
+ io:format("Parsing OutFile: ~ts~n", [OutFile]),
{ok, Fs2} = epp:parse_file(OutFile, [], []),
case [Error || {error, _} = Error <- Fs2] of
[] ->
@@ -445,7 +445,7 @@ pretty_print_parse_forms([{Fs0,Type}|FsForms],PrivDir,Filename) ->
{Fs2,{CC,CT}} = erl_syntax_lib:mapfold(Comment,{0,0}, Fs1),
io:format("Commented on ~w cases and ~w tries~n", [CC,CT]),
PP = erl_prettypr:format(Fs2),
- ok = file:write_file(OutFile,iolist_to_binary(PP)),
+ ok = file:write_file(OutFile,unicode:characters_to_binary(PP)),
pretty_print_parse_forms(FsForms,PrivDir,Filename).
diff --git a/lib/tools/emacs/erldoc.el b/lib/tools/emacs/erldoc.el
index 770ab299ee..bc16d7a14d 100644
--- a/lib/tools/emacs/erldoc.el
+++ b/lib/tools/emacs/erldoc.el
@@ -89,6 +89,13 @@ up the indexing."
:type 'file
:group 'erldoc)
+(defcustom erldoc-no-signature-function #'ignore
+ "Notification function called if no function signature was found."
+ :type '(choice (function-item :tag "Ignore" ignore)
+ (function-item :tag "Warn" warn)
+ (function-item :tag "Error" error))
+ :group 'erldoc)
+
(defun erldoc-strip-string (s)
(let* ((re "[ \t\n\r\f\v\u00a0]+")
(from (if (string-match (concat "\\`" re) s) (match-end 0) 0))
@@ -212,11 +219,21 @@ up the indexing."
;; Get the full function signature.
(when (and (eq (car-safe d) 'a)
(gethash (erldoc-dom-get-attribute d 'name) table))
- (push (append (gethash (erldoc-dom-get-attribute d 'name) table)
- (list (funcall span-content
- (or (erldoc-dom-get-element d 'span)
- (cadr (memq d erldoc-dom-walk-siblings))))))
- entries))
+ (let* ((name (erldoc-dom-get-attribute d 'name))
+ (mfa-url (gethash name table))
+ (mfa (car mfa-url))
+ (sig (or (funcall span-content d)
+ (funcall span-content
+ (or (erldoc-dom-get-element d 'span)
+ (cadr
+ (memq d erldoc-dom-walk-siblings))))
+ (progn
+ (funcall erldoc-no-signature-function
+ "erldoc-parse-man: no sig for %s"
+ mfa)
+ nil))))
+ (push (append mfa-url (list sig))
+ entries)))
;; Get data types
(when (and (eq (car-safe d) 'a)
(string-prefix-p "type-"
@@ -280,7 +297,7 @@ up the indexing."
(unless (file-exists-p of)
(erldoc-parse-all erldoc-man-index of))
(unless (string= erldoc-output-file of)
- (make-symbolic-link of erldoc-output-file))))
+ (make-symbolic-link (expand-file-name of) erldoc-output-file))))
(setq erldoc-lookup-table
(with-temp-buffer
(insert-file-contents erldoc-output-file)
@@ -356,9 +373,12 @@ up the indexing."
(sigs))
(maphash (lambda (k v)
(when (string-match re k)
- (push (cons (string-to-number (match-string 1 k))
- (cdr (erldoc-tokenize-signature (cadr v))))
- sigs)))
+ (if (cadr v)
+ (push (cons (string-to-number (match-string 1 k))
+ (cdr (erldoc-tokenize-signature (cadr v))))
+ sigs)
+ (funcall erldoc-no-signature-function
+ "erldoc-format-signature: No sig for %s" k))))
(erldoc-lookup-table))
(when sigs
;; Mostly single return type but there are exceptions such as
diff --git a/lib/wx/src/Makefile b/lib/wx/src/Makefile
index 21b45af2c4..52f4008e0a 100644
--- a/lib/wx/src/Makefile
+++ b/lib/wx/src/Makefile
@@ -111,10 +111,10 @@ $(APPUP_TARGET): $(APPUP_SRC) ../vsn.mk Makefile
# Rules
$(EBIN)/%.beam: $(ESRC)/%.erl $(HEADER_FILES)
- $(V_ERLC) -W -bbeam $(ERL_FLAGS) $(ERL_COMPILE_FLAGS) -o$(EBIN) $<
+ $(V_ERLC) -W -bbeam $(ERL_COMPILE_FLAGS) -o$(EBIN) $<
$(EBIN)/%.beam: $(EGEN)/%.erl $(HEADER_FILES)
- $(V_ERLC) -W -bbeam $(ERL_FLAGS) $(ERL_COMPILE_FLAGS) -o$(EBIN) $<
+ $(V_ERLC) -W -bbeam $(ERL_COMPILE_FLAGS) -o$(EBIN) $<
# ----------------------------------------------------
# Release Target
diff --git a/system/doc/design_principles/statem.xml b/system/doc/design_principles/statem.xml
index 45ea972ff2..23e9054547 100644
--- a/system/doc/design_principles/statem.xml
+++ b/system/doc/design_principles/statem.xml
@@ -759,7 +759,7 @@ StateName(EventType, EventContent, Data) ->
<p>
Since the <em>state enter call</em> is not an event there are restrictions
on the allowed return value and
- <seealso marker="#State Transition Actions">State Transition Actions</seealso>.
+ <seealso marker="#Transition Actions">State Transition Actions</seealso>.
You may not change the state,
<seealso marker="#Postponing Events">postpone</seealso>
this non-event, or
diff --git a/system/doc/reference_manual/expressions.xml b/system/doc/reference_manual/expressions.xml
index 8c47070890..ea3b2159fc 100644
--- a/system/doc/reference_manual/expressions.xml
+++ b/system/doc/reference_manual/expressions.xml
@@ -1221,10 +1221,10 @@ Ei = Value |
&lt;&lt;1,17,0,42&gt;&gt;
10> <input>H.</input>
&lt;&lt;17,0,42&gt;&gt;
-11> <input>&lt;&lt;G,H/bitstring&gt;&gt; = &lt;&lt;1,17,42:12&gt;&gt;.</input>
-&lt;&lt;1,17,1,10:4&gt;&gt;
-12> <input>H.</input>
-&lt;&lt;17,1,10:4&gt;&gt;
+11> <input>&lt;&lt;G,J/bitstring&gt;&gt; = &lt;&lt;1,17,42:12&gt;&gt;.</input>
+&lt;&lt;1,17,2,10:4&gt;&gt;
+12> <input>J.</input>
+&lt;&lt;17,2,10:4&gt;&gt;
13> <input>&lt;&lt;1024/utf8&gt;&gt;.</input>
&lt;&lt;208,128&gt;&gt;
</pre>