aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--erts/doc/src/socket.xml42
-rw-r--r--erts/doc/src/socket_usage.xml12
-rw-r--r--erts/emulator/beam/beam_bif_load.c72
-rw-r--r--erts/emulator/beam/copy.c49
-rw-r--r--erts/emulator/beam/dist.c28
-rw-r--r--erts/emulator/beam/dist.h16
-rw-r--r--erts/emulator/beam/erl_alloc.types1
-rw-r--r--erts/emulator/beam/erl_bif_persistent.c99
-rw-r--r--erts/emulator/beam/erl_db.c15
-rw-r--r--erts/emulator/beam/erl_db.h4
-rw-r--r--erts/emulator/beam/erl_db_catree.c28
-rw-r--r--erts/emulator/beam/erl_db_catree.h3
-rw-r--r--erts/emulator/beam/erl_db_hash.c6
-rw-r--r--erts/emulator/beam/erl_db_hash.h3
-rw-r--r--erts/emulator/beam/erl_db_tree.c6
-rw-r--r--erts/emulator/beam/erl_db_tree.h4
-rw-r--r--erts/emulator/beam/erl_gc.c10
-rw-r--r--erts/emulator/beam/erl_monitor_link.c49
-rw-r--r--erts/emulator/beam/erl_monitor_link.h17
-rw-r--r--erts/emulator/beam/erl_node_tables.c247
-rw-r--r--erts/emulator/beam/erl_node_tables.h39
-rw-r--r--erts/emulator/beam/erl_proc_sig_queue.c8
-rw-r--r--erts/emulator/beam/erl_process.c76
-rw-r--r--erts/emulator/beam/erl_process.h7
-rw-r--r--erts/emulator/beam/erl_trace.c62
-rw-r--r--erts/emulator/beam/erl_trace.h8
-rw-r--r--erts/emulator/beam/global.h42
-rw-r--r--erts/emulator/sys/unix/sys_drivers.c26
-rw-r--r--erts/emulator/test/node_container_SUITE.erl44
-rw-r--r--erts/emulator/test/socket_SUITE.erl71
-rw-r--r--erts/etc/unix/etp-commands.in75
-rw-r--r--lib/kernel/test/interactive_shell_SUITE.erl60
-rw-r--r--lib/kernel/test/interactive_shell_SUITE_data/.gitignore1
-rw-r--r--lib/kernel/test/interactive_shell_SUITE_data/io_columns.erl6
-rw-r--r--lib/kernel/test/interactive_shell_SUITE_data/io_rows.erl6
-rw-r--r--lib/snmp/src/manager/snmpm.erl11
-rw-r--r--lib/snmp/src/manager/snmpm_supervisor.erl39
-rw-r--r--lib/snmp/test/snmp_agent_test_lib.erl13
-rw-r--r--lib/snmp/test/snmp_manager_test.erl65
-rw-r--r--lib/snmp/test/snmp_test_lib.erl5
-rw-r--r--lib/ssl/doc/src/ssl.xml23
-rw-r--r--lib/ssl/src/dtls_handshake.erl3
-rw-r--r--lib/ssl/src/ssl.erl10
-rw-r--r--lib/ssl/src/ssl_cipher.erl30
-rw-r--r--lib/ssl/src/ssl_connection.erl11
-rw-r--r--lib/ssl/src/ssl_handshake.erl154
-rw-r--r--lib/ssl/src/tls_handshake.erl4
-rw-r--r--lib/ssl/src/tls_handshake_1_3.erl71
-rw-r--r--lib/ssl/src/tls_handshake_1_3.hrl47
-rw-r--r--lib/ssl/src/tls_record_1_3.erl9
-rw-r--r--lib/ssl/test/Makefile27
-rw-r--r--lib/ssl/test/openssl_alpn_SUITE.erl417
-rw-r--r--lib/ssl/test/openssl_cipher_suite_SUITE.erl (renamed from lib/ssl/test/openssl_server_cipher_suite_SUITE.erl)40
-rw-r--r--lib/ssl/test/openssl_client_cert_SUITE.erl331
-rw-r--r--lib/ssl/test/openssl_npn_SUITE.erl304
-rw-r--r--lib/ssl/test/openssl_reject_SUITE.erl209
-rw-r--r--lib/ssl/test/openssl_renegotiate_SUITE.erl341
-rw-r--r--lib/ssl/test/openssl_server_cert_SUITE.erl366
-rw-r--r--lib/ssl/test/openssl_session_SUITE.erl262
-rw-r--r--lib/ssl/test/openssl_sni_SUITE.erl251
-rw-r--r--lib/ssl/test/openssl_tls_1_3_version_SUITE.erl172
-rw-r--r--lib/ssl/test/property_test/ssl_eqc_handshake.erl105
-rw-r--r--lib/ssl/test/ssl_alert_SUITE.erl100
-rw-r--r--lib/ssl/test/ssl_alpn_SUITE.erl (renamed from lib/ssl/test/ssl_alpn_handshake_SUITE.erl)28
-rw-r--r--lib/ssl/test/ssl_api_SUITE.erl1976
-rw-r--r--lib/ssl/test/ssl_api_SUITE_data/dHParam.pem (renamed from lib/ssl/test/ssl_basic_SUITE_data/dHParam.pem)0
-rw-r--r--lib/ssl/test/ssl_app_env_SUITE.erl171
-rw-r--r--lib/ssl/test/ssl_basic_SUITE.erl6841
-rw-r--r--lib/ssl/test/ssl_bench_SUITE.erl7
-rw-r--r--lib/ssl/test/ssl_cert_SUITE.erl547
-rw-r--r--lib/ssl/test/ssl_cert_tests.erl371
-rw-r--r--lib/ssl/test/ssl_certificate_verify_SUITE.erl612
-rw-r--r--lib/ssl/test/ssl_cipher_suite_SUITE.erl20
-rw-r--r--lib/ssl/test/ssl_handshake_SUITE.erl2
-rw-r--r--lib/ssl/test/ssl_npn_SUITE.erl (renamed from lib/ssl/test/ssl_npn_handshake_SUITE.erl)2
-rw-r--r--lib/ssl/test/ssl_npn_hello_SUITE.erl9
-rw-r--r--lib/ssl/test/ssl_pem_cache_SUITE.erl55
-rw-r--r--lib/ssl/test/ssl_renegotiate_SUITE.erl499
-rw-r--r--lib/ssl/test/ssl_session_SUITE.erl377
-rw-r--r--lib/ssl/test/ssl_sni_SUITE.erl68
-rw-r--r--lib/ssl/test/ssl_socket_SUITE.erl437
-rw-r--r--lib/ssl/test/ssl_test_lib.erl284
-rw-r--r--lib/ssl/test/ssl_to_openssl_SUITE.erl2021
-rw-r--r--lib/ssl/test/tls_1_3_record_SUITE.erl973
-rw-r--r--lib/ssl/test/tls_1_3_version_SUITE.erl153
-rw-r--r--lib/ssl/test/tls_api_SUITE.erl880
86 files changed, 11214 insertions, 9781 deletions
diff --git a/erts/doc/src/socket.xml b/erts/doc/src/socket.xml
index da049b1a7f..2f7ff2fc07 100644
--- a/erts/doc/src/socket.xml
+++ b/erts/doc/src/socket.xml
@@ -47,14 +47,16 @@
<seealso marker="#recv_async"><c>recv/3</c></seealso>
function with Timeout set to <c>nowait</c> (<c>recv(Sock, 0, nowait)</c>)
when there is actually nothing to read, it will return with
- <c>{ok, </c>
- <seealso marker="#type-select_info"><c>SelectInfo</c></seealso><c>}</c>.
+ <c>{select, </c>
+ <seealso marker="#type-select_info"><c>SelectInfo</c></seealso><c>}</c>
+ (<c>SelectInfo</c> contains the
+ <seealso marker="socket#type-select_ref">SelectRef</seealso>).
When data eventually arrives a 'select' message
will be sent to the caller: </p>
<taglist>
<!-- NOTE THAT THE EMPTY TAG IS INTENTIONAL -->
<tag></tag>
- <item><c>{'$socket', socket(), select, select_ref()}</c></item>
+ <item><c>{'$socket', socket(), select, SelectRef}</c></item>
</taglist>
<p>The caller can now make another
call to the recv function and now expect data.</p>
@@ -70,7 +72,7 @@
<p>This message indicates
that the (asynchronous) operation has been aborted.
If, for instance, the socket has been closed (by another process),
- <c>Info</c> will be <c>{select_ref(), closed}</c>. </p>
+ <c>Info</c> will be <c>{SelectRef, closed}</c>. </p>
</note>
<note>
<p>There is currently <em>no</em> support for Windows. </p>
@@ -338,7 +340,9 @@
<p>In the case when there is no connections waiting, the function
will return with the <c>SelectInfo</c>. The caller can then await a
select message, <c>{'$socket', Socket, select, Info}</c> (where
- <c>Info</c> is the <c>select_ref()</c> from the <c>SelectInfo</c>),
+ <c>Info</c> is the
+ <seealso marker="socket#type-select_ref"><c>ref</c></seealso>
+ field from the <c>SelectInfo</c>),
when a client connects (a subsequent call to accept will then return
the socket). </p>
</desc>
@@ -410,7 +414,9 @@
<seealso marker="#type-select_info"><c>SelectInfo</c></seealso>.
The caller can then await a
select message, <c>{'$socket', Socket, select, Info}</c> (where
- <c>Info</c> is the <c>select_ref()</c> from the <c>SelectInfo</c>,
+ <c>Info</c> is the
+ <seealso marker="socket#type-select_ref"><c>ref</c></seealso>
+ field from the <c>SelectInfo</c>,
a subsequent call to connect will then
establish the connection). </p>
</desc>
@@ -551,7 +557,9 @@
<p>In the case when there is no data waiting, the function
will return with the <c>SelectInfo</c>. The caller can then await a
select message, <c>{'$socket', Socket, select, Info}</c> (where
- <c>Info</c> is the <c>select_ref()</c> from the <c>SelectInfo</c>),
+ <c>Info</c> is the
+ <seealso marker="socket#type-select_ref"><c>ref</c></seealso>
+ field from the <c>SelectInfo</c>),
when data has arrived (a subsequent call to recv will then return
the data). </p>
<p>Note that if a length (<c>> 0</c>) is specified, and only part
@@ -610,7 +618,9 @@
<p>In the case when there is no data waiting, the function
will return with the <c>SelectInfo</c>. The caller can then await a
select message, <c>{'$socket', Socket, select, Info}</c> (where
- <c>Info</c> is the <c>select_ref()</c> from the <c>SelectInfo</c>),
+ <c>Info</c> is the
+ <seealso marker="socket#type-select_ref"><c>ref</c></seealso>
+ field from the <c>SelectInfo</c>),
when data has arrived (a subsequent call to recvfrom will then return
the data). </p>
</desc>
@@ -686,7 +696,9 @@
<p>In the case when there is no data waiting, the function
will return with the <c>SelectInfo</c>. The caller can then await a
select message, <c>{'$socket', Socket, select, Info}</c> (where
- <c>Info</c> is the <c>select_ref()</c> from the <c>SelectInfo</c>),
+ <c>Info</c> is the
+ <seealso marker="socket#type-select_ref"><c>ref</c></seealso>
+ field from the <c>SelectInfo</c>),
when data has arrived (a subsequent call to recvmsg will then return
the data). </p>
</desc>
@@ -714,7 +726,9 @@
the function will return with the <c>SelectInfo</c>. The caller
can then await a select message,
<c>{'$socket', Socket, select, Info}</c>
- (where <c>Info</c> is the <c>select_ref()</c> from the
+ (where <c>Info</c> is the
+ <seealso marker="socket#type-select_ref"><c>ref</c></seealso>
+ field from the
<c>SelectInfo</c>), when there is room for more data (a subsequent
call to send will then send the data). </p>
<p>Note that if not all the data was sent, the function will return
@@ -772,7 +786,9 @@
the function will return with the <c>SelectInfo</c>. The caller
can then await a select message,
<c>{'$socket', Socket, select, Info}</c>
- (where <c>Info</c> is the <c>select_ref()</c> from the
+ (where <c>Info</c> is the
+ <seealso marker="socket#type-select_ref"><c>ref</c></seealso>
+ field from the
<c>SelectInfo</c>), when there is room for more data (a subsequent
call to sendmsg will then send the data). </p>
</desc>
@@ -800,7 +816,9 @@
the function will return with the <c>SelectInfo</c>. The caller
can then await a select message,
<c>{'$socket', Socket, select, Info}</c>
- (where <c>Info</c> is the <c>select_ref()</c> from the
+ (where <c>Info</c> is the
+ <seealso marker="socket#type-select_ref"><c>ref</c></seealso>
+ field from the
<c>SelectInfo</c>), when there is room for more data (a subsequent
call to sendto will then send the data). </p>
</desc>
diff --git a/erts/doc/src/socket_usage.xml b/erts/doc/src/socket_usage.xml
index 2d0865d45f..dd54e51813 100644
--- a/erts/doc/src/socket_usage.xml
+++ b/erts/doc/src/socket_usage.xml
@@ -56,14 +56,16 @@
function with Timeout set to <c>nowait</c> (i.e.
<c>recv(Sock, 0, nowait)</c>)
when there is actually nothing to read, it will return with
- <c>{ok, </c>
- <seealso marker="socket#type-select_info"><c>SelectInfo</c></seealso><c>}</c>.
+ <c>{select, </c>
+ <seealso marker="socket#type-select_info"><c>SelectInfo</c></seealso><c>}</c>
+ (<c>SelectInfo</c> contains the
+ <seealso marker="socket#type-select_ref">SelectRef</seealso>).
When data eventually arrives a 'select message'
will be sent to the caller:</p>
<taglist>
<!-- NOTE THAT THE EMPTY TAG IS INTENTIONAL -->
<tag></tag>
- <item><c>{'$socket', socket(), select, select_ref()}</c></item>
+ <item><c>{'$socket', socket(), select, SelectRef}</c></item>
</taglist>
<p>The caller can then make another
call to the recv function and now expect data.</p>
@@ -81,7 +83,7 @@
<p>If the operation is aborted
for whatever reason (e.g. if the socket is closed "by someone else").
The <c>Info</c> part contains the abort reason (in this case that
- the socket has been closed <c>Info = {select_ref(), closed}</c>). </p>
+ the socket has been closed <c>Info = {SelectRef, closed}</c>). </p>
<p>Note that all other users are <em>locked out</em> until the
'current user' has called the function (recv in this case). So either
immediately call the function or
@@ -224,7 +226,7 @@
<cell>integer()</cell>
<cell>yes</cell>
<cell>yes</cell>
- <cell>requires admin capability</cell>
+ <cell>may require admin capability</cell>
</row>
<row>
<cell>domain</cell>
diff --git a/erts/emulator/beam/beam_bif_load.c b/erts/emulator/beam/beam_bif_load.c
index bb1b2e5b27..4c8ee5178a 100644
--- a/erts/emulator/beam/beam_bif_load.c
+++ b/erts/emulator/beam/beam_bif_load.c
@@ -1799,6 +1799,78 @@ erts_queue_release_literals(Process* c_p, ErtsLiteralArea* literals)
}
}
+struct debug_la_oh {
+ void (*func)(ErlOffHeap *, void *);
+ void *arg;
+};
+
+static void debug_later_cleanup_literal_area_off_heap(void *vfap,
+ ErtsThrPrgrVal val,
+ void *vlrlap)
+{
+ struct debug_la_oh *fap = vfap;
+ ErtsLaterReleasLiteralArea *lrlap = vlrlap;
+ ErtsLiteralArea *lap = lrlap->la;
+ if (!erts_debug_have_accessed_literal_area(lap)) {
+ ErlOffHeap oh;
+ ERTS_INIT_OFF_HEAP(&oh);
+ oh.first = lap->off_heap;
+ (*fap->func)(&oh, fap->arg);
+ erts_debug_save_accessed_literal_area(lap);
+ }
+}
+
+static void debug_later_complete_literal_area_switch_off_heap(void *vfap,
+ ErtsThrPrgrVal val,
+ void *vlap)
+{
+ struct debug_la_oh *fap = vfap;
+ ErtsLiteralArea *lap = vlap;
+ if (lap && !erts_debug_have_accessed_literal_area(lap)) {
+ ErlOffHeap oh;
+ ERTS_INIT_OFF_HEAP(&oh);
+ oh.first = lap->off_heap;
+ (*fap->func)(&oh, fap->arg);
+ erts_debug_save_accessed_literal_area(lap);
+ }
+}
+
+
+void
+erts_debug_foreach_release_literal_area_off_heap(void (*func)(ErlOffHeap *, void *), void *arg)
+{
+ ErtsLiteralArea *lap;
+ ErlOffHeap oh;
+ ErtsLiteralAreaRef *ref;
+ struct debug_la_oh fa;
+ erts_mtx_lock(&release_literal_areas.mtx);
+ for (ref = release_literal_areas.first; ref; ref = ref->next) {
+ lap = ref->literal_area;
+ if (!erts_debug_have_accessed_literal_area(lap)) {
+ ERTS_INIT_OFF_HEAP(&oh);
+ oh.first = lap->off_heap;
+ (*func)(&oh, arg);
+ erts_debug_save_accessed_literal_area(lap);
+ }
+ }
+ erts_mtx_unlock(&release_literal_areas.mtx);
+ lap = ERTS_COPY_LITERAL_AREA();
+ if (lap && !erts_debug_have_accessed_literal_area(lap)) {
+ ERTS_INIT_OFF_HEAP(&oh);
+ oh.first = lap->off_heap;
+ (*func)(&oh, arg);
+ erts_debug_save_accessed_literal_area(lap);
+ }
+ fa.func = func;
+ fa.arg = arg;
+ erts_debug_later_op_foreach(later_release_literal_area,
+ debug_later_cleanup_literal_area_off_heap,
+ (void *) &fa);
+ erts_debug_later_op_foreach(complete_literal_area_switch,
+ debug_later_complete_literal_area_switch_off_heap,
+ (void *) &fa);
+}
+
/*
* Move code from current to old and null all export entries for the module
*/
diff --git a/erts/emulator/beam/copy.c b/erts/emulator/beam/copy.c
index db74b06cc5..9bbcba6f3b 100644
--- a/erts/emulator/beam/copy.c
+++ b/erts/emulator/beam/copy.c
@@ -604,7 +604,12 @@ cleanup:
/*
* Copy a structure to a heap.
*/
-Eterm copy_struct_x(Eterm obj, Uint sz, Eterm** hpp, ErlOffHeap* off_heap, Uint *bsz, erts_literal_area_t *litopt)
+Eterm copy_struct_x(Eterm obj, Uint sz, Eterm** hpp, ErlOffHeap* off_heap,
+ Uint *bsz, erts_literal_area_t *litopt
+#ifdef ERTS_COPY_REGISTER_LOCATION
+ , char *file, int line
+#endif
+ )
{
char* hstart;
Uint hsize;
@@ -854,7 +859,11 @@ Eterm copy_struct_x(Eterm obj, Uint sz, Eterm** hpp, ErlOffHeap* off_heap, Uint
case EXTERNAL_REF_SUBTAG:
{
ExternalThing *etp = (ExternalThing *) objp;
+#if defined(ERTS_COPY_REGISTER_LOCATION) && defined(ERL_NODE_BOOKKEEP)
+ erts_ref_node_entry__(etp->node, 2, make_boxed(htop), file, line);
+#else
erts_ref_node_entry(etp->node, 2, make_boxed(htop));
+#endif
}
L_off_heap_node_container_common:
{
@@ -1326,8 +1335,13 @@ Uint copy_shared_calculate(Eterm obj, erts_shcopy_t *info)
* Copy object "obj" preserving sharing.
* Second half: copy and restore the object.
*/
-Uint copy_shared_perform(Eterm obj, Uint size, erts_shcopy_t *info,
- Eterm** hpp, ErlOffHeap* off_heap) {
+Uint copy_shared_perform_x(Eterm obj, Uint size, erts_shcopy_t *info,
+ Eterm** hpp, ErlOffHeap* off_heap
+#ifdef ERTS_COPY_REGISTER_LOCATION
+ , char *file, int line
+#endif
+ )
+{
Uint e;
unsigned sz;
Eterm* ptr;
@@ -1393,7 +1407,11 @@ Uint copy_shared_perform(Eterm obj, Uint size, erts_shcopy_t *info,
*resp = obj;
} else {
Uint bsz = 0;
- *resp = copy_struct_x(obj, hbot - hp, &hp, off_heap, &bsz, NULL); /* copy literal */
+ *resp = copy_struct_x(obj, hbot - hp, &hp, off_heap, &bsz, NULL
+#ifdef ERTS_COPY_REGISTER_LOCATION
+ , file, line
+#endif
+ ); /* copy literal */
hbot -= bsz;
}
goto cleanup_next;
@@ -1461,7 +1479,11 @@ Uint copy_shared_perform(Eterm obj, Uint size, erts_shcopy_t *info,
*resp = obj;
} else {
Uint bsz = 0;
- *resp = copy_struct_x(obj, hbot - hp, &hp, off_heap, &bsz, NULL); /* copy literal */
+ *resp = copy_struct_x(obj, hbot - hp, &hp, off_heap, &bsz, NULL
+#ifdef ERTS_COPY_REGISTER_LOCATION
+ , file, line
+#endif
+ ); /* copy literal */
hbot -= bsz;
}
goto cleanup_next;
@@ -1660,7 +1682,12 @@ Uint copy_shared_perform(Eterm obj, Uint size, erts_shcopy_t *info,
case EXTERNAL_REF_SUBTAG:
{
ExternalThing *etp = (ExternalThing *) ptr;
+
+#if defined(ERTS_COPY_REGISTER_LOCATION) && defined(ERL_NODE_BOOKKEEP)
+ erts_ref_node_entry__(etp->node, 2, make_boxed(hp), file, line);
+#else
erts_ref_node_entry(etp->node, 2, make_boxed(hp));
+#endif
}
off_heap_node_container_common:
{
@@ -1823,8 +1850,12 @@ all_clean:
*
* NOTE: Assumes that term is a tuple (ptr is an untagged tuple ptr).
*/
-Eterm copy_shallow(Eterm* ERTS_RESTRICT ptr, Uint sz, Eterm** hpp,
- ErlOffHeap* off_heap)
+Eterm
+copy_shallow_x(Eterm* ERTS_RESTRICT ptr, Uint sz, Eterm** hpp, ErlOffHeap* off_heap
+#ifdef ERTS_COPY_REGISTER_LOCATION
+ , char *file, int line
+#endif
+ )
{
Eterm* tp = ptr;
Eterm* hp = *hpp;
@@ -1866,7 +1897,11 @@ Eterm copy_shallow(Eterm* ERTS_RESTRICT ptr, Uint sz, Eterm** hpp,
case EXTERNAL_REF_SUBTAG:
{
ExternalThing* etp = (ExternalThing *) (tp-1);
+#if defined(ERTS_COPY_REGISTER_LOCATION) && defined(ERL_NODE_BOOKKEEP)
+ erts_ref_node_entry__(etp->node, 2, make_boxed(hp-1), file, line);
+#else
erts_ref_node_entry(etp->node, 2, make_boxed(hp-1));
+#endif
}
off_heap_common:
{
diff --git a/erts/emulator/beam/dist.c b/erts/emulator/beam/dist.c
index 4537e3e569..eb9e749a08 100644
--- a/erts/emulator/beam/dist.c
+++ b/erts/emulator/beam/dist.c
@@ -1266,18 +1266,6 @@ erts_dsig_send_group_leader(ErtsDSigSendContext *ctx, Eterm leader, Eterm remote
return dsig_send_ctl(ctx, ctl);
}
-struct dist_sequences {
- ErlHeapFragment hfrag;
- struct dist_sequences *parent;
- struct dist_sequences *left;
- struct dist_sequences *right;
- char is_red;
-
- Uint64 seq_id;
- int cnt;
- Sint ctl_len;
-};
-
#define ERTS_RBT_PREFIX dist_seq
#define ERTS_RBT_T DistSeqNode
#define ERTS_RBT_KEY_T Uint
@@ -1312,25 +1300,25 @@ struct dist_sequences {
#include "erl_rbtree.h"
-struct erts_dist_seq_tree_foreach_iter_arg {
- int (*func)(ErtsDistExternal *, void *, Sint);
+struct erts_debug_dist_seq_tree_foreach_iter_arg {
+ int (*func)(DistSeqNode *, void *, Sint);
void *arg;
};
static int
-erts_dist_seq_tree_foreach_iter(DistSeqNode *seq, void *arg, Sint reds)
+erts_debug_dist_seq_tree_foreach_iter(DistSeqNode *seq, void *arg, Sint reds)
{
- struct erts_dist_seq_tree_foreach_iter_arg *state = arg;
- return state->func(erts_get_dist_ext(&seq->hfrag), state->arg, reds);
+ struct erts_debug_dist_seq_tree_foreach_iter_arg *state = arg;
+ return state->func(seq, state->arg, reds);
}
void
-erts_dist_seq_tree_foreach(DistEntry *dep, int (*func)(ErtsDistExternal *, void *, Sint), void *arg)
+erts_debug_dist_seq_tree_foreach(DistEntry *dep, int (*func)(DistSeqNode *, void *, Sint), void *arg)
{
- struct erts_dist_seq_tree_foreach_iter_arg state;
+ struct erts_debug_dist_seq_tree_foreach_iter_arg state;
state.func = func;
state.arg = arg;
- dist_seq_rbt_foreach(dep->sequences, erts_dist_seq_tree_foreach_iter, &state);
+ dist_seq_rbt_foreach(dep->sequences, erts_debug_dist_seq_tree_foreach_iter, &state);
}
static int dist_seq_cleanup(DistSeqNode *seq, void *unused, Sint reds)
diff --git a/erts/emulator/beam/dist.h b/erts/emulator/beam/dist.h
index 067028634b..a33fb7efcf 100644
--- a/erts/emulator/beam/dist.h
+++ b/erts/emulator/beam/dist.h
@@ -274,6 +274,18 @@ typedef struct erts_dsig_send_context {
typedef struct dist_sequences DistSeqNode;
+struct dist_sequences {
+ ErlHeapFragment hfrag;
+ struct dist_sequences *parent;
+ struct dist_sequences *left;
+ struct dist_sequences *right;
+ char is_red;
+
+ Uint64 seq_id;
+ int cnt;
+ Sint ctl_len;
+};
+
/*
* erts_dsig_send_* return values.
*/
@@ -306,9 +318,9 @@ extern Uint erts_dist_cache_size(void);
extern Sint erts_abort_connection_rwunlock(DistEntry *dep);
-extern void erts_dist_seq_tree_foreach(
+extern void erts_debug_dist_seq_tree_foreach(
DistEntry *dep,
- int (*func)(ErtsDistExternal *, void*, Sint), void *args);
+ int (*func)(DistSeqNode *, void*, Sint), void *args);
extern int erts_dsig_prepare(ErtsDSigSendContext *,
DistEntry*,
diff --git a/erts/emulator/beam/erl_alloc.types b/erts/emulator/beam/erl_alloc.types
index 92e5069c71..21941ba96e 100644
--- a/erts/emulator/beam/erl_alloc.types
+++ b/erts/emulator/beam/erl_alloc.types
@@ -149,6 +149,7 @@ type MODULE_TABLE LONG_LIVED CODE module_tab
type TAINT LONG_LIVED CODE taint_list
type MODULE_REFS STANDARD CODE module_refs
type NC_TMP TEMPORARY SYSTEM nc_tmp
+type NC_STD STANDARD SYSTEM nc_std
type TMP TEMPORARY SYSTEM tmp
type UNDEF SYSTEM SYSTEM undefined
type DCACHE STANDARD SYSTEM dcache
diff --git a/erts/emulator/beam/erl_bif_persistent.c b/erts/emulator/beam/erl_bif_persistent.c
index f38e0cc5cb..8662a9e33a 100644
--- a/erts/emulator/beam/erl_bif_persistent.c
+++ b/erts/emulator/beam/erl_bif_persistent.c
@@ -1234,3 +1234,102 @@ next_to_delete(void)
erts_mtx_unlock(&delete_queue_mtx);
return table;
}
+
+/*
+ * test/debug functionality follow...
+ */
+
+static Uint accessed_literal_areas_size;
+static Uint accessed_no_literal_areas;
+static ErtsLiteralArea **accessed_literal_areas;
+
+int
+erts_debug_have_accessed_literal_area(ErtsLiteralArea *lap)
+{
+ Uint i;
+ for (i = 0; i < accessed_no_literal_areas; i++) {
+ if (accessed_literal_areas[i] == lap)
+ return !0;
+ }
+ return 0;
+}
+
+void
+erts_debug_save_accessed_literal_area(ErtsLiteralArea *lap)
+{
+ if (accessed_no_literal_areas == accessed_literal_areas_size) {
+ accessed_literal_areas_size += 10;
+ accessed_literal_areas = erts_realloc(ERTS_ALC_T_TMP,
+ accessed_literal_areas,
+ (sizeof(ErtsLiteralArea *)
+ *accessed_literal_areas_size));
+ }
+ accessed_literal_areas[accessed_no_literal_areas++] = lap;
+}
+
+static void debug_foreach_off_heap(HashTable *tbl, void (*func)(ErlOffHeap *, void *), void *arg)
+{
+ int i;
+
+ for (i = 0; i < tbl->allocated; i++) {
+ Eterm term = tbl->term[i];
+ if (is_tuple_arity(term, 2)) {
+ ErtsLiteralArea *lap = term_to_area(term);
+ ErlOffHeap oh;
+ if (!erts_debug_have_accessed_literal_area(lap)) {
+ ERTS_INIT_OFF_HEAP(&oh);
+ oh.first = lap->off_heap;
+ (*func)(&oh, arg);
+ erts_debug_save_accessed_literal_area(lap);
+ }
+ }
+ }
+}
+
+struct debug_la_oh {
+ void (*func)(ErlOffHeap *, void *);
+ void *arg;
+};
+
+static void debug_handle_table(void *vfap,
+ ErtsThrPrgrVal val,
+ void *vtbl)
+{
+ struct debug_la_oh *fap = vfap;
+ HashTable *tbl = vtbl;
+ debug_foreach_off_heap(tbl, fap->func, fap->arg);
+}
+
+void
+erts_debug_foreach_persistent_term_off_heap(void (*func)(ErlOffHeap *, void *), void *arg)
+{
+ HashTable *tbl;
+ struct debug_la_oh fa;
+ accessed_no_literal_areas = 0;
+ accessed_literal_areas_size = 10;
+ accessed_literal_areas = erts_alloc(ERTS_ALC_T_TMP,
+ (sizeof(ErtsLiteralArea *)
+ * accessed_literal_areas_size));
+
+ tbl = (HashTable *) erts_atomic_read_nob(&the_hash_table);
+ debug_foreach_off_heap(tbl, func, arg);
+ erts_mtx_lock(&delete_queue_mtx);
+ for (tbl = delete_queue_head; tbl; tbl = tbl->delete_next)
+ debug_foreach_off_heap(tbl, func, arg);
+ erts_mtx_unlock(&delete_queue_mtx);
+ fa.func = func;
+ fa.arg = arg;
+ erts_debug_later_op_foreach(table_updater,
+ debug_handle_table,
+ (void *) &fa);
+ erts_debug_later_op_foreach(table_deleter,
+ debug_handle_table,
+ (void *) &fa);
+ erts_debug_foreach_release_literal_area_off_heap(func, arg);
+
+ erts_free(ERTS_ALC_T_TMP, accessed_literal_areas);
+ accessed_no_literal_areas = 0;
+ accessed_literal_areas_size = 0;
+ accessed_literal_areas = NULL;
+}
+
diff --git a/erts/emulator/beam/erl_db.c b/erts/emulator/beam/erl_db.c
index d24f30f126..3c74ef493b 100644
--- a/erts/emulator/beam/erl_db.c
+++ b/erts/emulator/beam/erl_db.c
@@ -4415,7 +4415,7 @@ void db_info(fmtfn_t to, void *to_arg, int show) /* Called by break handler *
pdbi.to_arg = to_arg;
pdbi.show = show;
- erts_db_foreach_table(db_info_print, &pdbi);
+ erts_db_foreach_table(db_info_print, &pdbi, !0);
}
Uint
@@ -4428,7 +4428,7 @@ erts_get_ets_misc_mem_size(void)
/* SMP Note: May only be used when system is locked */
void
-erts_db_foreach_table(void (*func)(DbTable *, void *), void *arg)
+erts_db_foreach_table(void (*func)(DbTable *, void *), void *arg, int alive_only)
{
int ix;
@@ -4440,7 +4440,7 @@ erts_db_foreach_table(void (*func)(DbTable *, void *), void *arg)
if (first) {
DbTable *tb = first;
do {
- if (is_table_alive(tb))
+ if (!alive_only || is_table_alive(tb))
(*func)(tb, arg);
tb = tb->common.all.next;
} while (tb != first);
@@ -4457,6 +4457,15 @@ erts_db_foreach_offheap(DbTable *tb,
tb->common.meth->db_foreach_offheap(tb, func, arg);
}
+void
+erts_db_foreach_thr_prgr_offheap(void (*func)(ErlOffHeap *, void *),
+ void *arg)
+{
+ erts_db_foreach_thr_prgr_offheap_hash(func, arg);
+ erts_db_foreach_thr_prgr_offheap_tree(func, arg);
+ erts_db_foreach_thr_prgr_offheap_catree(func, arg);
+}
+
/* retrieve max number of ets tables */
Uint
erts_db_get_max_tabs()
diff --git a/erts/emulator/beam/erl_db.h b/erts/emulator/beam/erl_db.h
index b3dc1b9ba3..c604744687 100644
--- a/erts/emulator/beam/erl_db.h
+++ b/erts/emulator/beam/erl_db.h
@@ -114,10 +114,12 @@ void init_db(ErtsDbSpinCount);
int erts_db_process_exiting(Process *, ErtsProcLocks, void **);
int erts_db_execute_free_fixation(Process*, DbFixation*);
void db_info(fmtfn_t, void *, int);
-void erts_db_foreach_table(void (*)(DbTable *, void *), void *);
+void erts_db_foreach_table(void (*)(DbTable *, void *), void *, int);
void erts_db_foreach_offheap(DbTable *,
void (*func)(ErlOffHeap *, void *),
void *);
+void erts_db_foreach_thr_prgr_offheap(void (*func)(ErlOffHeap *, void *),
+ void *);
extern int erts_ets_rwmtx_spin_count;
extern int user_requested_db_max_tabs; /* set in erl_init */
diff --git a/erts/emulator/beam/erl_db_catree.c b/erts/emulator/beam/erl_db_catree.c
index fed4b44a9b..8a89eb72df 100644
--- a/erts/emulator/beam/erl_db_catree.c
+++ b/erts/emulator/beam/erl_db_catree.c
@@ -2395,6 +2395,34 @@ void db_calc_stats_catree(DbTableCATree* tb, DbCATreeStats* stats)
} while (depth > 0);
}
+struct debug_catree_fa {
+ void (*func)(ErlOffHeap *, void *);
+ void *arg;
+};
+
+static void debug_free_route_node(void *vfap, ErtsThrPrgrVal val, void *vnp)
+{
+ DbTableCATreeNode *np = vnp;
+ if (np->u.route.key.oh) {
+ struct debug_catree_fa *fap = vfap;
+ ErlOffHeap oh;
+ ERTS_INIT_OFF_HEAP(&oh);
+ oh.first = np->u.route.key.oh;
+ (*fap->func)(&oh, fap->arg);
+ }
+}
+
+void
+erts_db_foreach_thr_prgr_offheap_catree(void (*func)(ErlOffHeap *, void *),
+ void *arg)
+{
+ struct debug_catree_fa fa;
+ fa.func = func;
+ fa.arg = arg;
+ erts_debug_later_op_foreach(do_free_route_node, debug_free_route_node, &fa);
+}
+
+
#ifdef HARDDEBUG
/*
diff --git a/erts/emulator/beam/erl_db_catree.h b/erts/emulator/beam/erl_db_catree.h
index c2c884eee3..2ede85e04e 100644
--- a/erts/emulator/beam/erl_db_catree.h
+++ b/erts/emulator/beam/erl_db_catree.h
@@ -132,6 +132,9 @@ typedef struct {
Uint max_depth;
} DbCATreeStats;
void db_calc_stats_catree(DbTableCATree*, DbCATreeStats*);
+void
+erts_db_foreach_thr_prgr_offheap_catree(void (*func)(ErlOffHeap *, void *),
+ void *arg);
#endif /* _DB_CATREE_H */
diff --git a/erts/emulator/beam/erl_db_hash.c b/erts/emulator/beam/erl_db_hash.c
index ceaccf7e44..4904d3fa42 100644
--- a/erts/emulator/beam/erl_db_hash.c
+++ b/erts/emulator/beam/erl_db_hash.c
@@ -3262,6 +3262,12 @@ Eterm erts_ets_hash_sizeof_ext_segtab(void)
return make_small(((SIZEOF_EXT_SEGTAB(0)-1) / sizeof(UWord)) + 1);
}
+void
+erts_db_foreach_thr_prgr_offheap_hash(void (*func)(ErlOffHeap *, void *),
+ void *arg)
+{
+}
+
#ifdef ERTS_ENABLE_LOCK_COUNT
void erts_lcnt_enable_db_hash_lock_count(DbTableHash *tb, int enable) {
int i;
diff --git a/erts/emulator/beam/erl_db_hash.h b/erts/emulator/beam/erl_db_hash.h
index eae5537ba4..9759d8b466 100644
--- a/erts/emulator/beam/erl_db_hash.h
+++ b/erts/emulator/beam/erl_db_hash.h
@@ -110,6 +110,9 @@ typedef struct {
void db_calc_stats_hash(DbTableHash* tb, DbHashStats*);
Eterm erts_ets_hash_sizeof_ext_segtab(void);
+void
+erts_db_foreach_thr_prgr_offheap_hash(void (*func)(ErlOffHeap *, void *),
+ void *arg);
#ifdef ERTS_ENABLE_LOCK_COUNT
void erts_lcnt_enable_db_hash_lock_count(DbTableHash *tb, int enable);
diff --git a/erts/emulator/beam/erl_db_tree.c b/erts/emulator/beam/erl_db_tree.c
index 492ea81b63..19b94b0634 100644
--- a/erts/emulator/beam/erl_db_tree.c
+++ b/erts/emulator/beam/erl_db_tree.c
@@ -3936,6 +3936,12 @@ static int doit_select_replace(DbTableCommon *tb, TreeDbTerm **this,
return 1;
}
+void
+erts_db_foreach_thr_prgr_offheap_tree(void (*func)(ErlOffHeap *, void *),
+ void *arg)
+{
+}
+
#ifdef TREE_DEBUG
static void do_dump_tree2(DbTableCommon* tb, int to, void *to_arg, int show,
TreeDbTerm *t, int offset)
diff --git a/erts/emulator/beam/erl_db_tree.h b/erts/emulator/beam/erl_db_tree.h
index 54da2a6bc1..06e0005801 100644
--- a/erts/emulator/beam/erl_db_tree.h
+++ b/erts/emulator/beam/erl_db_tree.h
@@ -53,4 +53,8 @@ void db_initialize_tree(void);
int db_create_tree(Process *p, DbTable *tbl);
+void
+erts_db_foreach_thr_prgr_offheap_tree(void (*func)(ErlOffHeap *, void *),
+ void *arg);
+
#endif /* _DB_TREE_H */
diff --git a/erts/emulator/beam/erl_gc.c b/erts/emulator/beam/erl_gc.c
index 7ab8034606..13b1f8ab4d 100644
--- a/erts/emulator/beam/erl_gc.c
+++ b/erts/emulator/beam/erl_gc.c
@@ -2887,7 +2887,7 @@ sweep_off_heap(Process *p, int fullsweep)
if (is_external_header(((struct erl_off_heap_header*) boxed_val(ptr->thing_word))->thing_word))
erts_node_bookkeep(((ExternalThing*)ptr)->node,
make_boxed(&ptr->thing_word),
- ERL_NODE_DEC);
+ ERL_NODE_DEC, __FILE__, __LINE__);
*prev = ptr = (struct erl_off_heap_header*) boxed_val(ptr->thing_word);
ASSERT(!IS_MOVED_BOXED(ptr->thing_word));
switch (ptr->thing_word) {
@@ -2918,7 +2918,7 @@ sweep_off_heap(Process *p, int fullsweep)
if (is_external_header(ptr->thing_word)) {
erts_node_bookkeep(((ExternalThing*)ptr)->node,
make_boxed(&ptr->thing_word),
- ERL_NODE_INC);
+ ERL_NODE_INC, __FILE__, __LINE__);
}
prev = &ptr->next;
ptr = ptr->next;
@@ -3089,9 +3089,11 @@ offset_heap(Eterm* hp, Uint sz, Sint offs, char* area, Uint area_size)
if (is_external_header(oh->thing_word)) {
erts_node_bookkeep(((ExternalThing*)oh)->node,
- make_boxed(((Eterm*)oh)-offs), ERL_NODE_DEC);
+ make_boxed(((Eterm*)oh)-offs),
+ ERL_NODE_DEC, __FILE__, __LINE__);
erts_node_bookkeep(((ExternalThing*)oh)->node,
- make_boxed((Eterm*)oh), ERL_NODE_INC);
+ make_boxed((Eterm*)oh), ERL_NODE_INC,
+ __FILE__, __LINE__);
}
if (ErtsInArea(oh->next, area, area_size)) {
diff --git a/erts/emulator/beam/erl_monitor_link.c b/erts/emulator/beam/erl_monitor_link.c
index 1c6b4afaa3..43028be39d 100644
--- a/erts/emulator/beam/erl_monitor_link.c
+++ b/erts/emulator/beam/erl_monitor_link.c
@@ -671,6 +671,24 @@ erts_monitor_tree_foreach(ErtsMonitor *root,
arg);
}
+void
+erts_debug_monitor_tree_destroying_foreach(ErtsMonitor *root,
+ ErtsMonitorFunc func,
+ void *arg,
+ void *vysp)
+{
+ void *tmp_vysp = erts_alloc(ERTS_ALC_T_ML_YIELD_STATE,
+ sizeof(ErtsMonLnkYieldState));
+ Sint reds;
+ sys_memcpy(tmp_vysp, tmp_vysp, sizeof(ErtsMonLnkYieldState));
+ do {
+ reds = ml_rbt_foreach_yielding((ErtsMonLnkNode *) root,
+ (ErtsMonLnkNodeFunc) func,
+ arg, &tmp_vysp, (Sint) INT_MAX);
+ } while (reds <= 0);
+ ERTS_ML_ASSERT(!tmp_vysp);
+}
+
int
erts_monitor_tree_foreach_yielding(ErtsMonitor *root,
ErtsMonitorFunc func,
@@ -716,6 +734,19 @@ erts_monitor_list_foreach(ErtsMonitor *list,
arg, &ystate, (Sint) INT_MAX));
}
+void
+erts_debug_monitor_list_destroying_foreach(ErtsMonitor *list,
+ ErtsMonitorFunc func,
+ void *arg,
+ void *vysp)
+{
+ void *tmp_vysp = vysp;
+ while (!ml_dl_list_foreach_yielding((ErtsMonLnkNode *) list,
+ (int (*)(ErtsMonLnkNode *, void *, Sint)) func,
+ arg, &tmp_vysp, (Sint) INT_MAX));
+ ERTS_ML_ASSERT(!tmp_vysp);
+}
+
int
erts_monitor_list_foreach_yielding(ErtsMonitor *list,
ErtsMonitorFunc func,
@@ -1080,6 +1111,24 @@ erts_link_tree_foreach(ErtsLink *root,
}
+void
+erts_debug_link_tree_destroying_foreach(ErtsLink *root,
+ ErtsLinkFunc func,
+ void *arg,
+ void *vysp)
+{
+ void *tmp_vysp = erts_alloc(ERTS_ALC_T_ML_YIELD_STATE,
+ sizeof(ErtsMonLnkYieldState));
+ Sint reds;
+ sys_memcpy(tmp_vysp, vysp, sizeof(ErtsMonLnkYieldState));
+ do {
+ reds = ml_rbt_foreach_yielding((ErtsMonLnkNode *) root,
+ (ErtsMonLnkNodeFunc) func,
+ arg, &tmp_vysp, (Sint) INT_MAX);
+ } while (reds <= 0);
+ ERTS_ML_ASSERT(!tmp_vysp);
+}
+
int
erts_link_tree_foreach_yielding(ErtsLink *root,
ErtsLinkFunc func,
diff --git a/erts/emulator/beam/erl_monitor_link.h b/erts/emulator/beam/erl_monitor_link.h
index eff861fce8..86be400c09 100644
--- a/erts/emulator/beam/erl_monitor_link.h
+++ b/erts/emulator/beam/erl_monitor_link.h
@@ -1509,6 +1509,17 @@ ERTS_GLB_INLINE ErtsMonitorSuspend *erts_monitor_suspend(ErtsMonitor *mon)
#endif
+void
+erts_debug_monitor_tree_destroying_foreach(ErtsMonitor *root,
+ ErtsMonitorFunc func,
+ void *arg,
+ void *vysp);
+void
+erts_debug_monitor_list_destroying_foreach(ErtsMonitor *list,
+ ErtsMonitorFunc func,
+ void *arg,
+ void *vysp);
+
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *\
* Link Operations *
\* */
@@ -2365,4 +2376,10 @@ erts_link_dist_delete(ErtsLink *lnk)
#endif /* ERTS_GLB_INLINE_INCL_FUNC_DEF */
+void
+erts_debug_link_tree_destroying_foreach(ErtsLink *root,
+ ErtsLinkFunc func,
+ void *arg,
+ void *vysp);
+
#endif /* ERL_MONITOR_LINK_H__ */
diff --git a/erts/emulator/beam/erl_node_tables.c b/erts/emulator/beam/erl_node_tables.c
index 4eb6c3e214..50e9812534 100644
--- a/erts/emulator/beam/erl_node_tables.c
+++ b/erts/emulator/beam/erl_node_tables.c
@@ -932,7 +932,8 @@ static void try_delete_node(void *venp)
*
* If refc > 0, the entry is in use. Keep the entry.
*/
- erts_node_bookkeep(enp, THE_NON_VALUE, ERL_NODE_DEC);
+ erts_node_bookkeep(enp, THE_NON_VALUE, ERL_NODE_DEC,
+ __FILE__, __LINE__);
refc = erts_refc_dectest(&enp->refc, -1);
if (refc == -1)
(void) hash_erase(&erts_node_table, (void *) enp);
@@ -1164,6 +1165,12 @@ void erts_lcnt_update_distribution_locks(int enable) {
* can damage the real-time properties of the system. *
\* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+#ifdef ERL_NODE_BOOKKEEP
+#define ERTS_DBG_NC_ALLOC_TYPE ERTS_ALC_T_NC_STD
+#else
+#define ERTS_DBG_NC_ALLOC_TYPE ERTS_ALC_T_NC_TMP
+#endif
+
#include "erl_db.h"
#undef INIT_AM
@@ -1188,10 +1195,12 @@ static Eterm AM_delayed_delete_timer;
static Eterm AM_thread_progress_delete_timer;
static Eterm AM_sequence;
static Eterm AM_signal;
+static Eterm AM_persistent_term;
static void setup_reference_table(void);
static Eterm reference_table_term(Uint **hpp, ErlOffHeap *ohp, Uint *szp);
static void delete_reference_table(void);
+static void clear_system(void);
#undef ERTS_MAX__
#define ERTS_MAX__(A, B) ((A) > (B) ? (A) : (B))
@@ -1244,11 +1253,11 @@ typedef struct inserted_bin_ {
Binary *bin_val;
} InsertedBin;
-static ReferredNode *referred_nodes;
+static ReferredNode *referred_nodes = NULL;
static int no_referred_nodes;
-static ReferredDist *referred_dists;
+static ReferredDist *referred_dists = NULL;
static int no_referred_dists;
-static InsertedBin *inserted_bins;
+static InsertedBin *inserted_bins = NULL;
Eterm
erts_get_node_and_dist_references(struct process *proc)
@@ -1284,9 +1293,15 @@ erts_get_node_and_dist_references(struct process *proc)
INIT_AM(thread_progress_delete_timer);
INIT_AM(signal);
INIT_AM(sequence);
+ INIT_AM(persistent_term);
references_atoms_need_init = 0;
}
+#ifdef ERL_NODE_BOOKKEEP
+ if (referred_nodes || referred_dists || inserted_bins)
+ delete_reference_table();
+#endif
+
setup_reference_table();
/* Get term size */
@@ -1304,7 +1319,11 @@ erts_get_node_and_dist_references(struct process *proc)
ASSERT(endp == hp);
+#ifndef ERL_NODE_BOOKKEEP
delete_reference_table();
+#endif
+
+ clear_system();
erts_thr_progress_unblock();
erts_proc_lock(proc, ERTS_PROC_LOCK_MAIN);
@@ -1339,7 +1358,7 @@ insert_dist_referrer(ReferredDist *referred_dist,
break;
if(!drp) {
- drp = (DistReferrer *) erts_alloc(ERTS_ALC_T_NC_TMP,
+ drp = (DistReferrer *) erts_alloc(ERTS_DBG_NC_ALLOC_TYPE,
sizeof(DistReferrer));
drp->next = referred_dist->referrers;
referred_dist->referrers = drp;
@@ -1402,7 +1421,7 @@ insert_node_referrer(ReferredNode *referred_node, int type, Eterm id)
break;
if(!nrp) {
- nrp = (NodeReferrer *) erts_alloc(ERTS_ALC_T_NC_TMP,
+ nrp = (NodeReferrer *) erts_alloc(ERTS_DBG_NC_ALLOC_TYPE,
sizeof(NodeReferrer));
nrp->next = referred_node->referrers;
ERTS_INIT_OFF_HEAP(&nrp->off_heap);
@@ -1516,7 +1535,8 @@ insert_offheap(ErlOffHeap *oh, int type, Eterm id)
erts_match_prog_foreach_offheap((Binary *) u.mref->mb,
insert_offheap2,
(void *) &a);
- nib = erts_alloc(ERTS_ALC_T_NC_TMP, sizeof(InsertedBin));
+ nib = erts_alloc(ERTS_DBG_NC_ALLOC_TYPE,
+ sizeof(InsertedBin));
nib->bin_val = (Binary *) u.mref->mb;
nib->next = inserted_bins;
inserted_bins = nib;
@@ -1574,18 +1594,6 @@ static int clear_visited_monitor(ErtsMonitor *mon, void *p, Sint reds)
}
static void
-insert_p_monitors(ErtsPTabElementCommon *p)
-{
- Eterm id = p->id;
- erts_monitor_tree_foreach(p->u.alive.monitors,
- insert_monitor,
- (void *) &id);
- erts_monitor_list_foreach(p->u.alive.lt_monitors,
- insert_monitor,
- (void *) &id);
-}
-
-static void
insert_dist_monitors(DistEntry *dep)
{
if (dep->mld) {
@@ -1600,8 +1608,10 @@ insert_dist_monitors(DistEntry *dep)
static int
-insert_sequence(ErtsDistExternal *edep, void *arg, Sint reds)
+insert_sequence(DistSeqNode *seq, void *arg, Sint reds)
{
+ ErtsDistExternal *edep = erts_get_dist_ext(&seq->hfrag);
+ insert_offheap(&seq->hfrag.off_heap, SEQUENCE_REF, *(Eterm*)arg);
insert_dist_entry(edep->dep, SEQUENCE_REF, *(Eterm*)arg, 0);
return 1;
}
@@ -1609,18 +1619,7 @@ insert_sequence(ErtsDistExternal *edep, void *arg, Sint reds)
static void
insert_dist_sequences(DistEntry *dep)
{
- erts_dist_seq_tree_foreach(dep, insert_sequence, (void *) &dep->sysname);
-}
-
-static void
-clear_visited_p_monitors(ErtsPTabElementCommon *p)
-{
- erts_monitor_tree_foreach(p->u.alive.monitors,
- clear_visited_monitor,
- NULL);
- erts_monitor_list_foreach(p->u.alive.lt_monitors,
- clear_visited_monitor,
- NULL);
+ erts_debug_dist_seq_tree_foreach(dep, insert_sequence, (void *) &dep->sysname);
}
static void
@@ -1667,13 +1666,6 @@ static int clear_visited_link(ErtsLink *lnk, void *p, Sint reds)
}
static void
-insert_p_links(ErtsPTabElementCommon *p)
-{
- Eterm id = p->id;
- erts_link_tree_foreach(p->u.alive.links, insert_link, (void *) &id);
-}
-
-static void
insert_dist_links(DistEntry *dep)
{
if (dep->mld)
@@ -1683,14 +1675,6 @@ insert_dist_links(DistEntry *dep)
}
static void
-clear_visited_p_links(ErtsPTabElementCommon *p)
-{
- erts_link_tree_foreach(p->u.alive.links,
- clear_visited_link,
- NULL);
-}
-
-static void
clear_visited_dist_links(DistEntry *dep)
{
if (dep->mld)
@@ -1885,15 +1869,11 @@ insert_process(Process *proc)
insert_sig_ext,
(void *) proc);
- /* If the process is FREE, the proc->common field has been
- re-used by the ptab delete, so we cannot trust it. */
- if (!(erts_atomic32_read_nob(&proc->state) & ERTS_PSFLG_FREE)) {
- /* Insert links */
- insert_p_links(&proc->common);
-
- /* Insert monitors */
- insert_p_monitors(&proc->common);
- }
+ /* Insert monitors and links... */
+ erts_debug_proc_monitor_link_foreach(proc,
+ insert_monitor,
+ insert_link,
+ (void *) &proc->common.id);
{
DistEntry *dep = ERTS_PROC_GET_DIST_ENTRY(proc);
@@ -1906,6 +1886,12 @@ insert_process(Process *proc)
}
static void
+insert_process2(Process *proc, void *arg)
+{
+ insert_process(proc);
+}
+
+static void
insert_dist_suspended_procs(DistEntry *dep)
{
ErtsProcList *plist = erts_proclist_peek_first(dep->suspended);
@@ -1916,16 +1902,47 @@ insert_dist_suspended_procs(DistEntry *dep)
}
}
+static void clear_process(Process *proc);
+
+static void
+clear_dist_suspended_procs(DistEntry *dep)
+{
+ ErtsProcList *plist = erts_proclist_peek_first(dep->suspended);
+ while (plist) {
+ if (is_not_immed(plist->u.pid))
+ clear_process(plist->u.p);
+ plist = erts_proclist_peek_next(dep->suspended, plist);
+ }
+}
+
+static void
+insert_persistent_term(ErlOffHeap *ohp, void *arg)
+{
+ Eterm heap[3];
+ insert_offheap(ohp, SYSTEM_REF,
+ TUPLE2(&heap[0], AM_system, AM_persistent_term));
+}
+
+static void
+insert_ets_offheap_thr_prgr(ErlOffHeap *ohp, void *arg)
+{
+ Eterm heap[3];
+ insert_offheap(ohp, ETS_REF,
+ TUPLE2(&heap[0], AM_system, AM_ets));
+}
+
#ifdef ERL_NODE_BOOKKEEP
void
-erts_node_bookkeep(ErlNode *np, Eterm term, int what)
+erts_node_bookkeep(ErlNode *np, Eterm term, int what, char *f, int l)
{
- erts_aint_t slot = (erts_atomic_inc_read_nob(&np->slot) - 1) % 1024;
+ erts_aint_t slot = (erts_atomic_inc_read_nob(&np->slot) - 1) % ERTS_BOOKKEEP_SIZE;
ErtsSchedulerData *esdp = erts_get_scheduler_data();
Eterm who = THE_NON_VALUE;
ASSERT(np);
np->books[slot].what = what;
np->books[slot].term = term;
+ np->books[slot].file = f;
+ np->books[slot].line = l;
if (esdp->current_process) {
who = esdp->current_process->common.id;
} else if (esdp->current_port) {
@@ -1946,14 +1963,14 @@ setup_reference_table(void)
inserted_bins = NULL;
hash_get_info(&hi, &erts_node_table);
- referred_nodes = erts_alloc(ERTS_ALC_T_NC_TMP,
+ referred_nodes = erts_alloc(ERTS_DBG_NC_ALLOC_TYPE,
hi.objs*sizeof(ReferredNode));
no_referred_nodes = 0;
hash_foreach(&erts_node_table, init_referred_node, NULL);
ASSERT(no_referred_nodes == hi.objs);
hash_get_info(&hi, &erts_dist_table);
- referred_dists = erts_alloc(ERTS_ALC_T_NC_TMP,
+ referred_dists = erts_alloc(ERTS_DBG_NC_ALLOC_TYPE,
hi.objs*sizeof(ReferredDist));
no_referred_dists = 0;
hash_foreach(&erts_dist_table, init_referred_dist, NULL);
@@ -1990,8 +2007,9 @@ setup_reference_table(void)
if (proc)
insert_process(proc);
}
+ erts_debug_free_process_foreach(insert_process2, NULL);
- erts_foreach_sys_msg_in_q(insert_sys_msg);
+ erts_debug_foreach_sys_msg_in_q(insert_sys_msg);
/* Insert all ports */
max = erts_ptab_max(&erts_port);
@@ -2008,10 +2026,18 @@ setup_reference_table(void)
if (state & ERTS_PORT_SFLGS_DEAD)
continue;
- /* Insert links */
- insert_p_links(&prt->common);
- /* Insert monitors */
- insert_p_monitors(&prt->common);
+ /* Insert links */
+ erts_link_tree_foreach(ERTS_P_LINKS(prt),
+ insert_link,
+ (void *) &prt->common.id);
+ /* Insert monitors */
+ erts_monitor_tree_foreach(ERTS_P_MONITORS(prt),
+ insert_monitor,
+ (void *) &prt->common.id);
+ /* Insert local target monitors */
+ erts_monitor_list_foreach(ERTS_P_LT_MONITORS(prt),
+ insert_monitor,
+ (void *) &prt->common.id);
/* Insert port data */
ohp = erts_port_data_offheap(prt);
if (ohp)
@@ -2091,11 +2117,16 @@ setup_reference_table(void)
}
/* Insert all ets tables */
- erts_db_foreach_table(insert_ets_table, NULL);
+ erts_db_foreach_table(insert_ets_table, NULL, 0);
+ erts_db_foreach_thr_prgr_offheap(insert_ets_offheap_thr_prgr, NULL);
/* Insert all bif timers */
erts_debug_bif_timer_foreach(insert_bif_timer, NULL);
+ /* Insert persistent term storage */
+ erts_debug_foreach_persistent_term_off_heap(insert_persistent_term,
+ NULL);
+
/* Insert node table (references to dist) */
hash_foreach(&erts_node_table, insert_erl_node, NULL);
}
@@ -2348,8 +2379,7 @@ static void noop_sig_ext(ErtsDistExternal *ext, void *arg)
static void
delete_reference_table(void)
{
- DistEntry *dep;
- int i, max;
+ int i;
for(i = 0; i < no_referred_nodes; i++) {
NodeReferrer *nrp;
NodeReferrer *tnrp;
@@ -2358,11 +2388,13 @@ delete_reference_table(void)
erts_cleanup_offheap(&nrp->off_heap);
tnrp = nrp;
nrp = nrp->next;
- erts_free(ERTS_ALC_T_NC_TMP, (void *) tnrp);
+ erts_free(ERTS_DBG_NC_ALLOC_TYPE, (void *) tnrp);
}
}
- if (referred_nodes)
- erts_free(ERTS_ALC_T_NC_TMP, (void *) referred_nodes);
+ if (referred_nodes) {
+ erts_free(ERTS_DBG_NC_ALLOC_TYPE, (void *) referred_nodes);
+ referred_nodes = NULL;
+ }
for(i = 0; i < no_referred_dists; i++) {
DistReferrer *drp;
@@ -2371,34 +2403,57 @@ delete_reference_table(void)
while(drp) {
tdrp = drp;
drp = drp->next;
- erts_free(ERTS_ALC_T_NC_TMP, (void *) tdrp);
+ erts_free(ERTS_DBG_NC_ALLOC_TYPE, (void *) tdrp);
}
}
- if (referred_dists)
- erts_free(ERTS_ALC_T_NC_TMP, (void *) referred_dists);
+ if (referred_dists) {
+ erts_free(ERTS_DBG_NC_ALLOC_TYPE, (void *) referred_dists);
+ referred_dists = NULL;
+ }
while(inserted_bins) {
InsertedBin *ib = inserted_bins;
inserted_bins = inserted_bins->next;
- erts_free(ERTS_ALC_T_NC_TMP, (void *)ib);
+ erts_free(ERTS_DBG_NC_ALLOC_TYPE, (void *)ib);
}
+}
+
+static void clear_process(Process *proc)
+{
+ erts_proc_sig_debug_foreach_sig(proc,
+ noop_sig_msg,
+ noop_sig_offheap,
+ clear_visited_monitor,
+ clear_visited_link,
+ noop_sig_ext,
+ (void *) proc);
+
+
+ /* Clear monitors and links... */
+ erts_debug_proc_monitor_link_foreach(proc,
+ clear_visited_monitor,
+ clear_visited_link,
+ (void *) &proc->common.id);
+}
+
+static void clear_process2(Process *proc, void *arg)
+{
+ clear_process(proc);
+}
- /* Cleanup... */
+static void
+clear_system(void)
+{
+ DistEntry *dep;
+ int i, max;
+ /* Clear... */
max = erts_ptab_max(&erts_proc);
for (i = 0; i < max; i++) {
Process *proc = erts_pix2proc(i);
- if (proc) {
- clear_visited_p_links(&proc->common);
- clear_visited_p_monitors(&proc->common);
- erts_proc_sig_debug_foreach_sig(proc,
- noop_sig_msg,
- noop_sig_offheap,
- clear_visited_monitor,
- clear_visited_link,
- noop_sig_ext,
- (void *) proc);
- }
+ if (proc)
+ clear_process(proc);
}
+ erts_debug_free_process_foreach(clear_process2, NULL);
max = erts_ptab_max(&erts_port);
for (i = 0; i < max; i++) {
@@ -2413,28 +2468,42 @@ delete_reference_table(void)
if (state & ERTS_PORT_SFLGS_DEAD)
continue;
- clear_visited_p_links(&prt->common);
- clear_visited_p_monitors(&prt->common);
+ /* Clear links */
+ erts_link_tree_foreach(ERTS_P_LINKS(prt),
+ clear_visited_link,
+ (void *) &prt->common.id);
+ /* Clear monitors */
+ erts_monitor_tree_foreach(ERTS_P_MONITORS(prt),
+ clear_visited_monitor,
+ (void *) &prt->common.id);
+ /* Clear local target monitors */
+ erts_monitor_list_foreach(ERTS_P_LT_MONITORS(prt),
+ clear_visited_monitor,
+ (void *) &prt->common.id);
}
for(dep = erts_visible_dist_entries; dep; dep = dep->next) {
clear_visited_dist_links(dep);
clear_visited_dist_monitors(dep);
+ clear_dist_suspended_procs(dep);
}
for(dep = erts_hidden_dist_entries; dep; dep = dep->next) {
clear_visited_dist_links(dep);
clear_visited_dist_monitors(dep);
+ clear_dist_suspended_procs(dep);
}
for(dep = erts_pending_dist_entries; dep; dep = dep->next) {
clear_visited_dist_links(dep);
clear_visited_dist_monitors(dep);
+ clear_dist_suspended_procs(dep);
}
for(dep = erts_not_connected_dist_entries; dep; dep = dep->next) {
clear_visited_dist_links(dep);
clear_visited_dist_monitors(dep);
+ clear_dist_suspended_procs(dep);
}
}
diff --git a/erts/emulator/beam/erl_node_tables.h b/erts/emulator/beam/erl_node_tables.h
index aa8af12555..ffaafbbbea 100644
--- a/erts/emulator/beam/erl_node_tables.h
+++ b/erts/emulator/beam/erl_node_tables.h
@@ -187,6 +187,7 @@ set pagination off
set $i = 0
set $node = referred_nodes[$node_ix].node
while $i < $node->slot.counter
+ printf "%s:%d ", $node->books[$i].file, $node->books[$i].line
printf "%p: ", $node->books[$i].term
etp-1 $node->books[$i].who
printf " "
@@ -211,8 +212,12 @@ lists:usort(lists:filter(fun({V,N}) -> N /= 0 end, maps:to_list(Accs))).
struct erl_node_bookkeeping {
Eterm who;
Eterm term;
+ char *file;
+ int line;
enum { ERL_NODE_INC, ERL_NODE_DEC } what;
};
+
+#define ERTS_BOOKKEEP_SIZE (1024)
#endif
typedef struct erl_node_ {
@@ -222,7 +227,7 @@ typedef struct erl_node_ {
Uint32 creation; /* Creation */
DistEntry *dist_entry; /* Corresponding dist entry */
#ifdef ERL_NODE_BOOKKEEP
- struct erl_node_bookkeeping books[1024];
+ struct erl_node_bookkeeping books[ERTS_BOOKKEEP_SIZE];
erts_atomic_t slot;
#endif
} ErlNode;
@@ -276,14 +281,21 @@ Eterm erts_build_dhandle(Eterm **hpp, ErlOffHeap*, DistEntry*, Uint32 conn_id);
Eterm erts_make_dhandle(Process *c_p, DistEntry*, Uint32 conn_id);
ERTS_GLB_INLINE void erts_init_node_entry(ErlNode *np, erts_aint_t val);
+#ifdef ERL_NODE_BOOKKEEP
+#define erts_ref_node_entry(NP, MIN, T) erts_ref_node_entry__((NP), (MIN), (T), __FILE__, __LINE__)
+#define erts_deref_node_entry(NP, T) erts_deref_node_entry__((NP), (T), __FILE__, __LINE__)
+ERTS_GLB_INLINE erts_aint_t erts_ref_node_entry__(ErlNode *np, int min_val, Eterm term, char *file, int line);
+ERTS_GLB_INLINE void erts_deref_node_entry__(ErlNode *np, Eterm term, char *file, int line);
+#else
ERTS_GLB_INLINE erts_aint_t erts_ref_node_entry(ErlNode *np, int min_val, Eterm term);
ERTS_GLB_INLINE void erts_deref_node_entry(ErlNode *np, Eterm term);
+#endif
ERTS_GLB_INLINE void erts_de_rlock(DistEntry *dep);
ERTS_GLB_INLINE void erts_de_runlock(DistEntry *dep);
ERTS_GLB_INLINE void erts_de_rwlock(DistEntry *dep);
ERTS_GLB_INLINE void erts_de_rwunlock(DistEntry *dep);
#ifdef ERL_NODE_BOOKKEEP
-void erts_node_bookkeep(ErlNode *, Eterm , int);
+void erts_node_bookkeep(ErlNode *, Eterm , int, char *file, int line);
#else
#define erts_node_bookkeep(...)
#endif
@@ -296,21 +308,40 @@ erts_init_node_entry(ErlNode *np, erts_aint_t val)
erts_refc_init(&np->refc, val);
}
+#ifdef ERL_NODE_BOOKKEEP
+
+ERTS_GLB_INLINE erts_aint_t
+erts_ref_node_entry__(ErlNode *np, int min_val, Eterm term, char *file, int line)
+{
+ erts_node_bookkeep(np, term, ERL_NODE_INC, file, line);
+ return erts_refc_inctest(&np->refc, min_val);
+}
+
+ERTS_GLB_INLINE void
+erts_deref_node_entry__(ErlNode *np, Eterm term, char *file, int line)
+{
+ erts_node_bookkeep(np, term, ERL_NODE_DEC, file, line);
+ if (erts_refc_dectest(&np->refc, 0) == 0)
+ erts_schedule_delete_node(np);
+}
+
+#else
+
ERTS_GLB_INLINE erts_aint_t
erts_ref_node_entry(ErlNode *np, int min_val, Eterm term)
{
- erts_node_bookkeep(np, term, ERL_NODE_INC);
return erts_refc_inctest(&np->refc, min_val);
}
ERTS_GLB_INLINE void
erts_deref_node_entry(ErlNode *np, Eterm term)
{
- erts_node_bookkeep(np, term, ERL_NODE_DEC);
if (erts_refc_dectest(&np->refc, 0) == 0)
erts_schedule_delete_node(np);
}
+#endif
+
ERTS_GLB_INLINE void
erts_de_rlock(DistEntry *dep)
{
diff --git a/erts/emulator/beam/erl_proc_sig_queue.c b/erts/emulator/beam/erl_proc_sig_queue.c
index fb900ca7ba..d5e0e3b218 100644
--- a/erts/emulator/beam/erl_proc_sig_queue.c
+++ b/erts/emulator/beam/erl_proc_sig_queue.c
@@ -4689,10 +4689,12 @@ erts_proc_sig_debug_foreach_sig(Process *c_p,
case ERTS_SIG_Q_OP_MONITOR_DOWN:
switch (type) {
case ERTS_SIG_Q_TYPE_GEN_EXIT:
- if (ERTS_SIG_IS_GEN_EXIT_EXTERNAL(sig))
- debug_foreach_sig_external(sig, ext_func, arg);
- else
+ if (!ERTS_SIG_IS_GEN_EXIT_EXTERNAL(sig))
debug_foreach_sig_heap_frags(&sig->hfrag, oh_func, arg);
+ else {
+ oh_func(&sig->hfrag.off_heap, arg);
+ debug_foreach_sig_external(sig, ext_func, arg);
+ }
break;
case ERTS_LNK_TYPE_PORT:
case ERTS_LNK_TYPE_PROC:
diff --git a/erts/emulator/beam/erl_process.c b/erts/emulator/beam/erl_process.c
index de0564292d..1c1ef1db84 100644
--- a/erts/emulator/beam/erl_process.c
+++ b/erts/emulator/beam/erl_process.c
@@ -13468,3 +13468,79 @@ erts_debug_later_op_foreach(void (*callback)(void*),
}
}
}
+
+void
+erts_debug_free_process_foreach(void (*func)(Process *, void *), void *arg)
+{
+ ErtsRunQueue *rq;
+ int ix, prio;
+ for (ix = 0; ix < erts_no_run_queues; ix++) {
+ rq = ERTS_RUNQ_IX(ix);
+ for (prio = PRIORITY_MAX; prio < PRIORITY_LOW; prio++) {
+ Process *p = rq->procs.prio[prio].first;
+ for (; p; p = p->next) {
+ if (ERTS_PSFLG_FREE & erts_atomic32_read_nob(&p->state))
+ (*func)(p, arg);
+ }
+ }
+ }
+}
+
+void
+erts_debug_proc_monitor_link_foreach(Process *proc,
+ int (*monitor_func)(ErtsMonitor *, void *, Sint ),
+ int (*link_func)(ErtsLink *, void *, Sint ),
+ void *arg)
+{
+ if (!(erts_atomic32_read_nob(&proc->state) & ERTS_PSFLG_FREE)) {
+ /* For all links */
+ erts_link_tree_foreach(ERTS_P_LINKS(proc),
+ link_func,
+ arg);
+ /* For all monitors */
+ erts_monitor_tree_foreach(ERTS_P_MONITORS(proc),
+ monitor_func,
+ arg);
+ /* For all local target monitors */
+ erts_monitor_list_foreach(ERTS_P_LT_MONITORS(proc),
+ monitor_func,
+ arg);
+ }
+ else {
+ struct continue_exit_state *ce_state = proc->u.terminate;
+
+ /* For all links */
+ if (ce_state->phase == ERTS_CONTINUE_EXIT_LINKS)
+ erts_debug_link_tree_destroying_foreach(ce_state->links,
+ link_func,
+ arg,
+ ce_state->yield_state);
+ else
+ erts_link_tree_foreach(ce_state->links,
+ link_func,
+ arg);
+
+ /* For all monitors */
+ if (ce_state->phase == ERTS_CONTINUE_EXIT_MONITORS)
+ erts_debug_monitor_tree_destroying_foreach(ce_state->monitors,
+ monitor_func,
+ arg,
+ ce_state->yield_state);
+ else
+ erts_monitor_tree_foreach(ce_state->monitors,
+ monitor_func,
+ arg);
+
+ /* For all local target monitors */
+ if (ce_state->phase == ERTS_CONTINUE_EXIT_LT_MONITORS)
+ erts_debug_monitor_list_destroying_foreach(ce_state->lt_monitors,
+ monitor_func,
+ arg,
+ ce_state->yield_state);
+ else
+ erts_monitor_list_foreach(ce_state->lt_monitors,
+ monitor_func,
+ arg);
+
+ }
+}
diff --git a/erts/emulator/beam/erl_process.h b/erts/emulator/beam/erl_process.h
index 745a2a482c..c0d7cfd13d 100644
--- a/erts/emulator/beam/erl_process.h
+++ b/erts/emulator/beam/erl_process.h
@@ -701,6 +701,13 @@ void
erts_debug_later_op_foreach(void (*callback)(void*),
void (*func)(void *, ErtsThrPrgrVal, void *),
void *arg);
+void
+erts_debug_free_process_foreach(void (*func)(Process *, void *), void *arg);
+void
+erts_debug_proc_monitor_link_foreach(Process *proc,
+ int (*monitor_func)(ErtsMonitor *, void *, Sint ),
+ int (*link_func)(ErtsLink *, void *, Sint ),
+ void *arg);
#ifdef ERTS_INCLUDE_SCHEDULER_INTERNALS
diff --git a/erts/emulator/beam/erl_trace.c b/erts/emulator/beam/erl_trace.c
index 9c835ac357..f6f177887c 100644
--- a/erts/emulator/beam/erl_trace.c
+++ b/erts/emulator/beam/erl_trace.c
@@ -2194,11 +2194,12 @@ sys_msg_dispatcher_wait(void *vwait_p)
erts_mtx_unlock(&smq_mtx);
}
+static ErtsSysMsgQ *local_sys_message_queue = NULL;
+
static void *
sys_msg_dispatcher_func(void *unused)
{
ErtsThrPrgrCallbacks callbacks;
- ErtsSysMsgQ *local_sys_message_queue = NULL;
ErtsThrPrgrData *tpd;
int wait = 0;
@@ -2206,6 +2207,8 @@ sys_msg_dispatcher_func(void *unused)
erts_lc_set_thread_name("system message dispatcher");
#endif
+ local_sys_message_queue = NULL;
+
callbacks.arg = (void *) &wait;
callbacks.wakeup = sys_msg_dispatcher_wakeup;
callbacks.prepare_wait = sys_msg_dispatcher_prep_wait;
@@ -2262,6 +2265,8 @@ sys_msg_dispatcher_func(void *unused)
Process *proc = NULL;
Port *port = NULL;
+ ASSERT(is_value(smqp->msg));
+
if (erts_thr_progress_update(tpd))
erts_thr_progress_leader_update(tpd);
@@ -2374,6 +2379,7 @@ sys_msg_dispatcher_func(void *unused)
erts_fprintf(stderr, "dropped\n");
#endif
}
+ smqp->msg = THE_NON_VALUE;
}
}
@@ -2381,32 +2387,38 @@ sys_msg_dispatcher_func(void *unused)
}
void
-erts_foreach_sys_msg_in_q(void (*func)(Eterm,
- Eterm,
- Eterm,
- ErlHeapFragment *))
+erts_debug_foreach_sys_msg_in_q(void (*func)(Eterm,
+ Eterm,
+ Eterm,
+ ErlHeapFragment *))
{
- ErtsSysMsgQ *sm;
- erts_mtx_lock(&smq_mtx);
- for (sm = sys_message_queue; sm; sm = sm->next) {
- Eterm to;
- switch (sm->type) {
- case SYS_MSG_TYPE_SYSMON:
- to = erts_get_system_monitor();
- break;
- case SYS_MSG_TYPE_SYSPROF:
- to = erts_get_system_profile();
- break;
- case SYS_MSG_TYPE_ERRLGR:
- to = erts_get_system_logger();
- break;
- default:
- to = NIL;
- break;
- }
- (*func)(sm->from, to, sm->msg, sm->bp);
+ ErtsSysMsgQ *smq[] = {sys_message_queue, local_sys_message_queue};
+ int i;
+
+ ERTS_LC_ASSERT(erts_thr_progress_is_blocking());
+
+ for (i = 0; i < sizeof(smq)/sizeof(smq[0]); i++) {
+ ErtsSysMsgQ *sm;
+ for (sm = smq[i]; sm; sm = sm->next) {
+ Eterm to;
+ switch (sm->type) {
+ case SYS_MSG_TYPE_SYSMON:
+ to = erts_get_system_monitor();
+ break;
+ case SYS_MSG_TYPE_SYSPROF:
+ to = erts_get_system_profile();
+ break;
+ case SYS_MSG_TYPE_ERRLGR:
+ to = erts_get_system_logger();
+ break;
+ default:
+ to = NIL;
+ break;
+ }
+ if (is_value(sm->msg))
+ (*func)(sm->from, to, sm->msg, sm->bp);
+ }
}
- erts_mtx_unlock(&smq_mtx);
}
diff --git a/erts/emulator/beam/erl_trace.h b/erts/emulator/beam/erl_trace.h
index b7844d1cb0..af38ef52db 100644
--- a/erts/emulator/beam/erl_trace.h
+++ b/erts/emulator/beam/erl_trace.h
@@ -90,10 +90,10 @@ int erts_is_tracer_valid(Process* p);
void erts_check_my_tracer_proc(Process *);
void erts_block_sys_msg_dispatcher(void);
void erts_release_sys_msg_dispatcher(void);
-void erts_foreach_sys_msg_in_q(void (*func)(Eterm,
- Eterm,
- Eterm,
- ErlHeapFragment *));
+void erts_debug_foreach_sys_msg_in_q(void (*func)(Eterm,
+ Eterm,
+ Eterm,
+ ErlHeapFragment *));
Eterm erts_set_system_logger(Eterm);
Eterm erts_get_system_logger(void);
void erts_queue_error_logger_message(Eterm, Eterm, ErlHeapFragment *);
diff --git a/erts/emulator/beam/global.h b/erts/emulator/beam/global.h
index 4c8d3d3dbe..0c2cf98033 100644
--- a/erts/emulator/beam/global.h
+++ b/erts/emulator/beam/global.h
@@ -907,7 +907,8 @@ Eterm erl_is_function(Process* p, Eterm arg1, Eterm arg2);
/* beam_bif_load.c */
Eterm erts_check_process_code(Process *c_p, Eterm module, int *redsp, int fcalls);
Eterm erts_proc_copy_literal_area(Process *c_p, int *redsp, int fcalls, int gc_allowed);
-
+void erts_debug_foreach_release_literal_area_off_heap(void (*func)(ErlOffHeap *, void *),
+ void *arg);
typedef struct ErtsLiteralArea_ {
struct erl_off_heap_header *off_heap;
Eterm *end;
@@ -1072,17 +1073,46 @@ Uint size_object_x(Eterm, erts_literal_area_t*);
#define size_object_litopt(Term,LitArea) size_object_x(Term,LitArea)
Uint copy_shared_calculate(Eterm, erts_shcopy_t*);
-Eterm copy_shared_perform(Eterm, Uint, erts_shcopy_t*, Eterm**, ErlOffHeap*);
-
Uint size_shared(Eterm);
+/* #define ERTS_COPY_REGISTER_LOCATION */
+
+#ifdef ERTS_COPY_REGISTER_LOCATION
+
+#define copy_shared_perform(U, V, X, Y, Z) \
+ copy_shared_perform_x((U), (V), (X), (Y), (Z), __FILE__, __LINE__)
+Eterm copy_shared_perform_x(Eterm, Uint, erts_shcopy_t*, Eterm**, ErlOffHeap*,
+ char *file, int line);
+
+Eterm copy_struct_x(Eterm, Uint, Eterm**, ErlOffHeap*, Uint*, erts_literal_area_t*,
+ char *file, int line);
+#define copy_struct(Obj,Sz,HPP,OH) \
+ copy_struct_x(Obj,Sz,HPP,OH,NULL,NULL,__FILE__,__LINE__)
+#define copy_struct_litopt(Obj,Sz,HPP,OH,LitArea) \
+ copy_struct_x(Obj,Sz,HPP,OH,NULL,LitArea,__FILE__,__LINE__)
+
+#define copy_shallow(R, SZ, HPP, OH) \
+ copy_shallow_x((R), (SZ), (HPP), (OH), __FILE__, __LINE__)
+Eterm copy_shallow_x(Eterm* ERTS_RESTRICT, Uint, Eterm**, ErlOffHeap*,
+ char *file, int line);
+
+#else
+
+#define copy_shared_perform(U, V, X, Y, Z) \
+ copy_shared_perform_x((U), (V), (X), (Y), (Z))
+Eterm copy_shared_perform_x(Eterm, Uint, erts_shcopy_t*, Eterm**, ErlOffHeap*);
+
Eterm copy_struct_x(Eterm, Uint, Eterm**, ErlOffHeap*, Uint*, erts_literal_area_t*);
#define copy_struct(Obj,Sz,HPP,OH) \
copy_struct_x(Obj,Sz,HPP,OH,NULL,NULL)
#define copy_struct_litopt(Obj,Sz,HPP,OH,LitArea) \
copy_struct_x(Obj,Sz,HPP,OH,NULL,LitArea)
-Eterm copy_shallow(Eterm* ERTS_RESTRICT, Uint, Eterm**, ErlOffHeap*);
+#define copy_shallow(R, SZ, HPP, OH) \
+ copy_shallow_x((R), (SZ), (HPP), (OH))
+Eterm copy_shallow_x(Eterm* ERTS_RESTRICT, Uint, Eterm**, ErlOffHeap*);
+
+#endif
void erts_move_multi_frags(Eterm** hpp, ErlOffHeap*, ErlHeapFragment* first,
Eterm* refs, unsigned nrefs, int literals);
@@ -1257,6 +1287,10 @@ Uint erts_persistent_term_count(void);
void erts_init_persistent_dumping(void);
extern ErtsLiteralArea** erts_persistent_areas;
extern Uint erts_num_persistent_areas;
+void erts_debug_foreach_persistent_term_off_heap(void (*func)(ErlOffHeap *, void *),
+ void *arg);
+int erts_debug_have_accessed_literal_area(ErtsLiteralArea *lap);
+void erts_debug_save_accessed_literal_area(ErtsLiteralArea *lap);
/* external.c */
void erts_init_external(void);
diff --git a/erts/emulator/sys/unix/sys_drivers.c b/erts/emulator/sys/unix/sys_drivers.c
index 664d677ebd..92020c6f35 100644
--- a/erts/emulator/sys/unix/sys_drivers.c
+++ b/erts/emulator/sys/unix/sys_drivers.c
@@ -785,15 +785,15 @@ static ErlDrvSSizeT spawn_control(ErlDrvData e, unsigned int cmd, char *buf,
static int fd_get_window_size(int fd, Uint32 *width, Uint32 *height)
{
-#ifdef TIOCGWINSZ
+#ifdef TIOCGWINSZ
struct winsize ws;
if (ioctl(fd,TIOCGWINSZ,&ws) == 0) {
*width = (Uint32) ws.ws_col;
*height = (Uint32) ws.ws_row;
- return 0;
+ return 1;
}
#endif
- return -1;
+ return 0;
}
static ErlDrvSSizeT fd_control(ErlDrvData drv_data,
@@ -801,16 +801,28 @@ static ErlDrvSSizeT fd_control(ErlDrvData drv_data,
char *buf, ErlDrvSizeT len,
char **rbuf, ErlDrvSizeT rlen)
{
- int fd = (int)(long)drv_data;
char resbuff[2*sizeof(Uint32)];
-
+ ErtsSysDriverData* dd = (ErtsSysDriverData*)drv_data;
command -= ERTS_TTYSL_DRV_CONTROL_MAGIC_NUMBER;
switch (command) {
case FD_CTRL_OP_GET_WINSIZE:
{
Uint32 w,h;
- if (fd_get_window_size(fd,&w,&h))
- return 0;
+ int success = 0;
+ if (dd->ofd != NULL) {
+ /* Try with output file descriptor */
+ int out_fd = dd->ofd->fd;
+ success = fd_get_window_size(out_fd,&w,&h);
+ }
+ if (!success && dd->ifd != NULL) {
+ /* Try with input file descriptor */
+ int in_fd = dd->ifd->fd;
+ success = fd_get_window_size(in_fd,&w,&h);
+ }
+ if (!success) {
+ return -1;
+ }
+ /* Succeeded */
memcpy(resbuff,&w,sizeof(Uint32));
memcpy(resbuff+sizeof(Uint32),&h,sizeof(Uint32));
}
diff --git a/erts/emulator/test/node_container_SUITE.erl b/erts/emulator/test/node_container_SUITE.erl
index 7d2db5257c..c44693f8d9 100644
--- a/erts/emulator/test/node_container_SUITE.erl
+++ b/erts/emulator/test/node_container_SUITE.erl
@@ -51,7 +51,8 @@
unique_pid/1,
iter_max_procs/1,
magic_ref/1,
- dist_entry_gc/1]).
+ dist_entry_gc/1,
+ persistent_term/1]).
suite() ->
[{ct_hooks,[ts_install_cth]},
@@ -63,7 +64,8 @@ all() ->
node_table_gc, dist_link_refc, dist_monitor_refc,
node_controller_refc, ets_refc, match_spec_refc,
timer_refc, pid_wrap, port_wrap, bad_nc,
- unique_pid, iter_max_procs, magic_ref].
+ unique_pid, iter_max_procs,
+ magic_ref, persistent_term].
init_per_suite(Config) ->
Config.
@@ -906,6 +908,44 @@ magic_ref(Config) when is_list(Config) ->
true = erts_debug:get_internal_state({magic_ref,MRef2}),
ok.
+persistent_term(Config) when is_list(Config) ->
+ {ok, Node} = start_node(get_nodefirstname()),
+ Self = self(),
+ NcData = make_ref(),
+ RPid = spawn_link(Node,
+ fun () ->
+ Self ! {NcData, self(), hd(erlang:ports()), erlang:make_ref()}
+ end),
+ Data = receive
+ {NcData, RPid, RPort, RRef} ->
+ {RPid, RPort, RRef}
+ end,
+ unlink(RPid),
+ stop_node(Node),
+ Stuff = lists:foldl(fun (N, Acc) ->
+ persistent_term:put({?MODULE, N}, Data),
+ persistent_term:erase({?MODULE, N-1}),
+ node_container_refc_check(node()),
+ Data = persistent_term:get({?MODULE, N}),
+ try
+ persistent_term:get({?MODULE, N-1})
+ catch
+ error:badarg ->
+ ok
+ end,
+ case N rem 4 of
+ 0 -> [persistent_term:get({?MODULE, N})|Acc];
+ _ -> Acc
+ end
+ end,
+ [],
+ lists:seq(1, 100)),
+ persistent_term:erase({?MODULE, 100}),
+ receive after 2000 -> ok end, %% give literal gc some time to run...
+ node_container_refc_check(node()),
+ id(Stuff),
+ ok.
+
lost_pending_connection(Node) ->
_ = (catch erts_internal:new_connection(Node)),
diff --git a/erts/emulator/test/socket_SUITE.erl b/erts/emulator/test/socket_SUITE.erl
index 4e3db11bbe..ff5a4e7e2e 100644
--- a/erts/emulator/test/socket_SUITE.erl
+++ b/erts/emulator/test/socket_SUITE.erl
@@ -58,6 +58,7 @@
-include_lib("common_test/include/ct.hrl").
-include_lib("common_test/include/ct_event.hrl").
+-include("socket_test_evaluator.hrl").
%% Suite exports
-export([suite/0, all/0, groups/0]).
@@ -556,30 +557,31 @@
]).
--include("socket_test_evaluator.hrl").
-
%% Internal exports
%% -export([]).
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
--define(BASIC_REQ, <<"hejsan">>).
--define(BASIC_REP, <<"hoppsan">>).
+-define(LIB, socket_test_lib).
+-define(TTEST_LIB, socket_test_ttest_lib).
+-define(LOGGER, socket_test_logger).
+
+-define(BASIC_REQ, <<"hejsan">>).
+-define(BASIC_REP, <<"hoppsan">>).
+
+-define(DATA, <<"HOPPSAN">>). % Temporary
+-define(FAIL(R), exit(R)).
--define(DATA, <<"HOPPSAN">>). % Temporary
--define(FAIL(R), exit(R)).
+-define(SLEEP(T), receive after T -> ok end).
--define(SLEEP(T), receive after T -> ok end).
+-define(MINS(M), timer:minutes(M)).
+-define(SECS(S), timer:seconds(S)).
--define(MINS(M), timer:minutes(M)).
--define(SECS(S), timer:seconds(S)).
+-define(TT(T), ct:timetrap(T)).
--define(TT(T), ct:timetrap(T)).
+-define(F(F, A), ?LIB:f(F, A)).
--define(LIB, socket_test_lib).
--define(TTEST_LIB, socket_test_ttest_lib).
--define(LOGGER, socket_test_logger).
-define(TPP_SMALL, lists:seq(1, 8)).
-define(TPP_MEDIUM, lists:flatten(lists:duplicate(1024, ?TPP_SMALL))).
@@ -793,8 +795,6 @@ api_options_otp_cases() ->
api_options_socket_cases() ->
[
{group, api_option_sock_acceptconn},
- %% api_opt_sock_acceptconn_udp,
- %% api_opt_sock_acceptconn_tcp,
api_opt_sock_acceptfilter,
api_opt_sock_bindtodevice,
api_opt_sock_broadcast,
@@ -12156,7 +12156,7 @@ sc_cpe_socket_cleanup_tcp4(suite) ->
sc_cpe_socket_cleanup_tcp4(doc) ->
[];
sc_cpe_socket_cleanup_tcp4(_Config) when is_list(_Config) ->
- ?TT(?SECS(5)),
+ ?TT(?SECS(30)),
tc_try(sc_cpe_socket_cleanup_tcp4,
fun() ->
InitState = #{domain => inet,
@@ -12176,7 +12176,7 @@ sc_cpe_socket_cleanup_tcp6(suite) ->
sc_cpe_socket_cleanup_tcp6(doc) ->
[];
sc_cpe_socket_cleanup_tcp6(_Config) when is_list(_Config) ->
- ?TT(?SECS(5)),
+ ?TT(?SECS(30)),
tc_try(sc_cpe_socket_cleanup_tcp6,
fun() -> has_support_ipv6() end,
fun() ->
@@ -12197,7 +12197,7 @@ sc_cpe_socket_cleanup_tcpL(suite) ->
sc_cpe_socket_cleanup_tcpL(doc) ->
[];
sc_cpe_socket_cleanup_tcpL(_Config) when is_list(_Config) ->
- ?TT(?SECS(5)),
+ ?TT(?SECS(30)),
tc_try(sc_cpe_socket_cleanup_tcpL,
fun() -> has_support_unix_domain_socket() end,
fun() ->
@@ -12218,7 +12218,7 @@ sc_cpe_socket_cleanup_udp4(suite) ->
sc_cpe_socket_cleanup_udp4(doc) ->
[];
sc_cpe_socket_cleanup_udp4(_Config) when is_list(_Config) ->
- ?TT(?SECS(5)),
+ ?TT(?SECS(30)),
tc_try(sc_cpe_socket_cleanup_udp4,
fun() ->
InitState = #{domain => inet,
@@ -12239,7 +12239,7 @@ sc_cpe_socket_cleanup_udp6(suite) ->
sc_cpe_socket_cleanup_udp6(doc) ->
[];
sc_cpe_socket_cleanup_udp6(_Config) when is_list(_Config) ->
- ?TT(?SECS(5)),
+ ?TT(?SECS(30)),
tc_try(sc_cpe_socket_cleanup_udp6,
fun() -> has_support_ipv6() end,
fun() ->
@@ -12260,7 +12260,7 @@ sc_cpe_socket_cleanup_udpL(suite) ->
sc_cpe_socket_cleanup_udpL(doc) ->
[];
sc_cpe_socket_cleanup_udpL(_Config) when is_list(_Config) ->
- ?TT(?SECS(5)),
+ ?TT(?SECS(30)),
tc_try(sc_cpe_socket_cleanup_udpL,
fun() -> has_support_unix_domain_socket() end,
fun() ->
@@ -12366,8 +12366,15 @@ sc_cpe_socket_cleanup(InitState) ->
ERROR
end
end},
+
+ ?SEV_SLEEP(?SECS(5)),
+
%% The reason we get closed, is that as long as there is a ref to
%% the resource (socket), then it will not be garbage collected.
+ %% Note that its still a race that the nif has processed that the
+ %% "controlling process" has terminated. There really is no
+ %% proper timeout for this, but the 5 seconds "should" be enough...
+ %% We should really have some way to subscribe to socket events...
#{desc => "verify no socket (closed)",
cmd => fun(#{owner := Pid, sock := Sock} = _State) ->
case socket:getopt(Sock, otp, controlling_process) of
@@ -20199,12 +20206,14 @@ traffic_ping_pong_send_and_receive_tcp(#{msg := Msg} = InitState) ->
?SEV_IPRINT("RcvBuf is ~p (needs atleast ~p)",
[RcvSz, 16+size(Msg)]),
if (RcvSz < size(Msg)) ->
- case socket:setopt(Sock,
- socket, rcvbuf, 1024+size(Msg)) of
+ NewRcvSz = 1024+size(Msg),
+ case socket:setopt(Sock, socket, rcvbuf, NewRcvSz) of
ok ->
ok;
{error, enobufs} ->
- skip({failed_change, rcvbuf});
+ skip(?F("Change ~w buffer size (to ~w) "
+ "not allowed",
+ [rcvbuf, NewRcvSz]));
{error, Reason1} ->
?FAIL({rcvbuf, Reason1})
end;
@@ -20215,12 +20224,14 @@ traffic_ping_pong_send_and_receive_tcp(#{msg := Msg} = InitState) ->
?SEV_IPRINT("SndBuf is ~p (needs atleast ~p)",
[SndSz, 16+size(Msg)]),
if (SndSz < size(Msg)) ->
- case socket:setopt(Sock,
- socket, sndbuf, 1024+size(Msg)) of
+ NewSndSz = 1024+size(Msg),
+ case socket:setopt(Sock, socket, sndbuf, NewSndSz) of
ok ->
ok;
{error, enobufs} ->
- skip({failed_change, sndbuf});
+ skip(?F("Change ~w buffer size (to ~w) "
+ "not allowed",
+ [sndbuf, NewSndSz]));
{error, Reason2} ->
?FAIL({sndbuf, Reason2})
end;
@@ -28804,8 +28815,10 @@ has_support_ip_multicast() ->
{error, Reason} ->
not_supported({multicast, Reason})
end;
+ {unix, OsName} ->
+ skip(?F("Not Supported: platform ~w", [OsName]));
Type ->
- not_supported({multicast, Type})
+ skip(?F("Not Supported: platform ~p", [Type]))
end.
has_support_sock_acceptconn() ->
@@ -28859,7 +28872,7 @@ has_support_socket_option(Level, Option) ->
true ->
ok;
false ->
- not_supported({options, Level, Option})
+ skip(?F("Not Supported: ~w option ~w", [Level, Option]))
end.
diff --git a/erts/etc/unix/etp-commands.in b/erts/etc/unix/etp-commands.in
index 8b6abb5336..20809d61e8 100644
--- a/erts/etc/unix/etp-commands.in
+++ b/erts/etc/unix/etp-commands.in
@@ -3993,22 +3993,79 @@ end
# ETS table debug
#
+define etp-ets-tab-status-int
+# Args:
+#
+# Non-reentrant
+ if ($arg0 & 0x1)
+ printf "priv"
+ end
+ if ($arg0 & 0x2)
+ printf "prot"
+ end
+ if ($arg0 & 0x4)
+ printf "pub"
+ end
+ if ($arg0 & 0x8)
+ printf "|del"
+ end
+ if ($arg0 & 0x10)
+ printf "|set"
+ end
+ if ($arg0 & 0x20)
+ printf "|bag"
+ end
+ if ($arg0 & 0x40)
+ printf "|dbag"
+ end
+ if ($arg0 & 0x80)
+ printf "|oset"
+ end
+ if ($arg0 & 0x100)
+ printf "|caoset"
+ end
+ if ($arg0 & 0x200)
+ printf "|flocked"
+ end
+ if ($arg0 & 0x400)
+ printf "|fread"
+ end
+ if ($arg0 & 0x800)
+ printf "|named"
+ end
+ if ($arg0 & 0x1000)
+ printf "|busy"
+ end
+end
+
define etp-ets-tables
# Args:
#
# Non-reentrant
- printf "%% Dumping < %lu ETS tables\n", (unsigned long)db_max_tabs
- while $etp_ets_tables_i < db_max_tabs
- if (meta_main_tab[$etp_ets_tables_i].u.next_free & 3) == 0
- printf "%% %d:", $etp_ets_tables_i
- etp-1 ((Eterm)(meta_main_tab[$etp_ets_tables_i].u.tb->common.id)) 0
+ set $sched_ix = 0
+ while $sched_ix < erts_no_schedulers
+ set $ets_tabs = &erts_aligned_scheduler_data[$sched_ix].esd.ets_tables
+ set $no_ets_tabs = *(unsigned long *)&($ets_tabs->count)
+ printf "\n%% %lu ETS tables created on scheduler %lu...\n\n", $no_ets_tabs, (unsigned long)$sched_ix+1
+ set $ets_tab = $ets_tabs->clist
+ set $first_ets_tab = $ets_tab
+ while $ets_tab
+ set $refn = &((ErtsMagicBinary *)$ets_tab->common->btid)->refn
+ printf "%% "
+ etp-1 $ets_tab->common.the_name 0
+ printf " #Ref<0.%u.%u.%u> ", (unsigned)$refn[2], (unsigned)$refn[1], (unsigned)$refn[0]
+ etp-1 $ets_tab->common.owner 0
printf " "
- etp-1 ((Eterm)(meta_main_tab[$etp_ets_tables_i].u.tb->common.owner)) 0
- printf "\n"
+ etp-ets-tab-status-int $ets_tab->common.status
+ printf " (DbTable*)%p\n", $ets_tab
+ if $ets_tab->common.all.next == $first_ets_tab
+ set $ets_tab = (DbTable *) 0
+ else
+ set $ets_tab = $ets_tab->common.all.next
+ end
end
- set $etp_ets_tables_i++
+ set $sched_ix++
end
- set $etp_ets_tables_i = 0
end
document etp-ets-tables
diff --git a/lib/kernel/test/interactive_shell_SUITE.erl b/lib/kernel/test/interactive_shell_SUITE.erl
index 298a364a91..173e25c520 100644
--- a/lib/kernel/test/interactive_shell_SUITE.erl
+++ b/lib/kernel/test/interactive_shell_SUITE.erl
@@ -23,7 +23,8 @@
init_per_group/2,end_per_group/2,
get_columns_and_rows/1, exit_initial/1, job_control_local/1,
job_control_remote/1,
- job_control_remote_noshell/1,ctrl_keys/1]).
+ job_control_remote_noshell/1,ctrl_keys/1,
+ get_columns_and_rows_escript/1]).
-export([init_per_testcase/2, end_per_testcase/2]).
%% For spawn
@@ -40,7 +41,8 @@ suite() ->
{timetrap,{minutes,3}}].
all() ->
- [get_columns_and_rows, exit_initial, job_control_local,
+ [get_columns_and_rows_escript,get_columns_and_rows,
+ exit_initial, job_control_local,
job_control_remote, job_control_remote_noshell,
ctrl_keys].
@@ -72,6 +74,60 @@ end_per_group(_GroupName, Config) ->
-define(dbg(Data),noop).
-endif.
+string_to_term(Str) ->
+ {ok,Tokens,_EndLine} = erl_scan:string(Str ++ "."),
+ {ok,AbsForm} = erl_parse:parse_exprs(Tokens),
+ {value,Value,_Bs} = erl_eval:exprs(AbsForm, erl_eval:new_bindings()),
+ Value.
+
+run_unbuffer_escript(Rows, Columns, EScript, NoTermStdIn, NoTermStdOut) ->
+ DataDir = filename:join(filename:dirname(code:which(?MODULE)), "interactive_shell_SUITE_data"),
+ TmpFile = filename:join(DataDir, "tmp"),
+ ok = file:write_file(TmpFile, <<>>),
+ CommandModifier =
+ case {NoTermStdIn, NoTermStdOut} of
+ {false, false} -> "";
+ {true, false} -> io_lib:format(" < ~s", [TmpFile]);
+ {false, true} -> io_lib:format(" > ~s ; cat ~s", [TmpFile, TmpFile]);
+ {true, true} -> io_lib:format(" > ~s < ~s ; cat ~s", [TmpFile, TmpFile, TmpFile])
+ end,
+ Command = io_lib:format("unbuffer -p bash -c \"stty rows ~p; stty columns ~p; escript ~s ~s\"",
+ [Rows, Columns, EScript, CommandModifier]),
+ %% io:format("Command: ~s ~n", [Command]),
+ Out = os:cmd(Command),
+ %% io:format("Out: ~p ~n", [Out]),
+ string_to_term(Out).
+
+get_columns_and_rows_escript(Config) when is_list(Config) ->
+ ExpectUnbufferInstalled =
+ try
+ "79" = string:trim(os:cmd("unbuffer -p bash -c \"stty columns 79 ; tput cols\"")),
+ true
+ catch
+ _:_ -> false
+ end,
+ case ExpectUnbufferInstalled of
+ false ->
+ {skip,
+ "The unbuffer tool (https://core.tcl-lang.org/expect/index) does not seem to be installed.~n"
+ "On Ubuntu/Debian: \"sudo apt-get install expect\""};
+ true ->
+ DataDir = filename:join(filename:dirname(code:which(?MODULE)), "interactive_shell_SUITE_data"),
+ IoColumnsErl = filename:join(DataDir, "io_columns.erl"),
+ IoRowsErl = filename:join(DataDir, "io_rows.erl"),
+ [
+ begin
+ {ok, 42} = run_unbuffer_escript(99, 42, IoColumnsErl, NoTermStdIn, NoTermStdOut),
+ {ok, 99} = run_unbuffer_escript(99, 42, IoRowsErl, NoTermStdIn, NoTermStdOut)
+ end
+ ||
+ {NoTermStdIn, NoTermStdOut} <- [{false, false}, {true, false}, {false, true}]
+ ],
+ {error,enotsup} = run_unbuffer_escript(99, 42, IoRowsErl, true, true),
+ {error,enotsup} = run_unbuffer_escript(99, 42, IoColumnsErl, true, true),
+ ok
+ end.
+
%% Test that the shell can access columns and rows.
get_columns_and_rows(Config) when is_list(Config) ->
case proplists:get_value(default_shell,Config) of
diff --git a/lib/kernel/test/interactive_shell_SUITE_data/.gitignore b/lib/kernel/test/interactive_shell_SUITE_data/.gitignore
new file mode 100644
index 0000000000..1c2f433de1
--- /dev/null
+++ b/lib/kernel/test/interactive_shell_SUITE_data/.gitignore
@@ -0,0 +1 @@
+tmp \ No newline at end of file
diff --git a/lib/kernel/test/interactive_shell_SUITE_data/io_columns.erl b/lib/kernel/test/interactive_shell_SUITE_data/io_columns.erl
new file mode 100644
index 0000000000..32d0cf25df
--- /dev/null
+++ b/lib/kernel/test/interactive_shell_SUITE_data/io_columns.erl
@@ -0,0 +1,6 @@
+-module(io_columns).
+
+-export([main/1]).
+
+main(_) ->
+ io:format("~p",[io:columns()]).
diff --git a/lib/kernel/test/interactive_shell_SUITE_data/io_rows.erl b/lib/kernel/test/interactive_shell_SUITE_data/io_rows.erl
new file mode 100644
index 0000000000..53ceb464b0
--- /dev/null
+++ b/lib/kernel/test/interactive_shell_SUITE_data/io_rows.erl
@@ -0,0 +1,6 @@
+-module(io_rows).
+
+-export([main/1]).
+
+main(_) ->
+ io:format("~p",[io:rows()]).
diff --git a/lib/snmp/src/manager/snmpm.erl b/lib/snmp/src/manager/snmpm.erl
index cf8c95d69f..8e60cecaf9 100644
--- a/lib/snmp/src/manager/snmpm.erl
+++ b/lib/snmp/src/manager/snmpm.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2004-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2004-2019. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -32,7 +32,7 @@
%% Management API
start/0, start/1,
start_link/0, start_link/1,
- stop/0,
+ stop/0, stop/1,
monitor/0, demonitor/1,
notify_started/1, cancel_notify_started/1,
@@ -196,7 +196,12 @@ start(Opts) ->
ok.
stop() ->
- snmpm_supervisor:stop().
+ stop(0).
+
+stop(Timeout) when (Timeout =:= infinity) orelse
+ (is_integer(Timeout) andalso (Timeout >= 0)) ->
+ snmpm_supervisor:stop(Timeout).
+
monitor() ->
diff --git a/lib/snmp/src/manager/snmpm_supervisor.erl b/lib/snmp/src/manager/snmpm_supervisor.erl
index c36bbe1bdd..0061488f54 100644
--- a/lib/snmp/src/manager/snmpm_supervisor.erl
+++ b/lib/snmp/src/manager/snmpm_supervisor.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2004-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2004-2019. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -24,7 +24,7 @@
%% External exports
--export([start_link/2, stop/0]).
+-export([start_link/2, stop/0, stop/1]).
%% supervisor callbacks
-export([init/1]).
@@ -44,20 +44,47 @@ start_link(Type, Opts) ->
SupName = {local, ?MODULE},
supervisor:start_link(SupName, ?MODULE, [Type, Opts]).
+
stop() ->
+ stop(0).
+
+stop(Timeout) ->
?d("stop -> entry", []),
case whereis(?SERVER) of
Pid when is_pid(Pid) ->
- ?d("stop -> Pid: ~p", [Pid]),
- exit(Pid, shutdown),
- ?d("stop -> stopped", []),
- ok;
+ stop(Pid, Timeout);
_ ->
?d("stop -> not running", []),
not_running
end.
+%% For some unfathomable reason there is no "nice" way to stop
+%% a supervisor. The "normal" way to do it is:
+%% 1) exit(Pid, kill) (kaboom)
+%% 2) If the caller is the *parent*: exit(Pid, shutdown)
+%% So, here we do it the really unly way...but since this function is
+%% intended for testing (mostly)...
+stop(Pid, Timeout) when (Timeout =:= 0) ->
+ ?d("stop -> Pid: ~p", [Pid]),
+ sys:terminate(whereis(?SERVER), shutdown),
+ ?d("stop -> stopped", []),
+ ok;
+stop(Pid, Timeout) ->
+ ?d("stop -> Pid: ~p", [Pid]),
+ MRef = erlang:monitor(process, Pid),
+ sys:terminate(whereis(?SERVER), shutdown),
+ receive
+ {'DOWN', MRef, process, Pid, _} ->
+ ?d("stop -> stopped", []),
+ ok
+ after Timeout ->
+ ?d("stop -> timeout", []),
+ erlang:demonitor(MRef, [flush]),
+ {error, timeout}
+ end.
+
+
%%%-------------------------------------------------------------------
%%% Callback functions from supervisor
%%%-------------------------------------------------------------------
diff --git a/lib/snmp/test/snmp_agent_test_lib.erl b/lib/snmp/test/snmp_agent_test_lib.erl
index 615d6774b9..c0da47dc4c 100644
--- a/lib/snmp/test/snmp_agent_test_lib.erl
+++ b/lib/snmp/test/snmp_agent_test_lib.erl
@@ -423,7 +423,18 @@ tc_wait(From, Env, M, F, A) ->
"~n ~p"
"~n", [Res]),
From ! {tc_runner_done, self(), Res, get(test_server_loc)},
- exit(Res).
+ %% The point of this is that in some cases we have seen that the
+ %% exit signal having been "passed on" to the CT, which consider any
+ %% exit a fail (even if its {'EXIT', ok}).
+ %% So, just to be on the safe side, convert an 'ok' to a 'normal'.
+ case Res of
+ ok ->
+ exit(normal);
+ {ok, _} ->
+ exit(normal);
+ _ ->
+ exit(Res)
+ end.
tc_run(Mod, Func, Args, Opts) ->
?PRINT2("tc_run -> entry with"
diff --git a/lib/snmp/test/snmp_manager_test.erl b/lib/snmp/test/snmp_manager_test.erl
index 7cd3eae0c7..d49ab53c9f 100644
--- a/lib/snmp/test/snmp_manager_test.erl
+++ b/lib/snmp/test/snmp_manager_test.erl
@@ -990,25 +990,23 @@ notify_started02(Config) when is_list(Config) ->
%% <CONDITIONAL-SKIP>
%% The point of this is to catch machines running
- %% SLES9 (2.6.5)
+ %% SLES9 (2.6.5).
LinuxVersionVerify =
fun() ->
case os:cmd("uname -m") of
"i686" ++ _ ->
-%% io:format("found an i686 machine, "
-%% "now check version~n", []),
case os:version() of
{2, 6, Rev} when Rev >= 16 ->
- true;
+ false;
{2, Min, _} when Min > 6 ->
- true;
+ false;
{Maj, _, _} when Maj > 2 ->
- true;
+ false;
_ ->
- false
+ true
end;
_ ->
- true
+ false
end
end,
Skippable = [{unix, [{linux, LinuxVersionVerify}]}],
@@ -1023,10 +1021,10 @@ notify_started02(Config) when is_list(Config) ->
write_manager_conf(ConfDir),
- Opts = [{server, [{verbosity, log}]},
- {net_if, [{verbosity, silence}]},
+ Opts = [{server, [{verbosity, log}]},
+ {net_if, [{verbosity, silence}]},
{note_store, [{verbosity, silence}]},
- {config, [{verbosity, log}, {dir, ConfDir}, {db_dir, DbDir}]}],
+ {config, [{verbosity, debug}, {dir, ConfDir}, {db_dir, DbDir}]}],
p("start snmpm client process"),
NumIterations = 5,
@@ -1056,8 +1054,14 @@ notify_started02(Config) when is_list(Config) ->
p("await snmpm client process exit (max ~p+10000 msec)", [ApproxStartTime]),
receive
+ %% We take this opportunity to check if we got a skip from
+ %% the ctrl process.
+ {'EXIT', Pid2, {skip, SkipReason1}} ->
+ ?SKIP(SkipReason1);
{'EXIT', Pid1, normal} ->
ok;
+ {'EXIT', Pid1, {suite_failed, Reason1}} ->
+ ?FAIL({client, Reason1});
{'EXIT', Pid1, Reason1} ->
?FAIL({client, Reason1})
after ApproxStartTime + 10000 ->
@@ -1070,6 +1074,9 @@ notify_started02(Config) when is_list(Config) ->
receive
{'EXIT', Pid2, normal} ->
ok;
+ {'EXIT', Pid2, {skip, SkipReason2}} ->
+ %% In case of a race
+ ?SKIP(SkipReason2);
{'EXIT', Pid2, Reason2} ->
?FAIL({ctrl, Reason2})
after 5000 ->
@@ -1094,7 +1101,7 @@ ns02_client_await_approx_runtime(Pid) ->
"~n ~p", [Pid, Reason]),
{error, Reason}
- after 15000 ->
+ after 30000 ->
%% Either something is *really* wrong or this machine
%% is dog slow. Either way, this is a skip-reason...
{skip, approx_runtime_timeout}
@@ -1159,6 +1166,12 @@ ns02_ctrl(Opts, N) ->
p("starting"),
ns02_ctrl_loop(Opts, N).
+
+%% We have seen that some times it takes unreasonably long time to
+%% start the manager (it got "stuck" in snmpm_config). But since
+%% we did not have enough verbosity, we do not know how far it got.
+%% So, we try to monitor each start attempt. We allow 5 sec (just
+%% to give slow boxes a chance).
ns02_ctrl_loop(_Opts, 0) ->
p("done"),
exit(normal);
@@ -1166,13 +1179,37 @@ ns02_ctrl_loop(Opts, N) ->
p("entry when N: ~p", [N]),
?SLEEP(2000),
p("start manager"),
- snmpm:start(Opts),
+ TS1 = erlang:system_time(millisecond),
+ {StarterPid, StarterMRef} =
+ erlang:spawn_monitor(fun() -> exit(snmpm:start(Opts)) end),
+ receive
+ {'DOWN', StarterMRef, process, StarterPid, ok} ->
+ TS2 = erlang:system_time(millisecond),
+ p("manager started: ~w ms", [TS2-TS1]),
+ ok
+ after 5000 ->
+ p("manager (~p) start timeout - kill", [StarterPid]),
+ exit(StarterPid, kill),
+ exit({skip, start_timeout})
+ end,
?SLEEP(2000),
p("stop manager"),
- snmpm:stop(),
+ ?SLEEP(100), % Give the verbosity to take effect...
+ TS3 = erlang:system_time(millisecond),
+ case snmpm:stop(5000) of
+ ok ->
+ TS4 = erlang:system_time(millisecond),
+ p("manager stopped: ~p ms", [TS4-TS3]),
+ ok;
+ {error, timeout} ->
+ p("manager stop timeout - kill (cleanup) and skip"),
+ exit(whereis(snmpm_supervisor), kill),
+ exit({skip, stop_timeout})
+ end,
ns02_ctrl_loop(Opts, N-1).
+
%%======================================================================
info(suite) -> [];
diff --git a/lib/snmp/test/snmp_test_lib.erl b/lib/snmp/test/snmp_test_lib.erl
index 35bc535a80..a05040e281 100644
--- a/lib/snmp/test/snmp_test_lib.erl
+++ b/lib/snmp/test/snmp_test_lib.erl
@@ -202,11 +202,14 @@ non_pc_tc_maybe_skip(Config, Condition, File, Line)
%% test-server...
ok;
_ ->
- case Condition() of
+ try Condition() of
true ->
skip(non_pc_testcase, File, Line);
false ->
ok
+ catch
+ C:E:S ->
+ skip({condition, C, E, S}, File, Line)
end
end
end.
diff --git a/lib/ssl/doc/src/ssl.xml b/lib/ssl/doc/src/ssl.xml
index 3aa6e09c2c..05590666da 100644
--- a/lib/ssl/doc/src/ssl.xml
+++ b/lib/ssl/doc/src/ssl.xml
@@ -207,6 +207,10 @@
<datatype>
<name name="sign_scheme"/>
</datatype>
+
+ <datatype>
+ <name name="group"/>
+ </datatype>
<datatype>
<name name="kex_algo"/>
@@ -363,7 +367,20 @@
</p>
</desc>
</datatype>
-
+
+ <datatype>
+ <name name="supported_groups"/>
+ <desc>
+ <p>TLS 1.3 introduces the "supported_groups" extension that is used for negotiating
+ the Diffie-Hellman parameters in a TLS 1.3 handshake. Both client and server
+ can specify a list of parameters that they are willing to use.
+ </p>
+ <p> If it is not specified it will use a default list ([x25519, x448, secp256r1, secp384r1]) that
+ is filtered based on the installed crypto library version.
+ </p>
+ </desc>
+ </datatype>
+
<datatype>
<name name="secure_renegotiation"/>
<desc><p>Specifies if to reject renegotiation attempt that does
@@ -919,6 +936,8 @@ fun(srp, Username :: string(), UserState :: term()) ->
<name name="dh_der"/>
<desc><p>The DER-encoded Diffie-Hellman parameters. If
specified, it overrides option <c>dhfile</c>.</p>
+ <warning><p>The <c>dh_der</c> option is not supported by TLS 1.3. Use the
+ <c>supported_groups</c> option instead.</p></warning>
</desc>
</datatype>
@@ -928,6 +947,8 @@ fun(srp, Username :: string(), UserState :: term()) ->
parameters to be used by the server if a cipher suite using
Diffie Hellman key exchange is negotiated. If not specified,
default parameters are used.</p>
+ <warning><p>The <c>dh_file</c> option is not supported by TLS 1.3. Use the
+ <c>supported_groups</c> option instead.</p></warning>
</desc>
</datatype>
diff --git a/lib/ssl/src/dtls_handshake.erl b/lib/ssl/src/dtls_handshake.erl
index d8c0e30973..4a381745d4 100644
--- a/lib/ssl/src/dtls_handshake.erl
+++ b/lib/ssl/src/dtls_handshake.erl
@@ -255,7 +255,8 @@ enc_handshake(#client_hello{client_version = {Major, Minor},
CmLength = byte_size(BinCompMethods),
BinCipherSuites = list_to_binary(CipherSuites),
CsLength = byte_size(BinCipherSuites),
- ExtensionsBin = ssl_handshake:encode_hello_extensions(HelloExtensions),
+ ExtensionsBin = ssl_handshake:encode_hello_extensions(HelloExtensions,
+ dtls_v1:corresponding_tls_version({Major, Minor})),
{?CLIENT_HELLO, <<?BYTE(Major), ?BYTE(Minor), Random:32/binary,
?BYTE(SIDLength), SessionID/binary,
diff --git a/lib/ssl/src/ssl.erl b/lib/ssl/src/ssl.erl
index 20b1e85ceb..7ff9aed8ea 100644
--- a/lib/ssl/src/ssl.erl
+++ b/lib/ssl/src/ssl.erl
@@ -128,7 +128,8 @@
tls_alert/0,
srp_param_type/0,
named_curve/0,
- sign_scheme/0]).
+ sign_scheme/0,
+ group/0]).
%% -------------------------------------------------------------------------------------------------------
@@ -243,7 +244,7 @@
secp160r2. % exported
-type group() :: secp256r1 | secp384r1 | secp521r1 | ffdhe2048 |
- ffdhe3072 | ffdhe4096 | ffdhe6144 | ffdhe8192.
+ ffdhe3072 | ffdhe4096 | ffdhe6144 | ffdhe8192. % exported
-type srp_param_type() :: srp_1024 |
srp_1536 |
@@ -296,6 +297,7 @@
{ciphers, cipher_suites()} |
{eccs, [named_curve()]} |
{signature_algs_cert, signature_schemes()} |
+ {supported_groups, supported_groups()} |
{secure_renegotiate, secure_renegotiation()} |
{depth, allowed_cert_chain_length()} |
{verify_fun, custom_verify()} |
@@ -342,6 +344,7 @@
-type protocol_versions() :: [protocol_version()].
-type signature_algs() :: [{hash(), sign_algo()}].
-type signature_schemes() :: [sign_scheme()].
+-type supported_groups() :: [group()].
-type custom_user_lookup() :: {Lookupfun :: fun(), UserState :: any()}.
-type padding_check() :: boolean().
-type beast_mitigation() :: one_n_minus_one | zero_n | disabled.
@@ -979,7 +982,8 @@ cipher_suites(all) ->
%% Description: Returns all default and all supported cipher suites for a
%% TLS/DTLS version
%%--------------------------------------------------------------------
-cipher_suites(Base, Version) when Version == 'tlsv1.2';
+cipher_suites(Base, Version) when Version == 'tlsv1.3';
+ Version == 'tlsv1.2';
Version == 'tlsv1.1';
Version == tlsv1;
Version == sslv3 ->
diff --git a/lib/ssl/src/ssl_cipher.erl b/lib/ssl/src/ssl_cipher.erl
index f4a91cac52..c16e2331ff 100644
--- a/lib/ssl/src/ssl_cipher.erl
+++ b/lib/ssl/src/ssl_cipher.erl
@@ -38,7 +38,7 @@
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,
+ srp_suites/1, srp_suites_anon/1,
rc4_suites/1, des_suites/1, rsa_suites/1,
filter/3, filter_suites/1, filter_suites/2,
hash_algorithm/1, sign_algorithm/1, is_acceptable_hash/2, is_fallback/1,
@@ -284,7 +284,7 @@ all_suites({3, _} = Version) ->
suites(Version)
++ chacha_suites(Version)
++ psk_suites(Version)
- ++ srp_suites()
+ ++ srp_suites(Version)
++ rc4_suites(Version)
++ des_suites(Version)
++ rsa_suites(Version);
@@ -313,8 +313,8 @@ chacha_suites(_) ->
%% Description: Returns a list of the anonymous cipher suites, only supported
%% if explicitly set by user. Intended only for testing.
%%--------------------------------------------------------------------
-anonymous_suites({3, N}) ->
- srp_suites_anon() ++ anonymous_suites(N);
+anonymous_suites({3, N} = Version) ->
+ srp_suites_anon(Version) ++ anonymous_suites(N);
anonymous_suites({254, _} = Version) ->
dtls_v1:anonymous_suites(Version);
anonymous_suites(4) ->
@@ -375,7 +375,7 @@ psk_suites(_) ->
%%--------------------------------------------------------------------
psk_suites_anon({3, N}) ->
psk_suites_anon(N);
-psk_suites_anon(3) ->
+psk_suites_anon(3 = N) ->
[
?TLS_DHE_PSK_WITH_AES_256_GCM_SHA384,
?TLS_PSK_WITH_AES_256_GCM_SHA384,
@@ -401,8 +401,8 @@ psk_suites_anon(3) ->
?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(_) ->
+ ] ++ psk_suites_anon(N-1);
+psk_suites_anon(N) when N > 0 ->
[?TLS_DHE_PSK_WITH_AES_256_CBC_SHA,
?TLS_PSK_WITH_AES_256_CBC_SHA,
?TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA,
@@ -413,14 +413,18 @@ psk_suites_anon(_) ->
?TLS_PSK_WITH_3DES_EDE_CBC_SHA,
?TLS_ECDHE_PSK_WITH_RC4_128_SHA,
?TLS_DHE_PSK_WITH_RC4_128_SHA,
- ?TLS_PSK_WITH_RC4_128_SHA].
+ ?TLS_PSK_WITH_RC4_128_SHA];
+psk_suites_anon(0) ->
+ [].
%%--------------------------------------------------------------------
--spec srp_suites() -> [ssl_cipher_format:cipher_suite()].
+-spec srp_suites(tls_record:tls_version()) -> [ssl_cipher_format:cipher_suite()].
%%
%% Description: Returns a list of the SRP cipher suites, only supported
%% if explicitly set by user.
%%--------------------------------------------------------------------
-srp_suites() ->
+srp_suites({3,0}) ->
+ [];
+srp_suites(_) ->
[?TLS_SRP_SHA_RSA_WITH_3DES_EDE_CBC_SHA,
?TLS_SRP_SHA_DSS_WITH_3DES_EDE_CBC_SHA,
?TLS_SRP_SHA_RSA_WITH_AES_128_CBC_SHA,
@@ -429,12 +433,14 @@ srp_suites() ->
?TLS_SRP_SHA_DSS_WITH_AES_256_CBC_SHA].
%%--------------------------------------------------------------------
--spec srp_suites_anon() -> [ssl_cipher_format:cipher_suite()].
+-spec srp_suites_anon(tls_record:tls_version()) -> [ssl_cipher_format:cipher_suite()].
%%
%% Description: Returns a list of the SRP anonymous cipher suites, only supported
%% if explicitly set by user.
%%--------------------------------------------------------------------
-srp_suites_anon() ->
+srp_suites_anon({3,0}) ->
+ [];
+srp_suites_anon(_) ->
[?TLS_SRP_SHA_WITH_3DES_EDE_CBC_SHA,
?TLS_SRP_SHA_WITH_AES_128_CBC_SHA,
?TLS_SRP_SHA_WITH_AES_256_CBC_SHA].
diff --git a/lib/ssl/src/ssl_connection.erl b/lib/ssl/src/ssl_connection.erl
index de12de646c..2483509228 100644
--- a/lib/ssl/src/ssl_connection.erl
+++ b/lib/ssl/src/ssl_connection.erl
@@ -1275,10 +1275,17 @@ connection({call, From}, {connection_information, false}, State, _) ->
Info = connection_info(State),
hibernate_after(?FUNCTION_NAME, State, [{reply, From, {ok, Info}}]);
connection({call, From}, negotiated_protocol,
- #state{handshake_env = #handshake_env{negotiated_protocol = undefined}} = State, _) ->
+ #state{handshake_env = #handshake_env{alpn = undefined,
+ negotiated_protocol = undefined}} = State, _) ->
hibernate_after(?FUNCTION_NAME, State, [{reply, From, {error, protocol_not_negotiated}}]);
connection({call, From}, negotiated_protocol,
- #state{handshake_env = #handshake_env{negotiated_protocol = SelectedProtocol}} = State, _) ->
+ #state{handshake_env = #handshake_env{alpn = undefined,
+ negotiated_protocol = SelectedProtocol}} = State, _) ->
+ hibernate_after(?FUNCTION_NAME, State,
+ [{reply, From, {ok, SelectedProtocol}}]);
+connection({call, From}, negotiated_protocol,
+ #state{handshake_env = #handshake_env{alpn = SelectedProtocol,
+ negotiated_protocol = undefined}} = State, _) ->
hibernate_after(?FUNCTION_NAME, State,
[{reply, From, {ok, SelectedProtocol}}]);
connection({call, From}, Msg, State, Connection) ->
diff --git a/lib/ssl/src/ssl_handshake.erl b/lib/ssl/src/ssl_handshake.erl
index c6698bc74a..bd2efa9fbb 100644
--- a/lib/ssl/src/ssl_handshake.erl
+++ b/lib/ssl/src/ssl_handshake.erl
@@ -58,7 +58,7 @@
]).
%% Encode
--export([encode_handshake/2, encode_hello_extensions/1, encode_extensions/1, encode_extensions/2,
+-export([encode_handshake/2, encode_hello_extensions/2, encode_extensions/1, encode_extensions/2,
encode_client_protocol_negotiation/2, encode_protocols_advertised_on_server/1]).
%% Decode
-export([decode_handshake/3, decode_vector/1, decode_hello_extensions/4, decode_extensions/3,
@@ -534,14 +534,14 @@ encode_handshake(#next_protocol{selected_protocol = SelectedProtocol}, _Version)
PaddingLength = 32 - ((byte_size(SelectedProtocol) + 2) rem 32),
{?NEXT_PROTOCOL, <<?BYTE((byte_size(SelectedProtocol))), SelectedProtocol/binary,
?BYTE(PaddingLength), 0:(PaddingLength * 8)>>};
-encode_handshake(#server_hello{server_version = {Major, Minor},
+encode_handshake(#server_hello{server_version = {Major, Minor} = Version,
random = Random,
session_id = Session_ID,
cipher_suite = CipherSuite,
compression_method = Comp_method,
extensions = Extensions}, _Version) ->
SID_length = byte_size(Session_ID),
- ExtensionsBin = encode_hello_extensions(Extensions),
+ ExtensionsBin = encode_hello_extensions(Extensions, Version),
{?SERVER_HELLO, <<?BYTE(Major), ?BYTE(Minor), Random:32/binary,
?BYTE(SID_length), Session_ID/binary,
CipherSuite/binary, ?BYTE(Comp_method), ExtensionsBin/binary>>};
@@ -589,7 +589,9 @@ encode_handshake(#certificate_verify{signature = BinSig, hashsign_algorithm = Ha
encode_handshake(#finished{verify_data = VerifyData}, _Version) ->
{?FINISHED, VerifyData}.
-encode_hello_extensions(Extensions) ->
+encode_hello_extensions(_, {3, 0}) ->
+ <<>>;
+encode_hello_extensions(Extensions, _) ->
encode_extensions(hello_extensions_list(Extensions), <<>>).
encode_extensions(Exts) ->
@@ -707,7 +709,25 @@ encode_extensions([#key_share_server_hello{server_share = ServerShare0} | Rest],
encode_extensions([#key_share_hello_retry_request{selected_group = Group0} | Rest], Acc) ->
Group = tls_v1:group_to_enum(Group0),
encode_extensions(Rest, <<?UINT16(?KEY_SHARE_EXT),
- ?UINT16(2), ?UINT16(Group), Acc/binary>>).
+ ?UINT16(2), ?UINT16(Group), Acc/binary>>);
+encode_extensions([#psk_key_exchange_modes{ke_modes = KEModes0} | Rest], Acc) ->
+ KEModes = encode_psk_key_exchange_modes(KEModes0),
+ KEModesLen = byte_size(KEModes),
+ ExtLen = KEModesLen + 1,
+ encode_extensions(Rest, <<?UINT16(?PSK_KEY_EXCHANGE_MODES_EXT),
+ ?UINT16(ExtLen), ?BYTE(KEModesLen), KEModes/binary, Acc/binary>>);
+encode_extensions([#pre_shared_key_client_hello{
+ offered_psks = #offered_psks{
+ identities = Identities0,
+ binders = Binders0} = PSKs} | Rest], Acc) ->
+ Identities = encode_psk_identities(Identities0),
+ Binders = encode_psk_binders(Binders0),
+ Len = byte_size(Identities) + byte_size(Binders),
+ encode_extensions(Rest, <<?UINT16(?PRE_SHARED_KEY_EXT),
+ ?UINT16(Len), Identities/binary, Binders/binary, Acc/binary>>);
+encode_extensions([#pre_shared_key_server_hello{selected_identity = Identity} | Rest], Acc) ->
+ encode_extensions(Rest, <<?UINT16(?PRE_SHARED_KEY_EXT),
+ ?UINT16(2), ?UINT16(Identity), Acc/binary>>).
encode_client_protocol_negotiation(undefined, _) ->
@@ -1256,6 +1276,8 @@ handle_server_hello_extensions(RecordCB, Random, CipherSuite, Compression,
%% We also ignore the ALPN extension during renegotiation (see encode_alpn/2).
[Protocol] when not Renegotiation ->
{ConnectionStates, alpn, Protocol};
+ [_] when Renegotiation ->
+ {ConnectionStates, alpn, undefined};
undefined ->
NextProtocolNegotiation = maps:get(next_protocol_negotiation, Exts, undefined),
Protocol = handle_next_protocol(NextProtocolNegotiation, NextProtoSelector, Renegotiation),
@@ -1486,8 +1508,12 @@ extension_value(#signature_algorithms_cert{signature_scheme_list = Schemes}) ->
Schemes;
extension_value(#key_share_client_hello{client_shares = ClientShares}) ->
ClientShares;
+extension_value(#key_share_server_hello{server_share = ServerShare}) ->
+ ServerShare;
extension_value(#client_hello_versions{versions = Versions}) ->
- Versions.
+ Versions;
+extension_value(#server_hello_selected_version{selected_version = SelectedVersion}) ->
+ SelectedVersion.
%%--------------------------------------------------------------------
@@ -2089,6 +2115,41 @@ encode_key_share_entry(#key_share_entry{
Len = byte_size(KeyExchange),
<<?UINT16((tls_v1:group_to_enum(Group))),?UINT16(Len),KeyExchange/binary>>.
+encode_psk_key_exchange_modes(KEModes) ->
+ encode_psk_key_exchange_modes(lists:reverse(KEModes), <<>>).
+%%
+encode_psk_key_exchange_modes([], Acc) ->
+ Acc;
+encode_psk_key_exchange_modes([psk_ke|T], Acc) ->
+ encode_psk_key_exchange_modes(T, <<?BYTE(?PSK_KE),Acc/binary>>);
+encode_psk_key_exchange_modes([psk_dhe_ke|T], Acc) ->
+ encode_psk_key_exchange_modes(T, <<?BYTE(?PSK_DHE_KE),Acc/binary>>).
+
+
+encode_psk_identities(Identities) ->
+ encode_psk_identities(Identities, <<>>).
+%%
+encode_psk_identities([], Acc) ->
+ Len = byte_size(Acc),
+ <<?UINT16(Len), Acc/binary>>;
+encode_psk_identities([#psk_identity{
+ identity = Identity,
+ obfuscated_ticket_age = Age}|T], Acc) ->
+ IdLen = byte_size(Identity),
+ encode_psk_identities(T, <<Acc/binary,?UINT16(IdLen),Identity/binary,Age/binary>>).
+
+
+encode_psk_binders(Binders) ->
+ encode_psk_binders(Binders, <<>>).
+%%
+encode_psk_binders([], Acc) ->
+ Len = byte_size(Acc),
+ <<?UINT16(Len), Acc/binary>>;
+encode_psk_binders([Binder|T], Acc) ->
+ Len = byte_size(Binder),
+ encode_psk_binders(T, <<Acc/binary,?BYTE(Len),Binder/binary>>).
+
+
hello_extensions_list(HelloExtensions) ->
[Ext || {_, Ext} <- maps:to_list(HelloExtensions), Ext =/= undefined].
@@ -2441,6 +2502,33 @@ decode_extensions(<<?UINT16(?KEY_SHARE_EXT), ?UINT16(Len),
#key_share_hello_retry_request{
selected_group = tls_v1:enum_to_group(Group)}});
+decode_extensions(<<?UINT16(?PSK_KEY_EXCHANGE_MODES_EXT), ?UINT16(Len),
+ ExtData:Len/binary, Rest/binary>>, Version, MessageType, Acc) ->
+ <<?BYTE(PLen),KEModes:PLen/binary>> = ExtData,
+ decode_extensions(Rest, Version, MessageType,
+ Acc#{psk_key_exchange_modes =>
+ #psk_key_exchange_modes{
+ ke_modes = decode_psk_key_exchange_modes(KEModes)}});
+
+decode_extensions(<<?UINT16(?PRE_SHARED_KEY_EXT), ?UINT16(Len),
+ ExtData:Len/binary, Rest/binary>>,
+ Version, MessageType = client_hello, Acc) ->
+ <<?UINT16(IdLen),Identities:IdLen/binary,?UINT16(BLen),Binders:BLen/binary>> = ExtData,
+ decode_extensions(Rest, Version, MessageType,
+ Acc#{pre_shared_key =>
+ #pre_shared_key_client_hello{
+ offered_psks = #offered_psks{
+ identities = decode_psk_identities(Identities),
+ binders = decode_psk_binders(Binders)}}});
+
+decode_extensions(<<?UINT16(?PRE_SHARED_KEY_EXT), ?UINT16(Len),
+ ExtData:Len/binary, Rest/binary>>,
+ Version, MessageType = server_hello, Acc) ->
+ <<?UINT16(Identity)>> = ExtData,
+ decode_extensions(Rest, Version, MessageType,
+ Acc#{pre_shared_key =>
+ #pre_shared_key_server_hello{
+ selected_identity = Identity}});
%% Ignore data following the ClientHello (i.e.,
%% extensions) if not understood.
@@ -2500,6 +2588,38 @@ decode_protocols(<<?BYTE(Len), Protocol:Len/binary, Rest/binary>>, Acc) ->
decode_protocols(_Bytes, _Acc) ->
{error, invalid_protocols}.
+
+decode_psk_key_exchange_modes(KEModes) ->
+ decode_psk_key_exchange_modes(KEModes, []).
+%%
+decode_psk_key_exchange_modes(<<>>, Acc) ->
+ lists:reverse(Acc);
+decode_psk_key_exchange_modes(<<?BYTE(?PSK_KE), Rest/binary>>, Acc) ->
+ decode_psk_key_exchange_modes(Rest, [psk_ke|Acc]);
+decode_psk_key_exchange_modes(<<?BYTE(?PSK_DHE_KE), Rest/binary>>, Acc) ->
+ decode_psk_key_exchange_modes(Rest, [psk_dhe_ke|Acc]).
+
+
+decode_psk_identities(Identities) ->
+ decode_psk_identities(Identities, []).
+%%
+decode_psk_identities(<<>>, Acc) ->
+ lists:reverse(Acc);
+decode_psk_identities(<<?UINT16(Len), Identity:Len/binary, Age:4/binary, Rest/binary>>, Acc) ->
+ decode_psk_identities(Rest, [#psk_identity{
+ identity = Identity,
+ obfuscated_ticket_age = Age}|Acc]).
+
+
+decode_psk_binders(Binders) ->
+ decode_psk_binders(Binders, []).
+%%
+decode_psk_binders(<<>>, Acc) ->
+ lists:reverse(Acc);
+decode_psk_binders(<<?BYTE(Len), Binder:Len/binary, Rest/binary>>, Acc) ->
+ decode_psk_binders(Rest, [Binder|Acc]).
+
+
%% encode/decode stream of certificate data to/from list of certificate data
certs_to_list(ASN1Certs) ->
certs_to_list(ASN1Certs, []).
@@ -2666,7 +2786,7 @@ filter_unavailable_ecc_suites(_, Suites) ->
handle_renegotiation_extension(Role, RecordCB, Version, Info, Random, NegotiatedCipherSuite,
ClientCipherSuites, Compression,
ConnectionStates0, Renegotiation, SecureRenegotation) ->
- {ok, ConnectionStates} = handle_renegotiation_info(RecordCB, Role, Info, ConnectionStates0,
+ {ok, ConnectionStates} = handle_renegotiation_info(Version, RecordCB, Role, Info, ConnectionStates0,
Renegotiation, SecureRenegotation,
ClientCipherSuites),
hello_pending_connection_states(RecordCB, Role,
@@ -2936,11 +3056,11 @@ renegotiation_info(_RecordCB, server, ConnectionStates, true) ->
#renegotiation_info{renegotiated_connection = undefined}
end.
-handle_renegotiation_info(_RecordCB, _, #renegotiation_info{renegotiated_connection = ?byte(0)},
+handle_renegotiation_info(_, _RecordCB, _, #renegotiation_info{renegotiated_connection = ?byte(0)},
ConnectionStates, false, _, _) ->
{ok, ssl_record:set_renegotiation_flag(true, ConnectionStates)};
-handle_renegotiation_info(_RecordCB, server, undefined, ConnectionStates, _, _, CipherSuites) ->
+handle_renegotiation_info(_, _RecordCB, server, undefined, ConnectionStates, _, _, CipherSuites) ->
case is_member(?TLS_EMPTY_RENEGOTIATION_INFO_SCSV, CipherSuites) of
true ->
{ok, ssl_record:set_renegotiation_flag(true, ConnectionStates)};
@@ -2948,10 +3068,10 @@ handle_renegotiation_info(_RecordCB, server, undefined, ConnectionStates, _, _,
{ok, ssl_record:set_renegotiation_flag(false, ConnectionStates)}
end;
-handle_renegotiation_info(_RecordCB, _, undefined, ConnectionStates, false, _, _) ->
+handle_renegotiation_info(_, _RecordCB, _, undefined, ConnectionStates, false, _, _) ->
{ok, ssl_record:set_renegotiation_flag(false, ConnectionStates)};
-handle_renegotiation_info(_RecordCB, client, #renegotiation_info{renegotiated_connection = ClientServerVerify},
+handle_renegotiation_info(_, _RecordCB, client, #renegotiation_info{renegotiated_connection = ClientServerVerify},
ConnectionStates, true, _, _) ->
ConnectionState = ssl_record:current_connection_state(ConnectionStates, read),
CData = maps:get(client_verify_data, ConnectionState),
@@ -2962,7 +3082,7 @@ handle_renegotiation_info(_RecordCB, client, #renegotiation_info{renegotiated_co
false ->
throw(?ALERT_REC(?FATAL, ?HANDSHAKE_FAILURE, client_renegotiation))
end;
-handle_renegotiation_info(_RecordCB, server, #renegotiation_info{renegotiated_connection = ClientVerify},
+handle_renegotiation_info(_, _RecordCB, server, #renegotiation_info{renegotiated_connection = ClientVerify},
ConnectionStates, true, _, CipherSuites) ->
case is_member(?TLS_EMPTY_RENEGOTIATION_INFO_SCSV, CipherSuites) of
@@ -2978,11 +3098,13 @@ handle_renegotiation_info(_RecordCB, server, #renegotiation_info{renegotiated_co
throw(?ALERT_REC(?FATAL, ?HANDSHAKE_FAILURE, server_renegotiation))
end
end;
+handle_renegotiation_info({3,0}, _RecordCB, client, undefined, ConnectionStates, true, _SecureRenegotation, _) ->
+ {ok, ssl_record:set_renegotiation_flag(true, ConnectionStates)};
-handle_renegotiation_info(RecordCB, client, undefined, ConnectionStates, true, SecureRenegotation, _) ->
+handle_renegotiation_info(_, RecordCB, client, undefined, ConnectionStates, true, SecureRenegotation, _) ->
handle_renegotiation_info(RecordCB, ConnectionStates, SecureRenegotation);
-handle_renegotiation_info(RecordCB, server, undefined, ConnectionStates, true, SecureRenegotation, CipherSuites) ->
+handle_renegotiation_info(_, RecordCB, server, undefined, ConnectionStates, true, SecureRenegotation, CipherSuites) ->
case is_member(?TLS_EMPTY_RENEGOTIATION_INFO_SCSV, CipherSuites) of
true ->
throw(?ALERT_REC(?FATAL, ?HANDSHAKE_FAILURE, {server_renegotiation, empty_renegotiation_info_scsv}));
@@ -3036,7 +3158,7 @@ empty_extensions({3,4}, client_hello) ->
%% padding => undefined,
key_share => undefined,
pre_shared_key => undefined,
- %% psk_key_exhange_modes => undefined,
+ psk_key_exchange_modes => undefined,
%% early_data => undefined,
%% cookie => undefined,
client_hello_versions => undefined,
@@ -3065,6 +3187,8 @@ empty_extensions({3,4}, hello_retry_request) ->
key_share => undefined,
pre_shared_key => undefined
};
+empty_extensions({3,0}, _) ->
+ empty_extensions();
empty_extensions(_, server_hello) ->
#{renegotiation_info => undefined,
alpn => undefined,
diff --git a/lib/ssl/src/tls_handshake.erl b/lib/ssl/src/tls_handshake.erl
index c132f75eae..37265e0759 100644
--- a/lib/ssl/src/tls_handshake.erl
+++ b/lib/ssl/src/tls_handshake.erl
@@ -379,7 +379,7 @@ do_hello(Version, Versions, CipherSuites, Hello, SslOpts, Info, Renegotiation) -
%%--------------------------------------------------------------------
enc_handshake(#hello_request{}, {3, N}) when N < 4 ->
{?HELLO_REQUEST, <<>>};
-enc_handshake(#client_hello{client_version = {Major, Minor},
+enc_handshake(#client_hello{client_version = {Major, Minor} = Version,
random = Random,
session_id = SessionID,
cipher_suites = CipherSuites,
@@ -390,7 +390,7 @@ enc_handshake(#client_hello{client_version = {Major, Minor},
CmLength = byte_size(BinCompMethods),
BinCipherSuites = list_to_binary(CipherSuites),
CsLength = byte_size(BinCipherSuites),
- ExtensionsBin = ssl_handshake:encode_hello_extensions(HelloExtensions),
+ ExtensionsBin = ssl_handshake:encode_hello_extensions(HelloExtensions, Version),
{?CLIENT_HELLO, <<?BYTE(Major), ?BYTE(Minor), Random:32/binary,
?BYTE(SIDLength), SessionID/binary,
diff --git a/lib/ssl/src/tls_handshake_1_3.erl b/lib/ssl/src/tls_handshake_1_3.erl
index 49d20b3ec0..c29366e717 100644
--- a/lib/ssl/src/tls_handshake_1_3.erl
+++ b/lib/ssl/src/tls_handshake_1_3.erl
@@ -39,7 +39,7 @@
%% Create handshake messages
-export([certificate/5,
certificate_verify/4,
- encrypted_extensions/0]).
+ encrypted_extensions/1]).
-export([do_start/2,
do_negotiated/2,
@@ -61,10 +61,10 @@
%% Create handshake messages
%%====================================================================
-server_hello(MsgType, SessionId, KeyShare, ConnectionStates, ALPN) ->
+server_hello(MsgType, SessionId, KeyShare, ConnectionStates) ->
#{security_parameters := SecParams} =
ssl_record:pending_connection_state(ConnectionStates, read),
- Extensions = server_hello_extensions(MsgType, KeyShare, ALPN),
+ Extensions = server_hello_extensions(MsgType, KeyShare),
#server_hello{server_version = {3,3}, %% legacy_version
cipher_suite = SecParams#security_parameters.cipher_suite,
compression_method = 0, %% legacy attribute
@@ -73,6 +73,7 @@ server_hello(MsgType, SessionId, KeyShare, ConnectionStates, ALPN) ->
extensions = Extensions
}.
+
%% The server's extensions MUST contain "supported_versions".
%% Additionally, it SHOULD contain the minimal set of extensions
%% necessary for the client to generate a correct ClientHello pair. As
@@ -80,18 +81,14 @@ server_hello(MsgType, SessionId, KeyShare, ConnectionStates, ALPN) ->
%% extensions that were not first offered by the client in its
%% ClientHello, with the exception of optionally the "cookie" (see
%% Section 4.2.2) extension.
-server_hello_extensions(hello_retry_request = MsgType, KeyShare, _) ->
+server_hello_extensions(hello_retry_request = MsgType, KeyShare) ->
SupportedVersions = #server_hello_selected_version{selected_version = {3,4}},
Extensions = #{server_hello_selected_version => SupportedVersions},
ssl_handshake:add_server_share(MsgType, Extensions, KeyShare);
-server_hello_extensions(MsgType, KeyShare, undefined) ->
+server_hello_extensions(MsgType, KeyShare) ->
SupportedVersions = #server_hello_selected_version{selected_version = {3,4}},
Extensions = #{server_hello_selected_version => SupportedVersions},
- ssl_handshake:add_server_share(MsgType, Extensions, KeyShare);
-server_hello_extensions(MsgType, KeyShare, ALPN0) ->
- Extensions0 = ssl_handshake:add_selected_version(#{}), %% {3,4} (TLS 1.3)
- Extensions1 = ssl_handshake:add_alpn(Extensions0, ALPN0),
- ssl_handshake:add_server_share(MsgType, Extensions1, KeyShare).
+ ssl_handshake:add_server_share(MsgType, Extensions, KeyShare).
server_hello_random(server_hello, #security_parameters{server_random = Random}) ->
@@ -107,10 +104,14 @@ server_hello_random(hello_retry_request, _) ->
?HELLO_RETRY_REQUEST_RANDOM.
-%% TODO: implement support for encrypted_extensions
-encrypted_extensions() ->
+encrypted_extensions(#state{handshake_env = #handshake_env{alpn = undefined}}) ->
#encrypted_extensions{
extensions = #{}
+ };
+encrypted_extensions(#state{handshake_env = #handshake_env{alpn = ALPNProtocol}}) ->
+ Extensions = ssl_handshake:add_alpn(#{}, ALPNProtocol),
+ #encrypted_extensions{
+ extensions = Extensions
}.
@@ -503,7 +504,8 @@ do_start(#client_hello{cipher_suites = ClientCiphers,
ssl_options = #ssl_options{ciphers = ServerCiphers,
signature_algs = ServerSignAlgs,
supported_groups = ServerGroups0,
- alpn_preferred_protocols = ALPNPreferredProtocols},
+ alpn_preferred_protocols = ALPNPreferredProtocols,
+ honor_cipher_order = HonorCipherOrder},
session = #session{own_certificate = Cert}} = State0) ->
ClientGroups0 = maps:get(elliptic_curves, Extensions, undefined),
ClientGroups = get_supported_groups(ClientGroups0),
@@ -530,7 +532,7 @@ do_start(#client_hello{cipher_suites = ClientCiphers,
%% cipher suite, an (EC)DHE group and key share for key establishment,
%% and a signature algorithm/certificate pair to authenticate itself to
%% the client.
- Cipher = Maybe(select_cipher_suite(ClientCiphers, ServerCiphers)),
+ Cipher = Maybe(select_cipher_suite(HonorCipherOrder, ClientCiphers, ServerCiphers)),
Groups = Maybe(select_common_groups(ServerGroups, ClientGroups)),
Maybe(validate_client_key_share(ClientGroups, ClientShares)),
@@ -673,8 +675,7 @@ do_negotiated(start_handshake,
dh_public_value = ClientPublicKey},
ssl_options = #ssl_options{} = SslOpts,
key_share = KeyShare,
- handshake_env = #handshake_env{tls_handshake_history = _HHistory0,
- alpn = ALPN},
+ handshake_env = #handshake_env{tls_handshake_history = _HHistory0},
connection_env = #connection_env{private_key = CertPrivateKey},
static_env = #static_env{
cert_db = CertDbHandle,
@@ -689,7 +690,7 @@ do_negotiated(start_handshake,
try
%% Create server_hello
%% Extensions: supported_versions, key_share, (pre_shared_key)
- ServerHello = server_hello(server_hello, SessionId, KeyShare, ConnectionStates0, ALPN),
+ ServerHello = server_hello(server_hello, SessionId, KeyShare, ConnectionStates0),
{State1, _} = tls_connection:send_handshake(ServerHello, State0),
@@ -699,7 +700,7 @@ do_negotiated(start_handshake,
State3 = ssl_record:step_encryption_state(State2),
%% Create EncryptedExtensions
- EncryptedExtensions = encrypted_extensions(),
+ EncryptedExtensions = encrypted_extensions(State2),
%% Encode EncryptedExtensions
State4 = tls_connection:queue_handshake(EncryptedExtensions, State3),
@@ -881,12 +882,19 @@ do_wait_sh(#server_hello{cipher_suite = SelectedCipherSuite,
end.
-do_wait_ee(#encrypted_extensions{extensions = _Extensions}, State0) ->
+do_wait_ee(#encrypted_extensions{extensions = Extensions}, State0) ->
+
+ ALPNProtocol0 = maps:get(alpn, Extensions, undefined),
+ ALPNProtocol = get_alpn(ALPNProtocol0),
{Ref,_Maybe} = maybe(),
try
- {State0, wait_cert_cr}
+ %% Update state
+ #state{handshake_env = HsEnv} = State0,
+ State1 = State0#state{handshake_env = HsEnv#handshake_env{alpn = ALPNProtocol}},
+
+ {State1, wait_cert_cr}
catch
{Ref, {insufficient_security, no_suitable_groups}} ->
?ALERT_REC(?FATAL, ?INSUFFICIENT_SECURITY, no_suitable_groups);
@@ -1041,10 +1049,9 @@ compare_verify_data(_, _) ->
{error, decrypt_error}.
-send_hello_retry_request(#state{connection_states = ConnectionStates0,
- handshake_env = #handshake_env{alpn = ALPN}} = State0,
+send_hello_retry_request(#state{connection_states = ConnectionStates0} = State0,
no_suitable_key, KeyShare, SessionId) ->
- ServerHello = server_hello(hello_retry_request, SessionId, KeyShare, ConnectionStates0, ALPN),
+ ServerHello = server_hello(hello_retry_request, SessionId, KeyShare, ConnectionStates0),
{State1, _} = tls_connection:send_handshake(ServerHello, State0),
%% Update handshake history
@@ -1725,15 +1732,19 @@ handle_alpn([ServerProtocol|T], ClientProtocols) ->
end.
-select_cipher_suite([], _) ->
+select_cipher_suite(_, [], _) ->
{error, no_suitable_cipher};
-select_cipher_suite([Cipher|ClientCiphers], ServerCiphers) ->
+%% If honor_cipher_order is set to true, use the server's preference for
+%% cipher suite selection.
+select_cipher_suite(true, ClientCiphers, ServerCiphers) ->
+ select_cipher_suite(false, ServerCiphers, ClientCiphers);
+select_cipher_suite(false, [Cipher|ClientCiphers], ServerCiphers) ->
case lists:member(Cipher, tls_v1:suites('TLS_v1.3')) andalso
lists:member(Cipher, ServerCiphers) of
true ->
{ok, Cipher};
false ->
- select_cipher_suite(ClientCiphers, ServerCiphers)
+ select_cipher_suite(false, ClientCiphers, ServerCiphers)
end.
@@ -1869,6 +1880,14 @@ get_key_shares(#key_share_server_hello{server_share = ServerShare}) ->
get_selected_group(#key_share_hello_retry_request{selected_group = SelectedGroup}) ->
SelectedGroup.
+get_alpn(ALPNProtocol0) ->
+ case ssl_handshake:decode_alpn(ALPNProtocol0) of
+ undefined ->
+ undefined;
+ [ALPNProtocol] ->
+ ALPNProtocol
+ end.
+
maybe() ->
Ref = erlang:make_ref(),
Ok = fun(ok) -> ok;
diff --git a/lib/ssl/src/tls_handshake_1_3.hrl b/lib/ssl/src/tls_handshake_1_3.hrl
index 7ae1b93e1c..eb85f216c8 100644
--- a/lib/ssl/src/tls_handshake_1_3.hrl
+++ b/lib/ssl/src/tls_handshake_1_3.hrl
@@ -74,29 +74,52 @@
y % opaque Y[coordinate_length];
}).
+%% RFC 8446 4.2.9. Pre-Shared Key Exchange Modes
+
+%% enum { psk_ke(0), psk_dhe_ke(1), (255) } PskKeyExchangeMode;
-define(PSK_KE, 0).
-define(PSK_DHE_KE, 1).
--record(psk_keyexchange_modes, {
+-record(psk_key_exchange_modes, {
ke_modes % ke_modes<1..255>
}).
+
+%% RFC 8446 4.2.10. Early Data Indication
-record(empty, {
}).
-record(early_data_indication, {
indication % uint32 max_early_data_size (new_session_ticket) |
%% #empty{} (client_hello, encrypted_extensions)
}).
--record(psk_identity, {
- identity, % opaque identity<1..2^16-1>
- obfuscated_ticket_age % uint32
- }).
--record(offered_psks, {
- psk_identity, %identities<7..2^16-1>;
- psk_binder_entry %binders<33..2^16-1>, opaque PskBinderEntry<32..255>
- }).
--record(pre_shared_keyextension,{
- extension %OfferedPsks (client_hello) | uint16 selected_identity (server_hello)
- }).
+
+%% RFC 8446 4.2.11. Pre-Shared Key Extension
+-record(psk_identity,
+ {
+ identity, % opaque identity<1..2^16-1>
+ obfuscated_ticket_age % uint32
+ }).
+
+-record(offered_psks,
+ {
+ identities, % PskIdentity identities<7..2^16-1>;
+ binders % PskBinderEntry binders<33..2^16-1>; opaque PskBinderEntry<32..255>
+ }).
+
+%% struct {
+%% select (Handshake.msg_type) {
+%% case client_hello: OfferedPsks;
+%% case server_hello: uint16 selected_identity;
+%% };
+%% } PreSharedKeyExtension;
+-record(pre_shared_key_client_hello,
+ {
+ offered_psks
+ }).
+
+-record(pre_shared_key_server_hello,
+ {
+ selected_identity
+ }).
%% RFC 8446 B.3.1.2.
-record(cookie, {
diff --git a/lib/ssl/src/tls_record_1_3.erl b/lib/ssl/src/tls_record_1_3.erl
index 74321a1ae2..d713062284 100644
--- a/lib/ssl/src/tls_record_1_3.erl
+++ b/lib/ssl/src/tls_record_1_3.erl
@@ -138,6 +138,15 @@ decode_cipher_text(#ssl_tls{type = ?ALERT,
{#ssl_tls{type = ?ALERT,
version = {3,4}, %% Internally use real version
fragment = <<2,47>>}, ConnectionStates0};
+%% TLS 1.3 server can receive a User Cancelled Alert when handshake is
+%% paused and then cancelled on the client side.
+decode_cipher_text(#ssl_tls{type = ?ALERT,
+ version = ?LEGACY_VERSION,
+ fragment = <<2,90>>},
+ ConnectionStates0) ->
+ {#ssl_tls{type = ?ALERT,
+ version = {3,4}, %% Internally use real version
+ fragment = <<2,90>>}, ConnectionStates0};
%% RFC8446 - TLS 1.3
%% D.4. Middlebox Compatibility Mode
%% - If not offering early data, the client sends a dummy
diff --git a/lib/ssl/test/Makefile b/lib/ssl/test/Makefile
index dba90aaff0..0925c0facc 100644
--- a/lib/ssl/test/Makefile
+++ b/lib/ssl/test/Makefile
@@ -37,14 +37,29 @@ VSN=$(SSL_VSN)
MODULES = \
ssl_test_lib \
+ ssl_app_env_SUITE\
+ ssl_alert_SUITE\
ssl_bench_test_lib \
ssl_dist_test_lib \
- ssl_alpn_handshake_SUITE \
+ ssl_api_SUITE\
+ tls_api_SUITE\
ssl_basic_SUITE \
ssl_bench_SUITE \
ssl_cipher_SUITE \
ssl_cipher_suite_SUITE \
- openssl_server_cipher_suite_SUITE\
+ openssl_cipher_suite_SUITE\
+ ssl_alpn_SUITE \
+ openssl_alpn_SUITE\
+ ssl_npn_SUITE \
+ openssl_npn_SUITE\
+ openssl_sni_SUITE\
+ ssl_renegotiate_SUITE\
+ openssl_renegotiate_SUITE\
+ openssl_reject_SUITE\
+ ssl_cert_tests\
+ ssl_cert_SUITE\
+ openssl_server_cert_SUITE\
+ openssl_client_cert_SUITE\
ssl_certificate_verify_SUITE\
ssl_crl_SUITE\
ssl_dist_SUITE \
@@ -52,12 +67,12 @@ MODULES = \
ssl_engine_SUITE\
ssl_handshake_SUITE \
ssl_npn_hello_SUITE \
- ssl_npn_handshake_SUITE \
ssl_packet_SUITE \
ssl_payload_SUITE \
ssl_pem_cache_SUITE \
+ ssl_session_SUITE \
ssl_session_cache_SUITE \
- ssl_to_openssl_SUITE \
+ openssl_session_SUITE \
ssl_ECC_SUITE \
ssl_ECC_openssl_SUITE \
ssl_ECC\
@@ -65,6 +80,10 @@ MODULES = \
ssl_sni_SUITE \
ssl_eqc_SUITE \
ssl_rfc_5869_SUITE \
+ tls_1_3_record_SUITE\
+ openssl_tls_1_3_version_SUITE\
+ tls_1_3_version_SUITE\
+ ssl_socket_SUITE\
make_certs \
x509_test \
inet_crypto_dist
diff --git a/lib/ssl/test/openssl_alpn_SUITE.erl b/lib/ssl/test/openssl_alpn_SUITE.erl
new file mode 100644
index 0000000000..1e8912be7d
--- /dev/null
+++ b/lib/ssl/test/openssl_alpn_SUITE.erl
@@ -0,0 +1,417 @@
+%%
+%% %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(openssl_alpn_SUITE).
+
+%% Note: This directive should only be used in test suites.
+-compile(export_all).
+
+-include_lib("common_test/include/ct.hrl").
+
+-define(OPENSSL_QUIT, "Q\n").
+-define(OPENSSL_RENEGOTIATE, "R\n").
+-define(SLEEP, 1000).
+
+%%--------------------------------------------------------------------
+%% Common Test interface functions -----------------------------------
+%%--------------------------------------------------------------------
+
+all() ->
+ %% Note: ALPN not supported in sslv3
+ case ssl_test_lib:openssl_sane_dtls() of
+ true ->
+ [
+ {group, 'tlsv1.3'},
+ {group, 'tlsv1.2'},
+ {group, 'tlsv1.1'},
+ {group, 'tlsv1'},
+ {group, 'dtlsv1.2'},
+ {group, 'dtlsv1'}];
+ false ->
+ [{group, 'tlsv1.2'},
+ {group, 'tlsv1.1'},
+ {group, 'tlsv1'}]
+ end.
+
+groups() ->
+ case ssl_test_lib:openssl_sane_dtls() of
+ true ->
+ [
+ {'tlsv1.3', [], alpn_tests()},
+ {'tlsv1.2', [], alpn_tests() ++ alpn_npn_coexist() ++ rengotiation_tests()},
+ {'tlsv1.1', [], alpn_tests() ++ alpn_npn_coexist() ++ rengotiation_tests()},
+ {'tlsv1', [], alpn_tests() ++ alpn_npn_coexist() ++ rengotiation_tests()},
+ {'dtlsv1.2', [], alpn_tests()},
+ {'dtlsv1', [], alpn_tests()}
+ ];
+ false ->
+ [
+ {'tlsv1.3', [], alpn_tests()},
+ {'tlsv1.2', [], alpn_tests() ++ alpn_npn_coexist() ++ rengotiation_tests()},
+ {'tlsv1.1', [], alpn_tests() ++ alpn_npn_coexist() ++ rengotiation_tests()},
+ {'tlsv1', [], alpn_tests() ++ alpn_npn_coexist() ++ rengotiation_tests()}
+ ]
+ end.
+
+alpn_tests() ->
+ [erlang_client_alpn_openssl_server_alpn,
+ erlang_server_alpn_openssl_client_alpn,
+ erlang_client_alpn_openssl_server,
+ erlang_client_openssl_server_alpn,
+ erlang_server_alpn_openssl_client,
+ erlang_server_openssl_client_alpn].
+
+alpn_npn_coexist() ->
+ [
+ erlang_client_alpn_npn_openssl_server_alpn_npn,
+ erlang_server_alpn_npn_openssl_client_alpn_npn
+ ].
+rengotiation_tests() ->
+ [erlang_client_alpn_openssl_server_alpn_renegotiate,
+ erlang_server_alpn_openssl_client_alpn_renegotiate].
+
+init_per_suite(Config0) ->
+ case os:find_executable("openssl") of
+ false ->
+ {skip, "Openssl not found"};
+ _ ->
+ case check_openssl_alpn_support(Config0) of
+ {skip, _} = Skip ->
+ Skip;
+ _ ->
+ ct:pal("Version: ~p", [os:cmd("openssl version")]),
+ catch crypto:stop(),
+ try crypto:start() of
+ ok ->
+ ssl_test_lib:clean_start(),
+ ssl_test_lib:make_rsa_cert(Config0)
+ catch _:_ ->
+ {skip, "Crypto did not start"}
+ end
+ end
+ end.
+
+end_per_suite(_Config) ->
+ ssl:stop(),
+ application:stop(crypto),
+ ssl_test_lib:kill_openssl().
+
+init_per_group(GroupName, Config) ->
+ case ssl_test_lib:is_tls_version(GroupName) of
+ true ->
+ case ssl_test_lib:supports_ssl_tls_version(GroupName) of
+ true ->
+ case ssl_test_lib:check_sane_openssl_version(GroupName) of
+ true ->
+ ssl_test_lib:init_tls_version(GroupName, Config);
+ false ->
+ {skip, openssl_does_not_support_version}
+ end;
+ false ->
+ {skip, openssl_does_not_support_version}
+ end;
+ _ ->
+ Config
+ 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) ->
+ ct:timetrap({seconds, 10}),
+ special_init(TestCase, Config).
+
+special_init(TestCase, Config)
+ when TestCase == erlang_client_alpn_openssl_server_alpn_renegotiate;
+ TestCase == erlang_server_alpn_openssl_client_alpn_renegotiate ->
+ {ok, Version} = application:get_env(ssl, protocol_version),
+ ssl_test_lib:check_sane_openssl_renegotaite(Config, Version);
+special_init(TestCase, Config)
+ when TestCase == erlang_client_alpn_npn_openssl_server_alpn_npn;
+ TestCase == erlang_server_alpn_npn_openssl_client_alpn_npn ->
+ ssl_test_lib:check_openssl_npn_support(Config);
+special_init(_, Config) ->
+ Config.
+
+end_per_testcase(_, Config) ->
+ Config.
+
+%%--------------------------------------------------------------------
+%% Test Cases --------------------------------------------------------
+%%--------------------------------------------------------------------
+
+erlang_client_alpn_openssl_server_alpn(Config) when is_list(Config) ->
+ Data = "From openssl to erlang",
+ start_erlang_client_and_openssl_server_for_alpn_negotiation(Config, Data, fun(Client, OpensslPort) ->
+ true = port_command(OpensslPort, Data),
+ ssl_test_lib:check_result(Client, Data)
+ end).
+
+%%--------------------------------------------------------------------
+
+erlang_server_alpn_openssl_client_alpn(Config) when is_list(Config) ->
+ Data = "From openssl to erlang",
+ start_erlang_server_and_openssl_client_for_alpn_negotiation(Config, Data, fun(Client, OpensslPort) ->
+ true = port_command(OpensslPort, Data),
+ ssl_test_lib:check_result(Client, Data)
+ end).
+
+%%--------------------------------------------------------------------------
+
+erlang_client_alpn_openssl_server(Config) when is_list(Config) ->
+ Data = "From openssl to erlang",
+ ssl_test_lib:start_erlang_client_and_openssl_server_with_opts(Config,
+ [{alpn_advertised_protocols, [<<"spdy/2">>]}],
+ [],
+ Data, fun(Client, OpensslPort) ->
+ true = port_command(OpensslPort, Data),
+ ssl_test_lib:check_result(Client, Data)
+ end).
+
+%%--------------------------------------------------------------------------
+
+erlang_client_openssl_server_alpn(Config) when is_list(Config) ->
+ Data = "From openssl to erlang",
+ ssl_test_lib:start_erlang_client_and_openssl_server_with_opts(Config,
+ [],
+ ["-alpn", "spdy/2"],
+ Data, fun(Client, OpensslPort) ->
+ true = port_command(OpensslPort, Data),
+ ssl_test_lib:check_result(Client, Data)
+ end).
+
+%%--------------------------------------------------------------------------
+
+erlang_server_alpn_openssl_client(Config) when is_list(Config) ->
+ Data = "From openssl to erlang",
+ ssl_test_lib:start_erlang_server_and_openssl_client_with_opts(Config,
+ [{alpn_preferred_protocols, [<<"spdy/2">>]}],
+ [],
+ Data, fun(Server, OpensslPort) ->
+ true = port_command(OpensslPort, Data),
+ ssl_test_lib:check_result(Server, Data)
+ end).
+
+%%--------------------------------------------------------------------------
+
+erlang_server_openssl_client_alpn(Config) when is_list(Config) ->
+ Data = "From openssl to erlang",
+ ssl_test_lib:start_erlang_server_and_openssl_client_with_opts(Config,
+ [],
+ ["-alpn", "spdy/2"],
+ Data, fun(Server, OpensslPort) ->
+ true = port_command(OpensslPort, Data),
+ ssl_test_lib:check_result(Server, Data)
+ end).
+
+%%--------------------------------------------------------------------
+
+erlang_client_alpn_openssl_server_alpn_renegotiate(Config) when is_list(Config) ->
+ Data = "From openssl to erlang",
+ start_erlang_client_and_openssl_server_for_alpn_negotiation(Config, Data, fun(Client, OpensslPort) ->
+ true = port_command(OpensslPort, ?OPENSSL_RENEGOTIATE),
+ ct:sleep(?SLEEP),
+ true = port_command(OpensslPort, Data),
+ ssl_test_lib:check_result(Client, Data)
+ end).
+
+%%--------------------------------------------------------------------
+
+erlang_server_alpn_openssl_client_alpn_renegotiate(Config) when is_list(Config) ->
+ Data = "From openssl to erlang",
+ start_erlang_server_and_openssl_client_for_alpn_negotiation(Config, Data, fun(Server, OpensslPort) ->
+ true = port_command(OpensslPort, ?OPENSSL_RENEGOTIATE),
+ ct:sleep(?SLEEP),
+ true = port_command(OpensslPort, Data),
+ ssl_test_lib:check_result(Server, Data)
+ end).
+
+%%--------------------------------------------------------------------
+
+erlang_client_alpn_npn_openssl_server_alpn_npn(Config) when is_list(Config) ->
+ Data = "From openssl to erlang",
+ start_erlang_client_and_openssl_server_for_alpn_npn_negotiation(Config, Data, fun(Client, OpensslPort) ->
+ true = port_command(OpensslPort, Data),
+ ssl_test_lib:check_result(Client, Data)
+ end).
+
+%%--------------------------------------------------------------------
+
+erlang_server_alpn_npn_openssl_client_alpn_npn(Config) when is_list(Config) ->
+ Data = "From openssl to erlang",
+ start_erlang_server_and_openssl_client_for_alpn_npn_negotiation(Config, Data, fun(Server, OpensslPort) ->
+ true = port_command(OpensslPort, Data),
+ ssl_test_lib:check_result(Server, Data)
+ end).
+
+
+%%--------------------------------------------------------------------
+%% Internal functions -----------------------------------------------
+%%--------------------------------------------------------------------
+check_openssl_alpn_support(Config) ->
+ HelpText = os:cmd("openssl s_client --help"),
+ case string:str(HelpText, "alpn") of
+ 0 ->
+ {skip, "Openssl not compiled with alpn support"};
+ _ ->
+ Config
+ end.
+
+start_erlang_client_and_openssl_server_for_alpn_negotiation(Config, Data, Callback) ->
+ process_flag(trap_exit, true),
+ ServerOpts = proplists:get_value(server_rsa_verify_opts, Config),
+ ClientOpts0 = ssl_test_lib:ssl_options(client_rsa_verify_opts, Config),
+ ClientOpts = [{alpn_advertised_protocols, [<<"spdy/2">>]} | ClientOpts0],
+
+ {ClientNode, _, Hostname} = ssl_test_lib:run_where(Config),
+
+ Data = "From openssl to erlang",
+
+ Port = ssl_test_lib:inet_port(node()),
+ CaCertFile = proplists:get_value(cacertfile, ServerOpts),
+ CertFile = proplists:get_value(certfile, ServerOpts),
+ KeyFile = proplists:get_value(keyfile, ServerOpts),
+ Version = ssl_test_lib:protocol_version(Config),
+
+ Exe = "openssl",
+ Args = ["s_server", "-msg", "-alpn", "http/1.1,spdy/2", "-accept",
+ integer_to_list(Port), ssl_test_lib:version_flag(Version),
+ "-CAfile", CaCertFile,
+ "-cert", CertFile, "-key", KeyFile],
+ OpensslPort = ssl_test_lib:portable_open_port(Exe, Args),
+ ssl_test_lib:wait_for_openssl_server(Port, proplists:get_value(protocol, Config)),
+
+ Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port},
+ {host, Hostname},
+ {from, self()},
+ {mfa, {ssl_test_lib,
+ erlang_ssl_receive_and_assert_negotiated_protocol, [<<"spdy/2">>, Data]}},
+ {options, [{reuse_sessions, false} | ClientOpts]}]),
+
+ Callback(Client, OpensslPort),
+
+ %% 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).
+
+start_erlang_server_and_openssl_client_for_alpn_negotiation(Config, Data, Callback) ->
+ process_flag(trap_exit, true),
+ ServerOpts0 = ssl_test_lib:ssl_options(server_rsa_opts, Config),
+ ServerOpts = [{alpn_preferred_protocols, [<<"spdy/2">>]} | ServerOpts0],
+
+ {_, ServerNode, _} = ssl_test_lib:run_where(Config),
+
+
+ Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0},
+ {from, self()},
+ {mfa, {ssl_test_lib, erlang_ssl_receive_and_assert_negotiated_protocol, [<<"spdy/2">>, Data]}},
+ {options, ServerOpts}]),
+ Port = ssl_test_lib:inet_port(Server),
+ Version = ssl_test_lib:protocol_version(Config),
+
+ Exe = "openssl",
+ Args = ["s_client", "-alpn", "http/1.0,spdy/2", "-msg", "-port",
+ integer_to_list(Port), ssl_test_lib:version_flag(Version),
+ "-host", "localhost"],
+
+ OpenSslPort = ssl_test_lib:portable_open_port(Exe, Args),
+
+ Callback(Server, OpenSslPort),
+
+ ssl_test_lib:close(Server),
+
+ ssl_test_lib:close_port(OpenSslPort),
+ process_flag(trap_exit, false).
+
+start_erlang_client_and_openssl_server_for_alpn_npn_negotiation(Config, Data, Callback) ->
+ process_flag(trap_exit, true),
+ ServerOpts = proplists:get_value(server_rsa_verify_opts, Config),
+ ClientOpts0 = ssl_test_lib:ssl_options(client_rsa_opts, Config),
+ ClientOpts = [{alpn_advertised_protocols, [<<"spdy/2">>]},
+ {client_preferred_next_protocols, {client, [<<"spdy/3">>, <<"http/1.1">>]}} | ClientOpts0],
+
+ {ClientNode, _, Hostname} = ssl_test_lib:run_where(Config),
+
+ Data = "From openssl to erlang",
+
+ Port = ssl_test_lib:inet_port(node()),
+ CertFile = proplists:get_value(certfile, ServerOpts),
+ KeyFile = proplists:get_value(keyfile, ServerOpts),
+ Version = ssl_test_lib:protocol_version(Config),
+
+ Exe = "openssl",
+ Args = ["s_server", "-msg", "-alpn", "http/1.1,spdy/2", "-nextprotoneg",
+ "spdy/3", "-accept", integer_to_list(Port), ssl_test_lib:version_flag(Version),
+ "-cert", CertFile, "-key", KeyFile],
+
+ OpensslPort = ssl_test_lib:portable_open_port(Exe, Args),
+
+ ssl_test_lib:wait_for_openssl_server(Port, proplists:get_value(protocol, Config)),
+
+ Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port},
+ {host, Hostname},
+ {from, self()},
+ {mfa, {ssl_test_lib,
+ erlang_ssl_receive_and_assert_negotiated_protocol, [<<"spdy/2">>, Data]}},
+ {options, [{reuse_sessions, false} | ClientOpts]}]),
+
+ Callback(Client, OpensslPort),
+
+ %% 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).
+
+start_erlang_server_and_openssl_client_for_alpn_npn_negotiation(Config, Data, Callback) ->
+ process_flag(trap_exit, true),
+ ServerOpts0 = ssl_test_lib:ssl_options(server_rsa_verify_opts, Config),
+ ServerOpts = [{alpn_preferred_protocols, [<<"spdy/2">>]},
+ {next_protocols_advertised, [<<"spdy/3">>, <<"http/1.1">>]} | ServerOpts0],
+
+ {_, ServerNode, _} = ssl_test_lib:run_where(Config),
+
+
+ Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0},
+ {from, self()},
+ {mfa, {ssl_test_lib, erlang_ssl_receive_and_assert_negotiated_protocol, [<<"spdy/2">>, Data]}},
+ {options, ServerOpts}]),
+ Port = ssl_test_lib:inet_port(Server),
+ Version = ssl_test_lib:protocol_version(Config),
+ Exe = "openssl",
+ Args = ["s_client", "-alpn", "http/1.1,spdy/2", "-nextprotoneg", "spdy/3",
+ "-msg", "-port", integer_to_list(Port), ssl_test_lib:version_flag(Version),
+ "-host", "localhost"],
+ OpenSslPort = ssl_test_lib:portable_open_port(Exe, Args),
+
+ Callback(Server, OpenSslPort),
+
+ ssl_test_lib:close(Server),
+ ssl_test_lib:close_port(OpenSslPort),
+ process_flag(trap_exit, false).
+
diff --git a/lib/ssl/test/openssl_server_cipher_suite_SUITE.erl b/lib/ssl/test/openssl_cipher_suite_SUITE.erl
index 0d68d84d61..955eb914c0 100644
--- a/lib/ssl/test/openssl_server_cipher_suite_SUITE.erl
+++ b/lib/ssl/test/openssl_cipher_suite_SUITE.erl
@@ -20,7 +20,7 @@
%%
--module(openssl_server_cipher_suite_SUITE).
+-module(openssl_cipher_suite_SUITE).
%% Note: This directive should only be used in test suites.
-compile(export_all).
@@ -31,19 +31,26 @@
%% Common Test interface functions -----------------------------------
%%--------------------------------------------------------------------
all() ->
- [
- {group, 'tlsv1.2'},
+ [
+ {group, openssl_server},
+ {group, openssl_client}
+ ].
+
+all_protocol_groups() ->
+ [{group, 'tlsv1.2'},
{group, 'tlsv1.1'},
{group, 'tlsv1'},
{group, 'sslv3'},
{group, 'dtlsv1.2'},
{group, 'dtlsv1'}
- ].
+ ].
groups() ->
%% TODO: Enable SRP, PSK suites (needs OpenSSL s_server conf)
%% TODO: Enable all "kex" on DTLS
[
+ {openssl_server, all_protocol_groups()},
+ {openssl_client, all_protocol_groups()},
{'tlsv1.2', [], kex()},
{'tlsv1.1', [], kex()},
{'tlsv1', [], kex()},
@@ -135,6 +142,9 @@ kex() ->
dtls_kex() -> %% Should be all kex in the future
dtls_rsa() ++ dss() ++ anonymous().
+ssl3_kex() ->
+ ssl3_rsa() ++ ssl3_dss() ++ ssl3_anonymous().
+
rsa() ->
[{group, dhe_rsa},
{group, ecdhe_rsa},
@@ -148,6 +158,11 @@ dtls_rsa() ->
%%,{group, rsa_psk}
].
+ssl3_rsa() ->
+ [{group, dhe_rsa},
+ {group, rsa}
+ ].
+
ecdsa() ->
[{group, ecdhe_ecdsa}].
@@ -156,6 +171,10 @@ dss() ->
%%{group, srp_dss}
].
+ssl3_dss() ->
+ [{group, dhe_dss}
+ ].
+
anonymous() ->
[{group, dh_anon},
{group, ecdh_anon}
@@ -165,6 +184,9 @@ anonymous() ->
%%{group, srp_anon}
].
+ssl3_anonymous() ->
+ [{group, dh_anon}].
+
init_per_suite(Config) ->
catch crypto:stop(),
try crypto:start() of
@@ -199,7 +221,12 @@ init_per_group(GroupName, Config) ->
false ->
do_init_per_group(GroupName, Config)
end.
-
+do_init_per_group(openssl_client, Config0) ->
+ Config = proplists:delete(server_type, proplists:delete(client_type, Config0)),
+ [{client_type, openssl}, {server_type, erlang} | Config];
+do_init_per_group(openssl_server, Config0) ->
+ Config = proplists:delete(server_type, proplists:delete(client_type, Config0)),
+ [{client_type, erlang}, {server_type, openssl} | Config];
do_init_per_group(GroupName, Config) when GroupName == ecdh_anon;
GroupName == ecdhe_rsa;
GroupName == ecdhe_psk ->
@@ -747,8 +774,7 @@ cipher_suite_test(CipherSuite, _Version, Config) ->
ct:log("Testing CipherSuite ~p~n", [CipherSuite]),
ct:log("Server Opts ~p~n", [ServerOpts]),
ct:log("Client Opts ~p~n", [ClientOpts]),
- ssl_test_lib:basic_test([{ciphers, [CipherSuite]} | COpts], SOpts, [{client_type, erlang},
- {server_type, openssl} | Config]).
+ ssl_test_lib:basic_test([{ciphers, [CipherSuite]} | COpts], SOpts, Config).
test_ciphers(Kex, Cipher, Version) ->
diff --git a/lib/ssl/test/openssl_client_cert_SUITE.erl b/lib/ssl/test/openssl_client_cert_SUITE.erl
new file mode 100644
index 0000000000..4844f06672
--- /dev/null
+++ b/lib/ssl/test/openssl_client_cert_SUITE.erl
@@ -0,0 +1,331 @@
+%%
+%% %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(openssl_client_cert_SUITE).
+
+%% Note: This directive should only be used in test suites.
+-compile(export_all).
+-include_lib("common_test/include/ct.hrl").
+-include_lib("public_key/include/public_key.hrl").
+
+%%--------------------------------------------------------------------
+%% Common Test interface functions -----------------------------------
+%%--------------------------------------------------------------------
+all() ->
+ [
+ {group, openssl_client}
+ ].
+
+groups() ->
+ [
+ {openssl_client, [], protocol_groups()},
+ {'tlsv1.3', [], tls_1_3_protocol_groups()},
+ {'tlsv1.2', [], pre_tls_1_3_protocol_groups()},
+ {'tlsv1.1', [], pre_tls_1_3_protocol_groups()},
+ {'tlsv1', [], pre_tls_1_3_protocol_groups()},
+ {'sslv3', [], ssl_protocol_groups()},
+ {'dtlsv1.2', [], pre_tls_1_3_protocol_groups()},
+ {'dtlsv1', [], pre_tls_1_3_protocol_groups()},
+ {rsa, [], all_version_tests()},
+ {ecdsa, [], all_version_tests()},
+ {dsa, [], all_version_tests()},
+ {rsa_1_3, [], all_version_tests() ++ tls_1_3_tests() ++ [unsupported_sign_algo_cert_client_auth]},
+ {ecdsa_1_3, [], all_version_tests() ++ tls_1_3_tests()}
+ ].
+
+protocol_groups() ->
+ [{group, 'tlsv1.3'},
+ {group, 'tlsv1.2'},
+ {group, 'tlsv1.1'},
+ {group, 'tlsv1'},
+ {group, 'sslv3'},
+ {group, 'dtlsv1.2'},
+ {group, 'dtlsv1'}
+ ].
+
+ssl_protocol_groups() ->
+ [{group, rsa},
+ {group, dsa}].
+
+pre_tls_1_3_protocol_groups() ->
+ [{group, rsa},
+ {group, ecdsa},
+ {group, dsa}].
+
+tls_1_3_protocol_groups() ->
+ [{group, rsa_1_3},
+ {group, ecdsa_1_3}].
+
+tls_1_3_tests() ->
+ [
+ hello_retry_request,
+ custom_groups,
+ hello_retry_client_auth,
+ hello_retry_client_auth_empty_cert_accepted,
+ hello_retry_client_auth_empty_cert_rejected
+ ].
+
+all_version_tests() ->
+ [
+ no_auth,
+ auth,
+ client_auth_empty_cert_accepted,
+ client_auth_empty_cert_rejected,
+ client_auth_partial_chain,
+ client_auth_allow_partial_chain,
+ client_auth_do_not_allow_partial_chain,
+ client_auth_partial_chain_fun_fail,
+ missing_root_cert_no_auth
+ %%invalid_signature_client
+ ].
+
+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:unload(ssl),
+ application:stop(crypto).
+
+init_per_group(openssl_client, Config0) ->
+ Config = proplists:delete(server_type, proplists:delete(client_type, Config0)),
+ [{client_type, openssl}, {server_type, erlang} | Config];
+init_per_group(Group, Config0) when Group == rsa;
+ Group == rsa_1_3 ->
+ Config = ssl_test_lib:make_rsa_cert(Config0),
+ COpts = proplists:get_value(client_rsa_opts, Config),
+ SOpts = proplists:get_value(server_rsa_opts, Config),
+ %% Make sure _rsa* suite is choosen by ssl_test_lib:start_server
+ Version = proplists:get_value(version,Config),
+ Ciphers = ssl_cert_tests:test_ciphers(fun(dhe_rsa) ->
+ true;
+ (ecdhe_rsa) ->
+ true;
+ (_) ->
+ false
+ end, Version),
+ case Ciphers of
+ [_|_] ->
+ [{cert_key_alg, rsa} |
+ lists:delete(cert_key_alg,
+ [{client_cert_opts, [{ciphers, Ciphers} | COpts]},
+ {server_cert_opts, SOpts} |
+ lists:delete(server_cert_opts,
+ lists:delete(client_cert_opts, Config))])];
+ [] ->
+ {skip, {no_sup, Group, Version}}
+ end;
+init_per_group(Group, Config0) when Group == ecdsa;
+ Group == ecdsa_1_3 ->
+ PKAlg = crypto:supports(public_keys),
+ case lists:member(ecdsa, PKAlg) andalso (lists:member(ecdh, PKAlg) orelse
+ lists:member(dh, PKAlg)) of
+ true ->
+ Config = ssl_test_lib:make_ecdsa_cert(Config0),
+ COpts = proplists:get_value(client_ecdsa_opts, Config),
+ SOpts = proplists:get_value(server_ecdsa_opts, Config),
+ %% Make sure ecdh* suite is choosen by ssl_test_lib:start_server
+ Version = proplists:get_value(version,Config),
+ Ciphers = ssl_cert_tests:test_ciphers(fun(ecdh_ecdsa) ->
+ true;
+ (ecdhe_ecdsa) ->
+ true;
+ (_) ->
+ false
+ end, Version),
+ case Ciphers of
+ [_|_] ->
+ [{cert_key_alg, ecdsa} |
+ lists:delete(cert_key_alg,
+ [{client_cert_opts, [{ciphers, Ciphers} | COpts]},
+ {server_cert_opts, SOpts} |
+ lists:delete(server_cert_opts,
+ lists:delete(client_cert_opts, Config))]
+ )];
+ [] ->
+ {skip, {no_sup, Group, Version}}
+ end;
+ false ->
+ {skip, "Missing EC crypto support"}
+ end;
+init_per_group(Group, Config0) when Group == dsa ->
+ PKAlg = crypto:supports(public_keys),
+ case lists:member(dss, PKAlg) andalso lists:member(dh, PKAlg) of
+ true ->
+ Config = ssl_test_lib:make_dsa_cert(Config0),
+ COpts = proplists:get_value(client_dsa_opts, Config),
+ SOpts = proplists:get_value(server_dsa_opts, Config),
+ %% Make sure dhe_dss* suite is choosen by ssl_test_lib:start_server
+ Version = proplists:get_value(version,Config),
+ Ciphers = ssl_cert_tests:test_ciphers(fun(dh_dss) ->
+ true;
+ (dhe_dss) ->
+ true;
+ (_) ->
+ false
+ end, Version),
+ case Ciphers of
+ [_|_] ->
+ [{cert_key_alg, dsa} |
+ lists:delete(cert_key_alg,
+ [{client_cert_opts, [{ciphers, Ciphers} | COpts]},
+ {server_cert_opts, SOpts} |
+ lists:delete(server_cert_opts,
+ lists:delete(client_cert_opts, Config))])];
+ [] ->
+ {skip, {no_sup, Group, Version}}
+ end;
+ false ->
+ {skip, "Missing DSS crypto support"}
+ end;
+init_per_group(GroupName, Config) ->
+ case ssl_test_lib:is_tls_version(GroupName) of
+ true ->
+ case ssl_test_lib:check_sane_openssl_version(GroupName) of
+ true ->
+ [{version, GroupName}
+ | ssl_test_lib:init_tls_version(GroupName, Config)];
+ false ->
+ {skip, "Missing openssl support"}
+ end;
+ _ ->
+ ssl:start(),
+ Config
+ 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) ->
+ ssl_test_lib:ct_log_supported_protocol_versions(Config),
+ ct:timetrap({seconds, 10}),
+ Config.
+
+end_per_testcase(_TestCase, Config) ->
+ Config.
+
+%%--------------------------------------------------------------------
+%% Test Cases --------------------------------------------------------
+%%--------------------------------------------------------------------
+
+no_auth() ->
+ ssl_cert_tests:no_auth().
+
+no_auth(Config) ->
+ ssl_cert_tests:no_auth(Config).
+%%--------------------------------------------------------------------
+auth() ->
+ ssl_cert_tests:auth().
+auth(Config) ->
+ ssl_cert_tests:auth(Config).
+%%--------------------------------------------------------------------
+client_auth_empty_cert_accepted() ->
+ ssl_cert_tests:client_auth_empty_cert_accepted().
+client_auth_empty_cert_accepted(Config) ->
+ ssl_cert_tests:client_auth_empty_cert_accepted(Config).
+%%--------------------------------------------------------------------
+client_auth_empty_cert_rejected() ->
+ ssl_cert_tests:client_auth_empty_cert_rejected().
+client_auth_empty_cert_rejected(Config) ->
+ ssl_cert_tests:client_auth_empty_cert_rejected(Config).
+%%--------------------------------------------------------------------
+client_auth_partial_chain() ->
+ ssl_cert_tests:client_auth_partial_chain().
+client_auth_partial_chain(Config) when is_list(Config) ->
+ ssl_cert_tests:client_auth_partial_chain(Config).
+
+%%--------------------------------------------------------------------
+client_auth_allow_partial_chain() ->
+ ssl_cert_tests:client_auth_allow_partial_chain().
+client_auth_allow_partial_chain(Config) when is_list(Config) ->
+ ssl_cert_tests:client_auth_allow_partial_chain(Config).
+%%--------------------------------------------------------------------
+client_auth_do_not_allow_partial_chain() ->
+ ssl_cert_tests:client_auth_do_not_allow_partial_chain().
+client_auth_do_not_allow_partial_chain(Config) when is_list(Config) ->
+ ssl_cert_tests:client_auth_do_not_allow_partial_chain(Config).
+
+%%--------------------------------------------------------------------
+client_auth_partial_chain_fun_fail() ->
+ ssl_cert_tests:client_auth_partial_chain_fun_fail().
+client_auth_partial_chain_fun_fail(Config) when is_list(Config) ->
+ ssl_cert_tests:client_auth_partial_chain_fun_fail(Config).
+
+%%--------------------------------------------------------------------
+missing_root_cert_no_auth() ->
+ ssl_cert_tests:missing_root_cert_no_auth().
+missing_root_cert_no_auth(Config) when is_list(Config) ->
+ ssl_cert_tests:missing_root_cert_no_auth(Config).
+
+%%--------------------------------------------------------------------
+invalid_signature_client() ->
+ ssl_cert_tests:invalid_signature_client().
+invalid_signature_client(Config) when is_list(Config) ->
+ ssl_cert_tests:invalid_signature_client(Config).
+%%--------------------------------------------------------------------
+invalid_signature_server() ->
+ ssl_cert_tests:invalid_signature_client().
+invalid_signature_server(Config) when is_list(Config) ->
+ ssl_cert_tests:invalid_signature_client(Config).
+
+%%--------------------------------------------------------------------
+%% TLS 1.3 Test Cases ------------------------------------------------
+%%--------------------------------------------------------------------
+hello_retry_request() ->
+ ssl_cert_tests:hello_retry_request().
+hello_retry_request(Config) ->
+ ssl_cert_tests:hello_retry_request(Config).
+%%--------------------------------------------------------------------
+custom_groups() ->
+ ssl_cert_tests:custom_groups().
+custom_groups(Config) ->
+ ssl_cert_tests:custom_groups(Config).
+unsupported_sign_algo_cert_client_auth() ->
+ ssl_cert_tests:unsupported_sign_algo_cert_client_auth().
+unsupported_sign_algo_cert_client_auth(Config) ->
+ ssl_cert_tests:unsupported_sign_algo_cert_client_auth(Config).
+%%--------------------------------------------------------------------
+hello_retry_client_auth() ->
+ ssl_cert_tests:hello_retry_client_auth().
+hello_retry_client_auth(Config) ->
+ ssl_cert_tests:hello_retry_client_auth(Config).
+%%--------------------------------------------------------------------
+hello_retry_client_auth_empty_cert_accepted() ->
+ ssl_cert_tests:hello_retry_client_auth_empty_cert_accepted().
+hello_retry_client_auth_empty_cert_accepted(Config) ->
+ ssl_cert_tests:hello_retry_client_auth_empty_cert_accepted(Config).
+%%--------------------------------------------------------------------
+hello_retry_client_auth_empty_cert_rejected() ->
+ ssl_cert_tests:hello_retry_client_auth_empty_cert_rejected().
+hello_retry_client_auth_empty_cert_rejected(Config) ->
+ ssl_cert_tests:hello_retry_client_auth_empty_cert_rejected(Config).
diff --git a/lib/ssl/test/openssl_npn_SUITE.erl b/lib/ssl/test/openssl_npn_SUITE.erl
new file mode 100644
index 0000000000..f249ba47c2
--- /dev/null
+++ b/lib/ssl/test/openssl_npn_SUITE.erl
@@ -0,0 +1,304 @@
+%%
+%% %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(openssl_npn_SUITE).
+
+%% Note: This directive should only be used in test suites.
+-compile(export_all).
+
+-include_lib("common_test/include/ct.hrl").
+
+-define(OPENSSL_QUIT, "Q\n").
+-define(OPENSSL_RENEGOTIATE, "R\n").
+-define(SLEEP, 1000).
+
+%%--------------------------------------------------------------------
+%% Common Test interface functions -----------------------------------
+%%--------------------------------------------------------------------
+all() ->
+ %% NPN is not supported in TLS-1.3 (replaced by ALPN and deprecated in TLS 1.2)
+ %% OpenSSL DTLS support for NPN is either not there or broken.
+ [{group, 'tlsv1.2'},
+ {group, 'tlsv1.1'},
+ {group, 'tlsv1'}].
+
+groups() ->
+ [{'tlsv1.2', [], npn_tests()},
+ {'tlsv1.1', [], npn_tests()},
+ {'tlsv1', [], npn_tests()}
+ ].
+
+npn_tests() ->
+ [erlang_client_openssl_server_npn,
+ erlang_server_openssl_client_npn,
+ erlang_server_openssl_client_npn_renegotiate,
+ erlang_client_openssl_server_npn_renegotiate,
+ erlang_server_openssl_client_npn_only_client,
+ erlang_server_openssl_client_npn_only_server,
+ erlang_client_openssl_server_npn_only_client,
+ erlang_client_openssl_server_npn_only_server].
+
+init_per_suite(Config0) ->
+ case os:find_executable("openssl") of
+ false ->
+ {skip, "Openssl not found"};
+ _ ->
+ case check_openssl_npn_support(Config0) of
+ {skip, _} = Skip ->
+ Skip;
+ _ ->
+ ct:pal("Version: ~p", [os:cmd("openssl version")]),
+ catch crypto:stop(),
+ try crypto:start() of
+ ok ->
+ ssl_test_lib:clean_start(),
+ ssl_test_lib:make_rsa_cert(Config0)
+ catch _:_ ->
+ {skip, "Crypto did not start"}
+ end
+ end
+ end.
+
+end_per_suite(_Config) ->
+ ssl:stop(),
+ application:stop(crypto),
+ ssl_test_lib:kill_openssl().
+
+init_per_group(GroupName, Config) ->
+ case ssl_test_lib:is_tls_version(GroupName) of
+ true ->
+ case ssl_test_lib:supports_ssl_tls_version(GroupName) of
+ true ->
+ case ssl_test_lib:check_sane_openssl_version(GroupName) of
+ true ->
+ ssl_test_lib:init_tls_version(GroupName, Config);
+ false ->
+ {skip, openssl_does_not_support_version}
+ end;
+ false ->
+ {skip, openssl_does_not_support_version}
+ end;
+ _ ->
+ Config
+ 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) ->
+ ct:timetrap({seconds, 10}),
+ special_init(TestCase, Config).
+
+special_init(TestCase, Config)
+ when TestCase == erlang_client_npn_openssl_server_npn_renegotiate;
+ TestCase == erlang_server_npn_openssl_client_npn_renegotiate ->
+ {ok, Version} = application:get_env(ssl, protocol_version),
+ ssl_test_lib:check_sane_openssl_renegotaite(Config, Version);
+special_init(_, Config) ->
+ Config.
+
+end_per_testcase(_, Config) ->
+ Config.
+
+%%--------------------------------------------------------------------
+%% Test Cases --------------------------------------------------------
+%%--------------------------------------------------------------------
+
+erlang_client_openssl_server_npn() ->
+ [{doc,"Test erlang client with openssl server doing npn negotiation"}].
+
+erlang_client_openssl_server_npn(Config) when is_list(Config) ->
+ Data = "From openssl to erlang",
+ start_erlang_client_and_openssl_server_for_npn_negotiation(Config, Data,
+ fun(Client, OpensslPort) ->
+ true = port_command(OpensslPort, Data),
+ ssl_test_lib:check_result(Client, Data)
+ end).
+
+%%--------------------------------------------------------------------
+erlang_client_openssl_server_npn_renegotiate() ->
+ [{doc,"Test erlang client with openssl server doing npn negotiation and renegotiate"}].
+
+erlang_client_openssl_server_npn_renegotiate(Config) when is_list(Config) ->
+ Data = "From openssl to erlang",
+ start_erlang_client_and_openssl_server_for_npn_negotiation(Config, Data,
+ fun(Client, OpensslPort) ->
+ true = port_command(OpensslPort,
+ ?OPENSSL_RENEGOTIATE),
+ ct:sleep(?SLEEP),
+ true = port_command(OpensslPort, Data),
+ ssl_test_lib:check_result(Client, Data)
+ end).
+%%--------------------------------------------------------------------------
+erlang_server_openssl_client_npn() ->
+ [{doc,"Test erlang server with openssl client and npn negotiation"}].
+
+erlang_server_openssl_client_npn(Config) when is_list(Config) ->
+
+ Data = "From openssl to erlang",
+ start_erlang_server_and_openssl_client_for_npn_negotiation(Config, Data,
+ fun(Server, OpensslPort) ->
+ true = port_command(OpensslPort, Data),
+ ssl_test_lib:check_result(Server, Data)
+ end).
+
+%%--------------------------------------------------------------------------
+erlang_server_openssl_client_npn_renegotiate() ->
+ [{doc,"Test erlang server with openssl client and npn negotiation with renegotiation"}].
+
+erlang_server_openssl_client_npn_renegotiate(Config) when is_list(Config) ->
+ Data = "From openssl to erlang",
+ start_erlang_server_and_openssl_client_for_npn_negotiation(Config, Data,
+ fun(Server, OpensslPort) ->
+ true = port_command(OpensslPort,
+ ?OPENSSL_RENEGOTIATE),
+ ct:sleep(?SLEEP),
+ true = port_command(OpensslPort, Data),
+ ssl_test_lib:check_result(Server, Data)
+ end).
+%%--------------------------------------------------------------------------
+erlang_client_openssl_server_npn_only_server(Config) when is_list(Config) ->
+ Data = "From openssl to erlang",
+ ssl_test_lib:start_erlang_client_and_openssl_server_with_opts(Config, [],
+ ["-nextprotoneg", "spdy/2"], Data,
+ fun(Server, OpensslPort) ->
+ true = port_command(OpensslPort, Data),
+ ssl_test_lib:check_result(Server, Data)
+ end).
+
+%%--------------------------------------------------------------------------
+
+erlang_client_openssl_server_npn_only_client(Config) when is_list(Config) ->
+ Data = "From openssl to erlang",
+ ssl_test_lib:start_erlang_client_and_openssl_server_with_opts(Config,
+ [{client_preferred_next_protocols,
+ {client, [<<"spdy/2">>], <<"http/1.1">>}}], [],
+ Data,
+ fun(Server, OpensslPort) ->
+ true = port_command(OpensslPort, Data),
+ ssl_test_lib:check_result(Server, Data)
+ end).
+
+%%--------------------------------------------------------------------------
+erlang_server_openssl_client_npn_only_server(Config) when is_list(Config) ->
+ Data = "From openssl to erlang",
+ ssl_test_lib:start_erlang_server_and_openssl_client_with_opts(Config,
+ [{next_protocols_advertised, [<<"spdy/2">>]}], [],
+ Data,
+ fun(Server, OpensslPort) ->
+ true = port_command(OpensslPort, Data),
+ ssl_test_lib:check_result(Server, Data)
+ end).
+
+erlang_server_openssl_client_npn_only_client(Config) when is_list(Config) ->
+ Data = "From openssl to erlang",
+ ssl_test_lib:start_erlang_server_and_openssl_client_with_opts(Config, [], ["-nextprotoneg", "spdy/2"],
+ Data,
+ fun(Server, OpensslPort) ->
+ true = port_command(OpensslPort, Data),
+ ssl_test_lib:check_result(Server, Data)
+ end).
+
+%%--------------------------------------------------------------------
+%% Internal functions -----------------------------------------------
+%%--------------------------------------------------------------------
+
+start_erlang_client_and_openssl_server_for_npn_negotiation(Config, Data, Callback) ->
+ process_flag(trap_exit, true),
+ ServerOpts = ssl_test_lib:ssl_options(server_rsa_verify_opts, Config),
+ ClientOpts0 = ssl_test_lib:ssl_options(client_rsa_verify_opts, Config),
+ ClientOpts = [{client_preferred_next_protocols, {client, [<<"spdy/2">>], <<"http/1.1">>}} | ClientOpts0],
+
+ {ClientNode, _, Hostname} = ssl_test_lib:run_where(Config),
+
+ Data = "From openssl to erlang",
+
+ Port = ssl_test_lib:inet_port(node()),
+ CaCertFile = proplists:get_value(cacertfile, ServerOpts),
+ CertFile = proplists:get_value(certfile, ServerOpts),
+ KeyFile = proplists:get_value(keyfile, ServerOpts),
+ Version = ssl_test_lib:protocol_version(Config),
+
+ Exe = "openssl",
+ Args = ["s_server", "-msg", "-nextprotoneg", "http/1.1,spdy/2", "-accept", integer_to_list(Port),
+ ssl_test_lib:version_flag(Version),
+ "-CAfile", CaCertFile,
+ "-cert", CertFile, "-key", KeyFile],
+ OpensslPort = ssl_test_lib:portable_open_port(Exe, Args),
+
+ ssl_test_lib:wait_for_openssl_server(Port, proplists:get_value(protocol, Config)),
+
+ Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port},
+ {host, Hostname},
+ {from, self()},
+ {mfa, {ssl_test_lib,
+ erlang_ssl_receive_and_assert_negotiated_protocol, [<<"spdy/2">>, Data]}},
+ {options, ClientOpts}]),
+
+ Callback(Client, OpensslPort),
+
+ %% 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).
+
+start_erlang_server_and_openssl_client_for_npn_negotiation(Config, Data, Callback) ->
+ process_flag(trap_exit, true),
+ ServerOpts0 = ssl_test_lib:ssl_options(server_rsa_opts, Config),
+ ServerOpts = [{next_protocols_advertised, [<<"spdy/2">>]} | ServerOpts0],
+
+ {_, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
+
+ Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0},
+ {from, self()},
+ {mfa, {ssl_test_lib, erlang_ssl_receive_and_assert_negotiated_protocol, [<<"spdy/2">>, Data]}},
+ {options, ServerOpts}]),
+ Port = ssl_test_lib:inet_port(Server),
+ Version = ssl_test_lib:protocol_version(Config),
+
+ Exe = "openssl",
+ Args = ["s_client", "-nextprotoneg", "http/1.0,spdy/2", "-msg", "-connect",
+ ssl_test_lib:hostname_format(Hostname) ++ ":"
+ ++ integer_to_list(Port), ssl_test_lib:version_flag(Version)],
+
+ OpenSslPort = ssl_test_lib:portable_open_port(Exe, Args),
+
+ Callback(Server, OpenSslPort),
+
+ ssl_test_lib:close(Server),
+
+ ssl_test_lib:close_port(OpenSslPort),
+ process_flag(trap_exit, false).
+
+check_openssl_npn_support(Config) ->
+ HelpText = os:cmd("openssl s_client --help"),
+ case string:str(HelpText, "nextprotoneg") of
+ 0 ->
+ {skip, "Openssl not compiled with nextprotoneg support"};
+ _ ->
+ Config
+ end.
diff --git a/lib/ssl/test/openssl_reject_SUITE.erl b/lib/ssl/test/openssl_reject_SUITE.erl
new file mode 100644
index 0000000000..deefd11823
--- /dev/null
+++ b/lib/ssl/test/openssl_reject_SUITE.erl
@@ -0,0 +1,209 @@
+%%
+%% %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(openssl_reject_SUITE).
+
+%% Note: This directive should only be used in test suites.
+-compile(export_all).
+
+-include_lib("common_test/include/ct.hrl").
+
+-define(SLEEP, 1000).
+-define(OPENSSL_GARBAGE, "P\n").
+
+%%--------------------------------------------------------------------
+%% Common Test interface functions -----------------------------------
+%%--------------------------------------------------------------------
+
+all() ->
+ [{group, 'tlsv1.2'},
+ {group, 'tlsv1.1'},
+ {group, 'tlsv1'},
+ {group, 'sslv3'}].
+
+groups() ->
+ [{'tlsv1.2', [], all_versions_tests()},
+ {'tlsv1.1', [], all_versions_tests()},
+ {'tlsv1', [], all_versions_tests()},
+ {'sslv3', [], all_versions_tests()}
+ ].
+
+all_versions_tests() ->
+ [
+ erlang_client_bad_openssl_server,
+ ssl2_erlang_server_openssl_client
+ ].
+
+init_per_suite(Config0) ->
+ case os:find_executable("openssl") of
+ false ->
+ {skip, "Openssl not found"};
+ _ ->
+ ct:pal("Version: ~p", [os:cmd("openssl version")]),
+ catch crypto:stop(),
+ try crypto:start() of
+ ok ->
+ ssl_test_lib:clean_start(),
+ ssl_test_lib:make_rsa_cert(Config0)
+ catch _:_ ->
+ {skip, "Crypto did not start"}
+ end
+ end.
+
+end_per_suite(_Config) ->
+ ssl:stop(),
+ application:stop(crypto),
+ ssl_test_lib:kill_openssl().
+
+init_per_group(GroupName, Config) ->
+ case ssl_test_lib:is_tls_version(GroupName) of
+ true ->
+ case ssl_test_lib:supports_ssl_tls_version(GroupName) of
+ true ->
+ case ssl_test_lib:check_sane_openssl_version(GroupName) of
+ true ->
+ ssl_test_lib:init_tls_version(GroupName, Config);
+ false ->
+ {skip, openssl_does_not_support_version}
+ end;
+ false ->
+ {skip, openssl_does_not_support_version}
+ end;
+ _ ->
+ Config
+ 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) ->
+ ct:timetrap({seconds, 10}),
+ special_init(TestCase, Config).
+
+special_init(ssl2_erlang_server_openssl_client, Config) ->
+ case ssl_test_lib:supports_ssl_tls_version(sslv2) of
+ true ->
+ Config;
+ false ->
+ {skip, "sslv2 not supported by openssl"}
+ end;
+special_init(_, Config) ->
+ Config.
+
+end_per_testcase(_, Config) ->
+ Config.
+
+%%--------------------------------------------------------------------
+%% Test Cases --------------------------------------------------------
+%%--------------------------------------------------------------------
+erlang_client_bad_openssl_server() ->
+ [{doc,"Test what happens if openssl server sends garbage to erlang ssl client"}].
+erlang_client_bad_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),
+
+ Port = ssl_test_lib:inet_port(node()),
+ CertFile = proplists:get_value(certfile, ServerOpts),
+ KeyFile = proplists:get_value(keyfile, ServerOpts),
+ Version = ssl_test_lib:protocol_version(Config),
+ Exe = "openssl",
+ Args = ["s_server", "-accept", integer_to_list(Port), ssl_test_lib:version_flag(Version),
+ "-cert", CertFile, "-key", KeyFile],
+ OpensslPort = ssl_test_lib:portable_open_port(Exe, Args),
+
+ ssl_test_lib:wait_for_openssl_server(Port, proplists:get_value(protocol, Config)),
+
+ Client0 = ssl_test_lib:start_client([{node, ClientNode}, {port, Port},
+ {host, Hostname},
+ {from, self()},
+ {mfa, {?MODULE, server_sent_garbage, []}},
+ {options,
+ [{versions, [Version]} | ClientOpts]}]),
+
+ %% Send garbage
+ true = port_command(OpensslPort, ?OPENSSL_GARBAGE),
+
+ ct:sleep(?SLEEP),
+
+ Client0 ! server_sent_garbage,
+
+ ssl_test_lib:check_result(Client0, true),
+
+ ssl_test_lib:close(Client0),
+
+ %% Make sure openssl does not hang and leave zombie process
+ Client1 = ssl_test_lib:start_client([{node, ClientNode}, {port, Port},
+ {host, Hostname},
+ {from, self()},
+ {mfa, {ssl_test_lib, no_result, []}},
+ {options,
+ [{versions, [Version]} | ClientOpts]}]),
+
+ %% Clean close down! Server needs to be closed first !!
+ ssl_test_lib:close_port(OpensslPort),
+ ssl_test_lib:close(Client1),
+ process_flag(trap_exit, false).
+
+%%--------------------------------------------------------------------
+ssl2_erlang_server_openssl_client() ->
+ [{doc,"Test that ssl v2 clients are rejected"}].
+
+ssl2_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),
+
+ Server = ssl_test_lib:start_server_error([{node, ServerNode}, {port, 0},
+ {from, self()},
+ {options, ServerOpts}]),
+ Port = ssl_test_lib:inet_port(Server),
+
+ Exe = "openssl",
+ Args = ["s_client", "-connect", ssl_test_lib:hostname_format(Hostname) ++ ":" ++ integer_to_list(Port),
+ "-ssl2", "-msg"],
+
+ OpenSslPort = ssl_test_lib:portable_open_port(Exe, Args),
+
+ ct:log("Ports ~p~n", [[erlang:port_info(P) || P <- erlang:ports()]]),
+ ssl_test_lib:consume_port_exit(OpenSslPort),
+ ssl_test_lib:check_server_alert(Server, unexpected_message),
+ process_flag(trap_exit, false).
+
+
+%%--------------------------------------------------------------------
+%% Internal functions ------------------------------------------------
+%%--------------------------------------------------------------------
+
+server_sent_garbage(Socket) ->
+ receive
+ server_sent_garbage ->
+ {error, closed} == ssl:send(Socket, "data")
+
+ end.
diff --git a/lib/ssl/test/openssl_renegotiate_SUITE.erl b/lib/ssl/test/openssl_renegotiate_SUITE.erl
new file mode 100644
index 0000000000..91a8175ac6
--- /dev/null
+++ b/lib/ssl/test/openssl_renegotiate_SUITE.erl
@@ -0,0 +1,341 @@
+%%
+%% %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(openssl_renegotiate_SUITE).
+
+%% Note: This directive should only be used in test suites.
+-compile(export_all).
+
+-include_lib("common_test/include/ct.hrl").
+
+-define(SLEEP, 1000).
+-define(OPENSSL_RENEGOTIATE, "R\n").
+
+%%--------------------------------------------------------------------
+%% Common Test interface functions -----------------------------------
+%%--------------------------------------------------------------------
+
+all() ->
+ case ssl_test_lib:openssl_sane_dtls() of
+ true ->
+ [{group, 'tlsv1.2'},
+ {group, 'tlsv1.1'},
+ {group, 'tlsv1'},
+ {group, 'sslv3'},
+ {group, 'dtlsv1.2'},
+ {group, 'dtlsv1'}];
+ false ->
+ [{group, 'tlsv1.2'},
+ {group, 'tlsv1.1'},
+ {group, 'tlsv1'},
+ {group, 'sslv3'}]
+ end.
+
+groups() ->
+ case ssl_test_lib:openssl_sane_dtls() of
+ true ->
+ [{'tlsv1.2', [], all_versions_tests()},
+ {'tlsv1.1', [], all_versions_tests()},
+ {'tlsv1', [], all_versions_tests()},
+ {'sslv3', [], all_versions_tests()},
+ {'dtlsv1.2', [], all_versions_tests()},
+ {'dtlsv1', [], all_versions_tests()}
+ ];
+ false ->
+ [{'tlsv1.2', [], all_versions_tests()},
+ {'tlsv1.1', [], all_versions_tests()},
+ {'tlsv1', [], all_versions_tests()},
+ {'sslv3', [], all_versions_tests()}
+ ]
+ end.
+
+all_versions_tests() ->
+ [
+ erlang_client_openssl_server_renegotiate,
+ erlang_client_openssl_server_renegotiate_after_client_data,
+ erlang_client_openssl_server_nowrap_seqnum,
+ erlang_server_openssl_client_nowrap_seqnum
+ ].
+
+
+init_per_suite(Config0) ->
+ case os:find_executable("openssl") of
+ false ->
+ {skip, "Openssl not found"};
+ _ ->
+ ct:pal("Version: ~p", [os:cmd("openssl version")]),
+ catch crypto:stop(),
+ try crypto:start() of
+ ok ->
+ ssl_test_lib:clean_start(),
+ ssl_test_lib:make_rsa_cert(Config0)
+ catch _:_ ->
+ {skip, "Crypto did not start"}
+ end
+ end.
+
+end_per_suite(_Config) ->
+ ssl:stop(),
+ application:stop(crypto),
+ ssl_test_lib:kill_openssl().
+
+init_per_group(GroupName, Config) ->
+ case ssl_test_lib:is_tls_version(GroupName) of
+ true ->
+ case ssl_test_lib:supports_ssl_tls_version(GroupName) of
+ true ->
+ case ssl_test_lib:check_sane_openssl_version(GroupName) of
+ true ->
+ ssl_test_lib:init_tls_version(GroupName, Config);
+ false ->
+ {skip, openssl_does_not_support_version}
+ end;
+ false ->
+ {skip, openssl_does_not_support_version}
+ end;
+ _ ->
+ Config
+ 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) ->
+ ct:timetrap({seconds, 10}),
+ special_init(TestCase, Config).
+
+special_init(TestCase, Config)
+ when TestCase == erlang_client_openssl_server_renegotiate;
+ TestCase == erlang_client_openssl_server_nowrap_seqnum;
+ TestCase == erlang_server_openssl_client_nowrap_seqnum;
+ TestCase == erlang_client_openssl_server_renegotiate_after_client_data
+ ->
+ {ok, Version} = application:get_env(ssl, protocol_version),
+ ssl_test_lib:check_sane_openssl_renegotaite(Config, Version);
+special_init(_, Config) ->
+ Config.
+
+end_per_testcase(_, Config) ->
+ Config.
+
+%%--------------------------------------------------------------------
+%% Test Cases --------------------------------------------------------
+%%--------------------------------------------------------------------
+
+erlang_client_openssl_server_renegotiate() ->
+ [{doc,"Test erlang client when openssl server issuses a renegotiate"}].
+erlang_client_openssl_server_renegotiate(Config) when is_list(Config) ->
+ process_flag(trap_exit, true),
+ ServerOpts = ssl_test_lib:ssl_options(server_rsa_verify_opts, Config),
+ ClientOpts = ssl_test_lib:ssl_options(client_rsa_verify_opts, Config),
+
+ {ClientNode, _, Hostname} = ssl_test_lib:run_where(Config),
+
+ ErlData = "From erlang to openssl",
+ OpenSslData = "From openssl to erlang",
+
+ Port = ssl_test_lib:inet_port(node()),
+ CertFile = proplists:get_value(certfile, ServerOpts),
+ CaCertFile = proplists:get_value(cacertfile, ServerOpts),
+ KeyFile = proplists:get_value(keyfile, ServerOpts),
+ Version = ssl_test_lib:protocol_version(Config),
+
+ Exe = "openssl",
+ Args = ["s_server", "-accept", integer_to_list(Port),
+ ssl_test_lib:version_flag(Version),
+ "-CAfile", CaCertFile,
+ "-cert", CertFile, "-key", KeyFile, "-msg"],
+
+ OpensslPort = ssl_test_lib:portable_open_port(Exe, Args),
+
+ ssl_test_lib:wait_for_openssl_server(Port, proplists:get_value(protocol, Config)),
+
+ Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port},
+ {host, Hostname},
+ {from, self()},
+ {mfa, {?MODULE,
+ delayed_send, [[ErlData, OpenSslData]]}},
+ {options, [{reuse_sessions, false} | ClientOpts]}]),
+
+ true = port_command(OpensslPort, ?OPENSSL_RENEGOTIATE),
+ ct:sleep(?SLEEP),
+ true = port_command(OpensslPort, OpenSslData),
+
+ ssl_test_lib:check_result(Client, OpenSslData),
+
+ %% 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),
+ ok.
+%%--------------------------------------------------------------------
+erlang_client_openssl_server_renegotiate_after_client_data() ->
+ [{doc,"Test erlang client when openssl server issuses a renegotiate after reading client data"}].
+erlang_client_openssl_server_renegotiate_after_client_data(Config) when is_list(Config) ->
+ process_flag(trap_exit, true),
+ ServerOpts = ssl_test_lib:ssl_options(server_rsa_verify_opts, Config),
+ ClientOpts = ssl_test_lib:ssl_options(client_rsa_verify_opts, Config),
+
+ {ClientNode, _, Hostname} = ssl_test_lib:run_where(Config),
+
+ ErlData = "From erlang to openssl",
+ OpenSslData = "From openssl to erlang",
+
+ Port = ssl_test_lib:inet_port(node()),
+ CaCertFile = proplists:get_value(cacertfile, ServerOpts),
+ CertFile = proplists:get_value(certfile, ServerOpts),
+ KeyFile = proplists:get_value(keyfile, ServerOpts),
+ Version = ssl_test_lib:protocol_version(Config),
+
+ Exe = "openssl",
+ Args = ["s_server", "-accept", integer_to_list(Port),
+ ssl_test_lib:version_flag(Version),
+ "-CAfile", CaCertFile,
+ "-cert", CertFile, "-key", KeyFile, "-msg"],
+
+ OpensslPort = ssl_test_lib:portable_open_port(Exe, Args),
+
+ ssl_test_lib:wait_for_openssl_server(Port, proplists:get_value(protocol, Config)),
+
+ Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port},
+ {host, Hostname},
+ {from, self()},
+ {mfa, {?MODULE,
+ send_wait_send, [[ErlData, OpenSslData]]}},
+ {options, [{reuse_sessions, false} |ClientOpts]}]),
+
+ true = port_command(OpensslPort, ?OPENSSL_RENEGOTIATE),
+ ct:sleep(?SLEEP),
+ true = port_command(OpensslPort, OpenSslData),
+
+ ssl_test_lib:check_result(Client, OpenSslData),
+
+ %% 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),
+ ok.
+
+%%--------------------------------------------------------------------
+erlang_client_openssl_server_nowrap_seqnum() ->
+ [{doc, "Test that erlang client will renegotiate session when",
+ "max sequence number celing is about to be reached. Although"
+ "in the testcase we use the test option renegotiate_at"
+ " to lower treashold substantially."}].
+erlang_client_openssl_server_nowrap_seqnum(Config) when is_list(Config) ->
+ process_flag(trap_exit, true),
+ ServerOpts = ssl_test_lib:ssl_options(server_rsa_verify_opts, Config),
+ ClientOpts = ssl_test_lib:ssl_options(client_rsa_opts, Config),
+
+ {ClientNode, _, Hostname} = ssl_test_lib:run_where(Config),
+
+ ErlData = "From erlang to openssl\n",
+ N = 10,
+
+ Port = ssl_test_lib:inet_port(node()),
+ CaCertFile = proplists:get_value(cacertfile, ServerOpts),
+ CertFile = proplists:get_value(certfile, ServerOpts),
+ KeyFile = proplists:get_value(keyfile, ServerOpts),
+ Version = ssl_test_lib:protocol_version(Config),
+ Exe = "openssl",
+ Args = ["s_server", "-accept", integer_to_list(Port),
+ ssl_test_lib:version_flag(Version),
+ "-CAfile", CaCertFile,
+ "-cert", CertFile, "-key", KeyFile, "-msg"],
+
+ OpensslPort = ssl_test_lib:portable_open_port(Exe, Args),
+
+ ssl_test_lib:wait_for_openssl_server(Port, proplists:get_value(protocol, Config)),
+
+ Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port},
+ {host, Hostname},
+ {from, self()},
+ {mfa, {ssl_test_lib,
+ trigger_renegotiate, [[ErlData, N+2]]}},
+ {options, [{reuse_sessions, false},
+ {renegotiate_at, N} | ClientOpts]}]),
+
+ 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).
+%%--------------------------------------------------------------------
+erlang_server_openssl_client_nowrap_seqnum() ->
+ [{doc, "Test that erlang client will renegotiate session when",
+ "max sequence number celing is about to be reached. Although"
+ "in the testcase we use the test option renegotiate_at"
+ " to lower treashold substantially."}].
+erlang_server_openssl_client_nowrap_seqnum(Config) when is_list(Config) ->
+ process_flag(trap_exit, true),
+ ServerOpts = ssl_test_lib:ssl_options(server_rsa_verify_opts, Config),
+
+ {_, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
+
+ Data = "From openssl to erlang",
+
+ N = 10,
+
+ Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0},
+ {from, self()},
+ {mfa, {ssl_test_lib,
+ trigger_renegotiate, [[Data, N+2]]}},
+ {options, [{renegotiate_at, N}, {reuse_sessions, false} | ServerOpts]}]),
+ Port = ssl_test_lib:inet_port(Server),
+ Version = ssl_test_lib:protocol_version(Config),
+ Exe = "openssl",
+ Args = ["s_client","-connect", ssl_test_lib:hostname_format(Hostname) ++ ":" ++ integer_to_list(Port),
+ ssl_test_lib:version_flag(Version),
+ "-msg"],
+
+ 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).
+
+
+%%--------------------------------------------------------------------
+%% Internal functions ------------------------------------------------
+%%--------------------------------------------------------------------
+delayed_send(Socket, [ErlData, OpenSslData]) ->
+ ct:sleep(?SLEEP),
+ ssl:send(Socket, ErlData),
+ ssl_test_lib:active_recv(Socket, length(OpenSslData)).
+
+
+send_wait_send(Socket, [ErlData, OpenSslData]) ->
+ ssl:send(Socket, ErlData),
+ ct:sleep(?SLEEP),
+ ssl:send(Socket, ErlData),
+ ssl_test_lib:active_recv(Socket, length(OpenSslData)).
+
diff --git a/lib/ssl/test/openssl_server_cert_SUITE.erl b/lib/ssl/test/openssl_server_cert_SUITE.erl
new file mode 100644
index 0000000000..83b0884f66
--- /dev/null
+++ b/lib/ssl/test/openssl_server_cert_SUITE.erl
@@ -0,0 +1,366 @@
+%%
+%% %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(openssl_server_cert_SUITE).
+
+%% Note: This directive should only be used in test suites.
+-compile(export_all).
+-include_lib("common_test/include/ct.hrl").
+-include_lib("public_key/include/public_key.hrl").
+
+%%--------------------------------------------------------------------
+%% Common Test interface functions -----------------------------------
+%%--------------------------------------------------------------------
+all() ->
+ [
+ {group, openssl_server}].
+
+groups() ->
+ [
+ {openssl_server, [], protocol_groups()},
+ {'tlsv1.3', [], tls_1_3_protocol_groups()},
+ {'tlsv1.2', [], pre_tls_1_3_protocol_groups()},
+ {'tlsv1.1', [], pre_tls_1_3_protocol_groups()},
+ {'tlsv1', [], pre_tls_1_3_protocol_groups()},
+ {'sslv3', [], ssl_protocol_groups()},
+ {'dtlsv1.2', [], pre_tls_1_3_protocol_groups()},
+ {'dtlsv1', [], pre_tls_1_3_protocol_groups()},
+ {rsa, [], all_version_tests()},
+ {ecdsa, [], all_version_tests()},
+ {dsa, [], all_version_tests()},
+ {rsa_1_3, [], all_version_tests() ++ tls_1_3_tests() ++ [unsupported_sign_algo_cert_client_auth]},
+ {ecdsa_1_3, [], all_version_tests() ++ tls_1_3_tests()}
+ ].
+
+protocol_groups() ->
+ [{group, 'tlsv1.3'},
+ {group, 'tlsv1.2'},
+ {group, 'tlsv1.1'},
+ {group, 'tlsv1'},
+ {group, 'sslv3'},
+ {group, 'dtlsv1.2'},
+ {group, 'dtlsv1'}
+ ].
+
+ssl_protocol_groups() ->
+ [{group, rsa},
+ {group, dsa}].
+
+pre_tls_1_3_protocol_groups() ->
+ [{group, rsa},
+ {group, ecdsa},
+ {group, dsa}].
+
+tls_1_3_protocol_groups() ->
+ [{group, rsa_1_3},
+ {group, ecdsa_1_3}].
+
+tls_1_3_tests() ->
+ [
+ hello_retry_request,
+ custom_groups,
+ hello_retry_client_auth,
+ hello_retry_client_auth_empty_cert_accepted,
+ hello_retry_client_auth_empty_cert_rejected
+ ].
+
+all_version_tests() ->
+ [
+ no_auth,
+ auth,
+ missing_root_cert_no_auth
+ %%invalid_signature_client
+ ].
+
+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:unload(ssl),
+ application:stop(crypto).
+
+init_per_group(openssl_server, Config0) ->
+ Config = proplists:delete(server_type, proplists:delete(client_type, Config0)),
+ [{client_type, erlang}, {server_type, openssl} | Config];
+init_per_group(rsa = Group, Config0) ->
+ Config = ssl_test_lib:make_rsa_cert(Config0),
+ COpts = proplists:get_value(client_rsa_opts, Config),
+ SOpts = proplists:get_value(server_rsa_opts, Config),
+ %% Make sure _rsa* suite is choosen by ssl_test_lib:start_server
+ Version = proplists:get_value(version,Config),
+ Ciphers = ssl_cert_tests:test_ciphers(fun(dhe_rsa) ->
+ true;
+ (ecdhe_rsa) ->
+ true;
+ (_) ->
+ false
+ end, Version),
+ case Ciphers of
+ [_|_] ->
+ [{cert_key_alg, rsa} |
+ lists:delete(cert_key_alg,
+ [{client_cert_opts, [{ciphers, Ciphers} | COpts]},
+ {server_cert_opts, SOpts} |
+ lists:delete(server_cert_opts,
+ lists:delete(client_cert_opts, Config))])];
+ [] ->
+ {skip, {no_sup, Group, Version}}
+ end;
+init_per_group(rsa_1_3 = Group, Config0) ->
+ Config = ssl_test_lib:make_rsa_cert(Config0),
+ COpts = proplists:get_value(client_rsa_opts, Config),
+ SOpts = proplists:get_value(server_rsa_opts, Config),
+ %% Make sure _rsa* suite is choosen by ssl_test_lib:start_server
+ Version = proplists:get_value(version,Config),
+ Ciphers = ssl_cert_tests:test_ciphers(undefined, Version),
+ case Ciphers of
+ [_|_] ->
+ [{cert_key_alg, rsa} |
+ lists:delete(cert_key_alg,
+ [{client_cert_opts, [{ciphers, Ciphers} | COpts]},
+ {server_cert_opts, SOpts} |
+ lists:delete(server_cert_opts,
+ lists:delete(client_cert_opts, Config))])];
+ [] ->
+ {skip, {no_sup, Group, Version}}
+ end;
+init_per_group(ecdsa = Group, Config0) ->
+ PKAlg = crypto:supports(public_keys),
+ case lists:member(ecdsa, PKAlg) andalso (lists:member(ecdh, PKAlg) orelse
+ lists:member(dh, PKAlg)) of
+ true ->
+ Config = ssl_test_lib:make_ecdsa_cert(Config0),
+ COpts = proplists:get_value(client_ecdsa_opts, Config),
+ SOpts = proplists:get_value(server_ecdsa_opts, Config),
+ %% Make sure ecdh* suite is choosen by ssl_test_lib:start_server
+ Version = proplists:get_value(version,Config),
+ Ciphers = ssl_cert_tests:test_ciphers(fun(ecdh_ecdsa) ->
+ true;
+ (ecdhe_ecdsa) ->
+ true;
+ (_) ->
+ false
+ end, Version),
+ case Ciphers of
+ [_|_] ->
+ [{cert_key_alg, ecdsa} |
+ lists:delete(cert_key_alg,
+ [{client_cert_opts, [{ciphers, Ciphers} | COpts]},
+ {server_cert_opts, SOpts} |
+ lists:delete(server_cert_opts,
+ lists:delete(client_cert_opts, Config))]
+ )];
+ [] ->
+ {skip, {no_sup, Group, Version}}
+ end;
+ false ->
+ {skip, "Missing EC crypto support"}
+ end;
+init_per_group(ecdsa_1_3 = Group, Config0) ->
+ PKAlg = crypto:supports(public_keys),
+ case lists:member(ecdsa, PKAlg) andalso (lists:member(ecdh, PKAlg) orelse
+ lists:member(dh, PKAlg)) of
+ true ->
+ Config = ssl_test_lib:make_ecdsa_cert(Config0),
+ COpts = proplists:get_value(client_ecdsa_opts, Config),
+ SOpts = proplists:get_value(server_ecdsa_opts, Config),
+ %% Make sure ecdh* suite is choosen by ssl_test_lib:start_server
+ Version = proplists:get_value(version,Config),
+ Ciphers = ssl_cert_tests:test_ciphers(undefined, Version),
+ case Ciphers of
+ [_|_] ->
+ [{cert_key_alg, ecdsa} |
+ lists:delete(cert_key_alg,
+ [{client_cert_opts, [{ciphers, Ciphers} | COpts]},
+ {server_cert_opts, SOpts} |
+ lists:delete(server_cert_opts,
+ lists:delete(client_cert_opts, Config))]
+ )];
+ [] ->
+ {skip, {no_sup, Group, Version}}
+ end;
+ false ->
+ {skip, "Missing EC crypto support"}
+ end;
+init_per_group(Group, Config0) when Group == dsa ->
+ PKAlg = crypto:supports(public_keys),
+ case lists:member(dss, PKAlg) andalso lists:member(dh, PKAlg) of
+ true ->
+ Config = ssl_test_lib:make_dsa_cert(Config0),
+ COpts = proplists:get_value(client_dsa_opts, Config),
+ SOpts = proplists:get_value(server_dsa_opts, Config),
+ %% Make sure dhe_dss* suite is choosen by ssl_test_lib:start_server
+ Version = proplists:get_value(version,Config),
+ Ciphers = ssl_cert_tests:test_ciphers(fun(dh_dss) ->
+ true;
+ (dhe_dss) ->
+ true;
+ (_) ->
+ false
+ end, Version),
+ case Ciphers of
+ [_|_] ->
+ [{cert_key_alg, dsa} |
+ lists:delete(cert_key_alg,
+ [{client_cert_opts, [{ciphers, Ciphers} | COpts]},
+ {server_cert_opts, SOpts} |
+ lists:delete(server_cert_opts,
+ lists:delete(client_cert_opts, Config))])];
+ [] ->
+ {skip, {no_sup, Group, Version}}
+ end;
+ false ->
+ {skip, "Missing DSS crypto support"}
+ end;
+init_per_group(GroupName, Config) ->
+ case ssl_test_lib:is_tls_version(GroupName) of
+ true ->
+ case ssl_test_lib:check_sane_openssl_version(GroupName) of
+ true ->
+ [{version, GroupName}
+ | ssl_test_lib:init_tls_version(GroupName, Config)];
+ false ->
+ {skip, "Missing openssl support"}
+ end;
+ _ ->
+ ssl:start(),
+ Config
+ 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) ->
+ ssl_test_lib:ct_log_supported_protocol_versions(Config),
+ ct:timetrap({seconds, 10}),
+ Config.
+
+end_per_testcase(_TestCase, Config) ->
+ Config.
+
+%%--------------------------------------------------------------------
+%% Test Cases --------------------------------------------------------
+%%--------------------------------------------------------------------
+
+no_auth() ->
+ ssl_cert_tests:no_auth().
+
+no_auth(Config) ->
+ ssl_cert_tests:no_auth(Config).
+%%--------------------------------------------------------------------
+auth() ->
+ ssl_cert_tests:auth().
+auth(Config) ->
+ ssl_cert_tests:auth(Config).
+%%--------------------------------------------------------------------
+client_auth_empty_cert_accepted() ->
+ ssl_cert_tests:client_auth_empty_cert_accepted().
+client_auth_empty_cert_accepted(Config) ->
+ ssl_cert_tests:client_auth_empty_cert_accepted(Config).
+%%--------------------------------------------------------------------
+client_auth_empty_cert_rejected() ->
+ ssl_cert_tests:client_auth_empty_cert_rejected().
+client_auth_empty_cert_rejected(Config) ->
+ ssl_cert_tests:client_auth_empty_cert_rejected(Config).
+%%--------------------------------------------------------------------
+client_auth_partial_chain() ->
+ ssl_cert_tests:client_auth_partial_chain().
+client_auth_partial_chain(Config) when is_list(Config) ->
+ ssl_cert_tests:client_auth_partial_chain(Config).
+
+%%--------------------------------------------------------------------
+client_auth_allow_partial_chain() ->
+ ssl_cert_tests:client_auth_allow_partial_chain().
+client_auth_allow_partial_chain(Config) when is_list(Config) ->
+ ssl_cert_tests:client_auth_allow_partial_chain(Config).
+%%--------------------------------------------------------------------
+client_auth_do_not_allow_partial_chain() ->
+ ssl_cert_tests:client_auth_do_not_allow_partial_chain().
+client_auth_do_not_allow_partial_chain(Config) when is_list(Config) ->
+ ssl_cert_tests:client_auth_do_not_allow_partial_chain(Config).
+
+%%--------------------------------------------------------------------
+client_auth_partial_chain_fun_fail() ->
+ ssl_cert_tests:client_auth_partial_chain_fun_fail().
+client_auth_partial_chain_fun_fail(Config) when is_list(Config) ->
+ ssl_cert_tests:client_auth_partial_chain_fun_fail(Config).
+
+%%--------------------------------------------------------------------
+missing_root_cert_no_auth() ->
+ ssl_cert_tests:missing_root_cert_no_auth().
+missing_root_cert_no_auth(Config) when is_list(Config) ->
+ ssl_cert_tests:missing_root_cert_no_auth(Config).
+
+%%--------------------------------------------------------------------
+invalid_signature_client() ->
+ ssl_cert_tests:invalid_signature_client().
+invalid_signature_client(Config) when is_list(Config) ->
+ ssl_cert_tests:invalid_signature_client(Config).
+%%--------------------------------------------------------------------
+invalid_signature_server() ->
+ ssl_cert_tests:invalid_signature_client().
+invalid_signature_server(Config) when is_list(Config) ->
+ ssl_cert_tests:invalid_signature_client(Config).
+
+%%--------------------------------------------------------------------
+%% TLS 1.3 Test Cases ------------------------------------------------
+%%--------------------------------------------------------------------
+hello_retry_request() ->
+ ssl_cert_tests:hello_retry_request().
+hello_retry_request(Config) ->
+ ssl_cert_tests:hello_retry_request(Config).
+%%--------------------------------------------------------------------
+custom_groups() ->
+ ssl_cert_tests:custom_groups().
+custom_groups(Config) ->
+ ssl_cert_tests:custom_groups(Config).
+unsupported_sign_algo_cert_client_auth() ->
+ ssl_cert_tests:unsupported_sign_algo_cert_client_auth().
+unsupported_sign_algo_cert_client_auth(Config) ->
+ ssl_cert_tests:unsupported_sign_algo_cert_client_auth(Config).
+%%--------------------------------------------------------------------
+hello_retry_client_auth() ->
+ ssl_cert_tests:hello_retry_client_auth().
+hello_retry_client_auth(Config) ->
+ ssl_cert_tests:hello_retry_client_auth(Config).
+%%--------------------------------------------------------------------
+hello_retry_client_auth_empty_cert_accepted() ->
+ ssl_cert_tests:hello_retry_client_auth_empty_cert_accepted().
+hello_retry_client_auth_empty_cert_accepted(Config) ->
+ ssl_cert_tests:hello_retry_client_auth_empty_cert_accepted(Config).
+%%--------------------------------------------------------------------
+hello_retry_client_auth_empty_cert_rejected() ->
+ ssl_cert_tests:hello_retry_client_auth_empty_cert_rejected().
+hello_retry_client_auth_empty_cert_rejected(Config) ->
+ ssl_cert_tests:hello_retry_client_auth_empty_cert_rejected(Config).
diff --git a/lib/ssl/test/openssl_session_SUITE.erl b/lib/ssl/test/openssl_session_SUITE.erl
new file mode 100644
index 0000000000..24dcaa7817
--- /dev/null
+++ b/lib/ssl/test/openssl_session_SUITE.erl
@@ -0,0 +1,262 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2008-2018. 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(openssl_session_SUITE).
+
+%% Note: This directive should only be used in test suites.
+-compile(export_all).
+
+-include_lib("common_test/include/ct.hrl").
+
+-define(SLEEP, 1000).
+-define(EXPIRE, 10).
+
+%%--------------------------------------------------------------------
+%% Common Test interface functions -----------------------------------
+%%--------------------------------------------------------------------
+
+all() ->
+ case ssl_test_lib:openssl_sane_dtls() of
+ true ->
+ [{group, 'tlsv1.2'},
+ {group, 'tlsv1.1'},
+ {group, 'tlsv1'},
+ {group, 'sslv3'},
+ {group, 'dtlsv1.2'},
+ {group, 'dtlsv1'}];
+ false ->
+ [{group, 'tlsv1.2'},
+ {group, 'tlsv1.1'},
+ {group, 'tlsv1'},
+ {group, 'sslv3'}]
+ end.
+
+groups() ->
+ case ssl_test_lib:openssl_sane_dtls() of
+ true ->
+ [{'tlsv1.2', [], tests()},
+ {'tlsv1.1', [], tests()},
+ {'tlsv1', [], tests()},
+ {'sslv3', [], tests()},
+ {'dtlsv1.2', [], dtls_tests()},
+ {'dtlsv1', [], dtls_tests()}
+ ];
+ false ->
+ [{'tlsv1.2', [], tests()},
+ {'tlsv1.1', [], tests()},
+ {'tlsv1', [], tests()},
+ {'sslv3', [], tests()}
+ ]
+ end.
+
+tests() ->
+ [
+ reuse_session_erlang_server,
+ reuse_session_erlang_client
+ ].
+
+dtls_tests() ->
+ [
+ reuse_session_erlang_server
+ ].
+
+
+init_per_suite(Config0) ->
+ case os:find_executable("openssl") of
+ false ->
+ {skip, "Openssl not found"};
+ _ ->
+ ct:pal("Version: ~p", [os:cmd("openssl version")]),
+ catch crypto:stop(),
+ try crypto:start() of
+ ok ->
+ ssl_test_lib:clean_start(),
+ ssl_test_lib:make_rsa_cert(Config0)
+ catch _:_ ->
+ {skip, "Crypto did not start"}
+ end
+ end.
+
+end_per_suite(_Config) ->
+ ssl:stop(),
+ application:stop(crypto),
+ ssl_test_lib:kill_openssl().
+
+init_per_group(GroupName, Config) ->
+ case ssl_test_lib:is_tls_version(GroupName) of
+ true ->
+ case ssl_test_lib:supports_ssl_tls_version(GroupName) of
+ true ->
+ case ssl_test_lib:check_sane_openssl_version(GroupName) of
+ true ->
+ ssl_test_lib:init_tls_version(GroupName, Config);
+ false ->
+ {skip, openssl_does_not_support_version}
+ end;
+ false ->
+ {skip, openssl_does_not_support_version}
+ end;
+ _ ->
+ ssl:start(),
+ Config
+ 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(reuse_session_erlang_client, Config) ->
+ ct:timetrap(?EXPIRE * 1000 * 5),
+ ssl:stop(),
+ application:load(ssl),
+ application:set_env(ssl, session_lifetime, ?EXPIRE),
+ ssl:start(),
+ Config;
+
+init_per_testcase(TestCase, Config) ->
+ ct:timetrap({seconds, 10}),
+ Config.
+
+end_per_testcase(reuse_session_erlang_client, Config) ->
+ application:unset_env(ssl, session_lifetime),
+ Config;
+end_per_testcase(_, Config) ->
+ Config.
+
+%%--------------------------------------------------------------------
+%% Test Cases --------------------------------------------------------
+%%--------------------------------------------------------------------
+
+%%--------------------------------------------------------------------
+reuse_session_erlang_server() ->
+ [{doc, "Test erlang server with openssl client that reconnects with the"
+ "same session id, to test reusing of sessions."}].
+reuse_session_erlang_server(Config) when is_list(Config) ->
+ 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, {ssl_test_lib, active_recv, [length(Data)]}},
+ {reconnect_times, 5},
+ {options, ServerOpts}]),
+ Port = ssl_test_lib:inet_port(Server),
+ Version = ssl_test_lib:protocol_version(Config),
+
+ Exe = "openssl",
+ Args = ["s_client", "-connect", ssl_test_lib:hostname_format(Hostname)
+ ++ ":" ++ integer_to_list(Port),
+ ssl_test_lib:version_flag(Version),
+ "-reconnect"],
+
+ OpenSslPort = ssl_test_lib:portable_open_port(Exe, Args),
+
+ true = port_command(OpenSslPort, Data),
+
+ ssl_test_lib:check_result(Server, Data),
+
+ %% Clean close down! Server needs to be closed first !!
+ ssl_test_lib:close(Server),
+ ssl_test_lib:close_port(OpenSslPort).
+
+%%--------------------------------------------------------------------
+
+reuse_session_erlang_client() ->
+ [{doc, "Test erlang ssl client that wants to reuse sessions"}].
+reuse_session_erlang_client(Config) when is_list(Config) ->
+ process_flag(trap_exit, true),
+ ClientOpts = ssl_test_lib:ssl_options(client_rsa_opts, Config),
+ ServerOpts = ssl_test_lib:ssl_options(server_rsa_opts, Config),
+ {ClientNode, _, Hostname} = ssl_test_lib:run_where(Config),
+
+ Port = ssl_test_lib:inet_port(node()),
+ CertFile = proplists:get_value(certfile, ServerOpts),
+ CACertFile = proplists:get_value(cacertfile, ServerOpts),
+ KeyFile = proplists:get_value(keyfile, ServerOpts),
+
+ Exe = "openssl",
+ Args = ["s_server", "-accept", integer_to_list(Port),
+ "-cert", CertFile,"-key", KeyFile, "-CAfile", CACertFile],
+
+ OpensslPort = ssl_test_lib:portable_open_port(Exe, Args),
+
+ ssl_test_lib:wait_for_openssl_server(Port, tls),
+
+ Client0 =
+ ssl_test_lib:start_client([{node, ClientNode},
+ {port, Port}, {host, Hostname},
+ {mfa, {ssl_test_lib, session_id, []}},
+ {from, self()}, {options, [{reuse_sessions, save}, {verify, verify_peer}| ClientOpts]}]),
+
+ SID = receive
+ {Client0, Id0} ->
+ Id0
+ end,
+
+ ssl_test_lib:close(Client0),
+
+ Client1 =
+ ssl_test_lib:start_client([{node, ClientNode},
+ {port, Port}, {host, Hostname},
+ {mfa, {ssl_test_lib, session_id, []}},
+ {from, self()}, {options, [{reuse_session, SID} | ClientOpts]}]),
+ receive
+ {Client1, SID} ->
+ ok
+ after ?SLEEP ->
+ ct:fail(session_not_reused)
+ end,
+
+
+ ssl_test_lib:close(Client1),
+ %% Make sure session is unregistered due to expiration
+ ct:sleep(20000),
+
+ Client2 =
+ ssl_test_lib:start_client([{node, ClientNode},
+ {port, Port}, {host, Hostname},
+ {mfa, {ssl_test_lib, session_id, []}},
+ {from, self()}, {options, ClientOpts}]),
+ receive
+ {Client2, ID} ->
+ case ID of
+ SID ->
+ ct:fail(expired_session_reused);
+ _ ->
+ ok
+ end
+ end,
+
+ %% Clean close down! Server needs to be closed first !!
+ ssl_test_lib:close_port(OpensslPort),
+ ssl_test_lib:close(Client2).
+
+
+%%--------------------------------------------------------------------
+%% Internal functions ------------------------------------------------
+%%--------------------------------------------------------------------
diff --git a/lib/ssl/test/openssl_sni_SUITE.erl b/lib/ssl/test/openssl_sni_SUITE.erl
new file mode 100644
index 0000000000..26f08e36c0
--- /dev/null
+++ b/lib/ssl/test/openssl_sni_SUITE.erl
@@ -0,0 +1,251 @@
+%%
+%% %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(openssl_sni_SUITE).
+
+%% Note: This directive should only be used in test suites.
+-compile(export_all).
+
+-include_lib("common_test/include/ct.hrl").
+
+-define(OPENSSL_QUIT, "Q\n").
+-define(OPENSSL_RENEGOTIATE, "R\n").
+-define(SLEEP, 1000).
+
+%%--------------------------------------------------------------------
+%% Common Test interface functions -----------------------------------
+%%--------------------------------------------------------------------
+
+all() ->
+ %% Note: SNI not supported in sslv3
+ case ssl_test_lib:openssl_sane_dtls() of
+ true ->
+ [{group, 'tlsv1.2'},
+ {group, 'tlsv1.1'},
+ {group, 'tlsv1'}
+ %% Seems broken in openssl
+ %%{group, 'dtlsv1.2'},
+ %%{group, 'dtlsv1'}
+ ];
+ false ->
+ [{group, 'tlsv1.2'},
+ {group, 'tlsv1.1'},
+ {group, 'tlsv1'}]
+ end.
+
+groups() ->
+ case ssl_test_lib:openssl_sane_dtls() of
+ true ->
+ [{'tlsv1.2', [], sni_tests()},
+ {'tlsv1.1', [], sni_tests()},
+ {'tlsv1', [], sni_tests()}
+ %% Seems broken in openssl
+ %%{'dtlsv1.2', [], sni_tests()},
+ %%{'dtlsv1', [], sni_tests()}
+ ];
+ false ->
+ [{'tlsv1.2', [], sni_tests()},
+ {'tlsv1.1', [], sni_tests()},
+ {'tlsv1', [], sni_tests()}
+ ]
+ end.
+
+sni_tests() ->
+ [erlang_server_openssl_client_sni_match,
+ erlang_server_openssl_client_sni_match_fun,
+ erlang_server_openssl_client_sni_no_match,
+ erlang_server_openssl_client_sni_no_match_fun,
+ erlang_server_openssl_client_sni_no_header,
+ erlang_server_openssl_client_sni_no_header_fun].
+
+init_per_suite(Config0) ->
+ case os:find_executable("openssl") of
+ false ->
+ {skip, "Openssl not found"};
+ _ ->
+ case check_openssl_sni_support(Config0) of
+ {skip, _} = Skip ->
+ Skip;
+ _ ->
+ ct:pal("Version: ~p", [os:cmd("openssl version")]),
+ catch crypto:stop(),
+ try crypto:start() of
+ ok ->
+ ssl_test_lib:clean_start(),
+ Config = ssl_test_lib:make_rsa_cert(Config0),
+ RsaOpts = ssl_test_lib:ssl_options(server_rsa_opts, Config),
+ [{sni_server_opts, [{sni_hosts,
+ [{"a.server", [
+ {certfile, proplists:get_value(certfile, RsaOpts)},
+ {keyfile, proplists:get_value(keyfile, RsaOpts)}
+ ]},
+ {"b.server", [
+ {certfile, proplists:get_value(certfile, RsaOpts)},
+ {keyfile, proplists:get_value(keyfile, RsaOpts)}
+ ]}
+ ]}]} | Config]
+ catch _:_ ->
+ {skip, "Crypto did not start"}
+ end
+ end
+ end.
+
+end_per_suite(_Config) ->
+ ssl:stop(),
+ application:stop(crypto),
+ ssl_test_lib:kill_openssl().
+
+init_per_group(GroupName, Config) ->
+ case ssl_test_lib:is_tls_version(GroupName) of
+ true ->
+ case ssl_test_lib:supports_ssl_tls_version(GroupName) of
+ true ->
+ case ssl_test_lib:check_sane_openssl_version(GroupName) of
+ true ->
+ ssl_test_lib:init_tls_version(GroupName, Config);
+ false ->
+ {skip, openssl_does_not_support_version}
+ end;
+ false ->
+ {skip, openssl_does_not_support_version}
+ end;
+ _ ->
+ Config
+ 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) ->
+ ct:timetrap({seconds, 10}),
+ Config.
+
+
+end_per_testcase(_, Config) ->
+ Config.
+
+%%--------------------------------------------------------------------
+%% Test Cases --------------------------------------------------------
+%%--------------------------------------------------------------------
+erlang_server_openssl_client_sni_no_header(Config) when is_list(Config) ->
+ erlang_server_openssl_client_sni_test(Config, undefined, undefined, "server Peer cert").
+
+erlang_server_openssl_client_sni_no_header_fun(Config) when is_list(Config) ->
+ erlang_server_openssl_client_sni_test_sni_fun(Config, undefined, undefined, "server Peer cert").
+
+erlang_server_openssl_client_sni_match(Config) when is_list(Config) ->
+ erlang_server_openssl_client_sni_test(Config, "a.server", "a.server", "server Peer cert").
+
+erlang_server_openssl_client_sni_match_fun(Config) when is_list(Config) ->
+ erlang_server_openssl_client_sni_test_sni_fun(Config, "a.server", "a.server", "server Peer cert").
+
+erlang_server_openssl_client_sni_no_match(Config) when is_list(Config) ->
+ erlang_server_openssl_client_sni_test(Config, "c.server", undefined, "server Peer cert").
+
+erlang_server_openssl_client_sni_no_match_fun(Config) when is_list(Config) ->
+ erlang_server_openssl_client_sni_test_sni_fun(Config, "c.server", undefined, "server Peer cert").
+
+
+erlang_server_openssl_client_sni_test(Config, SNIHostname, ExpectedSNIHostname, ExpectedCN) ->
+ Version = ssl_test_lib:protocol_version(Config),
+ ct:log("Start running handshake, Config: ~p, SNIHostname: ~p, ExpectedSNIHostname: ~p, ExpectedCN: ~p",
+ [Config, SNIHostname, ExpectedSNIHostname, ExpectedCN]),
+ ServerOptions = proplists:get_value(sni_server_opts, Config) ++ proplists:get_value(server_rsa_opts, Config),
+ {_, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
+ Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0},
+ {from, self()}, {mfa, {?MODULE, send_and_hostname, []}},
+ {options, ServerOptions}]),
+ Port = ssl_test_lib:inet_port(Server),
+ Exe = "openssl",
+ ClientArgs = case SNIHostname of
+ undefined ->
+ openssl_client_args(Version, Hostname,Port);
+ _ ->
+ openssl_client_args(Version, Hostname, Port, SNIHostname)
+ end,
+ ClientPort = ssl_test_lib:portable_open_port(Exe, ClientArgs),
+
+ ssl_test_lib:check_result(Server, ExpectedSNIHostname),
+ ssl_test_lib:close_port(ClientPort),
+ ssl_test_lib:close(Server),
+ ok.
+
+
+erlang_server_openssl_client_sni_test_sni_fun(Config, SNIHostname, ExpectedSNIHostname, ExpectedCN) ->
+ Version = ssl_test_lib:protocol_version(Config),
+ ct:log("Start running handshake for sni_fun, Config: ~p, SNIHostname: ~p, ExpectedSNIHostname: ~p, ExpectedCN: ~p",
+ [Config, SNIHostname, ExpectedSNIHostname, ExpectedCN]),
+ [{sni_hosts, ServerSNIConf}] = proplists:get_value(sni_server_opts, Config),
+ SNIFun = fun(Domain) -> proplists:get_value(Domain, ServerSNIConf, undefined) end,
+ ServerOptions = proplists:get_value(server_rsa_opts, Config) ++ [{sni_fun, SNIFun}],
+ {_, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
+ Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0},
+ {from, self()}, {mfa, {?MODULE, send_and_hostname, []}},
+ {options, ServerOptions}]),
+ Port = ssl_test_lib:inet_port(Server),
+ Exe = "openssl",
+ ClientArgs = case SNIHostname of
+ undefined ->
+ openssl_client_args(Version, Hostname,Port);
+ _ ->
+ openssl_client_args(Version, Hostname, Port, SNIHostname)
+ end,
+
+ ClientPort = ssl_test_lib:portable_open_port(Exe, ClientArgs),
+
+ ssl_test_lib:check_result(Server, ExpectedSNIHostname),
+ ssl_test_lib:close_port(ClientPort),
+ ssl_test_lib:close(Server).
+
+send_and_hostname(SSLSocket) ->
+ ssl:send(SSLSocket, "OK"),
+ case ssl:connection_information(SSLSocket, [sni_hostname]) of
+ {ok, []} ->
+ undefined;
+ {ok, [{sni_hostname, Hostname}]} ->
+ Hostname
+ end.
+
+openssl_client_args(Version, Hostname, Port) ->
+ ["s_client", "-connect", Hostname ++ ":" ++ integer_to_list(Port), ssl_test_lib:version_flag(Version)].
+
+openssl_client_args(Version, Hostname, Port, ServerName) ->
+ ["s_client", "-connect", Hostname ++ ":" ++
+ integer_to_list(Port), ssl_test_lib:version_flag(Version), "-servername", ServerName].
+
+check_openssl_sni_support(Config) ->
+ HelpText = os:cmd("openssl s_client --help"),
+ case ssl_test_lib:is_sane_oppenssl_client() of
+ true ->
+ case string:str(HelpText, "-servername") of
+ 0 ->
+ {skip, "Current openssl doesn't support SNI"};
+ _ ->
+ Config
+ end;
+ false ->
+ {skip, "Current openssl doesn't support SNI or extension handling is flawed"}
+ end.
diff --git a/lib/ssl/test/openssl_tls_1_3_version_SUITE.erl b/lib/ssl/test/openssl_tls_1_3_version_SUITE.erl
new file mode 100644
index 0000000000..8a2692ec1d
--- /dev/null
+++ b/lib/ssl/test/openssl_tls_1_3_version_SUITE.erl
@@ -0,0 +1,172 @@
+%%
+%% %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(openssl_tls_1_3_version_SUITE).
+
+%% Note: This directive should only be used in test suites.
+-compile(export_all).
+
+-include_lib("common_test/include/ct.hrl").
+-include_lib("public_key/include/public_key.hrl").
+
+%%--------------------------------------------------------------------
+%% Common Test interface functions -----------------------------------
+%%--------------------------------------------------------------------
+all() ->
+ [
+ %%{group, openssl_server},
+ {group, openssl_client}
+ ].
+
+groups() ->
+ [
+ %%{openssl_server, [{group, 'tlsv1.3'}]},
+ {openssl_client, [{group, 'tlsv1.3'}]},
+ {'tlsv1.3', [], cert_groups()},
+ {rsa, [], tests()},
+ {ecdsa, [], tests()}
+ ].
+
+cert_groups() ->
+ [{group, rsa},
+ {group, ecdsa}].
+
+tests() ->
+ [tls13_client_tls12_server,
+ %%tls13_client_with_ext_tls12_server,
+ tls12_client_tls13_server].
+
+init_per_suite(Config) ->
+ catch crypto:stop(),
+ try crypto:start() of
+ ok ->
+ case ssl_test_lib:check_sane_openssl_version('tlsv1.3') of
+ true ->
+ ssl_test_lib:clean_start(),
+ Config;
+ false ->
+ {skip, openssl_does_not_support_version}
+ end
+ catch _:_ ->
+ {skip, "Crypto did not start"}
+ end.
+
+end_per_suite(_Config) ->
+ ssl:stop(),
+ application:stop(crypto).
+
+init_per_group(openssl_client, Config0) ->
+ Config = proplists:delete(server_type, proplists:delete(client_type, Config0)),
+ [{client_type, openssl}, {server_type, erlang} | Config];
+init_per_group(openssl_server, Config0) ->
+ Config = proplists:delete(server_type, proplists:delete(client_type, Config0)),
+ [{client_type, erlang}, {server_type, openssl} | Config];
+init_per_group(rsa, Config0) ->
+ Config = ssl_test_lib:make_rsa_cert(Config0),
+ COpts = proplists:get_value(client_rsa_opts, Config),
+ SOpts = proplists:get_value(server_rsa_opts, Config),
+ [{client_cert_opts, COpts}, {server_cert_opts, SOpts} |
+ lists:delete(server_cert_opts, lists:delete(client_cert_opts, Config))];
+init_per_group(ecdsa, Config0) ->
+ PKAlg = crypto:supports(public_keys),
+ case lists:member(ecdsa, PKAlg) andalso
+ (lists:member(ecdh, PKAlg) orelse lists:member(dh, PKAlg)) of
+ true ->
+ Config = ssl_test_lib:make_ecdsa_cert(Config0),
+ COpts = proplists:get_value(client_ecdsa_opts, Config),
+ SOpts = proplists:get_value(server_ecdsa_opts, Config),
+ [{client_cert_opts, COpts}, {server_cert_opts, SOpts} |
+ lists:delete(server_cert_opts, lists:delete(client_cert_opts, Config))];
+ false ->
+ {skip, "Missing EC crypto support"}
+ end;
+init_per_group(GroupName, Config) ->
+ ssl_test_lib:clean_tls_version(Config),
+ case ssl_test_lib:is_tls_version(GroupName) andalso
+ ssl_test_lib:sufficient_crypto_support(GroupName) of
+ true ->
+ ssl_test_lib:init_tls_version(GroupName, Config);
+ _ ->
+ case ssl_test_lib:sufficient_crypto_support(GroupName) of
+ true ->
+ ssl:start(),
+ Config;
+ false ->
+ {skip, "Missing crypto support"}
+ end
+ 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.
+
+%%--------------------------------------------------------------------
+%% Test Cases --------------------------------------------------------
+%%--------------------------------------------------------------------
+
+tls13_client_tls12_server() ->
+ [{doc,"Test that a TLS 1.3 client can connect to a TLS 1.2 server."}].
+
+tls13_client_tls12_server(Config) when is_list(Config) ->
+ ClientOpts = [{versions,
+ ['tlsv1.3', 'tlsv1.2']} | ssl_test_lib:ssl_options(client_cert_opts, Config)],
+ ServerOpts = [{versions,
+ ['tlsv1.1', 'tlsv1.2']} | ssl_test_lib:ssl_options(server_cert_opts, Config)],
+ ssl_test_lib:basic_test(ClientOpts, ServerOpts, Config).
+
+%% tls13_client_with_ext_tls12_server() ->
+%% [{doc,"Test basic connection between TLS 1.2 server and TLS 1.3 client when "
+%% "client has TLS 1.3 specsific extensions"}].
+
+%% tls13_client_with_ext_tls12_server(Config) ->
+%% ClientOpts0 = ssl_test_lib:ssl_options(client_cert_opts, Config),
+%% ServerOpts0 = ssl_test_lib:ssl_options(server_cert_opts, Config),
+
+%% {ServerOpts, ClientOpts} =
+%% case proplists:get_value(client_type) of
+%% erlang ->
+%% {[{versions, ['tlsv1.2']}|ServerOpts0],
+%% [{versions, ['tlsv1.2','tlsv1.3']},
+%% {signature_algs_cert, [ecdsa_secp384r1_sha384,
+%% ecdsa_secp256r1_sha256,
+%% rsa_pss_rsae_sha256,
+%% rsa_pkcs1_sha256,
+%% {sha256,rsa},{sha256,dsa}]}|ClientOpts0]};
+%% openssl ->
+
+
+%% ssl_test_lib:basic_test(ClientOpts, ServerOpts, Config).
+
+tls12_client_tls13_server() ->
+ [{doc,"Test that a TLS 1.2 client can connect to a TLS 1.3 server."}].
+
+tls12_client_tls13_server(Config) when is_list(Config) ->
+ ClientOpts = [{versions,
+ ['tlsv1.1', 'tlsv1.2']} | ssl_test_lib:ssl_options(client_cert_opts, Config)],
+ ServerOpts = [{versions,
+ ['tlsv1.3', 'tlsv1.2']} | ssl_test_lib:ssl_options(server_cert_opts, Config)],
+ ssl_test_lib:basic_test(ClientOpts, ServerOpts, Config).
+
diff --git a/lib/ssl/test/property_test/ssl_eqc_handshake.erl b/lib/ssl/test/property_test/ssl_eqc_handshake.erl
index 38a4b7fb11..2ceb540e15 100644
--- a/lib/ssl/test/property_test/ssl_eqc_handshake.erl
+++ b/lib/ssl/test/property_test/ssl_eqc_handshake.erl
@@ -119,19 +119,27 @@ tls_msg(Version) ->
%%
client_hello(?'TLS_v1.3' = Version) ->
#client_hello{session_id = session_id(),
- client_version = ?'TLS_v1.2',
- cipher_suites = cipher_suites(Version),
+ client_version = ?'TLS_v1.2',
+ cipher_suites = cipher_suites(Version),
+ compression_methods = compressions(Version),
+ random = client_random(Version),
+ extensions = client_hello_extensions(Version)
+ };
+client_hello(Version) ->
+ #client_hello{session_id = session_id(),
+ client_version = Version,
+ cipher_suites = cipher_suites(Version),
compression_methods = compressions(Version),
random = client_random(Version),
extensions = client_hello_extensions(Version)
};
-client_hello(Version) ->
+client_hello(?'SSL_v3' = Version) ->
#client_hello{session_id = session_id(),
client_version = Version,
cipher_suites = cipher_suites(Version),
compression_methods = compressions(Version),
random = client_random(Version),
- extensions = client_hello_extensions(Version)
+ extensions = ssl_handshake:empty_extensions(Version, client_hello)
}.
server_hello(?'TLS_v1.3' = Version) ->
@@ -142,6 +150,14 @@ server_hello(?'TLS_v1.3' = Version) ->
compression_method = compression(Version),
extensions = server_hello_extensions(Version)
};
+server_hello(?'SSL_v3' = Version) ->
+ #server_hello{server_version = Version,
+ session_id = session_id(),
+ random = server_random(Version),
+ cipher_suite = cipher_suite(Version),
+ compression_method = compression(Version),
+ extensions = ssl_handshake:empty_extensions(Version, server_hello)
+ };
server_hello(Version) ->
#server_hello{server_version = Version,
session_id = session_id(),
@@ -291,7 +307,7 @@ pre_shared_keyextension() ->
%% | | |
%% | signature_algorithms_cert (RFC 8446) | CH, CR |
%% +--------------------------------------------------+-------------+
-extensions(?'TLS_v1.3' = Version, client_hello) ->
+extensions(?'TLS_v1.3' = Version, MsgType = client_hello) ->
?LET({
ServerName,
%% MaxFragmentLength,
@@ -306,8 +322,8 @@ extensions(?'TLS_v1.3' = Version, client_hello) ->
%% ServerCertificateType,
%% Padding,
KeyShare,
- %% PreSharedKey,
- %% PSKKeyExchangeModes,
+ PreSharedKey,
+ PSKKeyExchangeModes,
%% EarlyData,
%% Cookie,
SupportedVersions,
@@ -328,9 +344,9 @@ extensions(?'TLS_v1.3' = Version, client_hello) ->
%% oneof([client_cert_type(), undefined]),
%% oneof([server_cert_type(), undefined]),
%% oneof([padding(), undefined]),
- oneof([key_share(client_hello), undefined]),
- %% oneof([pre_shared_key(), undefined]),
- %% oneof([psk_key_exchange_modes(), undefined]),
+ oneof([key_share(MsgType), undefined]),
+ oneof([pre_shared_key(MsgType), undefined]),
+ oneof([psk_key_exchange_modes(), undefined]),
%% oneof([early_data(), undefined]),
%% oneof([cookie(), undefined]),
oneof([client_hello_versions(Version)]),
@@ -357,8 +373,8 @@ extensions(?'TLS_v1.3' = Version, client_hello) ->
%% server_cert_type => ServerCertificateType,
%% padding => Padding,
key_share => KeyShare,
- %% pre_shared_key => PreSharedKey,
- %% psk_key_exhange_modes => PSKKeyExchangeModes,
+ pre_shared_key => PreSharedKey,
+ psk_key_exchange_modes => PSKKeyExchangeModes,
%% early_data => EarlyData,
%% cookie => Cookie,
client_hello_versions => SupportedVersions,
@@ -401,15 +417,15 @@ extensions(Version, client_hello) ->
srp => SRP
%% renegotiation_info => RenegotiationInfo
}));
-extensions(?'TLS_v1.3' = Version, server_hello) ->
+extensions(?'TLS_v1.3' = Version, MsgType = server_hello) ->
?LET({
KeyShare,
- %% PreSharedKeys,
+ PreSharedKey,
SupportedVersions
},
{
- oneof([key_share(server_hello), undefined]),
- %% oneof([pre_shared_keys(), undefined]),
+ oneof([key_share(MsgType), undefined]),
+ oneof([pre_shared_key(MsgType), undefined]),
oneof([server_hello_selected_version()])
},
maps:filter(fun(_, undefined) ->
@@ -419,7 +435,7 @@ extensions(?'TLS_v1.3' = Version, server_hello) ->
end,
#{
key_share => KeyShare,
- %% pre_shared_keys => PreSharedKeys,
+ pre_shared_key => PreSharedKey,
server_hello_selected_version => SupportedVersions
}));
extensions(Version, server_hello) ->
@@ -810,3 +826,58 @@ group_list(N, Pool, Acc) ->
R = rand:uniform(length(Pool)),
G = lists:nth(R, Pool),
group_list(N - 1, Pool -- [G], [G|Acc]).
+
+
+ke_modes() ->
+ oneof([[psk_ke],[psk_dhe_ke],[psk_ke,psk_dhe_ke]]).
+
+psk_key_exchange_modes() ->
+ ?LET(KEModes, ke_modes(),
+ #psk_key_exchange_modes{
+ ke_modes = KEModes}).
+
+pre_shared_key(client_hello) ->
+ ?LET(OfferedPsks, offered_psks(),
+ #pre_shared_key_client_hello{
+ offered_psks = OfferedPsks});
+pre_shared_key(server_hello) ->
+ ?LET(SelectedIdentity, selected_identity(),
+ #pre_shared_key_server_hello{
+ selected_identity = SelectedIdentity}).
+
+selected_identity() ->
+ rand:uniform(32).
+
+offered_psks() ->
+ ?LET(Size, choose(1,5),
+ #offered_psks{
+ identities = psk_identities(Size),
+ binders = psk_binders(Size)}).
+
+psk_identities(Size) ->
+ psk_identities(Size, []).
+%%
+psk_identities(0, Acc) ->
+ Acc;
+psk_identities(N, Acc) ->
+ psk_identities(N - 1, [psk_identity()|Acc]).
+
+psk_identity() ->
+ Len = rand:uniform(32),
+ Identity = crypto:strong_rand_bytes(Len),
+ Age = crypto:strong_rand_bytes(4),
+ #psk_identity{
+ identity = Identity,
+ obfuscated_ticket_age = Age}.
+
+psk_binders(Size) ->
+ psk_binders(Size, []).
+%%
+psk_binders(0, Acc) ->
+ Acc;
+psk_binders(N, Acc) ->
+ psk_binders(N - 1, [psk_binder()|Acc]).
+
+psk_binder() ->
+ Len = rand:uniform(224) + 31,
+ crypto:strong_rand_bytes(Len).
diff --git a/lib/ssl/test/ssl_alert_SUITE.erl b/lib/ssl/test/ssl_alert_SUITE.erl
new file mode 100644
index 0000000000..cc0b636580
--- /dev/null
+++ b/lib/ssl/test/ssl_alert_SUITE.erl
@@ -0,0 +1,100 @@
+%%
+%% 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_alert_SUITE).
+
+%% Note: This directive should only be used in test suites.
+-compile(export_all).
+
+-include_lib("common_test/include/ct.hrl").
+-include_lib("public_key/include/public_key.hrl").
+
+-include_lib("ssl/src/ssl_alert.hrl").
+
+%%--------------------------------------------------------------------
+%% Common Test interface functions -----------------------------------
+%%--------------------------------------------------------------------
+all() ->
+ [
+ alerts,
+ alert_details,
+ alert_details_not_too_big
+ ].
+
+init_per_testcase(_TestCase, Config) ->
+ ct:timetrap({seconds, 5}),
+ Config.
+
+end_per_testcase(_TestCase, Config) ->
+ Config.
+
+%%--------------------------------------------------------------------
+%% Test Cases --------------------------------------------------------
+%%--------------------------------------------------------------------
+alerts() ->
+ [{doc, "Test ssl_alert:alert_txt/1"}].
+alerts(Config) when is_list(Config) ->
+ Descriptions = [?CLOSE_NOTIFY, ?UNEXPECTED_MESSAGE, ?BAD_RECORD_MAC,
+ ?DECRYPTION_FAILED_RESERVED, ?RECORD_OVERFLOW, ?DECOMPRESSION_FAILURE,
+ ?HANDSHAKE_FAILURE, ?BAD_CERTIFICATE, ?UNSUPPORTED_CERTIFICATE,
+ ?CERTIFICATE_REVOKED,?CERTIFICATE_EXPIRED, ?CERTIFICATE_UNKNOWN,
+ ?ILLEGAL_PARAMETER, ?UNKNOWN_CA, ?ACCESS_DENIED, ?DECODE_ERROR,
+ ?DECRYPT_ERROR, ?EXPORT_RESTRICTION, ?PROTOCOL_VERSION,
+ ?INSUFFICIENT_SECURITY, ?INTERNAL_ERROR, ?USER_CANCELED,
+ ?NO_RENEGOTIATION, ?UNSUPPORTED_EXTENSION, ?CERTIFICATE_UNOBTAINABLE,
+ ?UNRECOGNISED_NAME, ?BAD_CERTIFICATE_STATUS_RESPONSE,
+ ?BAD_CERTIFICATE_HASH_VALUE, ?UNKNOWN_PSK_IDENTITY,
+ 255 %% Unsupported/unknow alert will result in a description too
+ ],
+ Alerts = [?ALERT_REC(?WARNING, ?CLOSE_NOTIFY) |
+ [?ALERT_REC(?FATAL, Desc) || Desc <- Descriptions]],
+ lists:foreach(fun(Alert) ->
+ try ssl_alert:alert_txt(Alert)
+ catch
+ C:E:T ->
+ ct:fail({unexpected, {C, E, T}})
+ end
+ end, Alerts).
+%%--------------------------------------------------------------------
+alert_details() ->
+ [{doc, "Test that ssl_alert:alert_txt/1 result contains extendend error description"}].
+alert_details(Config) when is_list(Config) ->
+ Unique = make_ref(),
+ UniqueStr = lists:flatten(io_lib:format("~w", [Unique])),
+ Alert = ?ALERT_REC(?WARNING, ?CLOSE_NOTIFY, Unique),
+ case string:str(ssl_alert:alert_txt(Alert), UniqueStr) of
+ 0 ->
+ ct:fail(error_details_missing);
+ _ ->
+ ok
+ end.
+
+%%--------------------------------------------------------------------
+alert_details_not_too_big() ->
+ [{doc, "Test that ssl_alert:alert_txt/1 limits printed depth of extended error description"}].
+alert_details_not_too_big(Config) when is_list(Config) ->
+ Reason = lists:duplicate(10, lists:duplicate(10, lists:duplicate(10, {some, data}))),
+ Alert = ?ALERT_REC(?WARNING, ?CLOSE_NOTIFY, Reason),
+ case length(ssl_alert:alert_txt(Alert)) < 1000 of
+ true ->
+ ok;
+ false ->
+ ct:fail(ssl_alert_text_too_big)
+ end.
diff --git a/lib/ssl/test/ssl_alpn_handshake_SUITE.erl b/lib/ssl/test/ssl_alpn_SUITE.erl
index dfc780479e..82a49e1469 100644
--- a/lib/ssl/test/ssl_alpn_handshake_SUITE.erl
+++ b/lib/ssl/test/ssl_alpn_SUITE.erl
@@ -19,7 +19,7 @@
%%
%%
--module(ssl_alpn_handshake_SUITE).
+-module(ssl_alpn_SUITE).
%% Note: This directive should only be used in test suites.
-compile(export_all).
@@ -32,7 +32,9 @@
%%--------------------------------------------------------------------
all() ->
- [{group, 'tlsv1.2'},
+ [
+ {group, 'tlsv1.3'},
+ {group, 'tlsv1.2'},
{group, 'tlsv1.1'},
{group, 'tlsv1'},
{group, 'sslv3'},
@@ -42,12 +44,13 @@ all() ->
groups() ->
[
- {'tlsv1.2', [], alpn_tests()},
- {'tlsv1.1', [], alpn_tests()},
- {'tlsv1', [], alpn_tests()},
+ {'tlsv1.3', [], alpn_tests() -- [client_renegotiate, session_reused]},
+ {'tlsv1.2', [], alpn_tests() ++ alpn_npn_coexist()},
+ {'tlsv1.1', [], alpn_tests() ++ alpn_npn_coexist()},
+ {'tlsv1', [], alpn_tests() ++ alpn_npn_coexist()},
{'sslv3', [], alpn_not_supported()},
- {'dtlsv1.2', [], alpn_tests() -- [client_renegotiate]},
- {'dtlsv1', [], alpn_tests() -- [client_renegotiate]}
+ {'dtlsv1.2', [], alpn_tests() ++ alpn_npn_coexist()},
+ {'dtlsv1', [], alpn_tests() ++ alpn_npn_coexist()}
].
alpn_tests() ->
@@ -61,12 +64,16 @@ alpn_tests() ->
client_alpn_and_server_no_support,
client_no_support_and_server_alpn,
client_alpn_npn_and_server_alpn,
- client_alpn_npn_and_server_alpn_npn,
- client_alpn_and_server_alpn_npn,
client_renegotiate,
session_reused
].
+alpn_npn_coexist() ->
+ [
+ client_alpn_npn_and_server_alpn_npn,
+ client_alpn_and_server_alpn_npn
+ ].
+
alpn_not_supported() ->
[alpn_not_supported_client,
alpn_not_supported_server
@@ -77,8 +84,7 @@ init_per_suite(Config0) ->
try crypto:start() of
ok ->
ssl_test_lib:clean_start(),
- Config = ssl_test_lib:make_rsa_cert(Config0),
- ssl_test_lib:cert_options(Config)
+ ssl_test_lib:make_rsa_cert(Config0)
catch _:_ ->
{skip, "Crypto did not start"}
end.
diff --git a/lib/ssl/test/ssl_api_SUITE.erl b/lib/ssl/test/ssl_api_SUITE.erl
new file mode 100644
index 0000000000..fefecc0b65
--- /dev/null
+++ b/lib/ssl/test/ssl_api_SUITE.erl
@@ -0,0 +1,1976 @@
+%%
+%% %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_api_SUITE).
+
+%% Note: This directive should only be used in test suites.
+-compile(export_all).
+-include_lib("common_test/include/ct.hrl").
+-include_lib("ssl/src/ssl_api.hrl").
+
+-define(SLEEP, 500).
+%%--------------------------------------------------------------------
+%% Common Test interface functions -----------------------------------
+%%--------------------------------------------------------------------
+
+all() ->
+ [
+ {group, 'tlsv1.3'},
+ {group, 'tlsv1.2'},
+ {group, 'tlsv1.1'},
+ {group, 'tlsv1'},
+ {group, 'sslv3'},
+ {group, 'dtlsv1.2'},
+ {group, 'dtlsv1'}
+ ].
+
+groups() ->
+ [
+ {'tlsv1.3', [], ((gen_api_tests() ++ tls13_group() ++ handshake_paus_tests()) -- [dh_params, honor_server_cipher_order, honor_client_cipher_order,
+ new_options_in_handshake])
+ ++ (since_1_2() -- [conf_signature_algs])},
+ {'tlsv1.2', [], gen_api_tests() ++ since_1_2() ++ handshake_paus_tests() ++ pre_1_3()},
+ {'tlsv1.1', [], gen_api_tests() ++ handshake_paus_tests() ++ pre_1_3()},
+ {'tlsv1', [], gen_api_tests() ++ handshake_paus_tests() ++ pre_1_3() ++ beast_mitigation_test()},
+ {'sslv3', [], (gen_api_tests() -- [new_options_in_handshake]) ++ beast_mitigation_test() ++ pre_1_3()},
+ {'dtlsv1.2', [], (gen_api_tests() -- [invalid_keyfile, invalid_certfile, invalid_cacertfile,
+ invalid_options, new_options_in_handshake]) ++ handshake_paus_tests() ++ pre_1_3()},
+ {'dtlsv1', [], (gen_api_tests() -- [invalid_keyfile, invalid_certfile, invalid_cacertfile,
+ invalid_options, new_options_in_handshake]) ++ handshake_paus_tests() ++ pre_1_3()}
+ ].
+
+since_1_2() ->
+ [
+ conf_signature_algs,
+ no_common_signature_algs
+ ].
+
+pre_1_3() ->
+ [
+ default_reject_anonymous
+ ].
+gen_api_tests() ->
+ [
+ peercert,
+ peercert_with_client_cert,
+ connection_information,
+ secret_connection_info,
+ versions,
+ active_n,
+ dh_params,
+ hibernate,
+ hibernate_right_away,
+ listen_socket,
+ recv_active,
+ recv_active_once,
+ recv_active_n,
+ recv_timeout,
+ recv_close,
+ controlling_process,
+ controller_dies,
+ controlling_process_transport_accept_socket,
+ close_with_timeout,
+ close_in_error_state,
+ call_in_error_state,
+ close_transport_accept,
+ abuse_transport_accept_socket,
+ honor_server_cipher_order,
+ honor_client_cipher_order,
+ ipv6,
+ der_input,
+ new_options_in_handshake,
+ max_handshake_size,
+ invalid_certfile,
+ invalid_cacertfile,
+ invalid_keyfile,
+ options_not_proplist,
+ invalid_options
+ ].
+
+handshake_paus_tests() ->
+ [
+ handshake_continue,
+ handshake_continue_timeout,
+ hello_client_cancel,
+ hello_server_cancel
+ ].
+
+%% Only relevant for SSL 3.0 and TLS 1.1
+beast_mitigation_test() ->
+ [%% Original option
+ rizzo_disabled,
+ %% Same effect as disable
+ rizzo_zero_n,
+ %% Same as default
+ rizzo_one_n_minus_one
+ ].
+
+tls13_group() ->
+ [
+ supported_groups,
+ honor_server_cipher_order_tls13,
+ honor_client_cipher_order_tls13
+ ].
+
+
+init_per_suite(Config0) ->
+ catch crypto:stop(),
+ try crypto:start() of
+ ok ->
+ ssl_test_lib:clean_start(),
+ ssl_test_lib:make_rsa_cert(Config0)
+ catch _:_ ->
+ {skip, "Crypto did not start"}
+ end.
+
+end_per_suite(_Config) ->
+ ssl:stop(),
+ application:unload(ssl),
+ application:stop(crypto).
+
+
+init_per_group(GroupName, Config) ->
+ case ssl_test_lib:is_tls_version(GroupName) of
+ true ->
+ case ssl_test_lib:sufficient_crypto_support(GroupName) of
+ true ->
+ [{client_type, erlang},
+ {server_type, erlang} | ssl_test_lib:init_tls_version(GroupName, Config)];
+ false ->
+ {skip, "Missing crypto support"}
+ end;
+ _ ->
+ ssl:start(),
+ Config
+ 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(prf, Config) ->
+ ssl_test_lib:ct_log_supported_protocol_versions(Config),
+ ct:timetrap({seconds, 10}),
+ Version = ssl_test_lib:protocol_version(Config),
+ PRFS = [md5, sha, sha256, sha384, sha512],
+ %% All are the result of running tls_v1:prf(PrfAlgo, <<>>, <<>>, <<>>, 16)
+ %% with the specified PRF algorithm
+ ExpectedPrfResults =
+ [{md5, <<96,139,180,171,236,210,13,10,28,32,2,23,88,224,235,199>>},
+ {sha, <<95,3,183,114,33,169,197,187,231,243,19,242,220,228,70,151>>},
+ {sha256, <<166,249,145,171,43,95,158,232,6,60,17,90,183,180,0,155>>},
+ {sha384, <<153,182,217,96,186,130,105,85,65,103,123,247,146,91,47,106>>},
+ {sha512, <<145,8,98,38,243,96,42,94,163,33,53,49,241,4,127,28>>},
+ %% TLS 1.0 and 1.1 PRF:
+ {md5sha, <<63,136,3,217,205,123,200,177,251,211,17,229,132,4,173,80>>}],
+ TestPlan = prf_create_plan([Version], PRFS, ExpectedPrfResults),
+ [{prf_test_plan, TestPlan} | Config];
+init_per_testcase(_TestCase, Config) ->
+ ssl_test_lib:ct_log_supported_protocol_versions(Config),
+ ct:timetrap({seconds, 10}),
+ Config.
+
+end_per_testcase(internal_active_n, _Config) ->
+ application:unset_env(ssl, internal_active_n);
+end_per_testcase(_TestCase, Config) ->
+ Config.
+
+%%--------------------------------------------------------------------
+%% Test Cases --------------------------------------------------------
+%%--------------------------------------------------------------------
+peercert() ->
+ [{doc,"Test API function peercert/1"}].
+peercert(Config) when is_list(Config) ->
+ ClientOpts = ssl_test_lib:ssl_options(client_rsa_opts, Config),
+ ServerOpts = ssl_test_lib:ssl_options(server_rsa_opts, Config),
+ {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
+
+ Server = ssl_test_lib:start_server([{node, ClientNode}, {port, 0},
+ {from, self()},
+ {mfa, {?MODULE, peercert_result, []}},
+ {options, ServerOpts}]),
+ Port = ssl_test_lib:inet_port(Server),
+ Client = ssl_test_lib:start_client([{node, ServerNode}, {port, Port},
+ {host, Hostname},
+ {from, self()},
+ {mfa, {?MODULE, peercert_result, []}},
+ {options, ClientOpts}]),
+
+ CertFile = proplists:get_value(certfile, ServerOpts),
+ [{'Certificate', BinCert, _}]= ssl_test_lib:pem_to_der(CertFile),
+
+ ServerMsg = {error, no_peercert},
+ ClientMsg = {ok, BinCert},
+
+ ct:log("Testcase ~p, Client ~p Server ~p ~n",
+ [self(), Client, Server]),
+
+ ssl_test_lib:check_result(Server, ServerMsg, Client, ClientMsg),
+
+ ssl_test_lib:close(Server),
+ ssl_test_lib:close(Client).
+
+%%--------------------------------------------------------------------
+
+peercert_with_client_cert() ->
+ [{doc,"Test API function peercert/1"}].
+peercert_with_client_cert(Config) when is_list(Config) ->
+ ClientOpts = ssl_test_lib:ssl_options(client_rsa_opts, Config),
+ ServerOpts = ssl_test_lib:ssl_options(server_rsa_opts, Config),
+ {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
+
+ Server = ssl_test_lib:start_server([{node, ClientNode}, {port, 0},
+ {from, self()},
+ {mfa, {?MODULE, peercert_result, []}},
+ {options, [{verify, verify_peer} | ServerOpts]}]),
+ Port = ssl_test_lib:inet_port(Server),
+ Client = ssl_test_lib:start_client([{node, ServerNode}, {port, Port},
+ {host, Hostname},
+ {from, self()},
+ {mfa, {?MODULE, peercert_result, []}},
+ {options, ClientOpts}]),
+
+ ServerCertFile = proplists:get_value(certfile, ServerOpts),
+ [{'Certificate', ServerBinCert, _}]= ssl_test_lib:pem_to_der(ServerCertFile),
+ ClientCertFile = proplists:get_value(certfile, ClientOpts),
+ [{'Certificate', ClientBinCert, _}]= ssl_test_lib:pem_to_der(ClientCertFile),
+
+ ServerMsg = {ok, ClientBinCert},
+ ClientMsg = {ok, ServerBinCert},
+
+ ct:log("Testcase ~p, Client ~p Server ~p ~n",
+ [self(), Client, Server]),
+
+ ssl_test_lib:check_result(Server, ServerMsg, Client, ClientMsg),
+
+ ssl_test_lib:close(Server),
+ ssl_test_lib:close(Client).
+
+%%--------------------------------------------------------------------
+connection_information() ->
+ [{doc,"Test the API function ssl:connection_information/1"}].
+connection_information(Config) when is_list(Config) ->
+ ClientOpts = ssl_test_lib:ssl_options(client_rsa_opts, Config),
+ ServerOpts = ssl_test_lib:ssl_options(server_rsa_opts, Config),
+ {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
+ Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0},
+ {from, self()},
+ {mfa, {?MODULE, connection_information_result, []}},
+ {options, ServerOpts}]),
+
+ Port = ssl_test_lib:inet_port(Server),
+ Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port},
+ {host, Hostname},
+ {from, self()},
+ {mfa, {?MODULE, connection_information_result, []}},
+ {options, ClientOpts}]),
+
+ ct:log("Testcase ~p, Client ~p Server ~p ~n",
+ [self(), Client, Server]),
+
+ ssl_test_lib:check_result(Server, ok, Client, ok),
+
+ ssl_test_lib:close(Server),
+ ssl_test_lib:close(Client).
+%%--------------------------------------------------------------------
+
+secret_connection_info() ->
+ [{doc,"Test the API function ssl:connection_information/2"}].
+secret_connection_info(Config) when is_list(Config) ->
+ ClientOpts = ssl_test_lib:ssl_options(client_rsa_opts, Config),
+ ServerOpts = ssl_test_lib:ssl_options(server_rsa_opts, Config),
+ {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
+
+ Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0},
+ {from, self()},
+ {mfa, {?MODULE, secret_connection_info_result, []}},
+ {options, [{verify, verify_peer} | ServerOpts]}]),
+
+ Port = ssl_test_lib:inet_port(Server),
+ Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port},
+ {host, Hostname},
+ {from, self()},
+ {mfa, {?MODULE, secret_connection_info_result, []}},
+ {options, [{verify, verify_peer} |ClientOpts]}]),
+
+ ct:log("Testcase ~p, Client ~p Server ~p ~n",
+ [self(), Client, Server]),
+
+ ssl_test_lib:check_result(Server, true, Client, true),
+
+ ssl_test_lib:close(Server),
+ ssl_test_lib:close(Client).
+%%--------------------------------------------------------------------
+prf() ->
+ [{doc,"Test that ssl:prf/5 uses the negotiated PRF."}].
+prf(Config) when is_list(Config) ->
+ TestPlan = proplists:get_value(prf_test_plan, Config),
+ case TestPlan of
+ [] -> ct:fail({error, empty_prf_test_plan});
+ _ -> lists:foreach(fun(Suite) ->
+ lists:foreach(
+ fun(Test) ->
+ V = proplists:get_value(tls_ver, Test),
+ C = proplists:get_value(ciphers, Test),
+ E = proplists:get_value(expected, Test),
+ P = proplists:get_value(prf, Test),
+ prf_run_test(Config, V, C, E, P)
+ end, Suite)
+ end, TestPlan)
+ end.
+
+%%--------------------------------------------------------------------
+dh_params() ->
+ [{doc,"Test to specify DH-params file in server."}].
+
+dh_params(Config) when is_list(Config) ->
+ ClientOpts = ssl_test_lib:ssl_options(client_rsa_opts, Config),
+ ServerOpts = ssl_test_lib:ssl_options(server_rsa_opts, Config),
+ DataDir = proplists:get_value(data_dir, Config),
+ DHParamFile = filename:join(DataDir, "dHParam.pem"),
+
+ {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
+
+ Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0},
+ {from, self()},
+ {mfa, {ssl_test_lib, send_recv_result_active, []}},
+ {options, [{dhfile, DHParamFile} | ServerOpts]}]),
+ Port = ssl_test_lib:inet_port(Server),
+ Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port},
+ {host, Hostname},
+ {from, self()},
+ {mfa, {ssl_test_lib, send_recv_result_active, []}},
+ {options,
+ [{ciphers,[{dhe_rsa,aes_256_cbc,sha}]} |
+ ClientOpts]}]),
+
+ ssl_test_lib:check_result(Server, ok, Client, ok),
+
+ ssl_test_lib:close(Server),
+ ssl_test_lib:close(Client).
+
+%%--------------------------------------------------------------------
+conf_signature_algs() ->
+ [{doc,"Test to set the signature_algs option on both client and server"}].
+conf_signature_algs(Config) when is_list(Config) ->
+ ClientOpts = ssl_test_lib:ssl_options(client_rsa_opts, Config),
+ ServerOpts = ssl_test_lib:ssl_options(server_rsa_opts, Config),
+ {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
+ Server =
+ ssl_test_lib:start_server([{node, ServerNode}, {port, 0},
+ {from, self()},
+ {mfa, {ssl_test_lib, send_recv_result, []}},
+ {options, [{active, false}, {signature_algs, [{sha256, rsa}]} | ServerOpts]}]),
+ Port = ssl_test_lib:inet_port(Server),
+ Client =
+ ssl_test_lib:start_client([{node, ClientNode}, {port, Port},
+ {host, Hostname},
+ {from, self()},
+ {mfa, {ssl_test_lib, send_recv_result, []}},
+ {options, [{active, false}, {signature_algs, [{sha256, rsa}]} | ClientOpts]}]),
+
+ ct:log("Testcase ~p, Client ~p Server ~p ~n",
+ [self(), Client, Server]),
+
+ ssl_test_lib:check_result(Server, ok, Client, ok),
+
+ ssl_test_lib:close(Server),
+ ssl_test_lib:close(Client).
+
+
+%%--------------------------------------------------------------------
+no_common_signature_algs() ->
+ [{doc,"Set the signature_algs option so that there client and server does not share any hash sign algorithms"}].
+no_common_signature_algs(Config) when is_list(Config) ->
+
+ ClientOpts = ssl_test_lib:ssl_options(client_rsa_opts, Config),
+ ServerOpts = ssl_test_lib:ssl_options(server_rsa_opts, Config),
+
+ {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
+
+
+ Server = ssl_test_lib:start_server_error([{node, ServerNode}, {port, 0},
+ {from, self()},
+ {options, [{signature_algs, [{sha256, rsa}]}
+ | ServerOpts]}]),
+ Port = ssl_test_lib:inet_port(Server),
+ Client = ssl_test_lib:start_client_error([{node, ClientNode}, {port, Port},
+ {host, Hostname},
+ {from, self()},
+ {options, [{signature_algs, [{sha384, rsa}]}
+ | ClientOpts]}]),
+
+ ssl_test_lib:check_server_alert(Server, Client, insufficient_security).
+
+%%--------------------------------------------------------------------
+handshake_continue() ->
+ [{doc, "Test API function ssl:handshake_continue/3"}].
+handshake_continue(Config) when is_list(Config) ->
+ ClientOpts = ssl_test_lib:ssl_options(client_rsa_opts, Config),
+ ServerOpts = ssl_test_lib:ssl_options(server_rsa_opts, Config),
+ {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
+
+ Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0},
+ {from, self()},
+ {mfa, {ssl_test_lib, send_recv_result_active, []}},
+ {options, ssl_test_lib:ssl_options([{reuseaddr, true},
+ {verify, verify_peer},
+ {handshake, hello} | ServerOpts
+ ],
+ Config)},
+ {continue_options, proplists:delete(reuseaddr, ServerOpts)}
+ ]),
+
+ Port = ssl_test_lib:inet_port(Server),
+
+ Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port},
+ {host, Hostname},
+ {from, self()},
+ {mfa, {ssl_test_lib, send_recv_result_active, []}},
+ {options, ssl_test_lib:ssl_options([{handshake, hello},
+ {verify, verify_peer} | ClientOpts
+ ],
+ Config)},
+ {continue_options, proplists:delete(reuseaddr, ClientOpts)}]),
+
+ ssl_test_lib:check_result(Server, ok, Client, ok),
+
+ ssl_test_lib:close(Server),
+ ssl_test_lib:close(Client).
+
+
+%%------------------------------------------------------------------
+handshake_continue_timeout() ->
+ [{doc, "Test API function ssl:handshake_continue/3 with short timeout"}].
+handshake_continue_timeout(Config) when is_list(Config) ->
+ ClientOpts = ssl_test_lib:ssl_options(client_rsa_opts, Config),
+ ServerOpts = ssl_test_lib:ssl_options(server_rsa_opts, Config),
+ {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
+
+ Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0},
+ {from, self()},
+ {timeout, 1},
+ {options, ssl_test_lib:ssl_options([{reuseaddr, true}, {handshake, hello},
+ {verify, verify_peer} | ServerOpts],
+ Config)},
+ {continue_options, proplists:delete(reuseaddr, ServerOpts)}
+ ]),
+
+ Port = ssl_test_lib:inet_port(Server),
+
+
+ ssl_test_lib:start_client_error([{node, ClientNode}, {port, Port},
+ {host, Hostname},
+ {from, self()},
+ {options, [{verify, verify_peer} | ClientOpts]}]),
+
+ ssl_test_lib:check_result(Server, {error,timeout}),
+ ssl_test_lib:close(Server).
+
+
+%%--------------------------------------------------------------------
+hello_client_cancel() ->
+ [{doc, "Test API function ssl:handshake_cancel/1 on the client side"}].
+hello_client_cancel(Config) when is_list(Config) ->
+ ClientOpts = ssl_test_lib:ssl_options(client_rsa_opts, Config),
+ ServerOpts = ssl_test_lib:ssl_options(server_rsa_opts, Config),
+ {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
+
+ Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0},
+ {from, self()},
+ {options, ssl_test_lib:ssl_options([{handshake, hello},
+ {verify, verify_peer} | ServerOpts], Config)},
+ {continue_options, proplists:delete(reuseaddr, ServerOpts)}]),
+
+ Port = ssl_test_lib:inet_port(Server),
+
+ %% That is ssl:handshake_cancel returns ok
+ {connect_failed, ok} = ssl_test_lib:start_client([{node, ClientNode}, {port, Port},
+ {host, Hostname},
+ {from, self()},
+ {options, ssl_test_lib:ssl_options([{handshake, hello},
+ {verify, verify_peer} | ClientOpts], Config)},
+ {continue_options, cancel}]),
+ ssl_test_lib:check_server_alert(Server, user_canceled).
+%%--------------------------------------------------------------------
+hello_server_cancel() ->
+ [{doc, "Test API function ssl:handshake_cancel/1 on the server side"}].
+hello_server_cancel(Config) when is_list(Config) ->
+ ClientOpts = ssl_test_lib:ssl_options(client_rsa_opts, Config),
+ ServerOpts = ssl_test_lib:ssl_options(server_rsa_opts, Config),
+ {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
+
+ Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0},
+ {from, self()},
+ {options, ssl_test_lib:ssl_options([{handshake, hello},
+ {verify, verify_peer} | ServerOpts
+ ], Config)},
+ {continue_options, cancel}]),
+
+ Port = ssl_test_lib:inet_port(Server),
+
+ ssl_test_lib:start_client_error([{node, ClientNode}, {port, Port},
+ {host, Hostname},
+ {from, self()},
+ {options, ssl_test_lib:ssl_options([{handshake, hello},
+ {verify, verify_peer} | ClientOpts
+ ], Config)},
+ {continue_options, proplists:delete(reuseaddr, ClientOpts)}]),
+
+ ssl_test_lib:check_result(Server, ok).
+
+%%--------------------------------------------------------------------
+versions() ->
+ [{doc,"Test API function versions/0"}].
+
+versions(Config) when is_list(Config) ->
+ [_|_] = Versions = ssl:versions(),
+ ct:log("~p~n", [Versions]).
+
+%%--------------------------------------------------------------------
+%% Test case adapted from gen_tcp_misc_SUITE.
+active_n() ->
+ [{doc,"Test {active,N} option"}].
+
+active_n(Config) when is_list(Config) ->
+ ClientOpts = ssl_test_lib:ssl_options(client_rsa_opts, Config),
+ ServerOpts = ssl_test_lib:ssl_options(server_rsa_opts, Config),
+ Port = ssl_test_lib:inet_port(node()),
+ N = 3,
+ LS = ok(ssl:listen(Port, [{active,N}|ServerOpts])),
+ [{active,N}] = ok(ssl:getopts(LS, [active])),
+ active_n_common(LS, N),
+ Self = self(),
+ spawn_link(fun() ->
+ S0 = ok(ssl:transport_accept(LS)),
+ {ok, S} = ssl:handshake(S0),
+ ok = ssl:setopts(S, [{active,N}]),
+ [{active,N}] = ok(ssl:getopts(S, [active])),
+ ssl:controlling_process(S, Self),
+ Self ! {server, S}
+ end),
+ C = ok(ssl:connect("localhost", Port, [{active,N}|ClientOpts])),
+ [{active,N}] = ok(ssl:getopts(C, [active])),
+ S = receive
+ {server, S0} -> S0
+ after
+ 1000 ->
+ exit({error, connect})
+ end,
+ active_n_common(C, N),
+ active_n_common(S, N),
+ ok = ssl:setopts(C, [{active,N}]),
+ ok = ssl:setopts(S, [{active,N}]),
+ ReceiveMsg = fun(Socket, Msg) ->
+ receive
+ {ssl,Socket,Msg} ->
+ ok;
+ {ssl,Socket,Begin} ->
+ receive
+ {ssl,Socket,End} ->
+ Msg = Begin ++ End,
+ ok
+ after 1000 ->
+ exit(timeout)
+ end
+ after 1000 ->
+ exit(timeout)
+ end
+ end,
+ repeat(3, fun(I) ->
+ Msg = "message "++integer_to_list(I),
+ ok = ssl:send(C, Msg),
+ ReceiveMsg(S, Msg),
+ ok = ssl:send(S, Msg),
+ ReceiveMsg(C, Msg)
+ end),
+ receive
+ {ssl_passive,S} ->
+ [{active,false}] = ok(ssl:getopts(S, [active]))
+ after
+ 1000 ->
+ exit({error,ssl_passive})
+ end,
+ receive
+ {ssl_passive,C} ->
+ [{active,false}] = ok(ssl:getopts(C, [active]))
+ after
+ 1000 ->
+ exit({error,ssl_passive})
+ end,
+ LS2 = ok(ssl:listen(0, [{active,0}])),
+ receive
+ {ssl_passive,LS2} ->
+ [{active,false}] = ok(ssl:getopts(LS2, [active]))
+ after
+ 1000 ->
+ exit({error,ssl_passive})
+ end,
+ ok = ssl:close(LS2),
+ ok = ssl:close(C),
+ ok = ssl:close(S),
+ ok = ssl:close(LS),
+ ok.
+
+hibernate() ->
+ [{doc,"Check that an SSL connection that is started with option "
+ "{hibernate_after, 1000} indeed hibernates after 1000ms of "
+ "inactivity"}].
+
+hibernate(Config) ->
+ ClientOpts = ssl_test_lib:ssl_options(client_rsa_opts, Config),
+ ServerOpts = ssl_test_lib:ssl_options(server_rsa_opts, Config),
+
+ {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
+
+ Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0},
+ {from, self()},
+ {mfa, {ssl_test_lib, send_recv_result_active, []}},
+ {options, ServerOpts}]),
+ Port = ssl_test_lib:inet_port(Server),
+ {Client, #sslsocket{pid=[Pid|_]}} = ssl_test_lib:start_client([return_socket,
+ {node, ClientNode}, {port, Port},
+ {host, Hostname},
+ {from, self()},
+ {mfa, {ssl_test_lib, send_recv_result_active, []}},
+ {options, [{hibernate_after, 1000}|ClientOpts]}]),
+ {current_function, _} =
+ process_info(Pid, current_function),
+
+ ssl_test_lib:check_result(Server, ok, Client, ok),
+
+ ct:sleep(1500),
+ {current_function, {erlang, hibernate, 3}} =
+ process_info(Pid, current_function),
+
+ ssl_test_lib:close(Server),
+ ssl_test_lib:close(Client).
+
+%%--------------------------------------------------------------------
+
+hibernate_right_away() ->
+ [{doc,"Check that an SSL connection that is configured to hibernate "
+ "after 0 or 1 milliseconds hibernates as soon as possible and not "
+ "crashes"}].
+
+hibernate_right_away(Config) ->
+ ClientOpts = ssl_test_lib:ssl_options(client_rsa_opts, Config),
+ ServerOpts = ssl_test_lib:ssl_options(server_rsa_opts, Config),
+
+ {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
+
+ StartServerOpts = [{node, ServerNode}, {port, 0},
+ {from, self()},
+ {mfa, {ssl_test_lib, send_recv_result_active, []}},
+ {options, ServerOpts}],
+ StartClientOpts = [return_socket,
+ {node, ClientNode},
+ {host, Hostname},
+ {from, self()},
+ {mfa, {ssl_test_lib, send_recv_result_active, []}}],
+
+ Server1 = ssl_test_lib:start_server(StartServerOpts),
+ Port1 = ssl_test_lib:inet_port(Server1),
+ {Client1, #sslsocket{pid = [Pid1|_]}} = ssl_test_lib:start_client(StartClientOpts ++
+ [{port, Port1}, {options, [{hibernate_after, 0}|ClientOpts]}]),
+
+ ssl_test_lib:check_result(Server1, ok, Client1, ok),
+
+ ct:sleep(1000), %% Schedule out
+
+ {current_function, {erlang, hibernate, 3}} =
+ process_info(Pid1, current_function),
+ ssl_test_lib:close(Server1),
+ ssl_test_lib:close(Client1),
+
+ Server2 = ssl_test_lib:start_server(StartServerOpts),
+ Port2 = ssl_test_lib:inet_port(Server2),
+ {Client2, #sslsocket{pid = [Pid2|_]}} = ssl_test_lib:start_client(StartClientOpts ++
+ [{port, Port2}, {options, [{hibernate_after, 1}|ClientOpts]}]),
+
+ ssl_test_lib:check_result(Server2, ok, Client2, ok),
+
+ ct:sleep(1000), %% Schedule out
+
+ {current_function, {erlang, hibernate, 3}} =
+ process_info(Pid2, current_function),
+
+ ssl_test_lib:close(Server2),
+ ssl_test_lib:close(Client2).
+
+listen_socket() ->
+ [{doc,"Check error handling and inet compliance when calling API functions with listen sockets."}].
+
+listen_socket(Config) ->
+ ServerOpts = ssl_test_lib:ssl_options(server_rsa_opts, Config),
+ {ok, ListenSocket} = ssl:listen(0, ServerOpts),
+
+ %% This can be a valid thing to do as
+ %% options are inherited by the accept socket
+ ok = ssl:controlling_process(ListenSocket, self()),
+
+ {ok, _} = ssl:sockname(ListenSocket),
+
+ {error, enotconn} = ssl:send(ListenSocket, <<"data">>),
+ {error, enotconn} = ssl:recv(ListenSocket, 0),
+ {error, enotconn} = ssl:connection_information(ListenSocket),
+ {error, enotconn} = ssl:peername(ListenSocket),
+ {error, enotconn} = ssl:peercert(ListenSocket),
+ {error, enotconn} = ssl:renegotiate(ListenSocket),
+ {error, enotconn} = ssl:prf(ListenSocket, 'master_secret', <<"Label">>, [client_random], 256),
+ {error, enotconn} = ssl:shutdown(ListenSocket, read_write),
+
+ ok = ssl:close(ListenSocket).
+
+%%--------------------------------------------------------------------
+recv_active() ->
+ [{doc,"Test recv on active socket"}].
+
+recv_active(Config) when is_list(Config) ->
+ ClientOpts = ssl_test_lib:ssl_options(client_rsa_opts, Config),
+ ServerOpts = ssl_test_lib:ssl_options(server_rsa_opts, Config),
+ {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
+ Server =
+ ssl_test_lib:start_server([{node, ServerNode}, {port, 0},
+ {from, self()},
+ {mfa, {?MODULE, try_recv_active, []}},
+ {options, [{active, true} | ServerOpts]}]),
+ Port = ssl_test_lib:inet_port(Server),
+ Client =
+ ssl_test_lib:start_client([{node, ClientNode}, {port, Port},
+ {host, Hostname},
+ {from, self()},
+ {mfa, {?MODULE, try_recv_active, []}},
+ {options, [{active, true} | ClientOpts]}]),
+
+ ssl_test_lib:check_result(Server, ok, Client, ok),
+
+ ssl_test_lib:close(Server),
+ ssl_test_lib:close(Client).
+
+%%--------------------------------------------------------------------
+recv_active_once() ->
+ [{doc,"Test recv on active (once) socket"}].
+
+recv_active_once(Config) when is_list(Config) ->
+ ClientOpts = ssl_test_lib:ssl_options(client_rsa_opts, Config),
+ ServerOpts = ssl_test_lib:ssl_options(server_rsa_opts, Config),
+ {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
+ Server =
+ ssl_test_lib:start_server([{node, ServerNode}, {port, 0},
+ {from, self()},
+ {mfa, {?MODULE, try_recv_active_once, []}},
+ {options, [{active, once} | ServerOpts]}]),
+ Port = ssl_test_lib:inet_port(Server),
+ Client =
+ ssl_test_lib:start_client([{node, ClientNode}, {port, Port},
+ {host, Hostname},
+ {from, self()},
+ {mfa, {?MODULE, try_recv_active_once, []}},
+ {options, [{active, once} | ClientOpts]}]),
+
+ ssl_test_lib:check_result(Server, ok, Client, ok),
+
+ ssl_test_lib:close(Server),
+ ssl_test_lib:close(Client).
+
+%%--------------------------------------------------------------------
+recv_active_n() ->
+ [{doc,"Test recv on active (n) socket"}].
+
+recv_active_n(Config) when is_list(Config) ->
+ ClientOpts = ssl_test_lib:ssl_options(client_rsa_opts, Config),
+ ServerOpts = ssl_test_lib:ssl_options(server_rsa_opts, Config),
+ {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
+ Server =
+ ssl_test_lib:start_server([{node, ServerNode}, {port, 0},
+ {from, self()},
+ {mfa, {?MODULE, try_recv_active_once, []}},
+ {options, [{active, 1} | ServerOpts]}]),
+ Port = ssl_test_lib:inet_port(Server),
+ Client =
+ ssl_test_lib:start_client([{node, ClientNode}, {port, Port},
+ {host, Hostname},
+ {from, self()},
+ {mfa, {?MODULE, try_recv_active_once, []}},
+ {options, [{active, 1} | ClientOpts]}]),
+
+ ssl_test_lib:check_result(Server, ok, Client, ok),
+
+ ssl_test_lib:close(Server),
+ ssl_test_lib:close(Client).
+%%--------------------------------------------------------------------
+recv_timeout() ->
+ [{doc,"Test ssl:ssl_accept timeout"}].
+
+recv_timeout(Config) ->
+ ServerOpts = ssl_test_lib:ssl_options(server_rsa_opts, Config),
+ ClientOpts = ssl_test_lib:ssl_options(client_rsa_opts, Config),
+
+ {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
+
+ Server =
+ ssl_test_lib:start_server([{node, ServerNode}, {port, 0},
+ {from, self()},
+ {mfa, {?MODULE, send_recv_result_timeout_server, []}},
+ {options, [{active, false} | ServerOpts]}]),
+ Port = ssl_test_lib:inet_port(Server),
+
+ Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port},
+ {host, Hostname},
+ {from, self()},
+ {mfa, {?MODULE,
+ send_recv_result_timeout_client, []}},
+ {options, [{active, false} | ClientOpts]}]),
+
+ ssl_test_lib:check_result(Client, ok, Server, ok),
+ ssl_test_lib:close(Server),
+ ssl_test_lib:close(Client).
+
+%%--------------------------------------------------------------------
+recv_close() ->
+ [{doc,"Special case of call error handling"}].
+recv_close(Config) when is_list(Config) ->
+ ClientOpts = ssl_test_lib:ssl_options(client_rsa_opts, Config),
+ ServerOpts = ssl_test_lib:ssl_options(server_rsa_opts, Config),
+
+ {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
+ Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0},
+ {from, self()},
+ {mfa, {?MODULE, do_recv_close, []}},
+ {options, [{active, false} | ServerOpts]}]),
+ Port = ssl_test_lib:inet_port(Server),
+ {_Client, #sslsocket{} = SslSocket} = ssl_test_lib:start_client([return_socket,
+ {node, ClientNode}, {port, Port},
+ {host, Hostname},
+ {from, self()},
+ {mfa, {ssl_test_lib, no_result, []}},
+ {options, ClientOpts}]),
+ ssl:close(SslSocket),
+ ssl_test_lib:check_result(Server, ok).
+
+
+
+%%--------------------------------------------------------------------
+controlling_process() ->
+ [{doc,"Test API function controlling_process/2"}].
+
+controlling_process(Config) when is_list(Config) ->
+ ClientOpts = ssl_test_lib:ssl_options(client_rsa_opts, Config),
+ ServerOpts = ssl_test_lib:ssl_options(server_rsa_opts, Config),
+ {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
+ ClientMsg = "Server hello",
+ ServerMsg = "Client hello",
+
+ Server = ssl_test_lib:start_server([
+ {node, ServerNode}, {port, 0},
+ {from, self()},
+ {mfa, {?MODULE,
+ controlling_process_result, [self(),
+ ServerMsg]}},
+ {options, ServerOpts}]),
+ Port = ssl_test_lib:inet_port(Server),
+ {Client, CSocket} = ssl_test_lib:start_client([return_socket,
+ {node, ClientNode}, {port, Port},
+ {host, Hostname},
+ {from, self()},
+ {mfa, {?MODULE,
+ controlling_process_result, [self(),
+ ClientMsg]}},
+ {options, ClientOpts}]),
+
+ ct:log("Testcase ~p, Client ~p Server ~p ~n",
+ [self(), Client, Server]),
+
+ ServerMsg = ssl_test_lib:active_recv(CSocket, length(ServerMsg)),
+ %% We do not have the TLS server socket but all messages form the client
+ %% socket are now read, so ramining are form the server socket
+ ClientMsg = ssl_active_recv(length(ClientMsg)),
+
+ ssl_test_lib:close(Server),
+ ssl_test_lib:close(Client).
+%%--------------------------------------------------------------------
+controller_dies() ->
+ [{doc,"Test that the socket is closed after controlling process dies"}].
+controller_dies(Config) when is_list(Config) ->
+ ClientOpts = ssl_test_lib:ssl_options(client_rsa_opts, Config),
+ ServerOpts = ssl_test_lib:ssl_options(server_rsa_opts, Config),
+ {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
+ ClientMsg = "Hello server",
+ ServerMsg = "Hello client",
+
+ Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0},
+ {from, self()},
+ {mfa, {?MODULE,
+ controller_dies_result, [self(),
+ ServerMsg]}},
+ {options, ServerOpts}]),
+ Port = ssl_test_lib:inet_port(Server),
+ Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port},
+ {host, Hostname},
+ {from, self()},
+ {mfa, {?MODULE,
+ controller_dies_result, [self(),
+ ClientMsg]}},
+ {options, ClientOpts}]),
+
+ ct:log("Testcase ~p, Client ~p Server ~p ~n", [self(), Client, Server]),
+ ct:sleep(?SLEEP), %% so that they are connected
+
+ process_flag(trap_exit, true),
+
+ %% Test that clients die
+ exit(Client, killed),
+ get_close(Client, ?LINE),
+
+ %% Test that clients die when process disappear
+ Server ! listen,
+ Tester = self(),
+ Connect = fun(Pid) ->
+ {ok, Socket} = ssl:connect(Hostname, Port, ClientOpts),
+ %% Make sure server finishes and verification
+ %% and is in coonection state before
+ %% killing client
+ ct:sleep(?SLEEP),
+ Pid ! {self(), connected, Socket},
+ receive die_nice -> normal end
+ end,
+ Client2 = spawn_link(fun() -> Connect(Tester) end),
+ receive {Client2, connected, _Socket} -> Client2 ! die_nice end,
+
+ get_close(Client2, ?LINE),
+
+ %% Test that clients die when the controlling process have changed
+ Server ! listen,
+
+ Client3 = spawn_link(fun() -> Connect(Tester) end),
+ Controller = spawn_link(fun() -> receive die_nice -> normal end end),
+ receive
+ {Client3, connected, Socket} ->
+ ok = ssl:controlling_process(Socket, Controller),
+ Client3 ! die_nice
+ end,
+
+ ct:log("Wating on exit ~p~n",[Client3]),
+ receive {'EXIT', Client3, normal} -> ok end,
+
+ receive %% Client3 is dead but that doesn't matter, socket should not be closed.
+ Unexpected ->
+ ct:log("Unexpected ~p~n",[Unexpected]),
+ ct:fail({line, ?LINE-1})
+ after 1000 ->
+ ok
+ end,
+ Controller ! die_nice,
+ get_close(Controller, ?LINE),
+
+ %% Test that servers die
+ Server ! listen,
+ LastClient = ssl_test_lib:start_client([{node, ClientNode}, {port, Port},
+ {host, Hostname},
+ {from, self()},
+ {mfa, {?MODULE,
+ controller_dies_result, [self(),
+ ClientMsg]}},
+ {options, ClientOpts}]),
+ ct:sleep(?SLEEP), %% so that they are connected
+
+ exit(Server, killed),
+ get_close(Server, ?LINE),
+ process_flag(trap_exit, false),
+ ssl_test_lib:close(LastClient).
+%%--------------------------------------------------------------------
+controlling_process_transport_accept_socket() ->
+ [{doc,"Only ssl:handshake and ssl:controlling_process is allowed for transport_accept:sockets"}].
+controlling_process_transport_accept_socket(Config) when is_list(Config) ->
+ ServerOpts = ssl_test_lib:ssl_options(server_rsa_opts, Config),
+ ClientOpts = ssl_test_lib:ssl_options(client_rsa_opts, Config),
+ {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
+
+ Server = ssl_test_lib:start_server_transport_control([{node, ServerNode},
+ {port, 0},
+ {from, self()},
+ {options, ServerOpts}]),
+ Port = ssl_test_lib:inet_port(Server),
+
+ _Client = ssl_test_lib:start_client_error([{node, ClientNode}, {port, Port},
+ {host, Hostname},
+ {from, self()},
+ {options, ClientOpts}]),
+ ssl_test_lib:check_result(Server, ok),
+ ssl_test_lib:close(Server).
+
+%%--------------------------------------------------------------------
+close_with_timeout() ->
+ [{doc,"Test normal (not downgrade) ssl:close/2"}].
+close_with_timeout(Config) when is_list(Config) ->
+ ClientOpts = ssl_test_lib:ssl_options(client_rsa_opts, Config),
+ ServerOpts = ssl_test_lib:ssl_options(server_rsa_opts, Config),
+
+ {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
+
+ Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0},
+ {from, self()},
+ {mfa, {?MODULE, tls_close, []}},
+ {options,[{active, false} | ServerOpts]}]),
+ Port = ssl_test_lib:inet_port(Server),
+ Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port},
+ {host, Hostname},
+ {from, self()},
+ {mfa, {?MODULE, tls_close, []}},
+ {options, [{active, false} |ClientOpts]}]),
+
+ ssl_test_lib:check_result(Server, ok, Client, ok).
+
+%%--------------------------------------------------------------------
+close_in_error_state() ->
+ [{doc,"Special case of closing socket in error state"}].
+close_in_error_state(Config) when is_list(Config) ->
+ ServerOpts0 = ssl_test_lib:ssl_options(server_opts, Config),
+ ServerOpts = [{cacertfile, "foo.pem"} | proplists:delete(cacertfile, ServerOpts0)],
+ ClientOpts = ssl_test_lib:ssl_options(client_opts, Config),
+ _ = spawn_link(?MODULE, run_error_server_close, [[self() | ServerOpts]]),
+ receive
+ {_Pid, Port} ->
+ spawn_link(?MODULE, run_client_error, [[Port, ClientOpts]])
+ end,
+ receive
+ ok ->
+ ok;
+ Other ->
+ ct:fail(Other)
+ end.
+
+%%--------------------------------------------------------------------
+call_in_error_state() ->
+ [{doc,"Special case of call error handling"}].
+call_in_error_state(Config) when is_list(Config) ->
+ ServerOpts0 = ssl_test_lib:ssl_options(server_opts, Config),
+ ClientOpts = ssl_test_lib:ssl_options(client_opts, Config),
+ ServerOpts = [{cacertfile, "foo.pem"} | proplists:delete(cacertfile, ServerOpts0)],
+ Pid = spawn_link(?MODULE, run_error_server, [[self() | ServerOpts]]),
+ receive
+ {Pid, Port} ->
+ spawn_link(?MODULE, run_client_error, [[Port, ClientOpts]])
+ end,
+ receive
+ {error, closed} ->
+ ok;
+ Other ->
+ ct:fail(Other)
+ end.
+%%--------------------------------------------------------------------
+close_transport_accept() ->
+ [{doc,"Tests closing ssl socket when waiting on ssl:transport_accept/1"}].
+
+close_transport_accept(Config) when is_list(Config) ->
+ ServerOpts = ssl_test_lib:ssl_options(server_rsa_opts, Config),
+ {_ClientNode, ServerNode, _Hostname} = ssl_test_lib:run_where(Config),
+
+ Port = 0,
+ Opts = [{active, false} | ServerOpts],
+ {ok, ListenSocket} = rpc:call(ServerNode, ssl, listen, [Port, Opts]),
+ spawn_link(fun() ->
+ ct:sleep(?SLEEP),
+ rpc:call(ServerNode, ssl, close, [ListenSocket])
+ end),
+ case rpc:call(ServerNode, ssl, transport_accept, [ListenSocket]) of
+ {error, closed} ->
+ ok;
+ Other ->
+ exit({?LINE, Other})
+ end.
+%%--------------------------------------------------------------------
+abuse_transport_accept_socket() ->
+ [{doc,"Only ssl:handshake and ssl:controlling_process is allowed for transport_accept:sockets"}].
+abuse_transport_accept_socket(Config) when is_list(Config) ->
+ ServerOpts = ssl_test_lib:ssl_options(server_rsa_opts, Config),
+ ClientOpts = ssl_test_lib:ssl_options(client_rsa_opts, Config),
+ {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
+
+ Server = ssl_test_lib:start_server_transport_abuse_socket([{node, ServerNode},
+ {port, 0},
+ {from, self()},
+ {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, no_result, []}},
+ {options, ClientOpts}]),
+ ssl_test_lib:check_result(Server, ok),
+ ssl_test_lib:close(Server),
+ ssl_test_lib:close(Client).
+
+%%--------------------------------------------------------------------
+
+invalid_keyfile() ->
+ [{doc,"Test what happens with an invalid key file"}].
+invalid_keyfile(Config) when is_list(Config) ->
+ ClientOpts = ssl_test_lib:ssl_options(client_rsa_opts, Config),
+ ServerOpts = ssl_test_lib:ssl_options(server_rsa_opts, Config),
+ BadKeyFile = filename:join([proplists:get_value(priv_dir, Config),
+ "badkey.pem"]),
+ BadOpts = [{keyfile, BadKeyFile}| proplists:delete(keyfile, ServerOpts)],
+ {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
+
+ Server =
+ ssl_test_lib:start_server_error([{node, ServerNode}, {port, 0},
+ {from, self()},
+ {options, BadOpts}]),
+
+ Port = ssl_test_lib:inet_port(Server),
+
+ Client =
+ ssl_test_lib:start_client_error([{node, ClientNode},
+ {port, Port}, {host, Hostname},
+ {from, self()}, {options, ClientOpts}]),
+
+ File = proplists:get_value(keyfile,BadOpts),
+ ssl_test_lib:check_result(Server, {error,{options, {keyfile, File, {error,enoent}}}}, Client,
+ {error, closed}).
+
+%%--------------------------------------------------------------------
+honor_server_cipher_order() ->
+ [{doc,"Test API honor server cipher order."}].
+honor_server_cipher_order(Config) when is_list(Config) ->
+ ClientCiphers = [#{key_exchange => dhe_rsa,
+ cipher => aes_128_cbc,
+ mac => sha,
+ prf => default_prf},
+ #{key_exchange => dhe_rsa,
+ cipher => aes_256_cbc,
+ mac => sha,
+ prf => default_prf}],
+ ServerCiphers = [#{key_exchange => dhe_rsa,
+ cipher => aes_256_cbc,
+ mac =>sha,
+ prf => default_prf},
+ #{key_exchange => dhe_rsa,
+ cipher => aes_128_cbc,
+ mac => sha,
+ prf => default_prf}],
+ honor_cipher_order(Config, true, ServerCiphers, ClientCiphers, #{key_exchange => dhe_rsa,
+ cipher => aes_256_cbc,
+ mac => sha,
+ prf => default_prf}).
+
+%%--------------------------------------------------------------------
+honor_client_cipher_order() ->
+ [{doc,"Test API honor server cipher order."}].
+honor_client_cipher_order(Config) when is_list(Config) ->
+ ClientCiphers = [#{key_exchange => dhe_rsa,
+ cipher => aes_128_cbc,
+ mac => sha,
+ prf => default_prf},
+ #{key_exchange => dhe_rsa,
+ cipher => aes_256_cbc,
+ mac => sha,
+ prf => default_prf}],
+ ServerCiphers = [#{key_exchange => dhe_rsa,
+ cipher => aes_256_cbc,
+ mac =>sha,
+ prf => default_prf},
+ #{key_exchange => dhe_rsa,
+ cipher => aes_128_cbc,
+ mac => sha,
+ prf => default_prf}],
+ honor_cipher_order(Config, false, ServerCiphers, ClientCiphers, #{key_exchange => dhe_rsa,
+ cipher => aes_128_cbc,
+ mac => sha,
+ prf => default_prf}).
+
+%%--------------------------------------------------------------------
+ipv6() ->
+ [{require, ipv6_hosts},
+ {doc,"Test ipv6."}].
+ipv6(Config) when is_list(Config) ->
+ {ok, Hostname0} = inet:gethostname(),
+
+ case lists:member(list_to_atom(Hostname0), ct:get_config(ipv6_hosts)) of
+ true ->
+ ClientOpts = ssl_test_lib:ssl_options(client_rsa_opts, Config),
+ ServerOpts = ssl_test_lib:ssl_options(server_rsa_opts, Config),
+ {ClientNode, ServerNode, Hostname} =
+ ssl_test_lib:run_where(Config, ipv6),
+ Server = ssl_test_lib:start_server([{node, ServerNode},
+ {port, 0}, {from, self()},
+ {mfa, {ssl_test_lib, send_recv_result, []}},
+ {options,
+ [inet6, {active, false} | ServerOpts]}]),
+ Port = ssl_test_lib:inet_port(Server),
+ Client = ssl_test_lib:start_client([{node, ClientNode},
+ {port, Port}, {host, Hostname},
+ {from, self()},
+ {mfa, {ssl_test_lib, send_recv_result, []}},
+ {options,
+ [inet6, {active, false} | ClientOpts]}]),
+
+ ct:log("Testcase ~p, Client ~p Server ~p ~n",
+ [self(), Client, Server]),
+
+ ssl_test_lib:check_result(Server, ok, Client, ok),
+
+ ssl_test_lib:close(Server),
+ ssl_test_lib:close(Client);
+ false ->
+ {skip, "Host does not support IPv6"}
+ end.
+
+%%--------------------------------------------------------------------
+der_input() ->
+ [{doc,"Test to input certs and key as der"}].
+
+der_input(Config) when is_list(Config) ->
+ DataDir = proplists:get_value(data_dir, Config),
+ DHParamFile = filename:join(DataDir, "dHParam.pem"),
+
+ {status, _, _, StatusInfo} = sys:get_status(whereis(ssl_manager)),
+ [_, _,_, _, Prop] = StatusInfo,
+ State = ssl_test_lib:state(Prop),
+ [CADb | _] = element(6, State),
+
+ Size = ets:info(CADb, size),
+
+ SeverVerifyOpts = ssl_test_lib:ssl_options(server_rsa_opts, Config),
+ {ServerCert, ServerKey, ServerCaCerts, DHParams} = der_input_opts([{dhfile, DHParamFile} |
+ SeverVerifyOpts]),
+ ClientVerifyOpts = ssl_test_lib:ssl_options(client_rsa_opts, Config),
+ {ClientCert, ClientKey, ClientCaCerts, DHParams} = der_input_opts([{dhfile, DHParamFile} |
+ ClientVerifyOpts]),
+ ServerOpts = [{verify, verify_peer}, {fail_if_no_peer_cert, true},
+ {dh, DHParams},
+ {cert, ServerCert}, {key, ServerKey}, {cacerts, ServerCaCerts}],
+ ClientOpts = [{verify, verify_peer}, {fail_if_no_peer_cert, true},
+ {dh, DHParams},
+ {cert, ClientCert}, {key, ClientKey}, {cacerts, ClientCaCerts}],
+ {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
+ Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0},
+ {from, self()},
+ {mfa, {ssl_test_lib, send_recv_result, []}},
+ {options, [{active, false} | ServerOpts]}]),
+ Port = ssl_test_lib:inet_port(Server),
+ Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port},
+ {host, Hostname},
+ {from, self()},
+ {mfa, {ssl_test_lib, send_recv_result, []}},
+ {options, [{active, false} | ClientOpts]}]),
+
+ ssl_test_lib:check_result(Server, ok, Client, ok),
+ ssl_test_lib:close(Server),
+ ssl_test_lib:close(Client),
+ Size = ets:info(CADb, size).
+
+%%--------------------------------------------------------------------
+invalid_certfile() ->
+ [{doc,"Test what happens with an invalid cert file"}].
+
+invalid_certfile(Config) when is_list(Config) ->
+ ClientOpts = ssl_test_lib:ssl_options(client_rsa_opts, Config),
+ ServerOpts = ssl_test_lib:ssl_options(server_rsa_opts, Config),
+ BadCertFile = filename:join([proplists:get_value(priv_dir, Config),
+ "badcert.pem"]),
+ ServerBadOpts = [{certfile, BadCertFile}| proplists:delete(certfile, ServerOpts)],
+ {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
+
+
+ {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
+
+ Server =
+ ssl_test_lib:start_server_error([{node, ServerNode}, {port, 0},
+ {from, self()},
+ {options, ServerBadOpts}]),
+
+ Port = ssl_test_lib:inet_port(Server),
+
+ Client =
+ ssl_test_lib:start_client_error([{node, ClientNode},
+ {port, Port}, {host, Hostname},
+ {from, self()},
+ {options, ClientOpts}]),
+ File = proplists:get_value(certfile, ServerBadOpts),
+ ssl_test_lib:check_result(Server, {error,{options, {certfile, File, {error,enoent}}}},
+ Client, {error, closed}).
+
+
+%%--------------------------------------------------------------------
+invalid_cacertfile() ->
+ [{doc,"Test what happens with an invalid cacert file"}].
+
+invalid_cacertfile(Config) when is_list(Config) ->
+ ClientOpts = ssl_test_lib:ssl_options(client_rsa_opts, Config),
+ ServerOpts = ssl_test_lib:ssl_options(server_rsa_opts, Config),
+ BadCACertFile = filename:join([proplists:get_value(priv_dir, Config),
+ "badcacert.pem"]),
+ ServerBadOpts = [{cacertfile, BadCACertFile}| proplists:delete(cacertfile, ServerOpts)],
+
+ {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
+
+ Server0 =
+ ssl_test_lib:start_server_error([{node, ServerNode},
+ {port, 0}, {from, self()},
+ {options, ServerBadOpts}]),
+
+ Port0 = ssl_test_lib:inet_port(Server0),
+
+
+ Client0 =
+ ssl_test_lib:start_client_error([{node, ClientNode},
+ {port, Port0}, {host, Hostname},
+ {from, self()},
+ {options, ClientOpts}]),
+
+ File0 = proplists:get_value(cacertfile, ServerBadOpts),
+
+ ssl_test_lib:check_result(Server0, {error, {options, {cacertfile, File0,{error,enoent}}}},
+ Client0, {error, closed}),
+
+ File = File0 ++ "do_not_exit.pem",
+ ServerBadOpts1 = [{cacertfile, File}|proplists:delete(cacertfile, ServerBadOpts)],
+
+ Server1 =
+ ssl_test_lib:start_server_error([{node, ServerNode},
+ {port, 0}, {from, self()},
+ {options, ServerBadOpts1}]),
+
+ Port1 = ssl_test_lib:inet_port(Server1),
+
+ Client1 =
+ ssl_test_lib:start_client_error([{node, ClientNode},
+ {port, Port1}, {host, Hostname},
+ {from, self()},
+ {options, ClientOpts}]),
+
+
+ ssl_test_lib:check_result(Server1, {error, {options, {cacertfile, File,{error,enoent}}}},
+ Client1, {error, closed}),
+ ok.
+
+%%--------------------------------------------------------------------
+new_options_in_handshake() ->
+ [{doc,"Test that you can set ssl options in handshake/3 and not only in tcp upgrade"}].
+new_options_in_handshake(Config) when is_list(Config) ->
+ ClientOpts = ssl_test_lib:ssl_options(client_rsa_opts, Config),
+ ServerOpts = ssl_test_lib:ssl_options(server_rsa_opts, Config),
+ Version = ssl_test_lib:protocol_version(Config),
+ {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
+
+ [_, Cipher | _] = ssl:filter_cipher_suites(ssl:cipher_suites(all, Version),
+ [{key_exchange,
+ fun(dhe_rsa) ->
+ true;
+ (ecdhe_rsa) ->
+ true;
+ (ecdh_rsa) ->
+ true;
+ (rsa) ->
+ true;
+ (_) ->
+ false
+ end
+ }]),
+
+ Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0},
+ {from, self()},
+ {ssl_extra_opts, [{versions, [Version]},
+ {ciphers,[Cipher]}]}, %% To be set in ssl_accept/3
+ {mfa, {?MODULE, connection_info_result, []}},
+ {options, ServerOpts}]),
+
+ Port = ssl_test_lib:inet_port(Server),
+ Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port},
+ {host, Hostname},
+ {from, self()},
+ {mfa, {?MODULE, connection_info_result, []}},
+ {options, [{ciphers, [Cipher]} | ClientOpts]}]),
+
+ ct:log("Testcase ~p, Client ~p Server ~p ~n",
+ [self(), Client, Server]),
+
+ ServerMsg = ClientMsg = {ok, {Version, Cipher}},
+
+ ssl_test_lib:check_result(Server, ServerMsg, Client, ClientMsg),
+
+ ssl_test_lib:close(Server),
+ ssl_test_lib:close(Client).
+
+%%-------------------------------------------------------------------
+max_handshake_size() ->
+ [{doc,"Test that we can set max_handshake_size to max value."}].
+
+max_handshake_size(Config) when is_list(Config) ->
+ ClientOpts = ssl_test_lib:ssl_options(client_rsa_opts, Config),
+ ServerOpts = ssl_test_lib:ssl_options(server_rsa_opts, Config),
+
+ {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
+ Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0},
+ {from, self()},
+ {mfa, {ssl_test_lib, send_recv_result_active, []}},
+ {options, [{max_handshake_size, 8388607} |ServerOpts]}]),
+ Port = ssl_test_lib:inet_port(Server),
+
+ Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port},
+ {host, Hostname},
+ {from, self()},
+ {mfa, {ssl_test_lib, send_recv_result_active, []}},
+ {options, [{max_handshake_size, 8388607} | ClientOpts]}]),
+
+ ssl_test_lib:check_result(Server, ok, Client, ok).
+
+
+%%-------------------------------------------------------------------
+options_not_proplist() ->
+ [{doc,"Test what happens if an option is not a key value tuple"}].
+
+options_not_proplist(Config) when is_list(Config) ->
+ BadOption = {client_preferred_next_protocols,
+ client, [<<"spdy/3">>,<<"http/1.1">>], <<"http/1.1">>},
+ {option_not_a_key_value_tuple, BadOption} =
+ ssl:connect("twitter.com", 443, [binary, {active, false},
+ BadOption]).
+
+%%-------------------------------------------------------------------
+invalid_options() ->
+ [{doc,"Test what happens when we give invalid options"}].
+
+invalid_options(Config) when is_list(Config) ->
+ ClientOpts = ssl_test_lib:ssl_options(client_rsa_verify_opts, Config),
+ ServerOpts = ssl_test_lib:ssl_options(server_rsa_opts, Config),
+ {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
+
+ Check = fun(Client, Server, {versions, [sslv2, sslv3]} = Option) ->
+ ssl_test_lib:check_result(Server,
+ {error, {options, {sslv2, Option}}},
+ Client,
+ {error, {options, {sslv2, Option}}});
+ (Client, Server, Option) ->
+ ssl_test_lib:check_result(Server,
+ {error, {options, Option}},
+ Client,
+ {error, {options, Option}})
+ end,
+
+ TestOpts =
+ [{versions, [sslv2, sslv3]},
+ {verify, 4},
+ {verify_fun, function},
+ {fail_if_no_peer_cert, 0},
+ {verify_client_once, 1},
+ {depth, four},
+ {certfile, 'cert.pem'},
+ {keyfile,'key.pem' },
+ {password, foo},
+ {cacertfile, ""},
+ {dhfile,'dh.pem' },
+ {ciphers, [{foo, bar, sha, ignore}]},
+ {reuse_session, foo},
+ {reuse_sessions, 0},
+ {renegotiate_at, "10"},
+ {mode, depech},
+ {packet, 8.0},
+ {packet_size, "2"},
+ {header, a},
+ {active, trice},
+ {key, 'key.pem' }],
+
+ [begin
+ Server =
+ ssl_test_lib:start_server_error([{node, ServerNode}, {port, 0},
+ {from, self()},
+ {options, [TestOpt | ServerOpts]}]),
+ %% Will never reach a point where port is used.
+ Client =
+ ssl_test_lib:start_client_error([{node, ClientNode}, {port, 0},
+ {host, Hostname}, {from, self()},
+ {options, [TestOpt | ClientOpts]}]),
+ Check(Client, Server, TestOpt),
+ ok
+ end || TestOpt <- TestOpts],
+ ok.
+%%-------------------------------------------------------------------
+
+default_reject_anonymous()->
+ [{doc,"Test that by default anonymous cipher suites are rejected "}].
+default_reject_anonymous(Config) when is_list(Config) ->
+ {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
+ ClientOpts = ssl_test_lib:ssl_options(client_rsa_opts, Config),
+ ServerOpts = ssl_test_lib:ssl_options(server_rsa_opts, Config),
+ Version = ssl_test_lib:protocol_version(Config),
+ TLSVersion = ssl_test_lib:tls_version(Version),
+
+ [CipherSuite | _] = ssl_test_lib:ecdh_dh_anonymous_suites(TLSVersion),
+
+ Server = ssl_test_lib:start_server_error([{node, ServerNode}, {port, 0},
+ {from, self()},
+ {options, ServerOpts}]),
+ Port = ssl_test_lib:inet_port(Server),
+ Client = ssl_test_lib:start_client_error([{node, ClientNode}, {port, Port},
+ {host, Hostname},
+ {from, self()},
+ {options,
+ [{ciphers,[CipherSuite]} |
+ ClientOpts]}]),
+
+ ssl_test_lib:check_server_alert(Server, Client, insufficient_security).
+
+%%-------------------------------------------------------------------
+%% Note that these test only test that the options are valid to set. As application data
+%% is a stream you can not test that the send acctually splits it up as when it arrives
+%% again at the user layer it may be concatenated. But COVER can show that the split up
+%% code has been run.
+
+rizzo_disabled() ->
+ [{doc, "Test original beast mitigation disable option for SSL 3.0 and TLS 1.0"}].
+
+rizzo_disabled(Config) ->
+ ClientOpts = [{beast_mitigation, disabled} | ssl_test_lib:ssl_options(client_rsa_opts, Config)],
+ ServerOpts = [{beast_mitigation, disabled} | ssl_test_lib:ssl_options(server_rsa_opts, Config)],
+
+ ssl_test_lib:basic_test(ClientOpts, ServerOpts, Config).
+%%-------------------------------------------------------------------
+rizzo_zero_n() ->
+ [{doc, "Test zero_n beast mitigation option (same affect as original disable option) for SSL 3.0 and TLS 1.0"}].
+
+rizzo_zero_n(Config) ->
+ ClientOpts = [{beast_mitigation, zero_n} | ssl_test_lib:ssl_options(client_rsa_opts, Config)],
+ ServerOpts = [{beast_mitigation, zero_n} | ssl_test_lib:ssl_options(server_rsa_opts, Config)],
+
+ ssl_test_lib:basic_test(ClientOpts, ServerOpts, Config).
+%%-------------------------------------------------------------------
+rizzo_one_n_minus_one () ->
+ [{doc, "Test beast_mitigation option one_n_minus_one (same affect as default) for SSL 3.0 and TLS 1.0"}].
+
+rizzo_one_n_minus_one (Config) ->
+ ClientOpts = [{beast_mitigation, one_n_minus_one } | ssl_test_lib:ssl_options(client_rsa_opts, Config)],
+ ServerOpts = [{beast_mitigation, one_n_minus_one} | ssl_test_lib:ssl_options(server_rsa_opts, Config)],
+
+ ssl_test_lib:basic_test(ClientOpts, ServerOpts, Config).
+
+supported_groups() ->
+ [{doc,"Test the supported_groups option in TLS 1.3."}].
+
+supported_groups(Config) when is_list(Config) ->
+ ClientOpts = ssl_test_lib:ssl_options(client_rsa_opts, Config),
+ ServerOpts = ssl_test_lib:ssl_options(server_rsa_opts, Config),
+
+ {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
+
+ Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0},
+ {from, self()},
+ {mfa, {ssl_test_lib, send_recv_result_active, []}},
+ {options, [{supported_groups, [x448, x25519]} | ServerOpts]}]),
+ Port = ssl_test_lib:inet_port(Server),
+ Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port},
+ {host, Hostname},
+ {from, self()},
+ {mfa, {ssl_test_lib, send_recv_result_active, []}},
+ {options, [{supported_groups,[x448]} | ClientOpts]}]),
+
+ ssl_test_lib:check_result(Server, ok, Client, ok),
+
+ ssl_test_lib:close(Server),
+ ssl_test_lib:close(Client).
+
+%%--------------------------------------------------------------------
+honor_client_cipher_order_tls13() ->
+ [{doc,"Test API honor server cipher order in TLS 1.3."}].
+honor_client_cipher_order_tls13(Config) when is_list(Config) ->
+ ClientCiphers = [#{key_exchange => any,
+ cipher => aes_256_gcm,
+ mac => aead,
+ prf => sha384},
+ #{key_exchange => any,
+ cipher => aes_128_gcm,
+ mac => aead,
+ prf => sha256}],
+ ServerCiphers = [#{key_exchange => any,
+ cipher => aes_128_gcm,
+ mac => aead,
+ prf => sha256},
+ #{key_exchange => any,
+ cipher => aes_256_gcm,
+ mac => aead,
+ prf => sha384}],
+ honor_cipher_order(Config, false, ServerCiphers, ClientCiphers, #{key_exchange => any,
+ cipher => aes_256_gcm,
+ mac => aead,
+ prf => sha384}).
+
+%%--------------------------------------------------------------------
+honor_server_cipher_order_tls13() ->
+ [{doc,"Test API honor server cipher order in TLS 1.3."}].
+honor_server_cipher_order_tls13(Config) when is_list(Config) ->
+ ClientCiphers = [#{key_exchange => any,
+ cipher => aes_256_gcm,
+ mac => aead,
+ prf => sha384},
+ #{key_exchange => any,
+ cipher => aes_128_gcm,
+ mac => aead,
+ prf => sha256}],
+ ServerCiphers = [#{key_exchange => any,
+ cipher => aes_128_gcm,
+ mac => aead,
+ prf => sha256},
+ #{key_exchange => any,
+ cipher => aes_256_gcm,
+ mac => aead,
+ prf => sha384}],
+ honor_cipher_order(Config, true, ServerCiphers, ClientCiphers, #{key_exchange => any,
+ cipher => aes_128_gcm,
+ mac => aead,
+ prf => sha256}).
+
+
+%%--------------------------------------------------------------------
+%% Internal functions ------------------------------------------------
+%%--------------------------------------------------------------------
+
+peercert_result(Socket) ->
+ ssl:peercert(Socket).
+
+connection_information_result(Socket) ->
+ {ok, Info = [_ | _]} = ssl:connection_information(Socket),
+ case length(Info) > 3 of
+ true ->
+ %% Atleast one ssl_option() is set
+ ct:log("Info ~p", [Info]),
+ ok;
+ false ->
+ ct:fail(no_ssl_options_returned)
+ end.
+secret_connection_info_result(Socket) ->
+ {ok, [{protocol, Protocol}]} = ssl:connection_information(Socket, [protocol]),
+ {ok, ConnInfo} = ssl:connection_information(Socket, [client_random, server_random, master_secret]),
+ check_connection_info(Protocol, ConnInfo).
+
+
+%% In TLS 1.3 the master_secret field is used to store multiple secrets from the key schedule and it is a tuple.
+%% client_random and server_random are not used in the TLS 1.3 key schedule.
+check_connection_info('tlsv1.3', [{client_random, ClientRand}, {master_secret, {master_secret, MasterSecret}}]) ->
+ is_binary(ClientRand) andalso is_binary(MasterSecret);
+check_connection_info('tlsv1.3', [{server_random, ServerRand}, {master_secret, {master_secret, MasterSecret}}]) ->
+ is_binary(ServerRand) andalso is_binary(MasterSecret);
+check_connection_info(_, [{client_random, ClientRand}, {server_random, ServerRand}, {master_secret, MasterSecret}]) ->
+ is_binary(ClientRand) andalso is_binary(ServerRand) andalso is_binary(MasterSecret);
+check_connection_info(_, _) ->
+ false.
+
+
+prf_create_plan(TlsVersions, PRFs, Results) ->
+ lists:foldl(fun(Ver, Acc) ->
+ A = prf_ciphers_and_expected(Ver, PRFs, Results),
+ [A|Acc]
+ end, [], TlsVersions).
+
+prf_ciphers_and_expected(TlsVer, PRFs, Results) ->
+ case TlsVer of
+ TlsVer when TlsVer == sslv3 orelse TlsVer == tlsv1
+ orelse TlsVer == 'tlsv1.1' orelse TlsVer == 'dtlsv1' ->
+ Ciphers = ssl:cipher_suites(),
+ {_, Expected} = lists:keyfind(md5sha, 1, Results),
+ [[{tls_ver, TlsVer}, {ciphers, Ciphers}, {expected, Expected}, {prf, md5sha}]];
+ TlsVer when TlsVer == 'tlsv1.2' orelse TlsVer == 'dtlsv1.2'->
+ lists:foldl(
+ fun(PRF, Acc) ->
+ Ciphers = prf_get_ciphers(TlsVer, PRF),
+ case Ciphers of
+ [] ->
+ ct:log("No ciphers for PRF algorithm ~p. Skipping.", [PRF]),
+ Acc;
+ Ciphers ->
+ {_, Expected} = lists:keyfind(PRF, 1, Results),
+ [[{tls_ver, TlsVer}, {ciphers, Ciphers}, {expected, Expected},
+ {prf, PRF}] | Acc]
+ end
+ end, [], PRFs)
+ end.
+
+prf_get_ciphers(_, PRF) ->
+ lists:filter(
+ fun(C) when tuple_size(C) == 4 andalso
+ element(4, C) == PRF ->
+ true;
+ (_) ->
+ false
+ end,
+ ssl:cipher_suites()).
+
+prf_run_test(_, TlsVer, [], _, Prf) ->
+ ct:fail({error, cipher_list_empty, TlsVer, Prf});
+prf_run_test(Config, TlsVer, Ciphers, Expected, Prf) ->
+ {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
+ BaseOpts = [{active, true}, {versions, [TlsVer]}, {ciphers, Ciphers}, {protocol, tls_or_dtls(TlsVer)}],
+ ServerOpts = BaseOpts ++ proplists:get_value(server_opts, Config),
+ ClientOpts = BaseOpts ++ proplists:get_value(client_opts, Config),
+ Server = ssl_test_lib:start_server(
+ [{node, ServerNode}, {port, 0}, {from, self()},
+ {mfa, {?MODULE, prf_verify_value, [TlsVer, Expected, Prf]}},
+ {options, ServerOpts}]),
+ Port = ssl_test_lib:inet_port(Server),
+ Client = ssl_test_lib:start_client(
+ [{node, ClientNode}, {port, Port},
+ {host, Hostname}, {from, self()},
+ {mfa, {?MODULE, prf_verify_value, [TlsVer, Expected, Prf]}},
+ {options, ClientOpts}]),
+ ssl_test_lib:check_result(Server, ok, Client, ok),
+ ssl_test_lib:close(Server),
+ ssl_test_lib:close(Client).
+
+prf_verify_value(Socket, TlsVer, Expected, Algo) ->
+ Ret = ssl:prf(Socket, <<>>, <<>>, [<<>>], 16),
+ case TlsVer of
+ sslv3 ->
+ case Ret of
+ {error, undefined} -> ok;
+ _ ->
+ {error, {expected, {error, undefined},
+ got, Ret, tls_ver, TlsVer, prf_algorithm, Algo}}
+ end;
+ _ ->
+ case Ret of
+ {ok, Expected} -> ok;
+ {ok, Val} -> {error, {expected, Expected, got, Val, tls_ver, TlsVer,
+ prf_algorithm, Algo}}
+ end
+ end.
+
+tls_or_dtls('dtlsv1') ->
+ dtls;
+tls_or_dtls('dtlsv1.2') ->
+ dtls;
+tls_or_dtls(_) ->
+ tls.
+
+active_n_common(S, N) ->
+ ok = ssl:setopts(S, [{active,-N}]),
+ receive
+ {ssl_passive, S} -> ok
+ after
+ 1000 ->
+ error({error,ssl_passive_failure})
+ end,
+ [{active,false}] = ok(ssl:getopts(S, [active])),
+ ok = ssl:setopts(S, [{active,0}]),
+ receive
+ {ssl_passive, S} -> ok
+ after
+ 1000 ->
+ error({error,ssl_passive_failure})
+ end,
+ ok = ssl:setopts(S, [{active,32767}]),
+ {error,{options,_}} = ssl:setopts(S, [{active,1}]),
+ {error,{options,_}} = ssl:setopts(S, [{active,-32769}]),
+ ok = ssl:setopts(S, [{active,-32768}]),
+ receive
+ {ssl_passive, S} -> ok
+ after
+ 1000 ->
+ error({error,ssl_passive_failure})
+ end,
+ [{active,false}] = ok(ssl:getopts(S, [active])),
+ ok = ssl:setopts(S, [{active,N}]),
+ ok = ssl:setopts(S, [{active,true}]),
+ [{active,true}] = ok(ssl:getopts(S, [active])),
+ receive
+ _ -> error({error,active_n})
+ after
+ 0 ->
+ ok
+ end,
+ ok = ssl:setopts(S, [{active,N}]),
+ ok = ssl:setopts(S, [{active,once}]),
+ [{active,once}] = ok(ssl:getopts(S, [active])),
+ receive
+ _ -> error({error,active_n})
+ after
+ 0 ->
+ ok
+ end,
+ {error,{options,_}} = ssl:setopts(S, [{active,32768}]),
+ ok = ssl:setopts(S, [{active,false}]),
+ [{active,false}] = ok(ssl:getopts(S, [active])),
+ ok.
+
+ok({ok,V}) -> V.
+
+repeat(N, Fun) ->
+ repeat(N, N, Fun).
+
+repeat(N, T, Fun) when is_integer(N), N > 0 ->
+ Fun(T-N),
+ repeat(N-1, T, Fun);
+repeat(_, _, _) ->
+ ok.
+
+try_recv_active(Socket) ->
+ ssl:send(Socket, "Hello world"),
+ {error, einval} = ssl:recv(Socket, 11),
+ ok.
+try_recv_active_once(Socket) ->
+ {error, einval} = ssl:recv(Socket, 11),
+ ok.
+
+controlling_process_result(Socket, Pid, Msg) ->
+ ok = ssl:controlling_process(Socket, Pid),
+ %% Make sure other side has evaluated controlling_process
+ %% before message is sent
+ ct:sleep(?SLEEP),
+ ssl:send(Socket, Msg),
+ no_result_msg.
+
+controller_dies_result(_Socket, _Pid, _Msg) ->
+ receive Result -> Result end.
+get_close(Pid, Where) ->
+ receive
+ {'EXIT', Pid, _Reason} ->
+ receive
+ {_, {ssl_closed, Socket}} ->
+ ct:log("Socket closed ~p~n",[Socket]);
+ Unexpected ->
+ ct:log("Unexpected ~p~n",[Unexpected]),
+ ct:fail({line, ?LINE-1})
+ after 5000 ->
+ ct:fail({timeout, {line, ?LINE, Where}})
+ end;
+ Unexpected ->
+ ct:log("Unexpected ~p~n",[Unexpected]),
+ ct:fail({line, ?LINE-1})
+ after 5000 ->
+ ct:fail({timeout, {line, ?LINE, Where}})
+ end.
+
+ssl_active_recv(N) ->
+ ssl_active_recv(N, []).
+
+ssl_active_recv(0, Acc) ->
+ Acc;
+ssl_active_recv(N, Acc) ->
+ receive
+ {ssl, _, Bytes} ->
+ ssl_active_recv(N-length(Bytes), Acc ++ Bytes)
+ end.
+
+send_recv_result_timeout_client(Socket) ->
+ {error, timeout} = ssl:recv(Socket, 11, 500),
+ {error, timeout} = ssl:recv(Socket, 11, 0),
+ ssl:send(Socket, "Hello world"),
+ receive
+ Msg ->
+ io:format("Msg ~p~n",[Msg])
+ after 500 ->
+ ok
+ end,
+ {ok, "Hello world"} = ssl:recv(Socket, 11, 500),
+ ok.
+send_recv_result_timeout_server(Socket) ->
+ ssl:send(Socket, "Hello"),
+ {ok, "Hello world"} = ssl:recv(Socket, 11),
+ ssl:send(Socket, " world"),
+ ok.
+
+do_recv_close(Socket) ->
+ {error, closed} = ssl:recv(Socket, 11),
+ receive
+ {_,{error,closed}} ->
+ error_extra_close_sent_to_user_process
+ after 500 ->
+ ok
+ end.
+
+tls_close(Socket) ->
+ ok = ssl_test_lib:send_recv_result(Socket),
+ case ssl:close(Socket, 5000) of
+ ok ->
+ ok;
+ {error, closed} ->
+ ok;
+ Other ->
+ ct:fail(Other)
+ end.
+
+run_error_server_close([Pid | Opts]) ->
+ {ok, Listen} = ssl:listen(0, Opts),
+ {ok,{_, Port}} = ssl:sockname(Listen),
+ Pid ! {self(), Port},
+ {ok, Socket} = ssl:transport_accept(Listen),
+ Pid ! ssl:close(Socket).
+
+run_error_server([ Pid | Opts]) ->
+ {ok, Listen} = ssl:listen(0, Opts),
+ {ok,{_, Port}} = ssl:sockname(Listen),
+ Pid ! {self(), Port},
+ {ok, Socket} = ssl:transport_accept(Listen),
+ Pid ! ssl:controlling_process(Socket, self()).
+
+run_client_error([Port, Opts]) ->
+ ssl:connect("localhost", Port, Opts).
+
+honor_cipher_order(Config, Honor, ServerCiphers, ClientCiphers, Expected) ->
+ ClientOpts = ssl_test_lib:ssl_options(client_rsa_opts, Config),
+ ServerOpts = ssl_test_lib:ssl_options(server_rsa_opts, Config),
+
+ {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
+
+ Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0},
+ {from, self()},
+ {mfa, {?MODULE, connection_info_result, []}},
+ {options, [{ciphers, ServerCiphers}, {honor_cipher_order, Honor}
+ | ServerOpts]}]),
+ Port = ssl_test_lib:inet_port(Server),
+ Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port},
+ {host, Hostname},
+ {from, self()},
+ {mfa, {?MODULE, connection_info_result, []}},
+ {options, [{ciphers, ClientCiphers}, {honor_cipher_order, Honor}
+ | ClientOpts]}]),
+
+ Version = ssl_test_lib:protocol_version(Config),
+
+ ServerMsg = ClientMsg = {ok, {Version, Expected}},
+
+ ssl_test_lib:check_result(Server, ServerMsg, Client, ClientMsg),
+
+ ssl_test_lib:close(Server),
+ ssl_test_lib:close(Client).
+
+connection_info_result(Socket) ->
+ {ok, Info} = ssl:connection_information(Socket, [protocol, selected_cipher_suite]),
+ {ok, {proplists:get_value(protocol, Info), proplists:get_value(selected_cipher_suite, Info)}}.
+
+der_input_opts(Opts) ->
+ Certfile = proplists:get_value(certfile, Opts),
+ CaCertsfile = proplists:get_value(cacertfile, Opts),
+ Keyfile = proplists:get_value(keyfile, Opts),
+ Dhfile = proplists:get_value(dhfile, Opts),
+ [{_, Cert, _}] = ssl_test_lib:pem_to_der(Certfile),
+ [{Asn1Type, Key, _}] = ssl_test_lib:pem_to_der(Keyfile),
+ [{_, DHParams, _}] = ssl_test_lib:pem_to_der(Dhfile),
+ CaCerts =
+ lists:map(fun(Entry) ->
+ {_, CaCert, _} = Entry,
+ CaCert
+ end, ssl_test_lib:pem_to_der(CaCertsfile)),
+ {Cert, {Asn1Type, Key}, CaCerts, DHParams}.
diff --git a/lib/ssl/test/ssl_basic_SUITE_data/dHParam.pem b/lib/ssl/test/ssl_api_SUITE_data/dHParam.pem
index feb581da30..feb581da30 100644
--- a/lib/ssl/test/ssl_basic_SUITE_data/dHParam.pem
+++ b/lib/ssl/test/ssl_api_SUITE_data/dHParam.pem
diff --git a/lib/ssl/test/ssl_app_env_SUITE.erl b/lib/ssl/test/ssl_app_env_SUITE.erl
new file mode 100644
index 0000000000..27fbcb8e47
--- /dev/null
+++ b/lib/ssl/test/ssl_app_env_SUITE.erl
@@ -0,0 +1,171 @@
+%%
+%% %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_app_env_SUITE).
+
+%% Note: This directive should only be used in test suites.
+-compile(export_all).
+-include_lib("common_test/include/ct.hrl").
+-include_lib("ssl/src/ssl_api.hrl").
+
+-define(SLEEP, 500).
+%%--------------------------------------------------------------------
+%% Common Test interface functions -----------------------------------
+%%--------------------------------------------------------------------
+
+all() ->
+ [
+ {group, 'tlsv1.3'},
+ {group, 'tlsv1.2'},
+ {group, 'tlsv1.1'},
+ {group, 'tlsv1'},
+ {group, 'sslv3'},
+ {group, 'dtlsv1.2'},
+ {group, 'dtlsv1'}
+ ].
+
+groups() ->
+ [
+ {'tlsv1.3', [], tests()},
+ {'tlsv1.2', [], tests()},
+ {'tlsv1.1', [], tests()},
+ {'tlsv1', [], tests()},
+ {'sslv3', [], tests()},
+ {'dtlsv1.2', [], tests()},
+ {'dtlsv1', [], tests()}
+ ].
+
+tests() ->
+ [
+ internal_active_1,
+ protocol_versions,
+ empty_protocol_versions
+ ].
+
+
+init_per_suite(Config0) ->
+ catch crypto:stop(),
+ try crypto:start() of
+ ok ->
+ ssl_test_lib:clean_start(),
+ ssl_test_lib:make_rsa_cert(Config0)
+ catch _:_ ->
+ {skip, "Crypto did not start"}
+ end.
+
+end_per_suite(_Config) ->
+ ssl:stop(),
+ application:unload(ssl),
+ application:stop(crypto).
+
+
+init_per_group(GroupName, Config) ->
+ case ssl_test_lib:is_tls_version(GroupName) of
+ true ->
+ case ssl_test_lib:sufficient_crypto_support(GroupName) of
+ true ->
+ [{client_type, erlang},
+ {server_type, erlang} | ssl_test_lib:init_tls_version(GroupName, Config)];
+ false ->
+ {skip, "Missing crypto support"}
+ end;
+ _ ->
+ ssl:start(),
+ Config
+ 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(internal_active_1, Config) ->
+ ssl:stop(),
+ application:load(ssl),
+ application:set_env(ssl, internal_active_n, 1),
+ ssl:start(),
+ ct:timetrap({seconds, 5}),
+ Config;
+init_per_testcase(protocol_versions, Config) ->
+ Version = ssl_test_lib:protocol_version(Config),
+ case atom_to_list(Version) of
+ "d" ++ _ ->
+ ssl:stop(),
+ application:load(ssl),
+ application:set_env(ssl, dtls_protocol_version, [Version]),
+ ssl:start();
+ _ ->
+ ssl:stop(),
+ application:load(ssl),
+ application:set_env(ssl, protocol_version, [Version]),
+ ssl:start()
+ end,
+ ct:timetrap({seconds, 5}),
+ Config;
+init_per_testcase(empty_protocol_versions, Config) ->
+ ssl:stop(),
+ application:load(ssl),
+ ssl_test_lib:clean_env(),
+ application:set_env(ssl, protocol_version, []),
+ application:set_env(ssl, dtls_protocol_version, []),
+ ssl:start(),
+ ct:timetrap({seconds, 5}),
+ Config;
+init_per_testcase(_TestCase, Config) ->
+ ct:timetrap({seconds, 5}),
+ Config.
+
+end_per_testcase(_, _Config) ->
+ ssl_test_lib:clean_start().
+
+%%--------------------------------------------------------------------
+%% Test Cases --------------------------------------------------------
+%%--------------------------------------------------------------------
+%%--------------------------------------------------------------------
+internal_active_1() ->
+ [{doc,"Test internal active 1 (behave as internal active once)"}].
+
+internal_active_1(Config) when is_list(Config) ->
+ ClientOpts = ssl_test_lib:ssl_options(client_rsa_opts, Config),
+ ServerOpts = ssl_test_lib:ssl_options(server_rsa_opts, Config),
+ ssl_test_lib:basic_test(ClientOpts, ServerOpts, Config).
+
+%%--------------------------------------------------------------------
+protocol_versions() ->
+ [{doc,"Test to set a list of protocol versions in app environment."}].
+
+protocol_versions(Config) when is_list(Config) ->
+ ClientOpts = ssl_test_lib:ssl_options(client_rsa_opts, Config),
+ ServerOpts = ssl_test_lib:ssl_options(server_rsa_opts, Config),
+ ssl_test_lib:basic_test(ClientOpts, ServerOpts, Config).
+
+%%--------------------------------------------------------------------
+empty_protocol_versions() ->
+ [{doc,"Test to set an empty list of protocol versions in app environment."}].
+
+empty_protocol_versions(Config) when is_list(Config) ->
+ ClientOpts = ssl_test_lib:ssl_options(client_rsa_opts, Config),
+ ServerOpts = ssl_test_lib:ssl_options(server_rsa_opts, Config),
+ ssl_test_lib:basic_test(ClientOpts, ServerOpts, Config).
+
diff --git a/lib/ssl/test/ssl_basic_SUITE.erl b/lib/ssl/test/ssl_basic_SUITE.erl
index 86a0aaf67b..355cd31070 100644
--- a/lib/ssl/test/ssl_basic_SUITE.erl
+++ b/lib/ssl/test/ssl_basic_SUITE.erl
@@ -26,15 +26,8 @@
-compile(export_all).
-include_lib("common_test/include/ct.hrl").
--include_lib("public_key/include/public_key.hrl").
+-include_lib("ssl/src/ssl_api.hrl").
--include("ssl_api.hrl").
--include("ssl_cipher.hrl").
--include("ssl_internal.hrl").
--include("ssl_alert.hrl").
--include("ssl_internal.hrl").
--include("tls_record.hrl").
--include("tls_handshake.hrl").
-define(TIMEOUT, 20000).
-define(EXPIRE, 10).
@@ -49,243 +42,35 @@
all() ->
[
{group, basic},
- {group, basic_tls},
- {group, options},
- {group, options_tls},
- {group, session},
- {group, 'dtlsv1.2'},
- {group, 'dtlsv1'},
- {group, 'tlsv1.3'},
- {group, 'tlsv1.2'},
- {group, 'tlsv1.1'},
- {group, 'tlsv1'},
- {group, 'sslv3'}
+ {group, options}
].
groups() ->
[{basic, [], basic_tests()},
- {basic_tls, [], basic_tests_tls()},
- {options, [], options_tests()},
- {options_tls, [], options_tests_tls()},
- {'dtlsv1.2', [], all_versions_groups()},
- {'dtlsv1', [], all_versions_groups()},
- {'tlsv1.3', [], tls13_test_group()},
- {'tlsv1.2', [], all_versions_groups() ++ tls_versions_groups() ++ [conf_signature_algs, no_common_signature_algs]},
- {'tlsv1.1', [], all_versions_groups() ++ tls_versions_groups()},
- {'tlsv1', [], all_versions_groups() ++ tls_versions_groups() ++ rizzo_tests()},
- {'sslv3', [], all_versions_groups() ++ tls_versions_groups() ++ rizzo_tests() ++ [tls_ciphersuite_vs_version]},
- {api,[], api_tests()},
- {api_tls,[], api_tests_tls()},
- {session, [], session_tests()},
- {renegotiate, [], renegotiate_tests()},
- {ciphers, [], cipher_tests()},
- {error_handling_tests, [], error_handling_tests()},
- {error_handling_tests_tls, [], error_handling_tests_tls()}
+ {options, [], options_tests()}
].
-tls_versions_groups ()->
- [
- {group, api_tls},
- {group, error_handling_tests_tls}].
-
-all_versions_groups ()->
- [{group, api},
- {group, renegotiate},
- {group, ciphers},
- {group, error_handling_tests}].
-
-
basic_tests() ->
[app,
- appup,
- alerts,
- alert_details,
- alert_details_not_too_big,
+ appup,
version_option,
connect_twice,
connect_dist,
- clear_pem_cache,
defaults,
fallback,
cipher_format,
- suite_to_str
- ].
-
-basic_tests_tls() ->
- [tls_send_close
- ].
-
-options_tests() ->
- [der_input,
- ssl_options_not_proplist,
- raw_ssl_option,
- invalid_inet_get_option,
- invalid_inet_get_option_not_list,
- invalid_inet_get_option_improper_list,
- invalid_inet_set_option,
- invalid_inet_set_option_not_list,
- invalid_inet_set_option_improper_list,
- dh_params,
- invalid_certfile,
- invalid_cacertfile,
- invalid_keyfile,
- invalid_options,
- protocol_versions,
- empty_protocol_versions,
- ipv6,
- reuseaddr,
- honor_server_cipher_order,
- honor_client_cipher_order,
- unordered_protocol_versions_server,
- unordered_protocol_versions_client,
- max_handshake_size
-].
-
-options_tests_tls() ->
- [tls_misc_ssl_options,
- tls_tcp_reuseaddr].
-
-api_tests() ->
- [secret_connection_info,
- connection_information,
- peercert,
- peercert_with_client_cert,
- versions,
+ tls_versions_option,
eccs,
- controlling_process,
- getstat,
- close_with_timeout,
- hibernate,
- hibernate_right_away,
- listen_socket,
- ssl_recv_timeout,
- server_name_indication_option,
- accept_pool,
- prf,
- socket_options,
- active_n,
- internal_active_1,
cipher_suites,
- handshake_continue,
- handshake_continue_timeout,
- hello_client_cancel,
- hello_server_cancel
- ].
-
-api_tests_tls() ->
- [tls_versions_option,
- tls_upgrade,
- tls_upgrade_with_timeout,
- tls_ssl_accept_timeout,
- tls_downgrade,
- tls_shutdown,
- tls_shutdown_write,
- tls_shutdown_both,
- tls_shutdown_error,
- peername,
- sockname,
- tls_socket_options,
- new_options_in_accept
- ].
-
-session_tests() ->
- [reuse_session,
- reuse_session_expired,
- server_does_not_want_to_reuse_session,
- no_reuses_session_server_restart_new_cert,
- no_reuses_session_server_restart_new_cert_file].
-
-renegotiate_tests() ->
- [client_renegotiate,
- server_renegotiate,
- client_secure_renegotiate,
- client_secure_renegotiate_fallback,
- client_renegotiate_reused_session,
- server_renegotiate_reused_session,
- client_no_wrap_sequence_number,
- server_no_wrap_sequence_number,
- renegotiate_dos_mitigate_active,
- renegotiate_dos_mitigate_passive,
- renegotiate_dos_mitigate_absolute].
-
-cipher_tests() ->
- [old_cipher_suites,
- cipher_suites_mix,
- default_reject_anonymous].
-
-error_handling_tests()->
- [close_transport_accept,
- recv_active,
- recv_active_once,
- recv_active_n,
- recv_error_handling,
- call_in_error_state,
- close_in_error_state,
- abuse_transport_accept_socket,
- controlling_process_transport_accept_socket
- ].
-
-error_handling_tests_tls()->
- [controller_dies,
- tls_client_closes_socket,
- tls_closed_in_active_once,
- tls_tcp_error_propagation_in_active_mode,
- tls_tcp_connect,
- tls_tcp_connect_big,
- tls_dont_crash_on_handshake_garbage
+ old_cipher_suites,
+ cipher_suites_mix
].
-rizzo_tests() ->
- [rizzo,
- no_rizzo_rc4,
- rizzo_one_n_minus_one,
- rizzo_zero_n,
- rizzo_disabled].
-
-%% For testing TLS 1.3 features and possible regressions
-tls13_test_group() ->
- [handshake_continue_tls13_client,
- tls13_enable_client_side,
- tls13_enable_server_side,
- tls_record_1_3_encode_decode,
- tls13_finished_verify_data,
- tls13_1_RTT_handshake,
- tls12_ssl_server_tls13_ssl_client,
- tls13_basic_ssl_server_openssl_client,
- tls13_basic_ssl_server_ssl_client,
- tls13_basic_openssl_server_ssl_client,
- tls13_custom_groups_ssl_server_openssl_client,
- tls13_custom_groups_ssl_server_ssl_client,
- tls13_hello_retry_request_ssl_server_openssl_client,
- tls13_hello_retry_request_ssl_server_ssl_client,
- tls13_client_auth_empty_cert_alert_ssl_server_openssl_client,
- tls13_client_auth_empty_cert_alert_ssl_server_ssl_client,
- tls13_client_auth_empty_cert_ssl_server_openssl_client,
- tls13_client_auth_empty_cert_ssl_server_ssl_client,
- tls13_client_auth_ssl_server_openssl_client,
- tls13_client_auth_ssl_server_ssl_client,
- tls13_hrr_client_auth_empty_cert_alert_ssl_server_openssl_client,
- tls13_hrr_client_auth_empty_cert_alert_ssl_server_ssl_client,
- tls13_hrr_client_auth_empty_cert_ssl_server_openssl_client,
- tls13_hrr_client_auth_empty_cert_ssl_server_ssl_client,
- tls13_hrr_client_auth_ssl_server_openssl_client,
- tls13_hrr_client_auth_ssl_server_ssl_client,
- tls13_unsupported_sign_algo_client_auth_ssl_server_openssl_client,
- tls13_unsupported_sign_algo_client_auth_ssl_server_ssl_client,
- tls13_unsupported_sign_algo_cert_client_auth_ssl_server_openssl_client,
- tls13_unsupported_sign_algo_cert_client_auth_ssl_server_ssl_client,
- tls13_connection_information,
- tls13_ssl_server_with_alpn_ssl_client,
- tls13_ssl_server_with_alpn_ssl_client_empty_alpn,
- tls13_ssl_server_with_alpn_ssl_client_bad_alpn,
- tls13_ssl_server_with_alpn_ssl_client_alpn,
- tls13_ecdsa_ssl_server_openssl_client,
- tls13_ecdsa_ssl_server_ssl_client,
- tls13_ecdsa_openssl_server_ssl_client,
- tls13_ecdsa_client_auth_ssl_server_ssl_client
- ].
+options_tests() ->
+ [
+ unordered_protocol_versions_server,
+ unordered_protocol_versions_client].
-%%--------------------------------------------------------------------
init_per_suite(Config0) ->
catch crypto:stop(),
try crypto:start() of
@@ -308,229 +93,6 @@ end_per_suite(_Config) ->
application:stop(crypto).
%%--------------------------------------------------------------------
-
-init_per_group(GroupName, Config) when GroupName == basic_tls;
- GroupName == options_tls;
- GroupName == options;
- GroupName == basic;
- GroupName == session;
- GroupName == error_handling_tests_tls ->
- ssl_test_lib:clean_tls_version(Config);
-%% Do not automatically configure TLS version for the 'tlsv1.3' group
-init_per_group('tlsv1.3' = GroupName, Config) ->
- case ssl_test_lib:sufficient_crypto_support(GroupName) of
- true ->
- ssl:start(),
- Config;
- false ->
- {skip, "Missing crypto support"}
- end;
-init_per_group(GroupName, Config) ->
- ssl_test_lib:clean_tls_version(Config),
- case ssl_test_lib:is_tls_version(GroupName) andalso ssl_test_lib:sufficient_crypto_support(GroupName) of
- true ->
- ssl_test_lib:init_tls_version(GroupName, Config);
- _ ->
- case ssl_test_lib:sufficient_crypto_support(GroupName) of
- true ->
- ssl:start(),
- Config;
- false ->
- {skip, "Missing crypto support"}
- end
- 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(Case, Config) when Case == unordered_protocol_versions_client;
- Case == unordered_protocol_versions_server->
- case proplists:get_value(supported, ssl:versions()) of
- ['tlsv1.2' | _] ->
- ct:timetrap({seconds, 5}),
- Config;
- _ ->
- {skip, "TLS 1.2 need but not supported on this platform"}
- end;
-
-init_per_testcase(protocol_versions, Config) ->
- ssl:stop(),
- application:load(ssl),
- %% For backwards compatibility sslv2 should be filtered out.
- application:set_env(ssl, protocol_version, [sslv2, sslv3, tlsv1]),
- ssl:start(),
- ct:timetrap({seconds, 5}),
- Config;
-
-init_per_testcase(reuse_session_expired, Config) ->
- ssl:stop(),
- application:load(ssl),
- ssl_test_lib:clean_env(),
- application:set_env(ssl, session_lifetime, ?EXPIRE),
- application:set_env(ssl, session_delay_cleanup_time, 500),
- ssl:start(),
- ct:timetrap({seconds, 30}),
- Config;
-
-init_per_testcase(empty_protocol_versions, Config) ->
- ssl:stop(),
- application:load(ssl),
- ssl_test_lib:clean_env(),
- application:set_env(ssl, protocol_version, []),
- ssl:start(),
- ct:timetrap({seconds, 5}),
- Config;
-
-init_per_testcase(fallback, Config) ->
- case tls_record:highest_protocol_version([]) of
- {3, N} when N > 1 ->
- ct:timetrap({seconds, 5}),
- Config;
- _ ->
- {skip, "Not relevant if highest supported version is less than 3.2"}
- end;
-
-init_per_testcase(TestCase, Config) when TestCase == client_renegotiate;
- TestCase == server_renegotiate;
- TestCase == client_secure_renegotiate;
- TestCase == client_renegotiate_reused_session;
- TestCase == server_renegotiate_reused_session;
- TestCase == client_no_wrap_sequence_number;
- TestCase == server_no_wrap_sequence_number;
- TestCase == renegotiate_dos_mitigate_active;
- TestCase == renegotiate_dos_mitigate_passive;
- TestCase == renegotiate_dos_mitigate_absolute ->
- ssl_test_lib:ct_log_supported_protocol_versions(Config),
- ct:timetrap({seconds, ?SEC_RENEGOTIATION_TIMEOUT + 5}),
- Config;
-
-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}),
- Config;
-
-init_per_testcase(version_option, Config) ->
- ssl_test_lib:ct_log_supported_protocol_versions(Config),
- ct:timetrap({seconds, 10}),
- Config;
-
-init_per_testcase(reuse_session, Config) ->
- ssl_test_lib:ct_log_supported_protocol_versions(Config),
- ct:timetrap({seconds, 10}),
- Config;
-
-init_per_testcase(rizzo, Config) ->
- ssl_test_lib:ct_log_supported_protocol_versions(Config),
- ct:timetrap({seconds, 60}),
- Config;
-
-init_per_testcase(no_rizzo_rc4, Config) ->
- ssl_test_lib:ct_log_supported_protocol_versions(Config),
- ct:timetrap({seconds, 60}),
- Config;
-
-init_per_testcase(rizzo_one_n_minus_one, Config) ->
- ct:log("TLS/SSL version ~p~n ", [tls_record:supported_protocol_versions()]),
- ct:timetrap({seconds, 60}),
- rizzo_add_mitigation_option(one_n_minus_one, Config);
-
-init_per_testcase(rizzo_zero_n, Config) ->
- ct:log("TLS/SSL version ~p~n ", [tls_record:supported_protocol_versions()]),
- ct:timetrap({seconds, 60}),
- rizzo_add_mitigation_option(zero_n, Config);
-
-init_per_testcase(rizzo_disabled, Config) ->
- ct:log("TLS/SSL version ~p~n ", [tls_record:supported_protocol_versions()]),
- ct:timetrap({seconds, 60}),
- rizzo_add_mitigation_option(disabled, Config);
-
-init_per_testcase(TestCase, Config) when TestCase == no_reuses_session_server_restart_new_cert_file;
- TestCase == no_reuses_session_server_restart_new_cert ->
- ct:log("TLS/SSL version ~p~n ", [tls_record:supported_protocol_versions()]),
- ct:timetrap({seconds, 15}),
- Config;
-
-init_per_testcase(prf, Config) ->
- ct:log("TLS/SSL version ~p~n ", [tls_record:supported_protocol_versions()]),
- ct:timetrap({seconds, 40}),
- case proplists:get_value(tc_group_path, Config) of
- [] -> Prop = [];
- [Prop] -> Prop
- end,
- case proplists:get_value(name, Prop) of
- undefined -> TlsVersions = [sslv3, tlsv1, 'tlsv1.1', 'tlsv1.2'];
- TlsVersion when is_atom(TlsVersion) ->
- TlsVersions = [TlsVersion]
- end,
- PRFS=[md5, sha, sha256, sha384, sha512],
- %All are the result of running tls_v1:prf(PrfAlgo, <<>>, <<>>, <<>>, 16)
- %with the specified PRF algorithm
- ExpectedPrfResults=
- [{md5, <<96,139,180,171,236,210,13,10,28,32,2,23,88,224,235,199>>},
- {sha, <<95,3,183,114,33,169,197,187,231,243,19,242,220,228,70,151>>},
- {sha256, <<166,249,145,171,43,95,158,232,6,60,17,90,183,180,0,155>>},
- {sha384, <<153,182,217,96,186,130,105,85,65,103,123,247,146,91,47,106>>},
- {sha512, <<145,8,98,38,243,96,42,94,163,33,53,49,241,4,127,28>>},
- %TLS 1.0 and 1.1 PRF:
- {md5sha, <<63,136,3,217,205,123,200,177,251,211,17,229,132,4,173,80>>}],
- TestPlan = prf_create_plan(TlsVersions, PRFS, ExpectedPrfResults),
- [{prf_test_plan, TestPlan} | Config];
-
-init_per_testcase(TestCase, Config) when TestCase == tls_ssl_accept_timeout;
- TestCase == tls_client_closes_socket;
- TestCase == tls_closed_in_active_once;
- TestCase == tls_downgrade ->
- ssl:stop(),
- ssl:start(),
- ssl_test_lib:ct_log_supported_protocol_versions(Config),
- ct:timetrap({seconds, 15}),
- Config;
-init_per_testcase(TestCase, Config) when TestCase == clear_pem_cache;
- TestCase == der_input;
- TestCase == defaults ->
- ssl_test_lib:ct_log_supported_protocol_versions(Config),
- %% White box test need clean start
- ssl:stop(),
- ssl:start(),
- ct:timetrap({seconds, 20}),
- Config;
-init_per_testcase(raw_ssl_option, Config) ->
- ct:timetrap({seconds, 5}),
- case os:type() of
- {unix,linux} ->
- Config;
- _ ->
- {skip, "Raw options are platform-specific"}
- end;
-
-init_per_testcase(accept_pool, Config) ->
- ct:timetrap({seconds, 5}),
- case proplists:get_value(protocol, Config) of
- dtls ->
- {skip, "Not yet supported on DTLS sockets"};
- _ ->
- ssl_test_lib:ct_log_supported_protocol_versions(Config),
- Config
- end;
-
-init_per_testcase(internal_active_1, Config) ->
- ssl:stop(),
- application:load(ssl),
- application:set_env(ssl, internal_active_n, 1),
- ssl:start(),
- ct:timetrap({seconds, 5}),
- Config;
-
-init_per_testcase(controller_dies, Config) ->
- ct:timetrap({seconds, 10}),
- Config;
init_per_testcase(eccs, Config) ->
case ssl:eccs() of
[] ->
@@ -545,23 +107,8 @@ init_per_testcase(_TestCase, Config) ->
ct:timetrap({seconds, 5}),
Config.
-end_per_testcase(reuse_session_expired, Config) ->
- application:unset_env(ssl, session_lifetime),
- application:unset_env(ssl, session_delay_cleanup_time),
- end_per_testcase(default_action, Config);
-
-end_per_testcase(internal_active_n, Config) ->
- application:unset_env(ssl, internal_active_n),
- end_per_testcase(default_action, Config);
-
-end_per_testcase(Case, Config) when Case == protocol_versions;
- Case == empty_protocol_versions->
- application:unset_env(ssl, protocol_versions),
- end_per_testcase(default_action, Config);
-
end_per_testcase(_TestCase, Config) ->
Config.
-
%%--------------------------------------------------------------------
%% Test Cases --------------------------------------------------------
%%--------------------------------------------------------------------
@@ -575,669 +122,76 @@ appup() ->
appup(Config) when is_list(Config) ->
ok = ?t:appup_test(ssl).
%%--------------------------------------------------------------------
-alerts() ->
- [{doc, "Test ssl_alert:alert_txt/1"}].
-alerts(Config) when is_list(Config) ->
- Descriptions = [?CLOSE_NOTIFY, ?UNEXPECTED_MESSAGE, ?BAD_RECORD_MAC,
- ?DECRYPTION_FAILED_RESERVED, ?RECORD_OVERFLOW, ?DECOMPRESSION_FAILURE,
- ?HANDSHAKE_FAILURE, ?BAD_CERTIFICATE, ?UNSUPPORTED_CERTIFICATE,
- ?CERTIFICATE_REVOKED,?CERTIFICATE_EXPIRED, ?CERTIFICATE_UNKNOWN,
- ?ILLEGAL_PARAMETER, ?UNKNOWN_CA, ?ACCESS_DENIED, ?DECODE_ERROR,
- ?DECRYPT_ERROR, ?EXPORT_RESTRICTION, ?PROTOCOL_VERSION,
- ?INSUFFICIENT_SECURITY, ?INTERNAL_ERROR, ?USER_CANCELED,
- ?NO_RENEGOTIATION, ?UNSUPPORTED_EXTENSION, ?CERTIFICATE_UNOBTAINABLE,
- ?UNRECOGNISED_NAME, ?BAD_CERTIFICATE_STATUS_RESPONSE,
- ?BAD_CERTIFICATE_HASH_VALUE, ?UNKNOWN_PSK_IDENTITY,
- 255 %% Unsupported/unknow alert will result in a description too
- ],
- Alerts = [?ALERT_REC(?WARNING, ?CLOSE_NOTIFY) |
- [?ALERT_REC(?FATAL, Desc) || Desc <- Descriptions]],
- lists:foreach(fun(Alert) ->
- try ssl_alert:alert_txt(Alert)
- catch
- C:E:T ->
- ct:fail({unexpected, {C, E, T}})
- end
- end, Alerts).
-%%--------------------------------------------------------------------
-alert_details() ->
- [{doc, "Test that ssl_alert:alert_txt/1 result contains extendend error description"}].
-alert_details(Config) when is_list(Config) ->
- Unique = make_ref(),
- UniqueStr = lists:flatten(io_lib:format("~w", [Unique])),
- Alert = ?ALERT_REC(?WARNING, ?CLOSE_NOTIFY, Unique),
- case string:str(ssl_alert:alert_txt(Alert), UniqueStr) of
- 0 ->
- ct:fail(error_details_missing);
- _ ->
- ok
- end.
-
-%%--------------------------------------------------------------------
-alert_details_not_too_big() ->
- [{doc, "Test that ssl_alert:alert_txt/1 limits printed depth of extended error description"}].
-alert_details_not_too_big(Config) when is_list(Config) ->
- Reason = lists:duplicate(10, lists:duplicate(10, lists:duplicate(10, {some, data}))),
- Alert = ?ALERT_REC(?WARNING, ?CLOSE_NOTIFY, Reason),
- case length(ssl_alert:alert_txt(Alert)) < 1000 of
- true ->
- ok;
- false ->
- ct:fail(ssl_alert_text_too_big)
- end.
-
-%%--------------------------------------------------------------------
-new_options_in_accept() ->
- [{doc,"Test that you can set ssl options in ssl_accept/3 and not only in tcp upgrade"}].
-new_options_in_accept(Config) when is_list(Config) ->
- ClientOpts = ssl_test_lib:ssl_options(client_opts, Config),
- ServerOpts0 = ssl_test_lib:ssl_options(server_dsa_opts, Config),
- [_ , _ | ServerSslOpts] = ssl_test_lib:ssl_options(server_opts, Config), %% Remove non ssl opts
- {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
- Version = ssl_test_lib:protocol_options(Config, [{tls, sslv3}, {dtls, dtlsv1}]),
- Cipher = ssl_test_lib:protocol_options(Config, [{tls, #{key_exchange =>rsa,
- cipher => rc4_128,
- mac => sha,
- prf => default_prf
- }},
- {dtls, #{key_exchange =>rsa,
- cipher => aes_128_cbc,
- mac => sha,
- prf => default_prf
- }}]),
- Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0},
- {from, self()},
- {ssl_extra_opts, [{versions, [Version]},
- {ciphers,[Cipher]} | ServerSslOpts]}, %% To be set in ssl_accept/3
- {mfa, {?MODULE, connection_info_result, []}},
- {options, proplists:delete(cacertfile, ServerOpts0)}]),
-
- Port = ssl_test_lib:inet_port(Server),
- Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port},
- {host, Hostname},
- {from, self()},
- {mfa, {?MODULE, connection_info_result, []}},
- {options, [{versions, [Version]},
- {ciphers,[Cipher]} | ClientOpts]}]),
-
- ct:log("Testcase ~p, Client ~p Server ~p ~n",
- [self(), Client, Server]),
-
- ServerMsg = ClientMsg = {ok, {Version, Cipher}},
+version_option() ->
+ [{doc, "Use version option and do no specify ciphers list. Bug specified incorrect ciphers"}].
+version_option(Config) when is_list(Config) ->
+ Versions = proplists:get_value(supported, ssl:versions()),
+ [version_option_test(Config, Version) || Version <- Versions].
- ssl_test_lib:check_result(Server, ServerMsg, Client, ClientMsg),
-
- ssl_test_lib:close(Server),
- ssl_test_lib:close(Client).
-
-%%--------------------------------------------------------------------
-handshake_continue() ->
- [{doc, "Test API function ssl:handshake_continue/3"}].
-handshake_continue(Config) when is_list(Config) ->
- ClientOpts = ssl_test_lib:ssl_options(client_rsa_verify_opts, Config),
- ServerOpts = ssl_test_lib:ssl_options(server_rsa_verify_opts, Config),
- {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
-
- Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0},
- {from, self()},
- {mfa, {ssl_test_lib, send_recv_result_active, []}},
- {options, ssl_test_lib:ssl_options([{reuseaddr, true}, {handshake, hello}],
- Config)},
- {continue_options, proplists:delete(reuseaddr, ServerOpts)}
- ]),
-
- Port = ssl_test_lib:inet_port(Server),
-
- Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port},
- {host, Hostname},
- {from, self()},
- {mfa, {ssl_test_lib, send_recv_result_active, []}},
- {options, ssl_test_lib:ssl_options([{handshake, hello}],
- Config)},
- {continue_options, proplists:delete(reuseaddr, ClientOpts)}]),
-
- ssl_test_lib:check_result(Server, ok, Client, ok),
-
- ssl_test_lib:close(Server),
- ssl_test_lib:close(Client).
-
-
-%%--------------------------------------------------------------------
-handshake_continue_tls13_client() ->
- [{doc, "Test API function ssl:handshake_continue/3"}].
-handshake_continue_tls13_client(Config) when is_list(Config) ->
- ClientOpts0 = ssl_test_lib:ssl_options(client_rsa_verify_opts, Config),
- ServerOpts = ssl_test_lib:ssl_options(server_rsa_verify_opts, Config),
- ClientOpts = [{versions, ['tlsv1.2','tlsv1.3']}|ClientOpts0],
-
- ClientOptsHello0 = ssl_test_lib:ssl_options([{handshake, hello}], Config),
- ClientOptsHello = [{versions, ['tlsv1.2','tlsv1.3']}|ClientOptsHello0],
-
- {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
-
- Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0},
- {from, self()},
- {mfa, {ssl_test_lib, send_recv_result_active, []}},
- {options, ssl_test_lib:ssl_options([{reuseaddr, true}, {handshake, hello}],
- Config)},
- {continue_options, proplists:delete(reuseaddr, ServerOpts)}
- ]),
-
- Port = ssl_test_lib:inet_port(Server),
-
- Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port},
- {host, Hostname},
- {from, self()},
- {mfa, {ssl_test_lib, send_recv_result_active, []}},
- {options, ClientOptsHello},
- {continue_options, proplists:delete(reuseaddr, ClientOpts)}]),
-
- ssl_test_lib:check_result(Server, ok, Client, ok),
-
- ssl_test_lib:close(Server),
- ssl_test_lib:close(Client).
-
-
-%%------------------------------------------------------------------
-handshake_continue_timeout() ->
- [{doc, "Test API function ssl:handshake_continue/3 with short timeout"}].
-handshake_continue_timeout(Config) when is_list(Config) ->
- ClientOpts = ssl_test_lib:ssl_options(client_verification_opts, Config),
- ServerOpts = ssl_test_lib:ssl_options(server_verification_opts, Config),
- {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
-
- Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0},
- {from, self()},
- {timeout, 1},
- {options, ssl_test_lib:ssl_options([{reuseaddr, true}, {handshake, hello}],
- Config)},
- {continue_options, proplists:delete(reuseaddr, ServerOpts)}
- ]),
-
- Port = ssl_test_lib:inet_port(Server),
-
-
- {connect_failed, _} = ssl_test_lib:start_client([{node, ClientNode}, {port, Port},
- {host, Hostname},
- {from, self()},
- {options, ClientOpts}]),
-
- ssl_test_lib:check_result(Server, {error,timeout}),
- ssl_test_lib:close(Server).
-
-
-%%--------------------------------------------------------------------
-hello_client_cancel() ->
- [{doc, "Test API function ssl:handshake_cancel/1 on the client side"}].
-hello_client_cancel(Config) when is_list(Config) ->
- ServerOpts = ssl_test_lib:ssl_options(server_verification_opts, Config),
- ServerOpts = ssl_test_lib:ssl_options(server_verification_opts, Config),
- {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
-
- Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0},
- {from, self()},
- {options, ssl_test_lib:ssl_options([{handshake, hello}], Config)},
- {continue_options, proplists:delete(reuseaddr, ServerOpts)}]),
-
- Port = ssl_test_lib:inet_port(Server),
-
- %% That is ssl:handshake_cancel returns ok
- {connect_failed, ok} = ssl_test_lib:start_client([{node, ClientNode}, {port, Port},
- {host, Hostname},
- {from, self()},
- {options, ssl_test_lib:ssl_options([{handshake, hello}], Config)},
- {continue_options, cancel}]),
- ssl_test_lib:check_server_alert(Server, user_canceled).
%%--------------------------------------------------------------------
-hello_server_cancel() ->
- [{doc, "Test API function ssl:handshake_cancel/1 on the server side"}].
-hello_server_cancel(Config) when is_list(Config) ->
- ClientOpts = ssl_test_lib:ssl_options(client_rsa_verify_opts, Config),
- {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
-
- Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0},
- {from, self()},
- {options, ssl_test_lib:ssl_options([{handshake, hello}], Config)},
- {continue_options, cancel}]),
-
- Port = ssl_test_lib:inet_port(Server),
-
- {connect_failed, _} = ssl_test_lib:start_client([{node, ClientNode}, {port, Port},
- {host, Hostname},
- {from, self()},
- {options, ssl_test_lib:ssl_options([{handshake, hello}], Config)},
- {continue_options, proplists:delete(reuseaddr, ClientOpts)}]),
-
- ssl_test_lib:check_result(Server, ok).
-
-%%--------------------------------------------------------------------
-prf() ->
- [{doc,"Test that ssl:prf/5 uses the negotiated PRF."}].
-prf(Config) when is_list(Config) ->
- TestPlan = proplists:get_value(prf_test_plan, Config),
- case TestPlan of
- [] -> ct:fail({error, empty_prf_test_plan});
- _ -> lists:foreach(fun(Suite) ->
- lists:foreach(
- fun(Test) ->
- V = proplists:get_value(tls_ver, Test),
- C = proplists:get_value(ciphers, Test),
- E = proplists:get_value(expected, Test),
- P = proplists:get_value(prf, Test),
- prf_run_test(Config, V, C, E, P)
- end, Suite)
- end, TestPlan)
- end.
-
-%%--------------------------------------------------------------------
-
-secret_connection_info() ->
- [{doc,"Test the API function ssl:connection_information/2"}].
-secret_connection_info(Config) when is_list(Config) ->
- ClientOpts = ssl_test_lib:ssl_options(client_rsa_verify_opts, Config),
- ServerOpts = ssl_test_lib:ssl_options(server_rsa_verify_opts, Config),
- {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
-
- Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0},
- {from, self()},
- {mfa, {?MODULE, secret_connection_info_result, []}},
- {options, ServerOpts}]),
-
- Port = ssl_test_lib:inet_port(Server),
- Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port},
- {host, Hostname},
- {from, self()},
- {mfa, {?MODULE, secret_connection_info_result, []}},
- {options, ClientOpts}]),
-
- ct:log("Testcase ~p, Client ~p Server ~p ~n",
- [self(), Client, Server]),
-
- ssl_test_lib:check_result(Server, true, Client, true),
-
- ssl_test_lib:close(Server),
- ssl_test_lib:close(Client).
-
-
-%%--------------------------------------------------------------------
-
-connection_information() ->
- [{doc,"Test the API function ssl:connection_information/1"}].
-connection_information(Config) when is_list(Config) ->
- ClientOpts = ssl_test_lib:ssl_options(client_opts, Config),
- ServerOpts = ssl_test_lib:ssl_options(server_opts, Config),
- {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
- Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0},
- {from, self()},
- {mfa, {?MODULE, connection_information_result, []}},
- {options, ServerOpts}]),
-
- Port = ssl_test_lib:inet_port(Server),
- Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port},
- {host, Hostname},
- {from, self()},
- {mfa, {?MODULE, connection_information_result, []}},
- {options, ClientOpts}]),
-
- ct:log("Testcase ~p, Client ~p Server ~p ~n",
- [self(), Client, Server]),
-
- ServerMsg = ClientMsg = ok,
-
- ssl_test_lib:check_result(Server, ServerMsg, Client, ClientMsg),
-
- ssl_test_lib:close(Server),
- ssl_test_lib:close(Client).
-
-
-%%--------------------------------------------------------------------
-protocol_versions() ->
- [{doc,"Test to set a list of protocol versions in app environment."}].
-
-protocol_versions(Config) when is_list(Config) ->
- basic_test(Config).
-
-%%--------------------------------------------------------------------
-empty_protocol_versions() ->
- [{doc,"Test to set an empty list of protocol versions in app environment."}].
-
-empty_protocol_versions(Config) when is_list(Config) ->
- basic_test(Config).
-
-%%--------------------------------------------------------------------
-
-controlling_process() ->
- [{doc,"Test API function controlling_process/2"}].
-
-controlling_process(Config) when is_list(Config) ->
+connect_twice() ->
+ [{doc,""}].
+connect_twice(Config) when is_list(Config) ->
ClientOpts = ssl_test_lib:ssl_options(client_opts, Config),
ServerOpts = ssl_test_lib:ssl_options(server_opts, Config),
- {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
- ClientMsg = "Server hello",
- ServerMsg = "Client hello",
-
- Server = ssl_test_lib:start_server([
- {node, ServerNode}, {port, 0},
- {from, self()},
- {mfa, {?MODULE,
- controlling_process_result, [self(),
- ServerMsg]}},
- {options, ServerOpts}]),
- Port = ssl_test_lib:inet_port(Server),
- {Client, CSocket} = ssl_test_lib:start_client([return_socket,
- {node, ClientNode}, {port, Port},
- {host, Hostname},
- {from, self()},
- {mfa, {?MODULE,
- controlling_process_result, [self(),
- ClientMsg]}},
- {options, ClientOpts}]),
-
- ct:log("Testcase ~p, Client ~p Server ~p ~n",
- [self(), Client, Server]),
-
- ServerMsg = ssl_test_lib:active_recv(CSocket, length(ServerMsg)),
- %% We do not have the TLS server socket but all messages form the client
- %% socket are now read, so ramining are form the server socket
- ClientMsg = ssl_active_recv(length(ClientMsg)),
-
- ssl_test_lib:close(Server),
- ssl_test_lib:close(Client).
-
-%%--------------------------------------------------------------------
-getstat() ->
- [{doc,"Test API function getstat/2"}].
-getstat(Config) when is_list(Config) ->
- ClientOpts = ?config(client_opts, Config),
- ServerOpts = ?config(server_opts, Config),
{ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
- Server1 =
- ssl_test_lib:start_server([{node, ServerNode}, {port, 0},
- {from, self()},
- {mfa, {ssl_test_lib, send_recv_result, []}},
- {options, [{active, false} | ServerOpts]}]),
- Port1 = ssl_test_lib:inet_port(Server1),
- Server2 =
- ssl_test_lib:start_server([{node, ServerNode}, {port, 0},
- {from, self()},
- {mfa, {ssl_test_lib, send_recv_result, []}},
- {options, [{active, false} | ServerOpts]}]),
- Port2 = ssl_test_lib:inet_port(Server2),
- {ok, ActiveC} = rpc:call(ClientNode, ssl, connect,
- [Hostname,Port1,[{active, once}|ClientOpts]]),
- {ok, PassiveC} = rpc:call(ClientNode, ssl, connect,
- [Hostname,Port2,[{active, false}|ClientOpts]]),
-
- ct:log("Testcase ~p, Client ~p Servers ~p, ~p ~n",
- [self(), self(), Server1, Server2]),
-
- %% We only check that the values are non-zero initially
- %% (due to the handshake), and that sending more changes the values.
-
- %% Passive socket.
-
- {ok, InitialStats} = ssl:getstat(PassiveC),
- ct:pal("InitialStats ~p~n", [InitialStats]),
- [true] = lists:usort([0 =/= proplists:get_value(Name, InitialStats)
- || Name <- [recv_cnt, recv_oct, recv_avg, recv_max, send_cnt, send_oct, send_avg, send_max]]),
-
- ok = ssl:send(PassiveC, "Hello world"),
- wait_for_send(PassiveC),
- {ok, SStats} = ssl:getstat(PassiveC, [send_cnt, send_oct]),
- ct:pal("SStats ~p~n", [SStats]),
- [true] = lists:usort([proplists:get_value(Name, SStats) =/= proplists:get_value(Name, InitialStats)
- || Name <- [send_cnt, send_oct]]),
-
- %% Active socket.
-
- {ok, InitialAStats} = ssl:getstat(ActiveC),
- ct:pal("InitialAStats ~p~n", [InitialAStats]),
- [true] = lists:usort([0 =/= proplists:get_value(Name, InitialAStats)
- || Name <- [recv_cnt, recv_oct, recv_avg, recv_max, send_cnt, send_oct, send_avg, send_max]]),
- _ = receive
- {ssl, ActiveC, _} ->
- ok
- after
- ?SLEEP ->
- exit(timeout)
- end,
-
- ok = ssl:send(ActiveC, "Hello world"),
- wait_for_send(ActiveC),
- {ok, ASStats} = ssl:getstat(ActiveC, [send_cnt, send_oct]),
- ct:pal("ASStats ~p~n", [ASStats]),
- [true] = lists:usort([proplists:get_value(Name, ASStats) =/= proplists:get_value(Name, InitialAStats)
- || Name <- [send_cnt, send_oct]]),
-
- ok.
-
-%%--------------------------------------------------------------------
-controller_dies() ->
- [{doc,"Test that the socket is closed after controlling process dies"}].
-controller_dies(Config) when is_list(Config) ->
- ClientOpts = ssl_test_lib:ssl_options(client_opts, Config),
- ServerOpts = ssl_test_lib:ssl_options(server_opts, Config),
- {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
- ClientMsg = "Hello server",
- ServerMsg = "Hello client",
-
- Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0},
- {from, self()},
- {mfa, {?MODULE,
- controller_dies_result, [self(),
- ServerMsg]}},
- {options, ServerOpts}]),
- Port = ssl_test_lib:inet_port(Server),
- Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port},
- {host, Hostname},
- {from, self()},
- {mfa, {?MODULE,
- controller_dies_result, [self(),
- ClientMsg]}},
- {options, ClientOpts}]),
-
- ct:log("Testcase ~p, Client ~p Server ~p ~n", [self(), Client, Server]),
- ct:sleep(?SLEEP), %% so that they are connected
-
- process_flag(trap_exit, true),
-
- %% Test that clients die
- exit(Client, killed),
- get_close(Client, ?LINE),
-
- %% Test that clients die when process disappear
- Server ! listen,
- Tester = self(),
- Connect = fun(Pid) ->
- {ok, Socket} = ssl:connect(Hostname, Port, ClientOpts),
- %% Make sure server finishes and verification
- %% and is in coonection state before
- %% killing client
- ct:sleep(?SLEEP),
- Pid ! {self(), connected, Socket},
- receive die_nice -> normal end
- end,
- Client2 = spawn_link(fun() -> Connect(Tester) end),
- receive {Client2, connected, _Socket} -> Client2 ! die_nice end,
-
- get_close(Client2, ?LINE),
-
- %% Test that clients die when the controlling process have changed
- Server ! listen,
-
- Client3 = spawn_link(fun() -> Connect(Tester) end),
- Controller = spawn_link(fun() -> receive die_nice -> normal end end),
- receive
- {Client3, connected, Socket} ->
- ok = ssl:controlling_process(Socket, Controller),
- Client3 ! die_nice
- end,
-
- ct:log("Wating on exit ~p~n",[Client3]),
- receive {'EXIT', Client3, normal} -> ok end,
-
- receive %% Client3 is dead but that doesn't matter, socket should not be closed.
- Unexpected ->
- ct:log("Unexpected ~p~n",[Unexpected]),
- ct:fail({line, ?LINE-1})
- after 1000 ->
- ok
- end,
- Controller ! die_nice,
- get_close(Controller, ?LINE),
-
- %% Test that servers die
- Server ! listen,
- LastClient = ssl_test_lib:start_client([{node, ClientNode}, {port, Port},
- {host, Hostname},
- {from, self()},
- {mfa, {?MODULE,
- controller_dies_result, [self(),
- ClientMsg]}},
- {options, ClientOpts}]),
- ct:sleep(?SLEEP), %% so that they are connected
-
- exit(Server, killed),
- get_close(Server, ?LINE),
- process_flag(trap_exit, false),
- ssl_test_lib:close(LastClient).
-
-%%--------------------------------------------------------------------
-tls_client_closes_socket() ->
- [{doc,"Test what happens when client closes socket before handshake is compleated"}].
-
-tls_client_closes_socket(Config) when is_list(Config) ->
- ServerOpts = ssl_test_lib:ssl_options(server_opts, Config),
- {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
- TcpOpts = [binary, {reuseaddr, true}],
-
- Server = ssl_test_lib:start_upgrade_server_error([{node, ServerNode}, {port, 0},
- {from, self()},
- {tcp_options, TcpOpts},
- {ssl_options, ServerOpts}]),
+ Server =
+ ssl_test_lib:start_server([{node, ServerNode}, {port, 0},
+ {from, self()},
+ {mfa, {ssl_test_lib, send_recv_result, []}},
+ {options, [{keepalive, true},{active, false}
+ | ServerOpts]}]),
Port = ssl_test_lib:inet_port(Server),
+ Client =
+ ssl_test_lib:start_client([{node, ClientNode}, {port, Port},
+ {host, Hostname},
+ {from, self()},
+ {mfa, {ssl_test_lib, send_recv_result, []}},
+ {options, [{keepalive, true},{active, false}
+ | ClientOpts]}]),
+ Server ! listen,
- Connect = fun() ->
- {ok, _Socket} = rpc:call(ClientNode, gen_tcp, connect,
- [Hostname, Port, [binary]]),
- %% Make sure that ssl_accept is called before
- %% client process ends and closes socket.
- ct:sleep(?SLEEP)
- end,
-
- _Client = spawn_link(Connect),
-
- ssl_test_lib:check_result(Server, {error,closed}).
-
-%%--------------------------------------------------------------------
-tls_closed_in_active_once() ->
- [{doc, "Test that ssl_closed is delivered in active once with non-empty buffer, check ERL-420."}].
-
-tls_closed_in_active_once(Config) when is_list(Config) ->
- ClientOpts = ssl_test_lib:ssl_options(client_opts, Config),
- ServerOpts = ssl_test_lib:ssl_options(server_opts, Config),
- {_ClientNode, _ServerNode, Hostname} = ssl_test_lib:run_where(Config),
- TcpOpts = [binary, {reuseaddr, true}],
- Port = ssl_test_lib:inet_port(node()),
- Server = fun() ->
- {ok, Listen} = gen_tcp:listen(Port, TcpOpts),
- {ok, TcpServerSocket} = gen_tcp:accept(Listen),
- {ok, ServerSocket} = ssl:ssl_accept(TcpServerSocket, ServerOpts),
- lists:foreach(
- fun(_) ->
- ssl:send(ServerSocket, "some random message\r\n")
- end, lists:seq(1, 20)),
- %% Close TCP instead of SSL socket to trigger the bug:
- gen_tcp:close(TcpServerSocket),
- gen_tcp:close(Listen)
- end,
- spawn_link(Server),
- {ok, Socket} = ssl:connect(Hostname, Port, [{active, false} | ClientOpts]),
- Result = tls_closed_in_active_once_loop(Socket),
- ssl:close(Socket),
- case Result of
- ok -> ok;
- _ -> ct:fail(Result)
- end.
-
-tls_closed_in_active_once_loop(Socket) ->
- case ssl:setopts(Socket, [{active, once}]) of
- ok ->
- receive
- {ssl, Socket, _} ->
- tls_closed_in_active_once_loop(Socket);
- {ssl_closed, Socket} ->
- ok
- after 5000 ->
- no_ssl_closed_received
- end;
- {error, closed} ->
- ok
- end.
-%%--------------------------------------------------------------------
-connect_dist() ->
- [{doc,"Test a simple connect as is used by distribution"}].
-
-connect_dist(Config) when is_list(Config) ->
- ClientOpts0 = ssl_test_lib:ssl_options(client_kc_opts, Config),
- ClientOpts = [{ssl_imp, new},{active, false}, {packet,4}|ClientOpts0],
- ServerOpts0 = ssl_test_lib:ssl_options(server_kc_opts, Config),
- ServerOpts = [{ssl_imp, new},{active, false}, {packet,4}|ServerOpts0],
+ {Client1, #sslsocket{}} =
+ ssl_test_lib:start_client([return_socket,
+ {node, ClientNode}, {port, Port},
+ {host, Hostname},
+ {from, self()},
+ {mfa, {ssl_test_lib, send_recv_result, []}},
+ {options, [{keepalive, true},{active, false}
+ | ClientOpts]}]),
- {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
+ ct:log("Testcase ~p, Client ~p Server ~p ~n",
+ [self(), Client, Server]),
- Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0},
- {from, self()},
- {mfa, {?MODULE, connect_dist_s, []}},
- {options, ServerOpts}]),
- Port = ssl_test_lib:inet_port(Server),
- Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port},
- {host, Hostname},
- {from, self()},
- {mfa, {?MODULE, connect_dist_c, []}},
- {options, ClientOpts}]),
-
ssl_test_lib:check_result(Server, ok, Client, ok),
+ ssl_test_lib:check_result(Server, ok, Client1, ok),
ssl_test_lib:close(Server),
- ssl_test_lib:close(Client).
-
-%%--------------------------------------------------------------------
-
-clear_pem_cache() ->
- [{doc,"Test that internal reference tabel is cleaned properly even when "
- " the PEM cache is cleared" }].
-clear_pem_cache(Config) when is_list(Config) ->
- {status, _, _, StatusInfo} = sys:get_status(whereis(ssl_manager)),
- [_, _,_, _, Prop] = StatusInfo,
- State = ssl_test_lib:state(Prop),
- [_,{FilRefDb, _} |_] = element(6, State),
- {Server, Client} = basic_verify_test_no_close(Config),
- CountReferencedFiles = fun({_, -1}, Acc) ->
- Acc;
- ({_, N}, Acc) ->
- N + Acc
- end,
-
- 2 = ets:foldl(CountReferencedFiles, 0, FilRefDb),
- ssl:clear_pem_cache(),
- _ = sys:get_status(whereis(ssl_manager)),
- {Server1, Client1} = basic_verify_test_no_close(Config),
- 4 = ets:foldl(CountReferencedFiles, 0, FilRefDb),
- ssl_test_lib:close(Server),
ssl_test_lib:close(Client),
- ct:sleep(2000),
- _ = sys:get_status(whereis(ssl_manager)),
- 2 = ets:foldl(CountReferencedFiles, 0, FilRefDb),
- ssl_test_lib:close(Server1),
- ssl_test_lib:close(Client1),
- ct:sleep(2000),
- _ = sys:get_status(whereis(ssl_manager)),
- 0 = ets:foldl(CountReferencedFiles, 0, FilRefDb).
+ ssl_test_lib:close(Client1).
+defaults(Config) when is_list(Config)->
+ Versions = ssl:versions(),
+ true = lists:member(sslv3, proplists:get_value(available, Versions)),
+ false = lists:member(sslv3, proplists:get_value(supported, Versions)),
+ true = lists:member('tlsv1', proplists:get_value(available, Versions)),
+ false = lists:member('tlsv1', proplists:get_value(supported, Versions)),
+ true = lists:member('tlsv1.1', proplists:get_value(available, Versions)),
+ false = lists:member('tlsv1.1', proplists:get_value(supported, Versions)),
+ true = lists:member('tlsv1.2', proplists:get_value(available, Versions)),
+ true = lists:member('tlsv1.2', proplists:get_value(supported, Versions)),
+ false = lists:member({rsa,rc4_128,sha}, ssl:cipher_suites()),
+ true = lists:member({rsa,rc4_128,sha}, ssl:cipher_suites(all)),
+ false = lists:member({rsa,des_cbc,sha}, ssl:cipher_suites()),
+ true = lists:member({rsa,des_cbc,sha}, ssl:cipher_suites(all)),
+ false = lists:member({dhe_rsa,des_cbc,sha}, ssl:cipher_suites()),
+ true = lists:member({dhe_rsa,des_cbc,sha}, ssl:cipher_suites(all)),
+ true = lists:member('dtlsv1.2', proplists:get_value(available_dtls, Versions)),
+ true = lists:member('dtlsv1', proplists:get_value(available_dtls, Versions)),
+ true = lists:member('dtlsv1.2', proplists:get_value(supported_dtls, Versions)),
+ false = lists:member('dtlsv1', proplists:get_value(supported_dtls, Versions)).
-%%--------------------------------------------------------------------
fallback() ->
[{doc, "Test TLS_FALLBACK_SCSV downgrade prevention"}].
@@ -1263,7 +217,6 @@ fallback(Config) when is_list(Config) ->
| ClientOpts]}]),
ssl_test_lib:check_server_alert(Server, Client, inappropriate_fallback).
-
%%--------------------------------------------------------------------
cipher_format() ->
[{doc, "Test that cipher conversion from maps | tuples | stings to binarys works"}].
@@ -1277,175 +230,6 @@ cipher_format(Config) when is_list(Config) ->
ssl:close(Socket2).
%%--------------------------------------------------------------------
-suite_to_str() ->
- [{doc, "Test that the suite_to_str API works"}].
-suite_to_str(Config) when is_list(Config) ->
- "TLS_EMPTY_RENEGOTIATION_INFO_SCSV" =
- ssl:suite_to_str(#{key_exchange => null,
- cipher => null,
- mac => null,
- prf => null}),
- "TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256" =
- ssl:suite_to_str(#{key_exchange => ecdhe_ecdsa,
- cipher => aes_128_gcm,
- mac => aead,
- prf => sha256}),
- "TLS_ECDH_RSA_WITH_AES_128_CBC_SHA256" =
- ssl:suite_to_str(#{key_exchange => ecdh_rsa,
- cipher => aes_128_cbc,
- mac => sha256,
- prf => sha256}).
-
-%%--------------------------------------------------------------------
-
-peername() ->
- [{doc,"Test API function peername/1"}].
-
-peername(Config) when is_list(Config) ->
- ClientOpts = ssl_test_lib:ssl_options(client_opts, Config),
- ServerOpts = ssl_test_lib:ssl_options(server_opts, Config),
- {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
- Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0},
- {from, self()},
- {mfa, {?MODULE, peername_result, []}},
- {options, ServerOpts}]),
- Port = ssl_test_lib:inet_port(Server),
- Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port},
- {host, Hostname},
- {from, self()},
- {mfa, {?MODULE, peername_result, []}},
- {options, [{port, 0} | ClientOpts]}]),
-
- ClientPort = ssl_test_lib:inet_port(Client),
- ServerIp = ssl_test_lib:node_to_hostip(ServerNode, server),
- ClientIp = ssl_test_lib:node_to_hostip(ClientNode, client),
- ServerMsg = {ok, {ClientIp, ClientPort}},
- ClientMsg = {ok, {ServerIp, Port}},
-
- ct:log("Testcase ~p, Client ~p Server ~p ~n",
- [self(), Client, Server]),
-
- ssl_test_lib:check_result(Server, ServerMsg, Client, ClientMsg),
-
- ssl_test_lib:close(Server),
- ssl_test_lib:close(Client).
-
-%%--------------------------------------------------------------------
-peercert() ->
- [{doc,"Test API function peercert/1"}].
-peercert(Config) when is_list(Config) ->
- ClientOpts = ssl_test_lib:ssl_options(client_opts, Config),
- ServerOpts = ssl_test_lib:ssl_options(server_opts, Config),
- {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
-
- Server = ssl_test_lib:start_server([{node, ClientNode}, {port, 0},
- {from, self()},
- {mfa, {?MODULE, peercert_result, []}},
- {options, ServerOpts}]),
- Port = ssl_test_lib:inet_port(Server),
- Client = ssl_test_lib:start_client([{node, ServerNode}, {port, Port},
- {host, Hostname},
- {from, self()},
- {mfa, {?MODULE, peercert_result, []}},
- {options, ClientOpts}]),
-
- CertFile = proplists:get_value(certfile, ServerOpts),
- [{'Certificate', BinCert, _}]= ssl_test_lib:pem_to_der(CertFile),
-
- ServerMsg = {error, no_peercert},
- ClientMsg = {ok, BinCert},
-
- ct:log("Testcase ~p, Client ~p Server ~p ~n",
- [self(), Client, Server]),
-
- ssl_test_lib:check_result(Server, ServerMsg, Client, ClientMsg),
-
- ssl_test_lib:close(Server),
- ssl_test_lib:close(Client).
-
-peercert_result(Socket) ->
- ssl:peercert(Socket).
-%%--------------------------------------------------------------------
-
-peercert_with_client_cert() ->
- [{doc,"Test API function peercert/1"}].
-peercert_with_client_cert(Config) when is_list(Config) ->
- ClientOpts = ssl_test_lib:ssl_options(client_dsa_opts, Config),
- ServerOpts = ssl_test_lib:ssl_options(server_dsa_verify_opts, Config),
- {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
-
- Server = ssl_test_lib:start_server([{node, ClientNode}, {port, 0},
- {from, self()},
- {mfa, {?MODULE, peercert_result, []}},
- {options, ServerOpts}]),
- Port = ssl_test_lib:inet_port(Server),
- Client = ssl_test_lib:start_client([{node, ServerNode}, {port, Port},
- {host, Hostname},
- {from, self()},
- {mfa, {?MODULE, peercert_result, []}},
- {options, ClientOpts}]),
-
- ServerCertFile = proplists:get_value(certfile, ServerOpts),
- [{'Certificate', ServerBinCert, _}]= ssl_test_lib:pem_to_der(ServerCertFile),
- ClientCertFile = proplists:get_value(certfile, ClientOpts),
- [{'Certificate', ClientBinCert, _}]= ssl_test_lib:pem_to_der(ClientCertFile),
-
- ServerMsg = {ok, ClientBinCert},
- ClientMsg = {ok, ServerBinCert},
-
- ct:log("Testcase ~p, Client ~p Server ~p ~n",
- [self(), Client, Server]),
-
- ssl_test_lib:check_result(Server, ServerMsg, Client, ClientMsg),
-
- ssl_test_lib:close(Server),
- ssl_test_lib:close(Client).
-
-%%--------------------------------------------------------------------
-sockname() ->
- [{doc,"Test API function sockname/1"}].
-sockname(Config) when is_list(Config) ->
- ClientOpts = ssl_test_lib:ssl_options(client_opts, Config),
- ServerOpts = ssl_test_lib:ssl_options(server_opts, Config),
- {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
- Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0},
- {from, self()},
- {mfa, {?MODULE, sockname_result, []}},
- {options, ServerOpts}]),
- Port = ssl_test_lib:inet_port(Server),
- Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port},
- {host, Hostname},
- {from, self()},
- {mfa, {?MODULE, sockname_result, []}},
- {options, [{port, 0} | ClientOpts]}]),
-
- ClientPort = ssl_test_lib:inet_port(Client),
- ServerIp =
- case proplists:get_value(protocol, Config) of
- dtls ->
- %% DTLS sockets are not connected on the server side,
- %% so we can only get a ClientIP, ServerIP will always be 0.0.0.0
- {0,0,0,0};
- _ ->
- ssl_test_lib:node_to_hostip(ServerNode, server)
- end,
-
- ClientIp = ssl_test_lib:node_to_hostip(ClientNode, client),
- ServerMsg = {ok, {ServerIp, Port}},
- ClientMsg = {ok, {ClientIp, ClientPort}},
-
- ct:log("Testcase ~p, Client ~p Server ~p ~n",
- [self(), Client, Server]),
-
- ssl_test_lib:check_result(Server, ServerMsg, Client, ClientMsg),
-
- ssl_test_lib:close(Server),
- ssl_test_lib:close(Client).
-
-sockname_result(S) ->
- ssl:sockname(S).
-
-%%--------------------------------------------------------------------
cipher_suites() ->
[{doc,"Test API function cipher_suites/2, filter_cipher_suites/2"
@@ -1542,2750 +326,95 @@ cipher_suites_mix(Config) when is_list(Config) ->
ssl_test_lib:check_result(Server, ok, Client, ok),
ssl_test_lib:close(Server),
ssl_test_lib:close(Client).
-%%--------------------------------------------------------------------
-tls_socket_options() ->
- [{doc,"Test API function getopts/2 and setopts/2"}].
+unordered_protocol_versions_server() ->
+ [{doc,"Test that the highest protocol is selected even"
+ " when it is not first in the versions list."}].
-tls_socket_options(Config) when is_list(Config) ->
+unordered_protocol_versions_server(Config) when is_list(Config) ->
ClientOpts = ssl_test_lib:ssl_options(client_opts, Config),
- ServerOpts = ssl_test_lib:ssl_options(server_opts, Config),
- {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
- Values = [{mode, list}, {packet, 0}, {header, 0},
- {active, true}],
- %% Shall be the reverse order of Values!
- Options = [active, header, packet, mode],
-
- NewValues = [{mode, binary}, {active, once}],
- %% Shall be the reverse order of NewValues!
- NewOptions = [active, mode],
-
- Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0},
- {from, self()},
- {mfa, {?MODULE, tls_socket_options_result,
- [Options, Values, NewOptions, NewValues]}},
- {options, ServerOpts}]),
- Port = ssl_test_lib:inet_port(Server),
- Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port},
- {host, Hostname},
- {from, self()},
- {mfa, {?MODULE, tls_socket_options_result,
- [Options, Values, NewOptions, NewValues]}},
- {options, ClientOpts}]),
-
- ssl_test_lib:check_result(Server, ok, Client, ok),
-
- ssl_test_lib:close(Server),
-
- {ok, Listen} = ssl:listen(0, ServerOpts),
- {ok,[{mode,list}]} = ssl:getopts(Listen, [mode]),
- ok = ssl:setopts(Listen, [{mode, binary}]),
- {ok,[{mode, binary}]} = ssl:getopts(Listen, [mode]),
- {ok,[{recbuf, _}]} = ssl:getopts(Listen, [recbuf]),
- ssl:close(Listen).
-
-tls_socket_options_result(Socket, Options, DefaultValues, NewOptions, NewValues) ->
- %% Test get/set emulated opts
- {ok, DefaultValues} = ssl:getopts(Socket, Options),
- ssl:setopts(Socket, NewValues),
- {ok, NewValues} = ssl:getopts(Socket, NewOptions),
- %% Test get/set inet opts
- {ok,[{nodelay,false}]} = ssl:getopts(Socket, [nodelay]),
- ssl:setopts(Socket, [{nodelay, true}]),
- {ok,[{nodelay, true}]} = ssl:getopts(Socket, [nodelay]),
- {ok, All} = ssl:getopts(Socket, []),
- ct:log("All opts ~p~n", [All]),
- ok.
-
-
-%%--------------------------------------------------------------------
-socket_options() ->
- [{doc,"Test API function getopts/2 and setopts/2"}].
+ ServerOpts = ssl_test_lib:ssl_options(server_opts, Config),
-socket_options(Config) when is_list(Config) ->
- ClientOpts = ssl_test_lib:ssl_options(client_opts, Config),
- ServerOpts = ssl_test_lib:ssl_options(server_opts, Config),
{ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
- Values = [{mode, list}, {active, true}],
- %% Shall be the reverse order of Values!
- Options = [active, mode],
-
- NewValues = [{mode, binary}, {active, once}],
- %% Shall be the reverse order of NewValues!
- NewOptions = [active, mode],
-
Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0},
{from, self()},
- {mfa, {?MODULE, socket_options_result,
- [Options, Values, NewOptions, NewValues]}},
- {options, ServerOpts}]),
- Port = ssl_test_lib:inet_port(Server),
- Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port},
- {host, Hostname},
- {from, self()},
- {mfa, {?MODULE, socket_options_result,
- [Options, Values, NewOptions, NewValues]}},
- {options, ClientOpts}]),
-
- ssl_test_lib:check_result(Server, ok, Client, ok),
-
- ssl_test_lib:close(Server),
-
- {ok, Listen} = ssl:listen(0, ServerOpts),
- {ok,[{mode,list}]} = ssl:getopts(Listen, [mode]),
- ok = ssl:setopts(Listen, [{mode, binary}]),
- {ok,[{mode, binary}]} = ssl:getopts(Listen, [mode]),
- {ok,[{recbuf, _}]} = ssl:getopts(Listen, [recbuf]),
- ssl:close(Listen).
-
-
-socket_options_result(Socket, Options, DefaultValues, NewOptions, NewValues) ->
- %% Test get/set emulated opts
- {ok, DefaultValues} = ssl:getopts(Socket, Options),
- ssl:setopts(Socket, NewValues),
- {ok, NewValues} = ssl:getopts(Socket, NewOptions),
- %% Test get/set inet opts
- {ok,[{reuseaddr, _}]} = ssl:getopts(Socket, [reuseaddr]),
- {ok, All} = ssl:getopts(Socket, []),
- ct:log("All opts ~p~n", [All]),
- ok.
-
-
-%%--------------------------------------------------------------------
-invalid_inet_get_option() ->
- [{doc,"Test handling of invalid inet options in getopts"}].
-
-invalid_inet_get_option(Config) when is_list(Config) ->
- ClientOpts = ssl_test_lib:ssl_options(client_opts, Config),
- ServerOpts = ssl_test_lib:ssl_options(server_opts, Config),
- {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
- Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0},
- {from, self()},
- {mfa, {?MODULE, get_invalid_inet_option, []}},
- {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, no_result, []}},
- {options, ClientOpts}]),
-
- ct:log("Testcase ~p, Client ~p Server ~p ~n",
- [self(), Client, Server]),
-
- ssl_test_lib:check_result(Server, ok),
- ssl_test_lib:close(Server),
- ssl_test_lib:close(Client).
-
-%%--------------------------------------------------------------------
-invalid_inet_get_option_not_list() ->
- [{doc,"Test handling of invalid type in getopts"}].
-
-invalid_inet_get_option_not_list(Config) when is_list(Config) ->
- ClientOpts = ssl_test_lib:ssl_options(client_opts, Config),
- ServerOpts = ssl_test_lib:ssl_options(server_opts, Config),
- {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
- Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0},
- {from, self()},
- {mfa, {?MODULE, get_invalid_inet_option_not_list, []}},
- {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, no_result, []}},
- {options, ClientOpts}]),
-
- ct:log("Testcase ~p, Client ~p Server ~p ~n",
- [self(), Client, Server]),
-
- ssl_test_lib:check_result(Server, ok),
- ssl_test_lib:close(Server),
- ssl_test_lib:close(Client).
-
-
-get_invalid_inet_option_not_list(Socket) ->
- {error, {options, {socket_options, some_invalid_atom_here}}}
- = ssl:getopts(Socket, some_invalid_atom_here),
- ok.
-
-%%--------------------------------------------------------------------
-invalid_inet_get_option_improper_list() ->
- [{doc,"Test handling of invalid type in getopts"}].
-
-invalid_inet_get_option_improper_list(Config) when is_list(Config) ->
- ClientOpts = ssl_test_lib:ssl_options(client_opts, Config),
- ServerOpts = ssl_test_lib:ssl_options(server_opts, Config),
- {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
- Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0},
- {from, self()},
- {mfa, {?MODULE, get_invalid_inet_option_improper_list, []}},
- {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, no_result, []}},
- {options, ClientOpts}]),
-
- ct:log("Testcase ~p, Client ~p Server ~p ~n",
- [self(), Client, Server]),
-
- ssl_test_lib:check_result(Server, ok),
- ssl_test_lib:close(Server),
- ssl_test_lib:close(Client).
-
-
-get_invalid_inet_option_improper_list(Socket) ->
- {error, {options, {socket_options, foo,_}}} = ssl:getopts(Socket, [packet | foo]),
- ok.
-
-%%--------------------------------------------------------------------
-invalid_inet_set_option() ->
- [{doc,"Test handling of invalid inet options in setopts"}].
-
-invalid_inet_set_option(Config) when is_list(Config) ->
- ClientOpts = ssl_test_lib:ssl_options(client_opts, Config),
- ServerOpts = ssl_test_lib:ssl_options(server_opts, Config),
- {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
- Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0},
- {from, self()},
- {mfa, {?MODULE, set_invalid_inet_option, []}},
- {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, no_result, []}},
- {options, ClientOpts}]),
-
- ct:log("Testcase ~p, Client ~p Server ~p ~n",
- [self(), Client, Server]),
-
- ssl_test_lib:check_result(Server, ok),
- ssl_test_lib:close(Server),
- ssl_test_lib:close(Client).
-
-set_invalid_inet_option(Socket) ->
- {error, {options, {socket_options, {packet, foo}}}} = ssl:setopts(Socket, [{packet, foo}]),
- {error, {options, {socket_options, {header, foo}}}} = ssl:setopts(Socket, [{header, foo}]),
- {error, {options, {socket_options, {active, foo}}}} = ssl:setopts(Socket, [{active, foo}]),
- {error, {options, {socket_options, {mode, foo}}}} = ssl:setopts(Socket, [{mode, foo}]),
- ok.
-%%--------------------------------------------------------------------
-invalid_inet_set_option_not_list() ->
- [{doc,"Test handling of invalid type in setopts"}].
-
-invalid_inet_set_option_not_list(Config) when is_list(Config) ->
- ClientOpts = ssl_test_lib:ssl_options(client_opts, Config),
- ServerOpts = ssl_test_lib:ssl_options(server_opts, Config),
- {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
- Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0},
- {from, self()},
- {mfa, {?MODULE, set_invalid_inet_option_not_list, []}},
- {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, no_result, []}},
- {options, ClientOpts}]),
-
- ct:log("Testcase ~p, Client ~p Server ~p ~n",
- [self(), Client, Server]),
-
- ssl_test_lib:check_result(Server, ok),
- ssl_test_lib:close(Server),
- ssl_test_lib:close(Client).
-
-
-set_invalid_inet_option_not_list(Socket) ->
- {error, {options, {not_a_proplist, some_invalid_atom_here}}}
- = ssl:setopts(Socket, some_invalid_atom_here),
- ok.
-
-%%--------------------------------------------------------------------
-invalid_inet_set_option_improper_list() ->
- [{doc,"Test handling of invalid tye in setopts"}].
-
-invalid_inet_set_option_improper_list(Config) when is_list(Config) ->
- ClientOpts = ssl_test_lib:ssl_options(client_opts, Config),
- ServerOpts = ssl_test_lib:ssl_options(server_opts, Config),
- {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
- Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0},
- {from, self()},
- {mfa, {?MODULE, set_invalid_inet_option_improper_list, []}},
- {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, no_result, []}},
- {options, ClientOpts}]),
-
- ct:log("Testcase ~p, Client ~p Server ~p ~n",
- [self(), Client, Server]),
-
- ssl_test_lib:check_result(Server, ok),
- ssl_test_lib:close(Server),
- ssl_test_lib:close(Client).
-
-set_invalid_inet_option_improper_list(Socket) ->
- {error, {options, {not_a_proplist, [{packet, 0} | {foo, 2}]}}} =
- ssl:setopts(Socket, [{packet, 0} | {foo, 2}]),
- ok.
-
-%%--------------------------------------------------------------------
-tls_misc_ssl_options() ->
- [{doc,"Test what happens when we give valid options"}].
-
-tls_misc_ssl_options(Config) when is_list(Config) ->
- ClientOpts = ssl_test_lib:ssl_options(client_opts, Config),
- ServerOpts = ssl_test_lib:ssl_options(server_opts, Config),
- {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
-
- %% Check that ssl options not tested elsewhere are filtered away e.i. not passed to inet.
- TestOpts = [{depth, 1},
- {key, undefined},
- {password, []},
- {reuse_session, fun(_,_,_,_) -> true end},
- {cb_info, {gen_tcp, tcp, tcp_closed, tcp_error}}],
-
- Server =
- ssl_test_lib:start_server([{node, ServerNode}, {port, 0},
- {from, self()},
- {mfa, {ssl_test_lib, send_recv_result_active, []}},
- {options, TestOpts ++ ServerOpts}]),
- Port = ssl_test_lib:inet_port(Server),
- Client =
- ssl_test_lib:start_client([{node, ClientNode}, {port, Port},
- {host, Hostname},
- {from, self()},
- {mfa, {ssl_test_lib, send_recv_result_active, []}},
- {options, TestOpts ++ ClientOpts}]),
-
- ct:log("Testcase ~p, Client ~p Server ~p ~n",
- [self(), Client, Server]),
-
- ssl_test_lib:check_result(Server, ok, Client, ok),
- ssl_test_lib:close(Server),
- ssl_test_lib:close(Client).
-
-%%--------------------------------------------------------------------
-ssl_options_not_proplist() ->
- [{doc,"Test what happens if an option is not a key value tuple"}].
-
-ssl_options_not_proplist(Config) when is_list(Config) ->
- BadOption = {client_preferred_next_protocols,
- client, [<<"spdy/3">>,<<"http/1.1">>], <<"http/1.1">>},
- {option_not_a_key_value_tuple, BadOption} =
- ssl:connect("twitter.com", 443, [binary, {active, false},
- BadOption]).
-
-%%--------------------------------------------------------------------
-raw_ssl_option() ->
- [{doc,"Ensure that a single 'raw' option is passed to ssl:listen correctly."}].
-
-raw_ssl_option(Config) when is_list(Config) ->
- % 'raw' option values are platform-specific; these are the Linux values:
- IpProtoTcp = 6,
- % Use TCP_KEEPIDLE, because (e.g.) TCP_MAXSEG can't be read back reliably.
- TcpKeepIdle = 4,
- KeepAliveTimeSecs = 55,
- LOptions = [{raw, IpProtoTcp, TcpKeepIdle, <<KeepAliveTimeSecs:32/native>>}],
- {ok, LSocket} = ssl:listen(0, LOptions),
- % Per http://www.erlang.org/doc/man/inet.html#getopts-2, we have to specify
- % exactly which raw option we want, and the size of the buffer.
- {ok, [{raw, IpProtoTcp, TcpKeepIdle, <<KeepAliveTimeSecs:32/native>>}]} = ssl:getopts(LSocket, [{raw, IpProtoTcp, TcpKeepIdle, 4}]).
-
-
-%%--------------------------------------------------------------------
-versions() ->
- [{doc,"Test API function versions/0"}].
-
-versions(Config) when is_list(Config) ->
- [_|_] = Versions = ssl:versions(),
- ct:log("~p~n", [Versions]).
-
-
-%%--------------------------------------------------------------------
-eccs() ->
- [{doc, "Test API functions eccs/0 and eccs/1"}].
-
-eccs(Config) when is_list(Config) ->
- [_|_] = All = ssl:eccs(),
- [] = SSL3 = ssl:eccs(sslv3),
- [_|_] = Tls = ssl:eccs(tlsv1),
- [_|_] = Tls1 = ssl:eccs('tlsv1.1'),
- [_|_] = Tls2 = ssl:eccs('tlsv1.2'),
- [_|_] = Tls1 = ssl:eccs('dtlsv1'),
- [_|_] = Tls2 = ssl:eccs('dtlsv1.2'),
- %% ordering is currently unverified by the test
- true = lists:sort(All) =:= lists:usort(SSL3 ++ Tls ++ Tls1 ++ Tls2),
- ok.
-
-%%--------------------------------------------------------------------
-send_recv() ->
- [{doc,""}].
-send_recv(Config) when is_list(Config) ->
- ClientOpts = ssl_test_lib:ssl_options(client_opts, Config),
- ServerOpts = ssl_test_lib:ssl_options(server_opts, Config),
- {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
- Server =
- ssl_test_lib:start_server([{node, ServerNode}, {port, 0},
- {from, self()},
- {mfa, {ssl_test_lib, send_recv_result, []}},
- {options, [{active, false} | ServerOpts]}]),
- Port = ssl_test_lib:inet_port(Server),
- Client =
- ssl_test_lib:start_client([{node, ClientNode}, {port, Port},
- {host, Hostname},
- {from, self()},
- {mfa, {ssl_test_lib, send_recv_result, []}},
- {options, [{active, false} | ClientOpts]}]),
-
- ct:log("Testcase ~p, Client ~p Server ~p ~n",
- [self(), Client, Server]),
-
- ssl_test_lib:check_result(Server, ok, Client, ok),
-
- ssl_test_lib:close(Server),
- ssl_test_lib:close(Client).
-
-%%--------------------------------------------------------------------
-tls_send_close() ->
- [{doc,""}].
-tls_send_close(Config) when is_list(Config) ->
- ClientOpts = ssl_test_lib:ssl_options(client_opts, Config),
- ServerOpts = ssl_test_lib:ssl_options(server_opts, Config),
- {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
- Server =
- ssl_test_lib:start_server([{node, ServerNode}, {port, 0},
- {from, self()},
- {mfa, {ssl_test_lib, send_recv_result, []}},
- {options, [{active, false} | ServerOpts]}]),
- Port = ssl_test_lib:inet_port(Server),
- {ok, TcpS} = rpc:call(ClientNode, gen_tcp, connect,
- [Hostname,Port,[binary, {active, false}]]),
- {ok, SslS} = rpc:call(ClientNode, ssl, connect,
- [TcpS,[{active, false}|ClientOpts]]),
-
- ct:log("Testcase ~p, Client ~p Server ~p ~n",
- [self(), self(), Server]),
- ok = ssl:send(SslS, "Hello world"),
- {ok,<<"Hello world">>} = ssl:recv(SslS, 11),
- gen_tcp:close(TcpS),
- {error, _} = ssl:send(SslS, "Hello world").
-
-%%--------------------------------------------------------------------
-version_option() ->
- [{doc, "Use version option and do no specify ciphers list. Bug specified incorrect ciphers"}].
-version_option(Config) when is_list(Config) ->
- Versions = proplists:get_value(supported, ssl:versions()),
- [version_option_test(Config, Version) || Version <- Versions].
-
-%%--------------------------------------------------------------------
-close_transport_accept() ->
- [{doc,"Tests closing ssl socket when waiting on ssl:transport_accept/1"}].
-
-close_transport_accept(Config) when is_list(Config) ->
- ServerOpts = ssl_test_lib:ssl_options(server_opts, Config),
- {_ClientNode, ServerNode, _Hostname} = ssl_test_lib:run_where(Config),
-
- Port = 0,
- Opts = [{active, false} | ServerOpts],
- {ok, ListenSocket} = rpc:call(ServerNode, ssl, listen, [Port, Opts]),
- spawn_link(fun() ->
- ct:sleep(?SLEEP),
- rpc:call(ServerNode, ssl, close, [ListenSocket])
- end),
- case rpc:call(ServerNode, ssl, transport_accept, [ListenSocket]) of
- {error, closed} ->
- ok;
- Other ->
- exit({?LINE, Other})
- end.
-%%--------------------------------------------------------------------
-recv_active() ->
- [{doc,"Test recv on active socket"}].
-
-recv_active(Config) when is_list(Config) ->
- ClientOpts = ssl_test_lib:ssl_options(client_opts, Config),
- ServerOpts = ssl_test_lib:ssl_options(server_opts, Config),
- {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
- Server =
- ssl_test_lib:start_server([{node, ServerNode}, {port, 0},
- {from, self()},
- {mfa, {?MODULE, try_recv_active, []}},
- {options, [{active, true} | ServerOpts]}]),
- Port = ssl_test_lib:inet_port(Server),
- Client =
- ssl_test_lib:start_client([{node, ClientNode}, {port, Port},
- {host, Hostname},
- {from, self()},
- {mfa, {?MODULE, try_recv_active, []}},
- {options, [{active, true} | ClientOpts]}]),
-
- ssl_test_lib:check_result(Server, ok, Client, ok),
-
- ssl_test_lib:close(Server),
- ssl_test_lib:close(Client).
-
-%%--------------------------------------------------------------------
-recv_active_once() ->
- [{doc,"Test recv on active (once) socket"}].
-
-recv_active_once(Config) when is_list(Config) ->
- ClientOpts = ssl_test_lib:ssl_options(client_opts, Config),
- ServerOpts = ssl_test_lib:ssl_options(server_opts, Config),
- {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
- Server =
- ssl_test_lib:start_server([{node, ServerNode}, {port, 0},
- {from, self()},
- {mfa, {?MODULE, try_recv_active_once, []}},
- {options, [{active, once} | ServerOpts]}]),
+ {mfa, {?MODULE, protocol_info_result, []}},
+ {options, [{versions, ['tlsv1.1', 'tlsv1.2']} | ServerOpts]}]),
Port = ssl_test_lib:inet_port(Server),
- Client =
- ssl_test_lib:start_client([{node, ClientNode}, {port, Port},
- {host, Hostname},
- {from, self()},
- {mfa, {?MODULE, try_recv_active_once, []}},
- {options, [{active, once} | ClientOpts]}]),
-
- ssl_test_lib:check_result(Server, ok, Client, ok),
- ssl_test_lib:close(Server),
- ssl_test_lib:close(Client).
-
-
-
-
-
-%%--------------------------------------------------------------------
-recv_active_n() ->
- [{doc,"Test recv on active (n) socket"}].
-
-recv_active_n(Config) when is_list(Config) ->
- ClientOpts = ssl_test_lib:ssl_options(client_opts, Config),
- ServerOpts = ssl_test_lib:ssl_options(server_opts, Config),
- {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
- Server =
- ssl_test_lib:start_server([{node, ServerNode}, {port, 0},
- {from, self()},
- {mfa, {?MODULE, try_recv_active_once, []}},
- {options, [{active, 1} | ServerOpts]}]),
- Port = ssl_test_lib:inet_port(Server),
- Client =
- ssl_test_lib:start_client([{node, ClientNode}, {port, Port},
- {host, Hostname},
- {from, self()},
- {mfa, {?MODULE, try_recv_active_once, []}},
- {options, [{active, 1} | ClientOpts]}]),
-
- ssl_test_lib:check_result(Server, ok, Client, ok),
-
- ssl_test_lib:close(Server),
- ssl_test_lib:close(Client).
-
-
-%%--------------------------------------------------------------------
-%% Test case adapted from gen_tcp_misc_SUITE.
-active_n() ->
- [{doc,"Test {active,N} option"}].
-
-active_n(Config) when is_list(Config) ->
- ClientOpts = ssl_test_lib:ssl_options(client_opts, Config),
- ServerOpts = ssl_test_lib:ssl_options(server_opts, Config),
- Port = ssl_test_lib:inet_port(node()),
- N = 3,
- LS = ok(ssl:listen(Port, [{active,N}|ServerOpts])),
- [{active,N}] = ok(ssl:getopts(LS, [active])),
- active_n_common(LS, N),
- Self = self(),
- spawn_link(fun() ->
- S0 = ok(ssl:transport_accept(LS)),
- {ok, S} = ssl:handshake(S0),
- ok = ssl:setopts(S, [{active,N}]),
- [{active,N}] = ok(ssl:getopts(S, [active])),
- ssl:controlling_process(S, Self),
- Self ! {server, S}
- end),
- C = ok(ssl:connect("localhost", Port, [{active,N}|ClientOpts])),
- [{active,N}] = ok(ssl:getopts(C, [active])),
- S = receive
- {server, S0} -> S0
- after
- 1000 ->
- exit({error, connect})
- end,
- active_n_common(C, N),
- active_n_common(S, N),
- ok = ssl:setopts(C, [{active,N}]),
- ok = ssl:setopts(S, [{active,N}]),
- ReceiveMsg = fun(Socket, Msg) ->
- receive
- {ssl,Socket,Msg} ->
- ok;
- {ssl,Socket,Begin} ->
- receive
- {ssl,Socket,End} ->
- Msg = Begin ++ End,
- ok
- after 1000 ->
- exit(timeout)
- end
- after 1000 ->
- exit(timeout)
- end
- end,
- repeat(3, fun(I) ->
- Msg = "message "++integer_to_list(I),
- ok = ssl:send(C, Msg),
- ReceiveMsg(S, Msg),
- ok = ssl:send(S, Msg),
- ReceiveMsg(C, Msg)
- end),
- receive
- {ssl_passive,S} ->
- [{active,false}] = ok(ssl:getopts(S, [active]))
- after
- 1000 ->
- exit({error,ssl_passive})
- end,
- receive
- {ssl_passive,C} ->
- [{active,false}] = ok(ssl:getopts(C, [active]))
- after
- 1000 ->
- exit({error,ssl_passive})
- end,
- LS2 = ok(ssl:listen(0, [{active,0}])),
- receive
- {ssl_passive,LS2} ->
- [{active,false}] = ok(ssl:getopts(LS2, [active]))
- after
- 1000 ->
- exit({error,ssl_passive})
- end,
- ok = ssl:close(LS2),
- ok = ssl:close(C),
- ok = ssl:close(S),
- ok = ssl:close(LS),
- ok.
-
-active_n_common(S, N) ->
- ok = ssl:setopts(S, [{active,-N}]),
- receive
- {ssl_passive, S} -> ok
- after
- 1000 ->
- error({error,ssl_passive_failure})
- end,
- [{active,false}] = ok(ssl:getopts(S, [active])),
- ok = ssl:setopts(S, [{active,0}]),
- receive
- {ssl_passive, S} -> ok
- after
- 1000 ->
- error({error,ssl_passive_failure})
- end,
- ok = ssl:setopts(S, [{active,32767}]),
- {error,{options,_}} = ssl:setopts(S, [{active,1}]),
- {error,{options,_}} = ssl:setopts(S, [{active,-32769}]),
- ok = ssl:setopts(S, [{active,-32768}]),
- receive
- {ssl_passive, S} -> ok
- after
- 1000 ->
- error({error,ssl_passive_failure})
- end,
- [{active,false}] = ok(ssl:getopts(S, [active])),
- ok = ssl:setopts(S, [{active,N}]),
- ok = ssl:setopts(S, [{active,true}]),
- [{active,true}] = ok(ssl:getopts(S, [active])),
- receive
- _ -> error({error,active_n})
- after
- 0 ->
- ok
- end,
- ok = ssl:setopts(S, [{active,N}]),
- ok = ssl:setopts(S, [{active,once}]),
- [{active,once}] = ok(ssl:getopts(S, [active])),
- receive
- _ -> error({error,active_n})
- after
- 0 ->
- ok
- end,
- {error,{options,_}} = ssl:setopts(S, [{active,32768}]),
- ok = ssl:setopts(S, [{active,false}]),
- [{active,false}] = ok(ssl:getopts(S, [active])),
- ok.
-
-ok({ok,V}) -> V.
-
-repeat(N, Fun) ->
- repeat(N, N, Fun).
-
-repeat(N, T, Fun) when is_integer(N), N > 0 ->
- Fun(T-N),
- repeat(N-1, T, Fun);
-repeat(_, _, _) ->
- ok.
-
-%%--------------------------------------------------------------------
-dh_params() ->
- [{doc,"Test to specify DH-params file in server."}].
-
-dh_params(Config) when is_list(Config) ->
- ClientOpts = ssl_test_lib:ssl_options(client_opts, Config),
- ServerOpts = ssl_test_lib:ssl_options(server_opts, Config),
- DataDir = proplists:get_value(data_dir, Config),
- DHParamFile = filename:join(DataDir, "dHParam.pem"),
-
- {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
-
- Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0},
- {from, self()},
- {mfa, {ssl_test_lib, send_recv_result_active, []}},
- {options, [{dhfile, DHParamFile} | ServerOpts]}]),
- Port = ssl_test_lib:inet_port(Server),
Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port},
{host, Hostname},
- {from, self()},
- {mfa, {ssl_test_lib, send_recv_result_active, []}},
- {options,
- [{ciphers,[{dhe_rsa,aes_256_cbc,sha}]} |
- ClientOpts]}]),
-
- ssl_test_lib:check_result(Server, ok, Client, ok),
-
- ssl_test_lib:close(Server),
- ssl_test_lib:close(Client).
-
-%%--------------------------------------------------------------------
-tls_upgrade() ->
- [{doc,"Test that you can upgrade an tcp connection to an ssl connection"}].
-
-tls_upgrade(Config) when is_list(Config) ->
- ClientOpts = ssl_test_lib:ssl_options(client_opts, Config),
- ServerOpts = ssl_test_lib:ssl_options(server_opts, Config),
- {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
- TcpOpts = [binary, {reuseaddr, true}],
-
- Server = ssl_test_lib:start_upgrade_server([{node, ServerNode}, {port, 0},
- {from, self()},
- {mfa, {?MODULE,
- upgrade_result, []}},
- {tcp_options,
- [{active, false} | TcpOpts]},
- {ssl_options, ServerOpts}]),
- Port = ssl_test_lib:inet_port(Server),
- Client = ssl_test_lib:start_upgrade_client([{node, ClientNode},
- {port, Port},
- {host, Hostname},
- {from, self()},
- {mfa, {?MODULE, upgrade_result, []}},
- {tcp_options, [binary]},
- {ssl_options, ClientOpts}]),
-
- ct:log("Testcase ~p, Client ~p Server ~p ~n",
- [self(), Client, Server]),
-
- ssl_test_lib:check_result(Server, ok, Client, ok),
-
- ssl_test_lib:close(Server),
- ssl_test_lib:close(Client).
-
-upgrade_result(Socket) ->
- ssl:setopts(Socket, [{active, true}]),
- ok = ssl:send(Socket, "Hello world"),
- %% Make sure binary is inherited from tcp socket and that we do
- %% not get the list default!
- receive
- {ssl, _, <<"H">>} ->
- receive
- {ssl, _, <<"ello world">>} ->
- ok
- end;
- {ssl, _, <<"Hello world">>} ->
- ok
- end.
-
-
-%%--------------------------------------------------------------------
-internal_active_1() ->
- [{doc,"Test internal active 1 (behave as internal active once)"}].
-
-internal_active_1(Config) when is_list(Config) ->
- ClientOpts = ssl_test_lib:ssl_options(client_opts, Config),
- ServerOpts = ssl_test_lib:ssl_options(server_opts, Config),
- {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
- Server =
- ssl_test_lib:start_server([{node, ServerNode}, {port, 0},
- {from, self()},
- {mfa, {ssl_test_lib, send_recv_result_active, []}},
- {options, [{active, true} | ServerOpts]}]),
- Port = ssl_test_lib:inet_port(Server),
- Client =
- ssl_test_lib:start_client([{node, ClientNode}, {port, Port},
- {host, Hostname},
- {from, self()},
- {mfa, {ssl_test_lib, send_recv_result_active, []}},
- {options, [{active, true} | ClientOpts]}]),
-
- ssl_test_lib:check_result(Server, ok, Client, ok),
-
- ssl_test_lib:close(Server),
- ssl_test_lib:close(Client).
-
-%%--------------------------------------------------------------------
-tls_upgrade_with_timeout() ->
- [{doc,"Test ssl_accept/3"}].
-
-tls_upgrade_with_timeout(Config) when is_list(Config) ->
- ClientOpts = ssl_test_lib:ssl_options(client_opts, Config),
- ServerOpts = ssl_test_lib:ssl_options(server_opts, Config),
- {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
- TcpOpts = [binary, {reuseaddr, true}],
-
- Server = ssl_test_lib:start_upgrade_server([{node, ServerNode}, {port, 0},
- {from, self()},
- {timeout, 5000},
- {mfa, {?MODULE,
- upgrade_result, []}},
- {tcp_options,
- [{active, false} | TcpOpts]},
- {ssl_options, ServerOpts}]),
- Port = ssl_test_lib:inet_port(Server),
- Client = ssl_test_lib:start_upgrade_client([{node, ClientNode},
- {port, Port},
- {host, Hostname},
- {from, self()},
- {mfa, {?MODULE, upgrade_result, []}},
- {tcp_options, TcpOpts},
- {ssl_options, ClientOpts}]),
-
- ct:log("Testcase ~p, Client ~p Server ~p ~n",
- [self(), Client, Server]),
-
- ssl_test_lib:check_result(Server, ok, Client, ok),
-
- ssl_test_lib:close(Server),
- ssl_test_lib:close(Client).
-
-%%--------------------------------------------------------------------
-tls_downgrade() ->
- [{doc,"Test that you can downgarde an ssl connection to an tcp connection"}].
-tls_downgrade(Config) when is_list(Config) ->
- ClientOpts = ssl_test_lib:ssl_options(client_opts, Config),
- ServerOpts = ssl_test_lib:ssl_options(server_opts, Config),
-
- {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
-
- Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0},
- {from, self()},
- {mfa, {?MODULE, tls_downgrade_result, [self()]}},
- {options, [{active, false} | ServerOpts]}]),
- Port = ssl_test_lib:inet_port(Server),
- Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port},
- {host, Hostname},
- {from, self()},
- {mfa, {?MODULE, tls_downgrade_result, [self()]}},
- {options, [{active, false} |ClientOpts]}]),
-
-
- ssl_test_lib:check_result(Server, ready, Client, ready),
-
- Server ! go,
- Client ! go,
-
- ssl_test_lib:check_result(Server, ok, Client, ok),
- ssl_test_lib:close(Server),
- ssl_test_lib:close(Client).
-
-%%--------------------------------------------------------------------
-close_with_timeout() ->
- [{doc,"Test normal (not downgrade) ssl:close/2"}].
-close_with_timeout(Config) when is_list(Config) ->
- ClientOpts = ssl_test_lib:ssl_options(client_opts, Config),
- ServerOpts = ssl_test_lib:ssl_options(server_opts, Config),
-
- {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
-
- Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0},
- {from, self()},
- {mfa, {?MODULE, tls_close, []}},
- {options,[{active, false} | ServerOpts]}]),
- Port = ssl_test_lib:inet_port(Server),
- Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port},
- {host, Hostname},
- {from, self()},
- {mfa, {?MODULE, tls_close, []}},
- {options, [{active, false} |ClientOpts]}]),
-
- ssl_test_lib:check_result(Server, ok, Client, ok).
-
-
-%%--------------------------------------------------------------------
-tls_tcp_connect() ->
- [{doc,"Test what happens when a tcp tries to connect, i,e. a bad (ssl) packet is sent first"}].
-
-tls_tcp_connect(Config) when is_list(Config) ->
- ServerOpts = ssl_test_lib:ssl_options(server_opts, Config),
- {_, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
- TcpOpts = [binary, {reuseaddr, true}, {active, false}],
-
- Server = ssl_test_lib:start_upgrade_server_error([{node, ServerNode}, {port, 0},
- {from, self()},
- {timeout, 5000},
- {mfa, {?MODULE, dummy, []}},
- {tcp_options, TcpOpts},
- {ssl_options, ServerOpts}]),
- Port = ssl_test_lib:inet_port(Server),
-
- {ok, Socket} = gen_tcp:connect(Hostname, Port, [binary, {packet, 0}]),
- ct:log("Testcase ~p connected to Server ~p ~n", [self(), Server]),
- gen_tcp:send(Socket, "<SOME GARBLED NON SSL MESSAGE>"),
-
- receive
- {tcp_closed, Socket} ->
- receive
- {Server, {error, Error}} ->
- ct:log("Error ~p", [Error])
- end
- end.
-%%--------------------------------------------------------------------
-tls_tcp_connect_big() ->
- [{doc,"Test what happens when a tcp tries to connect, i,e. a bad big (ssl) packet is sent first"}].
-
-tls_tcp_connect_big(Config) when is_list(Config) ->
- process_flag(trap_exit, true),
- ServerOpts = ssl_test_lib:ssl_options(server_opts, Config),
- {_, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
- TcpOpts = [binary, {reuseaddr, true}],
-
- Rand = crypto:strong_rand_bytes(?MAX_CIPHER_TEXT_LENGTH+1),
- Server = ssl_test_lib:start_upgrade_server_error([{node, ServerNode}, {port, 0},
- {from, self()},
- {timeout, 5000},
- {mfa, {?MODULE, dummy, []}},
- {tcp_options, TcpOpts},
- {ssl_options, ServerOpts}]),
- Port = ssl_test_lib:inet_port(Server),
-
- {ok, Socket} = gen_tcp:connect(Hostname, Port, [binary, {packet, 0}]),
- ct:log("Testcase ~p connected to Server ~p ~n", [self(), Server]),
-
- gen_tcp:send(Socket, <<?BYTE(0),
- ?BYTE(3), ?BYTE(1), ?UINT16(?MAX_CIPHER_TEXT_LENGTH), Rand/binary>>),
-
- receive
- {tcp_closed, Socket} ->
- receive
- {Server, {error, timeout}} ->
- ct:fail("hangs");
- {Server, {error, Error}} ->
- ct:log("Error ~p", [Error]);
- {'EXIT', Server, _} ->
- ok
- end
- end.
-
-%%--------------------------------------------------------------------
-ipv6() ->
- [{require, ipv6_hosts},
- {doc,"Test ipv6."}].
-ipv6(Config) when is_list(Config) ->
- {ok, Hostname0} = inet:gethostname(),
-
- case lists:member(list_to_atom(Hostname0), ct:get_config(ipv6_hosts)) of
- true ->
- ClientOpts = ssl_test_lib:ssl_options(client_opts, Config),
- ServerOpts = ssl_test_lib:ssl_options(server_opts, Config),
- {ClientNode, ServerNode, Hostname} =
- ssl_test_lib:run_where(Config, ipv6),
- Server = ssl_test_lib:start_server([{node, ServerNode},
- {port, 0}, {from, self()},
- {mfa, {ssl_test_lib, send_recv_result, []}},
- {options,
- [inet6, {active, false} | ServerOpts]}]),
- Port = ssl_test_lib:inet_port(Server),
- Client = ssl_test_lib:start_client([{node, ClientNode},
- {port, Port}, {host, Hostname},
- {from, self()},
- {mfa, {ssl_test_lib, send_recv_result, []}},
- {options,
- [inet6, {active, false} | ClientOpts]}]),
-
- ct:log("Testcase ~p, Client ~p Server ~p ~n",
- [self(), Client, Server]),
-
- ssl_test_lib:check_result(Server, ok, Client, ok),
-
- ssl_test_lib:close(Server),
- ssl_test_lib:close(Client);
- false ->
- {skip, "Host does not support IPv6"}
- end.
-
-%%--------------------------------------------------------------------
-
-invalid_keyfile() ->
- [{doc,"Test what happens with an invalid key file"}].
-invalid_keyfile(Config) when is_list(Config) ->
- ClientOpts = ssl_test_lib:ssl_options(client_opts, Config),
- BadOpts = ssl_test_lib:ssl_options(server_bad_key, Config),
- {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
-
- Server =
- ssl_test_lib:start_server_error([{node, ServerNode}, {port, 0},
- {from, self()},
- {options, BadOpts}]),
-
- Port = ssl_test_lib:inet_port(Server),
-
- Client =
- ssl_test_lib:start_client_error([{node, ClientNode},
- {port, Port}, {host, Hostname},
- {from, self()}, {options, ClientOpts}]),
+ {from, self()},
+ {mfa, {?MODULE, protocol_info_result, []}},
+ {options, ClientOpts}]),
- File = proplists:get_value(keyfile,BadOpts),
- ssl_test_lib:check_result(Server, {error,{options, {keyfile, File, {error,enoent}}}}, Client,
- {error, closed}).
+ ServerMsg = ClientMsg = {ok,'tlsv1.2'},
+ ssl_test_lib:check_result(Server, ServerMsg, Client, ClientMsg).
%%--------------------------------------------------------------------
+unordered_protocol_versions_client() ->
+ [{doc,"Test that the highest protocol is selected even"
+ " when it is not first in the versions list."}].
-invalid_certfile() ->
- [{doc,"Test what happens with an invalid cert file"}].
-
-invalid_certfile(Config) when is_list(Config) ->
+unordered_protocol_versions_client(Config) when is_list(Config) ->
ClientOpts = ssl_test_lib:ssl_options(client_opts, Config),
- ServerBadOpts = ssl_test_lib:ssl_options(server_bad_cert, Config),
- {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
-
- Server =
- ssl_test_lib:start_server_error([{node, ServerNode}, {port, 0},
- {from, self()},
- {options, ServerBadOpts}]),
-
- Port = ssl_test_lib:inet_port(Server),
-
- Client =
- ssl_test_lib:start_client_error([{node, ClientNode},
- {port, Port}, {host, Hostname},
- {from, self()},
- {options, ClientOpts}]),
- File = proplists:get_value(certfile, ServerBadOpts),
- ssl_test_lib:check_result(Server, {error,{options, {certfile, File, {error,enoent}}}},
- Client, {error, closed}).
-
-
-%%--------------------------------------------------------------------
-invalid_cacertfile() ->
- [{doc,"Test what happens with an invalid cacert file"}].
-
-invalid_cacertfile(Config) when is_list(Config) ->
- ClientOpts = [{reuseaddr, true}|ssl_test_lib:ssl_options(client_opts, Config)],
- ServerBadOpts = [{reuseaddr, true}|ssl_test_lib:ssl_options(server_bad_ca, Config)],
- {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
-
- Server0 =
- ssl_test_lib:start_server_error([{node, ServerNode},
- {port, 0}, {from, self()},
- {options, ServerBadOpts}]),
-
- Port0 = ssl_test_lib:inet_port(Server0),
-
-
- Client0 =
- ssl_test_lib:start_client_error([{node, ClientNode},
- {port, Port0}, {host, Hostname},
- {from, self()},
- {options, ClientOpts}]),
-
- File0 = proplists:get_value(cacertfile, ServerBadOpts),
-
- ssl_test_lib:check_result(Server0, {error, {options, {cacertfile, File0,{error,enoent}}}},
- Client0, {error, closed}),
-
- File = File0 ++ "do_not_exit.pem",
- ServerBadOpts1 = [{cacertfile, File}|proplists:delete(cacertfile, ServerBadOpts)],
-
- Server1 =
- ssl_test_lib:start_server_error([{node, ServerNode},
- {port, 0}, {from, self()},
- {options, ServerBadOpts1}]),
-
- Port1 = ssl_test_lib:inet_port(Server1),
-
- Client1 =
- ssl_test_lib:start_client_error([{node, ClientNode},
- {port, Port1}, {host, Hostname},
- {from, self()},
- {options, ClientOpts}]),
-
-
- ssl_test_lib:check_result(Server1, {error, {options, {cacertfile, File,{error,enoent}}}},
- Client1, {error, closed}),
- ok.
-
-
-
-%%--------------------------------------------------------------------
-invalid_options() ->
- [{doc,"Test what happens when we give invalid options"}].
-
-invalid_options(Config) when is_list(Config) ->
- ClientOpts = ssl_test_lib:ssl_options(client_rsa_verify_opts, Config),
- ServerOpts = ssl_test_lib:ssl_options(server_rsa_opts, Config),
- {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
-
- Check = fun(Client, Server, {versions, [sslv2, sslv3]} = Option) ->
- ssl_test_lib:check_result(Server,
- {error, {options, {sslv2, Option}}},
- Client,
- {error, {options, {sslv2, Option}}});
- (Client, Server, Option) ->
- ssl_test_lib:check_result(Server,
- {error, {options, Option}},
- Client,
- {error, {options, Option}})
- end,
-
- TestOpts =
- [{versions, [sslv2, sslv3]},
- {verify, 4},
- {verify_fun, function},
- {fail_if_no_peer_cert, 0},
- {verify_client_once, 1},
- {depth, four},
- {certfile, 'cert.pem'},
- {keyfile,'key.pem' },
- {password, foo},
- {cacertfile, ""},
- {dhfile,'dh.pem' },
- {ciphers, [{foo, bar, sha, ignore}]},
- {reuse_session, foo},
- {reuse_sessions, 0},
- {renegotiate_at, "10"},
- {mode, depech},
- {packet, 8.0},
- {packet_size, "2"},
- {header, a},
- {active, trice},
- {key, 'key.pem' }],
-
- [begin
- Server =
- ssl_test_lib:start_server_error([{node, ServerNode}, {port, 0},
- {from, self()},
- {options, [TestOpt | ServerOpts]}]),
- %% Will never reach a point where port is used.
- Client =
- ssl_test_lib:start_client_error([{node, ClientNode}, {port, 0},
- {host, Hostname}, {from, self()},
- {options, [TestOpt | ClientOpts]}]),
- Check(Client, Server, TestOpt),
- ok
- end || TestOpt <- TestOpts],
- ok.
+ ServerOpts = ssl_test_lib:ssl_options(server_opts, Config),
-%%--------------------------------------------------------------------
-tls_shutdown() ->
- [{doc,"Test API function ssl:shutdown/2"}].
-tls_shutdown(Config) when is_list(Config) ->
- ClientOpts = ssl_test_lib:ssl_options(client_opts, Config),
- ServerOpts = ssl_test_lib:ssl_options(server_opts, Config),
{ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0},
{from, self()},
- {mfa, {?MODULE, tls_shutdown_result, [server]}},
- {options, [{exit_on_close, false},
- {active, false} | ServerOpts]}]),
+ {mfa, {?MODULE, protocol_info_result, []}},
+ {options, ServerOpts }]),
Port = ssl_test_lib:inet_port(Server),
- Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port},
- {host, Hostname},
- {from, self()},
- {mfa,
- {?MODULE, tls_shutdown_result, [client]}},
- {options,
- [{exit_on_close, false},
- {active, false} | ClientOpts]}]),
-
- ssl_test_lib:check_result(Server, ok, Client, ok),
- ssl_test_lib:close(Server),
- ssl_test_lib:close(Client).
-
-%%--------------------------------------------------------------------
-tls_shutdown_write() ->
- [{doc,"Test API function ssl:shutdown/2 with option write."}].
-tls_shutdown_write(Config) when is_list(Config) ->
- ClientOpts = ssl_test_lib:ssl_options(client_opts, Config),
- ServerOpts = ssl_test_lib:ssl_options(server_opts, Config),
- {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
- Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0},
- {from, self()},
- {mfa, {?MODULE, tls_shutdown_write_result, [server]}},
- {options, [{active, false} | ServerOpts]}]),
- Port = ssl_test_lib:inet_port(Server),
Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port},
{host, Hostname},
- {from, self()},
- {mfa, {?MODULE, tls_shutdown_write_result, [client]}},
- {options, [{active, false} | ClientOpts]}]),
-
- ssl_test_lib:check_result(Server, ok, Client, {error, closed}).
-
-%%--------------------------------------------------------------------
-tls_shutdown_both() ->
- [{doc,"Test API function ssl:shutdown/2 with option both."}].
-tls_shutdown_both(Config) when is_list(Config) ->
- ClientOpts = ssl_test_lib:ssl_options(client_opts, Config),
- ServerOpts = ssl_test_lib:ssl_options(server_opts, Config),
- {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
- Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0},
{from, self()},
- {mfa, {?MODULE, tls_shutdown_both_result, [server]}},
- {options, [{active, false} | ServerOpts]}]),
- Port = ssl_test_lib:inet_port(Server),
- Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port},
- {host, Hostname},
- {from, self()},
- {mfa, {?MODULE, tls_shutdown_both_result, [client]}},
- {options, [{active, false} | ClientOpts]}]),
-
- ssl_test_lib:check_result(Server, ok, Client, {error, closed}).
-
-%%--------------------------------------------------------------------
-tls_shutdown_error() ->
- [{doc,"Test ssl:shutdown/2 error handling"}].
-tls_shutdown_error(Config) when is_list(Config) ->
- ServerOpts = ssl_test_lib:ssl_options(server_opts, Config),
- Port = ssl_test_lib:inet_port(node()),
- {ok, Listen} = ssl:listen(Port, ServerOpts),
- {error, enotconn} = ssl:shutdown(Listen, read_write),
- ok = ssl:close(Listen),
- {error, closed} = ssl:shutdown(Listen, read_write).
-
-%%--------------------------------------------------------------------
-default_reject_anonymous()->
- [{doc,"Test that by default anonymous cipher suites are rejected "}].
-default_reject_anonymous(Config) when is_list(Config) ->
- {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
- ClientOpts = ssl_test_lib:ssl_options(client_opts, Config),
- ServerOpts = ssl_test_lib:ssl_options(server_opts, Config),
- Version = ssl_test_lib:protocol_version(Config),
- TLSVersion = ssl_test_lib:tls_version(Version),
-
- [CipherSuite | _] = ssl_test_lib:ecdh_dh_anonymous_suites(TLSVersion),
-
- Server = ssl_test_lib:start_server_error([{node, ServerNode}, {port, 0},
- {from, self()},
- {options, ServerOpts}]),
- Port = ssl_test_lib:inet_port(Server),
- Client = ssl_test_lib:start_client_error([{node, ClientNode}, {port, Port},
- {host, Hostname},
- {from, self()},
- {options,
- [{ciphers,[CipherSuite]} |
- ClientOpts]}]),
-
- ssl_test_lib:check_server_alert(Server, Client, insufficient_security).
-
-%%--------------------------------------------------------------------
-reuse_session() ->
- [{doc,"Test reuse of sessions (short handshake)"}].
-reuse_session(Config) when is_list(Config) ->
- ClientOpts = ssl_test_lib:ssl_options(client_rsa_verify_opts, Config),
- ServerOpts = ssl_test_lib:ssl_options(server_rsa_opts, Config),
-
- ssl_test_lib:reuse_session(ClientOpts, ServerOpts, Config).
-%%--------------------------------------------------------------------
-reuse_session_expired() ->
- [{doc,"Test sessions is not reused when it has expired"}].
-reuse_session_expired(Config) when is_list(Config) ->
- ClientOpts = ssl_test_lib:ssl_options(client_rsa_verify_opts, Config),
- ServerOpts = ssl_test_lib:ssl_options(server_rsa_opts, Config),
- {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
-
- Server0 =
- ssl_test_lib:start_server([{node, ServerNode}, {port, 0},
- {from, self()},
- {mfa, {ssl_test_lib, no_result, []}},
- {tcp_options, [{active, false}]},
- {options, ServerOpts}]),
- Port0 = ssl_test_lib:inet_port(Server0),
-
- Client0 = ssl_test_lib:start_client([{node, ClientNode},
- {port, Port0}, {host, Hostname},
- {mfa, {ssl_test_lib, session_id, []}},
- {from, self()}, {options, [{reuse_sessions, save} | ClientOpts]}]),
- Server0 ! listen,
-
- Client1 = ssl_test_lib:start_client([{node, ClientNode},
- {port, Port0}, {host, Hostname},
- {mfa, {ssl_test_lib, session_id, []}},
- {from, self()}, {options, ClientOpts}]),
-
- SID = receive
- {Client0, Id0} ->
- Id0
- end,
-
- receive
- {Client1, SID} ->
- ok
- after ?SLEEP ->
- ct:fail(session_not_reused)
- end,
-
- Server0 ! listen,
-
- %% Make sure session is unregistered due to expiration
- ct:sleep((?EXPIRE*2)),
-
- make_sure_expired(Hostname, Port0, SID),
-
- Client2 =
- ssl_test_lib:start_client([{node, ClientNode},
- {port, Port0}, {host, Hostname},
- {mfa, {ssl_test_lib, session_id, []}},
- {from, self()}, {options, ClientOpts}]),
- receive
- {Client2, SID} ->
- ct:fail(session_reused_when_session_expired);
- {Client2, _} ->
- ok
- end,
- process_flag(trap_exit, false),
- ssl_test_lib:close(Server0),
- ssl_test_lib:close(Client0),
- ssl_test_lib:close(Client1),
- ssl_test_lib:close(Client2).
-
-make_sure_expired(Host, Port, Id) ->
- {status, _, _, StatusInfo} = sys:get_status(whereis(ssl_manager)),
- [_, _,_, _, Prop] = StatusInfo,
- State = ssl_test_lib:state(Prop),
- ClientCache = element(2, State),
-
- case ssl_session_cache:lookup(ClientCache, {{Host, Port}, Id}) of
- undefined ->
- ok;
- #session{is_resumable = false} ->
- ok;
- _ ->
- ct:sleep(?SLEEP),
- make_sure_expired(Host, Port, Id)
- end.
-
-%%--------------------------------------------------------------------
-server_does_not_want_to_reuse_session() ->
- [{doc,"Test reuse of sessions (short handshake)"}].
-server_does_not_want_to_reuse_session(Config) when is_list(Config) ->
- ClientOpts = ssl_test_lib:ssl_options(client_rsa_verify_opts, Config),
- ServerOpts = ssl_test_lib:ssl_options(server_rsa_opts, Config),
- {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
-
- Server =
- ssl_test_lib:start_server([{node, ServerNode}, {port, 0},
- {from, self()},
- {mfa, {ssl_test_lib, session_info_result, []}},
- {options, [{reuse_session, fun(_,_,_,_) ->
- false
- end} |
- ServerOpts]}]),
- Port = ssl_test_lib:inet_port(Server),
- Client0 =
- ssl_test_lib:start_client([{node, ClientNode},
- {port, Port}, {host, Hostname},
- {mfa, {ssl_test_lib, no_result, []}},
- {from, self()}, {options, ClientOpts}]),
- SessionInfo =
- receive
- {Server, Info} ->
- Info
- end,
-
- Server ! {listen, {mfa, {ssl_test_lib, no_result, []}}},
-
- %% Make sure session is registered
- ct:sleep(?SLEEP),
- ssl_test_lib:close(Client0),
-
- Client1 =
- ssl_test_lib:start_client([{node, ClientNode},
- {port, Port}, {host, Hostname},
- {mfa, {ssl_test_lib, session_info_result, []}},
- {from, self()}, {options, ClientOpts}]),
- receive
- {Client1, SessionInfo} ->
- ct:fail(session_reused_when_server_does_not_want_to);
- {Client1, _Other} ->
- ok
- end,
-
- ssl_test_lib:close(Server),
- ssl_test_lib:close(Client1).
-
-%%--------------------------------------------------------------------
-client_renegotiate() ->
- [{doc,"Test ssl:renegotiate/1 on client."}].
-client_renegotiate(Config) when is_list(Config) ->
- ServerOpts = ssl_test_lib:ssl_options(server_opts, Config),
- ClientOpts = ssl_test_lib:ssl_options(client_opts, Config),
-
- {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
-
- Data = "From erlang 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),
-
- Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port},
- {host, Hostname},
- {from, self()},
- {mfa, {?MODULE,
- renegotiate, [Data]}},
- {options, [{reuse_sessions, false} | ClientOpts]}]),
-
- ssl_test_lib:check_result(Client, ok, Server, ok),
- ssl_test_lib:close(Server),
- ssl_test_lib:close(Client).
-
-%%--------------------------------------------------------------------
-client_secure_renegotiate() ->
- [{doc,"Test ssl:renegotiate/1 on client."}].
-client_secure_renegotiate(Config) when is_list(Config) ->
- ServerOpts = ssl_test_lib:ssl_options(server_opts, Config),
- ClientOpts = ssl_test_lib:ssl_options(client_opts, Config),
-
- {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
-
- Data = "From erlang to erlang",
-
- Server =
- ssl_test_lib:start_server([{node, ServerNode}, {port, 0},
- {from, self()},
- {mfa, {?MODULE, erlang_ssl_receive, [Data]}},
- {options, [{secure_renegotiate, true} | ServerOpts]}]),
- Port = ssl_test_lib:inet_port(Server),
-
- Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port},
- {host, Hostname},
- {from, self()},
- {mfa, {?MODULE,
- renegotiate, [Data]}},
- {options, [{reuse_sessions, false},
- {secure_renegotiate, true}| ClientOpts]}]),
-
- ssl_test_lib:check_result(Client, ok, Server, ok),
- ssl_test_lib:close(Server),
- ssl_test_lib:close(Client).
-
-%%--------------------------------------------------------------------
-client_secure_renegotiate_fallback() ->
- [{doc,"Test that we can set secure_renegotiate to false that is "
- "fallback option, we however do not have a insecure server to test against!"}].
-client_secure_renegotiate_fallback(Config) when is_list(Config) ->
- ServerOpts = ssl_test_lib:ssl_options(server_opts, Config),
- ClientOpts = ssl_test_lib:ssl_options(client_opts, Config),
-
- {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
-
- Data = "From erlang to erlang",
-
- Server =
- ssl_test_lib:start_server([{node, ServerNode}, {port, 0},
- {from, self()},
- {mfa, {?MODULE, erlang_ssl_receive, [Data]}},
- {options, [{secure_renegotiate, false} | ServerOpts]}]),
- Port = ssl_test_lib:inet_port(Server),
+ {mfa, {?MODULE, protocol_info_result, []}},
+ {options, [{versions, ['tlsv1.1', 'tlsv1.2']} | ClientOpts]}]),
- Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port},
- {host, Hostname},
- {from, self()},
- {mfa, {?MODULE,
- renegotiate, [Data]}},
- {options, [{reuse_sessions, false},
- {secure_renegotiate, false}| ClientOpts]}]),
-
- ssl_test_lib:check_result(Client, ok, Server, ok),
- ssl_test_lib:close(Server),
- ssl_test_lib:close(Client).
+ ServerMsg = ClientMsg = {ok, 'tlsv1.2'},
+ ssl_test_lib:check_result(Server, ServerMsg, Client, ClientMsg).
+
+connect_dist() ->
+ [{doc,"Test a simple connect as is used by distribution"}].
-%%--------------------------------------------------------------------
-server_renegotiate() ->
- [{doc,"Test ssl:renegotiate/1 on server."}].
-server_renegotiate(Config) when is_list(Config) ->
- ServerOpts = ssl_test_lib:ssl_options(server_opts, Config),
- ClientOpts = ssl_test_lib:ssl_options(client_opts, Config),
+connect_dist(Config) when is_list(Config) ->
+ ClientOpts0 = ssl_test_lib:ssl_options(client_kc_opts, Config),
+ ClientOpts = [{ssl_imp, new},{active, false}, {packet,4}|ClientOpts0],
+ ServerOpts0 = ssl_test_lib:ssl_options(server_kc_opts, Config),
+ ServerOpts = [{ssl_imp, new},{active, false}, {packet,4}|ServerOpts0],
{ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
- Data = "From erlang to erlang",
-
Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0},
{from, self()},
- {mfa, {?MODULE,
- renegotiate, [Data]}},
+ {mfa, {?MODULE, connect_dist_s, []}},
{options, ServerOpts}]),
Port = ssl_test_lib:inet_port(Server),
-
- Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port},
- {host, Hostname},
- {from, self()},
- {mfa, {?MODULE, erlang_ssl_receive, [Data]}},
- {options, [{reuse_sessions, false} | ClientOpts]}]),
-
- ssl_test_lib:check_result(Server, ok, Client, ok),
- ssl_test_lib:close(Server),
- ssl_test_lib:close(Client).
-
-%%--------------------------------------------------------------------
-client_renegotiate_reused_session() ->
- [{doc,"Test ssl:renegotiate/1 on client when the ssl session will be reused."}].
-client_renegotiate_reused_session(Config) when is_list(Config) ->
- ServerOpts = ssl_test_lib:ssl_options(server_opts, Config),
- ClientOpts = ssl_test_lib:ssl_options(client_opts, Config),
-
- {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
-
- Data = "From erlang 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),
-
Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port},
{host, Hostname},
- {from, self()},
- {mfa, {?MODULE,
- renegotiate_reuse_session, [Data]}},
- {options, [{reuse_sessions, true} | ClientOpts]}]),
-
- ssl_test_lib:check_result(Client, ok, Server, ok),
- ssl_test_lib:close(Server),
- ssl_test_lib:close(Client).
-%%--------------------------------------------------------------------
-server_renegotiate_reused_session() ->
- [{doc,"Test ssl:renegotiate/1 on server when the ssl session will be reused."}].
-server_renegotiate_reused_session(Config) when is_list(Config) ->
- ServerOpts = ssl_test_lib:ssl_options(server_opts, Config),
- ClientOpts = ssl_test_lib:ssl_options(client_opts, Config),
-
- {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
-
- Data = "From erlang to erlang",
-
- Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0},
- {from, self()},
- {mfa, {?MODULE,
- renegotiate_reuse_session, [Data]}},
- {options, ServerOpts}]),
- Port = ssl_test_lib:inet_port(Server),
-
- Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port},
- {host, Hostname},
- {from, self()},
- {mfa, {?MODULE, erlang_ssl_receive, [Data]}},
- {options, [{reuse_sessions, true} | ClientOpts]}]),
-
- ssl_test_lib:check_result(Server, ok, Client, ok),
- ssl_test_lib:close(Server),
- ssl_test_lib:close(Client).
-%%--------------------------------------------------------------------
-client_no_wrap_sequence_number() ->
- [{doc,"Test that erlang client will renegotiate session when",
- "max sequence number celing is about to be reached. Although"
- "in the testcase we use the test option renegotiate_at"
- " to lower treashold substantially."}].
-
-client_no_wrap_sequence_number(Config) when is_list(Config) ->
- ServerOpts = ssl_test_lib:ssl_options(server_opts, Config),
- ClientOpts = ssl_test_lib:ssl_options(client_opts, Config),
-
- {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
-
- ErlData = "From erlang to erlang",
- N = 12,
-
- Server =
- ssl_test_lib:start_server([{node, ServerNode}, {port, 0},
- {from, self()},
- {mfa, {ssl_test_lib, no_result, []}},
- {options, ServerOpts}]),
- Port = ssl_test_lib:inet_port(Server),
-
- Version = ssl_test_lib:protocol_version(Config, tuple),
-
- Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port},
- {host, Hostname},
- {from, self()},
- {mfa, {ssl_test_lib,
- trigger_renegotiate, [[ErlData, treashold(N, Version)]]}},
- {options, [{reuse_sessions, false},
- {renegotiate_at, N} | ClientOpts]}]),
-
- ssl_test_lib:check_result(Client, ok),
- ssl_test_lib:close(Server),
- ssl_test_lib:close(Client).
-
-%%--------------------------------------------------------------------
-server_no_wrap_sequence_number() ->
- [{doc, "Test that erlang server will renegotiate session when",
- "max sequence number celing is about to be reached. Although"
- "in the testcase we use the test option renegotiate_at"
- " to lower treashold substantially."}].
-
-server_no_wrap_sequence_number(Config) when is_list(Config) ->
- ServerOpts = ssl_test_lib:ssl_options(server_opts, Config),
- ClientOpts = ssl_test_lib:ssl_options(client_opts, Config),
-
- {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
-
- Data = "From erlang to erlang",
- N = 12,
-
- Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0},
- {from, self()},
- {mfa, {ssl_test_lib,
- trigger_renegotiate, [[Data, N+2]]}},
- {options, [{renegotiate_at, N} | 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, no_result, []}},
- {options, [{reuse_sessions, false} | ClientOpts]}]),
-
- ssl_test_lib:check_result(Server, ok),
- ssl_test_lib:close(Server),
- ssl_test_lib:close(Client).
-
-%%--------------------------------------------------------------------
-der_input() ->
- [{doc,"Test to input certs and key as der"}].
-
-der_input(Config) when is_list(Config) ->
- DataDir = proplists:get_value(data_dir, Config),
- DHParamFile = filename:join(DataDir, "dHParam.pem"),
-
- {status, _, _, StatusInfo} = sys:get_status(whereis(ssl_manager)),
- [_, _,_, _, Prop] = StatusInfo,
- State = ssl_test_lib:state(Prop),
- [CADb | _] = element(6, State),
-
- Size = ets:info(CADb, size),
-
- SeverVerifyOpts = ssl_test_lib:ssl_options(server_rsa_opts, Config),
- {ServerCert, ServerKey, ServerCaCerts, DHParams} = der_input_opts([{dhfile, DHParamFile} |
- SeverVerifyOpts]),
- ClientVerifyOpts = ssl_test_lib:ssl_options(client_rsa_opts, Config),
- {ClientCert, ClientKey, ClientCaCerts, DHParams} = der_input_opts([{dhfile, DHParamFile} |
- ClientVerifyOpts]),
- ServerOpts = [{verify, verify_peer}, {fail_if_no_peer_cert, true},
- {dh, DHParams},
- {cert, ServerCert}, {key, ServerKey}, {cacerts, ServerCaCerts}],
- ClientOpts = [{verify, verify_peer}, {fail_if_no_peer_cert, true},
- {dh, DHParams},
- {cert, ClientCert}, {key, ClientKey}, {cacerts, ClientCaCerts}],
- {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
- Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0},
- {from, self()},
- {mfa, {ssl_test_lib, send_recv_result, []}},
- {options, [{active, false} | ServerOpts]}]),
- Port = ssl_test_lib:inet_port(Server),
- Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port},
- {host, Hostname},
- {from, self()},
- {mfa, {ssl_test_lib, send_recv_result, []}},
- {options, [{active, false} | ClientOpts]}]),
-
- ssl_test_lib:check_result(Server, ok, Client, ok),
- ssl_test_lib:close(Server),
- ssl_test_lib:close(Client),
- Size = ets:info(CADb, size).
-
-%%--------------------------------------------------------------------
-der_input_opts(Opts) ->
- Certfile = proplists:get_value(certfile, Opts),
- CaCertsfile = proplists:get_value(cacertfile, Opts),
- Keyfile = proplists:get_value(keyfile, Opts),
- Dhfile = proplists:get_value(dhfile, Opts),
- [{_, Cert, _}] = ssl_test_lib:pem_to_der(Certfile),
- [{Asn1Type, Key, _}] = ssl_test_lib:pem_to_der(Keyfile),
- [{_, DHParams, _}] = ssl_test_lib:pem_to_der(Dhfile),
- CaCerts =
- lists:map(fun(Entry) ->
- {_, CaCert, _} = Entry,
- CaCert
- end, ssl_test_lib:pem_to_der(CaCertsfile)),
- {Cert, {Asn1Type, Key}, CaCerts, DHParams}.
-
-%%--------------------------------------------------------------------
-no_reuses_session_server_restart_new_cert() ->
- [{doc,"Check that a session is not reused if the server is restarted with a new cert."}].
-no_reuses_session_server_restart_new_cert(Config) when is_list(Config) ->
-
- ClientOpts = ssl_test_lib:ssl_options(client_opts, Config),
- ServerOpts = ssl_test_lib:ssl_options(server_opts, Config),
- DsaServerOpts = ssl_test_lib:ssl_options(server_dsa_opts, Config),
- {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
-
- Server =
- ssl_test_lib:start_server([{node, ServerNode}, {port, 0},
- {from, self()},
- {mfa, {ssl_test_lib, session_info_result, []}},
- {options, ServerOpts}]),
- Port = ssl_test_lib:inet_port(Server),
- Client0 =
- ssl_test_lib:start_client([{node, ClientNode},
- {port, Port}, {host, Hostname},
- {mfa, {ssl_test_lib, no_result, []}},
- {from, self()}, {options, ClientOpts}]),
- SessionInfo =
- receive
- {Server, Info} ->
- Info
- end,
-
- %% Make sure session is registered
- ct:sleep(?SLEEP),
- Monitor = erlang:monitor(process, Server),
- ssl_test_lib:close(Server),
- ssl_test_lib:close(Client0),
- receive
- {'DOWN', Monitor, _, _, _} ->
- ok
- end,
-
- Server1 =
- ssl_test_lib:start_server([{node, ServerNode}, {port, Port},
- {from, self()},
- {mfa, {ssl_test_lib, no_result, []}},
- {options, [{reuseaddr, true} | DsaServerOpts]}]),
-
- Client1 =
- ssl_test_lib:start_client([{node, ClientNode},
- {port, Port}, {host, Hostname},
- {mfa, {ssl_test_lib, session_info_result, []}},
- {from, self()}, {options, ClientOpts}]),
- receive
- {Client1, SessionInfo} ->
- ct:fail(session_reused_when_server_has_new_cert);
- {Client1, _Other} ->
- ok
- end,
- ssl_test_lib:close(Server1),
- ssl_test_lib:close(Client1).
-
-%%--------------------------------------------------------------------
-no_reuses_session_server_restart_new_cert_file() ->
- [{doc,"Check that a session is not reused if a server is restarted with a new "
- "cert contained in a file with the same name as the old cert."}].
-
-no_reuses_session_server_restart_new_cert_file(Config) when is_list(Config) ->
- ClientOpts = ssl_test_lib:ssl_options(client_opts, Config),
- ServerOpts = ssl_test_lib:ssl_options(server_verification_opts, Config),
- DsaServerOpts = ssl_test_lib:ssl_options(server_dsa_opts, Config),
- PrivDir = proplists:get_value(priv_dir, Config),
-
- NewServerOpts0 = new_config(PrivDir, ServerOpts),
- {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
-
- Server =
- ssl_test_lib:start_server([{node, ServerNode}, {port, 0},
- {from, self()},
- {mfa, {ssl_test_lib, session_info_result, []}},
- {options, NewServerOpts0}]),
- Port = ssl_test_lib:inet_port(Server),
- Client0 =
- ssl_test_lib:start_client([{node, ClientNode},
- {port, Port}, {host, Hostname},
- {mfa, {ssl_test_lib, no_result, []}},
- {from, self()}, {options, ClientOpts}]),
- SessionInfo =
- receive
- {Server, Info} ->
- Info
- end,
-
- %% Make sure session is registered and we get
- %% new file time stamp when calling new_config!
- ct:sleep(?SLEEP* 2),
- ssl_test_lib:close(Server),
- ssl_test_lib:close(Client0),
-
- ssl:clear_pem_cache(),
-
- NewServerOpts1 = new_config(PrivDir, DsaServerOpts),
-
- Server1 =
- ssl_test_lib:start_server([{node, ServerNode}, {port, Port},
- {from, self()},
- {mfa, {ssl_test_lib, no_result, []}},
- {options, [{reuseaddr, true} | NewServerOpts1]}]),
- Client1 =
- ssl_test_lib:start_client([{node, ClientNode},
- {port, Port}, {host, Hostname},
- {mfa, {ssl_test_lib, session_info_result, []}},
- {from, self()}, {options, ClientOpts}]),
- receive
- {Client1, SessionInfo} ->
- ct:fail(session_reused_when_server_has_new_cert);
- {Client1, _Other} ->
- ok
- end,
- ssl_test_lib:close(Server1),
- ssl_test_lib:close(Client1).
-
-%%--------------------------------------------------------------------
-defaults(Config) when is_list(Config)->
- Versions = ssl:versions(),
- true = lists:member(sslv3, proplists:get_value(available, Versions)),
- false = lists:member(sslv3, proplists:get_value(supported, Versions)),
- true = lists:member('tlsv1', proplists:get_value(available, Versions)),
- false = lists:member('tlsv1', proplists:get_value(supported, Versions)),
- true = lists:member('tlsv1.1', proplists:get_value(available, Versions)),
- false = lists:member('tlsv1.1', proplists:get_value(supported, Versions)),
- true = lists:member('tlsv1.2', proplists:get_value(available, Versions)),
- true = lists:member('tlsv1.2', proplists:get_value(supported, Versions)),
- false = lists:member({rsa,rc4_128,sha}, ssl:cipher_suites()),
- true = lists:member({rsa,rc4_128,sha}, ssl:cipher_suites(all)),
- false = lists:member({rsa,des_cbc,sha}, ssl:cipher_suites()),
- true = lists:member({rsa,des_cbc,sha}, ssl:cipher_suites(all)),
- false = lists:member({dhe_rsa,des_cbc,sha}, ssl:cipher_suites()),
- true = lists:member({dhe_rsa,des_cbc,sha}, ssl:cipher_suites(all)),
- true = lists:member('dtlsv1.2', proplists:get_value(available_dtls, Versions)),
- true = lists:member('dtlsv1', proplists:get_value(available_dtls, Versions)),
- true = lists:member('dtlsv1.2', proplists:get_value(supported_dtls, Versions)),
- false = lists:member('dtlsv1', proplists:get_value(supported_dtls, Versions)).
-
-%%--------------------------------------------------------------------
-reuseaddr() ->
- [{doc,"Test reuseaddr option"}].
-
-reuseaddr(Config) when is_list(Config) ->
- ClientOpts = ssl_test_lib:ssl_options(client_opts, Config),
- ServerOpts = ssl_test_lib:ssl_options(server_opts, Config),
- {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
- Server =
- ssl_test_lib:start_server([{node, ServerNode}, {port, 0},
- {from, self()},
- {mfa, {ssl_test_lib, no_result, []}},
- {options, [{active, false} | 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, no_result, []}},
- {options, [{active, false} | ClientOpts]}]),
- ssl_test_lib:close(Server),
- ssl_test_lib:close(Client),
-
- Server1 =
- ssl_test_lib:start_server([{node, ServerNode}, {port, Port},
- {from, self()},
- {mfa, {ssl_test_lib, send_recv_result, []}},
- {options, [{active, false} | ServerOpts]}]),
- Client1 =
- ssl_test_lib:start_client([{node, ClientNode}, {port, Port},
- {host, Hostname},
- {from, self()},
- {mfa, {ssl_test_lib, send_recv_result, []}},
- {options, [{active, false} | ClientOpts]}]),
-
- ssl_test_lib:check_result(Server1, ok, Client1, ok),
- ssl_test_lib:close(Server1),
- ssl_test_lib:close(Client1).
-
-%%--------------------------------------------------------------------
-tls_tcp_reuseaddr() ->
- [{doc, "Reference test case."}].
-tls_tcp_reuseaddr(Config) when is_list(Config) ->
- {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
- Server =
- ssl_test_lib:start_server([{node, ServerNode}, {port, 0},
- {from, self()},
- {transport, gen_tcp},
- {mfa, {ssl_test_lib, no_result, []}},
- {options, [{active, false}, {reuseaddr, true}]}]),
- Port = ssl_test_lib:inet_port(Server),
- Client =
- ssl_test_lib:start_client([{node, ClientNode}, {port, Port},
- {host, Hostname},
- {transport, gen_tcp},
- {from, self()},
- {mfa, {ssl_test_lib, no_result, []}},
- {options, [{active, false}]}]),
- ssl_test_lib:close(Server),
- ssl_test_lib:close(Client),
-
- Server1 =
- ssl_test_lib:start_server([{node, ServerNode}, {port, Port},
- {from, self()},
- {transport, gen_tcp},
- {mfa, {?MODULE, tcp_send_recv_result, []}},
- {options, [{active, false}, {reuseaddr, true}]}]),
- Client1 =
- ssl_test_lib:start_client([{node, ClientNode}, {port, Port},
- {host, Hostname},
- {from, self()},
- {transport, gen_tcp},
- {mfa, {?MODULE, tcp_send_recv_result, []}},
- {options, [{active, false}]}]),
-
- ssl_test_lib:check_result(Server1, ok, Client1, ok),
- ssl_test_lib:close(Server1),
- ssl_test_lib:close(Client1).
-
-%%--------------------------------------------------------------------
-
-honor_server_cipher_order() ->
- [{doc,"Test API honor server cipher order."}].
-honor_server_cipher_order(Config) when is_list(Config) ->
- ClientCiphers = [#{key_exchange => dhe_rsa,
- cipher => aes_128_cbc,
- mac => sha,
- prf => default_prf},
- #{key_exchange => dhe_rsa,
- cipher => aes_256_cbc,
- mac => sha,
- prf => default_prf}],
- ServerCiphers = [#{key_exchange => dhe_rsa,
- cipher => aes_256_cbc,
- mac =>sha,
- prf => default_prf},
- #{key_exchange => dhe_rsa,
- cipher => aes_128_cbc,
- mac => sha,
- prf => default_prf}],
- honor_cipher_order(Config, true, ServerCiphers, ClientCiphers, #{key_exchange => dhe_rsa,
- cipher => aes_256_cbc,
- mac => sha,
- prf => default_prf}).
-
-honor_client_cipher_order() ->
- [{doc,"Test API honor server cipher order."}].
-honor_client_cipher_order(Config) when is_list(Config) ->
- ClientCiphers = [#{key_exchange => dhe_rsa,
- cipher => aes_128_cbc,
- mac => sha,
- prf => default_prf},
- #{key_exchange => dhe_rsa,
- cipher => aes_256_cbc,
- mac => sha,
- prf => default_prf}],
- ServerCiphers = [#{key_exchange => dhe_rsa,
- cipher => aes_256_cbc,
- mac =>sha,
- prf => default_prf},
- #{key_exchange => dhe_rsa,
- cipher => aes_128_cbc,
- mac => sha,
- prf => default_prf}],
-honor_cipher_order(Config, false, ServerCiphers, ClientCiphers, #{key_exchange => dhe_rsa,
- cipher => aes_128_cbc,
- mac => sha,
- prf => default_prf}).
-
-honor_cipher_order(Config, Honor, ServerCiphers, ClientCiphers, Expected) ->
- ClientOpts = ssl_test_lib:ssl_options(client_opts, Config),
- ServerOpts = ssl_test_lib:ssl_options(server_opts, Config),
-
- {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
-
- Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0},
- {from, self()},
- {mfa, {?MODULE, connection_info_result, []}},
- {options, [{ciphers, ServerCiphers}, {honor_cipher_order, Honor}
- | ServerOpts]}]),
- Port = ssl_test_lib:inet_port(Server),
- Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port},
- {host, Hostname},
- {from, self()},
- {mfa, {?MODULE, connection_info_result, []}},
- {options, [{ciphers, ClientCiphers}, {honor_cipher_order, Honor}
- | ClientOpts]}]),
-
- Version = ssl_test_lib:protocol_version(Config),
-
- ServerMsg = ClientMsg = {ok, {Version, Expected}},
-
- ssl_test_lib:check_result(Server, ServerMsg, Client, ClientMsg),
-
- ssl_test_lib:close(Server),
- ssl_test_lib:close(Client).
-
-%%--------------------------------------------------------------------
-tls_ciphersuite_vs_version() ->
- [{doc,"Test a SSLv3 client cannot negotiate a TLSv* cipher suite."}].
-tls_ciphersuite_vs_version(Config) when is_list(Config) ->
-
- {_ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
- ServerOpts = ssl_test_lib:ssl_options(server_opts, Config),
-
- Server = ssl_test_lib:start_server_error([{node, ServerNode}, {port, 0},
- {from, self()},
- {options, ServerOpts}]),
- Port = ssl_test_lib:inet_port(Server),
-
- {ok, Socket} = gen_tcp:connect(Hostname, Port, [binary, {active, false}]),
- ok = gen_tcp:send(Socket,
- <<22, 3,0, 49:16, % handshake, SSL 3.0, length
- 1, 45:24, % client_hello, length
- 3,0, % SSL 3.0
- 16#deadbeef:256, % 32 'random' bytes = 256 bits
- 0, % no session ID
- %% three cipher suites -- null, one with sha256 hash and one with sha hash
- 6:16, 0,255, 0,61, 0,57,
- 1, 0 % no compression
- >>),
- {ok, <<22, RecMajor:8, RecMinor:8, _RecLen:16, 2, HelloLen:24>>} = gen_tcp:recv(Socket, 9, 10000),
- {ok, <<HelloBin:HelloLen/binary>>} = gen_tcp:recv(Socket, HelloLen, 5000),
- ServerHello = tls_handshake:decode_handshake({RecMajor, RecMinor}, 2, HelloBin),
- case ServerHello of
- #server_hello{server_version = {3,0}, cipher_suite = <<0,57>>} ->
- ok;
- _ ->
- ct:fail({unexpected_server_hello, ServerHello})
- end.
-
-%%--------------------------------------------------------------------
-conf_signature_algs() ->
- [{doc,"Test to set the signature_algs option on both client and server"}].
-conf_signature_algs(Config) when is_list(Config) ->
- ClientOpts = ssl_test_lib:ssl_options(client_opts, Config),
- ServerOpts = ssl_test_lib:ssl_options(server_opts, Config),
- {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
- Server =
- ssl_test_lib:start_server([{node, ServerNode}, {port, 0},
- {from, self()},
- {mfa, {ssl_test_lib, send_recv_result, []}},
- {options, [{active, false}, {signature_algs, [{sha, rsa}]} | ServerOpts]}]),
- Port = ssl_test_lib:inet_port(Server),
- Client =
- ssl_test_lib:start_client([{node, ClientNode}, {port, Port},
- {host, Hostname},
- {from, self()},
- {mfa, {ssl_test_lib, send_recv_result, []}},
- {options, [{active, false}, {signature_algs, [{sha, rsa}]} | ClientOpts]}]),
-
- ct:log("Testcase ~p, Client ~p Server ~p ~n",
- [self(), Client, Server]),
-
- ssl_test_lib:check_result(Server, ok, Client, ok),
-
- ssl_test_lib:close(Server),
- ssl_test_lib:close(Client).
-
-
-%%--------------------------------------------------------------------
-no_common_signature_algs() ->
- [{doc,"Set the signature_algs option so that there client and server does not share any hash sign algorithms"}].
-no_common_signature_algs(Config) when is_list(Config) ->
-
- ClientOpts = ssl_test_lib:ssl_options(client_opts, Config),
- ServerOpts = ssl_test_lib:ssl_options(server_opts, Config),
-
- {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
-
-
- Server = ssl_test_lib:start_server_error([{node, ServerNode}, {port, 0},
- {from, self()},
- {options, [{signature_algs, [{sha256, rsa}]}
- | ServerOpts]}]),
- Port = ssl_test_lib:inet_port(Server),
- Client = ssl_test_lib:start_client_error([{node, ClientNode}, {port, Port},
- {host, Hostname},
- {from, self()},
- {options, [{signature_algs, [{sha384, rsa}]}
- | ClientOpts]}]),
-
- ssl_test_lib:check_server_alert(Server, Client, insufficient_security).
-
-%%--------------------------------------------------------------------
-
-tls_dont_crash_on_handshake_garbage() ->
- [{doc, "Ensure SSL server worker thows an alert on garbage during handshake "
- "instead of crashing and exposing state to user code"}].
-
-tls_dont_crash_on_handshake_garbage(Config) ->
- ServerOpts = ssl_test_lib:ssl_options(server_opts, Config),
-
- {_ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
-
- Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0},
- {from, self()},
- {mfa, {ssl_test_lib, send_recv_result_active, []}},
- {options, ServerOpts}]),
- unlink(Server), monitor(process, Server),
- Port = ssl_test_lib:inet_port(Server),
-
- {ok, Socket} = gen_tcp:connect(Hostname, Port, [binary, {active, false}]),
-
- % Send hello and garbage record
- ok = gen_tcp:send(Socket,
- [<<22, 3,3, 49:16, 1, 45:24, 3,3, % client_hello
- 16#deadbeef:256, % 32 'random' bytes = 256 bits
- 0, 6:16, 0,255, 0,61, 0,57, 1, 0 >>, % some hello values
-
- <<22, 3,3, 5:16, 92,64,37,228,209>> % garbage
- ]),
- % Send unexpected change_cipher_spec
- ok = gen_tcp:send(Socket, <<20, 3,3, 12:16, 111,40,244,7,137,224,16,109,197,110,249,152>>),
-
- % Ensure we receive an alert, not sudden disconnect
- {ok, <<21, _/binary>>} = drop_handshakes(Socket, 1000).
-
-drop_handshakes(Socket, Timeout) ->
- {ok, <<RecType:8, _RecMajor:8, _RecMinor:8, RecLen:16>> = Header} = gen_tcp:recv(Socket, 5, Timeout),
- {ok, <<Frag:RecLen/binary>>} = gen_tcp:recv(Socket, RecLen, Timeout),
- case RecType of
- 22 -> drop_handshakes(Socket, Timeout);
- _ -> {ok, <<Header/binary, Frag/binary>>}
- end.
-
-
-%%--------------------------------------------------------------------
-
-hibernate() ->
- [{doc,"Check that an SSL connection that is started with option "
- "{hibernate_after, 1000} indeed hibernates after 1000ms of "
- "inactivity"}].
-
-hibernate(Config) ->
- ClientOpts = ssl_test_lib:ssl_options(client_opts, Config),
- ServerOpts = ssl_test_lib:ssl_options(server_opts, Config),
-
- {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
-
- Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0},
- {from, self()},
- {mfa, {ssl_test_lib, send_recv_result_active, []}},
- {options, ServerOpts}]),
- Port = ssl_test_lib:inet_port(Server),
- {Client, #sslsocket{pid=[Pid|_]}} = ssl_test_lib:start_client([return_socket,
- {node, ClientNode}, {port, Port},
- {host, Hostname},
- {from, self()},
- {mfa, {ssl_test_lib, send_recv_result_active, []}},
- {options, [{hibernate_after, 1000}|ClientOpts]}]),
- {current_function, _} =
- process_info(Pid, current_function),
-
- ssl_test_lib:check_result(Server, ok, Client, ok),
-
- ct:sleep(1500),
- {current_function, {erlang, hibernate, 3}} =
- process_info(Pid, current_function),
-
- ssl_test_lib:close(Server),
- ssl_test_lib:close(Client).
-
-%%--------------------------------------------------------------------
-
-hibernate_right_away() ->
- [{doc,"Check that an SSL connection that is configured to hibernate "
- "after 0 or 1 milliseconds hibernates as soon as possible and not "
- "crashes"}].
-
-hibernate_right_away(Config) ->
- ClientOpts = ssl_test_lib:ssl_options(client_opts, Config),
- ServerOpts = ssl_test_lib:ssl_options(server_opts, Config),
-
- {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
-
- StartServerOpts = [{node, ServerNode}, {port, 0},
- {from, self()},
- {mfa, {ssl_test_lib, send_recv_result_active, []}},
- {options, ServerOpts}],
- StartClientOpts = [return_socket,
- {node, ClientNode},
- {host, Hostname},
- {from, self()},
- {mfa, {ssl_test_lib, send_recv_result_active, []}}],
-
- Server1 = ssl_test_lib:start_server(StartServerOpts),
- Port1 = ssl_test_lib:inet_port(Server1),
- {Client1, #sslsocket{pid = [Pid1|_]}} = ssl_test_lib:start_client(StartClientOpts ++
- [{port, Port1}, {options, [{hibernate_after, 0}|ClientOpts]}]),
-
- ssl_test_lib:check_result(Server1, ok, Client1, ok),
-
- ct:sleep(1000), %% Schedule out
-
- {current_function, {erlang, hibernate, 3}} =
- process_info(Pid1, current_function),
- ssl_test_lib:close(Server1),
- ssl_test_lib:close(Client1),
-
- Server2 = ssl_test_lib:start_server(StartServerOpts),
- Port2 = ssl_test_lib:inet_port(Server2),
- {Client2, #sslsocket{pid = [Pid2|_]}} = ssl_test_lib:start_client(StartClientOpts ++
- [{port, Port2}, {options, [{hibernate_after, 1}|ClientOpts]}]),
-
- ssl_test_lib:check_result(Server2, ok, Client2, ok),
-
- ct:sleep(1000), %% Schedule out
-
- {current_function, {erlang, hibernate, 3}} =
- process_info(Pid2, current_function),
-
- ssl_test_lib:close(Server2),
- ssl_test_lib:close(Client2).
-
-%%--------------------------------------------------------------------
-listen_socket() ->
- [{doc,"Check error handling and inet compliance when calling API functions with listen sockets."}].
-
-listen_socket(Config) ->
- ServerOpts = ssl_test_lib:ssl_options(server_opts, Config),
- {ok, ListenSocket} = ssl:listen(0, ServerOpts),
-
- %% This can be a valid thing to do as
- %% options are inherited by the accept socket
- ok = ssl:controlling_process(ListenSocket, self()),
-
- {ok, _} = ssl:sockname(ListenSocket),
-
- {error, enotconn} = ssl:send(ListenSocket, <<"data">>),
- {error, enotconn} = ssl:recv(ListenSocket, 0),
- {error, enotconn} = ssl:connection_information(ListenSocket),
- {error, enotconn} = ssl:peername(ListenSocket),
- {error, enotconn} = ssl:peercert(ListenSocket),
- {error, enotconn} = ssl:renegotiate(ListenSocket),
- {error, enotconn} = ssl:prf(ListenSocket, 'master_secret', <<"Label">>, [client_random], 256),
- {error, enotconn} = ssl:shutdown(ListenSocket, read_write),
-
- ok = ssl:close(ListenSocket).
-%%--------------------------------------------------------------------
-tls_ssl_accept_timeout() ->
- [{doc,"Test ssl:ssl_accept timeout"}].
-
-tls_ssl_accept_timeout(Config) ->
- process_flag(trap_exit, true),
- ServerOpts = ssl_test_lib:ssl_options(server_opts, Config),
- {_, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
- Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0},
- {from, self()},
- {timeout, 5000},
- {mfa, {ssl_test_lib,
- no_result_msg, []}},
- {options, ServerOpts}]),
- Port = ssl_test_lib:inet_port(Server),
- {ok, CSocket} = gen_tcp:connect(Hostname, Port, [binary, {active, true}]),
-
- receive
- {tcp_closed, CSocket} ->
- ssl_test_lib:check_result(Server, {error, timeout}),
- receive
- {'EXIT', Server, _} ->
- %% Make sure supervisor had time to react on process exit
- %% Could we come up with a better solution to this?
- ct:sleep(500),
- [] = supervisor:which_children(tls_connection_sup)
- end
- end.
-
-%%--------------------------------------------------------------------
-ssl_recv_timeout() ->
- [{doc,"Test ssl:ssl_accept timeout"}].
-
-ssl_recv_timeout(Config) ->
- ServerOpts = ssl_test_lib:ssl_options(server_opts, Config),
- ClientOpts = ssl_test_lib:ssl_options(client_opts, Config),
-
- {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
-
- Server =
- ssl_test_lib:start_server([{node, ServerNode}, {port, 0},
- {from, self()},
- {mfa, {?MODULE, send_recv_result_timeout_server, []}},
- {options, [{active, false} | ServerOpts]}]),
- Port = ssl_test_lib:inet_port(Server),
-
- Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port},
- {host, Hostname},
- {from, self()},
- {mfa, {?MODULE,
- send_recv_result_timeout_client, []}},
- {options, [{active, false} | ClientOpts]}]),
-
- ssl_test_lib:check_result(Client, ok, Server, ok),
- ssl_test_lib:close(Server),
- ssl_test_lib:close(Client).
-
-%%--------------------------------------------------------------------
-connect_twice() ->
- [{doc,""}].
-connect_twice(Config) when is_list(Config) ->
- ClientOpts = ssl_test_lib:ssl_options(client_opts, Config),
- ServerOpts = ssl_test_lib:ssl_options(server_opts, Config),
-
- {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
-
- Server =
- ssl_test_lib:start_server([{node, ServerNode}, {port, 0},
- {from, self()},
- {mfa, {ssl_test_lib, send_recv_result, []}},
- {options, [{keepalive, true},{active, false}
- | ServerOpts]}]),
- Port = ssl_test_lib:inet_port(Server),
- Client =
- ssl_test_lib:start_client([{node, ClientNode}, {port, Port},
- {host, Hostname},
- {from, self()},
- {mfa, {ssl_test_lib, send_recv_result, []}},
- {options, [{keepalive, true},{active, false}
- | ClientOpts]}]),
- Server ! listen,
-
- {Client1, #sslsocket{}} =
- ssl_test_lib:start_client([return_socket,
- {node, ClientNode}, {port, Port},
- {host, Hostname},
- {from, self()},
- {mfa, {ssl_test_lib, send_recv_result, []}},
- {options, [{keepalive, true},{active, false}
- | ClientOpts]}]),
-
- ct:log("Testcase ~p, Client ~p Server ~p ~n",
- [self(), Client, Server]),
-
- ssl_test_lib:check_result(Server, ok, Client, ok),
- ssl_test_lib:check_result(Server, ok, Client1, ok),
-
- ssl_test_lib:close(Server),
- ssl_test_lib:close(Client),
- ssl_test_lib:close(Client1).
-
-%%--------------------------------------------------------------------
-renegotiate_dos_mitigate_active() ->
- [{doc, "Mitigate DOS computational attack by not allowing client to renegotiate many times in a row",
- "immediately after each other"}].
-renegotiate_dos_mitigate_active(Config) when is_list(Config) ->
- ServerOpts = ssl_test_lib:ssl_options(server_opts, Config),
- ClientOpts = ssl_test_lib:ssl_options(client_opts, Config),
-
- {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
-
- Server =
- ssl_test_lib:start_server([{node, ServerNode}, {port, 0},
- {from, self()},
- {mfa, {ssl_test_lib, send_recv_result_active, []}},
- {options, ServerOpts}]),
- Port = ssl_test_lib:inet_port(Server),
-
- Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port},
- {host, Hostname},
- {from, self()},
- {mfa, {?MODULE,
- renegotiate_immediately, []}},
- {options, ClientOpts}]),
-
- ssl_test_lib:check_result(Client, ok, Server, ok),
- ssl_test_lib:close(Server),
- ssl_test_lib:close(Client).
-
-%%--------------------------------------------------------------------
-renegotiate_dos_mitigate_passive() ->
- [{doc, "Mitigate DOS computational attack by not allowing client to renegotiate many times in a row",
- "immediately after each other"}].
-renegotiate_dos_mitigate_passive(Config) when is_list(Config) ->
- ServerOpts = ssl_test_lib:ssl_options(server_opts, Config),
- ClientOpts = ssl_test_lib:ssl_options(client_opts, Config),
-
- {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
-
- Server =
- ssl_test_lib:start_server([{node, ServerNode}, {port, 0},
- {from, self()},
- {mfa, {ssl_test_lib, send_recv_result, []}},
- {options, [{active, false} | ServerOpts]}]),
- Port = ssl_test_lib:inet_port(Server),
-
- Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port},
- {host, Hostname},
{from, self()},
- {mfa, {?MODULE,
- renegotiate_immediately, []}},
- {options, ClientOpts}]),
-
- ssl_test_lib:check_result(Client, ok, Server, ok),
- ssl_test_lib:close(Server),
- ssl_test_lib:close(Client).
-
-%%--------------------------------------------------------------------
-renegotiate_dos_mitigate_absolute() ->
- [{doc, "Mitigate DOS computational attack by not allowing client to initiate renegotiation"}].
-renegotiate_dos_mitigate_absolute(Config) when is_list(Config) ->
- ServerOpts = ssl_test_lib:ssl_options(server_opts, Config),
- ClientOpts = ssl_test_lib:ssl_options(client_opts, Config),
-
- {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
-
- Server =
- ssl_test_lib:start_server([{node, ServerNode}, {port, 0},
- {from, self()},
- {mfa, {ssl_test_lib, send_recv_result_active, []}},
- {options, [{client_renegotiation, false} | ServerOpts]}]),
- Port = ssl_test_lib:inet_port(Server),
-
- Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port},
- {host, Hostname},
- {from, self()},
- {mfa, {?MODULE,
- renegotiate_rejected,
- []}},
+ {mfa, {?MODULE, connect_dist_c, []}},
{options, ClientOpts}]),
-
- ssl_test_lib:check_result(Client, ok, Server, ok),
- ssl_test_lib:close(Server),
- ssl_test_lib:close(Client).
-
-%%--------------------------------------------------------------------
-tls_tcp_error_propagation_in_active_mode() ->
- [{doc,"Test that process recives {ssl_error, Socket, closed} when tcp error ocurres"}].
-tls_tcp_error_propagation_in_active_mode(Config) when is_list(Config) ->
- ClientOpts = ssl_test_lib:ssl_options(client_opts, Config),
- ServerOpts = ssl_test_lib:ssl_options(server_opts, Config),
-
- {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
-
- Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0},
- {from, self()},
- {mfa, {ssl_test_lib, no_result, []}},
- {options, ServerOpts}]),
- Port = ssl_test_lib:inet_port(Server),
- {Client, #sslsocket{pid=[Pid|_]} = SslSocket} = ssl_test_lib:start_client([return_socket,
- {node, ClientNode}, {port, Port},
- {host, Hostname},
- {from, self()},
- {mfa, {?MODULE, receive_msg, []}},
- {options, ClientOpts}]),
-
- {status, _, _, StatusInfo} = sys:get_status(Pid),
- [_, _,_, _, Prop] = StatusInfo,
- State = ssl_test_lib:state(Prop),
- StaticEnv = element(2, State),
- Socket = element(11, StaticEnv),
- %% Fake tcp error
- Pid ! {tcp_error, Socket, etimedout},
-
- ssl_test_lib:check_result(Client, {ssl_closed, SslSocket}).
-
-%%--------------------------------------------------------------------
-recv_error_handling() ->
- [{doc,"Special case of call error handling"}].
-recv_error_handling(Config) when is_list(Config) ->
- ClientOpts = ssl_test_lib:ssl_options(client_opts, Config),
- ServerOpts = ssl_test_lib:ssl_options(server_opts, Config),
-
- {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
- Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0},
- {from, self()},
- {mfa, {?MODULE, recv_close, []}},
- {options, [{active, false} | ServerOpts]}]),
- Port = ssl_test_lib:inet_port(Server),
- {_Client, #sslsocket{} = SslSocket} = ssl_test_lib:start_client([return_socket,
- {node, ClientNode}, {port, Port},
- {host, Hostname},
- {from, self()},
- {mfa, {ssl_test_lib, no_result, []}},
- {options, ClientOpts}]),
- ssl:close(SslSocket),
- ssl_test_lib:check_result(Server, ok).
-
-
-
-%%--------------------------------------------------------------------
-call_in_error_state() ->
- [{doc,"Special case of call error handling"}].
-call_in_error_state(Config) when is_list(Config) ->
- ServerOpts0 = ssl_test_lib:ssl_options(server_opts, Config),
- ClientOpts = ssl_test_lib:ssl_options(client_opts, Config),
- ServerOpts = [{cacertfile, "foo.pem"} | proplists:delete(cacertfile, ServerOpts0)],
- Pid = spawn_link(?MODULE, run_error_server, [[self() | ServerOpts]]),
- receive
- {Pid, Port} ->
- spawn_link(?MODULE, run_client_error, [[Port, ClientOpts]])
- end,
- receive
- {error, closed} ->
- ok;
- Other ->
- ct:fail(Other)
- end.
-
-run_client_error([Port, Opts]) ->
- ssl:connect("localhost", Port, Opts).
-run_error_server([ Pid | Opts]) ->
- {ok, Listen} = ssl:listen(0, Opts),
- {ok,{_, Port}} = ssl:sockname(Listen),
- Pid ! {self(), Port},
- {ok, Socket} = ssl:transport_accept(Listen),
- Pid ! ssl:controlling_process(Socket, self()).
-
-%%--------------------------------------------------------------------
-
-close_in_error_state() ->
- [{doc,"Special case of closing socket in error state"}].
-close_in_error_state(Config) when is_list(Config) ->
- ServerOpts0 = ssl_test_lib:ssl_options(server_opts, Config),
- ServerOpts = [{cacertfile, "foo.pem"} | proplists:delete(cacertfile, ServerOpts0)],
- ClientOpts = ssl_test_lib:ssl_options(client_opts, Config),
- _ = spawn_link(?MODULE, run_error_server_close, [[self() | ServerOpts]]),
- receive
- {_Pid, Port} ->
- spawn_link(?MODULE, run_client_error, [[Port, ClientOpts]])
- end,
- receive
- ok ->
- ok;
- Other ->
- ct:fail(Other)
- end.
-%%--------------------------------------------------------------------
-abuse_transport_accept_socket() ->
- [{doc,"Only ssl:handshake and ssl:controlling_process is allowed for transport_accept:sockets"}].
-abuse_transport_accept_socket(Config) when is_list(Config) ->
- ServerOpts = ssl_test_lib:ssl_options(server_opts, Config),
- ClientOpts = ssl_test_lib:ssl_options(client_opts, Config),
- {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
+ ssl_test_lib:check_result(Server, ok, Client, ok),
- Server = ssl_test_lib:start_server_transport_abuse_socket([{node, ServerNode},
- {port, 0},
- {from, self()},
- {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, no_result, []}},
- {options, ClientOpts}]),
- ssl_test_lib:check_result(Server, ok),
ssl_test_lib:close(Server),
ssl_test_lib:close(Client).
-
-
-%%--------------------------------------------------------------------
-controlling_process_transport_accept_socket() ->
- [{doc,"Only ssl:handshake and ssl:controlling_process is allowed for transport_accept:sockets"}].
-controlling_process_transport_accept_socket(Config) when is_list(Config) ->
- ServerOpts = ssl_test_lib:ssl_options(server_opts, Config),
- ClientOpts = ssl_test_lib:ssl_options(client_opts, Config),
- {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
-
- Server = ssl_test_lib:start_server_transport_control([{node, ServerNode},
- {port, 0},
- {from, self()},
- {options, ServerOpts}]),
- Port = ssl_test_lib:inet_port(Server),
-
- _Client = ssl_test_lib:start_client_error([{node, ClientNode}, {port, Port},
- {host, Hostname},
- {from, self()},
- {options, ClientOpts}]),
- ssl_test_lib:check_result(Server, ok),
- ssl_test_lib:close(Server).
-
-%%--------------------------------------------------------------------
-run_error_server_close([Pid | Opts]) ->
- {ok, Listen} = ssl:listen(0, Opts),
- {ok,{_, Port}} = ssl:sockname(Listen),
- Pid ! {self(), Port},
- {ok, Socket} = ssl:transport_accept(Listen),
- Pid ! ssl:close(Socket).
-
-%%--------------------------------------------------------------------
-
-rizzo() ->
- [{doc, "Test that there is a 1/n-1-split for non RC4 in 'TLS < 1.1' as it is
- vunrable to Rizzo/Dungon attack"}].
-
-rizzo(Config) when is_list(Config) ->
- Prop = proplists:get_value(tc_group_properties, Config),
- Version = proplists:get_value(name, Prop),
- NVersion = ssl_test_lib:protocol_version(Config, tuple),
- Ciphers = ssl:filter_cipher_suites(ssl:cipher_suites(all, NVersion),
- [{key_exchange,
- fun(Alg) when Alg == ecdh_rsa; Alg == ecdhe_rsa->
- true;
- (_) ->
- false
- end},
- {cipher,
- fun(rc4_128) ->
- false;
- (chacha20_poly1305) ->
- false;
- (_) ->
- true
- end}]),
-
- run_send_recv_rizzo(Ciphers, Config, Version,
- {?MODULE, send_recv_result_active_rizzo, []}).
-%%--------------------------------------------------------------------
-no_rizzo_rc4() ->
- [{doc,"Test that there is no 1/n-1-split for RC4 as it is not vunrable to Rizzo/Dungon attack"}].
-
-no_rizzo_rc4(Config) when is_list(Config) ->
- Prop = proplists:get_value(tc_group_properties, Config),
- Version = proplists:get_value(name, Prop),
- NVersion = ssl_test_lib:protocol_version(Config, tuple),
- %% Test uses RSA certs
- Ciphers = ssl:filter_cipher_suites(ssl_test_lib:rc4_suites(NVersion),
- [{key_exchange,
- fun(Alg) when Alg == ecdh_rsa; Alg == ecdhe_rsa->
- true;
- (_) ->
- false
- end}]),
- run_send_recv_rizzo(Ciphers, Config, Version,
- {?MODULE, send_recv_result_active_no_rizzo, []}).
-
-rizzo_one_n_minus_one() ->
- [{doc,"Test that the 1/n-1-split mitigation of Rizzo/Dungon attack can be explicitly selected"}].
-
-rizzo_one_n_minus_one(Config) when is_list(Config) ->
- Prop = proplists:get_value(tc_group_properties, Config),
- Version = proplists:get_value(name, Prop),
- NVersion = ssl_test_lib:protocol_version(Config, tuple),
- Ciphers = ssl:filter_cipher_suites(ssl:cipher_suites(all, NVersion),
- [{key_exchange,
- fun(Alg) when Alg == ecdh_rsa; Alg == ecdhe_rsa->
- true;
- (_) ->
- false
- end},
- {cipher,
- fun(rc4_128) ->
- false;
- %% TODO: remove this clause when chacha is fixed!
- (chacha20_poly1305) ->
- false;
- (_) ->
- true
- end}]),
- run_send_recv_rizzo(Ciphers, Config, Version,
- {?MODULE, send_recv_result_active_rizzo, []}).
-
-rizzo_zero_n() ->
- [{doc,"Test that the 0/n-split mitigation of Rizzo/Dungon attack can be explicitly selected"}].
-
-rizzo_zero_n(Config) when is_list(Config) ->
- Prop = proplists:get_value(tc_group_properties, Config),
- Version = proplists:get_value(name, Prop),
- NVersion = ssl_test_lib:protocol_version(Config, tuple),
- Ciphers = ssl:filter_cipher_suites(ssl:cipher_suites(default, NVersion),
- [{cipher,
- fun(rc4_128) ->
- false;
- (_) ->
- true
- end}]),
- run_send_recv_rizzo(Ciphers, Config, Version,
- {?MODULE, send_recv_result_active_no_rizzo, []}).
-
-rizzo_disabled() ->
- [{doc,"Test that the mitigation of Rizzo/Dungon attack can be explicitly disabled"}].
-
-rizzo_disabled(Config) when is_list(Config) ->
- Prop = proplists:get_value(tc_group_properties, Config),
- Version = proplists:get_value(name, Prop),
- NVersion = ssl_test_lib:protocol_version(Config, tuple),
- Ciphers = ssl:filter_cipher_suites(ssl:cipher_suites(default, NVersion),
- [{cipher,
- fun(rc4_128) ->
- false;
- (_) ->
- true
- end}]),
- run_send_recv_rizzo(Ciphers, Config, Version,
- {?MODULE, send_recv_result_active_no_rizzo, []}).
-
-%%--------------------------------------------------------------------
-new_server_wants_peer_cert() ->
- [{doc, "Test that server configured to do client certification does"
- " not reuse session without a client certificate."}].
-new_server_wants_peer_cert(Config) when is_list(Config) ->
- ServerOpts = ssl_test_lib:ssl_options(server_opts, Config),
- VServerOpts = [{verify, verify_peer}, {fail_if_no_peer_cert, true}
- | ssl_test_lib:ssl_options(server_verification_opts, Config)],
- ClientOpts = ssl_test_lib:ssl_options(client_verification_opts, Config),
-
- {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
-
- Server =
- ssl_test_lib:start_server([{node, ServerNode}, {port, 0},
- {from, self()},
- {mfa, {?MODULE, peercert_result, []}},
- {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, no_result, []}},
- {options, ClientOpts}]),
-
- Monitor = erlang:monitor(process, Server),
- ssl_test_lib:close(Server),
- ssl_test_lib:close(Client),
- receive
- {'DOWN', Monitor, _, _, _} ->
- ok
- end,
-
- Server1 = ssl_test_lib:start_server([{node, ServerNode}, {port, Port},
- {from, self()},
- {mfa, {?MODULE, peercert_result, []}},
- {options, VServerOpts}]),
- Client1 =
- ssl_test_lib:start_client([{node, ClientNode}, {port, Port},
- {host, Hostname},
- {from, self()},
- {mfa, {ssl_test_lib, no_result, []}},
- {options, [ClientOpts]}]),
-
- CertFile = proplists:get_value(certfile, ClientOpts),
- [{'Certificate', BinCert, _}]= ssl_test_lib:pem_to_der(CertFile),
-
- ServerMsg = {error, no_peercert},
- Sever1Msg = {ok, BinCert},
-
- ssl_test_lib:check_result(Server, ServerMsg, Server1, Sever1Msg),
-
- ssl_test_lib:close(Server1),
- ssl_test_lib:close(Client),
- ssl_test_lib:close(Client1).
-
-%%--------------------------------------------------------------------
-session_cache_process_list() ->
- [{doc,"Test reuse of sessions (short handshake)"}].
-session_cache_process_list(Config) when is_list(Config) ->
- session_cache_process(list,Config).
-%%--------------------------------------------------------------------
-session_cache_process_mnesia() ->
- [{doc,"Test reuse of sessions (short handshake)"}].
-session_cache_process_mnesia(Config) when is_list(Config) ->
- session_cache_process(mnesia,Config).
+eccs() ->
+ [{doc, "Test API functions eccs/0 and eccs/1"}].
-%%--------------------------------------------------------------------
+eccs(Config) when is_list(Config) ->
+ [_|_] = All = ssl:eccs(),
+ [] = ssl:eccs(sslv3),
+ [_|_] = Tls = ssl:eccs(tlsv1),
+ [_|_] = Tls1 = ssl:eccs('tlsv1.1'),
+ [_|_] = Tls2 = ssl:eccs('tlsv1.2'),
+ [_|_] = Tls1 = ssl:eccs('dtlsv1'),
+ [_|_] = Tls2 = ssl:eccs('dtlsv1.2'),
+ %% ordering is currently not verified by the test
+ true = lists:sort(All) =:= lists:usort(Tls ++ Tls1 ++ Tls2),
+ ok.
tls_versions_option() ->
[{doc,"Test API versions option to connect/listen."}].
@@ -4323,2140 +452,6 @@ tls_versions_option(Config) when is_list(Config) ->
%%--------------------------------------------------------------------
-unordered_protocol_versions_server() ->
- [{doc,"Test that the highest protocol is selected even"
- " when it is not first in the versions list."}].
-
-unordered_protocol_versions_server(Config) when is_list(Config) ->
- ClientOpts = ssl_test_lib:ssl_options(client_opts, Config),
- ServerOpts = ssl_test_lib:ssl_options(server_opts, Config),
-
- {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
- Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0},
- {from, self()},
- {mfa, {?MODULE, protocol_info_result, []}},
- {options, [{versions, ['tlsv1.1', 'tlsv1.2']} | ServerOpts]}]),
- Port = ssl_test_lib:inet_port(Server),
-
- Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port},
- {host, Hostname},
- {from, self()},
- {mfa, {?MODULE, protocol_info_result, []}},
- {options, ClientOpts}]),
-
- ServerMsg = ClientMsg = {ok,'tlsv1.2'},
- ssl_test_lib:check_result(Server, ServerMsg, Client, ClientMsg).
-
-%%--------------------------------------------------------------------
-unordered_protocol_versions_client() ->
- [{doc,"Test that the highest protocol is selected even"
- " when it is not first in the versions list."}].
-
-unordered_protocol_versions_client(Config) when is_list(Config) ->
- ClientOpts = ssl_test_lib:ssl_options(client_opts, Config),
- ServerOpts = ssl_test_lib:ssl_options(server_opts, Config),
-
- {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
- Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0},
- {from, self()},
- {mfa, {?MODULE, protocol_info_result, []}},
- {options, ServerOpts }]),
- Port = ssl_test_lib:inet_port(Server),
-
- Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port},
- {host, Hostname},
- {from, self()},
- {mfa, {?MODULE, protocol_info_result, []}},
- {options, [{versions, ['tlsv1.1', 'tlsv1.2']} | ClientOpts]}]),
-
- ServerMsg = ClientMsg = {ok, 'tlsv1.2'},
- ssl_test_lib:check_result(Server, ServerMsg, Client, ClientMsg).
-
-%%--------------------------------------------------------------------
-max_handshake_size() ->
- [{doc,"Test that we can set max_handshake_size to max value."}].
-
-max_handshake_size(Config) when is_list(Config) ->
- ClientOpts = ssl_test_lib:ssl_options(client_opts, Config),
- ServerOpts = ssl_test_lib:ssl_options(server_opts, Config),
-
- {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
- Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0},
- {from, self()},
- {mfa, {ssl_test_lib, send_recv_result_active, []}},
- {options, [{max_handshake_size, 8388607} |ServerOpts]}]),
- Port = ssl_test_lib:inet_port(Server),
-
- Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port},
- {host, Hostname},
- {from, self()},
- {mfa, {ssl_test_lib, send_recv_result_active, []}},
- {options, [{max_handshake_size, 8388607} | ClientOpts]}]),
-
- ssl_test_lib:check_result(Server, ok, Client, ok).
-
-%%--------------------------------------------------------------------
-
-server_name_indication_option() ->
- [{doc,"Test API server_name_indication option to connect."}].
-server_name_indication_option(Config) when is_list(Config) ->
- ClientOpts = ssl_test_lib:ssl_options(client_opts, Config),
- ServerOpts = ssl_test_lib:ssl_options(server_opts, Config),
-
- {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
- Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0},
- {from, self()},
- {mfa, {ssl_test_lib, send_recv_result_active, []}},
- {options, ServerOpts}]),
- Port = ssl_test_lib:inet_port(Server),
-
- Client0 = ssl_test_lib:start_client([{node, ClientNode}, {port, Port},
- {host, Hostname},
- {from, self()},
- {mfa, {ssl_test_lib, send_recv_result_active, []}},
- {options,
- [{server_name_indication, disable} |
- ClientOpts]}
- ]),
-
- ssl_test_lib:check_result(Server, ok, Client0, ok),
- Server ! listen,
-
- Client1 = ssl_test_lib:start_client([{node, ClientNode}, {port, Port},
- {host, Hostname},
- {from, self()},
- {mfa, {ssl_test_lib, send_recv_result_active, []}},
- {options,
- [{server_name_indication, Hostname} | ClientOpts]
- }]),
- ssl_test_lib:check_result(Server, ok, Client1, ok),
- ssl_test_lib:close(Server),
- ssl_test_lib:close(Client0),
- ssl_test_lib:close(Client1).
-%%--------------------------------------------------------------------
-
-accept_pool() ->
- [{doc,"Test having an accept pool."}].
-accept_pool(Config) when is_list(Config) ->
- ClientOpts = ssl_test_lib:ssl_options(client_opts, Config),
- ServerOpts = ssl_test_lib:ssl_options(server_opts, Config),
-
- {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
- Server0 = ssl_test_lib:start_server([{node, ServerNode}, {port, 0},
- {from, self()},
- {accepters, 3},
- {mfa, {ssl_test_lib, send_recv_result_active, []}},
- {options, ServerOpts}]),
- Port = ssl_test_lib:inet_port(Server0),
- [Server1, Server2] = ssl_test_lib:accepters(2),
-
- Client0 = ssl_test_lib:start_client([{node, ClientNode}, {port, Port},
- {host, Hostname},
- {from, self()},
- {mfa, {ssl_test_lib, send_recv_result_active, []}},
- {options, ClientOpts}
- ]),
-
- Client1 = ssl_test_lib:start_client([{node, ClientNode}, {port, Port},
- {host, Hostname},
- {from, self()},
- {mfa, {ssl_test_lib, send_recv_result_active, []}},
- {options, ClientOpts}
- ]),
-
- Client2 = ssl_test_lib:start_client([{node, ClientNode}, {port, Port},
- {host, Hostname},
- {from, self()},
- {mfa, {ssl_test_lib, send_recv_result_active, []}},
- {options, ClientOpts}
- ]),
-
- ssl_test_lib:check_ok([Server0, Server1, Server2, Client0, Client1, Client2]),
-
- ssl_test_lib:close(Server0),
- ssl_test_lib:close(Server1),
- ssl_test_lib:close(Server2),
- ssl_test_lib:close(Client0),
- ssl_test_lib:close(Client1),
- ssl_test_lib:close(Client2).
-
-%%--------------------------------------------------------------------
-%% TLS 1.3
-%%--------------------------------------------------------------------
-
-tls13_enable_client_side() ->
- [{doc,"Test that a TLS 1.3 client can connect to a TLS 1.2 server."}].
-
-tls13_enable_client_side(Config) when is_list(Config) ->
- ClientOpts = ssl_test_lib:ssl_options(client_opts, Config),
- ServerOpts = ssl_test_lib:ssl_options(server_opts, Config),
-
- {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
- Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0},
- {from, self()},
- {mfa, {?MODULE, protocol_info_result, []}},
- {options, [{versions,
- ['tlsv1.1', 'tlsv1.2']} | ServerOpts] }]),
- Port = ssl_test_lib:inet_port(Server),
-
- Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port},
- {host, Hostname},
- {from, self()},
- {mfa, {?MODULE, protocol_info_result, []}},
- {options, [{versions,
- ['tlsv1.2', 'tlsv1.3']} | ClientOpts]}]),
-
- ServerMsg = ClientMsg = {ok, 'tlsv1.2'},
- ssl_test_lib:check_result(Server, ServerMsg, Client, ClientMsg).
-
-tls13_enable_server_side() ->
- [{doc,"Test that a TLS 1.2 client can connect to a TLS 1.3 server."}].
-
-tls13_enable_server_side(Config) when is_list(Config) ->
- ClientOpts = ssl_test_lib:ssl_options(client_opts, Config),
- ServerOpts = ssl_test_lib:ssl_options(server_opts, Config),
-
- {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
- Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0},
- {from, self()},
- {mfa, {?MODULE, protocol_info_result, []}},
- {options, [{versions,
- ['tlsv1.2', 'tlsv1.3']} | ServerOpts] }]),
- Port = ssl_test_lib:inet_port(Server),
-
- Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port},
- {host, Hostname},
- {from, self()},
- {mfa, {?MODULE, protocol_info_result, []}},
- {options, [{versions,
- ['tlsv1.2', 'tlsv1.1']} | ClientOpts]}]),
-
- ServerMsg = ClientMsg = {ok, 'tlsv1.2'},
- ssl_test_lib:check_result(Server, ServerMsg, Client, ClientMsg).
-
-tls_record_1_3_encode_decode() ->
- [{doc,"Test TLS 1.3 record encode/decode functions"}].
-
-tls_record_1_3_encode_decode(_Config) ->
- ConnectionStates =
- #{current_read =>
- #{beast_mitigation => one_n_minus_one,
- cipher_state =>
- {cipher_state,
- <<14,172,111,243,199,170,242,203,126,205,34,93,122,115,226,14,
- 15,117,155,48,24,112,61,15,113,208,127,51,179,227,194,232>>,
- <<197,54,168,218,54,91,157,58,30,201,197,142,51,58,53,231,228,
- 131,57,122,170,78,82,196,30,48,23,16,95,255,185,236>>,
- undefined,undefined,undefined,16},
- client_verify_data => undefined,compression_state => undefined,
- mac_secret => undefined,secure_renegotiation => undefined,
- security_parameters =>
- {security_parameters,
- <<19,2>>,
- 0,8,2,undefined,undefined,undefined,undefined,undefined,
- sha384,undefined,undefined,
- {handshake_secret,
- <<128,229,186,211,62,127,182,20,62,166,233,23,135,64,121,
- 3,104,251,214,161,253,31,3,2,232,37,8,221,189,72,64,218,
- 121,41,112,148,254,34,68,164,228,60,161,201,132,55,56,
- 157>>},
- undefined,
- <<92,24,205,75,244,60,136,212,250,32,214,20,37,3,213,87,61,207,
- 147,61,168,145,177,118,160,153,33,53,48,108,191,174>>,
- undefined},
- sequence_number => 0,server_verify_data => undefined},
- current_write =>
- #{beast_mitigation => one_n_minus_one,
- cipher_state =>
- {cipher_state,
- <<14,172,111,243,199,170,242,203,126,205,34,93,122,115,226,14,
- 15,117,155,48,24,112,61,15,113,208,127,51,179,227,194,232>>,
- <<197,54,168,218,54,91,157,58,30,201,197,142,51,58,53,231,228,
- 131,57,122,170,78,82,196,30,48,23,16,95,255,185,236>>,
- undefined,undefined,undefined,16},
- client_verify_data => undefined,compression_state => undefined,
- mac_secret => undefined,secure_renegotiation => undefined,
- security_parameters =>
- {security_parameters,
- <<19,2>>,
- 0,8,2,undefined,undefined,undefined,undefined,undefined,
- sha384,undefined,undefined,
- {handshake_secret,
- <<128,229,186,211,62,127,182,20,62,166,233,23,135,64,121,
- 3,104,251,214,161,253,31,3,2,232,37,8,221,189,72,64,218,
- 121,41,112,148,254,34,68,164,228,60,161,201,132,55,56,
- 157>>},
- undefined,
- <<92,24,205,75,244,60,136,212,250,32,214,20,37,3,213,87,61,207,
- 147,61,168,145,177,118,160,153,33,53,48,108,191,174>>,
- undefined},
- sequence_number => 0,server_verify_data => undefined}},
-
- PlainText = [11,
- <<0,2,175>>,
- <<0,0,2,171,0,2,166,48,130,2,162,48,130,1,138,2,9,0,186,57,220,137,88,255,
- 191,235,48,13,6,9,42,134,72,134,247,13,1,1,11,5,0,48,18,49,16,48,14,6,3,85,
- 4,3,12,7,84,101,115,116,32,67,65,48,30,23,13,49,56,48,53,48,52,49,52,49,50,
- 51,56,90,23,13,50,56,48,50,48,52,49,52,49,50,51,56,90,48,20,49,18,48,16,6,
- 3,85,4,3,12,9,108,111,99,97,108,104,111,115,116,48,130,1,34,48,13,6,9,42,
- 134,72,134,247,13,1,1,1,5,0,3,130,1,15,0,48,130,1,10,2,130,1,1,0,169,40,
- 144,176,121,63,134,97,144,126,243,183,225,157,37,131,183,225,87,243,23,88,
- 230,70,9,134,32,147,7,27,167,98,51,81,224,75,199,12,229,251,195,207,75,179,
- 181,78,128,3,255,44,58,39,43,172,142,45,186,58,51,65,187,199,154,153,245,
- 70,133,137,1,27,87,42,116,65,251,129,109,145,233,97,171,71,54,213,185,74,
- 209,166,11,218,189,119,206,86,170,60,212,213,85,189,30,50,215,23,185,53,
- 132,238,132,176,198,250,139,251,198,221,225,128,109,113,23,220,39,143,71,
- 30,59,189,51,244,61,158,214,146,180,196,103,169,189,221,136,78,129,216,148,
- 2,9,8,65,37,224,215,233,13,209,21,235,20,143,33,74,59,53,208,90,152,94,251,
- 54,114,171,39,88,230,227,158,211,135,37,182,67,205,161,59,20,138,58,253,15,
- 53,48,8,157,9,95,197,9,177,116,21,54,9,125,78,109,182,83,20,16,234,223,116,
- 41,155,123,87,77,17,120,153,246,239,124,130,105,219,166,146,242,151,66,198,
- 75,72,63,28,246,86,16,244,223,22,36,50,15,247,222,98,6,152,136,154,72,150,
- 73,127,2,3,1,0,1,48,13,6,9,42,134,72,134,247,13,1,1,11,5,0,3,130,1,1,0,76,
- 33,54,160,229,219,219,193,150,116,245,252,18,39,235,145,86,12,167,171,52,
- 117,166,30,83,5,216,245,177,217,247,95,1,136,94,246,212,108,248,230,111,
- 225,202,189,6,129,8,70,128,245,18,204,215,87,82,129,253,227,122,66,182,184,
- 189,30,193,169,144,218,216,109,105,110,215,144,60,104,162,178,101,164,218,
- 122,60,37,41,143,57,150,52,59,51,112,238,113,239,168,114,69,183,143,154,73,
- 61,58,80,247,172,95,251,55,28,186,28,200,206,230,118,243,92,202,189,49,76,
- 124,252,76,0,247,112,85,194,69,59,222,163,228,103,49,110,104,109,251,155,
- 138,9,37,167,49,189,48,134,52,158,185,129,24,96,153,196,251,90,206,76,239,
- 175,119,174,165,133,108,222,125,237,125,187,149,152,83,190,16,202,94,202,
- 201,40,218,22,254,63,189,41,174,97,140,203,70,18,196,118,237,175,134,79,78,
- 246,2,61,54,77,186,112,32,17,193,192,188,217,252,215,200,7,245,180,179,132,
- 183,212,229,155,15,152,206,135,56,81,88,3,123,244,149,110,182,72,109,70,62,
- 146,152,146,151,107,126,216,210,9,93,0,0>>],
-
- {[_Header|Encoded], _} = tls_record_1_3:encode_plain_text(22, PlainText, ConnectionStates),
- CipherText = #ssl_tls{type = 23, version = {3,3}, fragment = Encoded},
-
- {#ssl_tls{type = 22, version = {3,4}, fragment = DecodedText}, _} =
- tls_record_1_3:decode_cipher_text(CipherText, ConnectionStates),
-
- DecodedText = iolist_to_binary(PlainText),
- ct:log("Decoded: ~p ~n", [DecodedText]),
- ok.
-
-tls13_1_RTT_handshake() ->
- [{doc,"Test TLS 1.3 1-RTT Handshake"}].
-
-tls13_1_RTT_handshake(_Config) ->
- %% ConnectionStates with NULL cipher
- ConnStatesNull =
- #{current_write =>
- #{security_parameters =>
- #security_parameters{cipher_suite = ?TLS_NULL_WITH_NULL_NULL},
- sequence_number => 0
- }
- },
-
- %% {client} construct a ClientHello handshake message:
- %%
- %% ClientHello (196 octets): 01 00 00 c0 03 03 cb 34 ec b1 e7 81 63
- %% ba 1c 38 c6 da cb 19 6a 6d ff a2 1a 8d 99 12 ec 18 a2 ef 62 83
- %% 02 4d ec e7 00 00 06 13 01 13 03 13 02 01 00 00 91 00 00 00 0b
- %% 00 09 00 00 06 73 65 72 76 65 72 ff 01 00 01 00 00 0a 00 14 00
- %% 12 00 1d 00 17 00 18 00 19 01 00 01 01 01 02 01 03 01 04 00 23
- %% 00 00 00 33 00 26 00 24 00 1d 00 20 99 38 1d e5 60 e4 bd 43 d2
- %% 3d 8e 43 5a 7d ba fe b3 c0 6e 51 c1 3c ae 4d 54 13 69 1e 52 9a
- %% af 2c 00 2b 00 03 02 03 04 00 0d 00 20 00 1e 04 03 05 03 06 03
- %% 02 03 08 04 08 05 08 06 04 01 05 01 06 01 02 01 04 02 05 02 06
- %% 02 02 02 00 2d 00 02 01 01 00 1c 00 02 40 01
- %%
- %% {client} send handshake record:
- %%
- %% payload (196 octets): 01 00 00 c0 03 03 cb 34 ec b1 e7 81 63 ba
- %% 1c 38 c6 da cb 19 6a 6d ff a2 1a 8d 99 12 ec 18 a2 ef 62 83 02
- %% 4d ec e7 00 00 06 13 01 13 03 13 02 01 00 00 91 00 00 00 0b 00
- %% 09 00 00 06 73 65 72 76 65 72 ff 01 00 01 00 00 0a 00 14 00 12
- %% 00 1d 00 17 00 18 00 19 01 00 01 01 01 02 01 03 01 04 00 23 00
- %% 00 00 33 00 26 00 24 00 1d 00 20 99 38 1d e5 60 e4 bd 43 d2 3d
- %% 8e 43 5a 7d ba fe b3 c0 6e 51 c1 3c ae 4d 54 13 69 1e 52 9a af
- %% 2c 00 2b 00 03 02 03 04 00 0d 00 20 00 1e 04 03 05 03 06 03 02
- %% 03 08 04 08 05 08 06 04 01 05 01 06 01 02 01 04 02 05 02 06 02
- %% 02 02 00 2d 00 02 01 01 00 1c 00 02 40 01
- %%
- %% complete record (201 octets): 16 03 01 00 c4 01 00 00 c0 03 03 cb
- %% 34 ec b1 e7 81 63 ba 1c 38 c6 da cb 19 6a 6d ff a2 1a 8d 99 12
- %% ec 18 a2 ef 62 83 02 4d ec e7 00 00 06 13 01 13 03 13 02 01 00
- %% 00 91 00 00 00 0b 00 09 00 00 06 73 65 72 76 65 72 ff 01 00 01
- %% 00 00 0a 00 14 00 12 00 1d 00 17 00 18 00 19 01 00 01 01 01 02
- %% 01 03 01 04 00 23 00 00 00 33 00 26 00 24 00 1d 00 20 99 38 1d
- %% e5 60 e4 bd 43 d2 3d 8e 43 5a 7d ba fe b3 c0 6e 51 c1 3c ae 4d
- %% 54 13 69 1e 52 9a af 2c 00 2b 00 03 02 03 04 00 0d 00 20 00 1e
- %% 04 03 05 03 06 03 02 03 08 04 08 05 08 06 04 01 05 01 06 01 02
- %% 01 04 02 05 02 06 02 02 02 00 2d 00 02 01 01 00 1c 00 02 40 01
- ClientHello =
- hexstr2bin("01 00 00 c0 03 03 cb 34 ec b1 e7 81 63
- ba 1c 38 c6 da cb 19 6a 6d ff a2 1a 8d 99 12 ec 18 a2 ef 62 83
- 02 4d ec e7 00 00 06 13 01 13 03 13 02 01 00 00 91 00 00 00 0b
- 00 09 00 00 06 73 65 72 76 65 72 ff 01 00 01 00 00 0a 00 14 00
- 12 00 1d 00 17 00 18 00 19 01 00 01 01 01 02 01 03 01 04 00 23
- 00 00 00 33 00 26 00 24 00 1d 00 20 99 38 1d e5 60 e4 bd 43 d2
- 3d 8e 43 5a 7d ba fe b3 c0 6e 51 c1 3c ae 4d 54 13 69 1e 52 9a
- af 2c 00 2b 00 03 02 03 04 00 0d 00 20 00 1e 04 03 05 03 06 03
- 02 03 08 04 08 05 08 06 04 01 05 01 06 01 02 01 04 02 05 02 06
- 02 02 02 00 2d 00 02 01 01 00 1c 00 02 40 01"),
-
- ClientHelloRecord =
- %% Current implementation always sets
- %% legacy_record_version to Ox0303
- hexstr2bin("16 03 03 00 c4 01 00 00 c0 03 03 cb
- 34 ec b1 e7 81 63 ba 1c 38 c6 da cb 19 6a 6d ff a2 1a 8d 99 12
- ec 18 a2 ef 62 83 02 4d ec e7 00 00 06 13 01 13 03 13 02 01 00
- 00 91 00 00 00 0b 00 09 00 00 06 73 65 72 76 65 72 ff 01 00 01
- 00 00 0a 00 14 00 12 00 1d 00 17 00 18 00 19 01 00 01 01 01 02
- 01 03 01 04 00 23 00 00 00 33 00 26 00 24 00 1d 00 20 99 38 1d
- e5 60 e4 bd 43 d2 3d 8e 43 5a 7d ba fe b3 c0 6e 51 c1 3c ae 4d
- 54 13 69 1e 52 9a af 2c 00 2b 00 03 02 03 04 00 0d 00 20 00 1e
- 04 03 05 03 06 03 02 03 08 04 08 05 08 06 04 01 05 01 06 01 02
- 01 04 02 05 02 06 02 02 02 00 2d 00 02 01 01 00 1c 00 02 40 01"),
-
- {CHEncrypted, _} =
- tls_record:encode_handshake(ClientHello, {3,4}, ConnStatesNull),
- ClientHelloRecord = iolist_to_binary(CHEncrypted),
-
- %% {server} extract secret "early":
- %%
- %% salt: 0 (all zero octets)
- %%
- %% IKM (32 octets): 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
- %% 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
- %%
- %% secret (32 octets): 33 ad 0a 1c 60 7e c0 3b 09 e6 cd 98 93 68 0c
- %% e2 10 ad f3 00 aa 1f 26 60 e1 b2 2e 10 f1 70 f9 2a
- HKDFAlgo = sha256,
- Salt = binary:copy(<<?BYTE(0)>>, 32),
- IKM = binary:copy(<<?BYTE(0)>>, 32),
- EarlySecret =
- hexstr2bin("33 ad 0a 1c 60 7e c0 3b 09 e6 cd 98 93 68 0c
- e2 10 ad f3 00 aa 1f 26 60 e1 b2 2e 10 f1 70 f9 2a"),
-
- {early_secret, EarlySecret} = tls_v1:key_schedule(early_secret, HKDFAlgo, {psk, Salt}),
-
- %% {client} create an ephemeral x25519 key pair:
- %%
- %% private key (32 octets): 49 af 42 ba 7f 79 94 85 2d 71 3e f2 78
- %% 4b cb ca a7 91 1d e2 6a dc 56 42 cb 63 45 40 e7 ea 50 05
- %%
- %% public key (32 octets): 99 38 1d e5 60 e4 bd 43 d2 3d 8e 43 5a 7d
- %% ba fe b3 c0 6e 51 c1 3c ae 4d 54 13 69 1e 52 9a af 2c
- CPublicKey =
- hexstr2bin("99 38 1d e5 60 e4 bd 43 d2 3d 8e 43 5a 7d
- ba fe b3 c0 6e 51 c1 3c ae 4d 54 13 69 1e 52 9a af 2c"),
-
- %% {server} create an ephemeral x25519 key pair:
- %%
- %% private key (32 octets): b1 58 0e ea df 6d d5 89 b8 ef 4f 2d 56
- %% 52 57 8c c8 10 e9 98 01 91 ec 8d 05 83 08 ce a2 16 a2 1e
- %%
- %% public key (32 octets): c9 82 88 76 11 20 95 fe 66 76 2b db f7 c6
- %% 72 e1 56 d6 cc 25 3b 83 3d f1 dd 69 b1 b0 4e 75 1f 0f
- SPrivateKey =
- hexstr2bin("b1 58 0e ea df 6d d5 89 b8 ef 4f 2d 56
- 52 57 8c c8 10 e9 98 01 91 ec 8d 05 83 08 ce a2 16 a2 1e"),
-
- SPublicKey =
- hexstr2bin("c9 82 88 76 11 20 95 fe 66 76 2b db f7 c6
- 72 e1 56 d6 cc 25 3b 83 3d f1 dd 69 b1 b0 4e 75 1f 0f"),
-
- %% {server} construct a ServerHello handshake message:
- %%
- %% ServerHello (90 octets): 02 00 00 56 03 03 a6 af 06 a4 12 18 60
- %% dc 5e 6e 60 24 9c d3 4c 95 93 0c 8a c5 cb 14 34 da c1 55 77 2e
- %% d3 e2 69 28 00 13 01 00 00 2e 00 33 00 24 00 1d 00 20 c9 82 88
- %% 76 11 20 95 fe 66 76 2b db f7 c6 72 e1 56 d6 cc 25 3b 83 3d f1
- %% dd 69 b1 b0 4e 75 1f 0f 00 2b 00 02 03 04
- ServerHello =
- hexstr2bin("02 00 00 56 03 03 a6 af 06 a4 12 18 60
- dc 5e 6e 60 24 9c d3 4c 95 93 0c 8a c5 cb 14 34 da c1 55 77 2e
- d3 e2 69 28 00 13 01 00 00 2e 00 33 00 24 00 1d 00 20 c9 82 88
- 76 11 20 95 fe 66 76 2b db f7 c6 72 e1 56 d6 cc 25 3b 83 3d f1
- dd 69 b1 b0 4e 75 1f 0f 00 2b 00 02 03 04"),
-
- %% {server} derive secret for handshake "tls13 derived":
- %%
- %% PRK (32 octets): 33 ad 0a 1c 60 7e c0 3b 09 e6 cd 98 93 68 0c e2
- %% 10 ad f3 00 aa 1f 26 60 e1 b2 2e 10 f1 70 f9 2a
- %%
- %% hash (32 octets): e3 b0 c4 42 98 fc 1c 14 9a fb f4 c8 99 6f b9 24
- %% 27 ae 41 e4 64 9b 93 4c a4 95 99 1b 78 52 b8 55
- %%
- %% info (49 octets): 00 20 0d 74 6c 73 31 33 20 64 65 72 69 76 65 64
- %% 20 e3 b0 c4 42 98 fc 1c 14 9a fb f4 c8 99 6f b9 24 27 ae 41 e4
- %% 64 9b 93 4c a4 95 99 1b 78 52 b8 55
- %%
- %% expanded (32 octets): 6f 26 15 a1 08 c7 02 c5 67 8f 54 fc 9d ba
- %% b6 97 16 c0 76 18 9c 48 25 0c eb ea c3 57 6c 36 11 ba
- Hash =
- hexstr2bin("e3 b0 c4 42 98 fc 1c 14 9a fb f4 c8 99 6f b9 24
- 27 ae 41 e4 64 9b 93 4c a4 95 99 1b 78 52 b8 55"),
-
- Hash = crypto:hash(HKDFAlgo, <<>>),
-
- Info =
- hexstr2bin("00 20 0d 74 6c 73 31 33 20 64 65 72 69 76 65 64
- 20 e3 b0 c4 42 98 fc 1c 14 9a fb f4 c8 99 6f b9 24 27 ae 41 e4
- 64 9b 93 4c a4 95 99 1b 78 52 b8 55"),
-
- Info = tls_v1:create_info(<<"derived">>, Hash, ssl_cipher:hash_size(HKDFAlgo)),
-
- Expanded =
- hexstr2bin("6f 26 15 a1 08 c7 02 c5 67 8f 54 fc 9d ba
- b6 97 16 c0 76 18 9c 48 25 0c eb ea c3 57 6c 36 11 ba"),
-
- Expanded = tls_v1:derive_secret(EarlySecret, <<"derived">>, <<>>, HKDFAlgo),
-
- %% {server} extract secret "handshake":
- %%
- %% salt (32 octets): 6f 26 15 a1 08 c7 02 c5 67 8f 54 fc 9d ba b6 97
- %% 16 c0 76 18 9c 48 25 0c eb ea c3 57 6c 36 11 ba
- %%
- %% IKM (32 octets): 8b d4 05 4f b5 5b 9d 63 fd fb ac f9 f0 4b 9f 0d
- %% 35 e6 d6 3f 53 75 63 ef d4 62 72 90 0f 89 49 2d
- %%
- %% secret (32 octets): 1d c8 26 e9 36 06 aa 6f dc 0a ad c1 2f 74 1b
- %% 01 04 6a a6 b9 9f 69 1e d2 21 a9 f0 ca 04 3f be ac
-
- %% salt = Expanded
- HandshakeIKM =
- hexstr2bin("8b d4 05 4f b5 5b 9d 63 fd fb ac f9 f0 4b 9f 0d
- 35 e6 d6 3f 53 75 63 ef d4 62 72 90 0f 89 49 2d"),
-
- HandshakeSecret =
- hexstr2bin("1d c8 26 e9 36 06 aa 6f dc 0a ad c1 2f 74 1b
- 01 04 6a a6 b9 9f 69 1e d2 21 a9 f0 ca 04 3f be ac"),
-
- HandshakeIKM = crypto:compute_key(ecdh, CPublicKey, SPrivateKey, x25519),
-
- {handshake_secret, HandshakeSecret} =
- tls_v1:key_schedule(handshake_secret, HKDFAlgo, HandshakeIKM,
- {early_secret, EarlySecret}),
-
- %% {server} derive secret "tls13 c hs traffic":
- %%
- %% PRK (32 octets): 1d c8 26 e9 36 06 aa 6f dc 0a ad c1 2f 74 1b 01
- %% 04 6a a6 b9 9f 69 1e d2 21 a9 f0 ca 04 3f be ac
- %%
- %% hash (32 octets): 86 0c 06 ed c0 78 58 ee 8e 78 f0 e7 42 8c 58 ed
- %% d6 b4 3f 2c a3 e6 e9 5f 02 ed 06 3c f0 e1 ca d8
- %%
- %% info (54 octets): 00 20 12 74 6c 73 31 33 20 63 20 68 73 20 74 72
- %% 61 66 66 69 63 20 86 0c 06 ed c0 78 58 ee 8e 78 f0 e7 42 8c 58
- %% ed d6 b4 3f 2c a3 e6 e9 5f 02 ed 06 3c f0 e1 ca d8
- %%
- %% expanded (32 octets): b3 ed db 12 6e 06 7f 35 a7 80 b3 ab f4 5e
- %% 2d 8f 3b 1a 95 07 38 f5 2e 96 00 74 6a 0e 27 a5 5a 21
-
- %% PRK = HandshakeSecret
- CHSTHash =
- hexstr2bin("86 0c 06 ed c0 78 58 ee 8e 78 f0 e7 42 8c 58 ed
- d6 b4 3f 2c a3 e6 e9 5f 02 ed 06 3c f0 e1 ca d8"),
-
- CHSTInfo =
- hexstr2bin("00 20 12 74 6c 73 31 33 20 63 20 68 73 20 74 72
- 61 66 66 69 63 20 86 0c 06 ed c0 78 58 ee 8e 78 f0 e7 42 8c 58
- ed d6 b4 3f 2c a3 e6 e9 5f 02 ed 06 3c f0 e1 ca d8"),
-
- CHSTrafficSecret =
- hexstr2bin(" b3 ed db 12 6e 06 7f 35 a7 80 b3 ab f4 5e
- 2d 8f 3b 1a 95 07 38 f5 2e 96 00 74 6a 0e 27 a5 5a 21"),
-
- CHSH = <<ClientHello/binary,ServerHello/binary>>,
- CHSTHash = crypto:hash(HKDFAlgo, CHSH),
- CHSTInfo = tls_v1:create_info(<<"c hs traffic">>, CHSTHash, ssl_cipher:hash_size(HKDFAlgo)),
-
- CHSTrafficSecret =
- tls_v1:client_handshake_traffic_secret(HKDFAlgo, {handshake_secret, HandshakeSecret}, CHSH),
-
- %% {server} derive secret "tls13 s hs traffic":
- %%
- %% PRK (32 octets): 1d c8 26 e9 36 06 aa 6f dc 0a ad c1 2f 74 1b 01
- %% 04 6a a6 b9 9f 69 1e d2 21 a9 f0 ca 04 3f be ac
- %%
- %% hash (32 octets): 86 0c 06 ed c0 78 58 ee 8e 78 f0 e7 42 8c 58 ed
- %% d6 b4 3f 2c a3 e6 e9 5f 02 ed 06 3c f0 e1 ca d8
- %%
- %% info (54 octets): 00 20 12 74 6c 73 31 33 20 73 20 68 73 20 74 72
- %% 61 66 66 69 63 20 86 0c 06 ed c0 78 58 ee 8e 78 f0 e7 42 8c 58
- %% ed d6 b4 3f 2c a3 e6 e9 5f 02 ed 06 3c f0 e1 ca d8
- %%
- %% expanded (32 octets): b6 7b 7d 69 0c c1 6c 4e 75 e5 42 13 cb 2d
- %% 37 b4 e9 c9 12 bc de d9 10 5d 42 be fd 59 d3 91 ad 38
-
- %% PRK = HandshakeSecret
- %% hash = CHSTHash
- SHSTInfo =
- hexstr2bin("00 20 12 74 6c 73 31 33 20 73 20 68 73 20 74 72
- 61 66 66 69 63 20 86 0c 06 ed c0 78 58 ee 8e 78 f0 e7 42 8c 58
- ed d6 b4 3f 2c a3 e6 e9 5f 02 ed 06 3c f0 e1 ca d8"),
-
- SHSTrafficSecret =
- hexstr2bin("b6 7b 7d 69 0c c1 6c 4e 75 e5 42 13 cb 2d
- 37 b4 e9 c9 12 bc de d9 10 5d 42 be fd 59 d3 91 ad 38"),
-
- SHSTInfo = tls_v1:create_info(<<"s hs traffic">>, CHSTHash, ssl_cipher:hash_size(HKDFAlgo)),
-
- SHSTrafficSecret =
- tls_v1:server_handshake_traffic_secret(HKDFAlgo, {handshake_secret, HandshakeSecret}, CHSH),
-
-
- %% {server} derive secret for master "tls13 derived":
- %%
- %% PRK (32 octets): 1d c8 26 e9 36 06 aa 6f dc 0a ad c1 2f 74 1b 01
- %% 04 6a a6 b9 9f 69 1e d2 21 a9 f0 ca 04 3f be ac
- %%
- %% hash (32 octets): e3 b0 c4 42 98 fc 1c 14 9a fb f4 c8 99 6f b9 24
- %% 27 ae 41 e4 64 9b 93 4c a4 95 99 1b 78 52 b8 55
- %%
- %% info (49 octets): 00 20 0d 74 6c 73 31 33 20 64 65 72 69 76 65 64
- %% 20 e3 b0 c4 42 98 fc 1c 14 9a fb f4 c8 99 6f b9 24 27 ae 41 e4
- %% 64 9b 93 4c a4 95 99 1b 78 52 b8 55
- %%
- %% expanded (32 octets): 43 de 77 e0 c7 77 13 85 9a 94 4d b9 db 25
- %% 90 b5 31 90 a6 5b 3e e2 e4 f1 2d d7 a0 bb 7c e2 54 b4
-
- %% PRK = HandshakeSecret
- %% hash = Hash
- %% info = Info
- MasterDeriveSecret =
- hexstr2bin("43 de 77 e0 c7 77 13 85 9a 94 4d b9 db 25
- 90 b5 31 90 a6 5b 3e e2 e4 f1 2d d7 a0 bb 7c e2 54 b4"),
-
- MasterDeriveSecret = tls_v1:derive_secret(HandshakeSecret, <<"derived">>, <<>>, HKDFAlgo),
-
- %% {server} extract secret "master":
- %%
- %% salt (32 octets): 43 de 77 e0 c7 77 13 85 9a 94 4d b9 db 25 90 b5
- %% 31 90 a6 5b 3e e2 e4 f1 2d d7 a0 bb 7c e2 54 b4
- %%
- %% IKM (32 octets): 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
- %% 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
- %%
- %% secret (32 octets): 18 df 06 84 3d 13 a0 8b f2 a4 49 84 4c 5f 8a
- %% 47 80 01 bc 4d 4c 62 79 84 d5 a4 1d a8 d0 40 29 19
-
- %% salt = MasterDeriveSecret
- %% IKM = IKM
- MasterSecret =
- hexstr2bin("18 df 06 84 3d 13 a0 8b f2 a4 49 84 4c 5f 8a
- 47 80 01 bc 4d 4c 62 79 84 d5 a4 1d a8 d0 40 29 19"),
-
- {master_secret, MasterSecret} =
- tls_v1:key_schedule(master_secret, HKDFAlgo, {handshake_secret, HandshakeSecret}),
-
- %% {server} send handshake record:
- %%
- %% payload (90 octets): 02 00 00 56 03 03 a6 af 06 a4 12 18 60 dc 5e
- %% 6e 60 24 9c d3 4c 95 93 0c 8a c5 cb 14 34 da c1 55 77 2e d3 e2
- %% 69 28 00 13 01 00 00 2e 00 33 00 24 00 1d 00 20 c9 82 88 76 11
- %% 20 95 fe 66 76 2b db f7 c6 72 e1 56 d6 cc 25 3b 83 3d f1 dd 69
- %% b1 b0 4e 75 1f 0f 00 2b 00 02 03 04
- %%
- %% complete record (95 octets): 16 03 03 00 5a 02 00 00 56 03 03 a6
- %% af 06 a4 12 18 60 dc 5e 6e 60 24 9c d3 4c 95 93 0c 8a c5 cb 14
- %% 34 da c1 55 77 2e d3 e2 69 28 00 13 01 00 00 2e 00 33 00 24 00
- %% 1d 00 20 c9 82 88 76 11 20 95 fe 66 76 2b db f7 c6 72 e1 56 d6
- %% cc 25 3b 83 3d f1 dd 69 b1 b0 4e 75 1f 0f 00 2b 00 02 03 04
-
- %% payload = ServerHello
- ServerHelloRecord =
- hexstr2bin("16 03 03 00 5a 02 00 00 56 03 03 a6
- af 06 a4 12 18 60 dc 5e 6e 60 24 9c d3 4c 95 93 0c 8a c5 cb 14
- 34 da c1 55 77 2e d3 e2 69 28 00 13 01 00 00 2e 00 33 00 24 00
- 1d 00 20 c9 82 88 76 11 20 95 fe 66 76 2b db f7 c6 72 e1 56 d6
- cc 25 3b 83 3d f1 dd 69 b1 b0 4e 75 1f 0f 00 2b 00 02 03 04"),
-
- {SHEncrypted, _} =
- tls_record:encode_handshake(ServerHello, {3,4}, ConnStatesNull),
- ServerHelloRecord = iolist_to_binary(SHEncrypted),
-
- %% {server} derive write traffic keys for handshake data:
- %%
- %% PRK (32 octets): b6 7b 7d 69 0c c1 6c 4e 75 e5 42 13 cb 2d 37 b4
- %% e9 c9 12 bc de d9 10 5d 42 be fd 59 d3 91 ad 38
- %%
- %% key info (13 octets): 00 10 09 74 6c 73 31 33 20 6b 65 79 00
- %%
- %% key expanded (16 octets): 3f ce 51 60 09 c2 17 27 d0 f2 e4 e8 6e
- %% e4 03 bc
- %%
- %% iv info (12 octets): 00 0c 08 74 6c 73 31 33 20 69 76 00
- %%
- %% iv expanded (12 octets): 5d 31 3e b2 67 12 76 ee 13 00 0b 30
-
- %% PRK = SHSTrafficSecret
- WriteKeyInfo =
- hexstr2bin("00 10 09 74 6c 73 31 33 20 6b 65 79 00"),
-
- WriteKey =
- hexstr2bin("3f ce 51 60 09 c2 17 27 d0 f2 e4 e8 6e e4 03 bc"),
-
- WriteIVInfo =
- hexstr2bin("00 0c 08 74 6c 73 31 33 20 69 76 00"),
-
- WriteIV =
- hexstr2bin(" 5d 31 3e b2 67 12 76 ee 13 00 0b 30"),
-
- Cipher = aes_128_gcm, %% TODO: get from ServerHello
-
- WriteKeyInfo = tls_v1:create_info(<<"key">>, <<>>, ssl_cipher:key_material(Cipher)),
- %% TODO: remove hardcoded IV size
- WriteIVInfo = tls_v1:create_info(<<"iv">>, <<>>, 12),
-
- {WriteKey, WriteIV} = tls_v1:calculate_traffic_keys(HKDFAlgo, Cipher, SHSTrafficSecret),
-
- %% {server} construct an EncryptedExtensions handshake message:
- %%
- %% EncryptedExtensions (40 octets): 08 00 00 24 00 22 00 0a 00 14 00
- %% 12 00 1d 00 17 00 18 00 19 01 00 01 01 01 02 01 03 01 04 00 1c
- %% 00 02 40 01 00 00 00 00
- %%
- %% {server} construct a Certificate handshake message:
- %%
- %% Certificate (445 octets): 0b 00 01 b9 00 00 01 b5 00 01 b0 30 82
- %% 01 ac 30 82 01 15 a0 03 02 01 02 02 01 02 30 0d 06 09 2a 86 48
- %% 86 f7 0d 01 01 0b 05 00 30 0e 31 0c 30 0a 06 03 55 04 03 13 03
- %% 72 73 61 30 1e 17 0d 31 36 30 37 33 30 30 31 32 33 35 39 5a 17
- %% 0d 32 36 30 37 33 30 30 31 32 33 35 39 5a 30 0e 31 0c 30 0a 06
- %% 03 55 04 03 13 03 72 73 61 30 81 9f 30 0d 06 09 2a 86 48 86 f7
- %% 0d 01 01 01 05 00 03 81 8d 00 30 81 89 02 81 81 00 b4 bb 49 8f
- %% 82 79 30 3d 98 08 36 39 9b 36 c6 98 8c 0c 68 de 55 e1 bd b8 26
- %% d3 90 1a 24 61 ea fd 2d e4 9a 91 d0 15 ab bc 9a 95 13 7a ce 6c
- %% 1a f1 9e aa 6a f9 8c 7c ed 43 12 09 98 e1 87 a8 0e e0 cc b0 52
- %% 4b 1b 01 8c 3e 0b 63 26 4d 44 9a 6d 38 e2 2a 5f da 43 08 46 74
- %% 80 30 53 0e f0 46 1c 8c a9 d9 ef bf ae 8e a6 d1 d0 3e 2b d1 93
- %% ef f0 ab 9a 80 02 c4 74 28 a6 d3 5a 8d 88 d7 9f 7f 1e 3f 02 03
- %% 01 00 01 a3 1a 30 18 30 09 06 03 55 1d 13 04 02 30 00 30 0b 06
- %% 03 55 1d 0f 04 04 03 02 05 a0 30 0d 06 09 2a 86 48 86 f7 0d 01
- %% 01 0b 05 00 03 81 81 00 85 aa d2 a0 e5 b9 27 6b 90 8c 65 f7 3a
- %% 72 67 17 06 18 a5 4c 5f 8a 7b 33 7d 2d f7 a5 94 36 54 17 f2 ea
- %% e8 f8 a5 8c 8f 81 72 f9 31 9c f3 6b 7f d6 c5 5b 80 f2 1a 03 01
- %% 51 56 72 60 96 fd 33 5e 5e 67 f2 db f1 02 70 2e 60 8c ca e6 be
- %% c1 fc 63 a4 2a 99 be 5c 3e b7 10 7c 3c 54 e9 b9 eb 2b d5 20 3b
- %% 1c 3b 84 e0 a8 b2 f7 59 40 9b a3 ea c9 d9 1d 40 2d cc 0c c8 f8
- %% 96 12 29 ac 91 87 b4 2b 4d e1 00 00
- %%
- %% {server} construct a CertificateVerify handshake message:
- %%
- %% CertificateVerify (136 octets): 0f 00 00 84 08 04 00 80 5a 74 7c
- %% 5d 88 fa 9b d2 e5 5a b0 85 a6 10 15 b7 21 1f 82 4c d4 84 14 5a
- %% b3 ff 52 f1 fd a8 47 7b 0b 7a bc 90 db 78 e2 d3 3a 5c 14 1a 07
- %% 86 53 fa 6b ef 78 0c 5e a2 48 ee aa a7 85 c4 f3 94 ca b6 d3 0b
- %% be 8d 48 59 ee 51 1f 60 29 57 b1 54 11 ac 02 76 71 45 9e 46 44
- %% 5c 9e a5 8c 18 1e 81 8e 95 b8 c3 fb 0b f3 27 84 09 d3 be 15 2a
- %% 3d a5 04 3e 06 3d da 65 cd f5 ae a2 0d 53 df ac d4 2f 74 f3
- EncryptedExtensions =
- hexstr2bin("08 00 00 24 00 22 00 0a 00 14 00
- 12 00 1d 00 17 00 18 00 19 01 00 01 01 01 02 01 03 01 04 00 1c
- 00 02 40 01 00 00 00 00"),
-
- Certificate =
- hexstr2bin("0b 00 01 b9 00 00 01 b5 00 01 b0 30 82
- 01 ac 30 82 01 15 a0 03 02 01 02 02 01 02 30 0d 06 09 2a 86 48
- 86 f7 0d 01 01 0b 05 00 30 0e 31 0c 30 0a 06 03 55 04 03 13 03
- 72 73 61 30 1e 17 0d 31 36 30 37 33 30 30 31 32 33 35 39 5a 17
- 0d 32 36 30 37 33 30 30 31 32 33 35 39 5a 30 0e 31 0c 30 0a 06
- 03 55 04 03 13 03 72 73 61 30 81 9f 30 0d 06 09 2a 86 48 86 f7
- 0d 01 01 01 05 00 03 81 8d 00 30 81 89 02 81 81 00 b4 bb 49 8f
- 82 79 30 3d 98 08 36 39 9b 36 c6 98 8c 0c 68 de 55 e1 bd b8 26
- d3 90 1a 24 61 ea fd 2d e4 9a 91 d0 15 ab bc 9a 95 13 7a ce 6c
- 1a f1 9e aa 6a f9 8c 7c ed 43 12 09 98 e1 87 a8 0e e0 cc b0 52
- 4b 1b 01 8c 3e 0b 63 26 4d 44 9a 6d 38 e2 2a 5f da 43 08 46 74
- 80 30 53 0e f0 46 1c 8c a9 d9 ef bf ae 8e a6 d1 d0 3e 2b d1 93
- ef f0 ab 9a 80 02 c4 74 28 a6 d3 5a 8d 88 d7 9f 7f 1e 3f 02 03
- 01 00 01 a3 1a 30 18 30 09 06 03 55 1d 13 04 02 30 00 30 0b 06
- 03 55 1d 0f 04 04 03 02 05 a0 30 0d 06 09 2a 86 48 86 f7 0d 01
- 01 0b 05 00 03 81 81 00 85 aa d2 a0 e5 b9 27 6b 90 8c 65 f7 3a
- 72 67 17 06 18 a5 4c 5f 8a 7b 33 7d 2d f7 a5 94 36 54 17 f2 ea
- e8 f8 a5 8c 8f 81 72 f9 31 9c f3 6b 7f d6 c5 5b 80 f2 1a 03 01
- 51 56 72 60 96 fd 33 5e 5e 67 f2 db f1 02 70 2e 60 8c ca e6 be
- c1 fc 63 a4 2a 99 be 5c 3e b7 10 7c 3c 54 e9 b9 eb 2b d5 20 3b
- 1c 3b 84 e0 a8 b2 f7 59 40 9b a3 ea c9 d9 1d 40 2d cc 0c c8 f8
- 96 12 29 ac 91 87 b4 2b 4d e1 00 00"),
-
- CertificateVerify =
- hexstr2bin("0f 00 00 84 08 04 00 80 5a 74 7c
- 5d 88 fa 9b d2 e5 5a b0 85 a6 10 15 b7 21 1f 82 4c d4 84 14 5a
- b3 ff 52 f1 fd a8 47 7b 0b 7a bc 90 db 78 e2 d3 3a 5c 14 1a 07
- 86 53 fa 6b ef 78 0c 5e a2 48 ee aa a7 85 c4 f3 94 ca b6 d3 0b
- be 8d 48 59 ee 51 1f 60 29 57 b1 54 11 ac 02 76 71 45 9e 46 44
- 5c 9e a5 8c 18 1e 81 8e 95 b8 c3 fb 0b f3 27 84 09 d3 be 15 2a
- 3d a5 04 3e 06 3d da 65 cd f5 ae a2 0d 53 df ac d4 2f 74 f3"),
-
- %% {server} calculate finished "tls13 finished":
- %%
- %% PRK (32 octets): b6 7b 7d 69 0c c1 6c 4e 75 e5 42 13 cb 2d 37 b4
- %% e9 c9 12 bc de d9 10 5d 42 be fd 59 d3 91 ad 38
- %%
- %% hash (0 octets): (empty)
- %%
- %% info (18 octets): 00 20 0e 74 6c 73 31 33 20 66 69 6e 69 73 68 65
- %% 64 00
- %%
- %% expanded (32 octets): 00 8d 3b 66 f8 16 ea 55 9f 96 b5 37 e8 85
- %% c3 1f c0 68 bf 49 2c 65 2f 01 f2 88 a1 d8 cd c1 9f c8
- %%
- %% finished (32 octets): 9b 9b 14 1d 90 63 37 fb d2 cb dc e7 1d f4
- %% de da 4a b4 2c 30 95 72 cb 7f ff ee 54 54 b7 8f 07 18
-
- %% PRK = SHSTrafficSecret
- FInfo =
- hexstr2bin("00 20 0e 74 6c 73 31 33 20 66 69 6e 69 73 68 65
- 64 00"),
-
- FExpanded =
- hexstr2bin("00 8d 3b 66 f8 16 ea 55 9f 96 b5 37 e8 85
- c3 1f c0 68 bf 49 2c 65 2f 01 f2 88 a1 d8 cd c1 9f c8"),
-
- FinishedVerifyData =
- hexstr2bin("9b 9b 14 1d 90 63 37 fb d2 cb dc e7 1d f4
- de da 4a b4 2c 30 95 72 cb 7f ff ee 54 54 b7 8f 07 18"),
-
- FInfo = tls_v1:create_info(<<"finished">>, <<>>, ssl_cipher:hash_size(HKDFAlgo)),
-
- FExpanded = tls_v1:finished_key(SHSTrafficSecret, HKDFAlgo),
-
- MessageHistory0 = [CertificateVerify,
- Certificate,
- EncryptedExtensions,
- ServerHello,
- ClientHello],
-
- FinishedVerifyData = tls_v1:finished_verify_data(FExpanded, HKDFAlgo, MessageHistory0),
-
- %% {server} construct a Finished handshake message:
- %%
- %% Finished (36 octets): 14 00 00 20 9b 9b 14 1d 90 63 37 fb d2 cb
- %% dc e7 1d f4 de da 4a b4 2c 30 95 72 cb 7f ff ee 54 54 b7 8f 07
- %% 18
- FinishedHSBin =
- hexstr2bin("14 00 00 20 9b 9b 14 1d 90 63 37 fb d2 cb
- dc e7 1d f4 de da 4a b4 2c 30 95 72 cb 7f ff ee 54 54 b7 8f 07
- 18"),
-
- FinishedHS = #finished{verify_data = FinishedVerifyData},
-
- FinishedIOList = tls_handshake:encode_handshake(FinishedHS, {3,4}),
- FinishedHSBin = iolist_to_binary(FinishedIOList),
-
- %% {server} derive secret "tls13 c ap traffic":
- %%
- %% PRK (32 octets): 18 df 06 84 3d 13 a0 8b f2 a4 49 84 4c 5f 8a 47
- %% 80 01 bc 4d 4c 62 79 84 d5 a4 1d a8 d0 40 29 19
- %%
- %% hash (32 octets): 96 08 10 2a 0f 1c cc 6d b6 25 0b 7b 7e 41 7b 1a
- %% 00 0e aa da 3d aa e4 77 7a 76 86 c9 ff 83 df 13
- %%
- %% info (54 octets): 00 20 12 74 6c 73 31 33 20 63 20 61 70 20 74 72
- %% 61 66 66 69 63 20 96 08 10 2a 0f 1c cc 6d b6 25 0b 7b 7e 41 7b
- %% 1a 00 0e aa da 3d aa e4 77 7a 76 86 c9 ff 83 df 13
- %%
- %% expanded (32 octets): 9e 40 64 6c e7 9a 7f 9d c0 5a f8 88 9b ce
- %% 65 52 87 5a fa 0b 06 df 00 87 f7 92 eb b7 c1 75 04 a5
-
- %% PRK = MasterSecret
- CAPTHash =
- hexstr2bin("96 08 10 2a 0f 1c cc 6d b6 25 0b 7b 7e 41 7b 1a
- 00 0e aa da 3d aa e4 77 7a 76 86 c9 ff 83 df 13"),
- CAPTInfo =
- hexstr2bin("00 20 12 74 6c 73 31 33 20 63 20 61 70 20 74 72
- 61 66 66 69 63 20 96 08 10 2a 0f 1c cc 6d b6 25 0b 7b 7e 41 7b
- 1a 00 0e aa da 3d aa e4 77 7a 76 86 c9 ff 83 df 13"),
-
- CAPTrafficSecret =
- hexstr2bin("9e 40 64 6c e7 9a 7f 9d c0 5a f8 88 9b ce
- 65 52 87 5a fa 0b 06 df 00 87 f7 92 eb b7 c1 75 04 a5"),
-
- CHSF = <<ClientHello/binary,
- ServerHello/binary,
- EncryptedExtensions/binary,
- Certificate/binary,
- CertificateVerify/binary,
- FinishedHSBin/binary>>,
-
- CAPTHash = crypto:hash(HKDFAlgo, CHSF),
-
- CAPTInfo =
- tls_v1:create_info(<<"c ap traffic">>, CAPTHash, ssl_cipher:hash_size(HKDFAlgo)),
-
- CAPTrafficSecret =
- tls_v1:client_application_traffic_secret_0(HKDFAlgo, {master_secret, MasterSecret}, CHSF),
-
- %% {server} derive secret "tls13 s ap traffic":
- %%
- %% PRK (32 octets): 18 df 06 84 3d 13 a0 8b f2 a4 49 84 4c 5f 8a 47
- %% 80 01 bc 4d 4c 62 79 84 d5 a4 1d a8 d0 40 29 19
- %%
- %% hash (32 octets): 96 08 10 2a 0f 1c cc 6d b6 25 0b 7b 7e 41 7b 1a
- %% 00 0e aa da 3d aa e4 77 7a 76 86 c9 ff 83 df 13
- %%
- %% info (54 octets): 00 20 12 74 6c 73 31 33 20 73 20 61 70 20 74 72
- %% 61 66 66 69 63 20 96 08 10 2a 0f 1c cc 6d b6 25 0b 7b 7e 41 7b
- %% 1a 00 0e aa da 3d aa e4 77 7a 76 86 c9 ff 83 df 13
- %%
- %% expanded (32 octets): a1 1a f9 f0 55 31 f8 56 ad 47 11 6b 45 a9
- %% 50 32 82 04 b4 f4 4b fb 6b 3a 4b 4f 1f 3f cb 63 16 43
-
- %% PRK = MasterSecret
- %% hash = CAPTHash
- SAPTInfo =
- hexstr2bin(" 00 20 12 74 6c 73 31 33 20 73 20 61 70 20 74 72
- 61 66 66 69 63 20 96 08 10 2a 0f 1c cc 6d b6 25 0b 7b 7e 41 7b
- 1a 00 0e aa da 3d aa e4 77 7a 76 86 c9 ff 83 df 13"),
-
- SAPTrafficSecret =
- hexstr2bin("a1 1a f9 f0 55 31 f8 56 ad 47 11 6b 45 a9
- 50 32 82 04 b4 f4 4b fb 6b 3a 4b 4f 1f 3f cb 63 16 43"),
-
- SAPTInfo =
- tls_v1:create_info(<<"s ap traffic">>, CAPTHash, ssl_cipher:hash_size(HKDFAlgo)),
-
- SAPTrafficSecret =
- tls_v1:server_application_traffic_secret_0(HKDFAlgo, {master_secret, MasterSecret}, CHSF),
-
- %% {server} derive secret "tls13 exp master":
- %%
- %% PRK (32 octets): 18 df 06 84 3d 13 a0 8b f2 a4 49 84 4c 5f 8a 47
- %% 80 01 bc 4d 4c 62 79 84 d5 a4 1d a8 d0 40 29 19
- %%
- %% hash (32 octets): 96 08 10 2a 0f 1c cc 6d b6 25 0b 7b 7e 41 7b 1a
- %% 00 0e aa da 3d aa e4 77 7a 76 86 c9 ff 83 df 13
- %%
- %% info (52 octets): 00 20 10 74 6c 73 31 33 20 65 78 70 20 6d 61 73
- %% 74 65 72 20 96 08 10 2a 0f 1c cc 6d b6 25 0b 7b 7e 41 7b 1a 00
- %% 0e aa da 3d aa e4 77 7a 76 86 c9 ff 83 df 13
- %%
- %% expanded (32 octets): fe 22 f8 81 17 6e da 18 eb 8f 44 52 9e 67
- %% 92 c5 0c 9a 3f 89 45 2f 68 d8 ae 31 1b 43 09 d3 cf 50
-
- %% PRK = MasterSecret
- %% hash = CAPTHash
- ExporterInfo =
- hexstr2bin("00 20 10 74 6c 73 31 33 20 65 78 70 20 6d 61 73
- 74 65 72 20 96 08 10 2a 0f 1c cc 6d b6 25 0b 7b 7e 41 7b 1a 00
- 0e aa da 3d aa e4 77 7a 76 86 c9 ff 83 df 13"),
-
- ExporterMasterSecret =
- hexstr2bin("fe 22 f8 81 17 6e da 18 eb 8f 44 52 9e 67
- 92 c5 0c 9a 3f 89 45 2f 68 d8 ae 31 1b 43 09 d3 cf 50"),
-
- ExporterInfo =
- tls_v1:create_info(<<"exp master">>, CAPTHash, ssl_cipher:hash_size(HKDFAlgo)),
-
- ExporterMasterSecret =
- tls_v1:exporter_master_secret(HKDFAlgo, {master_secret, MasterSecret}, CHSF),
-
- %% {server} derive write traffic keys for application data:
- %%
- %% PRK (32 octets): a1 1a f9 f0 55 31 f8 56 ad 47 11 6b 45 a9 50 32
- %% 82 04 b4 f4 4b fb 6b 3a 4b 4f 1f 3f cb 63 16 43
- %%
- %% key info (13 octets): 00 10 09 74 6c 73 31 33 20 6b 65 79 00
- %%
- %% key expanded (16 octets): 9f 02 28 3b 6c 9c 07 ef c2 6b b9 f2 ac
- %% 92 e3 56
- %%
- %% iv info (12 octets): 00 0c 08 74 6c 73 31 33 20 69 76 00
- %%
- %% iv expanded (12 octets): cf 78 2b 88 dd 83 54 9a ad f1 e9 84
-
- %% PRK = SAPTrafficsecret
- %% key info = WriteKeyInfo
- %% iv info = WrtieIVInfo
- SWKey =
- hexstr2bin("9f 02 28 3b 6c 9c 07 ef c2 6b b9 f2 ac 92 e3 56"),
-
- SWIV =
- hexstr2bin("cf 78 2b 88 dd 83 54 9a ad f1 e9 84"),
-
- {SWKey, SWIV} = tls_v1:calculate_traffic_keys(HKDFAlgo, Cipher, SAPTrafficSecret),
-
- %% {server} derive read traffic keys for handshake data:
- %%
- %% PRK (32 octets): b3 ed db 12 6e 06 7f 35 a7 80 b3 ab f4 5e 2d 8f
- %% 3b 1a 95 07 38 f5 2e 96 00 74 6a 0e 27 a5 5a 21
- %%
- %% key info (13 octets): 00 10 09 74 6c 73 31 33 20 6b 65 79 00
- %%
- %% key expanded (16 octets): db fa a6 93 d1 76 2c 5b 66 6a f5 d9 50
- %% 25 8d 01
- %%
- %% iv info (12 octets): 00 0c 08 74 6c 73 31 33 20 69 76 00
- %%
- %% iv expanded (12 octets): 5b d3 c7 1b 83 6e 0b 76 bb 73 26 5f
-
- %% PRK = CHSTrafficsecret
- %% key info = WriteKeyInfo
- %% iv info = WrtieIVInfo
- SRKey =
- hexstr2bin("db fa a6 93 d1 76 2c 5b 66 6a f5 d9 50 25 8d 01"),
-
- SRIV =
- hexstr2bin("5b d3 c7 1b 83 6e 0b 76 bb 73 26 5f"),
-
- {SRKey, SRIV} = tls_v1:calculate_traffic_keys(HKDFAlgo, Cipher, CHSTrafficSecret).
-
-
-tls13_finished_verify_data() ->
- [{doc,"Test TLS 1.3 Finished message handling"}].
-
-tls13_finished_verify_data(_Config) ->
- ClientHello =
- hexstr2bin("01 00 00 c6 03 03 00 01 02 03 04 05 06 07 08 09
- 0a 0b 0c 0d 0e 0f 10 11 12 13 14 15 16 17 18 19
- 1a 1b 1c 1d 1e 1f 20 e0 e1 e2 e3 e4 e5 e6 e7 e8
- e9 ea eb ec ed ee ef f0 f1 f2 f3 f4 f5 f6 f7 f8
- f9 fa fb fc fd fe ff 00 06 13 01 13 02 13 03 01
- 00 00 77 00 00 00 18 00 16 00 00 13 65 78 61 6d
- 70 6c 65 2e 75 6c 66 68 65 69 6d 2e 6e 65 74 00
- 0a 00 08 00 06 00 1d 00 17 00 18 00 0d 00 14 00
- 12 04 03 08 04 04 01 05 03 08 05 05 01 08 06 06
- 01 02 01 00 33 00 26 00 24 00 1d 00 20 35 80 72
- d6 36 58 80 d1 ae ea 32 9a df 91 21 38 38 51 ed
- 21 a2 8e 3b 75 e9 65 d0 d2 cd 16 62 54 00 2d 00
- 02 01 01 00 2b 00 03 02 03 04"),
-
- ServerHello =
- hexstr2bin("02 00 00 76 03 03 70 71 72 73 74 75 76 77 78 79
- 7a 7b 7c 7d 7e 7f 80 81 82 83 84 85 86 87 88 89
- 8a 8b 8c 8d 8e 8f 20 e0 e1 e2 e3 e4 e5 e6 e7 e8
- e9 ea eb ec ed ee ef f0 f1 f2 f3 f4 f5 f6 f7 f8
- f9 fa fb fc fd fe ff 13 01 00 00 2e 00 33 00 24
- 00 1d 00 20 9f d7 ad 6d cf f4 29 8d d3 f9 6d 5b
- 1b 2a f9 10 a0 53 5b 14 88 d7 f8 fa bb 34 9a 98
- 28 80 b6 15 00 2b 00 02 03 04"),
-
- EncryptedExtensions =
- hexstr2bin("08 00 00 02 00 00"),
-
- Certificate =
- hexstr2bin("0b 00 03 2e 00 00 03 2a 00 03 25 30 82 03 21 30
- 82 02 09 a0 03 02 01 02 02 08 15 5a 92 ad c2 04
- 8f 90 30 0d 06 09 2a 86 48 86 f7 0d 01 01 0b 05
- 00 30 22 31 0b 30 09 06 03 55 04 06 13 02 55 53
- 31 13 30 11 06 03 55 04 0a 13 0a 45 78 61 6d 70
- 6c 65 20 43 41 30 1e 17 0d 31 38 31 30 30 35 30
- 31 33 38 31 37 5a 17 0d 31 39 31 30 30 35 30 31
- 33 38 31 37 5a 30 2b 31 0b 30 09 06 03 55 04 06
- 13 02 55 53 31 1c 30 1a 06 03 55 04 03 13 13 65
- 78 61 6d 70 6c 65 2e 75 6c 66 68 65 69 6d 2e 6e
- 65 74 30 82 01 22 30 0d 06 09 2a 86 48 86 f7 0d
- 01 01 01 05 00 03 82 01 0f 00 30 82 01 0a 02 82
- 01 01 00 c4 80 36 06 ba e7 47 6b 08 94 04 ec a7
- b6 91 04 3f f7 92 bc 19 ee fb 7d 74 d7 a8 0d 00
- 1e 7b 4b 3a 4a e6 0f e8 c0 71 fc 73 e7 02 4c 0d
- bc f4 bd d1 1d 39 6b ba 70 46 4a 13 e9 4a f8 3d
- f3 e1 09 59 54 7b c9 55 fb 41 2d a3 76 52 11 e1
- f3 dc 77 6c aa 53 37 6e ca 3a ec be c3 aa b7 3b
- 31 d5 6c b6 52 9c 80 98 bc c9 e0 28 18 e2 0b f7
- f8 a0 3a fd 17 04 50 9e ce 79 bd 9f 39 f1 ea 69
- ec 47 97 2e 83 0f b5 ca 95 de 95 a1 e6 04 22 d5
- ee be 52 79 54 a1 e7 bf 8a 86 f6 46 6d 0d 9f 16
- 95 1a 4c f7 a0 46 92 59 5c 13 52 f2 54 9e 5a fb
- 4e bf d7 7a 37 95 01 44 e4 c0 26 87 4c 65 3e 40
- 7d 7d 23 07 44 01 f4 84 ff d0 8f 7a 1f a0 52 10
- d1 f4 f0 d5 ce 79 70 29 32 e2 ca be 70 1f df ad
- 6b 4b b7 11 01 f4 4b ad 66 6a 11 13 0f e2 ee 82
- 9e 4d 02 9d c9 1c dd 67 16 db b9 06 18 86 ed c1
- ba 94 21 02 03 01 00 01 a3 52 30 50 30 0e 06 03
- 55 1d 0f 01 01 ff 04 04 03 02 05 a0 30 1d 06 03
- 55 1d 25 04 16 30 14 06 08 2b 06 01 05 05 07 03
- 02 06 08 2b 06 01 05 05 07 03 01 30 1f 06 03 55
- 1d 23 04 18 30 16 80 14 89 4f de 5b cc 69 e2 52
- cf 3e a3 00 df b1 97 b8 1d e1 c1 46 30 0d 06 09
- 2a 86 48 86 f7 0d 01 01 0b 05 00 03 82 01 01 00
- 59 16 45 a6 9a 2e 37 79 e4 f6 dd 27 1a ba 1c 0b
- fd 6c d7 55 99 b5 e7 c3 6e 53 3e ff 36 59 08 43
- 24 c9 e7 a5 04 07 9d 39 e0 d4 29 87 ff e3 eb dd
- 09 c1 cf 1d 91 44 55 87 0b 57 1d d1 9b df 1d 24
- f8 bb 9a 11 fe 80 fd 59 2b a0 39 8c de 11 e2 65
- 1e 61 8c e5 98 fa 96 e5 37 2e ef 3d 24 8a fd e1
- 74 63 eb bf ab b8 e4 d1 ab 50 2a 54 ec 00 64 e9
- 2f 78 19 66 0d 3f 27 cf 20 9e 66 7f ce 5a e2 e4
- ac 99 c7 c9 38 18 f8 b2 51 07 22 df ed 97 f3 2e
- 3e 93 49 d4 c6 6c 9e a6 39 6d 74 44 62 a0 6b 42
- c6 d5 ba 68 8e ac 3a 01 7b dd fc 8e 2c fc ad 27
- cb 69 d3 cc dc a2 80 41 44 65 d3 ae 34 8c e0 f3
- 4a b2 fb 9c 61 83 71 31 2b 19 10 41 64 1c 23 7f
- 11 a5 d6 5c 84 4f 04 04 84 99 38 71 2b 95 9e d6
- 85 bc 5c 5d d6 45 ed 19 90 94 73 40 29 26 dc b4
- 0e 34 69 a1 59 41 e8 e2 cc a8 4b b6 08 46 36 a0
- 00 00"),
-
- CertificateVerify =
- hexstr2bin("0f 00 01 04 08 04 01 00 17 fe b5 33 ca 6d 00 7d
- 00 58 25 79 68 42 4b bc 3a a6 90 9e 9d 49 55 75
- 76 a5 20 e0 4a 5e f0 5f 0e 86 d2 4f f4 3f 8e b8
- 61 ee f5 95 22 8d 70 32 aa 36 0f 71 4e 66 74 13
- 92 6e f4 f8 b5 80 3b 69 e3 55 19 e3 b2 3f 43 73
- df ac 67 87 06 6d cb 47 56 b5 45 60 e0 88 6e 9b
- 96 2c 4a d2 8d ab 26 ba d1 ab c2 59 16 b0 9a f2
- 86 53 7f 68 4f 80 8a ef ee 73 04 6c b7 df 0a 84
- fb b5 96 7a ca 13 1f 4b 1c f3 89 79 94 03 a3 0c
- 02 d2 9c bd ad b7 25 12 db 9c ec 2e 5e 1d 00 e5
- 0c af cf 6f 21 09 1e bc 4f 25 3c 5e ab 01 a6 79
- ba ea be ed b9 c9 61 8f 66 00 6b 82 44 d6 62 2a
- aa 56 88 7c cf c6 6a 0f 38 51 df a1 3a 78 cf f7
- 99 1e 03 cb 2c 3a 0e d8 7d 73 67 36 2e b7 80 5b
- 00 b2 52 4f f2 98 a4 da 48 7c ac de af 8a 23 36
- c5 63 1b 3e fa 93 5b b4 11 e7 53 ca 13 b0 15 fe
- c7 e4 a7 30 f1 36 9f 9e"),
-
- BaseKey =
- hexstr2bin("a2 06 72 65 e7 f0 65 2a 92 3d 5d 72 ab 04 67 c4
- 61 32 ee b9 68 b6 a3 2d 31 1c 80 58 68 54 88 14"),
-
- VerifyData =
- hexstr2bin("ea 6e e1 76 dc cc 4a f1 85 9e 9e 4e 93 f7 97 ea
- c9 a7 8c e4 39 30 1e 35 27 5a d4 3f 3c dd bd e3"),
-
- Messages = [CertificateVerify,
- Certificate,
- EncryptedExtensions,
- ServerHello,
- ClientHello],
-
- FinishedKey = tls_v1:finished_key(BaseKey, sha256),
- VerifyData = tls_v1:finished_verify_data(FinishedKey, sha256, Messages).
-
-
-tls12_ssl_server_tls13_ssl_client() ->
- [{doc,"Test basic connection between TLS 1.2 server and TLS 1.3 client"}].
-
-tls12_ssl_server_tls13_ssl_client(Config) ->
- ClientOpts0 = ssl_test_lib:ssl_options(client_rsa_opts, Config),
- ServerOpts0 = ssl_test_lib:ssl_options(server_rsa_opts, Config),
- {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
-
- %% Set versions
- ServerOpts = [{versions, ['tlsv1.2']}|ServerOpts0],
- ClientOpts = [{versions, ['tlsv1.2','tlsv1.3']},
- {signature_algs_cert, [ecdsa_secp384r1_sha384,
- rsa_pss_rsae_sha256,
- rsa_pkcs1_sha256,
- {sha256,rsa},{sha256,dsa}]}|ClientOpts0],
-
- Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0},
- {from, self()},
- {mfa, {ssl_test_lib, send_recv_result_active, []}},
- {options, ServerOpts}]),
- Port = ssl_test_lib:inet_port(Server),
-
- Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port},
- {host, Hostname},
- {from, self()},
- {mfa, {ssl_test_lib, send_recv_result_active, []}},
- {options, ClientOpts}]),
-
- ssl_test_lib:check_result(Server, ok, Client, ok),
-
- ssl_test_lib:close(Server),
- ssl_test_lib:close_port(Client).
-
-
-tls13_basic_ssl_server_openssl_client() ->
- [{doc,"Test TLS 1.3 basic connection between ssl server and openssl s_client"}].
-
-tls13_basic_ssl_server_openssl_client(Config) ->
- ClientOpts = ssl_test_lib:ssl_options(client_rsa_opts, Config),
- ServerOpts0 = ssl_test_lib:ssl_options(server_rsa_opts, Config),
- %% Set versions
- ServerOpts = [{versions, ['tlsv1.2','tlsv1.3']}|ServerOpts0],
- {_ClientNode, ServerNode, _Hostname} = ssl_test_lib:run_where(Config),
-
- Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0},
- {from, self()},
- {mfa, {ssl_test_lib, send_recv_result_active, []}},
- {options, ServerOpts}]),
- Port = ssl_test_lib:inet_port(Server),
-
- Client = ssl_test_lib:start_basic_client(openssl, 'tlsv1.3', Port, ClientOpts),
-
- ssl_test_lib:check_result(Server, ok),
- ssl_test_lib:close(Server),
- ssl_test_lib:close_port(Client).
-
-tls13_basic_ssl_server_ssl_client() ->
- [{doc,"Test TLS 1.3 basic connection between ssl server and ssl client"}].
-
-tls13_basic_ssl_server_ssl_client(Config) ->
- ClientOpts0 = ssl_test_lib:ssl_options(client_rsa_opts, Config),
- ServerOpts0 = ssl_test_lib:ssl_options(server_rsa_opts, Config),
- {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
-
- %% Set versions
- ServerOpts = [{versions, ['tlsv1.2','tlsv1.3']}|ServerOpts0],
- ClientOpts = [{versions, ['tlsv1.2','tlsv1.3']}|ClientOpts0],
-
- Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0},
- {from, self()},
- {mfa, {ssl_test_lib, send_recv_result_active, []}},
- {options, ServerOpts}]),
- Port = ssl_test_lib:inet_port(Server),
-
- Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port},
- {host, Hostname},
- {from, self()},
- {mfa, {ssl_test_lib, send_recv_result_active, []}},
- {options, ClientOpts}]),
-
- ssl_test_lib:check_result(Server, ok, Client, ok),
-
- ssl_test_lib:close(Server),
- ssl_test_lib:close_port(Client).
-
-
-tls13_basic_openssl_server_ssl_client() ->
- [{doc,"Test TLS 1.3 basic connection between openssl server and ssl client"}].
-
-tls13_basic_openssl_server_ssl_client(Config) ->
- process_flag(trap_exit, true),
- ServerOpts = ssl_test_lib:ssl_options(server_rsa_verify_opts, Config),
- ClientOpts0 = ssl_test_lib:ssl_options(client_rsa_verify_opts, Config),
-
- ClientOpts = [{versions, ['tlsv1.2','tlsv1.3']}|ClientOpts0],
-
- {ClientNode, _, Hostname} = ssl_test_lib:run_where(Config),
-
- Data = "From openssl to erlang",
-
- Port = ssl_test_lib:inet_port(node()),
- CertFile = proplists:get_value(certfile, ServerOpts),
- CaCertFile = proplists:get_value(cacertfile, ServerOpts),
- KeyFile = proplists:get_value(keyfile, ServerOpts),
- Exe = "openssl",
- Args = ["s_server", "-accept", integer_to_list(Port),
- "-tls1_3",
- "-cert", CertFile, "-CAfile", CaCertFile,
- "-key", KeyFile, "-Verify", "2"],
-
- OpensslPort = ssl_test_lib:portable_open_port(Exe, Args),
-
- ssl_test_lib:wait_for_openssl_server(Port, tls),
-
- Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port},
- {host, Hostname},
- {from, self()},
- {mfa, {?MODULE,
- erlang_ssl_receive, [Data]}},
- {options, ClientOpts}]),
- true = port_command(OpensslPort, Data),
-
- ssl_test_lib:check_result(Client, ok),
-
- %% Clean close down! Server needs to be closed first !!
- ssl_test_lib:close_port(OpensslPort),
- ssl_test_lib:close(Client),
- process_flag(trap_exit, false).
-
-
-tls13_custom_groups_ssl_server_openssl_client() ->
- [{doc,"Test that ssl server can select a common group for key-exchange"}].
-
-tls13_custom_groups_ssl_server_openssl_client(Config) ->
- ClientOpts0 = ssl_test_lib:ssl_options(client_rsa_opts, Config),
- ServerOpts0 = ssl_test_lib:ssl_options(server_rsa_opts, Config),
- %% Set versions
- ServerOpts = [{versions, ['tlsv1.2','tlsv1.3']},
- {supported_groups, [x448, secp256r1, secp384r1]}|ServerOpts0],
- {_ClientNode, ServerNode, _Hostname} = ssl_test_lib:run_where(Config),
-
- Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0},
- {from, self()},
- {mfa, {ssl_test_lib, send_recv_result_active, []}},
- {options, ServerOpts}]),
- Port = ssl_test_lib:inet_port(Server),
-
- ClientOpts = [{groups,"P-384:P-256:X25519"}|ClientOpts0],
- Client = ssl_test_lib:start_basic_client(openssl, 'tlsv1.3', Port, ClientOpts),
-
- ssl_test_lib:check_result(Server, ok),
- ssl_test_lib:close(Server),
- ssl_test_lib:close_port(Client).
-
-
-tls13_custom_groups_ssl_server_ssl_client() ->
- [{doc,"Test that ssl server can select a common group for key-exchange"}].
-
-tls13_custom_groups_ssl_server_ssl_client(Config) ->
- ClientOpts0 = ssl_test_lib:ssl_options(client_rsa_opts, Config),
- ServerOpts0 = ssl_test_lib:ssl_options(server_rsa_opts, Config),
-
- %% Set versions
- ServerOpts = [{versions, ['tlsv1.2','tlsv1.3']},
- {supported_groups, [x448, secp256r1, secp384r1]}|ServerOpts0],
- ClientOpts1 = [{versions, ['tlsv1.2','tlsv1.3']}|ClientOpts0],
- {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
-
- Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0},
- {from, self()},
- {mfa, {ssl_test_lib, send_recv_result_active, []}},
- {options, ServerOpts}]),
- Port = ssl_test_lib:inet_port(Server),
-
- ClientOpts = [{supported_groups,[secp384r1, secp256r1, x25519]}|ClientOpts1],
-
- Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port},
- {host, Hostname},
- {from, self()},
- {mfa, {ssl_test_lib, send_recv_result_active, []}},
- {options, ClientOpts}]),
-
- ssl_test_lib:check_result(Server, ok, Client, ok),
- ssl_test_lib:close(Server),
- ssl_test_lib:close_port(Client).
-
-
-tls13_hello_retry_request_ssl_server_openssl_client() ->
- [{doc,"Test that ssl server can request a new group when the client's first key share"
- "is not supported"}].
-
-tls13_hello_retry_request_ssl_server_openssl_client(Config) ->
- ClientOpts0 = ssl_test_lib:ssl_options(client_rsa_opts, Config),
- ServerOpts0 = ssl_test_lib:ssl_options(server_rsa_opts, Config),
- %% Set versions
- ServerOpts = [{versions, ['tlsv1.2','tlsv1.3']},
- {supported_groups, [x448, x25519]}|ServerOpts0],
- {_ClientNode, ServerNode, _Hostname} = ssl_test_lib:run_where(Config),
-
- Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0},
- {from, self()},
- {mfa, {ssl_test_lib, send_recv_result_active, []}},
- {options, ServerOpts}]),
- Port = ssl_test_lib:inet_port(Server),
-
- ClientOpts = [{groups,"P-256:X25519"}|ClientOpts0],
- Client = ssl_test_lib:start_basic_client(openssl, 'tlsv1.3', Port, ClientOpts),
-
- ssl_test_lib:check_result(Server, ok),
- ssl_test_lib:close(Server),
- ssl_test_lib:close_port(Client).
-
-
-tls13_hello_retry_request_ssl_server_ssl_client() ->
- [{doc,"Test that ssl server can request a new group when the client's first key share"
- "is not supported"}].
-
-tls13_hello_retry_request_ssl_server_ssl_client(Config) ->
- ClientOpts0 = ssl_test_lib:ssl_options(client_rsa_opts, Config),
- ServerOpts0 = ssl_test_lib:ssl_options(server_rsa_opts, Config),
- %% Set versions
- ServerOpts = [{versions, ['tlsv1.2','tlsv1.3']},
- {supported_groups, [x448, x25519]}|ServerOpts0],
- ClientOpts = [{versions, ['tlsv1.2','tlsv1.3']},
- {supported_groups, [secp256r1, x25519]}|ClientOpts0],
- {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
-
- Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0},
- {from, self()},
- {mfa, {ssl_test_lib, send_recv_result_active, []}},
- {options, ServerOpts}]),
- Port = ssl_test_lib:inet_port(Server),
-
- Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port},
- {host, Hostname},
- {from, self()},
- {mfa, {ssl_test_lib, send_recv_result_active, []}},
- {options, ClientOpts}]),
-
-
- ssl_test_lib:check_result(Server, ok, Client, ok),
- ssl_test_lib:close(Server),
- ssl_test_lib:close_port(Client).
-
-tls13_client_auth_empty_cert_alert_ssl_server_openssl_client() ->
- [{doc,"TLS 1.3: Test client authentication when client sends an empty certificate and fail_if_no_peer_cert is set to true."}].
-
-tls13_client_auth_empty_cert_alert_ssl_server_openssl_client(Config) ->
- ClientOpts0 = ssl_test_lib:ssl_options(client_rsa_opts, Config),
- %% Delete Client Cert and Key
- ClientOpts1 = proplists:delete(certfile, ClientOpts0),
- ClientOpts = proplists:delete(keyfile, ClientOpts1),
-
- ServerOpts0 = ssl_test_lib:ssl_options(server_rsa_opts, Config),
- %% Set versions
- ServerOpts = [{versions, ['tlsv1.2','tlsv1.3']},
- {verify, verify_peer},
- {fail_if_no_peer_cert, true}|ServerOpts0],
- {_ClientNode, ServerNode, _Hostname} = ssl_test_lib:run_where(Config),
-
- Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0},
- {from, self()},
- {mfa, {ssl_test_lib, send_recv_result_active, []}},
- {options, ServerOpts}]),
- Port = ssl_test_lib:inet_port(Server),
-
- Client = ssl_test_lib:start_basic_client(openssl, 'tlsv1.3', Port, ClientOpts),
-
- ssl_test_lib:check_server_alert(Server, certificate_required),
- ssl_test_lib:close(Server),
- ssl_test_lib:close_port(Client).
-
-
-tls13_client_auth_empty_cert_alert_ssl_server_ssl_client() ->
- [{doc,"TLS 1.3: Test client authentication when client sends an empty certificate and fail_if_no_peer_cert is set to true."}].
-
-tls13_client_auth_empty_cert_alert_ssl_server_ssl_client(Config) ->
- ClientOpts0 = ssl_test_lib:ssl_options(client_rsa_opts, Config),
- %% Delete Client Cert and Key
- ClientOpts1 = proplists:delete(certfile, ClientOpts0),
- ClientOpts2 = proplists:delete(keyfile, ClientOpts1),
-
- ServerOpts0 = ssl_test_lib:ssl_options(server_rsa_opts, Config),
- %% Set versions
- ServerOpts = [{versions, ['tlsv1.2','tlsv1.3']},
- {verify, verify_peer},
- {fail_if_no_peer_cert, true}|ServerOpts0],
- ClientOpts = [{versions, ['tlsv1.2','tlsv1.3']}|ClientOpts2],
- {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
-
- Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0},
- {from, self()},
- {mfa, {ssl_test_lib, send_recv_result_active, []}},
- {options, ServerOpts}]),
- Port = ssl_test_lib:inet_port(Server),
-
- Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port},
- {host, Hostname},
- {from, self()},
- {mfa, {ssl_test_lib, send_recv_result_active, []}},
- {options, ClientOpts}]),
-
- ssl_test_lib:check_server_alert(Server, certificate_required),
- ssl_test_lib:close(Server),
- ssl_test_lib:close_port(Client).
-
-
-tls13_client_auth_empty_cert_ssl_server_openssl_client() ->
- [{doc,"TLS 1.3: Test client authentication when client sends an empty certificate and fail_if_no_peer_cert is set to false."}].
-
-tls13_client_auth_empty_cert_ssl_server_openssl_client(Config) ->
- ClientOpts0 = ssl_test_lib:ssl_options(client_rsa_opts, Config),
- %% Delete Client Cert and Key
- ClientOpts1 = proplists:delete(certfile, ClientOpts0),
- ClientOpts = proplists:delete(keyfile, ClientOpts1),
-
- ServerOpts0 = ssl_test_lib:ssl_options(server_rsa_opts, Config),
- %% Set versions
- ServerOpts = [{versions, ['tlsv1.2','tlsv1.3']},
- {verify, verify_peer},
- {fail_if_no_peer_cert, false}|ServerOpts0],
- {_ClientNode, ServerNode, _Hostname} = ssl_test_lib:run_where(Config),
-
- Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0},
- {from, self()},
- {mfa, {ssl_test_lib, send_recv_result_active, []}},
- {options, ServerOpts}]),
- Port = ssl_test_lib:inet_port(Server),
-
- Client = ssl_test_lib:start_basic_client(openssl, 'tlsv1.3', Port, ClientOpts),
-
- ssl_test_lib:check_result(Server, ok),
- ssl_test_lib:close(Server),
- ssl_test_lib:close_port(Client).
-
-
-tls13_client_auth_empty_cert_ssl_server_ssl_client() ->
- [{doc,"TLS 1.3: Test client authentication when client sends an empty certificate and fail_if_no_peer_cert is set to false."}].
-
-tls13_client_auth_empty_cert_ssl_server_ssl_client(Config) ->
- ClientOpts0 = ssl_test_lib:ssl_options(client_rsa_opts, Config),
- %% Delete Client Cert and Key
- ClientOpts1 = proplists:delete(certfile, ClientOpts0),
- ClientOpts2 = proplists:delete(keyfile, ClientOpts1),
-
- ServerOpts0 = ssl_test_lib:ssl_options(server_rsa_opts, Config),
- %% Set versions
- ServerOpts = [{versions, ['tlsv1.2','tlsv1.3']},
- {verify, verify_peer},
- {fail_if_no_peer_cert, false}|ServerOpts0],
- ClientOpts = [{versions, ['tlsv1.2','tlsv1.3']}|ClientOpts2],
- {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
-
- Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0},
- {from, self()},
- {mfa, {ssl_test_lib, send_recv_result_active, []}},
- {options, ServerOpts}]),
- Port = ssl_test_lib:inet_port(Server),
-
- Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port},
- {host, Hostname},
- {from, self()},
- {mfa, {ssl_test_lib, send_recv_result_active, []}},
- {options, ClientOpts}]),
-
- ssl_test_lib:check_result(Server, ok, Client, ok),
- ssl_test_lib:close(Server),
- ssl_test_lib:close_port(Client).
-
-
-tls13_client_auth_ssl_server_openssl_client() ->
- [{doc,"TLS 1.3: Test client authentication."}].
-
-tls13_client_auth_ssl_server_openssl_client(Config) ->
- ClientOpts = ssl_test_lib:ssl_options(client_rsa_opts, Config),
- ServerOpts0 = ssl_test_lib:ssl_options(server_rsa_opts, Config),
-
- %% Set versions
- ServerOpts = [{versions, ['tlsv1.2','tlsv1.3']},
- {verify, verify_peer},
- {fail_if_no_peer_cert, true}|ServerOpts0],
- {_ClientNode, ServerNode, _Hostname} = ssl_test_lib:run_where(Config),
-
- Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0},
- {from, self()},
- {mfa, {ssl_test_lib, send_recv_result_active, []}},
- {options, ServerOpts}]),
- Port = ssl_test_lib:inet_port(Server),
-
- Client = ssl_test_lib:start_basic_client(openssl, 'tlsv1.3', Port, ClientOpts),
-
- ssl_test_lib:check_result(Server, ok),
- ssl_test_lib:close(Server),
- ssl_test_lib:close_port(Client).
-
-
-tls13_client_auth_ssl_server_ssl_client() ->
- [{doc,"TLS 1.3: Test client authentication."}].
-
-tls13_client_auth_ssl_server_ssl_client(Config) ->
- ClientOpts0 = ssl_test_lib:ssl_options(client_rsa_opts, Config),
- ServerOpts0 = ssl_test_lib:ssl_options(server_rsa_opts, Config),
-
- %% Set versions
- ServerOpts = [{versions, ['tlsv1.2','tlsv1.3']},
- {verify, verify_peer},
- {fail_if_no_peer_cert, true}|ServerOpts0],
- ClientOpts = [{versions, ['tlsv1.2','tlsv1.3']}|ClientOpts0],
- {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
-
- Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0},
- {from, self()},
- {mfa, {ssl_test_lib, send_recv_result_active, []}},
- {options, ServerOpts}]),
- Port = ssl_test_lib:inet_port(Server),
-
- %%Client = ssl_test_lib:start_basic_client(openssl, 'tlsv1.3', Port, ClientOpts),
- Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port},
- {host, Hostname},
- {from, self()},
- {mfa, {ssl_test_lib, send_recv_result_active, []}},
- {options, ClientOpts}]),
-
- ssl_test_lib:check_result(Server, ok, Client, ok),
- ssl_test_lib:close(Server),
- ssl_test_lib:close_port(Client).
-
-
-tls13_hrr_client_auth_empty_cert_alert_ssl_server_openssl_client() ->
- [{doc,"TLS 1.3 (HelloRetryRequest): Test client authentication when client sends an empty certificate and fail_if_no_peer_cert is set to true."}].
-
-tls13_hrr_client_auth_empty_cert_alert_ssl_server_openssl_client(Config) ->
- ClientOpts0 = ssl_test_lib:ssl_options(client_rsa_opts, Config),
- %% Delete Client Cert and Key
- ClientOpts1 = proplists:delete(certfile, ClientOpts0),
- ClientOpts2 = proplists:delete(keyfile, ClientOpts1),
- ClientOpts = [{groups,"P-256:X25519"}|ClientOpts2],
-
- ServerOpts0 = ssl_test_lib:ssl_options(server_rsa_opts, Config),
- %% Set versions
- ServerOpts = [{versions, ['tlsv1.2','tlsv1.3']},
- {verify, verify_peer},
- {fail_if_no_peer_cert, true},
- {supported_groups, [x448, x25519]}|ServerOpts0],
- {_ClientNode, ServerNode, _Hostname} = ssl_test_lib:run_where(Config),
-
- Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0},
- {from, self()},
- {mfa, {ssl_test_lib, send_recv_result_active, []}},
- {options, ServerOpts}]),
- Port = ssl_test_lib:inet_port(Server),
-
- Client = ssl_test_lib:start_basic_client(openssl, 'tlsv1.3', Port, ClientOpts),
-
- ssl_test_lib:check_server_alert(Server, certificate_required),
- ssl_test_lib:close(Server),
- ssl_test_lib:close_port(Client).
-
-
-tls13_hrr_client_auth_empty_cert_alert_ssl_server_ssl_client() ->
- [{doc,"TLS 1.3 (HelloRetryRequest): Test client authentication when client sends an empty certificate and fail_if_no_peer_cert is set to true."}].
-
-tls13_hrr_client_auth_empty_cert_alert_ssl_server_ssl_client(Config) ->
- ClientOpts0 = ssl_test_lib:ssl_options(client_rsa_opts, Config),
- %% Delete Client Cert and Key
- ClientOpts1 = proplists:delete(certfile, ClientOpts0),
- ClientOpts2 = proplists:delete(keyfile, ClientOpts1),
-
- ServerOpts0 = ssl_test_lib:ssl_options(server_rsa_opts, Config),
- %% Set versions
- ServerOpts = [{versions, ['tlsv1.2','tlsv1.3']},
- {verify, verify_peer},
- {fail_if_no_peer_cert, true},
- {supported_groups, [x448, x25519]}|ServerOpts0],
- ClientOpts = [{versions, ['tlsv1.2','tlsv1.3']},
- {supported_groups, [secp256r1, x25519]}|ClientOpts2],
- {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
-
- Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0},
- {from, self()},
- {mfa, {ssl_test_lib, send_recv_result_active, []}},
- {options, ServerOpts}]),
- Port = ssl_test_lib:inet_port(Server),
-
- Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port},
- {host, Hostname},
- {from, self()},
- {mfa, {ssl_test_lib, send_recv_result_active, []}},
- {options, ClientOpts}]),
-
- ssl_test_lib:check_server_alert(Server, certificate_required),
- ssl_test_lib:close(Server),
- ssl_test_lib:close_port(Client).
-
-
-tls13_hrr_client_auth_empty_cert_ssl_server_openssl_client() ->
- [{doc,"TLS 1.3 (HelloRetryRequest): Test client authentication when client sends an empty certificate and fail_if_no_peer_cert is set to false."}].
-
-tls13_hrr_client_auth_empty_cert_ssl_server_openssl_client(Config) ->
- ClientOpts0 = ssl_test_lib:ssl_options(client_rsa_opts, Config),
- %% Delete Client Cert and Key
- ClientOpts1 = proplists:delete(certfile, ClientOpts0),
- ClientOpts2 = proplists:delete(keyfile, ClientOpts1),
- ClientOpts = [{groups,"P-256:X25519"}|ClientOpts2],
-
- ServerOpts0 = ssl_test_lib:ssl_options(server_rsa_opts, Config),
- %% Set versions
- ServerOpts = [{versions, ['tlsv1.2','tlsv1.3']},
- {verify, verify_peer},
- {fail_if_no_peer_cert, false},
- {supported_groups, [x448, x25519]}|ServerOpts0],
- {_ClientNode, ServerNode, _Hostname} = ssl_test_lib:run_where(Config),
-
- Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0},
- {from, self()},
- {mfa, {ssl_test_lib, send_recv_result_active, []}},
- {options, ServerOpts}]),
- Port = ssl_test_lib:inet_port(Server),
-
- Client = ssl_test_lib:start_basic_client(openssl, 'tlsv1.3', Port, ClientOpts),
-
- ssl_test_lib:check_result(Server, ok),
- ssl_test_lib:close(Server),
- ssl_test_lib:close_port(Client).
-
-
-tls13_hrr_client_auth_empty_cert_ssl_server_ssl_client() ->
- [{doc,"TLS 1.3 (HelloRetryRequest): Test client authentication when client sends an empty certificate and fail_if_no_peer_cert is set to false."}].
-
-tls13_hrr_client_auth_empty_cert_ssl_server_ssl_client(Config) ->
- ClientOpts0 = ssl_test_lib:ssl_options(client_rsa_opts, Config),
- %% Delete Client Cert and Key
- ClientOpts1 = proplists:delete(certfile, ClientOpts0),
- ClientOpts2 = proplists:delete(keyfile, ClientOpts1),
-
- ServerOpts0 = ssl_test_lib:ssl_options(server_rsa_opts, Config),
- %% Set versions
- ServerOpts = [{versions, ['tlsv1.2','tlsv1.3']},
- {verify, verify_peer},
- {fail_if_no_peer_cert, false},
- {supported_groups, [x448, x25519]}|ServerOpts0],
- ClientOpts = [{versions, ['tlsv1.2','tlsv1.3']},
- {supported_groups, [secp256r1, x25519]}|ClientOpts2],
- {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
-
- Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0},
- {from, self()},
- {mfa, {ssl_test_lib, send_recv_result_active, []}},
- {options, ServerOpts}]),
- Port = ssl_test_lib:inet_port(Server),
-
- Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port},
- {host, Hostname},
- {from, self()},
- {mfa, {ssl_test_lib, send_recv_result_active, []}},
- {options, ClientOpts}]),
-
- ssl_test_lib:check_result(Server, ok, Client, ok),
- ssl_test_lib:close(Server),
- ssl_test_lib:close_port(Client).
-
-
-tls13_hrr_client_auth_ssl_server_openssl_client() ->
- [{doc,"TLS 1.3 (HelloRetryRequest): Test client authentication."}].
-
-tls13_hrr_client_auth_ssl_server_openssl_client(Config) ->
- ClientOpts0 = ssl_test_lib:ssl_options(client_rsa_opts, Config),
- ClientOpts = [{groups,"P-256:X25519"}|ClientOpts0],
-
- ServerOpts0 = ssl_test_lib:ssl_options(server_rsa_opts, Config),
- %% Set versions
- ServerOpts = [{versions, ['tlsv1.2','tlsv1.3']},
- {verify, verify_peer},
- {fail_if_no_peer_cert, true},
- {supported_groups, [x448, x25519]}|ServerOpts0],
- {_ClientNode, ServerNode, _Hostname} = ssl_test_lib:run_where(Config),
-
- Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0},
- {from, self()},
- {mfa, {ssl_test_lib, send_recv_result_active, []}},
- {options, ServerOpts}]),
- Port = ssl_test_lib:inet_port(Server),
-
- Client = ssl_test_lib:start_basic_client(openssl, 'tlsv1.3', Port, ClientOpts),
-
- ssl_test_lib:check_result(Server, ok),
- ssl_test_lib:close(Server),
- ssl_test_lib:close_port(Client).
-
-
-tls13_hrr_client_auth_ssl_server_ssl_client() ->
- [{doc,"TLS 1.3 (HelloRetryRequest): Test client authentication."}].
-
-tls13_hrr_client_auth_ssl_server_ssl_client(Config) ->
- ClientOpts0 = ssl_test_lib:ssl_options(client_rsa_opts, Config),
-
- ServerOpts0 = ssl_test_lib:ssl_options(server_rsa_opts, Config),
- %% Set versions
- ServerOpts = [{versions, ['tlsv1.2','tlsv1.3']},
- {verify, verify_peer},
- {fail_if_no_peer_cert, true},
- {supported_groups, [x448, x25519]}|ServerOpts0],
- ClientOpts = [{versions, ['tlsv1.2','tlsv1.3']},
- {supported_groups, [secp256r1, x25519]}|ClientOpts0],
- {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
-
- Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0},
- {from, self()},
- {mfa, {ssl_test_lib, send_recv_result_active, []}},
- {options, ServerOpts}]),
- Port = ssl_test_lib:inet_port(Server),
-
- Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port},
- {host, Hostname},
- {from, self()},
- {mfa, {ssl_test_lib, send_recv_result_active, []}},
- {options, ClientOpts}]),
-
- ssl_test_lib:check_result(Server, ok, Client, ok),
- ssl_test_lib:close(Server),
- ssl_test_lib:close_port(Client).
-
-
-tls13_unsupported_sign_algo_client_auth_ssl_server_openssl_client() ->
- [{doc,"TLS 1.3: Test client authentication with unsupported signature_algorithm"}].
-
-tls13_unsupported_sign_algo_client_auth_ssl_server_openssl_client(Config) ->
- ClientOpts = ssl_test_lib:ssl_options(client_rsa_opts, Config),
-
- ServerOpts0 = ssl_test_lib:ssl_options(server_rsa_opts, Config),
- %% Set versions
- ServerOpts = [{versions, ['tlsv1.2','tlsv1.3']},
- {verify, verify_peer},
- %% Skip rsa_pkcs1_sha256!
- {signature_algs, [rsa_pkcs1_sha384, rsa_pkcs1_sha512]},
- {fail_if_no_peer_cert, true}|ServerOpts0],
- {_ClientNode, ServerNode, _Hostname} = ssl_test_lib:run_where(Config),
-
- Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0},
- {from, self()},
- {mfa, {ssl_test_lib, send_recv_result_active, []}},
- {options, ServerOpts}]),
- Port = ssl_test_lib:inet_port(Server),
-
- Client = ssl_test_lib:start_basic_client(openssl, 'tlsv1.3', Port, ClientOpts),
-
- ssl_test_lib:check_server_alert(Server, insufficient_security),
- ssl_test_lib:close(Server),
- ssl_test_lib:close_port(Client).
-
-
-tls13_unsupported_sign_algo_client_auth_ssl_server_ssl_client() ->
- [{doc,"TLS 1.3: Test client authentication with unsupported signature_algorithm"}].
-
-tls13_unsupported_sign_algo_client_auth_ssl_server_ssl_client(Config) ->
- ClientOpts0 = ssl_test_lib:ssl_options(client_rsa_opts, Config),
-
- ServerOpts0 = ssl_test_lib:ssl_options(server_rsa_opts, Config),
- %% Set versions
- ServerOpts = [{versions, ['tlsv1.2','tlsv1.3']},
- {verify, verify_peer},
- %% Skip rsa_pkcs1_sha256!
- {signature_algs, [rsa_pkcs1_sha384, rsa_pkcs1_sha512]},
- {fail_if_no_peer_cert, true}|ServerOpts0],
- ClientOpts = [{versions, ['tlsv1.2','tlsv1.3']}|ClientOpts0],
- {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
-
- Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0},
- {from, self()},
- {mfa, {ssl_test_lib, send_recv_result_active, []}},
- {options, ServerOpts}]),
- Port = ssl_test_lib:inet_port(Server),
-
- Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port},
- {host, Hostname},
- {from, self()},
- {mfa, {ssl_test_lib, send_recv_result_active, []}},
- {options, ClientOpts}]),
-
- ssl_test_lib:check_server_alert(Server, insufficient_security),
- ssl_test_lib:close(Server),
- ssl_test_lib:close_port(Client).
-
-
-%% Triggers a Server Alert as openssl s_client does not have a certificate with a
-%% signature algorithm supported by the server (signature_algorithms_cert extension
-%% of CertificateRequest does not contain the algorithm of the client certificate).
-%% openssl s_client sends an empty certificate.
-tls13_unsupported_sign_algo_cert_client_auth_ssl_server_openssl_client() ->
- [{doc,"TLS 1.3: Test client authentication with unsupported signature_algorithm_cert"}].
-
-tls13_unsupported_sign_algo_cert_client_auth_ssl_server_openssl_client(Config) ->
- ClientOpts = ssl_test_lib:ssl_options(client_rsa_opts, Config),
-
- ServerOpts0 = ssl_test_lib:ssl_options(server_rsa_opts, Config),
- %% Set versions
- ServerOpts = [{versions, ['tlsv1.2','tlsv1.3']},
- {log_level, debug},
- {verify, verify_peer},
- {signature_algs, [rsa_pkcs1_sha256, rsa_pkcs1_sha384, rsa_pss_rsae_sha256]},
- %% Skip rsa_pkcs1_sha256!
- {signature_algs_cert, [rsa_pkcs1_sha384, rsa_pkcs1_sha512]},
- {fail_if_no_peer_cert, true}|ServerOpts0],
- {_ClientNode, ServerNode, _Hostname} = ssl_test_lib:run_where(Config),
-
- Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0},
- {from, self()},
- {mfa, {ssl_test_lib, send_recv_result_active, []}},
- {options, ServerOpts}]),
- Port = ssl_test_lib:inet_port(Server),
-
- Client = ssl_test_lib:start_basic_client(openssl, 'tlsv1.3', Port, ClientOpts),
-
- ssl_test_lib:check_server_alert(Server, certificate_required),
- ssl_test_lib:close(Server),
- ssl_test_lib:close_port(Client).
-
-
-%% Triggers a Server Alert as ssl client does not have a certificate with a
-%% signature algorithm supported by the server (signature_algorithms_cert extension
-%% of CertificateRequest does not contain the algorithm of the client certificate).
-%% ssl client sends an empty certificate.
-tls13_unsupported_sign_algo_cert_client_auth_ssl_server_ssl_client() ->
- [{doc,"TLS 1.3: Test client authentication with unsupported signature_algorithm_cert"}].
-
-tls13_unsupported_sign_algo_cert_client_auth_ssl_server_ssl_client(Config) ->
- ClientOpts0 = ssl_test_lib:ssl_options(client_rsa_opts, Config),
-
- ServerOpts0 = ssl_test_lib:ssl_options(server_rsa_opts, Config),
- %% Set versions
- ServerOpts = [{versions, ['tlsv1.2','tlsv1.3']},
- {log_level, debug},
- {verify, verify_peer},
- {signature_algs, [rsa_pkcs1_sha256, rsa_pkcs1_sha384, rsa_pss_rsae_sha256]},
- %% Skip rsa_pkcs1_sha256!
- {signature_algs_cert, [rsa_pkcs1_sha384, rsa_pkcs1_sha512]},
- {fail_if_no_peer_cert, true}|ServerOpts0],
- ClientOpts = [{versions, ['tlsv1.2','tlsv1.3']}|ClientOpts0],
- {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
-
- Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0},
- {from, self()},
- {mfa, {ssl_test_lib, send_recv_result_active, []}},
- {options, ServerOpts}]),
- Port = ssl_test_lib:inet_port(Server),
-
- Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port},
- {host, Hostname},
- {from, self()},
- {mfa, {ssl_test_lib, send_recv_result_active, []}},
- {options, ClientOpts}]),
-
- ssl_test_lib:check_server_alert(Server, certificate_required),
- ssl_test_lib:close(Server),
- ssl_test_lib:close_port(Client).
-
-
-tls13_connection_information() ->
- [{doc,"Test the API function ssl:connection_information/1 in a TLS 1.3 connection"}].
-
-tls13_connection_information(Config) ->
- ClientOpts = ssl_test_lib:ssl_options(client_rsa_opts, Config),
- ServerOpts0 = ssl_test_lib:ssl_options(server_rsa_opts, Config),
- %% Set versions
- ServerOpts = [{versions, ['tlsv1.2','tlsv1.3']}|ServerOpts0],
- {_ClientNode, ServerNode, _Hostname} = ssl_test_lib:run_where(Config),
-
- Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0},
- {from, self()},
- {mfa, {?MODULE, connection_information_result, []}},
- {options, ServerOpts}]),
- Port = ssl_test_lib:inet_port(Server),
-
- Client = ssl_test_lib:start_basic_client(openssl, 'tlsv1.3', Port, ClientOpts),
-
- ssl_test_lib:check_result(Server, ok),
- ssl_test_lib:close(Server),
- ssl_test_lib:close_port(Client).
-
-
-tls13_ssl_server_with_alpn_ssl_client() ->
- [{doc,"Test TLS 1.3 between ssl server with ALPN configured and ssl client"}].
-
-tls13_ssl_server_with_alpn_ssl_client(Config) ->
- ClientOpts0 = ssl_test_lib:ssl_options(client_rsa_opts, Config),
- ServerOpts0 = ssl_test_lib:ssl_options(server_rsa_opts, Config),
- {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
-
- %% Set versions
- ServerOpts = [{versions, ['tlsv1.2','tlsv1.3']},
- {alpn_preferred_protocols, [<<5,6>>, <<1>>]}|ServerOpts0],
- ClientOpts = [{versions, ['tlsv1.2','tlsv1.3']}|ClientOpts0],
-
- Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0},
- {from, self()},
- {mfa, {ssl_test_lib, send_recv_result_active, []}},
- {options, ServerOpts}]),
- Port = ssl_test_lib:inet_port(Server),
-
- Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port},
- {host, Hostname},
- {from, self()},
- {mfa, {ssl_test_lib, send_recv_result_active, []}},
- {options, ClientOpts}]),
-
- ssl_test_lib:check_result(Server, ok, Client, ok),
-
- ssl_test_lib:close(Server),
- ssl_test_lib:close_port(Client).
-
-
-tls13_ssl_server_with_alpn_ssl_client_empty_alpn() ->
- [{doc,"Test TLS 1.3 between ssl server with ALPN configured and ssl client with empty ALPN"}].
-
-tls13_ssl_server_with_alpn_ssl_client_empty_alpn(Config) ->
- ClientOpts0 = ssl_test_lib:ssl_options(client_rsa_opts, Config),
- ServerOpts0 = ssl_test_lib:ssl_options(server_rsa_opts, Config),
- {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
-
- %% Set versions
- ServerOpts = [{versions, ['tlsv1.2','tlsv1.3']},
- {alpn_preferred_protocols, [<<5,6>>, <<1>>]}|ServerOpts0],
- ClientOpts = [{versions, ['tlsv1.2','tlsv1.3']},
- {alpn_advertised_protocols, []}|ClientOpts0],
-
- Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0},
- {from, self()},
- {mfa, {ssl_test_lib, send_recv_result_active, []}},
- {options, ServerOpts}]),
- Port = ssl_test_lib:inet_port(Server),
-
- Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port},
- {host, Hostname},
- {from, self()},
- {mfa, {ssl_test_lib, send_recv_result_active, []}},
- {options, ClientOpts}]),
-
- ssl_test_lib:check_server_alert(Server, no_application_protocol),
-
- ssl_test_lib:close(Server),
- ssl_test_lib:close_port(Client).
-
-
-tls13_ssl_server_with_alpn_ssl_client_bad_alpn() ->
- [{doc,"Test TLS 1.3 between ssl server with ALPN configured and ssl client with bad ALPN"}].
-
-tls13_ssl_server_with_alpn_ssl_client_bad_alpn(Config) ->
- ClientOpts0 = ssl_test_lib:ssl_options(client_rsa_opts, Config),
- ServerOpts0 = ssl_test_lib:ssl_options(server_rsa_opts, Config),
- {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
-
- %% Set versions
- ServerOpts = [{versions, ['tlsv1.2','tlsv1.3']},
- {alpn_preferred_protocols, [<<5,6>>, <<1>>]}|ServerOpts0],
- ClientOpts = [{versions, ['tlsv1.2','tlsv1.3']},
- {alpn_advertised_protocols, [<<1,2,3,4>>]}|ClientOpts0],
-
- Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0},
- {from, self()},
- {mfa, {ssl_test_lib, send_recv_result_active, []}},
- {options, ServerOpts}]),
- Port = ssl_test_lib:inet_port(Server),
-
- Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port},
- {host, Hostname},
- {from, self()},
- {mfa, {ssl_test_lib, send_recv_result_active, []}},
- {options, ClientOpts}]),
-
- ssl_test_lib:check_server_alert(Server, no_application_protocol),
-
- ssl_test_lib:close(Server),
- ssl_test_lib:close_port(Client).
-
-tls13_ssl_server_with_alpn_ssl_client_alpn() ->
- [{doc,"Test TLS 1.3 between ssl server with ALPN configured and ssl client with correct ALPN"}].
-
-tls13_ssl_server_with_alpn_ssl_client_alpn(Config) ->
- ClientOpts0 = ssl_test_lib:ssl_options(client_rsa_opts, Config),
- ServerOpts0 = ssl_test_lib:ssl_options(server_rsa_opts, Config),
- {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
-
- %% Set versions
- ServerOpts = [{versions, ['tlsv1.2','tlsv1.3']},
- {alpn_preferred_protocols, [<<5,6>>, <<1>>]}|ServerOpts0],
- ClientOpts = [{versions, ['tlsv1.2','tlsv1.3']},
- {alpn_advertised_protocols, [<<1,2,3,4>>, <<5,6>>]}|ClientOpts0],
-
- Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0},
- {from, self()},
- {mfa, {ssl_test_lib, send_recv_result_active, []}},
- {options, ServerOpts}]),
- Port = ssl_test_lib:inet_port(Server),
-
- Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port},
- {host, Hostname},
- {from, self()},
- {mfa, {ssl_test_lib, send_recv_result_active, []}},
- {options, ClientOpts}]),
-
- ssl_test_lib:check_result(Server, ok, Client, ok),
-
- ssl_test_lib:close(Server),
- ssl_test_lib:close_port(Client).
-
-
-tls13_ecdsa_ssl_server_openssl_client() ->
- [{doc,"Test TLS 1.3 basic connection between ssl server and openssl s_client using ECDSA certificates"}].
-
-tls13_ecdsa_ssl_server_openssl_client(Config) ->
- ClientOpts = ssl_test_lib:ssl_options(client_ecdsa_opts, Config),
- ServerOpts0 = ssl_test_lib:ssl_options(server_ecdsa_opts, Config),
- %% Set versions
- ServerOpts = [{versions, ['tlsv1.2','tlsv1.3']}|ServerOpts0],
- {_ClientNode, ServerNode, _Hostname} = ssl_test_lib:run_where(Config),
-
- Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0},
- {from, self()},
- {mfa, {ssl_test_lib, send_recv_result_active, []}},
- {options, ServerOpts}]),
- Port = ssl_test_lib:inet_port(Server),
-
- Client = ssl_test_lib:start_basic_client(openssl, 'tlsv1.3', Port, ClientOpts),
-
- ssl_test_lib:check_result(Server, ok),
- ssl_test_lib:close(Server),
- ssl_test_lib:close_port(Client).
-
-tls13_ecdsa_ssl_server_ssl_client() ->
- [{doc,"Test TLS 1.3 basic connection between ssl server and ssl client using ECDSA certificates"}].
-
-tls13_ecdsa_ssl_server_ssl_client(Config) ->
- ClientOpts0 = ssl_test_lib:ssl_options(client_ecdsa_opts, Config),
- ServerOpts0 = ssl_test_lib:ssl_options(server_ecdsa_opts, Config),
- {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
-
- %% Set versions
- ServerOpts = [{versions, ['tlsv1.2','tlsv1.3']}|ServerOpts0],
- ClientOpts = [{versions, ['tlsv1.2','tlsv1.3']}|ClientOpts0],
-
- Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0},
- {from, self()},
- {mfa, {ssl_test_lib, send_recv_result_active, []}},
- {options, ServerOpts}]),
- Port = ssl_test_lib:inet_port(Server),
-
- Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port},
- {host, Hostname},
- {from, self()},
- {mfa, {ssl_test_lib, send_recv_result_active, []}},
- {options, ClientOpts}]),
-
- ssl_test_lib:check_result(Server, ok, Client, ok),
-
- ssl_test_lib:close(Server),
- ssl_test_lib:close_port(Client).
-
-
-tls13_ecdsa_openssl_server_ssl_client() ->
- [{doc,"Test TLS 1.3 basic connection between openssl server and ssl client using ECDSA certificates"}].
-
-tls13_ecdsa_openssl_server_ssl_client(Config) ->
- process_flag(trap_exit, true),
- ServerOpts = ssl_test_lib:ssl_options(server_ecdsa_verify_opts, Config),
- ClientOpts0 = ssl_test_lib:ssl_options(client_ecdsa_opts, Config),
-
- ClientOpts = [{versions, ['tlsv1.2','tlsv1.3']}|ClientOpts0],
-
- {ClientNode, _, Hostname} = ssl_test_lib:run_where(Config),
-
- Data = "From openssl to erlang",
-
- Port = ssl_test_lib:inet_port(node()),
- CertFile = proplists:get_value(certfile, ServerOpts),
- CaCertFile = proplists:get_value(cacertfile, ServerOpts),
- KeyFile = proplists:get_value(keyfile, ServerOpts),
- Exe = "openssl",
- Args = ["s_server", "-accept", integer_to_list(Port),
- "-tls1_3",
- "-cert", CertFile, "-CAfile", CaCertFile,
- "-key", KeyFile, "-Verify", "2"],
-
- OpensslPort = ssl_test_lib:portable_open_port(Exe, Args),
-
- ssl_test_lib:wait_for_openssl_server(Port, tls),
-
- Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port},
- {host, Hostname},
- {from, self()},
- {mfa, {?MODULE,
- erlang_ssl_receive, [Data]}},
- {options, ClientOpts}]),
- true = port_command(OpensslPort, Data),
-
- ssl_test_lib:check_result(Client, ok),
-
- %% Clean close down! Server needs to be closed first !!
- ssl_test_lib:close_port(OpensslPort),
- ssl_test_lib:close(Client),
- process_flag(trap_exit, false).
-
-
-tls13_ecdsa_client_auth_ssl_server_ssl_client() ->
- [{doc,"TLS 1.3: Test client authentication with ECDSA certificates."}].
-
-tls13_ecdsa_client_auth_ssl_server_ssl_client(Config) ->
- ClientOpts0 = ssl_test_lib:ssl_options(client_ecdsa_opts, Config),
- ServerOpts0 = ssl_test_lib:ssl_options(server_ecdsa_opts, Config),
-
- %% Set versions
- ServerOpts = [{versions, ['tlsv1.2','tlsv1.3']},
- {verify, verify_peer},
- {fail_if_no_peer_cert, true}|ServerOpts0],
- ClientOpts = [{versions, ['tlsv1.2','tlsv1.3']}|ClientOpts0],
- {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
-
- Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0},
- {from, self()},
- {mfa, {ssl_test_lib, send_recv_result_active, []}},
- {options, ServerOpts}]),
- Port = ssl_test_lib:inet_port(Server),
-
- %%Client = ssl_test_lib:start_basic_client(openssl, 'tlsv1.3', Port, ClientOpts),
- Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port},
- {host, Hostname},
- {from, self()},
- {mfa, {ssl_test_lib, send_recv_result_active, []}},
- {options, ClientOpts}]),
-
- ssl_test_lib:check_result(Server, ok, Client, ok),
- ssl_test_lib:close(Server),
- ssl_test_lib:close_port(Client).
-
-
-
-%%--------------------------------------------------------------------
%% Internal functions ------------------------------------------------
%%--------------------------------------------------------------------
send_recv_result(Socket) ->
@@ -6468,491 +463,9 @@ tcp_send_recv_result(Socket) ->
{ok,"Hello world"} = gen_tcp:recv(Socket, 11),
ok.
-basic_verify_test_no_close(Config) ->
- ClientOpts = ssl_test_lib:ssl_options(client_rsa_verify_opts, Config),
- ServerOpts = ssl_test_lib:ssl_options(server_rsa_verify_opts, Config),
-
- {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
-
- Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0},
- {from, self()},
- {mfa, {ssl_test_lib, send_recv_result_active, []}},
- {options, ServerOpts}]),
- Port = ssl_test_lib:inet_port(Server),
- Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port},
- {host, Hostname},
- {from, self()},
- {mfa, {ssl_test_lib, send_recv_result_active, []}},
- {options, ClientOpts}]),
-
- ssl_test_lib:check_result(Server, ok, Client, ok),
- {Server, Client}.
-
-basic_test(Config) ->
- ClientOpts = ssl_test_lib:ssl_options(client_opts, Config),
- ServerOpts = ssl_test_lib:ssl_options(server_opts, Config),
-
- {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
-
- Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0},
- {from, self()},
- {mfa, {ssl_test_lib, send_recv_result_active, []}},
- {options, ServerOpts}]),
- Port = ssl_test_lib:inet_port(Server),
- Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port},
- {host, Hostname},
- {from, self()},
- {mfa, {ssl_test_lib, send_recv_result_active, []}},
- {options, ClientOpts}]),
-
- ssl_test_lib:check_result(Server, ok, Client, ok),
- ssl_test_lib:close(Server),
- ssl_test_lib:close(Client).
-
-prf_create_plan(TlsVersions, PRFs, Results) ->
- lists:foldl(fun(Ver, Acc) ->
- A = prf_ciphers_and_expected(Ver, PRFs, Results),
- [A|Acc]
- end, [], TlsVersions).
-prf_ciphers_and_expected(TlsVer, PRFs, Results) ->
- case TlsVer of
- TlsVer when TlsVer == sslv3 orelse TlsVer == tlsv1
- orelse TlsVer == 'tlsv1.1' orelse TlsVer == 'dtlsv1' ->
- Ciphers = ssl:cipher_suites(),
- {_, Expected} = lists:keyfind(md5sha, 1, Results),
- [[{tls_ver, TlsVer}, {ciphers, Ciphers}, {expected, Expected}, {prf, md5sha}]];
- TlsVer when TlsVer == 'tlsv1.2' orelse TlsVer == 'dtlsv1.2'->
- lists:foldl(
- fun(PRF, Acc) ->
- Ciphers = prf_get_ciphers(TlsVer, PRF),
- case Ciphers of
- [] ->
- ct:log("No ciphers for PRF algorithm ~p. Skipping.", [PRF]),
- Acc;
- Ciphers ->
- {_, Expected} = lists:keyfind(PRF, 1, Results),
- [[{tls_ver, TlsVer}, {ciphers, Ciphers}, {expected, Expected},
- {prf, PRF}] | Acc]
- end
- end, [], PRFs)
- end.
-prf_get_ciphers(_, PRF) ->
- lists:filter(
- fun(C) when tuple_size(C) == 4 andalso
- element(4, C) == PRF ->
- true;
- (_) ->
- false
- end,
- ssl:cipher_suites()).
-prf_run_test(_, TlsVer, [], _, Prf) ->
- ct:fail({error, cipher_list_empty, TlsVer, Prf});
-prf_run_test(Config, TlsVer, Ciphers, Expected, Prf) ->
- {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
- BaseOpts = [{active, true}, {versions, [TlsVer]}, {ciphers, Ciphers}, {protocol, tls_or_dtls(TlsVer)}],
- ServerOpts = BaseOpts ++ proplists:get_value(server_opts, Config),
- ClientOpts = BaseOpts ++ proplists:get_value(client_opts, Config),
- Server = ssl_test_lib:start_server(
- [{node, ServerNode}, {port, 0}, {from, self()},
- {mfa, {?MODULE, prf_verify_value, [TlsVer, Expected, Prf]}},
- {options, ServerOpts}]),
- Port = ssl_test_lib:inet_port(Server),
- Client = ssl_test_lib:start_client(
- [{node, ClientNode}, {port, Port},
- {host, Hostname}, {from, self()},
- {mfa, {?MODULE, prf_verify_value, [TlsVer, Expected, Prf]}},
- {options, ClientOpts}]),
- ssl_test_lib:check_result(Server, ok, Client, ok),
- ssl_test_lib:close(Server),
- ssl_test_lib:close(Client).
-prf_verify_value(Socket, TlsVer, Expected, Algo) ->
- Ret = ssl:prf(Socket, <<>>, <<>>, [<<>>], 16),
- case TlsVer of
- sslv3 ->
- case Ret of
- {error, undefined} -> ok;
- _ ->
- {error, {expected, {error, undefined},
- got, Ret, tls_ver, TlsVer, prf_algorithm, Algo}}
- end;
- _ ->
- case Ret of
- {ok, Expected} -> ok;
- {ok, Val} -> {error, {expected, Expected, got, Val, tls_ver, TlsVer,
- prf_algorithm, Algo}}
- end
- end.
-
-send_recv_result_timeout_client(Socket) ->
- {error, timeout} = ssl:recv(Socket, 11, 500),
- {error, timeout} = ssl:recv(Socket, 11, 0),
- ssl:send(Socket, "Hello world"),
- receive
- Msg ->
- io:format("Msg ~p~n",[Msg])
- after 500 ->
- ok
- end,
- {ok, "Hello world"} = ssl:recv(Socket, 11, 500),
- ok.
-send_recv_result_timeout_server(Socket) ->
- ssl:send(Socket, "Hello"),
- {ok, "Hello world"} = ssl:recv(Socket, 11),
- ssl:send(Socket, " world"),
- ok.
-
-recv_close(Socket) ->
- {error, closed} = ssl:recv(Socket, 11),
- receive
- {_,{error,closed}} ->
- error_extra_close_sent_to_user_process
- after 500 ->
- ok
- end.
-
-
-send_recv_result_active_rizzo(Socket) ->
- ssl:send(Socket, "Hello world"),
- "Hello world" = ssl_test_lib:active_recv(Socket, 11),
- ok.
-
-send_recv_result_active_no_rizzo(Socket) ->
- ssl:send(Socket, "Hello world"),
- "Hello world" = ssl_test_lib:active_recv(Socket, 11),
- ok.
-
-
-ssl_active_recv(N) ->
- ssl_active_recv(N, []).
-
-ssl_active_recv(0, Acc) ->
- Acc;
-ssl_active_recv(N, Acc) ->
- receive
- {ssl, _, Bytes} ->
- ssl_active_recv(N-length(Bytes), Acc ++ Bytes)
- end.
-
result_ok(_Socket) ->
ok.
-renegotiate(Socket, Data) ->
- ct:log("Renegotiating ~n", []),
- Result = ssl:renegotiate(Socket),
- ct:log("Result ~p~n", [Result]),
- ssl:send(Socket, Data),
- case Result of
- ok ->
- ok;
- Other ->
- Other
- end.
-
-renegotiate_reuse_session(Socket, Data) ->
- %% Make sure session is registered
- ct:sleep(?SLEEP),
- renegotiate(Socket, Data).
-
-renegotiate_immediately(Socket) ->
- _ = ssl_test_lib:active_recv(Socket, 11),
- ok = ssl:renegotiate(Socket),
- {error, renegotiation_rejected} = ssl:renegotiate(Socket),
- ct:sleep(?RENEGOTIATION_DISABLE_TIME + ?SLEEP),
- ok = ssl:renegotiate(Socket),
- ct:log("Renegotiated again"),
- ssl:send(Socket, "Hello world"),
- ok.
-
-renegotiate_rejected(Socket) ->
- _ = ssl_test_lib:active_recv(Socket, 11),
- {error, renegotiation_rejected} = ssl:renegotiate(Socket),
- {error, renegotiation_rejected} = ssl:renegotiate(Socket),
- ct:sleep(?RENEGOTIATION_DISABLE_TIME +1),
- {error, renegotiation_rejected} = ssl:renegotiate(Socket),
- ct:log("Failed to renegotiate again"),
- ssl:send(Socket, "Hello world"),
- ok.
-
-rizzo_add_mitigation_option(Value, Config) ->
- lists:foldl(fun(Opt, Acc) ->
- case proplists:get_value(Opt, Acc) of
- undefined -> Acc;
- C ->
- N = lists:keystore(beast_mitigation, 1, C,
- {beast_mitigation, Value}),
- lists:keystore(Opt, 1, Acc, {Opt, N})
- end
- end, Config,
- [client_opts, client_dsa_opts, server_opts, server_dsa_opts,
- server_ecdsa_opts, server_ecdh_rsa_opts]).
-
-new_config(PrivDir, ServerOpts0) ->
- CaCertFile = proplists:get_value(cacertfile, ServerOpts0),
- CertFile = proplists:get_value(certfile, ServerOpts0),
- KeyFile = proplists:get_value(keyfile, ServerOpts0),
- NewCaCertFile = filename:join(PrivDir, "new_ca.pem"),
- NewCertFile = filename:join(PrivDir, "new_cert.pem"),
- NewKeyFile = filename:join(PrivDir, "new_key.pem"),
- file:copy(CaCertFile, NewCaCertFile),
- file:copy(CertFile, NewCertFile),
- file:copy(KeyFile, NewKeyFile),
- ServerOpts1 = proplists:delete(cacertfile, ServerOpts0),
- ServerOpts2 = proplists:delete(certfile, ServerOpts1),
- ServerOpts = proplists:delete(keyfile, ServerOpts2),
-
- {ok, PEM} = file:read_file(NewCaCertFile),
- ct:log("CA file content: ~p~n", [public_key:pem_decode(PEM)]),
-
- [{cacertfile, NewCaCertFile}, {certfile, NewCertFile},
- {keyfile, NewKeyFile} | ServerOpts].
-
-session_cache_process(_Type,Config) when is_list(Config) ->
- reuse_session(Config).
-
-init([Type]) ->
- ets:new(ssl_test, [named_table, public, set]),
- ets:insert(ssl_test, {type, Type}),
- case Type of
- list ->
- spawn(fun() -> session_loop([]) end);
- mnesia ->
- mnesia:start(),
- {atomic,ok} = mnesia:create_table(sess_cache, []),
- sess_cache
- end.
-
-session_cb() ->
- [{type, Type}] = ets:lookup(ssl_test, type),
- Type.
-
-terminate(Cache) ->
- case session_cb() of
- list ->
- Cache ! terminate;
- mnesia ->
- catch {atomic,ok} =
- mnesia:delete_table(sess_cache)
- end.
-
-lookup(Cache, Key) ->
- case session_cb() of
- list ->
- Cache ! {self(), lookup, Key},
- receive {Cache, Res} -> Res end;
- mnesia ->
- case mnesia:transaction(fun() ->
- mnesia:read(sess_cache,
- Key, read)
- end) of
- {atomic, [{sess_cache, Key, Value}]} ->
- Value;
- _ ->
- undefined
- end
- end.
-
-update(Cache, Key, Value) ->
- case session_cb() of
- list ->
- Cache ! {update, Key, Value};
- mnesia ->
- {atomic, ok} =
- mnesia:transaction(fun() ->
- mnesia:write(sess_cache,
- {sess_cache, Key, Value}, write)
- end)
- end.
-
-delete(Cache, Key) ->
- case session_cb() of
- list ->
- Cache ! {delete, Key};
- mnesia ->
- {atomic, ok} =
- mnesia:transaction(fun() ->
- mnesia:delete(sess_cache, Key)
- end)
- end.
-
-foldl(Fun, Acc, Cache) ->
- case session_cb() of
- list ->
- Cache ! {self(),foldl,Fun,Acc},
- receive {Cache, Res} -> Res end;
- mnesia ->
- Foldl = fun() ->
- mnesia:foldl(Fun, Acc, sess_cache)
- end,
- {atomic, Res} = mnesia:transaction(Foldl),
- Res
- end.
-
-select_session(Cache, PartialKey) ->
- case session_cb() of
- list ->
- Cache ! {self(),select_session, PartialKey},
- receive
- {Cache, Res} ->
- Res
- end;
- mnesia ->
- Sel = fun() ->
- mnesia:select(Cache,
- [{{sess_cache,{PartialKey,'$1'}, '$2'},
- [],['$$']}])
- end,
- {atomic, Res} = mnesia:transaction(Sel),
- Res
- end.
-
-session_loop(Sess) ->
- receive
- terminate ->
- ok;
- {Pid, lookup, Key} ->
- case lists:keysearch(Key,1,Sess) of
- {value, {Key,Value}} ->
- Pid ! {self(), Value};
- _ ->
- Pid ! {self(), undefined}
- end,
- session_loop(Sess);
- {update, Key, Value} ->
- NewSess = [{Key,Value}| lists:keydelete(Key,1,Sess)],
- session_loop(NewSess);
- {delete, Key} ->
- session_loop(lists:keydelete(Key,1,Sess));
- {Pid,foldl,Fun,Acc} ->
- Res = lists:foldl(Fun, Acc,Sess),
- Pid ! {self(), Res},
- session_loop(Sess);
- {Pid,select_session,PKey} ->
- Sel = fun({{PKey0, Id},Session}, Acc) when PKey == PKey0 ->
- [[Id, Session]|Acc];
- (_,Acc) ->
- Acc
- end,
- Sessions = lists:foldl(Sel, [], Sess),
- Pid ! {self(), Sessions},
- session_loop(Sess)
- end.
-
-
-erlang_ssl_receive(Socket, Data) ->
- case ssl_test_lib:active_recv(Socket, length(Data)) of
- Data ->
- ok;
- Other ->
- ct:fail({{expected, Data}, {got, Other}})
- end.
-
-receive_msg(_) ->
- receive
- Msg ->
- Msg
- end.
-
-controlling_process_result(Socket, Pid, Msg) ->
- ok = ssl:controlling_process(Socket, Pid),
- %% Make sure other side has evaluated controlling_process
- %% before message is sent
- ct:sleep(?SLEEP),
- ssl:send(Socket, Msg),
- no_result_msg.
-
-
-controller_dies_result(_Socket, _Pid, _Msg) ->
- receive Result -> Result end.
-
-get_close(Pid, Where) ->
- receive
- {'EXIT', Pid, _Reason} ->
- receive
- {_, {ssl_closed, Socket}} ->
- ct:log("Socket closed ~p~n",[Socket]);
- Unexpected ->
- ct:log("Unexpected ~p~n",[Unexpected]),
- ct:fail({line, ?LINE-1})
- after 5000 ->
- ct:fail({timeout, {line, ?LINE, Where}})
- end;
- Unexpected ->
- ct:log("Unexpected ~p~n",[Unexpected]),
- ct:fail({line, ?LINE-1})
- after 5000 ->
- ct:fail({timeout, {line, ?LINE, Where}})
- end.
-
-run_send_recv_rizzo(Ciphers, Config, Version, Mfa) ->
- Result = lists:map(fun(Cipher) ->
- rizzo_test(Cipher, Config, Version, Mfa) end,
- Ciphers),
- case lists:flatten(Result) of
- [] ->
- ok;
- Error ->
- ct:log("Cipher suite errors: ~p~n", [Error]),
- ct:fail(cipher_suite_failed_see_test_case_log)
- end.
-
-rizzo_test(Cipher, Config, Version, Mfa) ->
- {ClientOpts, ServerOpts} = client_server_opts(Cipher, Config),
- {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
- Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0},
- {from, self()},
- {mfa, Mfa},
- {options, [{active, true}, {ciphers, [Cipher]},
- {versions, [Version]}
- | ServerOpts]}]),
- Port = ssl_test_lib:inet_port(Server),
- Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port},
- {host, Hostname},
- {from, self()},
- {mfa, Mfa},
- {options, [{active, true}, {ciphers, [Cipher]}| ClientOpts]}]),
-
- Result = ssl_test_lib:check_result(Server, ok, Client, ok),
- ssl_test_lib:close(Server),
- ssl_test_lib:close(Client),
- case Result of
- ok ->
- [];
- Error ->
- [{Cipher, Error}]
- end.
-
-client_server_opts(#{key_exchange := KeyAlgo}, Config)
- when KeyAlgo == rsa orelse
- KeyAlgo == dhe_rsa orelse
- KeyAlgo == ecdhe_rsa orelse
- KeyAlgo == rsa_psk orelse
- KeyAlgo == srp_rsa ->
- {ssl_test_lib:ssl_options(client_opts, Config),
- ssl_test_lib:ssl_options(server_opts, Config)};
-client_server_opts(#{key_exchange := KeyAlgo}, Config) when KeyAlgo == dss orelse KeyAlgo == dhe_dss ->
- {ssl_test_lib:ssl_options(client_dsa_opts, Config),
- ssl_test_lib:ssl_options(server_dsa_opts, Config)};
-client_server_opts(#{key_exchange := KeyAlgo}, Config) when KeyAlgo == ecdh_ecdsa orelse KeyAlgo == ecdhe_ecdsa ->
- {ssl_test_lib:ssl_options(client_opts, Config),
- ssl_test_lib:ssl_options(server_ecdsa_opts, Config)};
-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)}.
-
-connection_information_result(Socket) ->
- {ok, Info = [_ | _]} = ssl:connection_information(Socket),
- case length(Info) > 3 of
- true ->
- %% Atleast one ssl_option() is set
- ct:log("Info ~p", [Info]),
- ok;
- false ->
- ct:fail(no_ssl_options_returned)
- end.
-
-connection_info_result(Socket) ->
- {ok, Info} = ssl:connection_information(Socket, [protocol, selected_cipher_suite]),
- {ok, {proplists:get_value(protocol, Info), proplists:get_value(selected_cipher_suite, Info)}}.
protocol_info_result(Socket) ->
{ok, [{protocol, PVersion}]} = ssl:connection_information(Socket, [protocol]),
@@ -6962,11 +475,7 @@ version_info_result(Socket) ->
{ok, [{version, Version}]} = ssl:connection_information(Socket, [version]),
{ok, Version}.
-secret_connection_info_result(Socket) ->
- {ok, [{client_random, ClientRand}, {server_random, ServerRand}, {master_secret, MasterSecret}]}
- = ssl:connection_information(Socket, [client_random, server_random, master_secret]),
- is_binary(ClientRand) andalso is_binary(ServerRand) andalso is_binary(MasterSecret).
-
+
connect_dist_s(S) ->
Msg = term_to_binary({erlang,term}),
ok = ssl:send(S, Msg).
@@ -6976,88 +485,11 @@ connect_dist_c(S) ->
{ok, Test} = ssl:recv(S, 0, 10000),
ok.
-tls_downgrade_result(Socket, Pid) ->
- ok = ssl_test_lib:send_recv_result(Socket),
- Pid ! {self(), ready},
- receive
- go ->
- ok
- end,
- case ssl:close(Socket, {self(), 10000}) of
- {ok, TCPSocket} ->
- inet:setopts(TCPSocket, [{active, true}]),
- gen_tcp:send(TCPSocket, "Downgraded"),
- receive
- {tcp, TCPSocket, <<"Downgraded">>} ->
- ok;
- {tcp_closed, TCPSocket} ->
- ct:fail("Peer timed out, downgrade aborted"),
- ok;
- Other ->
- {error, Other}
- end;
- {error, timeout} ->
- ct:fail("Timed out, downgrade aborted"),
- ok;
- Fail ->
- {error, Fail}
- end.
-
-tls_close(Socket) ->
- ok = ssl_test_lib:send_recv_result(Socket),
- case ssl:close(Socket, 5000) of
- ok ->
- ok;
- {error, closed} ->
- ok;
- Other ->
- ct:fail(Other)
- end.
-
- %% First two clauses handles 1/n-1 splitting countermeasure Rizzo/Duong-Beast
-treashold(N, {3,0}) ->
- (N div 2) + 1;
-treashold(N, {3,1}) ->
- (N div 2) + 1;
-treashold(N, _) ->
- N + 1.
-
-get_invalid_inet_option(Socket) ->
- {error, {options, {socket_options, foo, _}}} = ssl:getopts(Socket, [foo]),
- ok.
-
-tls_shutdown_result(Socket, server) ->
- ssl:send(Socket, "Hej"),
- ok = ssl:shutdown(Socket, write),
- {ok, "Hej hopp"} = ssl:recv(Socket, 8),
- ok;
-
-tls_shutdown_result(Socket, client) ->
- ssl:send(Socket, "Hej hopp"),
- ok = ssl:shutdown(Socket, write),
- {ok, "Hej"} = ssl:recv(Socket, 3),
- ok.
-
-tls_shutdown_write_result(Socket, server) ->
- ct:sleep(?SLEEP),
- ssl:shutdown(Socket, write);
-tls_shutdown_write_result(Socket, client) ->
- ssl:recv(Socket, 0).
-
dummy(_Socket) ->
%% Should not happen as the ssl connection will not be established
%% due to fatal handshake failiure
exit(kill).
-tls_shutdown_both_result(Socket, server) ->
- ct:sleep(?SLEEP),
- ssl:shutdown(Socket, read_write);
-tls_shutdown_both_result(Socket, client) ->
- ssl:recv(Socket, 0).
-
-peername_result(S) ->
- ssl:peername(S).
-
version_option_test(Config, Version) ->
ClientOpts = ssl_test_lib:ssl_options(client_opts, Config),
ServerOpts = ssl_test_lib:ssl_options(server_opts, Config),
@@ -7083,50 +515,3 @@ version_option_test(Config, Version) ->
ssl_test_lib:close(Server),
ssl_test_lib:close(Client).
-try_recv_active(Socket) ->
- ssl:send(Socket, "Hello world"),
- {error, einval} = ssl:recv(Socket, 11),
- ok.
-try_recv_active_once(Socket) ->
- {error, einval} = ssl:recv(Socket, 11),
- ok.
-
-
-wait_for_send(Socket) ->
- %% Make sure TLS process processed send message event
- _ = ssl:connection_information(Socket).
-
-tls_or_dtls('dtlsv1') ->
- dtls;
-tls_or_dtls('dtlsv1.2') ->
- dtls;
-tls_or_dtls(_) ->
- tls.
-
-hexstr2int(S) ->
- B = hexstr2bin(S),
- Bits = size(B) * 8,
- <<Integer:Bits/integer>> = B,
- Integer.
-
-hexstr2bin(S) when is_binary(S) ->
- hexstr2bin(S, <<>>);
-hexstr2bin(S) ->
- hexstr2bin(list_to_binary(S), <<>>).
-%%
-hexstr2bin(<<>>, Acc) ->
- Acc;
-hexstr2bin(<<C,T/binary>>, Acc) when C =:= 32; %% SPACE
- C =:= 10; %% LF
- C =:= 13 -> %% CR
- hexstr2bin(T, Acc);
-hexstr2bin(<<X,Y,T/binary>>, Acc) ->
- I = hex2int(X) * 16 + hex2int(Y),
- hexstr2bin(T, <<Acc/binary,I>>).
-
-hex2int(C) when $0 =< C, C =< $9 ->
- C - $0;
-hex2int(C) when $A =< C, C =< $F ->
- C - $A + 10;
-hex2int(C) when $a =< C, C =< $f ->
- C - $a + 10.
diff --git a/lib/ssl/test/ssl_bench_SUITE.erl b/lib/ssl/test/ssl_bench_SUITE.erl
index 35efa2b8a3..a297539c36 100644
--- a/lib/ssl/test/ssl_bench_SUITE.erl
+++ b/lib/ssl/test/ssl_bench_SUITE.erl
@@ -174,7 +174,12 @@ do_test(Type, TC, Loop, ParallellConnections, Server) ->
end,
{TimeInMicro, _} = timer:tc(Run),
TotalTests = ParallellConnections * Loop,
- TestPerSecond = 1000000 * TotalTests div TimeInMicro,
+ TestPerSecond = case TimeInMicro of
+ 0 ->
+ undefined;
+ _ ->
+ 1000000 * TotalTests div TimeInMicro
+ end,
io:format("TC ~p ~p ~p ~p 1/s~n", [TC, Type, ParallellConnections, TestPerSecond]),
unlink(SPid),
SPid ! quit,
diff --git a/lib/ssl/test/ssl_cert_SUITE.erl b/lib/ssl/test/ssl_cert_SUITE.erl
new file mode 100644
index 0000000000..571e7428ea
--- /dev/null
+++ b/lib/ssl/test/ssl_cert_SUITE.erl
@@ -0,0 +1,547 @@
+%%
+%% %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_cert_SUITE).
+
+%% Note: This directive should only be used in test suites.
+-compile(export_all).
+-include_lib("common_test/include/ct.hrl").
+-include_lib("public_key/include/public_key.hrl").
+
+%%--------------------------------------------------------------------
+%% Common Test interface functions -----------------------------------
+%%--------------------------------------------------------------------
+
+all() ->
+ [
+ {group, 'tlsv1.3'},
+ {group, 'tlsv1.2'},
+ {group, 'tlsv1.1'},
+ {group, 'tlsv1'},
+ {group, 'sslv3'},
+ {group, 'dtlsv1.2'},
+ {group, 'dtlsv1'}
+ ].
+
+groups() ->
+ [
+ {'tlsv1.3', [], tls_1_3_protocol_groups()},
+ {'tlsv1.2', [], pre_tls_1_3_protocol_groups()},
+ {'tlsv1.1', [], pre_tls_1_3_protocol_groups()},
+ {'tlsv1', [], pre_tls_1_3_protocol_groups()},
+ {'sslv3', [], ssl_protocol_groups()},
+ {'dtlsv1.2', [], pre_tls_1_3_protocol_groups()},
+ {'dtlsv1', [], pre_tls_1_3_protocol_groups()},
+ {rsa, [], all_version_tests()},
+ {ecdsa, [], all_version_tests()},
+ {dsa, [], all_version_tests()},
+ {rsa_1_3, [], all_version_tests() ++ tls_1_3_tests() ++ [unsupported_sign_algo_cert_client_auth]},
+ {ecdsa_1_3, [], all_version_tests() ++ tls_1_3_tests()}
+ ].
+
+ssl_protocol_groups() ->
+ [{group, rsa},
+ {group, dsa}].
+
+pre_tls_1_3_protocol_groups() ->
+ [{group, rsa},
+ {group, ecdsa},
+ {group, dsa}].
+
+tls_1_3_protocol_groups() ->
+ [{group, rsa_1_3},
+ {group, ecdsa_1_3}].
+
+tls_1_3_tests() ->
+ [
+ hello_retry_request,
+ custom_groups,
+ hello_retry_client_auth,
+ hello_retry_client_auth_empty_cert_accepted,
+ hello_retry_client_auth_empty_cert_rejected
+ ].
+
+all_version_tests() ->
+ [
+ no_auth,
+ auth,
+ client_auth_empty_cert_accepted,
+ client_auth_empty_cert_rejected,
+ client_auth_partial_chain,
+ client_auth_allow_partial_chain,
+ client_auth_do_not_allow_partial_chain,
+ client_auth_partial_chain_fun_fail,
+ missing_root_cert_no_auth,
+ missing_root_cert_auth,
+ missing_root_cert_auth_user_verify_fun_accept,
+ missing_root_cert_auth_user_verify_fun_reject,
+ verify_fun_always_run_client,
+ verify_fun_always_run_server,
+ incomplete_chain_auth
+ %%invalid_signature_client
+ ].
+
+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:unload(ssl),
+ application:stop(crypto).
+
+init_per_group(Group, Config0) when Group == rsa;
+ Group == rsa_1_3 ->
+ Config = ssl_test_lib:make_rsa_cert(Config0),
+ COpts = proplists:get_value(client_rsa_opts, Config),
+ SOpts = proplists:get_value(server_rsa_opts, Config),
+ [{cert_key_alg, rsa} |
+ lists:delete(cert_key_alg,
+ [{client_cert_opts, COpts},
+ {server_cert_opts, SOpts} |
+ lists:delete(server_cert_opts,
+ lists:delete(client_cert_opts, Config))])];
+init_per_group(Group, Config0) when Group == ecdsa;
+ Group == ecdsa_1_3 ->
+
+ PKAlg = crypto:supports(public_keys),
+ case lists:member(ecdsa, PKAlg) andalso (lists:member(ecdh, PKAlg) orelse lists:member(dh, PKAlg)) of
+ true ->
+ Config = ssl_test_lib:make_ecdsa_cert(Config0),
+ COpts = proplists:get_value(client_ecdsa_opts, Config),
+ SOpts = proplists:get_value(server_ecdsa_opts, Config),
+ [{cert_key_alg, ecdsa} |
+ lists:delete(cert_key_alg,
+ [{client_cert_opts, COpts},
+ {server_cert_opts, SOpts} |
+ lists:delete(server_cert_opts,
+ lists:delete(client_cert_opts, Config))]
+ )];
+ false ->
+ {skip, "Missing EC crypto support"}
+ end;
+
+init_per_group(Group, Config0) when Group == dsa ->
+ PKAlg = crypto:supports(public_keys),
+ case lists:member(dss, PKAlg) andalso lists:member(dh, PKAlg) of
+ true ->
+ Config = ssl_test_lib:make_dsa_cert(Config0),
+ COpts = proplists:get_value(client_dsa_opts, Config),
+ SOpts = proplists:get_value(server_dsa_opts, Config),
+ [{cert_key_alg, dsa} |
+ lists:delete(cert_key_alg,
+ [{client_cert_opts, COpts},
+ {server_cert_opts, SOpts} |
+ lists:delete(server_cert_opts,
+ lists:delete(client_cert_opts, Config))])];
+ false ->
+ {skip, "Missing DSS crypto support"}
+ end;
+init_per_group(GroupName, Config) ->
+ case ssl_test_lib:is_tls_version(GroupName) of
+ true ->
+ case ssl_test_lib:sufficient_crypto_support(GroupName) of
+ true ->
+ [{client_type, erlang},
+ {server_type, erlang}, {version, GroupName}
+ | ssl_test_lib:init_tls_version(GroupName, Config)];
+ false ->
+ {skip, "Missing crypto support"}
+ end;
+ _ ->
+ ssl:start(),
+ Config
+ 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) ->
+ ssl_test_lib:ct_log_supported_protocol_versions(Config),
+ ct:timetrap({seconds, 10}),
+ Config.
+
+end_per_testcase(_TestCase, Config) ->
+ Config.
+
+%%--------------------------------------------------------------------
+%% Test Cases --------------------------------------------------------
+%%--------------------------------------------------------------------
+no_auth() ->
+ ssl_cert_tests:no_auth().
+
+no_auth(Config) ->
+ ssl_cert_tests:no_auth(Config).
+%%--------------------------------------------------------------------
+auth() ->
+ ssl_cert_tests:auth().
+auth(Config) ->
+ ssl_cert_tests:auth(Config).
+%%--------------------------------------------------------------------
+client_auth_empty_cert_accepted() ->
+ ssl_cert_tests:client_auth_empty_cert_accepted().
+client_auth_empty_cert_accepted(Config) ->
+ ssl_cert_tests:client_auth_empty_cert_accepted(Config).
+%%--------------------------------------------------------------------
+client_auth_empty_cert_rejected() ->
+ ssl_cert_tests:client_auth_empty_cert_rejected().
+client_auth_empty_cert_rejected(Config) ->
+ ssl_cert_tests:client_auth_empty_cert_rejected(Config).
+%%--------------------------------------------------------------------
+client_auth_partial_chain() ->
+ ssl_cert_tests:client_auth_partial_chain().
+client_auth_partial_chain(Config) when is_list(Config) ->
+ ssl_cert_tests:client_auth_partial_chain(Config).
+
+%%--------------------------------------------------------------------
+client_auth_allow_partial_chain() ->
+ ssl_cert_tests:client_auth_allow_partial_chain().
+client_auth_allow_partial_chain(Config) when is_list(Config) ->
+ ssl_cert_tests:client_auth_allow_partial_chain(Config).
+%%--------------------------------------------------------------------
+client_auth_do_not_allow_partial_chain() ->
+ ssl_cert_tests:client_auth_do_not_allow_partial_chain().
+client_auth_do_not_allow_partial_chain(Config) when is_list(Config) ->
+ ssl_cert_tests:client_auth_do_not_allow_partial_chain(Config).
+
+%%--------------------------------------------------------------------
+client_auth_partial_chain_fun_fail() ->
+ ssl_cert_tests:client_auth_partial_chain_fun_fail().
+client_auth_partial_chain_fun_fail(Config) when is_list(Config) ->
+ ssl_cert_tests:client_auth_partial_chain_fun_fail(Config).
+
+
+%%--------------------------------------------------------------------
+missing_root_cert_no_auth() ->
+ ssl_cert_tests:missing_root_cert_no_auth().
+missing_root_cert_no_auth(Config) when is_list(Config) ->
+ ssl_cert_tests:missing_root_cert_no_auth(Config).
+
+%%--------------------------------------------------------------------
+missing_root_cert_auth() ->
+ [{doc,"Must have ROOT certs to be able to verify verify peer"}].
+missing_root_cert_auth(Config) when is_list(Config) ->
+ ServerOpts = proplists:delete(cacertfile, ssl_test_lib:ssl_options(server_cert_opts, Config)),
+ {ClientNode, ServerNode, _} = ssl_test_lib:run_where(Config),
+ Server = ssl_test_lib:start_server_error([{node, ServerNode}, {port, 0},
+ {from, self()},
+ {options, [{verify, verify_peer}
+ | ServerOpts]}]),
+
+ ssl_test_lib:check_result(Server, {error, {options, {cacertfile, ""}}}),
+
+ ClientOpts = proplists:delete(cacertfile, ssl_test_lib:ssl_options(client_cert_opts, Config)),
+ Client = ssl_test_lib:start_client_error([{node, ClientNode}, {port, 0},
+ {from, self()},
+ {options, [{verify, verify_peer}
+ | ClientOpts]}]),
+
+ ssl_test_lib:check_result(Client, {error, {options, {cacertfile, ""}}}).
+
+%%--------------------------------------------------------------------
+missing_root_cert_auth_user_verify_fun_accept() ->
+ [{doc, "Test that the client succeds if the ROOT CA is unknown in verify_peer mode"
+ " with a verify_fun that accepts the unknown CA error"}].
+
+missing_root_cert_auth_user_verify_fun_accept(Config) ->
+ ServerOpts = ssl_test_lib:ssl_options(server_cert_opts, Config),
+ FunAndState = {fun(_,{bad_cert, unknown_ca}, UserState) ->
+ {valid, UserState};
+ (_,{bad_cert, _} = Reason, _) ->
+ {fail, Reason};
+ (_,{extension, _}, UserState) ->
+ {unknown, UserState};
+ (_, valid, UserState) ->
+ {valid, UserState};
+ (_, valid_peer, UserState) ->
+ {valid, UserState}
+ end, []},
+ ClientOpts = ssl_test_lib:ssl_options([{verify, verify_peer},
+ {verify_fun, FunAndState}], Config),
+ ssl_test_lib:basic_test(ClientOpts, ServerOpts, Config).
+
+%%--------------------------------------------------------------------
+missing_root_cert_auth_user_backwardscompatibility_verify_fun_accept() ->
+ [{doc, "Test old style verify fun"}].
+
+missing_root_cert_auth_user_backwardscompatibility_verify_fun_accept(Config) ->
+ ServerOpts = ssl_test_lib:ssl_options(server_cert_opts, Config),
+ AcceptBadCa = fun({bad_cert,unknown_ca}, Acc) -> Acc;
+ (Other, Acc) -> [Other | Acc]
+ end,
+ VerifyFun =
+ fun(ErrorList) ->
+ case lists:foldl(AcceptBadCa, [], ErrorList) of
+ [] -> true;
+ [_|_] -> false
+ end
+ end,
+
+ ClientOpts = ssl_test_lib:ssl_options([{verify, verify_peer},
+ {verify_fun, VerifyFun}], Config),
+ ssl_test_lib:basic_test(ClientOpts, ServerOpts, Config).
+
+%%--------------------------------------------------------------------
+missing_root_cert_auth_user_verify_fun_reject() ->
+ [{doc, "Test that the client fails if the ROOT CA is unknown in verify_peer mode"
+ " with a verify_fun that rejects the unknown CA error"}].
+
+missing_root_cert_auth_user_verify_fun_reject(Config) ->
+ ServerOpts = ssl_test_lib:ssl_options(server_cert_opts, Config),
+ FunAndState = {fun(_,{bad_cert, unknown_ca} = Reason, _UserState) ->
+ {fail, Reason};
+ (_,{bad_cert, _} = Reason, _) ->
+ {fail, Reason};
+ (_,{extension, UserState}, _) ->
+ {unknown, UserState};
+ (_, valid, UserState) ->
+ {valid, UserState};
+ (_, valid_peer, UserState) ->
+ {valid, UserState}
+ end, []},
+ ClientOpts = ssl_test_lib:ssl_options([{verify, verify_peer},
+ {verify_fun, FunAndState}], Config),
+ ssl_test_lib:basic_alert(ClientOpts, ServerOpts, Config, unknown_ca).
+%%--------------------------------------------------------------------
+incomplete_chain_auth() ->
+ [{doc,"Test that we can verify an incompleat chain when we have the certs to rebuild it"}].
+incomplete_chain_auth(Config) when is_list(Config) ->
+ DefaultCertConf = ssl_test_lib:default_cert_chain_conf(),
+ #{client_config := ClientOpts0,
+ server_config := ServerOpts0} = ssl_test_lib:make_cert_chains_der(proplists:get_value(cert_key_alg, Config),
+ [{server_chain, DefaultCertConf},
+ {client_chain, DefaultCertConf}]),
+ [ServerRoot| _] = ServerCas = proplists:get_value(cacerts, ServerOpts0),
+ ClientCas = proplists:get_value(cacerts, ClientOpts0),
+ ClientOpts = ssl_test_lib:ssl_options([{verify, verify_peer},
+ {cacerts, ServerCas ++ ClientCas} |
+ proplists:delete(cacerts, ClientOpts0)], Config),
+ ServerOpts = ssl_test_lib:ssl_options([{verify, verify_peer},
+ {cacerts, [ServerRoot]} |
+ proplists:delete(cacerts, ServerOpts0)], Config),
+ ssl_test_lib:basic_test(ClientOpts, ServerOpts, Config).
+
+%%--------------------------------------------------------------------
+verify_fun_always_run_client() ->
+ [{doc,"Verify that user verify_fun is always run (for valid and valid_peer not only unknown_extension)"}].
+
+verify_fun_always_run_client(Config) when is_list(Config) ->
+ ClientOpts = ssl_test_lib:ssl_options(client_cert_opts, Config),
+ ServerOpts = ssl_test_lib:ssl_options(server_cert_opts, Config),
+ {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
+ Server = ssl_test_lib:start_server_error([{node, ServerNode}, {port, 0},
+ {from, self()},
+ {mfa, {ssl_test_lib,
+ no_result, []}},
+ {options, ServerOpts}]),
+ Port = ssl_test_lib:inet_port(Server),
+
+ %% If user verify fun is called correctly we fail the connection.
+ %% otherwise we cannot tell this case apart form where we miss
+ %% to call users verify fun
+ FunAndState = {fun(_,{extension, _}, UserState) ->
+ {unknown, UserState};
+ (_, valid, [ChainLen]) ->
+ {valid, [ChainLen + 1]};
+ (_, valid_peer, [1]) ->
+ {fail, "verify_fun_was_always_run"};
+ (_, valid_peer, UserState) ->
+ {valid, UserState}
+ end, [0]},
+
+ Client = ssl_test_lib:start_client_error([{node, ClientNode}, {port, Port},
+ {host, Hostname},
+ {from, self()},
+ {mfa, {ssl_test_lib,
+ no_result, []}},
+ {options,
+ [{verify, verify_peer},
+ {verify_fun, FunAndState}
+ | ClientOpts]}]),
+
+ ssl_test_lib:check_client_alert(Server, Client, handshake_failure).
+
+%%--------------------------------------------------------------------
+verify_fun_always_run_server() ->
+ [{doc,"Verify that user verify_fun is always run (for valid and valid_peer not only unknown_extension)"}].
+verify_fun_always_run_server(Config) when is_list(Config) ->
+ ClientOpts = ssl_test_lib:ssl_options(client_cert_opts, Config),
+ ServerOpts = ssl_test_lib:ssl_options(server_cert_opts, Config),
+ {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
+
+ %% If user verify fun is called correctly we fail the connection.
+ %% otherwise we cannot tell this case apart form where we miss
+ %% to call users verify fun
+ FunAndState = {fun(_,{extension, _}, UserState) ->
+ {unknown, UserState};
+ (_, valid, [ChainLen]) ->
+ {valid, [ChainLen + 1]};
+ (_, valid_peer, [1]) ->
+ {fail, "verify_fun_was_always_run"};
+ (_, valid_peer, UserState) ->
+ {valid, UserState}
+ end, [0]},
+
+ Server = ssl_test_lib:start_server_error([{node, ServerNode}, {port, 0},
+ {from, self()},
+ {mfa, {ssl_test_lib,
+ no_result, []}},
+ {options,
+ [{verify, verify_peer},
+ {verify_fun, FunAndState} |
+ ServerOpts]}]),
+ Port = ssl_test_lib:inet_port(Server),
+
+ Client = ssl_test_lib:start_client_error([{node, ClientNode}, {port, Port},
+ {host, Hostname},
+ {from, self()},
+ {mfa, {ssl_test_lib,
+ no_result, []}},
+ {options, ClientOpts}]),
+
+ ssl_test_lib:check_client_alert(Server, Client, handshake_failure).
+
+%%--------------------------------------------------------------------
+invalid_signature_client() ->
+ ssl_cert_tests:invalid_signature_client().
+invalid_signature_client(Config) when is_list(Config) ->
+ ssl_cert_tests:invalid_signature_client(Config).
+%%--------------------------------------------------------------------
+invalid_signature_server() ->
+ ssl_cert_tests:invalid_signature_client().
+invalid_signature_server(Config) when is_list(Config) ->
+ ssl_cert_tests:invalid_signature_client(Config).
+
+%%--------------------------------------------------------------------
+%% TLS 1.3 Test cases -----------------------------------------------
+%%--------------------------------------------------------------------
+hello_retry_request() ->
+ [{doc,"Test that ssl server can request a new group when the client's first key share"
+ "is not supported"}].
+
+hello_retry_request(Config) ->
+ ClientOpts0 = ssl_test_lib:ssl_options(client_cert_opts, Config),
+ ServerOpts0 = ssl_test_lib:ssl_options(server_cert_opts, Config),
+ ServerOpts = [{versions, ['tlsv1.2','tlsv1.3']},
+ {supported_groups, [x448, x25519]}|ServerOpts0],
+ ClientOpts = [{versions, ['tlsv1.2','tlsv1.3']},
+ {supported_groups, [secp256r1, x25519]}|ClientOpts0],
+ ssl_test_lib:basic_test(ClientOpts, ServerOpts, Config).
+%%--------------------------------------------------------------------
+custom_groups() ->
+ [{doc,"Test that ssl server can select a common group for key-exchange"}].
+
+custom_groups(Config) ->
+ ClientOpts0 = ssl_test_lib:ssl_options(client_cert_opts, Config),
+ ServerOpts0 = ssl_test_lib:ssl_options(server_cert_opts, Config),
+
+ %% Set versions
+ ServerOpts = [{versions, ['tlsv1.2','tlsv1.3']},
+ {supported_groups, [x448, secp256r1, secp384r1]}|ServerOpts0],
+ ClientOpts1 = [{versions, ['tlsv1.2','tlsv1.3']}|ClientOpts0],
+ ClientOpts = [{supported_groups,[secp384r1, secp256r1, x25519]}|ClientOpts1],
+ ssl_test_lib:basic_test(ClientOpts, ServerOpts, Config).
+
+%%--------------------------------------------------------------------
+%% Triggers a Server Alert as ssl client does not have a certificate with a
+%% signature algorithm supported by the server (signature_algorithms_cert extension
+%% of CertificateRequest does not contain the algorithm of the client certificate).
+%% ssl client sends an empty certificate.
+unsupported_sign_algo_cert_client_auth() ->
+ [{doc,"TLS 1.3: Test client authentication with unsupported signature_algorithm_cert"}].
+
+unsupported_sign_algo_cert_client_auth(Config) ->
+ ClientOpts0 = ssl_test_lib:ssl_options(client_cert_opts, Config),
+ ServerOpts0 = ssl_test_lib:ssl_options(server_cert_opts, Config),
+ ServerOpts = [{versions, ['tlsv1.2','tlsv1.3']},
+ {verify, verify_peer},
+ %% Skip rsa_pkcs1_sha256!
+ {signature_algs, [rsa_pkcs1_sha384, rsa_pss_rsae_sha256]},
+ {fail_if_no_peer_cert, true}|ServerOpts0],
+ ClientOpts = [{versions, ['tlsv1.2','tlsv1.3']}|ClientOpts0],
+ ssl_test_lib:basic_alert(ClientOpts, ServerOpts, Config, handshake_failure).
+%%--------------------------------------------------------------------
+hello_retry_client_auth() ->
+ [{doc, "TLS 1.3 (HelloRetryRequest): Test client authentication."}].
+
+hello_retry_client_auth(Config) ->
+ ClientOpts0 = ssl_test_lib:ssl_options(client_cert_opts, Config),
+ ServerOpts0 = ssl_test_lib:ssl_options(server_cert_opts, Config),
+ ServerOpts1 = [{versions, ['tlsv1.2','tlsv1.3']},
+ {supported_groups, [x448, x25519]}|ServerOpts0],
+ ClientOpts = [{versions, ['tlsv1.2','tlsv1.3']},
+ {supported_groups, [secp256r1, x25519]}|ClientOpts0],
+ ServerOpts = [{verify, verify_peer},
+ {fail_if_no_peer_cert, true} | ServerOpts1],
+
+ ssl_test_lib:basic_test(ClientOpts, ServerOpts, Config).
+%%--------------------------------------------------------------------
+hello_retry_client_auth_empty_cert_accepted() ->
+ [{doc,"TLS 1.3 (HelloRetryRequest): Test client authentication when client sends an empty "
+ "certificate and fail_if_no_peer_cert is set to true."}].
+
+hello_retry_client_auth_empty_cert_accepted(Config) ->
+ ClientOpts0 = ssl_test_lib:ssl_options(client_cert_opts, Config),
+ %% Delete Client Cert and Key
+ ClientOpts1 = proplists:delete(certfile, ClientOpts0),
+ ClientOpts2 = proplists:delete(keyfile, ClientOpts1),
+
+ ServerOpts0 = ssl_test_lib:ssl_options(server_cert_opts, Config),
+ %% Set versions
+ ServerOpts = [{versions, ['tlsv1.2','tlsv1.3']},
+ {verify, verify_peer},
+ {fail_if_no_peer_cert, false},
+ {supported_groups, [x448, x25519]}|ServerOpts0],
+ ClientOpts = [{versions, ['tlsv1.2','tlsv1.3']},
+ {supported_groups, [secp256r1, x25519]}|ClientOpts2],
+ ssl_test_lib:basic_test(ClientOpts, ServerOpts, Config).
+%%--------------------------------------------------------------------
+hello_retry_client_auth_empty_cert_rejected() ->
+ [{doc,"TLS 1.3 (HelloRetryRequest): Test client authentication when client "
+ "sends an empty certificate and fail_if_no_peer_cert is set to true."}].
+
+hello_retry_client_auth_empty_cert_rejected(Config) ->
+ ClientOpts0 = ssl_test_lib:ssl_options(client_cert_opts, Config),
+ %% Delete Client Cert and Key
+ ClientOpts1 = proplists:delete(certfile, ClientOpts0),
+ ClientOpts2 = proplists:delete(keyfile, ClientOpts1),
+
+ ServerOpts0 = ssl_test_lib:ssl_options(server_cert_opts, Config),
+ %% Set versions
+ ServerOpts = [{versions, ['tlsv1.2','tlsv1.3']},
+ {verify, verify_peer},
+ {fail_if_no_peer_cert, true},
+ {supported_groups, [x448, x25519]}|ServerOpts0],
+ ClientOpts = [{versions, ['tlsv1.2','tlsv1.3']},
+ {supported_groups, [secp256r1, x25519]}|ClientOpts2],
+
+ ssl_test_lib:basic_alert(ClientOpts, ServerOpts, Config, certificate_required).
diff --git a/lib/ssl/test/ssl_cert_tests.erl b/lib/ssl/test/ssl_cert_tests.erl
new file mode 100644
index 0000000000..1c73dac3f9
--- /dev/null
+++ b/lib/ssl/test/ssl_cert_tests.erl
@@ -0,0 +1,371 @@
+%%
+%% %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_cert_tests).
+
+%% Note: This directive should only be used in test suites.
+-compile(export_all).
+
+-include_lib("public_key/include/public_key.hrl").
+
+%%--------------------------------------------------------------------
+%% Test Cases --------------------------------------------------------
+%%--------------------------------------------------------------------
+
+no_auth() ->
+ [{doc,"Test connection without authentication"}].
+
+no_auth(Config) ->
+ ClientOpts = [{verify, verify_none} | ssl_test_lib:ssl_options(client_cert_opts, Config)],
+ ServerOpts = [{verify, verify_none} | ssl_test_lib:ssl_options(server_cert_opts, Config)],
+
+ ssl_test_lib:basic_test(ClientOpts, ServerOpts, Config).
+%%--------------------------------------------------------------------
+auth() ->
+ [{doc,"Test connection with mutual authentication"}].
+
+auth(Config) ->
+ ClientOpts = [{verify, verify_peer} | ssl_test_lib:ssl_options(client_cert_opts, Config)],
+ ServerOpts = [{verify, verify_peer} | ssl_test_lib:ssl_options(server_cert_opts, Config)],
+
+ ssl_test_lib:basic_test(ClientOpts, ServerOpts, Config).
+
+%%--------------------------------------------------------------------
+client_auth_empty_cert_accepted() ->
+ [{doc,"Test client authentication when client sends an empty certificate and "
+ "fail_if_no_peer_cert is set to false."}].
+
+client_auth_empty_cert_accepted(Config) ->
+ ClientOpts = proplists:delete(keyfile,
+ proplists:delete(certfile,
+ ssl_test_lib:ssl_options(client_cert_opts, Config))),
+ ServerOpts0 = ssl_test_lib:ssl_options(server_cert_opts, Config),
+ ServerOpts = [{verify, verify_peer},
+ {fail_if_no_peer_cert, false} | ServerOpts0],
+ ssl_test_lib:basic_test(ClientOpts, ServerOpts, Config).
+%%--------------------------------------------------------------------
+client_auth_empty_cert_rejected() ->
+ [{doc,"Test client authentication when client sends an empty certificate and "
+ "fail_if_no_peer_cert is set to true."}].
+
+client_auth_empty_cert_rejected(Config) ->
+ ServerOpts = [{verify, verify_peer}, {fail_if_no_peer_cert, true}
+ | ssl_test_lib:ssl_options(server_cert_opts, Config)],
+ ClientOpts0 = ssl_test_lib:ssl_options([], Config),
+ %% Delete Client Cert and Key
+ ClientOpts1 = proplists:delete(certfile, ClientOpts0),
+ ClientOpts = proplists:delete(keyfile, ClientOpts1),
+
+ Version = proplists:get_value(version,Config),
+ case Version of
+ 'tlsv1.3' ->
+ ssl_test_lib:basic_alert(ClientOpts, ServerOpts, Config, certificate_required);
+ _ ->
+ ssl_test_lib:basic_alert(ClientOpts, ServerOpts, Config, handshake_failure)
+ end.
+%%--------------------------------------------------------------------
+client_auth_partial_chain() ->
+ [{doc, "Client sends an incompleate chain, by default not acceptable."}].
+
+client_auth_partial_chain(Config) when is_list(Config) ->
+ ServerOpts = [{verify, verify_peer}, {fail_if_no_peer_cert, true}
+ | ssl_test_lib:ssl_options(server_cert_opts, Config)],
+ ClientOpts0 = ssl_test_lib:ssl_options(client_cert_opts, Config),
+ {ok, ClientCAs} = file:read_file(proplists:get_value(cacertfile, ClientOpts0)),
+ [{_,RootCA,_} | _] = public_key:pem_decode(ClientCAs),
+ ClientOpts = [{cacerts, [RootCA]} |
+ proplists:delete(cacertfile, ClientOpts0)],
+ ssl_test_lib:basic_alert(ClientOpts, ServerOpts, Config, unknown_ca).
+
+%%--------------------------------------------------------------------
+client_auth_allow_partial_chain() ->
+ [{doc, "Server trusts intermediat CA and accepts a partial chain. (partial_chain option)"}].
+
+client_auth_allow_partial_chain(Config) when is_list(Config) ->
+ ServerOpts0 = [{verify, verify_peer}, {fail_if_no_peer_cert, true}
+ | ssl_test_lib:ssl_options(server_cert_opts, Config)],
+ ClientOpts = ssl_test_lib:ssl_options(client_cert_opts, Config),
+ {ok, ClientCAs} = file:read_file(proplists:get_value(cacertfile, ClientOpts)),
+ [{_,_,_}, {_, IntermidiateCA, _} | _] = public_key:pem_decode(ClientCAs),
+
+ PartialChain = fun(CertChain) ->
+ case lists:member(IntermidiateCA, CertChain) of
+ true ->
+ {trusted_ca, IntermidiateCA};
+ false ->
+ unknown_ca
+ end
+ end,
+ ServerOpts = [{cacerts, [IntermidiateCA]},
+ {partial_chain, PartialChain} |
+ proplists:delete(cacertfile, ServerOpts0)],
+
+ ssl_test_lib:basic_test(ClientOpts, ServerOpts, Config).
+
+ %%--------------------------------------------------------------------
+client_auth_do_not_allow_partial_chain() ->
+ [{doc, "Server does not accept the chain sent by the client as ROOT CA is unkown, "
+ "and we do not choose to trust the intermediate CA. (partial_chain option)"}].
+
+client_auth_do_not_allow_partial_chain(Config) when is_list(Config) ->
+ ServerOpts0 = [{verify, verify_peer}, {fail_if_no_peer_cert, true}
+ | ssl_test_lib:ssl_options(server_cert_opts, Config)],
+ ClientOpts = ssl_test_lib:ssl_options(client_cert_opts, Config),
+ {ok, ServerCAs} = file:read_file(proplists:get_value(cacertfile, ServerOpts0)),
+ [{_,_,_}, {_, IntermidiateCA, _} | _] = public_key:pem_decode(ServerCAs),
+
+ PartialChain = fun(_CertChain) ->
+ unknown_ca
+ end,
+ ServerOpts = [{cacerts, [IntermidiateCA]},
+ {partial_chain, PartialChain} |
+ proplists:delete(cacertfile, ServerOpts0)],
+ ssl_test_lib:basic_alert(ClientOpts, ServerOpts, Config, unknown_ca).
+
+ %%--------------------------------------------------------------------
+client_auth_partial_chain_fun_fail() ->
+ [{doc, "If parial_chain fun crashes, treat it as if it returned unkown_ca"}].
+
+client_auth_partial_chain_fun_fail(Config) when is_list(Config) ->
+ ServerOpts0 = [{verify, verify_peer}, {fail_if_no_peer_cert, true}
+ | ssl_test_lib:ssl_options(server_cert_opts, Config)],
+ ClientOpts = ssl_test_lib:ssl_options(client_cert_opts, Config),
+
+ {ok, ServerCAs} = file:read_file(proplists:get_value(cacertfile, ServerOpts0)),
+ [{_,_,_}, {_, IntermidiateCA, _} | _] = public_key:pem_decode(ServerCAs),
+
+ PartialChain = fun(_CertChain) ->
+ true = false %% crash on purpose
+ end,
+ ServerOpts = [{cacerts, [IntermidiateCA]},
+ {partial_chain, PartialChain} |
+ proplists:delete(cacertfile, ServerOpts0)],
+
+ ssl_test_lib:basic_alert(ClientOpts, ServerOpts, Config, unknown_ca).
+
+%%--------------------------------------------------------------------
+missing_root_cert_no_auth() ->
+ [{doc,"Test that the client succeds if the ROOT CA is unknown in verify_none mode"}].
+
+missing_root_cert_no_auth(Config) ->
+ ClientOpts = [{verify, verify_none} | ssl_test_lib:ssl_options(client_cert_opts, Config)],
+ ServerOpts = [{verify, verify_none} | ssl_test_lib:ssl_options(server_cert_opts, Config)],
+
+ ssl_test_lib:basic_test(ClientOpts, ServerOpts, Config).
+
+%%--------------------------------------------------------------------
+invalid_signature_client() ->
+ [{doc,"Test server with invalid signature"}].
+
+invalid_signature_client(Config) when is_list(Config) ->
+ ClientOpts0 = ssl_test_lib:ssl_options(client_cert_opts, Config),
+ ServerOpts0 = ssl_test_lib:ssl_options(server_cert_opts, Config),
+ PrivDir = proplists:get_value(priv_dir, Config),
+
+ KeyFile = proplists:get_value(keyfile, ClientOpts0),
+ [KeyEntry] = ssl_test_lib:pem_to_der(KeyFile),
+ Key = ssl_test_lib:public_key(public_key:pem_entry_decode(KeyEntry)),
+
+ ClientCertFile = proplists:get_value(certfile, ClientOpts0),
+ NewClientCertFile = filename:join(PrivDir, "client_invalid_cert.pem"),
+ [{'Certificate', ClientDerCert, _}] = ssl_test_lib:pem_to_der(ClientCertFile),
+ ClientOTPCert = public_key:pkix_decode_cert(ClientDerCert, otp),
+ ClientOTPTbsCert = ClientOTPCert#'OTPCertificate'.tbsCertificate,
+ NewClientDerCert = public_key:pkix_sign(ClientOTPTbsCert, Key),
+ ssl_test_lib:der_to_pem(NewClientCertFile, [{'Certificate', NewClientDerCert, not_encrypted}]),
+ ClientOpts = [{certfile, NewClientCertFile} | proplists:delete(certfile, ClientOpts0)],
+ ServerOpts = [{verify, verify_peer} | ServerOpts0],
+ ssl_test_lib:basic_alert(ClientOpts, ServerOpts, Config, unknown_ca).
+
+%%--------------------------------------------------------------------
+invalid_signature_server() ->
+ [{doc,"Test client with invalid signature"}].
+
+invalid_signature_server(Config) when is_list(Config) ->
+ ClientOpts0 = ssl_test_lib:ssl_options(client_cert_opts, Config),
+ ServerOpts0 = ssl_test_lib:ssl_options(server_cert_opts, Config),
+ PrivDir = proplists:get_value(priv_dir, Config),
+
+ KeyFile = proplists:get_value(keyfile, ServerOpts0),
+ [KeyEntry] = ssl_test_lib:pem_to_der(KeyFile),
+ Key = ssl_test_lib:public_key(public_key:pem_entry_decode(KeyEntry)),
+
+ ServerCertFile = proplists:get_value(certfile, ServerOpts0),
+ NewServerCertFile = filename:join(PrivDir, "server_invalid_cert.pem"),
+ [{'Certificate', ServerDerCert, _}] = ssl_test_lib:pem_to_der(ServerCertFile),
+ ServerOTPCert = public_key:pkix_decode_cert(ServerDerCert, otp),
+ ServerOTPTbsCert = ServerOTPCert#'OTPCertificate'.tbsCertificate,
+ NewServerDerCert = public_key:pkix_sign(ServerOTPTbsCert, Key),
+ ssl_test_lib:der_to_pem(NewServerCertFile, [{'Certificate', NewServerDerCert, not_encrypted}]),
+ ServerOpts = [{certfile, NewServerCertFile} | proplists:delete(certfile, ServerOpts0)],
+ ClientOpts = [{verify, verify_peer} | ClientOpts0],
+ ssl_test_lib:basic_alert(ClientOpts, ServerOpts, Config, unknown_ca).
+
+%%--------------------------------------------------------------------
+%% TLS 1.3 Test Cases --------------------------------------------------------
+%%--------------------------------------------------------------------
+hello_retry_request() ->
+ [{doc,"Test that ssl server can request a new group when the client's first key share"
+ "is not supported"}].
+
+hello_retry_request(Config) ->
+ ClientOpts0 = ssl_test_lib:ssl_options(client_cert_opts, Config),
+ ServerOpts0 = ssl_test_lib:ssl_options(server_cert_opts, Config),
+
+ {ServerOpts, ClientOpts} = group_config(Config,
+ [{versions, ['tlsv1.2','tlsv1.3']} | ServerOpts0],
+ [{versions, ['tlsv1.2','tlsv1.3']} | ClientOpts0]),
+
+ ssl_test_lib:basic_test(ClientOpts, ServerOpts, Config).
+%%--------------------------------------------------------------------
+custom_groups() ->
+ [{doc,"Test that ssl server can select a common group for key-exchange"}].
+
+custom_groups(Config) ->
+ ClientOpts0 = ssl_test_lib:ssl_options(client_cert_opts, Config),
+ ServerOpts0 = ssl_test_lib:ssl_options(server_cert_opts, Config),
+
+ {ServerOpts, ClientOpts} = group_config_custom(Config,
+ [{versions, ['tlsv1.2','tlsv1.3']} | ServerOpts0],
+ [{versions, ['tlsv1.2','tlsv1.3']} | ClientOpts0]),
+
+ ssl_test_lib:basic_test(ClientOpts, ServerOpts, Config).
+
+%%--------------------------------------------------------------------
+%% Triggers a Server Alert as ssl client does not have a certificate with a
+%% signature algorithm supported by the server (signature_algorithms_cert extension
+%% of CertificateRequest does not contain the algorithm of the client certificate).
+%% ssl client sends an empty certificate.
+unsupported_sign_algo_cert_client_auth() ->
+ [{doc,"TLS 1.3: Test client authentication with unsupported signature_algorithm_cert"}].
+
+unsupported_sign_algo_cert_client_auth(Config) ->
+ ClientOpts0 = ssl_test_lib:ssl_options(client_cert_opts, Config),
+ ServerOpts0 = ssl_test_lib:ssl_options(server_cert_opts, Config),
+ ServerOpts = [{versions, ['tlsv1.2','tlsv1.3']},
+ {verify, verify_peer},
+ %% Skip rsa_pkcs1_sha256!
+ {signature_algs, [rsa_pkcs1_sha384, rsa_pss_rsae_sha256]},
+ {fail_if_no_peer_cert, true}|ServerOpts0],
+ ClientOpts = [{versions, ['tlsv1.2','tlsv1.3']}|ClientOpts0],
+ ssl_test_lib:basic_alert(ClientOpts, ServerOpts, Config, handshake_failure).
+%%--------------------------------------------------------------------
+hello_retry_client_auth() ->
+ [{doc, "TLS 1.3 (HelloRetryRequest): Test client authentication."}].
+
+hello_retry_client_auth(Config) ->
+ ClientOpts0 = ssl_test_lib:ssl_options(client_cert_opts, Config),
+ ServerOpts0 = ssl_test_lib:ssl_options(server_cert_opts, Config),
+
+ {ServerOpts, ClientOpts} = group_config(Config,
+ [{versions, ['tlsv1.2','tlsv1.3']},
+ {verify, verify_peer},
+ {fail_if_no_peer_cert, true} | ServerOpts0],
+ [{versions, ['tlsv1.2','tlsv1.3']}, {verify, verify_peer} | ClientOpts0]),
+
+ ssl_test_lib:basic_test(ClientOpts, ServerOpts, Config).
+%%--------------------------------------------------------------------
+hello_retry_client_auth_empty_cert_accepted() ->
+ [{doc,"TLS 1.3 (HelloRetryRequest): Test client authentication when client sends an empty "
+ "certificate and fail_if_no_peer_cert is set to false."}].
+
+hello_retry_client_auth_empty_cert_accepted(Config) ->
+ ClientOpts0 = proplists:delete(keyfile,
+ proplists:delete(certfile,
+ ssl_test_lib:ssl_options(client_cert_opts, Config))),
+ ServerOpts0 = ssl_test_lib:ssl_options(server_cert_opts, Config),
+
+ {ServerOpts, ClientOpts} = group_config(Config,
+ [{versions, ['tlsv1.2','tlsv1.3']},
+ {verify, verify_peer},
+ {fail_if_no_peer_cert, false} | ServerOpts0],
+ [{versions, ['tlsv1.2','tlsv1.3']}, {verify, verify_peer} | ClientOpts0]),
+
+ ssl_test_lib:basic_test(ClientOpts, ServerOpts, Config).
+%%--------------------------------------------------------------------
+hello_retry_client_auth_empty_cert_rejected() ->
+ [{doc,"TLS 1.3 (HelloRetryRequest): Test client authentication when client "
+ "sends an empty certificate and fail_if_no_peer_cert is set to true."}].
+
+hello_retry_client_auth_empty_cert_rejected(Config) ->
+ ClientOpts0 = proplists:delete(keyfile,
+ proplists:delete(certfile,
+ ssl_test_lib:ssl_options(client_cert_opts, Config))),
+ ServerOpts0 = ssl_test_lib:ssl_options(server_cert_opts, Config),
+
+ {ServerOpts, ClientOpts} = group_config(Config,
+ [{versions, ['tlsv1.2','tlsv1.3']},
+ {verify, verify_peer},
+ {fail_if_no_peer_cert, true} | ServerOpts0],
+ [{versions, ['tlsv1.2','tlsv1.3']}, {verify, verify_peer} | ClientOpts0]),
+
+ ssl_test_lib:basic_alert(ClientOpts, ServerOpts, Config, certificate_required).
+
+
+%%--------------------------------------------------------------------
+%% Internal functions -----------------------------------------------
+%%--------------------------------------------------------------------
+
+group_config_custom(Config, ServerOpts, ClientOpts) ->
+ case proplists:get_value(client_type, Config) of
+ erlang ->
+ {[{groups,"X448:P-256:P-384"} | ServerOpts],
+ [{supported_groups, [secp384r1, secp256r1, x25519]} | ClientOpts]};
+ openssl ->
+ {[{supported_groups, [x448, secp256r1, secp384r1]} | ServerOpts],
+ [{groups,"P-384:P-256:X25519"} | ClientOpts]}
+ end.
+
+group_config(Config, ServerOpts, ClientOpts) ->
+ case proplists:get_value(client_type, Config) of
+ erlang ->
+ {[{groups,"X448:X25519"} | ServerOpts],
+ [{supported_groups, [secp256r1, x25519]} | ClientOpts]};
+ openssl ->
+ {[{supported_groups, [x448, x25519]} | ServerOpts],
+ [{groups,"P-256:X25519"} | ClientOpts]}
+ end.
+
+test_ciphers(_, 'tlsv1.3' = Version) ->
+ Ciphers = ssl:cipher_suites(default, Version),
+ ct:log("Version ~p Testing ~p~n", [Version, Ciphers]),
+ OpenSSLCiphers = openssl_ciphers(),
+ ct:log("OpenSSLCiphers ~p~n", [OpenSSLCiphers]),
+ lists:filter(fun(C) ->
+ ct:log("Cipher ~p~n", [C]),
+ lists:member(ssl_cipher_format:suite_map_to_openssl_str(C), OpenSSLCiphers)
+ end, Ciphers);
+test_ciphers(Kex, Version) ->
+ Ciphers = ssl:filter_cipher_suites(ssl:cipher_suites(default, Version),
+ [{key_exchange, Kex}]),
+ ct:log("Version ~p Testing ~p~n", [Version, Ciphers]),
+ OpenSSLCiphers = openssl_ciphers(),
+ ct:log("OpenSSLCiphers ~p~n", [OpenSSLCiphers]),
+ lists:filter(fun(C) ->
+ ct:log("Cipher ~p~n", [C]),
+ lists:member(ssl_cipher_format:suite_map_to_openssl_str(C), OpenSSLCiphers)
+ end, Ciphers).
+
+
+
+openssl_ciphers() ->
+ Str = os:cmd("openssl ciphers"),
+ string:split(string:strip(Str, right, $\n), ":", all).
diff --git a/lib/ssl/test/ssl_certificate_verify_SUITE.erl b/lib/ssl/test/ssl_certificate_verify_SUITE.erl
index 4de4a35e59..f38858e0bf 100644
--- a/lib/ssl/test/ssl_certificate_verify_SUITE.erl
+++ b/lib/ssl/test/ssl_certificate_verify_SUITE.erl
@@ -71,37 +71,20 @@ all_protocol_groups() ->
{group, error_handling}].
tests() ->
- [verify_peer,
- verify_none,
- server_require_peer_cert_ok,
- server_require_peer_cert_fail,
- server_require_peer_cert_empty_ok,
- server_require_peer_cert_partial_chain,
- server_require_peer_cert_allow_partial_chain,
- server_require_peer_cert_do_not_allow_partial_chain,
- server_require_peer_cert_partial_chain_fun_fail,
- verify_fun_always_run_client,
- verify_fun_always_run_server,
- cert_expired,
- invalid_signature_client,
- invalid_signature_server,
+ [cert_expired,
+ %invalid_signature_client,
+ %%invalid_signature_server,
extended_key_usage_verify_both,
extended_key_usage_verify_server,
critical_extension_verify_client,
critical_extension_verify_server,
critical_extension_verify_none,
- customize_hostname_check,
- incomplete_chain,
long_chain
].
error_handling_tests()->
[client_with_cert_cipher_suites_handshake,
- server_verify_no_cacerts,
- unknown_server_ca_fail,
- unknown_server_ca_accept_verify_none,
- unknown_server_ca_accept_verify_peer,
- unknown_server_ca_accept_backwardscompatibility,
+ %%unknown_server_ca_accept_backwardscompatibility,
no_authority_key_identifier,
no_authority_key_identifier_keyEncipherment].
@@ -160,61 +143,6 @@ end_per_testcase(_TestCase, Config) ->
%%--------------------------------------------------------------------
%% Test Cases --------------------------------------------------------
%%--------------------------------------------------------------------
-
-verify_peer() ->
- [{doc,"Test option verify_peer"}].
-verify_peer(Config) when is_list(Config) ->
- ClientOpts = ssl_test_lib:ssl_options(client_rsa_opts, Config),
- ServerOpts = ssl_test_lib:ssl_options(server_rsa_opts, Config),
- Active = proplists:get_value(active, Config),
- ReceiveFunction = proplists:get_value(receive_function, Config),
- {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
- Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0},
- {from, self()},
- {mfa, {ssl_test_lib, ReceiveFunction, []}},
- {options, [{active, Active}, {verify, verify_peer}
- | 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, ReceiveFunction, []}},
- {options, [{active, Active}, {verify, verify_peer} | ClientOpts]}]),
-
- ssl_test_lib:check_result(Server, ok, Client, ok),
- ssl_test_lib:close(Server),
- ssl_test_lib:close(Client).
-
-%%--------------------------------------------------------------------
-verify_none() ->
- [{doc,"Test option verify_none"}].
-
-verify_none(Config) when is_list(Config) ->
- ClientOpts = ssl_test_lib:ssl_options(client_rsa_opts, Config),
- ServerOpts = ssl_test_lib:ssl_options(server_rsa_opts, Config),
- Active = proplists:get_value(active, Config),
- ReceiveFunction = proplists:get_value(receive_function, Config),
-
- {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
- Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0},
- {from, self()},
- {mfa, {ssl_test_lib, ReceiveFunction, []}},
- {options, [{active, Active}, {verify, verify_none}
- | 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, ReceiveFunction, []}},
- {options, [{active, Active},
- {verify, verify_none} | ClientOpts]}]),
-
- ssl_test_lib:check_result(Server, ok, Client, ok),
- ssl_test_lib:close(Server),
- ssl_test_lib:close(Client).
-
-%%--------------------------------------------------------------------
-
server_verify_client_once() ->
[{doc,"Test server option verify_client_once"}].
@@ -253,309 +181,6 @@ server_verify_client_once(Config) when is_list(Config) ->
%%--------------------------------------------------------------------
-server_require_peer_cert_ok() ->
- [{doc,"Test server option fail_if_no_peer_cert when peer sends cert"}].
-
-server_require_peer_cert_ok(Config) when is_list(Config) ->
- ServerOpts = [{verify, verify_peer}, {fail_if_no_peer_cert, true}
- | ssl_test_lib:ssl_options(server_rsa_opts, Config)],
- ClientOpts = ssl_test_lib:ssl_options(client_rsa_opts, Config),
- Active = proplists:get_value(active, Config),
- ReceiveFunction = proplists:get_value(receive_function, Config),
- {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
-
-
- Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0},
- {from, self()},
- {mfa, {ssl_test_lib, ReceiveFunction, []}},
- {options, [{active, Active} | 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, ReceiveFunction, []}},
- {options, [{active, Active} | ClientOpts]}]),
-
- ssl_test_lib:check_result(Server, ok, Client, ok),
- ssl_test_lib:close(Server),
- ssl_test_lib:close(Client).
-
-%%--------------------------------------------------------------------
-
-server_require_peer_cert_fail() ->
- [{doc,"Test server option fail_if_no_peer_cert when peer doesn't send cert"}].
-
-server_require_peer_cert_fail(Config) when is_list(Config) ->
- ServerOpts = [{verify, verify_peer}, {fail_if_no_peer_cert, true}
- | ssl_test_lib:ssl_options(server_rsa_opts, Config)],
- BadClientOpts = ssl_test_lib:ssl_options(empty_client_opts, Config),
- Active = proplists:get_value(active, Config),
- {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
-
- Server = ssl_test_lib:start_server_error([{node, ServerNode}, {port, 0},
- {from, self()},
- {options, [{active, Active} | ServerOpts]}]),
-
- Port = ssl_test_lib:inet_port(Server),
-
- Client = ssl_test_lib:start_client_error([{node, ClientNode}, {port, Port},
- {host, Hostname},
- {from, self()},
- {options, [{active, Active} | BadClientOpts]}]),
-
- Version = proplists:get_value(version,Config),
- case Version of
- 'tlsv1.3' ->
- ssl_test_lib:check_server_alert(Server, Client, certificate_required);
- _ ->
- ssl_test_lib:check_server_alert(Server, Client, handshake_failure)
- end.
-
-%%--------------------------------------------------------------------
-server_require_peer_cert_empty_ok() ->
- [{doc,"Test server option fail_if_no_peer_cert when peer sends cert"}].
-
-server_require_peer_cert_empty_ok(Config) when is_list(Config) ->
- ServerOpts = [{verify, verify_peer}, {fail_if_no_peer_cert, false}
- | ssl_test_lib:ssl_options(server_rsa_opts, Config)],
- ClientOpts0 = ssl_test_lib:ssl_options(client_rsa_opts, Config),
- Active = proplists:get_value(active, Config),
- ReceiveFunction = proplists:get_value(receive_function, Config),
- {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
-
- ClientOpts = proplists:delete(keyfile, proplists:delete(certfile, ClientOpts0)),
-
- Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0},
- {from, self()},
- {mfa, {ssl_test_lib, ReceiveFunction, []}},
- {options, [{active, Active} | 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, ReceiveFunction, []}},
- {options, [{active, Active} | ClientOpts]}]),
-
- ssl_test_lib:check_result(Server, ok, Client, ok),
- ssl_test_lib:close(Server),
- ssl_test_lib:close(Client).
-
-%%--------------------------------------------------------------------
-
-server_require_peer_cert_partial_chain() ->
- [{doc, "Client sends an incompleate chain, by default not acceptable."}].
-
-server_require_peer_cert_partial_chain(Config) when is_list(Config) ->
- ServerOpts = [{verify, verify_peer}, {fail_if_no_peer_cert, true}
- | ssl_test_lib:ssl_options(server_rsa_opts, Config)],
- ClientOpts = ssl_test_lib:ssl_options(client_rsa_opts, Config),
- Active = proplists:get_value(active, Config),
- {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
-
- {ok, ClientCAs} = file:read_file(proplists:get_value(cacertfile, ClientOpts)),
- [{_,RootCA,_} | _] = public_key:pem_decode(ClientCAs),
-
-
- Server = ssl_test_lib:start_server_error([{node, ServerNode}, {port, 0},
- {from, self()},
- {mfa, {ssl_test_lib, no_result, []}},
- {options, [{active, Active} | ServerOpts]}]),
- Port = ssl_test_lib:inet_port(Server),
- Client = ssl_test_lib:start_client_error([{node, ClientNode}, {port, Port},
- {host, Hostname},
- {from, self()},
- {mfa, {ssl_test_lib, no_result, []}},
- {options, [{active, Active},
- {cacerts, [RootCA]} |
- proplists:delete(cacertfile, ClientOpts)]}]),
- ssl_test_lib:check_server_alert(Server, Client, unknown_ca).
-
-%%--------------------------------------------------------------------
-server_require_peer_cert_allow_partial_chain() ->
- [{doc, "Server trusts intermediat CA and accepts a partial chain. (partial_chain option)"}].
-
-server_require_peer_cert_allow_partial_chain(Config) when is_list(Config) ->
- ServerOpts = [{verify, verify_peer}, {fail_if_no_peer_cert, true}
- | ssl_test_lib:ssl_options(server_rsa_opts, Config)],
- ClientOpts = ssl_test_lib:ssl_options(client_rsa_opts, Config),
- {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
- Active = proplists:get_value(active, Config),
- ReceiveFunction = proplists:get_value(receive_function, Config),
-
- {ok, ClientCAs} = file:read_file(proplists:get_value(cacertfile, ClientOpts)),
- [{_,_,_}, {_, IntermidiateCA, _} | _] = public_key:pem_decode(ClientCAs),
-
- PartialChain = fun(CertChain) ->
- case lists:member(IntermidiateCA, CertChain) of
- true ->
- {trusted_ca, IntermidiateCA};
- false ->
- unknown_ca
- end
- end,
-
- Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0},
- {from, self()},
- {mfa, {ssl_test_lib, ReceiveFunction, []}},
- {options, [{active, Active},
- {cacerts, [IntermidiateCA]},
- {partial_chain, PartialChain} |
- proplists:delete(cacertfile, 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, ReceiveFunction, []}},
- {options, [{active, Active} | ClientOpts]}]),
- ssl_test_lib:check_result(Server, ok, Client, ok),
- ssl_test_lib:close(Server),
- ssl_test_lib:close(Client).
-
- %%--------------------------------------------------------------------
-server_require_peer_cert_do_not_allow_partial_chain() ->
- [{doc, "Server does not accept the chain sent by the client as ROOT CA is unkown, "
- "and we do not choose to trust the intermediate CA. (partial_chain option)"}].
-
-server_require_peer_cert_do_not_allow_partial_chain(Config) when is_list(Config) ->
- ServerOpts = [{verify, verify_peer}, {fail_if_no_peer_cert, true}
- | ssl_test_lib:ssl_options(server_rsa_opts, Config)],
- ClientOpts = ssl_test_lib:ssl_options(client_rsa_opts, Config),
- {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
-
- {ok, ServerCAs} = file:read_file(proplists:get_value(cacertfile, ServerOpts)),
- [{_,_,_}, {_, IntermidiateCA, _} | _] = public_key:pem_decode(ServerCAs),
-
- PartialChain = fun(_CertChain) ->
- unknown_ca
- end,
-
- Server = ssl_test_lib:start_server_error([{node, ServerNode}, {port, 0},
- {from, self()},
- {mfa, {ssl_test_lib, no_result, []}},
- {options, [{cacerts, [IntermidiateCA]},
- {partial_chain, PartialChain} |
- proplists:delete(cacertfile, ServerOpts)]}]),
-
- Port = ssl_test_lib:inet_port(Server),
- Client = ssl_test_lib:start_client_error([{node, ClientNode}, {port, Port},
- {host, Hostname},
- {from, self()},
- {mfa, {ssl_test_lib, no_result, []}},
- {options, ClientOpts}]),
- ssl_test_lib:check_server_alert(Server, Client, unknown_ca).
- %%--------------------------------------------------------------------
-server_require_peer_cert_partial_chain_fun_fail() ->
- [{doc, "If parial_chain fun crashes, treat it as if it returned unkown_ca"}].
-
-server_require_peer_cert_partial_chain_fun_fail(Config) when is_list(Config) ->
- ServerOpts = [{verify, verify_peer}, {fail_if_no_peer_cert, true}
- | ssl_test_lib:ssl_options(server_rsa_opts, Config)],
- ClientOpts = ssl_test_lib:ssl_options(client_rsa_opts, Config),
- {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
-
- {ok, ServerCAs} = file:read_file(proplists:get_value(cacertfile, ServerOpts)),
- [{_,_,_}, {_, IntermidiateCA, _} | _] = public_key:pem_decode(ServerCAs),
-
- PartialChain = fun(_CertChain) ->
- true = false %% crash on purpose
- end,
-
- Server = ssl_test_lib:start_server_error([{node, ServerNode}, {port, 0},
- {from, self()},
- {mfa, {ssl_test_lib, no_result, []}},
- {options, [{cacerts, [IntermidiateCA]},
- {partial_chain, PartialChain} |
- proplists:delete(cacertfile, ServerOpts)]}]),
-
- Port = ssl_test_lib:inet_port(Server),
- Client = ssl_test_lib:start_client_error([{node, ClientNode}, {port, Port},
- {host, Hostname},
- {from, self()},
- {mfa, {ssl_test_lib, no_result, []}},
- {options, ClientOpts}]),
- ssl_test_lib:check_server_alert(Server, Client, unknown_ca).
-
-%%--------------------------------------------------------------------
-verify_fun_always_run_client() ->
- [{doc,"Verify that user verify_fun is always run (for valid and valid_peer not only unknown_extension)"}].
-
-verify_fun_always_run_client(Config) when is_list(Config) ->
- ClientOpts = ssl_test_lib:ssl_options(client_rsa_opts, Config),
- ServerOpts = ssl_test_lib:ssl_options(server_rsa_opts, Config),
- {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
- Server = ssl_test_lib:start_server_error([{node, ServerNode}, {port, 0},
- {from, self()},
- {mfa, {ssl_test_lib,
- no_result, []}},
- {options, ServerOpts}]),
- Port = ssl_test_lib:inet_port(Server),
-
- %% If user verify fun is called correctly we fail the connection.
- %% otherwise we cannot tell this case apart form where we miss
- %% to call users verify fun
- FunAndState = {fun(_,{extension, _}, UserState) ->
- {unknown, UserState};
- (_, valid, [ChainLen]) ->
- {valid, [ChainLen + 1]};
- (_, valid_peer, [1]) ->
- {fail, "verify_fun_was_always_run"};
- (_, valid_peer, UserState) ->
- {valid, UserState}
- end, [0]},
-
- Client = ssl_test_lib:start_client_error([{node, ClientNode}, {port, Port},
- {host, Hostname},
- {from, self()},
- {mfa, {ssl_test_lib,
- no_result, []}},
- {options,
- [{verify, verify_peer},
- {verify_fun, FunAndState}
- | ClientOpts]}]),
-
- ssl_test_lib:check_client_alert(Server, Client, handshake_failure).
-
-%%--------------------------------------------------------------------
-verify_fun_always_run_server() ->
- [{doc,"Verify that user verify_fun is always run (for valid and valid_peer not only unknown_extension)"}].
-verify_fun_always_run_server(Config) when is_list(Config) ->
- ClientOpts = ssl_test_lib:ssl_options(client_rsa_opts, Config),
- ServerOpts = ssl_test_lib:ssl_options(server_rsa_verify_opts, Config),
- {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
-
- %% If user verify fun is called correctly we fail the connection.
- %% otherwise we cannot tell this case apart form where we miss
- %% to call users verify fun
- FunAndState = {fun(_,{extension, _}, UserState) ->
- {unknown, UserState};
- (_, valid, [ChainLen]) ->
- {valid, [ChainLen + 1]};
- (_, valid_peer, [1]) ->
- {fail, "verify_fun_was_always_run"};
- (_, valid_peer, UserState) ->
- {valid, UserState}
- end, [0]},
-
- Server = ssl_test_lib:start_server_error([{node, ServerNode}, {port, 0},
- {from, self()},
- {mfa, {ssl_test_lib,
- no_result, []}},
- {options,
- [{verify, verify_peer},
- {verify_fun, FunAndState} |
- ServerOpts]}]),
- Port = ssl_test_lib:inet_port(Server),
-
- Client = ssl_test_lib:start_client_error([{node, ClientNode}, {port, Port},
- {host, Hostname},
- {from, self()},
- {mfa, {ssl_test_lib,
- no_result, []}},
- {options, ClientOpts}]),
-
- ssl_test_lib:check_client_alert(Server, Client, handshake_failure).
-%%--------------------------------------------------------------------
-
cert_expired() ->
[{doc,"Test server with expired certificate"}].
@@ -937,235 +562,6 @@ client_with_cert_cipher_suites_handshake(Config) when is_list(Config) ->
%%--------------------------------------------------------------------
-server_verify_no_cacerts() ->
- [{doc,"Test server must have cacerts if it wants to verify client"}].
-server_verify_no_cacerts(Config) when is_list(Config) ->
- ServerOpts = proplists:delete(cacertfile, ssl_test_lib:ssl_options(server_rsa_opts, Config)),
- {_, ServerNode, _} = ssl_test_lib:run_where(Config),
- Server = ssl_test_lib:start_server_error([{node, ServerNode}, {port, 0},
- {from, self()},
- {options, [{verify, verify_peer}
- | ServerOpts]}]),
-
- ssl_test_lib:check_result(Server, {error, {options, {cacertfile, ""}}}).
-
-
-%%--------------------------------------------------------------------
-unknown_server_ca_fail() ->
- [{doc,"Test that the client fails if the ca is unknown in verify_peer mode"}].
-unknown_server_ca_fail(Config) when is_list(Config) ->
- ClientOpts = ssl_test_lib:ssl_options(empty_client_opts, Config),
- ServerOpts = ssl_test_lib:ssl_options(server_rsa_verify_opts, Config),
- {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
- Server = ssl_test_lib:start_server_error([{node, ServerNode}, {port, 0},
- {from, self()},
- {mfa, {ssl_test_lib,
- no_result, []}},
- {options, ServerOpts}]),
- Port = ssl_test_lib:inet_port(Server),
-
- FunAndState = {fun(_,{bad_cert, unknown_ca} = Reason, _) ->
- {fail, Reason};
- (_,{extension, _}, UserState) ->
- {unknown, UserState};
- (_, valid, UserState) ->
- {valid, [test_to_update_user_state | UserState]};
- (_, valid_peer, UserState) ->
- {valid, UserState}
- end, []},
-
- Client = ssl_test_lib:start_client_error([{node, ClientNode}, {port, Port},
- {host, Hostname},
- {from, self()},
- {mfa, {ssl_test_lib,
- no_result, []}},
- {options,
- [{verify, verify_peer},
- {verify_fun, FunAndState}
- | ClientOpts]}]),
- ssl_test_lib:check_client_alert(Server, Client, unknown_ca).
-
-%%--------------------------------------------------------------------
-unknown_server_ca_accept_verify_none() ->
- [{doc,"Test that the client succeds if the ca is unknown in verify_none mode"}].
-unknown_server_ca_accept_verify_none(Config) when is_list(Config) ->
- ClientOpts = ssl_test_lib:ssl_options(empty_client_opts, Config),
- ServerOpts = ssl_test_lib:ssl_options(server_rsa_verify_opts, Config),
- {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
- Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0},
- {from, self()},
- {mfa, {ssl_test_lib,
- send_recv_result_active, []}},
- {options, ServerOpts}]),
- Port = ssl_test_lib:inet_port(Server),
- Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port},
- {host, Hostname},
- {from, self()},
- {mfa, {ssl_test_lib,
- send_recv_result_active, []}},
- {options,
- [{verify, verify_none}| ClientOpts]}]),
-
- ssl_test_lib:check_result(Server, ok, Client, ok),
- ssl_test_lib:close(Server),
- ssl_test_lib:close(Client).
-%%--------------------------------------------------------------------
-unknown_server_ca_accept_verify_peer() ->
- [{doc, "Test that the client succeds if the ca is unknown in verify_peer mode"
- " with a verify_fun that accepts the unknown ca error"}].
-unknown_server_ca_accept_verify_peer(Config) when is_list(Config) ->
- ClientOpts = ssl_test_lib:ssl_options(empty_client_opts, Config),
- ServerOpts = ssl_test_lib:ssl_options(server_rsa_verify_opts, Config),
- {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
- Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0},
- {from, self()},
- {mfa, {ssl_test_lib,
- send_recv_result_active, []}},
- {options, ServerOpts}]),
- Port = ssl_test_lib:inet_port(Server),
-
- FunAndState = {fun(_,{bad_cert, unknown_ca}, UserState) ->
- {valid, UserState};
- (_,{bad_cert, _} = Reason, _) ->
- {fail, Reason};
- (_,{extension, _}, UserState) ->
- {unknown, UserState};
- (_, valid, UserState) ->
- {valid, UserState};
- (_, valid_peer, UserState) ->
- {valid, UserState}
- end, []},
-
- Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port},
- {host, Hostname},
- {from, self()},
- {mfa, {ssl_test_lib,
- send_recv_result_active, []}},
- {options,
- [{verify, verify_peer},
- {verify_fun, FunAndState}| ClientOpts]}]),
-
- ssl_test_lib:check_result(Server, ok, Client, ok),
- ssl_test_lib:close(Server),
- ssl_test_lib:close(Client).
-
-%%--------------------------------------------------------------------
-unknown_server_ca_accept_backwardscompatibility() ->
- [{doc,"Test that old style verify_funs will work"}].
-unknown_server_ca_accept_backwardscompatibility(Config) when is_list(Config) ->
- ClientOpts = ssl_test_lib:ssl_options(empty_client_opts, Config),
- ServerOpts = ssl_test_lib:ssl_options(server_rsa_verify_opts, Config),
- {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
- Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0},
- {from, self()},
- {mfa, {ssl_test_lib,
- send_recv_result_active, []}},
- {options, ServerOpts}]),
- Port = ssl_test_lib:inet_port(Server),
-
- AcceptBadCa = fun({bad_cert,unknown_ca}, Acc) -> Acc;
- (Other, Acc) -> [Other | Acc]
- end,
- VerifyFun =
- fun(ErrorList) ->
- case lists:foldl(AcceptBadCa, [], ErrorList) of
- [] -> true;
- [_|_] -> false
- end
- end,
-
- Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port},
- {host, Hostname},
- {from, self()},
- {mfa, {ssl_test_lib,
- send_recv_result_active, []}},
- {options,
- [{verify, verify_peer},
- {verify_fun, VerifyFun}| ClientOpts]}]),
-
- ssl_test_lib:check_result(Server, ok, Client, ok),
- ssl_test_lib:close(Server),
- ssl_test_lib:close(Client).
-
-%%--------------------------------------------------------------------
-
-customize_hostname_check() ->
- [{doc,"Test option customize_hostname_check."}].
-customize_hostname_check(Config) when is_list(Config) ->
- Ext = [#'Extension'{extnID = ?'id-ce-subjectAltName',
- extnValue = [{dNSName, "*.example.org"}],
- critical = false}
- ],
- {ClientOpts0, ServerOpts0} = ssl_test_lib:make_rsa_cert_chains([{server_chain,
- [[],
- [],
- [{extensions, Ext}]
- ]}],
- Config, "https_hostname_convention"),
- ClientOpts = ssl_test_lib:ssl_options(ClientOpts0, Config),
- ServerOpts = ssl_test_lib:ssl_options(ServerOpts0, Config),
-
- {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
- Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0},
- {from, self()},
- {mfa, {ssl_test_lib, send_recv_result_active, []}},
- {options, ServerOpts}]),
- Port = ssl_test_lib:inet_port(Server),
-
- CustomFun = public_key:pkix_verify_hostname_match_fun(https),
-
- Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port},
- {host, Hostname},
- {from, self()},
- {mfa, {ssl_test_lib, send_recv_result_active, []}},
- {options,
- [{server_name_indication, "other.example.org"},
- {customize_hostname_check,
- [{match_fun, CustomFun}]} | ClientOpts]
- }]),
- ssl_test_lib:check_result(Server, ok, Client, ok),
-
- Server ! {listen, {mfa, {ssl_test_lib, no_result, []}}},
-
- Client1 = ssl_test_lib:start_client_error([{node, ClientNode}, {port, Port},
- {host, Hostname},
- {from, self()},
- {mfa, {ssl_test_lib, no_result, []}},
- {options, ClientOpts}
- ]),
- ssl_test_lib:check_client_alert(Server, Client1, handshake_failure).
-
-incomplete_chain() ->
- [{doc,"Test option verify_peer"}].
-incomplete_chain(Config) when is_list(Config) ->
- DefConf = ssl_test_lib:default_cert_chain_conf(),
- CertChainConf = ssl_test_lib:gen_conf(rsa, rsa, DefConf, DefConf),
- #{server_config := ServerConf,
- client_config := ClientConf} = public_key:pkix_test_data(CertChainConf),
- [ServerRoot| _] = ServerCas = proplists:get_value(cacerts, ServerConf),
- ClientCas = proplists:get_value(cacerts, ClientConf),
-
- Active = proplists:get_value(active, Config),
- ReceiveFunction = proplists:get_value(receive_function, Config),
- {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
- Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0},
- {from, self()},
- {mfa, {ssl_test_lib, ReceiveFunction, []}},
- {options, [{active, Active}, {verify, verify_peer},
- {cacerts, [ServerRoot]} |
- proplists:delete(cacerts, ServerConf)]}]),
- 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, ReceiveFunction, []}},
- {options, [{active, Active},
- {verify, verify_peer},
- {cacerts, ServerCas ++ ClientCas} |
- proplists:delete(cacerts, ClientConf)]}]),
- ssl_test_lib:check_result(Server, ok, Client, ok),
- ssl_test_lib:close(Server),
- ssl_test_lib:close(Client).
long_chain() ->
[{doc,"Test option verify_peer"}].
diff --git a/lib/ssl/test/ssl_cipher_suite_SUITE.erl b/lib/ssl/test/ssl_cipher_suite_SUITE.erl
index 51788c29e7..e598d662e9 100644
--- a/lib/ssl/test/ssl_cipher_suite_SUITE.erl
+++ b/lib/ssl/test/ssl_cipher_suite_SUITE.erl
@@ -45,7 +45,7 @@ groups() ->
{'tlsv1.2', [], kex()},
{'tlsv1.1', [], kex()},
{'tlsv1', [], kex()},
- {'sslv3', [], kex()},
+ {'sslv3', [], ssl3_kex()},
{'dtlsv1.2', [], kex()},
{'dtlsv1', [], kex()},
{dhe_rsa, [],[dhe_rsa_3des_ede_cbc,
@@ -130,6 +130,11 @@ groups() ->
kex() ->
rsa() ++ ecdsa() ++ dss() ++ anonymous().
+
+ssl3_kex() ->
+ ssl3_rsa() ++ ssl3_dss() ++ ssl3_anonymous().
+
+
rsa() ->
[{group, dhe_rsa},
{group, ecdhe_rsa},
@@ -138,6 +143,11 @@ rsa() ->
{group, rsa_psk}
].
+ssl3_rsa() ->
+ [{group, dhe_rsa},
+ {group, rsa}
+ ].
+
ecdsa() ->
[{group, ecdhe_ecdsa}].
@@ -145,6 +155,10 @@ dss() ->
[{group, dhe_dss},
{group, srp_dss}].
+ssl3_dss() ->
+ [{group, dhe_dss}
+ ].
+
anonymous() ->
[{group, dh_anon},
{group, ecdh_anon},
@@ -154,6 +168,10 @@ anonymous() ->
{group, srp_anon}
].
+ssl3_anonymous() ->
+ [{group, dh_anon}].
+
+
init_per_suite(Config) ->
catch crypto:stop(),
try crypto:start() of
diff --git a/lib/ssl/test/ssl_handshake_SUITE.erl b/lib/ssl/test/ssl_handshake_SUITE.erl
index 1b432970b6..2750a4a9dc 100644
--- a/lib/ssl/test/ssl_handshake_SUITE.erl
+++ b/lib/ssl/test/ssl_handshake_SUITE.erl
@@ -214,7 +214,7 @@ encode_decode_srp(_Config) ->
0,3, % HostNameLength
98,97,114>>, % hostname = "bar"
EncodedExts0 = <<?UINT16(_),EncodedExts/binary>> =
- ssl_handshake:encode_hello_extensions(Exts),
+ ssl_handshake:encode_hello_extensions(Exts, {3,3}),
Exts = ssl_handshake:decode_hello_extensions(EncodedExts, {3,3}, {3,3}, client).
signature_algorithms(Config) ->
diff --git a/lib/ssl/test/ssl_npn_handshake_SUITE.erl b/lib/ssl/test/ssl_npn_SUITE.erl
index 878e983bb9..8a76a3a82b 100644
--- a/lib/ssl/test/ssl_npn_handshake_SUITE.erl
+++ b/lib/ssl/test/ssl_npn_SUITE.erl
@@ -19,7 +19,7 @@
%%
%%
--module(ssl_npn_handshake_SUITE).
+-module(ssl_npn_SUITE).
%% Note: This directive should only be used in test suites.
-compile(export_all).
diff --git a/lib/ssl/test/ssl_npn_hello_SUITE.erl b/lib/ssl/test/ssl_npn_hello_SUITE.erl
index 46734ba180..7dbc0c5134 100644
--- a/lib/ssl/test/ssl_npn_hello_SUITE.erl
+++ b/lib/ssl/test/ssl_npn_hello_SUITE.erl
@@ -24,10 +24,11 @@
%% Note: This directive should only be used in test suites.
-compile(export_all).
--include("ssl_cipher.hrl").
--include("ssl_internal.hrl").
--include("tls_handshake.hrl").
--include("tls_record.hrl").
+
+-include_lib("ssl/src/tls_record.hrl").
+-include_lib("ssl/src/tls_handshake.hrl").
+-include_lib("ssl/src/ssl_cipher.hrl").
+-include_lib("ssl/src/ssl_internal.hrl").
-include_lib("common_test/include/ct.hrl").
%%--------------------------------------------------------------------
diff --git a/lib/ssl/test/ssl_pem_cache_SUITE.erl b/lib/ssl/test/ssl_pem_cache_SUITE.erl
index 6f11e2bbe8..3c7f6ab20f 100644
--- a/lib/ssl/test/ssl_pem_cache_SUITE.erl
+++ b/lib/ssl/test/ssl_pem_cache_SUITE.erl
@@ -34,7 +34,10 @@
%% Common Test interface functions -----------------------------------
%%--------------------------------------------------------------------
all() ->
- [pem_cleanup, invalid_insert].
+ [
+ pem_cleanup,
+ clear_pem_cache,
+ invalid_insert].
groups() ->
[].
@@ -110,6 +113,37 @@ pem_cleanup(Config)when is_list(Config) ->
ssl_test_lib:close(Client),
false = Size == Size1.
+clear_pem_cache() ->
+ [{doc,"Test that internal reference tabel is cleaned properly even when "
+ " the PEM cache is cleared" }].
+clear_pem_cache(Config) when is_list(Config) ->
+ {status, _, _, StatusInfo} = sys:get_status(whereis(ssl_manager)),
+ [_, _,_, _, Prop] = StatusInfo,
+ State = ssl_test_lib:state(Prop),
+ [_,{FilRefDb, _} |_] = element(6, State),
+ {Server, Client} = basic_verify_test_no_close(Config),
+ CountReferencedFiles = fun({_, -1}, Acc) ->
+ Acc;
+ ({_, N}, Acc) ->
+ N + Acc
+ end,
+
+ 2 = ets:foldl(CountReferencedFiles, 0, FilRefDb),
+ ssl:clear_pem_cache(),
+ _ = sys:get_status(whereis(ssl_manager)),
+ {Server1, Client1} = basic_verify_test_no_close(Config),
+ 4 = ets:foldl(CountReferencedFiles, 0, FilRefDb),
+ ssl_test_lib:close(Server),
+ ssl_test_lib:close(Client),
+ ct:sleep(2000),
+ _ = sys:get_status(whereis(ssl_manager)),
+ 2 = ets:foldl(CountReferencedFiles, 0, FilRefDb),
+ ssl_test_lib:close(Server1),
+ ssl_test_lib:close(Client1),
+ ct:sleep(2000),
+ _ = sys:get_status(whereis(ssl_manager)),
+ 0 = ets:foldl(CountReferencedFiles, 0, FilRefDb).
+
invalid_insert() ->
[{doc, "Test that insert of invalid pem does not cause empty cache entry"}].
invalid_insert(Config)when is_list(Config) ->
@@ -163,3 +197,22 @@ later()->
Gregorian = calendar:datetime_to_gregorian_seconds(DateTime),
calendar:gregorian_seconds_to_datetime(Gregorian + (2 * ?CLEANUP_INTERVAL)).
+basic_verify_test_no_close(Config) ->
+ ClientOpts = ssl_test_lib:ssl_options(client_rsa_opts, Config),
+ ServerOpts = ssl_test_lib:ssl_options(server_rsa_opts, Config),
+
+ {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
+
+ Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0},
+ {from, self()},
+ {mfa, {ssl_test_lib, send_recv_result_active, []}},
+ {options, ServerOpts}]),
+ Port = ssl_test_lib:inet_port(Server),
+ Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port},
+ {host, Hostname},
+ {from, self()},
+ {mfa, {ssl_test_lib, send_recv_result_active, []}},
+ {options, ClientOpts}]),
+
+ ssl_test_lib:check_result(Server, ok, Client, ok),
+ {Server, Client}.
diff --git a/lib/ssl/test/ssl_renegotiate_SUITE.erl b/lib/ssl/test/ssl_renegotiate_SUITE.erl
new file mode 100644
index 0000000000..ef3f9ebb52
--- /dev/null
+++ b/lib/ssl/test/ssl_renegotiate_SUITE.erl
@@ -0,0 +1,499 @@
+%%
+%% %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_renegotiate_SUITE).
+
+%% Note: This directive should only be used in test suites.
+-compile(export_all).
+
+-include_lib("common_test/include/ct.hrl").
+-include_lib("public_key/include/public_key.hrl").
+
+-define(SLEEP, 500).
+-define(RENEGOTIATION_DISABLE_TIME, 12000).
+
+%%--------------------------------------------------------------------
+%% Common Test interface functions -----------------------------------
+%%--------------------------------------------------------------------
+all() ->
+ [
+ {group, 'tlsv1.2'},
+ {group, 'tlsv1.1'},
+ {group, 'tlsv1'},
+ {group, 'sslv3'},
+ {group, 'dtlsv1.2'},
+ {group, 'dtlsv1'}
+ ].
+
+groups() ->
+ [{'dtlsv1.2', [], renegotiate_tests()},
+ {'dtlsv1', [], renegotiate_tests()},
+ {'tlsv1.3', [], renegotiate_tests()},
+ {'tlsv1.2', [], renegotiate_tests()},
+ {'tlsv1.1', [], renegotiate_tests()},
+ {'tlsv1', [], renegotiate_tests()},
+ {'sslv3', [], ssl3_renegotiate_tests()}
+ ].
+
+renegotiate_tests() ->
+ [client_renegotiate,
+ server_renegotiate,
+ client_secure_renegotiate,
+ client_secure_renegotiate_fallback,
+ client_renegotiate_reused_session,
+ server_renegotiate_reused_session,
+ client_no_wrap_sequence_number,
+ server_no_wrap_sequence_number,
+ renegotiate_dos_mitigate_active,
+ renegotiate_dos_mitigate_passive,
+ renegotiate_dos_mitigate_absolute].
+
+ssl3_renegotiate_tests() ->
+ [client_renegotiate,
+ server_renegotiate,
+ client_renegotiate_reused_session,
+ server_renegotiate_reused_session,
+ client_no_wrap_sequence_number,
+ server_no_wrap_sequence_number,
+ renegotiate_dos_mitigate_active,
+ renegotiate_dos_mitigate_passive,
+ renegotiate_dos_mitigate_absolute].
+
+init_per_suite(Config) ->
+ catch crypto:stop(),
+ try crypto:start() of
+ ok ->
+ ssl_test_lib:clean_start(),
+ ssl_test_lib:make_rsa_cert(Config)
+ catch _:_ ->
+ {skip, "Crypto did not start"}
+ end.
+
+end_per_suite(_Config) ->
+ ssl:stop(),
+ application:stop(crypto).
+
+init_per_group(GroupName, Config) ->
+ ssl_test_lib:clean_tls_version(Config),
+ case ssl_test_lib:is_tls_version(GroupName) andalso ssl_test_lib:sufficient_crypto_support(GroupName) of
+ true ->
+ ssl_test_lib:init_tls_version(GroupName, Config);
+ _ ->
+ case ssl_test_lib:sufficient_crypto_support(GroupName) of
+ true ->
+ ssl:start(),
+ Config;
+ false ->
+ {skip, "Missing crypto support"}
+ end
+ 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.
+
+%%--------------------------------------------------------------------
+%% Test Cases --------------------------------------------------------
+%%--------------------------------------------------------------------
+client_renegotiate() ->
+ [{doc,"Test ssl:renegotiate/1 on client."}].
+client_renegotiate(Config) when is_list(Config) ->
+ ServerOpts = ssl_test_lib:ssl_options(server_rsa_verify_opts, Config),
+ ClientOpts = ssl_test_lib:ssl_options(client_rsa_verify_opts, Config),
+
+ {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
+
+ Data = "From erlang 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),
+
+ Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port},
+ {host, Hostname},
+ {from, self()},
+ {mfa, {?MODULE,
+ renegotiate, [Data]}},
+ {options, [{reuse_sessions, false} | ClientOpts]}]),
+
+ ssl_test_lib:check_result(Client, ok, Server, ok),
+ ssl_test_lib:close(Server),
+ ssl_test_lib:close(Client).
+
+%%--------------------------------------------------------------------
+client_secure_renegotiate() ->
+ [{doc,"Test ssl:renegotiate/1 on client."}].
+client_secure_renegotiate(Config) when is_list(Config) ->
+ ServerOpts = ssl_test_lib:ssl_options(server_rsa_verify_opts, Config),
+ ClientOpts = ssl_test_lib:ssl_options(client_rsa_verify_opts, Config),
+
+ {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
+
+ Data = "From erlang to erlang",
+
+ Server =
+ ssl_test_lib:start_server([{node, ServerNode}, {port, 0},
+ {from, self()},
+ {mfa, {?MODULE, erlang_ssl_receive, [Data]}},
+ {options, [{secure_renegotiate, true} | ServerOpts]}]),
+ Port = ssl_test_lib:inet_port(Server),
+
+ Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port},
+ {host, Hostname},
+ {from, self()},
+ {mfa, {?MODULE,
+ renegotiate, [Data]}},
+ {options, [{reuse_sessions, false},
+ {secure_renegotiate, true}| ClientOpts]}]),
+
+ ssl_test_lib:check_result(Client, ok, Server, ok),
+ ssl_test_lib:close(Server),
+ ssl_test_lib:close(Client).
+
+%%--------------------------------------------------------------------
+client_secure_renegotiate_fallback() ->
+ [{doc,"Test that we can set secure_renegotiate to false that is "
+ "fallback option, we however do not have a insecure server to test against!"}].
+client_secure_renegotiate_fallback(Config) when is_list(Config) ->
+ ServerOpts = ssl_test_lib:ssl_options(server_rsa_verify_opts, Config),
+ ClientOpts = ssl_test_lib:ssl_options(client_rsa_verify_opts, Config),
+
+ {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
+
+ Data = "From erlang to erlang",
+
+ Server =
+ ssl_test_lib:start_server([{node, ServerNode}, {port, 0},
+ {from, self()},
+ {mfa, {?MODULE, erlang_ssl_receive, [Data]}},
+ {options, [{secure_renegotiate, false} | ServerOpts]}]),
+ Port = ssl_test_lib:inet_port(Server),
+
+ Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port},
+ {host, Hostname},
+ {from, self()},
+ {mfa, {?MODULE,
+ renegotiate, [Data]}},
+ {options, [{reuse_sessions, false},
+ {secure_renegotiate, false}| ClientOpts]}]),
+
+ ssl_test_lib:check_result(Client, ok, Server, ok),
+ ssl_test_lib:close(Server),
+ ssl_test_lib:close(Client).
+
+%%--------------------------------------------------------------------
+server_renegotiate() ->
+ [{doc,"Test ssl:renegotiate/1 on server."}].
+server_renegotiate(Config) when is_list(Config) ->
+ ServerOpts = ssl_test_lib:ssl_options(server_rsa_verify_opts, Config),
+ ClientOpts = ssl_test_lib:ssl_options(client_rsa_verify_opts, Config),
+
+ {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
+
+ Data = "From erlang to erlang",
+
+ Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0},
+ {from, self()},
+ {mfa, {?MODULE,
+ renegotiate, [Data]}},
+ {options, ServerOpts}]),
+ Port = ssl_test_lib:inet_port(Server),
+
+ Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port},
+ {host, Hostname},
+ {from, self()},
+ {mfa, {?MODULE, erlang_ssl_receive, [Data]}},
+ {options, [{reuse_sessions, false} | ClientOpts]}]),
+
+ ssl_test_lib:check_result(Server, ok, Client, ok),
+ ssl_test_lib:close(Server),
+ ssl_test_lib:close(Client).
+
+%%--------------------------------------------------------------------
+client_renegotiate_reused_session() ->
+ [{doc,"Test ssl:renegotiate/1 on client when the ssl session will be reused."}].
+client_renegotiate_reused_session(Config) when is_list(Config) ->
+ ServerOpts = ssl_test_lib:ssl_options(server_rsa_verify_opts, Config),
+ ClientOpts = ssl_test_lib:ssl_options(client_rsa_verify_opts, Config),
+
+ {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
+
+ Data = "From erlang 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),
+
+ Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port},
+ {host, Hostname},
+ {from, self()},
+ {mfa, {?MODULE,
+ renegotiate_reuse_session, [Data]}},
+ {options, [{reuse_sessions, true} | ClientOpts]}]),
+
+ ssl_test_lib:check_result(Client, ok, Server, ok),
+ ssl_test_lib:close(Server),
+ ssl_test_lib:close(Client).
+%%--------------------------------------------------------------------
+server_renegotiate_reused_session() ->
+ [{doc,"Test ssl:renegotiate/1 on server when the ssl session will be reused."}].
+server_renegotiate_reused_session(Config) when is_list(Config) ->
+ ServerOpts = ssl_test_lib:ssl_options(server_rsa_verify_opts, Config),
+ ClientOpts = ssl_test_lib:ssl_options(client_rsa_verify_opts, Config),
+
+ {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
+
+ Data = "From erlang to erlang",
+
+ Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0},
+ {from, self()},
+ {mfa, {?MODULE,
+ renegotiate_reuse_session, [Data]}},
+ {options, ServerOpts}]),
+ Port = ssl_test_lib:inet_port(Server),
+
+ Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port},
+ {host, Hostname},
+ {from, self()},
+ {mfa, {?MODULE, erlang_ssl_receive, [Data]}},
+ {options, [{reuse_sessions, true} | ClientOpts]}]),
+
+ ssl_test_lib:check_result(Server, ok, Client, ok),
+ ssl_test_lib:close(Server),
+ ssl_test_lib:close(Client).
+%%--------------------------------------------------------------------
+client_no_wrap_sequence_number() ->
+ [{doc,"Test that erlang client will renegotiate session when",
+ "max sequence number celing is about to be reached. Although"
+ "in the testcase we use the test option renegotiate_at"
+ " to lower treashold substantially."}].
+
+client_no_wrap_sequence_number(Config) when is_list(Config) ->
+ ServerOpts = ssl_test_lib:ssl_options(server_rsa_verify_opts, Config),
+ ClientOpts = ssl_test_lib:ssl_options(client_rsa_verify_opts, Config),
+
+ {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
+
+ ErlData = "From erlang to erlang",
+ N = 12,
+
+ Server =
+ ssl_test_lib:start_server([{node, ServerNode}, {port, 0},
+ {from, self()},
+ {mfa, {ssl_test_lib, no_result, []}},
+ {options, ServerOpts}]),
+ Port = ssl_test_lib:inet_port(Server),
+
+ Version = ssl_test_lib:protocol_version(Config, tuple),
+
+ Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port},
+ {host, Hostname},
+ {from, self()},
+ {mfa, {ssl_test_lib,
+ trigger_renegotiate, [[ErlData, treashold(N, Version)]]}},
+ {options, [{reuse_sessions, false},
+ {renegotiate_at, N} | ClientOpts]}]),
+
+ ssl_test_lib:check_result(Client, ok),
+ ssl_test_lib:close(Server),
+ ssl_test_lib:close(Client).
+
+%%--------------------------------------------------------------------
+server_no_wrap_sequence_number() ->
+ [{doc, "Test that erlang server will renegotiate session when",
+ "max sequence number celing is about to be reached. Although"
+ "in the testcase we use the test option renegotiate_at"
+ " to lower treashold substantially."}].
+
+server_no_wrap_sequence_number(Config) when is_list(Config) ->
+ ServerOpts = ssl_test_lib:ssl_options(server_rsa_verify_opts, Config),
+ ClientOpts = ssl_test_lib:ssl_options(client_rsa_verify_opts, Config),
+
+ {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
+
+ Data = "From erlang to erlang",
+ N = 12,
+
+ Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0},
+ {from, self()},
+ {mfa, {ssl_test_lib,
+ trigger_renegotiate, [[Data, N+2]]}},
+ {options, [{renegotiate_at, N} | 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, no_result, []}},
+ {options, [{reuse_sessions, false} | ClientOpts]}]),
+
+ ssl_test_lib:check_result(Server, ok),
+ ssl_test_lib:close(Server),
+ ssl_test_lib:close(Client).
+renegotiate_dos_mitigate_active() ->
+ [{doc, "Mitigate DOS computational attack by not allowing client to renegotiate many times in a row",
+ "immediately after each other"}].
+renegotiate_dos_mitigate_active(Config) when is_list(Config) ->
+ ServerOpts = ssl_test_lib:ssl_options(server_rsa_verify_opts, Config),
+ ClientOpts = ssl_test_lib:ssl_options(client_rsa_verify_opts, Config),
+
+ {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
+
+ Server =
+ ssl_test_lib:start_server([{node, ServerNode}, {port, 0},
+ {from, self()},
+ {mfa, {ssl_test_lib, send_recv_result_active, []}},
+ {options, ServerOpts}]),
+ Port = ssl_test_lib:inet_port(Server),
+
+ Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port},
+ {host, Hostname},
+ {from, self()},
+ {mfa, {?MODULE,
+ renegotiate_immediately, []}},
+ {options, ClientOpts}]),
+
+ ssl_test_lib:check_result(Client, ok, Server, ok),
+ ssl_test_lib:close(Server),
+ ssl_test_lib:close(Client).
+
+%%--------------------------------------------------------------------
+renegotiate_dos_mitigate_passive() ->
+ [{doc, "Mitigate DOS computational attack by not allowing client to renegotiate many times in a row",
+ "immediately after each other"}].
+renegotiate_dos_mitigate_passive(Config) when is_list(Config) ->
+ ServerOpts = ssl_test_lib:ssl_options(server_rsa_verify_opts, Config),
+ ClientOpts = ssl_test_lib:ssl_options(client_rsa_verify_opts, Config),
+
+ {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
+
+ Server =
+ ssl_test_lib:start_server([{node, ServerNode}, {port, 0},
+ {from, self()},
+ {mfa, {ssl_test_lib, send_recv_result, []}},
+ {options, [{active, false} | ServerOpts]}]),
+ Port = ssl_test_lib:inet_port(Server),
+
+ Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port},
+ {host, Hostname},
+ {from, self()},
+ {mfa, {?MODULE,
+ renegotiate_immediately, []}},
+ {options, ClientOpts}]),
+
+ ssl_test_lib:check_result(Client, ok, Server, ok),
+ ssl_test_lib:close(Server),
+ ssl_test_lib:close(Client).
+
+%%--------------------------------------------------------------------
+renegotiate_dos_mitigate_absolute() ->
+ [{doc, "Mitigate DOS computational attack by not allowing client to initiate renegotiation"}].
+renegotiate_dos_mitigate_absolute(Config) when is_list(Config) ->
+ ServerOpts = ssl_test_lib:ssl_options(server_rsa_verify_opts, Config),
+ ClientOpts = ssl_test_lib:ssl_options(client_rsa_verify_opts, Config),
+
+ {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
+
+ Server =
+ ssl_test_lib:start_server([{node, ServerNode}, {port, 0},
+ {from, self()},
+ {mfa, {ssl_test_lib, send_recv_result_active, []}},
+ {options, [{client_renegotiation, false} | ServerOpts]}]),
+ Port = ssl_test_lib:inet_port(Server),
+
+ Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port},
+ {host, Hostname},
+ {from, self()},
+ {mfa, {?MODULE,
+ renegotiate_rejected,
+ []}},
+ {options, ClientOpts}]),
+
+ ssl_test_lib:check_result(Client, ok, Server, ok),
+ ssl_test_lib:close(Server),
+ ssl_test_lib:close(Client).
+
+%%--------------------------------------------------------------------
+%% Internal functions ------------------------------------------------
+%%--------------------------------------------------------------------
+renegotiate(Socket, Data) ->
+ ct:log("Renegotiating ~n", []),
+ Result = ssl:renegotiate(Socket),
+ ct:log("Result ~p~n", [Result]),
+ ssl:send(Socket, Data),
+ case Result of
+ ok ->
+ ok;
+ Other ->
+ Other
+ end.
+
+renegotiate_reuse_session(Socket, Data) ->
+ %% Make sure session is registered
+ ct:sleep(?SLEEP),
+ renegotiate(Socket, Data).
+
+renegotiate_immediately(Socket) ->
+ _ = ssl_test_lib:active_recv(Socket, 11),
+ ok = ssl:renegotiate(Socket),
+ {error, renegotiation_rejected} = ssl:renegotiate(Socket),
+ ct:sleep(?RENEGOTIATION_DISABLE_TIME + ?SLEEP),
+ ok = ssl:renegotiate(Socket),
+ ct:log("Renegotiated again"),
+ ssl:send(Socket, "Hello world"),
+ ok.
+
+renegotiate_rejected(Socket) ->
+ _ = ssl_test_lib:active_recv(Socket, 11),
+ {error, renegotiation_rejected} = ssl:renegotiate(Socket),
+ {error, renegotiation_rejected} = ssl:renegotiate(Socket),
+ ct:sleep(?RENEGOTIATION_DISABLE_TIME +1),
+ {error, renegotiation_rejected} = ssl:renegotiate(Socket),
+ ct:log("Failed to renegotiate again"),
+ ssl:send(Socket, "Hello world"),
+ ok.
+
+%% First two clauses handles 1/n-1 splitting countermeasure Rizzo/Duong-Beast
+treashold(N, {3,0}) ->
+ (N div 2) + 1;
+treashold(N, {3,1}) ->
+ (N div 2) + 1;
+treashold(N, _) ->
+ N + 1.
+
+erlang_ssl_receive(Socket, Data) ->
+ case ssl_test_lib:active_recv(Socket, length(Data)) of
+ Data ->
+ ok;
+ Other ->
+ ct:fail({{expected, Data}, {got, Other}})
+ end.
diff --git a/lib/ssl/test/ssl_session_SUITE.erl b/lib/ssl/test/ssl_session_SUITE.erl
new file mode 100644
index 0000000000..aa79698a72
--- /dev/null
+++ b/lib/ssl/test/ssl_session_SUITE.erl
@@ -0,0 +1,377 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2007-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_session_SUITE).
+
+%% Note: This directive should only be used in test suites.
+-compile(export_all).
+
+-include("tls_handshake.hrl").
+
+-include_lib("common_test/include/ct.hrl").
+-include_lib("public_key/include/public_key.hrl").
+
+-define(SLEEP, 500).
+-define(EXPIRE, 10).
+
+%%--------------------------------------------------------------------
+%% Common Test interface functions -----------------------------------
+%%--------------------------------------------------------------------
+all() ->
+ [
+ {group, 'tlsv1.2'},
+ {group, 'tlsv1.1'},
+ {group, 'tlsv1'},
+ {group, 'sslv3'},
+ {group, 'dtlsv1.2'},
+ {group, 'dtlsv1'}
+ ].
+
+groups() ->
+ [{'dtlsv1.2', [], session_tests()},
+ {'dtlsv1', [], session_tests()},
+ {'tlsv1.3', [], session_tests()},
+ {'tlsv1.2', [], session_tests()},
+ {'tlsv1.1', [], session_tests()},
+ {'tlsv1', [], session_tests()},
+ {'sslv3', [], session_tests()}
+ ].
+
+session_tests() ->
+ [reuse_session,
+ reuse_session_expired,
+ server_does_not_want_to_reuse_session,
+ no_reuses_session_server_restart_new_cert,
+ no_reuses_session_server_restart_new_cert_file].
+
+
+init_per_suite(Config0) ->
+ catch crypto:stop(),
+ try crypto:start() of
+ ok ->
+ ssl_test_lib:clean_start(),
+ Config = ssl_test_lib:make_rsa_cert(Config0),
+ ssl_test_lib:make_dsa_cert(Config)
+ catch _:_ ->
+ {skip, "Crypto did not start"}
+ end.
+
+end_per_suite(_Config) ->
+ ssl:stop(),
+ application:stop(crypto).
+
+init_per_group(GroupName, Config) ->
+ ssl_test_lib:clean_tls_version(Config),
+ case ssl_test_lib:is_tls_version(GroupName) andalso ssl_test_lib:sufficient_crypto_support(GroupName) of
+ true ->
+ ssl_test_lib:init_tls_version(GroupName, Config);
+ _ ->
+ case ssl_test_lib:sufficient_crypto_support(GroupName) of
+ true ->
+ ssl:start(),
+ Config;
+ false ->
+ {skip, "Missing crypto support"}
+ end
+ 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(reuse_session_expired, Config) ->
+ ssl:stop(),
+ application:load(ssl),
+ ssl_test_lib:clean_env(),
+ application:set_env(ssl, session_lifetime, ?EXPIRE),
+ application:set_env(ssl, session_delay_cleanup_time, 500),
+ ssl:start(),
+ ct:timetrap({seconds, 30}),
+ Config;
+init_per_testcase(_, Config) ->
+ ct:timetrap({seconds, 15}),
+ Config.
+
+end_per_testcase(_TestCase, Config) ->
+ Config.
+
+%%--------------------------------------------------------------------
+%% Test Cases --------------------------------------------------------
+%%--------------------------------------------------------------------
+
+reuse_session() ->
+ [{doc,"Test reuse of sessions (short handshake)"}].
+reuse_session(Config) when is_list(Config) ->
+ ClientOpts = ssl_test_lib:ssl_options(client_rsa_verify_opts, Config),
+ ServerOpts = ssl_test_lib:ssl_options(server_rsa_verify_opts, Config),
+
+ ssl_test_lib:reuse_session(ClientOpts, ServerOpts, Config).
+%%--------------------------------------------------------------------
+reuse_session_expired() ->
+ [{doc,"Test sessions is not reused when it has expired"}].
+reuse_session_expired(Config) when is_list(Config) ->
+ ClientOpts = ssl_test_lib:ssl_options(client_rsa_verify_opts, Config),
+ ServerOpts = ssl_test_lib:ssl_options(server_rsa_verify_opts, Config),
+ {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
+
+ Server0 =
+ ssl_test_lib:start_server([{node, ServerNode}, {port, 0},
+ {from, self()},
+ {mfa, {ssl_test_lib, no_result, []}},
+ {tcp_options, [{active, false}]},
+ {options, ServerOpts}]),
+ Port0 = ssl_test_lib:inet_port(Server0),
+
+ Client0 = ssl_test_lib:start_client([{node, ClientNode},
+ {port, Port0}, {host, Hostname},
+ {mfa, {ssl_test_lib, session_id, []}},
+ {from, self()}, {options, [{reuse_sessions, save} | ClientOpts]}]),
+ Server0 ! listen,
+
+ Client1 = ssl_test_lib:start_client([{node, ClientNode},
+ {port, Port0}, {host, Hostname},
+ {mfa, {ssl_test_lib, session_id, []}},
+ {from, self()}, {options, ClientOpts}]),
+
+ SID = receive
+ {Client0, Id0} ->
+ Id0
+ end,
+
+ receive
+ {Client1, SID} ->
+ ok
+ after ?SLEEP ->
+ ct:fail(session_not_reused)
+ end,
+
+ Server0 ! listen,
+
+ %% Make sure session is unregistered due to expiration
+ ct:sleep((?EXPIRE*2)),
+
+ make_sure_expired(Hostname, Port0, SID),
+
+ Client2 =
+ ssl_test_lib:start_client([{node, ClientNode},
+ {port, Port0}, {host, Hostname},
+ {mfa, {ssl_test_lib, session_id, []}},
+ {from, self()}, {options, ClientOpts}]),
+ receive
+ {Client2, SID} ->
+ ct:fail(session_reused_when_session_expired);
+ {Client2, _} ->
+ ok
+ end,
+ process_flag(trap_exit, false),
+ ssl_test_lib:close(Server0),
+ ssl_test_lib:close(Client0),
+ ssl_test_lib:close(Client1),
+ ssl_test_lib:close(Client2).
+
+make_sure_expired(Host, Port, Id) ->
+ {status, _, _, StatusInfo} = sys:get_status(whereis(ssl_manager)),
+ [_, _,_, _, Prop] = StatusInfo,
+ State = ssl_test_lib:state(Prop),
+ ClientCache = element(2, State),
+
+ case ssl_session_cache:lookup(ClientCache, {{Host, Port}, Id}) of
+ undefined ->
+ ok;
+ #session{is_resumable = false} ->
+ ok;
+ _ ->
+ ct:sleep(?SLEEP),
+ make_sure_expired(Host, Port, Id)
+ end.
+
+%%--------------------------------------------------------------------
+server_does_not_want_to_reuse_session() ->
+ [{doc,"Test reuse of sessions (short handshake)"}].
+server_does_not_want_to_reuse_session(Config) when is_list(Config) ->
+ ClientOpts = ssl_test_lib:ssl_options(client_rsa_verify_opts, Config),
+ ServerOpts = ssl_test_lib:ssl_options(server_rsa_verify_opts, Config),
+ {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
+
+ Server =
+ ssl_test_lib:start_server([{node, ServerNode}, {port, 0},
+ {from, self()},
+ {mfa, {ssl_test_lib, session_info_result, []}},
+ {options, [{reuse_session, fun(_,_,_,_) ->
+ false
+ end} |
+ ServerOpts]}]),
+ Port = ssl_test_lib:inet_port(Server),
+ Client0 =
+ ssl_test_lib:start_client([{node, ClientNode},
+ {port, Port}, {host, Hostname},
+ {mfa, {ssl_test_lib, no_result, []}},
+ {from, self()}, {options, ClientOpts}]),
+ SessionInfo =
+ receive
+ {Server, Info} ->
+ Info
+ end,
+
+ Server ! {listen, {mfa, {ssl_test_lib, no_result, []}}},
+
+ %% Make sure session is registered
+ ct:sleep(?SLEEP),
+
+ Client1 =
+ ssl_test_lib:start_client([{node, ClientNode},
+ {port, Port}, {host, Hostname},
+ {mfa, {ssl_test_lib, session_info_result, []}},
+ {from, self()}, {options, ClientOpts}]),
+ receive
+ {Client1, SessionInfo} ->
+ ct:fail(session_reused_when_server_does_not_want_to);
+ {Client1, _Other} ->
+ ok
+ end,
+ ssl_test_lib:close(Client0),
+ ssl_test_lib:close(Server),
+ ssl_test_lib:close(Client1).
+
+no_reuses_session_server_restart_new_cert() ->
+ [{doc,"Check that a session is not reused if the server is restarted with a new cert."}].
+no_reuses_session_server_restart_new_cert(Config) when is_list(Config) ->
+
+ ClientOpts = ssl_test_lib:ssl_options(client_rsa_opts, Config),
+ ServerOpts = ssl_test_lib:ssl_options(server_rsa_verify_opts, Config),
+ DsaServerOpts = ssl_test_lib:ssl_options(server_dsa_verify_opts, Config),
+ DsaClientOpts = ssl_test_lib:ssl_options(client_dsa_opts, Config),
+ {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
+
+ Server =
+ ssl_test_lib:start_server([{node, ServerNode}, {port, 0},
+ {from, self()},
+ {mfa, {ssl_test_lib, session_info_result, []}},
+ {options, ServerOpts}]),
+ Port = ssl_test_lib:inet_port(Server),
+ Client0 =
+ ssl_test_lib:start_client([{node, ClientNode},
+ {port, Port}, {host, Hostname},
+ {mfa, {ssl_test_lib, no_result, []}},
+ {from, self()}, {options, ClientOpts}]),
+ SessionInfo =
+ receive
+ {Server, Info} ->
+ Info
+ end,
+
+ %% Make sure session is registered
+ ct:sleep(?SLEEP),
+ Monitor = erlang:monitor(process, Server),
+ ssl_test_lib:close(Server),
+ ssl_test_lib:close(Client0),
+ receive
+ {'DOWN', Monitor, _, _, _} ->
+ ok
+ end,
+
+ Server1 =
+ ssl_test_lib:start_server([{node, ServerNode}, {port, Port},
+ {from, self()},
+ {mfa, {ssl_test_lib, no_result, []}},
+ {options, [{reuseaddr, true} | DsaServerOpts]}]),
+
+ Client1 =
+ ssl_test_lib:start_client([{node, ClientNode},
+ {port, Port}, {host, Hostname},
+ {mfa, {ssl_test_lib, session_info_result, []}},
+ {from, self()}, {options, DsaClientOpts}]),
+ receive
+ {Client1, SessionInfo} ->
+ ct:fail(session_reused_when_server_has_new_cert);
+ {Client1, _Other} ->
+ ok
+ end,
+ ssl_test_lib:close(Server1),
+ ssl_test_lib:close(Client1).
+
+%%--------------------------------------------------------------------
+no_reuses_session_server_restart_new_cert_file() ->
+ [{doc,"Check that a session is not reused if a server is restarted with a new "
+ "cert contained in a file with the same name as the old cert."}].
+
+no_reuses_session_server_restart_new_cert_file(Config) when is_list(Config) ->
+ ClientOpts = ssl_test_lib:ssl_options(client_rsa_opts, Config),
+ ServerOpts = ssl_test_lib:ssl_options(server_rsa_verify_opts, Config),
+ DsaServerOpts = ssl_test_lib:ssl_options(server_dsa_verify_opts, Config),
+ PrivDir = proplists:get_value(priv_dir, Config),
+
+ NewServerOpts0 = ssl_test_lib:new_config(PrivDir, ServerOpts),
+ {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
+
+ Server =
+ ssl_test_lib:start_server([{node, ServerNode}, {port, 0},
+ {from, self()},
+ {mfa, {ssl_test_lib, session_info_result, []}},
+ {options, NewServerOpts0}]),
+ Port = ssl_test_lib:inet_port(Server),
+ Client0 =
+ ssl_test_lib:start_client([{node, ClientNode},
+ {port, Port}, {host, Hostname},
+ {mfa, {ssl_test_lib, no_result, []}},
+ {from, self()}, {options, ClientOpts}]),
+ SessionInfo =
+ receive
+ {Server, Info} ->
+ Info
+ end,
+
+ %% Make sure session is registered and we get
+ %% new file time stamp when calling new_config!
+ ct:sleep(?SLEEP* 2),
+ ssl_test_lib:close(Server),
+ ssl_test_lib:close(Client0),
+
+ ssl:clear_pem_cache(),
+
+ NewServerOpts1 = ssl_test_lib:new_config(PrivDir, DsaServerOpts),
+
+ Server1 =
+ ssl_test_lib:start_server([{node, ServerNode}, {port, Port},
+ {from, self()},
+ {mfa, {ssl_test_lib, no_result, []}},
+ {options, [{reuseaddr, true} | NewServerOpts1]}]),
+ Client1 =
+ ssl_test_lib:start_client([{node, ClientNode},
+ {port, Port}, {host, Hostname},
+ {mfa, {ssl_test_lib, session_info_result, []}},
+ {from, self()}, {options, ClientOpts}]),
+ receive
+ {Client1, SessionInfo} ->
+ ct:fail(session_reused_when_server_has_new_cert);
+ {Client1, _Other} ->
+ ok
+ end,
+ ssl_test_lib:close(Server1),
+ ssl_test_lib:close(Client1).
+
+%%--------------------------------------------------------------------
+%% Internal functions ------------------------------------------------
+%%--------------------------------------------------------------------
diff --git a/lib/ssl/test/ssl_sni_SUITE.erl b/lib/ssl/test/ssl_sni_SUITE.erl
index 7629d75100..e68ea2c99d 100644
--- a/lib/ssl/test/ssl_sni_SUITE.erl
+++ b/lib/ssl/test/ssl_sni_SUITE.erl
@@ -36,7 +36,6 @@ all() ->
[{group, 'tlsv1.2'},
{group, 'tlsv1.1'},
{group, 'tlsv1'},
- {group, 'sslv3'},
{group, 'dtlsv1.2'},
{group, 'dtlsv1'}
].
@@ -46,7 +45,6 @@ groups() ->
{'tlsv1.2', [], sni_tests()},
{'tlsv1.1', [], sni_tests()},
{'tlsv1', [], sni_tests()},
- {'sslv3', [], sni_tests()},
{'dtlsv1.2', [], sni_tests()},
{'dtlsv1', [], sni_tests()}
].
@@ -61,7 +59,8 @@ sni_tests() ->
dns_name,
ip_fallback,
no_ip_fallback,
- dns_name_reuse].
+ dns_name_reuse,
+ customize_hostname_check].
init_per_suite(Config0) ->
catch crypto:stop(),
@@ -88,12 +87,10 @@ end_per_suite(_) ->
ssl:stop(),
application:stop(crypto).
-init_per_testcase(TestCase, Config) when TestCase == ip_fallback;
- TestCase == no_ip_fallback;
- TestCase == dns_name_reuse ->
+init_per_testcase(customize_hostname_check, Config) ->
ssl_test_lib:ct_log_supported_protocol_versions(Config),
- ct:log("Ciphers: ~p~n ", [ ssl:cipher_suites()]),
- ct:timetrap({seconds, 20}),
+ ssl_test_lib:clean_start(),
+ ct:timetrap({seconds, 5}),
Config;
init_per_testcase(_TestCase, Config) ->
ssl_test_lib:ct_log_supported_protocol_versions(Config),
@@ -236,7 +233,60 @@ dns_name_reuse(Config) ->
{mfa, {ssl_test_lib, session_info_result, []}},
{from, self()}, {options, [{verify, verify_peer} | ClientConf]}]),
- ssl_test_lib:check_client_alert(Client1, handshake_failure).
+ ssl_test_lib:check_client_alert(Client1, handshake_failure),
+ ssl_test_lib:close(Client0).
+
+
+customize_hostname_check() ->
+ [{doc,"Test option customize_hostname_check."}].
+customize_hostname_check(Config) when is_list(Config) ->
+ Ext = [#'Extension'{extnID = ?'id-ce-subjectAltName',
+ extnValue = [{dNSName, "*.example.org"}],
+ critical = false}
+ ],
+ #{server_config := ServerOpts0,
+ client_config := ClientOpts0} = ssl_test_lib:make_cert_chains_pem(rsa, [{server_chain,
+ [[],
+ [],
+ [{extensions, Ext}]
+ ]}],
+ Config, "https_hostname_convention"),
+ ClientOpts = ssl_test_lib:ssl_options(ClientOpts0, Config),
+ ServerOpts = ssl_test_lib:ssl_options(ServerOpts0, Config),
+
+ {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
+
+ Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0},
+ {host, Hostname},
+ {from, self()},
+ {mfa, {ssl_test_lib, send_recv_result_active, []}},
+ {options, ServerOpts}]),
+ Port = ssl_test_lib:inet_port(Server),
+
+ CustomFun = public_key:pkix_verify_hostname_match_fun(https),
+
+ Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port},
+ {host, Hostname},
+ {from, self()},
+ {mfa, {ssl_test_lib, send_recv_result_active, []}},
+ {options,
+ [{verify, verify_peer},
+ {server_name_indication, "other.example.org"},
+ {customize_hostname_check,
+ [{match_fun, CustomFun}]} | ClientOpts]
+ }]),
+ ssl_test_lib:check_result(Server, ok, Client, ok),
+
+ Server ! {listen, {mfa, {ssl_test_lib, no_result, []}}},
+
+ Client1 = ssl_test_lib:start_client_error([{node, ClientNode}, {port, Port},
+ {host, Hostname},
+ {from, self()},
+ {mfa, {ssl_test_lib, no_result, []}},
+ {options, [{verify, verify_peer},
+ {server_name_indication, "other.example.org"} | ClientOpts]}
+ ]),
+ ssl_test_lib:check_client_alert(Server, Client1, handshake_failure).
%%--------------------------------------------------------------------
%% Internal Functions ------------------------------------------------
diff --git a/lib/ssl/test/ssl_socket_SUITE.erl b/lib/ssl/test/ssl_socket_SUITE.erl
new file mode 100644
index 0000000000..d648f2f9e1
--- /dev/null
+++ b/lib/ssl/test/ssl_socket_SUITE.erl
@@ -0,0 +1,437 @@
+%%
+%% 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_socket_SUITE).
+
+%% Note: This directive should only be used in test suites.
+-compile(export_all).
+
+-include_lib("common_test/include/ct.hrl").
+-include_lib("public_key/include/public_key.hrl").
+
+-define(SLEEP, 500).
+%%--------------------------------------------------------------------
+%% Common Test interface functions -----------------------------------
+%%--------------------------------------------------------------------
+all() ->
+ [
+ {group, tls},
+ {group, dtls}
+ ].
+
+groups() ->
+ [
+ {tls,[], socket_tests() ++ raw_inet_opt()},
+ {dtls,[], socket_tests()}
+ ].
+
+socket_tests() ->
+ [
+ getstat,
+ socket_options,
+ invalid_inet_get_option,
+ invalid_inet_get_option_not_list,
+ invalid_inet_get_option_improper_list,
+ invalid_inet_set_option,
+ invalid_inet_set_option_not_list,
+ invalid_inet_set_option_improper_list
+ ].
+
+raw_inet_opt() ->
+ [
+ raw_inet_option
+ ].
+
+
+init_per_suite(Config0) ->
+ catch crypto:stop(),
+ try crypto:start() of
+ ok ->
+ ssl_test_lib:clean_start(),
+ ssl_test_lib:make_rsa_cert(Config0)
+ catch _:_ ->
+ {skip, "Crypto did not start"}
+ end.
+
+end_per_suite(_Config) ->
+ ssl:stop(),
+ application:unload(ssl),
+ application:stop(crypto).
+
+init_per_group(dtls, Config) ->
+ [{protocol_opts, [{protocol, dtls}]} | proplists:delete(protocol_opts, Config)];
+init_per_group(tls, Config) ->
+ [{protocol_opts, [{protocol, tls}]} | proplists:delete(protocol_opts, Config)];
+init_per_group(_GroupName, Config) ->
+ [{client_type, erlang},
+ {server_type, erlang} | Config].
+
+end_per_group(_GroupName, Config) ->
+ Config.
+
+init_per_testcase(raw_inet_option, Config) ->
+ ct:timetrap({seconds, 5}),
+ case os:type() of
+ {unix,linux} ->
+ Config;
+ _ ->
+ {skip, "Raw options are platform-specific"}
+ end;
+init_per_testcase(_TestCase, Config) ->
+ ct:timetrap({seconds, 5}),
+ Config.
+
+end_per_testcase(_TestCase, Config) ->
+ Config.
+
+%%--------------------------------------------------------------------
+%% Test Cases --------------------------------------------------------
+%%--------------------------------------------------------------------
+
+getstat() ->
+ [{doc,"Test API function getstat/2"}].
+
+getstat(Config) when is_list(Config) ->
+ ClientOpts = ?config(client_rsa_opts, Config),
+ ServerOpts = ?config(server_rsa_opts, Config),
+ {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
+ Server1 =
+ ssl_test_lib:start_server([{node, ServerNode}, {port, 0},
+ {from, self()},
+ {mfa, {ssl_test_lib, send_recv_result, []}},
+ {options, [{active, false} | ServerOpts]}]),
+ Port1 = ssl_test_lib:inet_port(Server1),
+ Server2 =
+ ssl_test_lib:start_server([{node, ServerNode}, {port, 0},
+ {from, self()},
+ {mfa, {ssl_test_lib, send_recv_result, []}},
+ {options, [{active, false} | ServerOpts]}]),
+ Port2 = ssl_test_lib:inet_port(Server2),
+ {ok, ActiveC} = rpc:call(ClientNode, ssl, connect,
+ [Hostname,Port1,[{active, once}|ClientOpts]]),
+ {ok, PassiveC} = rpc:call(ClientNode, ssl, connect,
+ [Hostname,Port2,[{active, false}|ClientOpts]]),
+
+ ct:log("Testcase ~p, Client ~p Servers ~p, ~p ~n",
+ [self(), self(), Server1, Server2]),
+
+ %% We only check that the values are non-zero initially
+ %% (due to the handshake), and that sending more changes the values.
+
+ %% Passive socket.
+
+ {ok, InitialStats} = ssl:getstat(PassiveC),
+ ct:pal("InitialStats ~p~n", [InitialStats]),
+ [true] = lists:usort([0 =/= proplists:get_value(Name, InitialStats)
+ || Name <- [recv_cnt, recv_oct, recv_avg, recv_max, send_cnt, send_oct, send_avg, send_max]]),
+
+ ok = ssl:send(PassiveC, "Hello world"),
+ wait_for_send(PassiveC),
+ {ok, SStats} = ssl:getstat(PassiveC, [send_cnt, send_oct]),
+ ct:pal("SStats ~p~n", [SStats]),
+ [true] = lists:usort([proplists:get_value(Name, SStats) =/= proplists:get_value(Name, InitialStats)
+ || Name <- [send_cnt, send_oct]]),
+
+ %% Active socket.
+
+ {ok, InitialAStats} = ssl:getstat(ActiveC),
+ ct:pal("InitialAStats ~p~n", [InitialAStats]),
+ [true] = lists:usort([0 =/= proplists:get_value(Name, InitialAStats)
+ || Name <- [recv_cnt, recv_oct, recv_avg, recv_max, send_cnt, send_oct, send_avg, send_max]]),
+
+ _ = receive
+ {ssl, ActiveC, _} ->
+ ok
+ after
+ ?SLEEP ->
+ exit(timeout)
+ end,
+
+ ok = ssl:send(ActiveC, "Hello world"),
+ wait_for_send(ActiveC),
+ {ok, ASStats} = ssl:getstat(ActiveC, [send_cnt, send_oct]),
+ ct:pal("ASStats ~p~n", [ASStats]),
+ [true] = lists:usort([proplists:get_value(Name, ASStats) =/= proplists:get_value(Name, InitialAStats)
+ || Name <- [send_cnt, send_oct]]),
+
+ ok.
+%%--------------------------------------------------------------------
+socket_options() ->
+ [{doc,"Test API function getopts/2 and setopts/2"}].
+
+socket_options(Config) when is_list(Config) ->
+ ClientOpts = ssl_test_lib:ssl_options(client_rsa_opts, Config),
+ ServerOpts = ssl_test_lib:ssl_options(server_rsa_opts, Config),
+ {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
+ Values = [{mode, list}, {active, true}],
+ %% Shall be the reverse order of Values!
+ Options = [active, mode],
+
+ NewValues = [{mode, binary}, {active, once}],
+ %% Shall be the reverse order of NewValues!
+ NewOptions = [active, mode],
+
+ Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0},
+ {from, self()},
+ {mfa, {?MODULE, socket_options_result,
+ [Options, Values, NewOptions, NewValues]}},
+ {options, ServerOpts}]),
+ Port = ssl_test_lib:inet_port(Server),
+ Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port},
+ {host, Hostname},
+ {from, self()},
+ {mfa, {?MODULE, socket_options_result,
+ [Options, Values, NewOptions, NewValues]}},
+ {options, ClientOpts}]),
+
+ ssl_test_lib:check_result(Server, ok, Client, ok),
+
+ ssl_test_lib:close(Server),
+
+ {ok, Listen} = ssl:listen(0, ServerOpts),
+ {ok,[{mode,list}]} = ssl:getopts(Listen, [mode]),
+ ok = ssl:setopts(Listen, [{mode, binary}]),
+ {ok,[{mode, binary}]} = ssl:getopts(Listen, [mode]),
+ {ok,[{recbuf, _}]} = ssl:getopts(Listen, [recbuf]),
+ ssl:close(Listen).
+
+%%--------------------------------------------------------------------
+raw_inet_option() ->
+ [{doc,"Ensure that a single 'raw' option is passed to ssl:listen correctly."}].
+
+raw_inet_option(Config) when is_list(Config) ->
+ % 'raw' option values are platform-specific; these are the Linux values:
+ IpProtoTcp = 6,
+ % Use TCP_KEEPIDLE, because (e.g.) TCP_MAXSEG can't be read back reliably.
+ TcpKeepIdle = 4,
+ KeepAliveTimeSecs = 55,
+ LOptions = [{raw, IpProtoTcp, TcpKeepIdle, <<KeepAliveTimeSecs:32/native>>}],
+ {ok, LSocket} = ssl:listen(0, LOptions),
+ % Per http://www.erlang.org/doc/man/inet.html#getopts-2, we have to specify
+ % exactly which raw option we want, and the size of the buffer.
+ {ok, [{raw, IpProtoTcp, TcpKeepIdle, <<KeepAliveTimeSecs:32/native>>}]} =
+ ssl:getopts(LSocket, [{raw, IpProtoTcp, TcpKeepIdle, 4}]).
+
+%%--------------------------------------------------------------------
+
+invalid_inet_get_option() ->
+ [{doc,"Test handling of invalid inet options in getopts"}].
+
+invalid_inet_get_option(Config) when is_list(Config) ->
+ ClientOpts = ssl_test_lib:ssl_options(client_rsa_opts, Config),
+ ServerOpts = ssl_test_lib:ssl_options(server_rsa_opts, Config),
+ {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
+ Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0},
+ {from, self()},
+ {mfa, {?MODULE, get_invalid_inet_option, []}},
+ {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, no_result, []}},
+ {options, ClientOpts}]),
+
+ ct:log("Testcase ~p, Client ~p Server ~p ~n",
+ [self(), Client, Server]),
+
+ ssl_test_lib:check_result(Server, ok),
+ ssl_test_lib:close(Server),
+ ssl_test_lib:close(Client).
+
+%%--------------------------------------------------------------------
+invalid_inet_get_option_not_list() ->
+ [{doc,"Test handling of invalid type in getopts"}].
+
+invalid_inet_get_option_not_list(Config) when is_list(Config) ->
+ ClientOpts = ssl_test_lib:ssl_options(client_rsa_opts, Config),
+ ServerOpts = ssl_test_lib:ssl_options(server_rsa_opts, Config),
+ {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
+ Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0},
+ {from, self()},
+ {mfa, {?MODULE, get_invalid_inet_option_not_list, []}},
+ {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, no_result, []}},
+ {options, ClientOpts}]),
+
+ ct:log("Testcase ~p, Client ~p Server ~p ~n",
+ [self(), Client, Server]),
+
+ ssl_test_lib:check_result(Server, ok),
+ ssl_test_lib:close(Server),
+ ssl_test_lib:close(Client).
+
+%%--------------------------------------------------------------------
+invalid_inet_get_option_improper_list() ->
+ [{doc,"Test handling of invalid type in getopts"}].
+
+invalid_inet_get_option_improper_list(Config) when is_list(Config) ->
+ ClientOpts = ssl_test_lib:ssl_options(client_rsa_opts, Config),
+ ServerOpts = ssl_test_lib:ssl_options(server_rsa_opts, Config),
+ {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
+ Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0},
+ {from, self()},
+ {mfa, {?MODULE, get_invalid_inet_option_improper_list, []}},
+ {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, no_result, []}},
+ {options, ClientOpts}]),
+
+ ct:log("Testcase ~p, Client ~p Server ~p ~n",
+ [self(), Client, Server]),
+
+ ssl_test_lib:check_result(Server, ok),
+ ssl_test_lib:close(Server),
+ ssl_test_lib:close(Client).
+
+%%--------------------------------------------------------------------
+invalid_inet_set_option() ->
+ [{doc,"Test handling of invalid inet options in setopts"}].
+
+invalid_inet_set_option(Config) when is_list(Config) ->
+ ClientOpts = ssl_test_lib:ssl_options(client_rsa_opts, Config),
+ ServerOpts = ssl_test_lib:ssl_options(server_rsa_opts, Config),
+ {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
+ Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0},
+ {from, self()},
+ {mfa, {?MODULE, set_invalid_inet_option, []}},
+ {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, no_result, []}},
+ {options, ClientOpts}]),
+
+ ct:log("Testcase ~p, Client ~p Server ~p ~n",
+ [self(), Client, Server]),
+
+ ssl_test_lib:check_result(Server, ok),
+ ssl_test_lib:close(Server),
+ ssl_test_lib:close(Client).
+
+%%--------------------------------------------------------------------
+invalid_inet_set_option_not_list() ->
+ [{doc,"Test handling of invalid type in setopts"}].
+
+invalid_inet_set_option_not_list(Config) when is_list(Config) ->
+ ClientOpts = ssl_test_lib:ssl_options(client_rsa_opts, Config),
+ ServerOpts = ssl_test_lib:ssl_options(server_rsa_opts, Config),
+ {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
+ Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0},
+ {from, self()},
+ {mfa, {?MODULE, set_invalid_inet_option_not_list, []}},
+ {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, no_result, []}},
+ {options, ClientOpts}]),
+
+ ct:log("Testcase ~p, Client ~p Server ~p ~n",
+ [self(), Client, Server]),
+
+ ssl_test_lib:check_result(Server, ok),
+ ssl_test_lib:close(Server),
+ ssl_test_lib:close(Client).
+
+%%--------------------------------------------------------------------
+invalid_inet_set_option_improper_list() ->
+ [{doc,"Test handling of invalid tye in setopts"}].
+
+invalid_inet_set_option_improper_list(Config) when is_list(Config) ->
+ ClientOpts = ssl_test_lib:ssl_options(client_rsa_opts, Config),
+ ServerOpts = ssl_test_lib:ssl_options(server_rsa_opts, Config),
+ {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
+ Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0},
+ {from, self()},
+ {mfa, {?MODULE, set_invalid_inet_option_improper_list, []}},
+ {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, no_result, []}},
+ {options, ClientOpts}]),
+
+ ct:log("Testcase ~p, Client ~p Server ~p ~n",
+ [self(), Client, Server]),
+
+ ssl_test_lib:check_result(Server, ok),
+ ssl_test_lib:close(Server),
+ ssl_test_lib:close(Client).
+
+
+%%--------------------------------------------------------------------
+%% Internal functions ------------------------------------------------
+%%--------------------------------------------------------------------
+socket_options_result(Socket, Options, DefaultValues, NewOptions, NewValues) ->
+ %% Test get/set emulated opts
+ {ok, DefaultValues} = ssl:getopts(Socket, Options),
+ ssl:setopts(Socket, NewValues),
+ {ok, NewValues} = ssl:getopts(Socket, NewOptions),
+ %% Test get/set inet opts
+ {ok,[{reuseaddr, _}]} = ssl:getopts(Socket, [reuseaddr]),
+ {ok, All} = ssl:getopts(Socket, []),
+ ct:log("All opts ~p~n", [All]),
+ ok.
+
+get_invalid_inet_option(Socket) ->
+ {error, {options, {socket_options, foo, _}}} = ssl:getopts(Socket, [foo]),
+ ok.
+
+get_invalid_inet_option_not_list(Socket) ->
+ {error, {options, {socket_options, some_invalid_atom_here}}}
+ = ssl:getopts(Socket, some_invalid_atom_here),
+ ok.
+
+get_invalid_inet_option_improper_list(Socket) ->
+ {error, {options, {socket_options, foo,_}}} = ssl:getopts(Socket, [packet | foo]),
+ ok.
+
+set_invalid_inet_option(Socket) ->
+ {error, {options, {socket_options, {packet, foo}}}} = ssl:setopts(Socket, [{packet, foo}]),
+ {error, {options, {socket_options, {header, foo}}}} = ssl:setopts(Socket, [{header, foo}]),
+ {error, {options, {socket_options, {active, foo}}}} = ssl:setopts(Socket, [{active, foo}]),
+ {error, {options, {socket_options, {mode, foo}}}} = ssl:setopts(Socket, [{mode, foo}]),
+ ok.
+
+set_invalid_inet_option_not_list(Socket) ->
+ {error, {options, {not_a_proplist, some_invalid_atom_here}}}
+ = ssl:setopts(Socket, some_invalid_atom_here),
+ ok.
+
+set_invalid_inet_option_improper_list(Socket) ->
+ {error, {options, {not_a_proplist, [{packet, 0} | {foo, 2}]}}} =
+ ssl:setopts(Socket, [{packet, 0} | {foo, 2}]),
+ ok.
+
+wait_for_send(Socket) ->
+ %% Make sure TLS process processed send message event
+ _ = ssl:connection_information(Socket).
+
diff --git a/lib/ssl/test/ssl_test_lib.erl b/lib/ssl/test/ssl_test_lib.erl
index c791f438d0..7009a628f1 100644
--- a/lib/ssl/test/ssl_test_lib.erl
+++ b/lib/ssl/test/ssl_test_lib.erl
@@ -218,6 +218,55 @@ start_server_transport_control(Args) ->
Result
end.
+start_erlang_client_and_openssl_server_with_opts(Config, ErlangClientOpts, OpensslServerOpts, Data, Callback) ->
+ process_flag(trap_exit, true),
+ ServerOpts = ssl_test_lib:ssl_options(server_rsa_verify_opts, Config),
+ ClientOpts0 = ssl_test_lib:ssl_options(client_rsa_verify_opts, Config),
+ ClientOpts = ErlangClientOpts ++ ClientOpts0,
+
+ {ClientNode, _, Hostname} = ssl_test_lib:run_where(Config),
+
+ Data = "From openssl to erlang",
+
+ Port = ssl_test_lib:inet_port(node()),
+ CaCertFile = proplists:get_value(cacertfile, ServerOpts),
+ CertFile = proplists:get_value(certfile, ServerOpts),
+ KeyFile = proplists:get_value(keyfile, ServerOpts),
+ Version = ssl_test_lib:protocol_version(Config),
+
+ Exe = "openssl",
+ Args = case OpensslServerOpts of
+ [] ->
+ ["s_server", "-accept",
+ integer_to_list(Port), ssl_test_lib:version_flag(Version),
+ "-CAfile", CaCertFile,
+ "-cert", CertFile,"-key", KeyFile];
+ [Opt, Value] ->
+ ["s_server", Opt, Value, "-accept",
+ integer_to_list(Port), ssl_test_lib:version_flag(Version),
+ "-CAfile", CaCertFile,
+ "-cert", CertFile,"-key", KeyFile]
+ end,
+
+ OpensslPort = ssl_test_lib:portable_open_port(Exe, Args),
+
+ ssl_test_lib:wait_for_openssl_server(Port, proplists:get_value(protocol, Config)),
+
+ Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port},
+ {host, Hostname},
+ {from, self()},
+ {mfa, {?MODULE,
+ active_recv, [length(Data)]}},
+ {options, ClientOpts}]),
+
+ Callback(Client, OpensslPort),
+
+ %% 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).
+
transport_accept_abuse(Opts) ->
Port = proplists:get_value(port, Opts),
@@ -233,6 +282,34 @@ transport_accept_abuse(Opts) ->
_ = ssl:handshake(AcceptSocket, infinity),
Pid ! {self(), ok}.
+start_erlang_server_and_openssl_client_with_opts(Config, ErlangServerOpts, OpenSSLClientOpts, Data, Callback) ->
+ process_flag(trap_exit, true),
+ ServerOpts0 = ssl_test_lib:ssl_options(server_rsa_opts, Config),
+ ServerOpts = ErlangServerOpts ++ ServerOpts0,
+
+ {_, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
+
+
+ Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0},
+ {from, self()},
+ {mfa, {?MODULE, active_recv, [length(Data)]}},
+ {options, ServerOpts}]),
+ Port = ssl_test_lib:inet_port(Server),
+ Version = ssl_test_lib:protocol_version(Config),
+
+ Exe = "openssl",
+ Args = ["s_client"] ++ OpenSSLClientOpts ++ ["-msg", "-connect",
+ hostname_format(Hostname) ++ ":" ++ integer_to_list(Port),
+ ssl_test_lib:version_flag(Version)],
+
+ OpenSslPort = ssl_test_lib:portable_open_port(Exe, Args),
+
+ Callback(Server, OpenSslPort),
+
+ ssl_test_lib:close(Server),
+
+ ssl_test_lib:close_port(OpenSslPort),
+ process_flag(trap_exit, false).
transport_switch_control(Opts) ->
Port = proplists:get_value(port, Opts),
@@ -586,30 +663,6 @@ cert_options(Config) ->
{ssl_imp, new}]},
{server_opts, [{ssl_imp, new},{reuseaddr, true}, {cacertfile, ServerCaCertFile},
{certfile, ServerCertFile}, {keyfile, ServerKeyFile}]},
- {client_psk, [{ssl_imp, new},
- {psk_identity, "Test-User"},
- {user_lookup_fun, {fun user_lookup/3, PskSharedSecret}}]},
- {server_psk, [{ssl_imp, new},{reuseaddr, true},
- {certfile, ServerCertFile}, {keyfile, ServerKeyFile},
- {user_lookup_fun, {fun user_lookup/3, PskSharedSecret}}]},
- {server_psk_hint, [{ssl_imp, new},{reuseaddr, true},
- {certfile, ServerCertFile}, {keyfile, ServerKeyFile},
- {psk_identity, "HINT"},
- {user_lookup_fun, {fun user_lookup/3, PskSharedSecret}}]},
- {server_psk_anon, [{ssl_imp, new},{reuseaddr, true},
- {user_lookup_fun, {fun user_lookup/3, PskSharedSecret}}]},
- {server_psk_anon_hint, [{ssl_imp, new},{reuseaddr, true},
- {psk_identity, "HINT"},
- {user_lookup_fun, {fun user_lookup/3, PskSharedSecret}}]},
- {client_srp, [{ssl_imp, new},
- {srp_identity, {"Test-User", "secret"}}]},
- {server_srp, [{ssl_imp, new},{reuseaddr, true},
- {certfile, ServerCertFile}, {keyfile, ServerKeyFile},
- {user_lookup_fun, {fun user_lookup/3, undefined}},
- {ciphers, srp_suites()}]},
- {server_srp_anon, [{ssl_imp, new},{reuseaddr, true},
- {user_lookup_fun, {fun user_lookup/3, undefined}},
- {ciphers, srp_anon_suites()}]},
{server_verification_opts, [{ssl_imp, new},{reuseaddr, true},
{cacertfile, ClientCaCertFile},
{certfile, ServerCertFile}, {keyfile, ServerKeyFile}]},
@@ -650,15 +703,32 @@ make_dsa_cert(Config) ->
[{server_dsa_opts, ServerConf},
{server_dsa_verify_opts, [{verify, verify_peer} | ServerConf]},
- {client_dsa_opts, ClientConf},
- {server_srp_dsa, [{user_lookup_fun, {fun user_lookup/3, undefined}},
- {ciphers, srp_dss_suites()} | ServerConf]},
- {client_srp_dsa, [{srp_identity, {"Test-User", "secret"}}
- | ClientConf]}
+ {client_dsa_opts, ClientConf}
| Config];
false ->
Config
end.
+
+
+make_cert_chains_der(Alg, UserConf) ->
+ ClientChain = proplists:get_value(client_chain, UserConf, default_cert_chain_conf()),
+ ServerChain = proplists:get_value(server_chain, UserConf, default_cert_chain_conf()),
+ CertChainConf = gen_conf(Alg, Alg, ClientChain, ServerChain),
+ public_key:pkix_test_data(CertChainConf).
+
+make_cert_chains_pem(Alg, UserConf, Config, Suffix) ->
+ ClientChain = proplists:get_value(client_chain, UserConf, default_cert_chain_conf()),
+ ServerChain = proplists:get_value(server_chain, UserConf, default_cert_chain_conf()),
+ CertChainConf = gen_conf(Alg, Alg, ClientChain, ServerChain),
+ ClientFileBase = filename:join([proplists:get_value(priv_dir, Config), atom_to_list(Alg) ++ Suffix]),
+ ServerFileBase = filename:join([proplists:get_value(priv_dir, Config), atom_to_list(Alg) ++ Suffix]),
+ GenCertData = public_key:pkix_test_data(CertChainConf),
+ Conf = x509_test:gen_pem_config_files(GenCertData, ClientFileBase, ServerFileBase),
+ CConf = proplists:get_value(client_config, Conf),
+ SConf = proplists:get_value(server_config, Conf),
+ #{server_config => SConf,
+ client_config => CConf}.
+
make_rsa_cert_chains(UserConf, Config, Suffix) ->
ClientChain = proplists:get_value(client_chain, UserConf, default_cert_chain_conf()),
ServerChain = proplists:get_value(server_chain, UserConf, default_cert_chain_conf()),
@@ -1156,6 +1226,24 @@ basic_test(COpts, SOpts, Config) ->
gen_check_result(Server, SType, Client, CType),
stop(Server, Client).
+basic_alert(ClientOpts, ServerOpts, Config, Alert) ->
+ {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
+
+ Server = start_server_error([{node, ServerNode}, {port, 0},
+ {from, self()},
+ {mfa, {ssl_test_lib, no_result, []}},
+ {options, ServerOpts}]),
+
+ Port = inet_port(Server),
+
+ Client = start_client_error([{node, ClientNode}, {port, Port},
+ {host, Hostname},
+ {from, self()},
+ {mfa, {ssl_test_lib, no_result, []}},
+ {options, ClientOpts}]),
+
+ check_server_alert(Server, Client, Alert).
+
ecc_test(Expect, COpts, SOpts, CECCOpts, SECCOpts, Config) ->
{Server, Port} = start_server_ecc(erlang, SOpts, Expect, SECCOpts, Config),
Client = start_client_ecc(erlang, Port, COpts, Expect, CECCOpts, Config),
@@ -1202,11 +1290,27 @@ start_client(openssl, Port, ClientOpts, Config) ->
CA = proplists:get_value(cacertfile, ClientOpts),
Version = ssl_test_lib:protocol_version(Config),
Exe = "openssl",
+ Groups0 = proplists:get_value(groups, ClientOpts),
+ Exe = "openssl",
Args0 = ["s_client", "-verify", "2", "-port", integer_to_list(Port),
ssl_test_lib:version_flag(Version),
- "-cert", Cert, "-CAfile", CA,
- "-key", Key, "-host","localhost", "-msg", "-debug"],
- Args = maybe_force_ipv4(Args0),
+ "-CAfile", CA, "-host", "localhost", "-msg", "-debug"],
+ Args1 =
+ case Groups0 of
+ undefined ->
+ Args0;
+ G ->
+ Args0 ++ ["-groups", G]
+ end,
+ Args2 =
+ case {Cert, Key} of
+ {C, K} when C =:= undefined orelse
+ K =:= undefined ->
+ Args1;
+ {C, K} ->
+ Args1 ++ ["-cert", C, "-key", K]
+ end,
+ Args = maybe_force_ipv4(Args2),
OpenSslPort = ssl_test_lib:portable_open_port(Exe, Args),
true = port_command(OpenSslPort, "Hello world"),
OpenSslPort;
@@ -1259,7 +1363,7 @@ start_server(openssl, ClientOpts, ServerOpts, Config) ->
Exe = "openssl",
CertArgs = openssl_cert_options(ServerOpts),
[Cipher|_] = proplists:get_value(ciphers, ClientOpts, ssl:cipher_suites(default,Version)),
- Args = ["s_server", "-accept", integer_to_list(Port), "-cipher",
+ Args = ["s_server", "-accept", integer_to_list(Port), cipher_flag(Version),
ssl_cipher_format:suite_map_to_openssl_str(Cipher),
ssl_test_lib:version_flag(Version)] ++ CertArgs ++ ["-msg", "-debug"],
OpenSslPort = portable_open_port(Exe, Args),
@@ -1268,14 +1372,20 @@ start_server(openssl, ClientOpts, ServerOpts, Config) ->
start_server(erlang, _, ServerOpts, Config) ->
{_, ServerNode, _} = ssl_test_lib:run_where(Config),
KeyEx = proplists:get_value(check_keyex, Config, false),
+ Versions = protocol_versions(Config),
Server = start_server([{node, ServerNode}, {port, 0},
{from, self()},
{mfa, {ssl_test_lib,
check_key_exchange_send_active,
[KeyEx]}},
- {options, [{verify, verify_peer} | ServerOpts]}]),
+ {options, [{verify, verify_peer}, {versions, Versions} | ServerOpts]}]),
{Server, inet_port(Server)}.
+cipher_flag('tlsv1.3') ->
+ "-ciphersuites";
+cipher_flag(_) ->
+ "-cipher".
+
start_server_with_raw_key(erlang, ServerOpts, Config) ->
{_, ServerNode, _} = ssl_test_lib:run_where(Config),
Server = start_server([{node, ServerNode}, {port, 0},
@@ -2005,12 +2115,61 @@ check_sane_openssl_version(Version) ->
false;
{'tlsv1.1', "OpenSSL 0" ++ _} ->
false;
+ {'tlsv1', "OpenSSL 0" ++ _} ->
+ false;
{_, _} ->
true
end;
false ->
false
end.
+check_sane_openssl_renegotaite(Config, Version) when Version == 'tlsv1.1';
+ Version == 'tlsv1.2' ->
+ case os:cmd("openssl version") of
+ "OpenSSL 1.0.1c" ++ _ ->
+ {skip, "Known renegotiation bug in OpenSSL"};
+ "OpenSSL 1.0.1b" ++ _ ->
+ {skip, "Known renegotiation bug in OpenSSL"};
+ "OpenSSL 1.0.1a" ++ _ ->
+ {skip, "Known renegotiation bug in OpenSSL"};
+ "OpenSSL 1.0.1 " ++ _ ->
+ {skip, "Known renegotiation bug in OpenSSL"};
+ _ ->
+ check_sane_openssl_renegotaite(Config)
+ end;
+check_sane_openssl_renegotaite(Config, _) ->
+ check_sane_openssl_renegotaite(Config).
+
+check_sane_openssl_renegotaite(Config) ->
+ case os:cmd("openssl version") of
+ "OpenSSL 1.0.0" ++ _ ->
+ {skip, "Known renegotiation bug in OpenSSL"};
+ "OpenSSL 0.9.8" ++ _ ->
+ {skip, "Known renegotiation bug in OpenSSL"};
+ "OpenSSL 0.9.7" ++ _ ->
+ {skip, "Known renegotiation bug in OpenSSL"};
+ _ ->
+ Config
+ end.
+
+workaround_openssl_s_clinent() ->
+ %% http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=683159
+ %% https://bugs.archlinux.org/task/33919
+ %% Bug seems to manifests it self if TLS version is not
+ %% explicitly specified
+ case os:cmd("openssl version") of
+ "OpenSSL 1.0.1c" ++ _ ->
+ ["-no_tls1_2"];
+ "OpenSSL 1.0.1d" ++ _ ->
+ ["-no_tls1_2"];
+ "OpenSSL 1.0.1e" ++ _ ->
+ ["-no_tls1_2"];
+ "OpenSSL 1.0.1f" ++ _ ->
+ ["-no_tls1_2"];
+ _ ->
+ []
+ end.
+
enough_openssl_crl_support("OpenSSL 0." ++ _) -> false;
enough_openssl_crl_support(_) -> true.
@@ -2060,8 +2219,8 @@ filter_suites(Ciphers0, AtomVersion) ->
++ ssl_cipher:anonymous_suites(Version)
++ ssl_cipher:psk_suites(Version)
++ ssl_cipher:psk_suites_anon(Version)
- ++ ssl_cipher:srp_suites()
- ++ ssl_cipher:srp_suites_anon()
+ ++ ssl_cipher:srp_suites(Version)
+ ++ ssl_cipher:srp_suites_anon(Version)
++ ssl_cipher:rc4_suites(Version),
Supported1 = ssl_cipher:filter_suites(Supported0),
Supported2 = [ssl_cipher_format:suite_bin_to_map(S) || S <- Supported1],
@@ -2178,6 +2337,14 @@ protocol_version(Config, atom) ->
tls_record:protocol_version(protocol_version(Config, tuple))
end.
+protocol_versions(Config) ->
+ Version = protocol_version(Config),
+ case Version of
+ 'tlsv1.3' -> %% TLS-1.3 servers shall also support 1.2
+ ['tlsv1.3', 'tlsv1.2'];
+ _ ->
+ [Version]
+ end.
protocol_options(Config, Options) ->
Protocol = proplists:get_value(protocol, Config, tls),
{Protocol, Opts} = lists:keyfind(Protocol, 1, Options),
@@ -2504,3 +2671,48 @@ kill_openssl() ->
{win32, _} ->
os:cmd("cmd.exe /C \"taskkill /IM openssl.exe /F\"")
end.
+
+hostname_format(Hostname) ->
+ case lists:member($., Hostname) of
+ true ->
+ Hostname;
+ false ->
+ "localhost"
+ end.
+
+erlang_ssl_receive_and_assert_negotiated_protocol(Socket, Protocol, Data) ->
+ case ssl:negotiated_protocol(Socket) of
+ {ok, Protocol} ->
+ active_recv(Socket, length(Data));
+ Result ->
+ {error, {{expected, Protocol}, {got, Result}}}
+ end.
+
+check_openssl_npn_support(Config) ->
+ HelpText = os:cmd("openssl s_client --help"),
+ case string:str(HelpText, "nextprotoneg") of
+ 0 ->
+ {skip, "Openssl not compiled with nextprotoneg support"};
+ _ ->
+ Config
+ end.
+
+new_config(PrivDir, ServerOpts0) ->
+ CaCertFile = proplists:get_value(cacertfile, ServerOpts0),
+ CertFile = proplists:get_value(certfile, ServerOpts0),
+ KeyFile = proplists:get_value(keyfile, ServerOpts0),
+ NewCaCertFile = filename:join(PrivDir, "new_ca.pem"),
+ NewCertFile = filename:join(PrivDir, "new_cert.pem"),
+ NewKeyFile = filename:join(PrivDir, "new_key.pem"),
+ file:copy(CaCertFile, NewCaCertFile),
+ file:copy(CertFile, NewCertFile),
+ file:copy(KeyFile, NewKeyFile),
+ ServerOpts1 = proplists:delete(cacertfile, ServerOpts0),
+ ServerOpts2 = proplists:delete(certfile, ServerOpts1),
+ ServerOpts = proplists:delete(keyfile, ServerOpts2),
+
+ {ok, PEM} = file:read_file(NewCaCertFile),
+ ct:log("CA file content: ~p~n", [public_key:pem_decode(PEM)]),
+
+ [{cacertfile, NewCaCertFile}, {certfile, NewCertFile},
+ {keyfile, NewKeyFile} | ServerOpts].
diff --git a/lib/ssl/test/ssl_to_openssl_SUITE.erl b/lib/ssl/test/ssl_to_openssl_SUITE.erl
deleted file mode 100644
index 31d9af5298..0000000000
--- a/lib/ssl/test/ssl_to_openssl_SUITE.erl
+++ /dev/null
@@ -1,2021 +0,0 @@
-%%
-%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 2008-2018. 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_to_openssl_SUITE).
-
-%% Note: This directive should only be used in test suites.
--compile(export_all).
-
--include_lib("common_test/include/ct.hrl").
-
--define(SLEEP, 1000).
--define(OPENSSL_RENEGOTIATE, "R\n").
--define(OPENSSL_QUIT, "Q\n").
--define(OPENSSL_GARBAGE, "P\n").
--define(EXPIRE, 10).
-
-%%--------------------------------------------------------------------
-%% Common Test interface functions -----------------------------------
-%%--------------------------------------------------------------------
-
-all() ->
- case ssl_test_lib:openssl_sane_dtls() of
- true ->
- [{group, 'tlsv1.2'},
- {group, 'tlsv1.1'},
- {group, 'tlsv1'},
- {group, 'sslv3'},
- {group, 'dtlsv1.2'},
- {group, 'dtlsv1'}];
- false ->
- [{group, 'tlsv1.2'},
- {group, 'tlsv1.1'},
- {group, 'tlsv1'},
- {group, 'sslv3'}]
- end.
-
-groups() ->
- case ssl_test_lib:openssl_sane_dtls() of
- true ->
- [{'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()},
- {'dtlsv1.2', [], dtls_all_versions_tests()},
- {'dtlsv1', [], dtls_all_versions_tests()}
- ];
- false ->
- [{'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.
-
-all_versions_tests() ->
- [
- erlang_client_openssl_server,
- erlang_server_openssl_client,
- erlang_client_openssl_server_dsa_cert,
- erlang_server_openssl_client_dsa_cert,
- erlang_client_openssl_server_anon,
- erlang_server_openssl_client_anon,
- erlang_server_openssl_client_anon_with_cert,
- erlang_server_openssl_client_reuse_session,
- erlang_client_openssl_server_renegotiate,
- erlang_client_openssl_server_renegotiate_after_client_data,
- erlang_client_openssl_server_nowrap_seqnum,
- erlang_server_openssl_client_nowrap_seqnum,
- erlang_client_openssl_server_no_server_ca_cert,
- erlang_client_openssl_server_client_cert,
- erlang_server_openssl_client_client_cert,
- ciphers_rsa_signed_certs,
- ciphers_dsa_signed_certs,
- erlang_client_bad_openssl_server,
- expired_session,
- ssl2_erlang_server_openssl_client
- ].
-
-dtls_all_versions_tests() ->
- case ssl_test_lib:openssl_sane_client_cert() of
- true ->
- [erlang_server_openssl_client_client_cert,
- erlang_client_openssl_server_no_server_ca_cert,
- erlang_client_openssl_server_client_cert
- | dtls_all_versions_tests_2()];
- false ->
- dtls_all_versions_tests_2()
- end.
-
-dtls_all_versions_tests_2() ->
- [erlang_client_openssl_server,
- erlang_server_openssl_client,
- erlang_client_openssl_server_dsa_cert,
- erlang_server_openssl_client_dsa_cert,
- erlang_client_openssl_server_anon,
- erlang_server_openssl_client_anon,
- erlang_server_openssl_client_anon_with_cert,
- erlang_server_openssl_client_reuse_session,
- erlang_client_openssl_server_renegotiate,
- erlang_client_openssl_server_nowrap_seqnum,
- erlang_server_openssl_client_nowrap_seqnum,
- ciphers_rsa_signed_certs,
- ciphers_dsa_signed_certs
- %%expired_session
- ].
-
-alpn_tests() ->
- [erlang_client_alpn_openssl_server_alpn,
- erlang_server_alpn_openssl_client_alpn,
- erlang_client_alpn_openssl_server,
- erlang_client_openssl_server_alpn,
- erlang_server_alpn_openssl_client,
- erlang_server_openssl_client_alpn,
- erlang_client_alpn_openssl_server_alpn_renegotiate,
- erlang_server_alpn_openssl_client_alpn_renegotiate,
- erlang_client_alpn_npn_openssl_server_alpn_npn,
- erlang_server_alpn_npn_openssl_client_alpn_npn].
-
-npn_tests() ->
- [erlang_client_openssl_server_npn,
- erlang_server_openssl_client_npn,
- erlang_server_openssl_client_npn_renegotiate,
- erlang_client_openssl_server_npn_renegotiate,
- erlang_server_openssl_client_npn_only_client,
- erlang_server_openssl_client_npn_only_server,
- erlang_client_openssl_server_npn_only_client,
- erlang_client_openssl_server_npn_only_server].
-
-sni_server_tests() ->
- [erlang_server_openssl_client_sni_match,
- erlang_server_openssl_client_sni_match_fun,
- erlang_server_openssl_client_sni_no_match,
- erlang_server_openssl_client_sni_no_match_fun,
- erlang_server_openssl_client_sni_no_header,
- erlang_server_openssl_client_sni_no_header_fun].
-
-
-init_per_suite(Config0) ->
- case os:find_executable("openssl") of
- false ->
- {skip, "Openssl not found"};
- _ ->
- ct:pal("Version: ~p", [os:cmd("openssl version")]),
- catch crypto:stop(),
- try crypto:start() of
- ok ->
- ssl_test_lib:clean_start(),
- Config =
- case ssl_test_lib:openssl_dsa_support() of
- true ->
- Config1 = ssl_test_lib:make_rsa_cert(Config0),
- ssl_test_lib:make_dsa_cert(Config1);
- false ->
- ssl_test_lib:make_rsa_cert(Config0)
- end,
- ssl_test_lib:cipher_restriction(Config)
- catch _:_ ->
- {skip, "Crypto did not start"}
- end
- end.
-
-end_per_suite(_Config) ->
- ssl:stop(),
- application:stop(crypto),
- ssl_test_lib:kill_openssl().
-
-init_per_group(GroupName, Config) ->
- case ssl_test_lib:is_tls_version(GroupName) of
- true ->
- case ssl_test_lib:supports_ssl_tls_version(GroupName) of
- true ->
- case ssl_test_lib:check_sane_openssl_version(GroupName) of
- true ->
- ssl_test_lib:init_tls_version(GroupName, Config);
- false ->
- {skip, openssl_does_not_support_version}
- end;
- false ->
- {skip, openssl_does_not_support_version}
- end;
- _ ->
- ssl:start(),
- Config
- 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(expired_session, Config) ->
- ct:timetrap(?EXPIRE * 1000 * 5),
- ssl:stop(),
- application:load(ssl),
- application:set_env(ssl, session_lifetime, ?EXPIRE),
- ssl:start(),
- Config;
-
-init_per_testcase(TestCase, Config) when
- TestCase == ciphers_dsa_signed_certs;
- TestCase == erlang_client_openssl_server_dsa_cert;
- TestCase == erlang_server_openssl_client_dsa_cert;
- TestCase == erlang_client_openssl_server_dsa_cert;
- TestCase == erlang_server_openssl_client_dsa_cert ->
- case ssl_test_lib:openssl_dsa_support() andalso ssl_test_lib:is_sane_oppenssl_client() of
- true ->
- special_init(TestCase, Config);
- false ->
- {skip, "DSA not supported by OpenSSL"}
- end;
-init_per_testcase(TestCase, Config) ->
- ct:timetrap({seconds, 35}),
- special_init(TestCase, Config).
-
-special_init(TestCase, Config) when
- TestCase == ciphers_rsa_signed_certs;
- TestCase == ciphers_dsa_signed_certs->
- ct:timetrap({seconds, 90}),
- Config;
-special_init(TestCase, Config)
- when TestCase == erlang_client_openssl_server_renegotiate;
- TestCase == erlang_client_openssl_server_nowrap_seqnum;
- TestCase == erlang_server_openssl_client_nowrap_seqnum;
- TestCase == erlang_client_openssl_server_renegotiate_after_client_data
- ->
- {ok, Version} = application:get_env(ssl, protocol_version),
- check_sane_openssl_renegotaite(Config, Version);
-
-special_init(ssl2_erlang_server_openssl_client, Config) ->
- case ssl_test_lib:supports_ssl_tls_version(sslv2) of
- true ->
- Config;
- false ->
- {skip, "sslv2 not supported by openssl"}
- end;
-
-special_init(TestCase, Config)
- when TestCase == erlang_client_alpn_openssl_server_alpn;
- TestCase == erlang_server_alpn_openssl_client_alpn;
- TestCase == erlang_client_alpn_openssl_server;
- TestCase == erlang_client_openssl_server_alpn;
- TestCase == erlang_server_alpn_openssl_client;
- TestCase == erlang_server_openssl_client_alpn ->
- check_openssl_alpn_support(Config);
-
-special_init(TestCase, Config)
- when TestCase == erlang_client_alpn_openssl_server_alpn_renegotiate;
- TestCase == erlang_server_alpn_openssl_client_alpn_renegotiate ->
- {ok, Version} = application:get_env(ssl, protocol_version),
- case check_sane_openssl_renegotaite(Config, Version) of
- {skip, _} = Skip ->
- Skip;
- _ ->
- check_openssl_alpn_support(Config)
- end;
-
-special_init(TestCase, Config)
- when TestCase == erlang_client_alpn_npn_openssl_server_alpn_npn;
- TestCase == erlang_server_alpn_npn_openssl_client_alpn_npn ->
- case check_openssl_alpn_support(Config) of
- {skip, _} = Skip ->
- Skip;
- _ ->
- check_openssl_npn_support(Config)
- end;
-
-special_init(TestCase, Config)
- when TestCase == erlang_client_openssl_server_npn;
- TestCase == erlang_server_openssl_client_npn;
- TestCase == erlang_server_openssl_client_npn_only_server;
- TestCase == erlang_server_openssl_client_npn_only_client;
- TestCase == erlang_client_openssl_server_npn_only_client;
- TestCase == erlang_client_openssl_server_npn_only_server ->
- check_openssl_npn_support(Config);
-
-special_init(TestCase, Config)
- when TestCase == erlang_server_openssl_client_npn_renegotiate;
- TestCase == erlang_client_openssl_server_npn_renegotiate ->
- {ok, Version} = application:get_env(ssl, protocol_version),
- case check_sane_openssl_renegotaite(Config, Version) of
- {skip, _} = Skip ->
- Skip;
- _ ->
- check_openssl_npn_support(Config)
- end;
-
-special_init(TestCase, Config0)
- when TestCase == erlang_server_openssl_client_sni_match;
- TestCase == erlang_server_openssl_client_sni_no_match;
- TestCase == erlang_server_openssl_client_sni_no_header;
- TestCase == erlang_server_openssl_client_sni_match_fun;
- TestCase == erlang_server_openssl_client_sni_no_match_fun;
- TestCase == erlang_server_openssl_client_sni_no_header_fun ->
- RsaOpts = ssl_test_lib:ssl_options(server_rsa_opts, Config0),
- Config = [{sni_server_opts, [{sni_hosts,
- [{"a.server", [
- {certfile, proplists:get_value(certfile, RsaOpts)},
- {keyfile, proplists:get_value(keyfile, RsaOpts)}
- ]},
- {"b.server", [
- {certfile, proplists:get_value(certfile, RsaOpts)},
- {keyfile, proplists:get_value(keyfile, RsaOpts)}
- ]}
- ]}]} | Config0],
- check_openssl_sni_support(Config);
-special_init(TestCase, Config)
- when TestCase == erlang_server_openssl_client;
- TestCase == erlang_server_openssl_client_client_cert;
- TestCase == erlang_server_openssl_client_reuse_session ->
- case ssl_test_lib:is_sane_oppenssl_client() of
- true ->
- Config;
- false ->
- {skip, "Broken OpenSSL client"}
- end;
-special_init(_, Config) ->
- Config.
-
-end_per_testcase(reuse_session_expired, Config) ->
- application:unset_env(ssl, session_lifetime),
- Config;
-end_per_testcase(_, Config) ->
- Config.
-
-%%--------------------------------------------------------------------
-%% Test Cases --------------------------------------------------------
-%%--------------------------------------------------------------------
-
-erlang_client_openssl_server() ->
- [{doc,"Test erlang client with openssl server"}].
-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),
- Version = ssl_test_lib:protocol_version(Config),
- Exe = "openssl",
- Args = ["s_server", "-accept", integer_to_list(Port),
- ssl_test_lib:version_flag(Version),
- "-cert", CertFile, "-key", KeyFile],
-
- OpensslPort = ssl_test_lib:portable_open_port(Exe, Args),
-
- ssl_test_lib:wait_for_openssl_server(Port, proplists:get_value(protocol, Config)),
-
- 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).
-
-%%--------------------------------------------------------------------
-erlang_server_openssl_client() ->
- [{doc,"Test erlang server with openssl client"}].
-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),
- Version = ssl_test_lib:protocol_version(Config),
-
- Exe = "openssl",
- Args = ["s_client", "-connect", hostname_format(Hostname) ++":" ++ integer_to_list(Port),
- ssl_test_lib:version_flag(Version)],
-
- 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_dsa_cert() ->
- [{doc,"Test erlang server with openssl client"}].
-erlang_client_openssl_server_dsa_cert(Config) when is_list(Config) ->
- process_flag(trap_exit, true),
- ClientOpts = ssl_test_lib:ssl_options(client_dsa_opts, Config),
- ServerOpts = ssl_test_lib:ssl_options(server_dsa_verify_opts, Config),
-
- {ClientNode, _, Hostname} = ssl_test_lib:run_where(Config),
-
- Data = "From openssl to erlang",
-
- Port = ssl_test_lib:inet_port(node()),
- CaCertFile = proplists:get_value(cacertfile, ServerOpts),
- CertFile = proplists:get_value(certfile, ServerOpts),
- KeyFile = proplists:get_value(keyfile, ServerOpts),
- Version = ssl_test_lib:protocol_version(Config),
- Exe = "openssl",
- Args = ["s_server", "-accept", integer_to_list(Port),
- ssl_test_lib:version_flag(Version),
- "-cert", CertFile, "-CAfile", CaCertFile,
- "-key", KeyFile, "-Verify", "2", "-msg"],
-
- OpensslPort = ssl_test_lib:portable_open_port(Exe, Args),
-
- ssl_test_lib:wait_for_openssl_server(Port, proplists:get_value(protocol, Config)),
-
- 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),
- ok.
-%%--------------------------------------------------------------------
-erlang_server_openssl_client_dsa_cert() ->
- [{doc,"Test erlang server with openssl client"}].
-erlang_server_openssl_client_dsa_cert(Config) when is_list(Config) ->
- process_flag(trap_exit, true),
- ClientOpts = ssl_test_lib:ssl_options(client_dsa_opts, Config),
- ServerOpts = ssl_test_lib:ssl_options(server_dsa_verify_opts, Config),
-
- {_, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
-
- Data = "From openssl to erlang",
- CaCertFile = proplists:get_value(cacertfile, ClientOpts),
- CertFile = proplists:get_value(certfile, ClientOpts),
- KeyFile = proplists:get_value(keyfile, ClientOpts),
-
- 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),
- Version = ssl_test_lib:protocol_version(Config),
- Exe = "openssl",
- Args = ["s_client", "-connect", hostname_format(Hostname) ++ ":" ++ integer_to_list(Port),
- ssl_test_lib:version_flag(Version),
- "-cert", CertFile,
- "-CAfile", CaCertFile,
- "-key", KeyFile, "-msg"],
-
- 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_anon() ->
- [{doc,"Test erlang client with openssl server, anonymous"}].
-erlang_client_openssl_server_anon(Config) when is_list(Config) ->
- process_flag(trap_exit, true),
- %% OpenSSL expects a certificate and key, even if the cipher spec
- %% is restructed to aNULL, so we use 'server_rsa_opts' here
- ServerOpts = ssl_test_lib:ssl_options(server_rsa_opts, Config),
- ClientOpts = ssl_test_lib:ssl_options(client_anon_opts, Config),
- VersionTuple = ssl_test_lib:protocol_version(Config, tuple),
- Ciphers = ssl_test_lib:ecdh_dh_anonymous_suites(VersionTuple),
-
- case openssl_has_common_ciphers(Ciphers) of
- false ->
- {skip, not_supported_by_openssl};
- true ->
-
- {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),
- Version = ssl_test_lib:protocol_version(Config),
- Exe = "openssl",
- Args = ["s_server", "-accept", integer_to_list(Port),
- ssl_test_lib:version_flag(Version),
- "-cert", CertFile, "-key", KeyFile,
- "-cipher", "aNULL", "-msg"],
-
- OpensslPort = ssl_test_lib:portable_open_port(Exe, Args),
-
- ssl_test_lib:wait_for_openssl_server(Port, proplists:get_value(protocol, Config)),
-
- Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port},
- {host, Hostname},
- {from, self()},
- {mfa, {?MODULE,
- erlang_ssl_receive, [Data]}},
- {options, [{ciphers, Ciphers} | 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)
- end.
-%%--------------------------------------------------------------------
-erlang_server_openssl_client_anon() ->
- [{doc,"Test erlang server with openssl client, anonymous"}].
-erlang_server_openssl_client_anon(Config) when is_list(Config) ->
-
- process_flag(trap_exit, true),
- ServerOpts = ssl_test_lib:ssl_options(server_anon_opts, Config),
- VersionTuple = ssl_test_lib:protocol_version(Config, tuple),
- Ciphers = ssl_test_lib:ecdh_dh_anonymous_suites(VersionTuple),
-
- case openssl_has_common_ciphers(Ciphers) of
- false ->
- {skip, not_supported_by_openssl};
- true ->
- {_, 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, [{ciphers, Ciphers} | ServerOpts]}]),
- Port = ssl_test_lib:inet_port(Server),
- Version = ssl_test_lib:protocol_version(Config),
- Exe = "openssl",
- Args = ["s_client", "-connect", hostname_format(Hostname) ++ ":" ++ integer_to_list(Port),
- ssl_test_lib:version_flag(Version),
- "-cipher", "aNULL", "-msg"],
-
- 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)
- end.
-
-%%--------------------------------------------------------------------
-erlang_server_openssl_client_anon_with_cert() ->
- [{doc,"Test erlang server with openssl client, anonymous (with cert)"}].
-erlang_server_openssl_client_anon_with_cert(Config) when is_list(Config) ->
- process_flag(trap_exit, true),
- ServerOpts = ssl_test_lib:ssl_options(server_rsa_opts, Config),
- VersionTuple = ssl_test_lib:protocol_version(Config, tuple),
- Ciphers = ssl_test_lib:ecdh_dh_anonymous_suites(VersionTuple),
-
- case openssl_has_common_ciphers(Ciphers) of
- false ->
- {skip, not_supported_by_openssl};
- true ->
- {_, 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, [{ciphers, Ciphers} | ServerOpts]}]),
- Port = ssl_test_lib:inet_port(Server),
- Version = ssl_test_lib:protocol_version(Config),
- Exe = "openssl",
- Args = ["s_client", "-connect", hostname_format(Hostname) ++ ":" ++ integer_to_list(Port),
- ssl_test_lib:version_flag(Version),
- "-cipher", "aNULL", "-msg"],
-
- 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)
- end.
-
- %%--------------------------------------------------------------------
-erlang_server_openssl_client_reuse_session() ->
- [{doc, "Test erlang server with openssl client that reconnects with the"
- "same session id, to test reusing of sessions."}].
-erlang_server_openssl_client_reuse_session(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]}},
- {reconnect_times, 5},
- {options, ServerOpts}]),
- Port = ssl_test_lib:inet_port(Server),
- Version = ssl_test_lib:protocol_version(Config),
-
- Exe = "openssl",
- Args = ["s_client", "-connect", hostname_format(Hostname)
- ++ ":" ++ integer_to_list(Port),
- ssl_test_lib:version_flag(Version),
- "-reconnect"],
-
- 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),
- ok.
-
-%%--------------------------------------------------------------------
-
-erlang_client_openssl_server_renegotiate() ->
- [{doc,"Test erlang client when openssl server issuses a renegotiate"}].
-erlang_client_openssl_server_renegotiate(Config) when is_list(Config) ->
- process_flag(trap_exit, true),
- ServerOpts = ssl_test_lib:ssl_options(server_rsa_verify_opts, Config),
- ClientOpts = ssl_test_lib:ssl_options(client_rsa_verify_opts, Config),
-
- {ClientNode, _, Hostname} = ssl_test_lib:run_where(Config),
-
- ErlData = "From erlang to openssl",
- OpenSslData = "From openssl to erlang",
-
- Port = ssl_test_lib:inet_port(node()),
- CertFile = proplists:get_value(certfile, ServerOpts),
- CaCertFile = proplists:get_value(cacertfile, ServerOpts),
- KeyFile = proplists:get_value(keyfile, ServerOpts),
- Version = ssl_test_lib:protocol_version(Config),
-
- Exe = "openssl",
- Args = ["s_server", "-accept", integer_to_list(Port),
- ssl_test_lib:version_flag(Version),
- "-CAfile", CaCertFile,
- "-cert", CertFile, "-key", KeyFile, "-msg"],
-
- OpensslPort = ssl_test_lib:portable_open_port(Exe, Args),
-
- ssl_test_lib:wait_for_openssl_server(Port, proplists:get_value(protocol, Config)),
-
- Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port},
- {host, Hostname},
- {from, self()},
- {mfa, {?MODULE,
- delayed_send, [[ErlData, OpenSslData]]}},
- {options, ClientOpts}]),
-
- true = port_command(OpensslPort, ?OPENSSL_RENEGOTIATE),
- ct:sleep(?SLEEP),
- true = port_command(OpensslPort, OpenSslData),
-
- 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),
- ok.
-%%--------------------------------------------------------------------
-erlang_client_openssl_server_renegotiate_after_client_data() ->
- [{doc,"Test erlang client when openssl server issuses a renegotiate after reading client data"}].
-erlang_client_openssl_server_renegotiate_after_client_data(Config) when is_list(Config) ->
- process_flag(trap_exit, true),
- ServerOpts = ssl_test_lib:ssl_options(server_rsa_verify_opts, Config),
- ClientOpts = ssl_test_lib:ssl_options(client_rsa_verify_opts, Config),
-
- {ClientNode, _, Hostname} = ssl_test_lib:run_where(Config),
-
- ErlData = "From erlang to openssl",
- OpenSslData = "From openssl to erlang",
-
- Port = ssl_test_lib:inet_port(node()),
- CaCertFile = proplists:get_value(cacertfile, ServerOpts),
- CertFile = proplists:get_value(certfile, ServerOpts),
- KeyFile = proplists:get_value(keyfile, ServerOpts),
- Version = ssl_test_lib:protocol_version(Config),
-
- Exe = "openssl",
- Args = ["s_server", "-accept", integer_to_list(Port),
- ssl_test_lib:version_flag(Version),
- "-CAfile", CaCertFile,
- "-cert", CertFile, "-key", KeyFile, "-msg"],
-
- OpensslPort = ssl_test_lib:portable_open_port(Exe, Args),
-
- ssl_test_lib:wait_for_openssl_server(Port, proplists:get_value(protocol, Config)),
-
- Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port},
- {host, Hostname},
- {from, self()},
- {mfa, {?MODULE,
- send_wait_send, [[ErlData, OpenSslData]]}},
- {options, ClientOpts}]),
-
- true = port_command(OpensslPort, ?OPENSSL_RENEGOTIATE),
- ct:sleep(?SLEEP),
- true = port_command(OpensslPort, OpenSslData),
-
- 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),
- ok.
-
-%%--------------------------------------------------------------------
-
-erlang_client_openssl_server_nowrap_seqnum() ->
- [{doc, "Test that erlang client will renegotiate session when",
- "max sequence number celing is about to be reached. Although"
- "in the testcase we use the test option renegotiate_at"
- " to lower treashold substantially."}].
-erlang_client_openssl_server_nowrap_seqnum(Config) when is_list(Config) ->
- process_flag(trap_exit, true),
- ServerOpts = ssl_test_lib:ssl_options(server_rsa_verify_opts, Config),
- ClientOpts = ssl_test_lib:ssl_options(client_rsa_opts, Config),
-
- {ClientNode, _, Hostname} = ssl_test_lib:run_where(Config),
-
- ErlData = "From erlang to openssl\n",
- N = 10,
-
- Port = ssl_test_lib:inet_port(node()),
- CaCertFile = proplists:get_value(cacertfile, ServerOpts),
- CertFile = proplists:get_value(certfile, ServerOpts),
- KeyFile = proplists:get_value(keyfile, ServerOpts),
- Version = ssl_test_lib:protocol_version(Config),
- Exe = "openssl",
- Args = ["s_server", "-accept", integer_to_list(Port),
- ssl_test_lib:version_flag(Version),
- "-CAfile", CaCertFile,
- "-cert", CertFile, "-key", KeyFile, "-msg"],
-
- OpensslPort = ssl_test_lib:portable_open_port(Exe, Args),
-
- ssl_test_lib:wait_for_openssl_server(Port, proplists:get_value(protocol, Config)),
-
- Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port},
- {host, Hostname},
- {from, self()},
- {mfa, {ssl_test_lib,
- trigger_renegotiate, [[ErlData, N+2]]}},
- {options, [{reuse_sessions, false},
- {renegotiate_at, N} | ClientOpts]}]),
-
- 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).
-%%--------------------------------------------------------------------
-erlang_server_openssl_client_nowrap_seqnum() ->
- [{doc, "Test that erlang client will renegotiate session when",
- "max sequence number celing is about to be reached. Although"
- "in the testcase we use the test option renegotiate_at"
- " to lower treashold substantially."}].
-erlang_server_openssl_client_nowrap_seqnum(Config) when is_list(Config) ->
- process_flag(trap_exit, true),
- ServerOpts = ssl_test_lib:ssl_options(server_rsa_verify_opts, Config),
-
- {_, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
-
- Data = "From openssl to erlang",
-
- N = 10,
-
- Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0},
- {from, self()},
- {mfa, {ssl_test_lib,
- trigger_renegotiate, [[Data, N+2]]}},
- {options, [{renegotiate_at, N}, {reuse_sessions, false} | ServerOpts]}]),
- Port = ssl_test_lib:inet_port(Server),
- Version = ssl_test_lib:protocol_version(Config),
- Exe = "openssl",
- Args = ["s_client","-connect", hostname_format(Hostname) ++ ":" ++ integer_to_list(Port),
- ssl_test_lib:version_flag(Version),
- "-msg"],
-
- 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_no_server_ca_cert() ->
- [{doc, "Test erlang client when openssl server sends a cert chain not"
- "including the ca cert. Explicitly test this even if it is"
- "implicitly tested eleswhere."}].
-erlang_client_openssl_server_no_server_ca_cert(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),
- Version = ssl_test_lib:protocol_version(Config),
- Exe = "openssl",
- Args = ["s_server", "-accept", integer_to_list(Port),
- ssl_test_lib:version_flag(Version),
- "-cert", CertFile, "-key", KeyFile, "-msg"],
-
- OpensslPort = ssl_test_lib:portable_open_port(Exe, Args),
-
- ssl_test_lib:wait_for_openssl_server(Port, proplists:get_value(protocol, Config)),
-
- 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).
-
-%%--------------------------------------------------------------------
-erlang_client_openssl_server_client_cert() ->
- [{doc,"Test erlang client with openssl server when client sends cert"}].
-erlang_client_openssl_server_client_cert(Config) when is_list(Config) ->
- process_flag(trap_exit, true),
- ServerOpts = ssl_test_lib:ssl_options(server_rsa_verify_opts, Config),
- ClientOpts = ssl_test_lib:ssl_options(client_rsa_verify_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),
- CaCertFile = proplists:get_value(cacertfile, ServerOpts),
- KeyFile = proplists:get_value(keyfile, ServerOpts),
- Version = ssl_test_lib:protocol_version(Config),
- Exe = "openssl",
- Args = ["s_server", "-accept", integer_to_list(Port),
- ssl_test_lib:version_flag(Version),
- "-cert", CertFile, "-CAfile", CaCertFile,
- "-key", KeyFile, "-Verify", "2"],
-
- OpensslPort = ssl_test_lib:portable_open_port(Exe, Args),
-
- ssl_test_lib:wait_for_openssl_server(Port, proplists:get_value(protocol, Config)),
-
- 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).
-
-%%--------------------------------------------------------------------
-erlang_server_openssl_client_client_cert() ->
- [{doc,"Test erlang server with openssl client when client sends cert"}].
-erlang_server_openssl_client_client_cert(Config) when is_list(Config) ->
- process_flag(trap_exit, true),
- ServerOpts = ssl_test_lib:ssl_options(server_rsa_verify_opts, Config),
- ClientOpts = ssl_test_lib:ssl_options(client_rsa_verify_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,
- [{verify , verify_peer}
- | ServerOpts]}]),
- Port = ssl_test_lib:inet_port(Server),
-
- CaCertFile = proplists:get_value(cacertfile, ClientOpts),
- CertFile = proplists:get_value(certfile, ClientOpts),
- KeyFile = proplists:get_value(keyfile, ClientOpts),
- Version = ssl_test_lib:protocol_version(Config),
- Exe = "openssl",
- Args = ["s_client", "-cert", CertFile,
- "-CAfile", CaCertFile,
- "-key", KeyFile,"-connect", hostname_format(Hostname) ++ ":" ++ integer_to_list(Port),
- ssl_test_lib:version_flag(Version)],
- 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_port(OpenSslPort),
- ssl_test_lib:close(Server),
- process_flag(trap_exit, false).
-
-%%--------------------------------------------------------------------
-erlang_server_erlang_client_client_cert() ->
- [{doc,"Test erlang server with erlang client when client sends cert"}].
-erlang_server_erlang_client_client_cert(Config) when is_list(Config) ->
- process_flag(trap_exit, true),
- ServerOpts = proplists:get_value(server_rsa_verify_opts, Config),
- ClientOpts = proplists:get_value(client_rsa_verify_opts, Config),
- Version = ssl_test_lib:protocol_version(Config),
- {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
-
- Data = "From erlang to erlang",
-
- Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0},
- {from, self()},
- {mfa, {?MODULE,
- erlang_ssl_receive,
- %% Due to 1/n-1 splitting countermeasure Rizzo/Duong-Beast
- [Data]}},
- {options,
- [{verify , verify_peer}
- | ServerOpts]}]),
- Port = ssl_test_lib:inet_port(Server),
-
- Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port},
- {host, Hostname},
- {from, self()},
- %% Due to 1/n-1 splitting countermeasure Rizzo/Duong-Beast
- {mfa, {ssl, send, [Data]}},
- {options,
- [{versions, [Version]} | ClientOpts]}]),
-
- ssl_test_lib:check_result(Server, ok, Client, ok),
-
- ssl_test_lib:close(Server),
- ssl_test_lib:close(Client),
- process_flag(trap_exit, false).
-
-%%--------------------------------------------------------------------
-
-ciphers_rsa_signed_certs() ->
- [{doc,"Test cipher suites that uses rsa certs"}].
-ciphers_rsa_signed_certs(Config) when is_list(Config) ->
- Version = ssl_test_lib:protocol_version(Config),
- Ciphers = ssl_test_lib:rsa_suites(openssl),
- run_suites(Ciphers, Version, Config, rsa).
-%%--------------------------------------------------------------------
-
-ciphers_dsa_signed_certs() ->
- [{doc,"Test cipher suites that uses dsa certs"}].
-ciphers_dsa_signed_certs(Config) when is_list(Config) ->
- Version = ssl_test_lib:protocol_version(Config),
- NVersion = ssl_test_lib:protocol_version(Config, tuple),
- Ciphers = ssl_test_lib:dsa_suites(NVersion),
- run_suites(Ciphers, Version, Config, dsa).
-
-%%--------------------------------------------------------------------
-erlang_client_bad_openssl_server() ->
- [{doc,"Test what happens if openssl server sends garbage to erlang ssl client"}].
-erlang_client_bad_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),
-
- Port = ssl_test_lib:inet_port(node()),
- CertFile = proplists:get_value(certfile, ServerOpts),
- KeyFile = proplists:get_value(keyfile, ServerOpts),
- Version = ssl_test_lib:protocol_version(Config),
- Exe = "openssl",
- Args = ["s_server", "-accept", integer_to_list(Port), ssl_test_lib:version_flag(Version),
- "-cert", CertFile, "-key", KeyFile],
- OpensslPort = ssl_test_lib:portable_open_port(Exe, Args),
-
- ssl_test_lib:wait_for_openssl_server(Port, proplists:get_value(protocol, Config)),
-
- Client0 = ssl_test_lib:start_client([{node, ClientNode}, {port, Port},
- {host, Hostname},
- {from, self()},
- {mfa, {?MODULE, server_sent_garbage, []}},
- {options,
- [{versions, [Version]} | ClientOpts]}]),
-
- %% Send garbage
- true = port_command(OpensslPort, ?OPENSSL_GARBAGE),
-
- ct:sleep(?SLEEP),
-
- Client0 ! server_sent_garbage,
-
- ssl_test_lib:check_result(Client0, true),
-
- ssl_test_lib:close(Client0),
-
- %% Make sure openssl does not hang and leave zombie process
- Client1 = ssl_test_lib:start_client([{node, ClientNode}, {port, Port},
- {host, Hostname},
- {from, self()},
- {mfa, {ssl_test_lib, no_result, []}},
- {options,
- [{versions, [Version]} | ClientOpts]}]),
-
- %% Clean close down! Server needs to be closed first !!
- ssl_test_lib:close_port(OpensslPort),
- ssl_test_lib:close(Client1),
- process_flag(trap_exit, false),
- ok.
-
-%%--------------------------------------------------------------------
-
-expired_session() ->
- [{doc, "Test our ssl client handling of expired sessions. Will make"
- "better code coverage of the ssl_manager module"}].
-expired_session(Config) when is_list(Config) ->
- process_flag(trap_exit, true),
- ClientOpts = ssl_test_lib:ssl_options(client_rsa_opts, Config),
- ServerOpts = ssl_test_lib:ssl_options(server_rsa_opts, Config),
- {ClientNode, _, Hostname} = ssl_test_lib:run_where(Config),
-
- 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),
-
- Client0 =
- ssl_test_lib:start_client([{node, ClientNode},
- {port, Port}, {host, Hostname},
- {mfa, {ssl_test_lib, no_result, []}},
- {from, self()}, {options, ClientOpts}]),
-
- ssl_test_lib:close(Client0),
-
- %% Make sure session is registered
- ct:sleep(?SLEEP),
-
- Client1 =
- ssl_test_lib:start_client([{node, ClientNode},
- {port, Port}, {host, Hostname},
- {mfa, {ssl_test_lib, no_result, []}},
- {from, self()}, {options, ClientOpts}]),
-
- ssl_test_lib:close(Client1),
- %% Make sure session is unregistered due to expiration
- ct:sleep((?EXPIRE+1) * 1000),
-
- Client2 =
- ssl_test_lib:start_client([{node, ClientNode},
- {port, Port}, {host, Hostname},
- {mfa, {ssl_test_lib, no_result, []}},
- {from, self()}, {options, ClientOpts}]),
-
- %% Clean close down! Server needs to be closed first !!
- ssl_test_lib:close_port(OpensslPort),
- ssl_test_lib:close(Client2),
- process_flag(trap_exit, false).
-
-%%--------------------------------------------------------------------
-ssl2_erlang_server_openssl_client() ->
- [{doc,"Test that ssl v2 clients are rejected"}].
-
-ssl2_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),
-
- Server = ssl_test_lib:start_server_error([{node, ServerNode}, {port, 0},
- {from, self()},
- {options, ServerOpts}]),
- Port = ssl_test_lib:inet_port(Server),
-
- Exe = "openssl",
- Args = ["s_client", "-connect", hostname_format(Hostname) ++ ":" ++ integer_to_list(Port),
- "-ssl2", "-msg"],
-
- OpenSslPort = ssl_test_lib:portable_open_port(Exe, Args),
-
- ct:log("Ports ~p~n", [[erlang:port_info(P) || P <- erlang:ports()]]),
- ssl_test_lib:consume_port_exit(OpenSslPort),
- ssl_test_lib:check_server_alert(Server, unexpected_message),
- process_flag(trap_exit, false).
-
-%%--------------------------------------------------------------------
-
-erlang_client_alpn_openssl_server_alpn(Config) when is_list(Config) ->
- Data = "From openssl to erlang",
- start_erlang_client_and_openssl_server_for_alpn_negotiation(Config, Data, fun(Client, OpensslPort) ->
- true = port_command(OpensslPort, Data),
-
- ssl_test_lib:check_result(Client, ok)
- end),
- ok.
-
-%%--------------------------------------------------------------------
-
-erlang_server_alpn_openssl_client_alpn(Config) when is_list(Config) ->
- Data = "From openssl to erlang",
- start_erlang_server_and_openssl_client_for_alpn_negotiation(Config, Data, fun(Client, OpensslPort) ->
- true = port_command(OpensslPort, Data),
-
- ssl_test_lib:check_result(Client, ok)
- end),
- ok.
-
-%%--------------------------------------------------------------------------
-
-erlang_client_alpn_openssl_server(Config) when is_list(Config) ->
- Data = "From openssl to erlang",
- start_erlang_client_and_openssl_server_with_opts(Config,
- [{alpn_advertised_protocols, [<<"spdy/2">>]}],
- [],
- Data, fun(Server, OpensslPort) ->
- true = port_command(OpensslPort, Data),
- ssl_test_lib:check_result(Server, ok)
- end),
- ok.
-
-%%--------------------------------------------------------------------------
-
-erlang_client_openssl_server_alpn(Config) when is_list(Config) ->
- Data = "From openssl to erlang",
- start_erlang_client_and_openssl_server_with_opts(Config,
- [],
- ["-alpn", "spdy/2"],
- Data, fun(Server, OpensslPort) ->
- true = port_command(OpensslPort, Data),
- ssl_test_lib:check_result(Server, ok)
- end),
- ok.
-
-%%--------------------------------------------------------------------------
-
-erlang_server_alpn_openssl_client(Config) when is_list(Config) ->
- Data = "From openssl to erlang",
- start_erlang_server_and_openssl_client_with_opts(Config,
- [{alpn_preferred_protocols, [<<"spdy/2">>]}],
- [],
- Data, fun(Server, OpensslPort) ->
- true = port_command(OpensslPort, Data),
- ssl_test_lib:check_result(Server, ok)
- end),
- ok.
-
-%%--------------------------------------------------------------------------
-
-erlang_server_openssl_client_alpn(Config) when is_list(Config) ->
- Data = "From openssl to erlang",
- start_erlang_server_and_openssl_client_with_opts(Config,
- [],
- ["-alpn", "spdy/2"],
- Data, fun(Server, OpensslPort) ->
- true = port_command(OpensslPort, Data),
- ssl_test_lib:check_result(Server, ok)
- end),
- ok.
-
-%%--------------------------------------------------------------------
-
-erlang_client_alpn_openssl_server_alpn_renegotiate(Config) when is_list(Config) ->
- Data = "From openssl to erlang",
- start_erlang_client_and_openssl_server_for_alpn_negotiation(Config, Data, fun(Client, OpensslPort) ->
- true = port_command(OpensslPort, ?OPENSSL_RENEGOTIATE),
- ct:sleep(?SLEEP),
- true = port_command(OpensslPort, Data),
-
- ssl_test_lib:check_result(Client, ok)
- end),
- ok.
-
-%%--------------------------------------------------------------------
-
-erlang_server_alpn_openssl_client_alpn_renegotiate(Config) when is_list(Config) ->
- Data = "From openssl to erlang",
- start_erlang_server_and_openssl_client_for_alpn_negotiation(Config, Data, fun(Client, OpensslPort) ->
- true = port_command(OpensslPort, ?OPENSSL_RENEGOTIATE),
- ct:sleep(?SLEEP),
- true = port_command(OpensslPort, Data),
-
- ssl_test_lib:check_result(Client, ok)
- end),
- ok.
-
-%%--------------------------------------------------------------------
-
-erlang_client_alpn_npn_openssl_server_alpn_npn(Config) when is_list(Config) ->
- Data = "From openssl to erlang",
- start_erlang_client_and_openssl_server_for_alpn_npn_negotiation(Config, Data, fun(Client, OpensslPort) ->
- true = port_command(OpensslPort, Data),
-
- ssl_test_lib:check_result(Client, ok)
- end),
- ok.
-
-%%--------------------------------------------------------------------
-
-erlang_server_alpn_npn_openssl_client_alpn_npn(Config) when is_list(Config) ->
- Data = "From openssl to erlang",
- start_erlang_server_and_openssl_client_for_alpn_npn_negotiation(Config, Data, fun(Client, OpensslPort) ->
- true = port_command(OpensslPort, Data),
-
- ssl_test_lib:check_result(Client, ok)
- end),
- ok.
-
-%%--------------------------------------------------------------------
-erlang_client_openssl_server_npn() ->
- [{doc,"Test erlang client with openssl server doing npn negotiation"}].
-
-erlang_client_openssl_server_npn(Config) when is_list(Config) ->
- Data = "From openssl to erlang",
- start_erlang_client_and_openssl_server_for_npn_negotiation(Config, Data, fun(Client, OpensslPort) ->
- true = port_command(OpensslPort, Data),
-
- ssl_test_lib:check_result(Client, ok)
- end),
- ok.
-
-%%--------------------------------------------------------------------
-erlang_client_openssl_server_npn_renegotiate() ->
- [{doc,"Test erlang client with openssl server doing npn negotiation and renegotiate"}].
-
-erlang_client_openssl_server_npn_renegotiate(Config) when is_list(Config) ->
- Data = "From openssl to erlang",
- start_erlang_client_and_openssl_server_for_npn_negotiation(Config, Data, fun(Client, OpensslPort) ->
- true = port_command(OpensslPort, ?OPENSSL_RENEGOTIATE),
- ct:sleep(?SLEEP),
- true = port_command(OpensslPort, Data),
- ssl_test_lib:check_result(Client, ok)
- end),
- ok.
-%%--------------------------------------------------------------------------
-erlang_server_openssl_client_npn() ->
- [{doc,"Test erlang server with openssl client and npn negotiation"}].
-
-erlang_server_openssl_client_npn(Config) when is_list(Config) ->
-
- Data = "From openssl to erlang",
- start_erlang_server_and_openssl_client_for_npn_negotiation(Config, Data, fun(Server, OpensslPort) ->
- true = port_command(OpensslPort, Data),
- ssl_test_lib:check_result(Server, ok)
- end),
- ok.
-
-%%--------------------------------------------------------------------------
-erlang_server_openssl_client_npn_renegotiate() ->
- [{doc,"Test erlang server with openssl client and npn negotiation with renegotiation"}].
-
-erlang_server_openssl_client_npn_renegotiate(Config) when is_list(Config) ->
- Data = "From openssl to erlang",
- start_erlang_server_and_openssl_client_for_npn_negotiation(Config, Data, fun(Server, OpensslPort) ->
- true = port_command(OpensslPort, ?OPENSSL_RENEGOTIATE),
- ct:sleep(?SLEEP),
- true = port_command(OpensslPort, Data),
- ssl_test_lib:check_result(Server, ok)
- end),
- ok.
-%%--------------------------------------------------------------------------
-erlang_client_openssl_server_npn_only_server(Config) when is_list(Config) ->
- Data = "From openssl to erlang",
- start_erlang_client_and_openssl_server_with_opts(Config, [],
- ["-nextprotoneg", "spdy/2"], Data, fun(Server, OpensslPort) ->
- true = port_command(OpensslPort, Data),
- ssl_test_lib:check_result(Server, ok)
- end),
- ok.
-
-%%--------------------------------------------------------------------------
-
-erlang_client_openssl_server_npn_only_client(Config) when is_list(Config) ->
- Data = "From openssl to erlang",
- start_erlang_client_and_openssl_server_with_opts(Config,
- [{client_preferred_next_protocols,
- {client, [<<"spdy/2">>], <<"http/1.1">>}}], [],
- Data, fun(Server, OpensslPort) ->
- true = port_command(OpensslPort, Data),
- ssl_test_lib:check_result(Server, ok)
- end),
- ok.
-
-%%--------------------------------------------------------------------------
-erlang_server_openssl_client_npn_only_server(Config) when is_list(Config) ->
- Data = "From openssl to erlang",
- start_erlang_server_and_openssl_client_with_opts(Config, [{next_protocols_advertised, [<<"spdy/2">>]}], [],
- Data, fun(Server, OpensslPort) ->
- true = port_command(OpensslPort, Data),
- ssl_test_lib:check_result(Server, ok)
- end),
- ok.
-
-erlang_server_openssl_client_npn_only_client(Config) when is_list(Config) ->
- Data = "From openssl to erlang",
- start_erlang_server_and_openssl_client_with_opts(Config, [], ["-nextprotoneg", "spdy/2"],
- Data, fun(Server, OpensslPort) ->
- true = port_command(OpensslPort, Data),
- ssl_test_lib:check_result(Server, ok)
- end),
- ok.
-%--------------------------------------------------------------------------
-erlang_server_openssl_client_sni_no_header(Config) when is_list(Config) ->
- erlang_server_openssl_client_sni_test(Config, undefined, undefined, "server Peer cert").
-
-erlang_server_openssl_client_sni_no_header_fun(Config) when is_list(Config) ->
- erlang_server_openssl_client_sni_test_sni_fun(Config, undefined, undefined, "server Peer cert").
-
-erlang_server_openssl_client_sni_match(Config) when is_list(Config) ->
- erlang_server_openssl_client_sni_test(Config, "a.server", "a.server", "server Peer cert").
-
-erlang_server_openssl_client_sni_match_fun(Config) when is_list(Config) ->
- erlang_server_openssl_client_sni_test_sni_fun(Config, "a.server", "a.server", "server Peer cert").
-
-erlang_server_openssl_client_sni_no_match(Config) when is_list(Config) ->
- erlang_server_openssl_client_sni_test(Config, "c.server", undefined, "server Peer cert").
-
-erlang_server_openssl_client_sni_no_match_fun(Config) when is_list(Config) ->
- erlang_server_openssl_client_sni_test_sni_fun(Config, "c.server", undefined, "server Peer cert").
-
-
-%%--------------------------------------------------------------------
-%% Internal functions ------------------------------------------------
-%%--------------------------------------------------------------------
-run_suites(Ciphers, Version, Config, Type) ->
- {ClientOpts, ServerOpts} =
- case Type of
- rsa ->
- {ssl_test_lib:ssl_options(client_rsa_opts, Config),
- ssl_test_lib:ssl_options(server_rsa_opts, Config)};
- dsa ->
- {ssl_test_lib:ssl_options(client_dsa_opts, Config),
- ssl_test_lib:ssl_options(server_dsa_verify_opts, Config)}
- end,
-
- Result = lists:map(fun(Cipher) ->
- cipher(Cipher, Version, Config, ClientOpts, ServerOpts) end,
- Ciphers),
- case lists:flatten(Result) of
- [] ->
- ok;
- Error ->
- ct:log("Cipher suite errors: ~p~n", [Error]),
- ct:fail(cipher_suite_failed_see_test_case_log)
- end.
-
-client_read_check([], _Data) ->
- ok;
-client_read_check([Hd | T], Data) ->
- case binary:match(Data, list_to_binary(Hd)) of
- nomatch ->
- nomatch;
- _ ->
- client_read_check(T, Data)
- end.
-client_check_result(Port, DataExpected, DataReceived) ->
- receive
- {Port, {data, TheData}} ->
- Data = list_to_binary(TheData),
- NewData = <<DataReceived/binary, Data/binary>>,
- ct:log("New Data: ~p", [NewData]),
- case client_read_check(DataExpected, NewData) of
- ok ->
- ok;
- _ ->
- client_check_result(Port, DataExpected, NewData)
- end
- after 20000 ->
- ct:fail({"Time out on openSSL Client", {expected, DataExpected},
- {got, DataReceived}})
- end.
-client_check_result(Port, DataExpected) ->
- client_check_result(Port, DataExpected, <<"">>).
-
-send_and_hostname(SSLSocket) ->
- ssl:send(SSLSocket, "OK"),
- case ssl:connection_information(SSLSocket, [sni_hostname]) of
- {ok, []} ->
- undefined;
- {ok, [{sni_hostname, Hostname}]} ->
- Hostname
- end.
-
-erlang_server_openssl_client_sni_test(Config, SNIHostname, ExpectedSNIHostname, ExpectedCN) ->
- Version = ssl_test_lib:protocol_version(Config),
- ct:log("Start running handshake, Config: ~p, SNIHostname: ~p, ExpectedSNIHostname: ~p, ExpectedCN: ~p", [Config, SNIHostname, ExpectedSNIHostname, ExpectedCN]),
- ServerOptions = proplists:get_value(sni_server_opts, Config) ++ proplists:get_value(server_rsa_opts, Config),
- {_, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
- Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0},
- {from, self()}, {mfa, {?MODULE, send_and_hostname, []}},
- {options, ServerOptions}]),
- Port = ssl_test_lib:inet_port(Server),
- Exe = "openssl",
- ClientArgs = case SNIHostname of
- undefined ->
- openssl_client_args(Version, Hostname,Port);
- _ ->
- openssl_client_args(Version, Hostname, Port, SNIHostname)
- end,
- ClientPort = ssl_test_lib:portable_open_port(Exe, ClientArgs),
-
- ssl_test_lib:check_result(Server, ExpectedSNIHostname),
- ssl_test_lib:close_port(ClientPort),
- ssl_test_lib:close(Server),
- ok.
-
-
-erlang_server_openssl_client_sni_test_sni_fun(Config, SNIHostname, ExpectedSNIHostname, ExpectedCN) ->
- Version = ssl_test_lib:protocol_version(Config),
- ct:log("Start running handshake for sni_fun, Config: ~p, SNIHostname: ~p, ExpectedSNIHostname: ~p, ExpectedCN: ~p", [Config, SNIHostname, ExpectedSNIHostname, ExpectedCN]),
- [{sni_hosts, ServerSNIConf}] = proplists:get_value(sni_server_opts, Config),
- SNIFun = fun(Domain) -> proplists:get_value(Domain, ServerSNIConf, undefined) end,
- ServerOptions = proplists:get_value(server_rsa_opts, Config) ++ [{sni_fun, SNIFun}],
- {_, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
- Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0},
- {from, self()}, {mfa, {?MODULE, send_and_hostname, []}},
- {options, ServerOptions}]),
- Port = ssl_test_lib:inet_port(Server),
- Exe = "openssl",
- ClientArgs = case SNIHostname of
- undefined ->
- openssl_client_args(Version, Hostname,Port);
- _ ->
- openssl_client_args(Version, Hostname, Port, SNIHostname)
- end,
-
- ClientPort = ssl_test_lib:portable_open_port(Exe, ClientArgs),
-
- ssl_test_lib:check_result(Server, ExpectedSNIHostname),
- ssl_test_lib:close_port(ClientPort),
- ssl_test_lib:close(Server).
-
-
-cipher(CipherSuite, Version, Config, ClientOpts, ServerOpts) ->
- process_flag(trap_exit, true),
- ct:log("Testing CipherSuite ~p~n", [CipherSuite]),
- {ClientNode, _ServerNode, Hostname} = ssl_test_lib:run_where(Config),
-
- 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), ssl_test_lib:version_flag(Version),
- "-cert", CertFile, "-key", KeyFile],
-
- OpenSslPort = ssl_test_lib:portable_open_port(Exe, Args),
-
- ssl_test_lib:wait_for_openssl_server(Port, proplists:get_value(protocol, Config)),
-
- ConnectionInfo = {ok, {Version, CipherSuite}},
-
- 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]}]),
-
- true = port_command(OpenSslPort, "Hello\n"),
-
- receive
- {Port, {data, _}} when is_port(Port) ->
- ok
- after 500 ->
- ct:log("Time out on openssl port, check that"
- " the messages Hello and world are received"
- " during close of port" , []),
- ok
- end,
-
- true = port_command(OpenSslPort, " world\n"),
-
- Result = ssl_test_lib:wait_for_result(Client, ok),
-
- %% Clean close down! Server needs to be closed first !!
- ssl_test_lib:close_port(OpenSslPort),
- ssl_test_lib:close(Client),
-
- Return = case Result of
- ok ->
- [];
- Error ->
- [{CipherSuite, Error}]
- end,
- process_flag(trap_exit, false),
- Return.
-
-start_erlang_client_and_openssl_server_with_opts(Config, ErlangClientOpts, OpensslServerOpts, Data, Callback) ->
- process_flag(trap_exit, true),
- ServerOpts = ssl_test_lib:ssl_options(server_rsa_verify_opts, Config),
- ClientOpts0 = ssl_test_lib:ssl_options(client_rsa_verify_opts, Config),
- ClientOpts = ErlangClientOpts ++ ClientOpts0,
-
- {ClientNode, _, Hostname} = ssl_test_lib:run_where(Config),
-
- Data = "From openssl to erlang",
-
- Port = ssl_test_lib:inet_port(node()),
- CaCertFile = proplists:get_value(cacertfile, ServerOpts),
- CertFile = proplists:get_value(certfile, ServerOpts),
- KeyFile = proplists:get_value(keyfile, ServerOpts),
- Version = ssl_test_lib:protocol_version(Config),
-
- Exe = "openssl",
- Args = case OpensslServerOpts of
- [] ->
- ["s_server", "-accept",
- integer_to_list(Port), ssl_test_lib:version_flag(Version),
- "-CAfile", CaCertFile,
- "-cert", CertFile,"-key", KeyFile];
- [Opt, Value] ->
- ["s_server", Opt, Value, "-accept",
- integer_to_list(Port), ssl_test_lib:version_flag(Version),
- "-CAfile", CaCertFile,
- "-cert", CertFile,"-key", KeyFile]
- end,
-
- OpensslPort = ssl_test_lib:portable_open_port(Exe, Args),
-
- ssl_test_lib:wait_for_openssl_server(Port, proplists:get_value(protocol, Config)),
-
- Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port},
- {host, Hostname},
- {from, self()},
- {mfa, {?MODULE,
- erlang_ssl_receive, [Data]}},
- {options, ClientOpts}]),
-
- Callback(Client, OpensslPort),
-
- %% 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).
-
-start_erlang_client_and_openssl_server_for_alpn_negotiation(Config, Data, Callback) ->
- process_flag(trap_exit, true),
- ServerOpts = proplists:get_value(server_rsa_verify_opts, Config),
- ClientOpts0 = proplists:get_value(client_rsa_verify_opts, Config),
- ClientOpts = [{alpn_advertised_protocols, [<<"spdy/2">>]} | ClientOpts0],
-
- {ClientNode, _, Hostname} = ssl_test_lib:run_where(Config),
-
- Data = "From openssl to erlang",
-
- Port = ssl_test_lib:inet_port(node()),
- CaCertFile = proplists:get_value(cacertfile, ServerOpts),
- CertFile = proplists:get_value(certfile, ServerOpts),
- KeyFile = proplists:get_value(keyfile, ServerOpts),
- Version = ssl_test_lib:protocol_version(Config),
-
- Exe = "openssl",
- Args = ["s_server", "-msg", "-alpn", "http/1.1,spdy/2", "-accept", integer_to_list(Port), ssl_test_lib:version_flag(Version),
- "-CAfile", CaCertFile,
- "-cert", CertFile, "-key", KeyFile],
- OpensslPort = ssl_test_lib:portable_open_port(Exe, Args),
- ssl_test_lib:wait_for_openssl_server(Port, proplists:get_value(protocol, Config)),
-
- Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port},
- {host, Hostname},
- {from, self()},
- {mfa, {?MODULE,
- erlang_ssl_receive_and_assert_negotiated_protocol, [<<"spdy/2">>, Data]}},
- {options, ClientOpts}]),
-
- Callback(Client, OpensslPort),
-
- %% 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).
-
-start_erlang_server_and_openssl_client_for_alpn_negotiation(Config, Data, Callback) ->
- process_flag(trap_exit, true),
- ServerOpts0 = proplists:get_value(server_rsa_opts, Config),
- ServerOpts = [{alpn_preferred_protocols, [<<"spdy/2">>]} | ServerOpts0],
-
- {_, ServerNode, _} = ssl_test_lib:run_where(Config),
-
-
- Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0},
- {from, self()},
- {mfa, {?MODULE, erlang_ssl_receive_and_assert_negotiated_protocol, [<<"spdy/2">>, Data]}},
- {options, ServerOpts}]),
- Port = ssl_test_lib:inet_port(Server),
- Version = ssl_test_lib:protocol_version(Config),
-
- Exe = "openssl",
- Args = ["s_client", "-alpn", "http/1.0,spdy/2", "-msg", "-port",
- integer_to_list(Port), ssl_test_lib:version_flag(Version),
- "-host", "localhost"],
-
- OpenSslPort = ssl_test_lib:portable_open_port(Exe, Args),
-
- Callback(Server, OpenSslPort),
-
- ssl_test_lib:close(Server),
-
- ssl_test_lib:close_port(OpenSslPort),
- process_flag(trap_exit, false).
-
-start_erlang_client_and_openssl_server_for_alpn_npn_negotiation(Config, Data, Callback) ->
- process_flag(trap_exit, true),
- ServerOpts = proplists:get_value(server_rsa_opts, Config),
- ClientOpts0 = proplists:get_value(client_rsa_opts, Config),
- ClientOpts = [{alpn_advertised_protocols, [<<"spdy/2">>]},
- {client_preferred_next_protocols, {client, [<<"spdy/3">>, <<"http/1.1">>]}} | ClientOpts0],
-
- {ClientNode, _, Hostname} = ssl_test_lib:run_where(Config),
-
- Data = "From openssl to erlang",
-
- Port = ssl_test_lib:inet_port(node()),
- CertFile = proplists:get_value(certfile, ServerOpts),
- KeyFile = proplists:get_value(keyfile, ServerOpts),
- Version = ssl_test_lib:protocol_version(Config),
-
- Exe = "openssl",
- Args = ["s_server", "-msg", "-alpn", "http/1.1,spdy/2", "-nextprotoneg",
- "spdy/3", "-accept", integer_to_list(Port), ssl_test_lib:version_flag(Version),
- "-cert", CertFile, "-key", KeyFile],
-
- OpensslPort = ssl_test_lib:portable_open_port(Exe, Args),
-
- ssl_test_lib:wait_for_openssl_server(Port, proplists:get_value(protocol, Config)),
-
- Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port},
- {host, Hostname},
- {from, self()},
- {mfa, {?MODULE,
- erlang_ssl_receive_and_assert_negotiated_protocol, [<<"spdy/2">>, Data]}},
- {options, ClientOpts}]),
-
- Callback(Client, OpensslPort),
-
- %% 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).
-
-start_erlang_server_and_openssl_client_for_alpn_npn_negotiation(Config, Data, Callback) ->
- process_flag(trap_exit, true),
- ServerOpts0 = proplists:get_value(server_rsa_opts, Config),
- ServerOpts = [{alpn_preferred_protocols, [<<"spdy/2">>]},
- {next_protocols_advertised, [<<"spdy/3">>, <<"http/1.1">>]} | ServerOpts0],
-
- {_, ServerNode, _} = ssl_test_lib:run_where(Config),
-
-
- Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0},
- {from, self()},
- {mfa, {?MODULE, erlang_ssl_receive_and_assert_negotiated_protocol, [<<"spdy/2">>, Data]}},
- {options, ServerOpts}]),
- Port = ssl_test_lib:inet_port(Server),
- Version = ssl_test_lib:protocol_version(Config),
- Exe = "openssl",
- Args = ["s_client", "-alpn", "http/1.1,spdy/2", "-nextprotoneg", "spdy/3",
- "-msg", "-port", integer_to_list(Port), ssl_test_lib:version_flag(Version),
- "-host", "localhost"],
- OpenSslPort = ssl_test_lib:portable_open_port(Exe, Args),
-
- Callback(Server, OpenSslPort),
-
- ssl_test_lib:close(Server),
- ssl_test_lib:close_port(OpenSslPort),
- process_flag(trap_exit, false).
-
-start_erlang_client_and_openssl_server_for_npn_negotiation(Config, Data, Callback) ->
- process_flag(trap_exit, true),
- ServerOpts = ssl_test_lib:ssl_options(server_rsa_verify_opts, Config),
- ClientOpts0 = ssl_test_lib:ssl_options(client_rsa_verify_opts, Config),
- ClientOpts = [{client_preferred_next_protocols, {client, [<<"spdy/2">>], <<"http/1.1">>}} | ClientOpts0],
-
- {ClientNode, _, Hostname} = ssl_test_lib:run_where(Config),
-
- Data = "From openssl to erlang",
-
- Port = ssl_test_lib:inet_port(node()),
- CaCertFile = proplists:get_value(cacertfile, ServerOpts),
- CertFile = proplists:get_value(certfile, ServerOpts),
- KeyFile = proplists:get_value(keyfile, ServerOpts),
- Version = ssl_test_lib:protocol_version(Config),
-
- Exe = "openssl",
- Args = ["s_server", "-msg", "-nextprotoneg", "http/1.1,spdy/2", "-accept", integer_to_list(Port),
- ssl_test_lib:version_flag(Version),
- "-CAfile", CaCertFile,
- "-cert", CertFile, "-key", KeyFile],
- OpensslPort = ssl_test_lib:portable_open_port(Exe, Args),
-
- ssl_test_lib:wait_for_openssl_server(Port, proplists:get_value(protocol, Config)),
-
- Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port},
- {host, Hostname},
- {from, self()},
- {mfa, {?MODULE,
- erlang_ssl_receive_and_assert_negotiated_protocol, [<<"spdy/2">>, Data]}},
- {options, ClientOpts}]),
-
- Callback(Client, OpensslPort),
-
- %% 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).
-
-start_erlang_server_and_openssl_client_for_npn_negotiation(Config, Data, Callback) ->
- process_flag(trap_exit, true),
- ServerOpts0 = ssl_test_lib:ssl_options(server_rsa_opts, Config),
- ServerOpts = [{next_protocols_advertised, [<<"spdy/2">>]}, ServerOpts0],
-
- {_, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
-
-
- Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0},
- {from, self()},
- {mfa, {?MODULE, erlang_ssl_receive_and_assert_negotiated_protocol, [<<"spdy/2">>, Data]}},
- {options, ServerOpts}]),
- Port = ssl_test_lib:inet_port(Server),
- Version = ssl_test_lib:protocol_version(Config),
-
- Exe = "openssl",
- Args = ["s_client", "-nextprotoneg", "http/1.0,spdy/2", "-msg", "-connect",
- hostname_format(Hostname) ++ ":"
- ++ integer_to_list(Port), ssl_test_lib:version_flag(Version)],
-
- OpenSslPort = ssl_test_lib:portable_open_port(Exe, Args),
-
- Callback(Server, OpenSslPort),
-
- ssl_test_lib:close(Server),
-
- ssl_test_lib:close_port(OpenSslPort),
- process_flag(trap_exit, false).
-
-
-start_erlang_server_and_openssl_client_with_opts(Config, ErlangServerOpts, OpenSSLClientOpts, Data, Callback) ->
- process_flag(trap_exit, true),
- ServerOpts0 = ssl_test_lib:ssl_options(server_rsa_opts, Config),
- ServerOpts = ErlangServerOpts ++ ServerOpts0,
-
- {_, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
-
-
- 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),
- Version = ssl_test_lib:protocol_version(Config),
-
- Exe = "openssl",
- Args = ["s_client"] ++ OpenSSLClientOpts ++ ["-msg", "-connect",
- hostname_format(Hostname) ++ ":" ++ integer_to_list(Port),
- ssl_test_lib:version_flag(Version)],
-
- OpenSslPort = ssl_test_lib:portable_open_port(Exe, Args),
-
- Callback(Server, OpenSslPort),
-
- ssl_test_lib:close(Server),
-
- ssl_test_lib:close_port(OpenSslPort),
- process_flag(trap_exit, false).
-
-
-erlang_ssl_receive_and_assert_negotiated_protocol(Socket, Protocol, Data) ->
- {ok, Protocol} = ssl:negotiated_protocol(Socket),
- erlang_ssl_receive(Socket, Data),
- {ok, Protocol} = ssl:negotiated_protocol(Socket),
- ok.
-
-erlang_ssl_receive(Socket, Data) ->
- ct:log("Connection info: ~p~n",
- [ssl:connection_information(Socket)]),
- receive
- {ssl, Socket, "R\n"} ->
- %% Swallow s_client renegotiation command.
- %% openssl s_client connected commands can appear on
- %% server side with some openssl versions.
- erlang_ssl_receive(Socket,Data);
- {ssl, Socket, Data} ->
- io:format("Received ~p~n",[Data]),
- %% open_ssl server sometimes hangs waiting in blocking read
- ssl:send(Socket, "Got it"),
- ok;
- {ssl, Socket, Byte} when length(Byte) == 1 ->
- erlang_ssl_receive(Socket, tl(Data));
- {Port, {data,Debug}} when is_port(Port) ->
- io:format("openssl ~s~n",[Debug]),
- erlang_ssl_receive(Socket,Data);
- Other ->
- ct:fail({unexpected_message, Other})
- end.
-
-connection_info(Socket, Version) ->
- case ssl:connection_information(Socket, [version]) of
- {ok, [{version, Version}] = Info} ->
- ct:log("Connection info: ~p~n", [Info]),
- ok;
- {ok, [{version, OtherVersion}]} ->
- {wrong_version, OtherVersion}
- end.
-
-connection_info_result(Socket) ->
- ssl:connection_information(Socket).
-
-
-delayed_send(Socket, [ErlData, OpenSslData]) ->
- ct:sleep(?SLEEP),
- ssl:send(Socket, ErlData),
- erlang_ssl_receive(Socket, OpenSslData).
-
-server_sent_garbage(Socket) ->
- receive
- server_sent_garbage ->
- {error, closed} == ssl:send(Socket, "data")
-
- end.
-
-send_wait_send(Socket, [ErlData, OpenSslData]) ->
- ssl:send(Socket, ErlData),
- ct:sleep(?SLEEP),
- ssl:send(Socket, ErlData),
- erlang_ssl_receive(Socket, OpenSslData).
-
-check_openssl_sni_support(Config) ->
- HelpText = os:cmd("openssl s_client --help"),
- case ssl_test_lib:is_sane_oppenssl_client() of
- true ->
- case string:str(HelpText, "-servername") of
- 0 ->
- {skip, "Current openssl doesn't support SNI"};
- _ ->
- Config
- end;
- false ->
- {skip, "Current openssl doesn't support SNI or extension handling is flawed"}
- end.
-
-
-check_openssl_npn_support(Config) ->
- HelpText = os:cmd("openssl s_client --help"),
- case string:str(HelpText, "nextprotoneg") of
- 0 ->
- {skip, "Openssl not compiled with nextprotoneg support"};
- _ ->
- Config
- end.
-
-check_openssl_alpn_support(Config) ->
- HelpText = os:cmd("openssl s_client --help"),
- case string:str(HelpText, "alpn") of
- 0 ->
- {skip, "Openssl not compiled with alpn support"};
- _ ->
- Config
- end.
-
-check_sane_openssl_renegotaite(Config, Version) when Version == 'tlsv1.1';
- Version == 'tlsv1.2' ->
- case os:cmd("openssl version") of
- "OpenSSL 1.0.1c" ++ _ ->
- {skip, "Known renegotiation bug in OpenSSL"};
- "OpenSSL 1.0.1b" ++ _ ->
- {skip, "Known renegotiation bug in OpenSSL"};
- "OpenSSL 1.0.1a" ++ _ ->
- {skip, "Known renegotiation bug in OpenSSL"};
- "OpenSSL 1.0.1 " ++ _ ->
- {skip, "Known renegotiation bug in OpenSSL"};
- _ ->
- check_sane_openssl_renegotaite(Config)
- end;
-check_sane_openssl_renegotaite(Config, _) ->
- check_sane_openssl_renegotaite(Config).
-
-check_sane_openssl_renegotaite(Config) ->
- case os:cmd("openssl version") of
- "OpenSSL 1.0.0" ++ _ ->
- {skip, "Known renegotiation bug in OpenSSL"};
- "OpenSSL 0.9.8" ++ _ ->
- {skip, "Known renegotiation bug in OpenSSL"};
- "OpenSSL 0.9.7" ++ _ ->
- {skip, "Known renegotiation bug in OpenSSL"};
- _ ->
- Config
- end.
-
-workaround_openssl_s_clinent() ->
- %% http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=683159
- %% https://bugs.archlinux.org/task/33919
- %% Bug seems to manifests it self if TLS version is not
- %% explicitly specified
- case os:cmd("openssl version") of
- "OpenSSL 1.0.1c" ++ _ ->
- ["-no_tls1_2"];
- "OpenSSL 1.0.1d" ++ _ ->
- ["-no_tls1_2"];
- "OpenSSL 1.0.1e" ++ _ ->
- ["-no_tls1_2"];
- "OpenSSL 1.0.1f" ++ _ ->
- ["-no_tls1_2"];
- _ ->
- []
- end.
-
-openssl_client_args(Version, Hostname, Port) ->
- ["s_client", "-connect", Hostname ++ ":" ++ integer_to_list(Port), ssl_test_lib:version_flag(Version)].
-
-openssl_client_args(Version, Hostname, Port, ServerName) ->
- ["s_client", "-connect", Hostname ++ ":" ++
- integer_to_list(Port), ssl_test_lib:version_flag(Version), "-servername", ServerName].
-
-
-hostname_format(Hostname) ->
- case lists:member($., Hostname) of
- true ->
- Hostname;
- false ->
- "localhost"
- end.
-
-
-openssl_has_common_ciphers(Ciphers) ->
- OCiphers = ssl_test_lib:common_ciphers(openssl),
- has_common_ciphers(Ciphers, OCiphers).
-
-has_common_ciphers([], _) ->
- false;
-has_common_ciphers([Cipher | Rest], OCiphers) ->
- case lists:member(Cipher, OCiphers) of
- true ->
- true;
- _ ->
- has_common_ciphers(Rest, OCiphers)
- end.
diff --git a/lib/ssl/test/tls_1_3_record_SUITE.erl b/lib/ssl/test/tls_1_3_record_SUITE.erl
new file mode 100644
index 0000000000..5df8853b1b
--- /dev/null
+++ b/lib/ssl/test/tls_1_3_record_SUITE.erl
@@ -0,0 +1,973 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2008-2018. 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(tls_1_3_record_SUITE).
+
+%% Note: This directive should only be used in test suites.
+-compile(export_all).
+
+-include_lib("common_test/include/ct.hrl").
+-include_lib("ssl/src/tls_record.hrl").
+-include_lib("ssl/src/tls_handshake.hrl").
+-include_lib("ssl/src/ssl_cipher.hrl").
+-include_lib("ssl/src/ssl_internal.hrl").
+
+all() ->
+ [encode_decode,
+ finished_verify_data,
+ '1_RTT_handshake'].
+
+init_per_suite(Config) ->
+ catch crypto:stop(),
+ try (ok == crypto:start()) andalso ssl_test_lib:sufficient_crypto_support('tlsv1.3') of
+ true ->
+ ssl_test_lib:clean_start(),
+ Config;
+ false ->
+ {skip, "Not enough crypto support for TLS-1.3"}
+ catch _:_ ->
+ {skip, "Crypto did not start"}
+ end.
+
+end_per_suite(_Config) ->
+ ssl:stop(),
+ application:unload(ssl),
+ application:stop(crypto).
+%%--------------------------------------------------------------------
+%% Test Cases --------------------------------------------------------
+%%--------------------------------------------------------------------
+
+encode_decode() ->
+ [{doc,"Test TLS 1.3 record encode/decode functions"}].
+
+encode_decode(_Config) ->
+ ConnectionStates =
+ #{current_read =>
+ #{beast_mitigation => one_n_minus_one,
+ cipher_state =>
+ {cipher_state,
+ <<14,172,111,243,199,170,242,203,126,205,34,93,122,115,226,14,
+ 15,117,155,48,24,112,61,15,113,208,127,51,179,227,194,232>>,
+ <<197,54,168,218,54,91,157,58,30,201,197,142,51,58,53,231,228,
+ 131,57,122,170,78,82,196,30,48,23,16,95,255,185,236>>,
+ undefined,undefined,undefined,16},
+ client_verify_data => undefined,compression_state => undefined,
+ mac_secret => undefined,secure_renegotiation => undefined,
+ security_parameters =>
+ {security_parameters,
+ <<19,2>>,
+ 0,8,2,undefined,undefined,undefined,undefined,undefined,
+ sha384,undefined,undefined,
+ {handshake_secret,
+ <<128,229,186,211,62,127,182,20,62,166,233,23,135,64,121,
+ 3,104,251,214,161,253,31,3,2,232,37,8,221,189,72,64,218,
+ 121,41,112,148,254,34,68,164,228,60,161,201,132,55,56,
+ 157>>},
+ undefined,
+ <<92,24,205,75,244,60,136,212,250,32,214,20,37,3,213,87,61,207,
+ 147,61,168,145,177,118,160,153,33,53,48,108,191,174>>,
+ undefined},
+ sequence_number => 0,server_verify_data => undefined},
+ current_write =>
+ #{beast_mitigation => one_n_minus_one,
+ cipher_state =>
+ {cipher_state,
+ <<14,172,111,243,199,170,242,203,126,205,34,93,122,115,226,14,
+ 15,117,155,48,24,112,61,15,113,208,127,51,179,227,194,232>>,
+ <<197,54,168,218,54,91,157,58,30,201,197,142,51,58,53,231,228,
+ 131,57,122,170,78,82,196,30,48,23,16,95,255,185,236>>,
+ undefined,undefined,undefined,16},
+ client_verify_data => undefined,compression_state => undefined,
+ mac_secret => undefined,secure_renegotiation => undefined,
+ security_parameters =>
+ {security_parameters,
+ <<19,2>>,
+ 0,8,2,undefined,undefined,undefined,undefined,undefined,
+ sha384,undefined,undefined,
+ {handshake_secret,
+ <<128,229,186,211,62,127,182,20,62,166,233,23,135,64,121,
+ 3,104,251,214,161,253,31,3,2,232,37,8,221,189,72,64,218,
+ 121,41,112,148,254,34,68,164,228,60,161,201,132,55,56,
+ 157>>},
+ undefined,
+ <<92,24,205,75,244,60,136,212,250,32,214,20,37,3,213,87,61,207,
+ 147,61,168,145,177,118,160,153,33,53,48,108,191,174>>,
+ undefined},
+ sequence_number => 0,server_verify_data => undefined}},
+
+ PlainText = [11,
+ <<0,2,175>>,
+ <<0,0,2,171,0,2,166,48,130,2,162,48,130,1,138,2,9,0,186,57,220,137,88,255,
+ 191,235,48,13,6,9,42,134,72,134,247,13,1,1,11,5,0,48,18,49,16,48,14,6,3,85,
+ 4,3,12,7,84,101,115,116,32,67,65,48,30,23,13,49,56,48,53,48,52,49,52,49,50,
+ 51,56,90,23,13,50,56,48,50,48,52,49,52,49,50,51,56,90,48,20,49,18,48,16,6,
+ 3,85,4,3,12,9,108,111,99,97,108,104,111,115,116,48,130,1,34,48,13,6,9,42,
+ 134,72,134,247,13,1,1,1,5,0,3,130,1,15,0,48,130,1,10,2,130,1,1,0,169,40,
+ 144,176,121,63,134,97,144,126,243,183,225,157,37,131,183,225,87,243,23,88,
+ 230,70,9,134,32,147,7,27,167,98,51,81,224,75,199,12,229,251,195,207,75,179,
+ 181,78,128,3,255,44,58,39,43,172,142,45,186,58,51,65,187,199,154,153,245,
+ 70,133,137,1,27,87,42,116,65,251,129,109,145,233,97,171,71,54,213,185,74,
+ 209,166,11,218,189,119,206,86,170,60,212,213,85,189,30,50,215,23,185,53,
+ 132,238,132,176,198,250,139,251,198,221,225,128,109,113,23,220,39,143,71,
+ 30,59,189,51,244,61,158,214,146,180,196,103,169,189,221,136,78,129,216,148,
+ 2,9,8,65,37,224,215,233,13,209,21,235,20,143,33,74,59,53,208,90,152,94,251,
+ 54,114,171,39,88,230,227,158,211,135,37,182,67,205,161,59,20,138,58,253,15,
+ 53,48,8,157,9,95,197,9,177,116,21,54,9,125,78,109,182,83,20,16,234,223,116,
+ 41,155,123,87,77,17,120,153,246,239,124,130,105,219,166,146,242,151,66,198,
+ 75,72,63,28,246,86,16,244,223,22,36,50,15,247,222,98,6,152,136,154,72,150,
+ 73,127,2,3,1,0,1,48,13,6,9,42,134,72,134,247,13,1,1,11,5,0,3,130,1,1,0,76,
+ 33,54,160,229,219,219,193,150,116,245,252,18,39,235,145,86,12,167,171,52,
+ 117,166,30,83,5,216,245,177,217,247,95,1,136,94,246,212,108,248,230,111,
+ 225,202,189,6,129,8,70,128,245,18,204,215,87,82,129,253,227,122,66,182,184,
+ 189,30,193,169,144,218,216,109,105,110,215,144,60,104,162,178,101,164,218,
+ 122,60,37,41,143,57,150,52,59,51,112,238,113,239,168,114,69,183,143,154,73,
+ 61,58,80,247,172,95,251,55,28,186,28,200,206,230,118,243,92,202,189,49,76,
+ 124,252,76,0,247,112,85,194,69,59,222,163,228,103,49,110,104,109,251,155,
+ 138,9,37,167,49,189,48,134,52,158,185,129,24,96,153,196,251,90,206,76,239,
+ 175,119,174,165,133,108,222,125,237,125,187,149,152,83,190,16,202,94,202,
+ 201,40,218,22,254,63,189,41,174,97,140,203,70,18,196,118,237,175,134,79,78,
+ 246,2,61,54,77,186,112,32,17,193,192,188,217,252,215,200,7,245,180,179,132,
+ 183,212,229,155,15,152,206,135,56,81,88,3,123,244,149,110,182,72,109,70,62,
+ 146,152,146,151,107,126,216,210,9,93,0,0>>],
+
+ {[_Header|Encoded], _} = tls_record_1_3:encode_plain_text(22, PlainText, ConnectionStates),
+ CipherText = #ssl_tls{type = 23, version = {3,3}, fragment = Encoded},
+
+ {#ssl_tls{type = 22, version = {3,4}, fragment = DecodedText}, _} =
+ tls_record_1_3:decode_cipher_text(CipherText, ConnectionStates),
+
+ DecodedText = iolist_to_binary(PlainText),
+ ct:log("Decoded: ~p ~n", [DecodedText]),
+ ok.
+%%--------------------------------------------------------------------
+'1_RTT_handshake'() ->
+ [{doc,"Test TLS 1.3 1-RTT Handshake"}].
+
+'1_RTT_handshake'(_Config) ->
+ %% ConnectionStates with NULL cipher
+ ConnStatesNull =
+ #{current_write =>
+ #{security_parameters =>
+ #security_parameters{cipher_suite = ?TLS_NULL_WITH_NULL_NULL},
+ sequence_number => 0
+ }
+ },
+
+ %% {client} construct a ClientHello handshake message:
+ %%
+ %% ClientHello (196 octets): 01 00 00 c0 03 03 cb 34 ec b1 e7 81 63
+ %% ba 1c 38 c6 da cb 19 6a 6d ff a2 1a 8d 99 12 ec 18 a2 ef 62 83
+ %% 02 4d ec e7 00 00 06 13 01 13 03 13 02 01 00 00 91 00 00 00 0b
+ %% 00 09 00 00 06 73 65 72 76 65 72 ff 01 00 01 00 00 0a 00 14 00
+ %% 12 00 1d 00 17 00 18 00 19 01 00 01 01 01 02 01 03 01 04 00 23
+ %% 00 00 00 33 00 26 00 24 00 1d 00 20 99 38 1d e5 60 e4 bd 43 d2
+ %% 3d 8e 43 5a 7d ba fe b3 c0 6e 51 c1 3c ae 4d 54 13 69 1e 52 9a
+ %% af 2c 00 2b 00 03 02 03 04 00 0d 00 20 00 1e 04 03 05 03 06 03
+ %% 02 03 08 04 08 05 08 06 04 01 05 01 06 01 02 01 04 02 05 02 06
+ %% 02 02 02 00 2d 00 02 01 01 00 1c 00 02 40 01
+ %%
+ %% {client} send handshake record:
+ %%
+ %% payload (196 octets): 01 00 00 c0 03 03 cb 34 ec b1 e7 81 63 ba
+ %% 1c 38 c6 da cb 19 6a 6d ff a2 1a 8d 99 12 ec 18 a2 ef 62 83 02
+ %% 4d ec e7 00 00 06 13 01 13 03 13 02 01 00 00 91 00 00 00 0b 00
+ %% 09 00 00 06 73 65 72 76 65 72 ff 01 00 01 00 00 0a 00 14 00 12
+ %% 00 1d 00 17 00 18 00 19 01 00 01 01 01 02 01 03 01 04 00 23 00
+ %% 00 00 33 00 26 00 24 00 1d 00 20 99 38 1d e5 60 e4 bd 43 d2 3d
+ %% 8e 43 5a 7d ba fe b3 c0 6e 51 c1 3c ae 4d 54 13 69 1e 52 9a af
+ %% 2c 00 2b 00 03 02 03 04 00 0d 00 20 00 1e 04 03 05 03 06 03 02
+ %% 03 08 04 08 05 08 06 04 01 05 01 06 01 02 01 04 02 05 02 06 02
+ %% 02 02 00 2d 00 02 01 01 00 1c 00 02 40 01
+ %%
+ %% complete record (201 octets): 16 03 01 00 c4 01 00 00 c0 03 03 cb
+ %% 34 ec b1 e7 81 63 ba 1c 38 c6 da cb 19 6a 6d ff a2 1a 8d 99 12
+ %% ec 18 a2 ef 62 83 02 4d ec e7 00 00 06 13 01 13 03 13 02 01 00
+ %% 00 91 00 00 00 0b 00 09 00 00 06 73 65 72 76 65 72 ff 01 00 01
+ %% 00 00 0a 00 14 00 12 00 1d 00 17 00 18 00 19 01 00 01 01 01 02
+ %% 01 03 01 04 00 23 00 00 00 33 00 26 00 24 00 1d 00 20 99 38 1d
+ %% e5 60 e4 bd 43 d2 3d 8e 43 5a 7d ba fe b3 c0 6e 51 c1 3c ae 4d
+ %% 54 13 69 1e 52 9a af 2c 00 2b 00 03 02 03 04 00 0d 00 20 00 1e
+ %% 04 03 05 03 06 03 02 03 08 04 08 05 08 06 04 01 05 01 06 01 02
+ %% 01 04 02 05 02 06 02 02 02 00 2d 00 02 01 01 00 1c 00 02 40 01
+ ClientHello =
+ hexstr2bin("01 00 00 c0 03 03 cb 34 ec b1 e7 81 63
+ ba 1c 38 c6 da cb 19 6a 6d ff a2 1a 8d 99 12 ec 18 a2 ef 62 83
+ 02 4d ec e7 00 00 06 13 01 13 03 13 02 01 00 00 91 00 00 00 0b
+ 00 09 00 00 06 73 65 72 76 65 72 ff 01 00 01 00 00 0a 00 14 00
+ 12 00 1d 00 17 00 18 00 19 01 00 01 01 01 02 01 03 01 04 00 23
+ 00 00 00 33 00 26 00 24 00 1d 00 20 99 38 1d e5 60 e4 bd 43 d2
+ 3d 8e 43 5a 7d ba fe b3 c0 6e 51 c1 3c ae 4d 54 13 69 1e 52 9a
+ af 2c 00 2b 00 03 02 03 04 00 0d 00 20 00 1e 04 03 05 03 06 03
+ 02 03 08 04 08 05 08 06 04 01 05 01 06 01 02 01 04 02 05 02 06
+ 02 02 02 00 2d 00 02 01 01 00 1c 00 02 40 01"),
+
+ ClientHelloRecord =
+ %% Current implementation always sets
+ %% legacy_record_version to Ox0303
+ hexstr2bin("16 03 03 00 c4 01 00 00 c0 03 03 cb
+ 34 ec b1 e7 81 63 ba 1c 38 c6 da cb 19 6a 6d ff a2 1a 8d 99 12
+ ec 18 a2 ef 62 83 02 4d ec e7 00 00 06 13 01 13 03 13 02 01 00
+ 00 91 00 00 00 0b 00 09 00 00 06 73 65 72 76 65 72 ff 01 00 01
+ 00 00 0a 00 14 00 12 00 1d 00 17 00 18 00 19 01 00 01 01 01 02
+ 01 03 01 04 00 23 00 00 00 33 00 26 00 24 00 1d 00 20 99 38 1d
+ e5 60 e4 bd 43 d2 3d 8e 43 5a 7d ba fe b3 c0 6e 51 c1 3c ae 4d
+ 54 13 69 1e 52 9a af 2c 00 2b 00 03 02 03 04 00 0d 00 20 00 1e
+ 04 03 05 03 06 03 02 03 08 04 08 05 08 06 04 01 05 01 06 01 02
+ 01 04 02 05 02 06 02 02 02 00 2d 00 02 01 01 00 1c 00 02 40 01"),
+
+ {CHEncrypted, _} =
+ tls_record:encode_handshake(ClientHello, {3,4}, ConnStatesNull),
+ ClientHelloRecord = iolist_to_binary(CHEncrypted),
+
+ %% {server} extract secret "early":
+ %%
+ %% salt: 0 (all zero octets)
+ %%
+ %% IKM (32 octets): 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+ %% 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+ %%
+ %% secret (32 octets): 33 ad 0a 1c 60 7e c0 3b 09 e6 cd 98 93 68 0c
+ %% e2 10 ad f3 00 aa 1f 26 60 e1 b2 2e 10 f1 70 f9 2a
+ HKDFAlgo = sha256,
+ Salt = binary:copy(<<?BYTE(0)>>, 32),
+ IKM = binary:copy(<<?BYTE(0)>>, 32),
+ EarlySecret =
+ hexstr2bin("33 ad 0a 1c 60 7e c0 3b 09 e6 cd 98 93 68 0c
+ e2 10 ad f3 00 aa 1f 26 60 e1 b2 2e 10 f1 70 f9 2a"),
+
+ {early_secret, EarlySecret} = tls_v1:key_schedule(early_secret, HKDFAlgo, {psk, Salt}),
+
+ %% {client} create an ephemeral x25519 key pair:
+ %%
+ %% private key (32 octets): 49 af 42 ba 7f 79 94 85 2d 71 3e f2 78
+ %% 4b cb ca a7 91 1d e2 6a dc 56 42 cb 63 45 40 e7 ea 50 05
+ %%
+ %% public key (32 octets): 99 38 1d e5 60 e4 bd 43 d2 3d 8e 43 5a 7d
+ %% ba fe b3 c0 6e 51 c1 3c ae 4d 54 13 69 1e 52 9a af 2c
+ CPublicKey =
+ hexstr2bin("99 38 1d e5 60 e4 bd 43 d2 3d 8e 43 5a 7d
+ ba fe b3 c0 6e 51 c1 3c ae 4d 54 13 69 1e 52 9a af 2c"),
+
+ %% {server} create an ephemeral x25519 key pair:
+ %%
+ %% private key (32 octets): b1 58 0e ea df 6d d5 89 b8 ef 4f 2d 56
+ %% 52 57 8c c8 10 e9 98 01 91 ec 8d 05 83 08 ce a2 16 a2 1e
+ %%
+ %% public key (32 octets): c9 82 88 76 11 20 95 fe 66 76 2b db f7 c6
+ %% 72 e1 56 d6 cc 25 3b 83 3d f1 dd 69 b1 b0 4e 75 1f 0f
+ SPrivateKey =
+ hexstr2bin("b1 58 0e ea df 6d d5 89 b8 ef 4f 2d 56
+ 52 57 8c c8 10 e9 98 01 91 ec 8d 05 83 08 ce a2 16 a2 1e"),
+
+ SPublicKey =
+ hexstr2bin("c9 82 88 76 11 20 95 fe 66 76 2b db f7 c6
+ 72 e1 56 d6 cc 25 3b 83 3d f1 dd 69 b1 b0 4e 75 1f 0f"),
+
+ %% {server} construct a ServerHello handshake message:
+ %%
+ %% ServerHello (90 octets): 02 00 00 56 03 03 a6 af 06 a4 12 18 60
+ %% dc 5e 6e 60 24 9c d3 4c 95 93 0c 8a c5 cb 14 34 da c1 55 77 2e
+ %% d3 e2 69 28 00 13 01 00 00 2e 00 33 00 24 00 1d 00 20 c9 82 88
+ %% 76 11 20 95 fe 66 76 2b db f7 c6 72 e1 56 d6 cc 25 3b 83 3d f1
+ %% dd 69 b1 b0 4e 75 1f 0f 00 2b 00 02 03 04
+ ServerHello =
+ hexstr2bin("02 00 00 56 03 03 a6 af 06 a4 12 18 60
+ dc 5e 6e 60 24 9c d3 4c 95 93 0c 8a c5 cb 14 34 da c1 55 77 2e
+ d3 e2 69 28 00 13 01 00 00 2e 00 33 00 24 00 1d 00 20 c9 82 88
+ 76 11 20 95 fe 66 76 2b db f7 c6 72 e1 56 d6 cc 25 3b 83 3d f1
+ dd 69 b1 b0 4e 75 1f 0f 00 2b 00 02 03 04"),
+
+ %% {server} derive secret for handshake "tls13 derived":
+ %%
+ %% PRK (32 octets): 33 ad 0a 1c 60 7e c0 3b 09 e6 cd 98 93 68 0c e2
+ %% 10 ad f3 00 aa 1f 26 60 e1 b2 2e 10 f1 70 f9 2a
+ %%
+ %% hash (32 octets): e3 b0 c4 42 98 fc 1c 14 9a fb f4 c8 99 6f b9 24
+ %% 27 ae 41 e4 64 9b 93 4c a4 95 99 1b 78 52 b8 55
+ %%
+ %% info (49 octets): 00 20 0d 74 6c 73 31 33 20 64 65 72 69 76 65 64
+ %% 20 e3 b0 c4 42 98 fc 1c 14 9a fb f4 c8 99 6f b9 24 27 ae 41 e4
+ %% 64 9b 93 4c a4 95 99 1b 78 52 b8 55
+ %%
+ %% expanded (32 octets): 6f 26 15 a1 08 c7 02 c5 67 8f 54 fc 9d ba
+ %% b6 97 16 c0 76 18 9c 48 25 0c eb ea c3 57 6c 36 11 ba
+ Hash =
+ hexstr2bin("e3 b0 c4 42 98 fc 1c 14 9a fb f4 c8 99 6f b9 24
+ 27 ae 41 e4 64 9b 93 4c a4 95 99 1b 78 52 b8 55"),
+
+ Hash = crypto:hash(HKDFAlgo, <<>>),
+
+ Info =
+ hexstr2bin("00 20 0d 74 6c 73 31 33 20 64 65 72 69 76 65 64
+ 20 e3 b0 c4 42 98 fc 1c 14 9a fb f4 c8 99 6f b9 24 27 ae 41 e4
+ 64 9b 93 4c a4 95 99 1b 78 52 b8 55"),
+
+ Info = tls_v1:create_info(<<"derived">>, Hash, ssl_cipher:hash_size(HKDFAlgo)),
+
+ Expanded =
+ hexstr2bin("6f 26 15 a1 08 c7 02 c5 67 8f 54 fc 9d ba
+ b6 97 16 c0 76 18 9c 48 25 0c eb ea c3 57 6c 36 11 ba"),
+
+ Expanded = tls_v1:derive_secret(EarlySecret, <<"derived">>, <<>>, HKDFAlgo),
+
+ %% {server} extract secret "handshake":
+ %%
+ %% salt (32 octets): 6f 26 15 a1 08 c7 02 c5 67 8f 54 fc 9d ba b6 97
+ %% 16 c0 76 18 9c 48 25 0c eb ea c3 57 6c 36 11 ba
+ %%
+ %% IKM (32 octets): 8b d4 05 4f b5 5b 9d 63 fd fb ac f9 f0 4b 9f 0d
+ %% 35 e6 d6 3f 53 75 63 ef d4 62 72 90 0f 89 49 2d
+ %%
+ %% secret (32 octets): 1d c8 26 e9 36 06 aa 6f dc 0a ad c1 2f 74 1b
+ %% 01 04 6a a6 b9 9f 69 1e d2 21 a9 f0 ca 04 3f be ac
+
+ %% salt = Expanded
+ HandshakeIKM =
+ hexstr2bin("8b d4 05 4f b5 5b 9d 63 fd fb ac f9 f0 4b 9f 0d
+ 35 e6 d6 3f 53 75 63 ef d4 62 72 90 0f 89 49 2d"),
+
+ HandshakeSecret =
+ hexstr2bin("1d c8 26 e9 36 06 aa 6f dc 0a ad c1 2f 74 1b
+ 01 04 6a a6 b9 9f 69 1e d2 21 a9 f0 ca 04 3f be ac"),
+
+ HandshakeIKM = crypto:compute_key(ecdh, CPublicKey, SPrivateKey, x25519),
+
+ {handshake_secret, HandshakeSecret} =
+ tls_v1:key_schedule(handshake_secret, HKDFAlgo, HandshakeIKM,
+ {early_secret, EarlySecret}),
+
+ %% {server} derive secret "tls13 c hs traffic":
+ %%
+ %% PRK (32 octets): 1d c8 26 e9 36 06 aa 6f dc 0a ad c1 2f 74 1b 01
+ %% 04 6a a6 b9 9f 69 1e d2 21 a9 f0 ca 04 3f be ac
+ %%
+ %% hash (32 octets): 86 0c 06 ed c0 78 58 ee 8e 78 f0 e7 42 8c 58 ed
+ %% d6 b4 3f 2c a3 e6 e9 5f 02 ed 06 3c f0 e1 ca d8
+ %%
+ %% info (54 octets): 00 20 12 74 6c 73 31 33 20 63 20 68 73 20 74 72
+ %% 61 66 66 69 63 20 86 0c 06 ed c0 78 58 ee 8e 78 f0 e7 42 8c 58
+ %% ed d6 b4 3f 2c a3 e6 e9 5f 02 ed 06 3c f0 e1 ca d8
+ %%
+ %% expanded (32 octets): b3 ed db 12 6e 06 7f 35 a7 80 b3 ab f4 5e
+ %% 2d 8f 3b 1a 95 07 38 f5 2e 96 00 74 6a 0e 27 a5 5a 21
+
+ %% PRK = HandshakeSecret
+ CHSTHash =
+ hexstr2bin("86 0c 06 ed c0 78 58 ee 8e 78 f0 e7 42 8c 58 ed
+ d6 b4 3f 2c a3 e6 e9 5f 02 ed 06 3c f0 e1 ca d8"),
+
+ CHSTInfo =
+ hexstr2bin("00 20 12 74 6c 73 31 33 20 63 20 68 73 20 74 72
+ 61 66 66 69 63 20 86 0c 06 ed c0 78 58 ee 8e 78 f0 e7 42 8c 58
+ ed d6 b4 3f 2c a3 e6 e9 5f 02 ed 06 3c f0 e1 ca d8"),
+
+ CHSTrafficSecret =
+ hexstr2bin(" b3 ed db 12 6e 06 7f 35 a7 80 b3 ab f4 5e
+ 2d 8f 3b 1a 95 07 38 f5 2e 96 00 74 6a 0e 27 a5 5a 21"),
+
+ CHSH = <<ClientHello/binary,ServerHello/binary>>,
+ CHSTHash = crypto:hash(HKDFAlgo, CHSH),
+ CHSTInfo = tls_v1:create_info(<<"c hs traffic">>, CHSTHash, ssl_cipher:hash_size(HKDFAlgo)),
+
+ CHSTrafficSecret =
+ tls_v1:client_handshake_traffic_secret(HKDFAlgo, {handshake_secret, HandshakeSecret}, CHSH),
+
+ %% {server} derive secret "tls13 s hs traffic":
+ %%
+ %% PRK (32 octets): 1d c8 26 e9 36 06 aa 6f dc 0a ad c1 2f 74 1b 01
+ %% 04 6a a6 b9 9f 69 1e d2 21 a9 f0 ca 04 3f be ac
+ %%
+ %% hash (32 octets): 86 0c 06 ed c0 78 58 ee 8e 78 f0 e7 42 8c 58 ed
+ %% d6 b4 3f 2c a3 e6 e9 5f 02 ed 06 3c f0 e1 ca d8
+ %%
+ %% info (54 octets): 00 20 12 74 6c 73 31 33 20 73 20 68 73 20 74 72
+ %% 61 66 66 69 63 20 86 0c 06 ed c0 78 58 ee 8e 78 f0 e7 42 8c 58
+ %% ed d6 b4 3f 2c a3 e6 e9 5f 02 ed 06 3c f0 e1 ca d8
+ %%
+ %% expanded (32 octets): b6 7b 7d 69 0c c1 6c 4e 75 e5 42 13 cb 2d
+ %% 37 b4 e9 c9 12 bc de d9 10 5d 42 be fd 59 d3 91 ad 38
+
+ %% PRK = HandshakeSecret
+ %% hash = CHSTHash
+ SHSTInfo =
+ hexstr2bin("00 20 12 74 6c 73 31 33 20 73 20 68 73 20 74 72
+ 61 66 66 69 63 20 86 0c 06 ed c0 78 58 ee 8e 78 f0 e7 42 8c 58
+ ed d6 b4 3f 2c a3 e6 e9 5f 02 ed 06 3c f0 e1 ca d8"),
+
+ SHSTrafficSecret =
+ hexstr2bin("b6 7b 7d 69 0c c1 6c 4e 75 e5 42 13 cb 2d
+ 37 b4 e9 c9 12 bc de d9 10 5d 42 be fd 59 d3 91 ad 38"),
+
+ SHSTInfo = tls_v1:create_info(<<"s hs traffic">>, CHSTHash, ssl_cipher:hash_size(HKDFAlgo)),
+
+ SHSTrafficSecret =
+ tls_v1:server_handshake_traffic_secret(HKDFAlgo, {handshake_secret, HandshakeSecret}, CHSH),
+
+
+ %% {server} derive secret for master "tls13 derived":
+ %%
+ %% PRK (32 octets): 1d c8 26 e9 36 06 aa 6f dc 0a ad c1 2f 74 1b 01
+ %% 04 6a a6 b9 9f 69 1e d2 21 a9 f0 ca 04 3f be ac
+ %%
+ %% hash (32 octets): e3 b0 c4 42 98 fc 1c 14 9a fb f4 c8 99 6f b9 24
+ %% 27 ae 41 e4 64 9b 93 4c a4 95 99 1b 78 52 b8 55
+ %%
+ %% info (49 octets): 00 20 0d 74 6c 73 31 33 20 64 65 72 69 76 65 64
+ %% 20 e3 b0 c4 42 98 fc 1c 14 9a fb f4 c8 99 6f b9 24 27 ae 41 e4
+ %% 64 9b 93 4c a4 95 99 1b 78 52 b8 55
+ %%
+ %% expanded (32 octets): 43 de 77 e0 c7 77 13 85 9a 94 4d b9 db 25
+ %% 90 b5 31 90 a6 5b 3e e2 e4 f1 2d d7 a0 bb 7c e2 54 b4
+
+ %% PRK = HandshakeSecret
+ %% hash = Hash
+ %% info = Info
+ MasterDeriveSecret =
+ hexstr2bin("43 de 77 e0 c7 77 13 85 9a 94 4d b9 db 25
+ 90 b5 31 90 a6 5b 3e e2 e4 f1 2d d7 a0 bb 7c e2 54 b4"),
+
+ MasterDeriveSecret = tls_v1:derive_secret(HandshakeSecret, <<"derived">>, <<>>, HKDFAlgo),
+
+ %% {server} extract secret "master":
+ %%
+ %% salt (32 octets): 43 de 77 e0 c7 77 13 85 9a 94 4d b9 db 25 90 b5
+ %% 31 90 a6 5b 3e e2 e4 f1 2d d7 a0 bb 7c e2 54 b4
+ %%
+ %% IKM (32 octets): 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+ %% 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+ %%
+ %% secret (32 octets): 18 df 06 84 3d 13 a0 8b f2 a4 49 84 4c 5f 8a
+ %% 47 80 01 bc 4d 4c 62 79 84 d5 a4 1d a8 d0 40 29 19
+
+ %% salt = MasterDeriveSecret
+ %% IKM = IKM
+ MasterSecret =
+ hexstr2bin("18 df 06 84 3d 13 a0 8b f2 a4 49 84 4c 5f 8a
+ 47 80 01 bc 4d 4c 62 79 84 d5 a4 1d a8 d0 40 29 19"),
+
+ {master_secret, MasterSecret} =
+ tls_v1:key_schedule(master_secret, HKDFAlgo, {handshake_secret, HandshakeSecret}),
+
+ %% {server} send handshake record:
+ %%
+ %% payload (90 octets): 02 00 00 56 03 03 a6 af 06 a4 12 18 60 dc 5e
+ %% 6e 60 24 9c d3 4c 95 93 0c 8a c5 cb 14 34 da c1 55 77 2e d3 e2
+ %% 69 28 00 13 01 00 00 2e 00 33 00 24 00 1d 00 20 c9 82 88 76 11
+ %% 20 95 fe 66 76 2b db f7 c6 72 e1 56 d6 cc 25 3b 83 3d f1 dd 69
+ %% b1 b0 4e 75 1f 0f 00 2b 00 02 03 04
+ %%
+ %% complete record (95 octets): 16 03 03 00 5a 02 00 00 56 03 03 a6
+ %% af 06 a4 12 18 60 dc 5e 6e 60 24 9c d3 4c 95 93 0c 8a c5 cb 14
+ %% 34 da c1 55 77 2e d3 e2 69 28 00 13 01 00 00 2e 00 33 00 24 00
+ %% 1d 00 20 c9 82 88 76 11 20 95 fe 66 76 2b db f7 c6 72 e1 56 d6
+ %% cc 25 3b 83 3d f1 dd 69 b1 b0 4e 75 1f 0f 00 2b 00 02 03 04
+
+ %% payload = ServerHello
+ ServerHelloRecord =
+ hexstr2bin("16 03 03 00 5a 02 00 00 56 03 03 a6
+ af 06 a4 12 18 60 dc 5e 6e 60 24 9c d3 4c 95 93 0c 8a c5 cb 14
+ 34 da c1 55 77 2e d3 e2 69 28 00 13 01 00 00 2e 00 33 00 24 00
+ 1d 00 20 c9 82 88 76 11 20 95 fe 66 76 2b db f7 c6 72 e1 56 d6
+ cc 25 3b 83 3d f1 dd 69 b1 b0 4e 75 1f 0f 00 2b 00 02 03 04"),
+
+ {SHEncrypted, _} =
+ tls_record:encode_handshake(ServerHello, {3,4}, ConnStatesNull),
+ ServerHelloRecord = iolist_to_binary(SHEncrypted),
+
+ %% {server} derive write traffic keys for handshake data:
+ %%
+ %% PRK (32 octets): b6 7b 7d 69 0c c1 6c 4e 75 e5 42 13 cb 2d 37 b4
+ %% e9 c9 12 bc de d9 10 5d 42 be fd 59 d3 91 ad 38
+ %%
+ %% key info (13 octets): 00 10 09 74 6c 73 31 33 20 6b 65 79 00
+ %%
+ %% key expanded (16 octets): 3f ce 51 60 09 c2 17 27 d0 f2 e4 e8 6e
+ %% e4 03 bc
+ %%
+ %% iv info (12 octets): 00 0c 08 74 6c 73 31 33 20 69 76 00
+ %%
+ %% iv expanded (12 octets): 5d 31 3e b2 67 12 76 ee 13 00 0b 30
+
+ %% PRK = SHSTrafficSecret
+ WriteKeyInfo =
+ hexstr2bin("00 10 09 74 6c 73 31 33 20 6b 65 79 00"),
+
+ WriteKey =
+ hexstr2bin("3f ce 51 60 09 c2 17 27 d0 f2 e4 e8 6e e4 03 bc"),
+
+ WriteIVInfo =
+ hexstr2bin("00 0c 08 74 6c 73 31 33 20 69 76 00"),
+
+ WriteIV =
+ hexstr2bin(" 5d 31 3e b2 67 12 76 ee 13 00 0b 30"),
+
+ Cipher = aes_128_gcm, %% TODO: get from ServerHello
+
+ WriteKeyInfo = tls_v1:create_info(<<"key">>, <<>>, ssl_cipher:key_material(Cipher)),
+ %% TODO: remove hardcoded IV size
+ WriteIVInfo = tls_v1:create_info(<<"iv">>, <<>>, 12),
+
+ {WriteKey, WriteIV} = tls_v1:calculate_traffic_keys(HKDFAlgo, Cipher, SHSTrafficSecret),
+
+ %% {server} construct an EncryptedExtensions handshake message:
+ %%
+ %% EncryptedExtensions (40 octets): 08 00 00 24 00 22 00 0a 00 14 00
+ %% 12 00 1d 00 17 00 18 00 19 01 00 01 01 01 02 01 03 01 04 00 1c
+ %% 00 02 40 01 00 00 00 00
+ %%
+ %% {server} construct a Certificate handshake message:
+ %%
+ %% Certificate (445 octets): 0b 00 01 b9 00 00 01 b5 00 01 b0 30 82
+ %% 01 ac 30 82 01 15 a0 03 02 01 02 02 01 02 30 0d 06 09 2a 86 48
+ %% 86 f7 0d 01 01 0b 05 00 30 0e 31 0c 30 0a 06 03 55 04 03 13 03
+ %% 72 73 61 30 1e 17 0d 31 36 30 37 33 30 30 31 32 33 35 39 5a 17
+ %% 0d 32 36 30 37 33 30 30 31 32 33 35 39 5a 30 0e 31 0c 30 0a 06
+ %% 03 55 04 03 13 03 72 73 61 30 81 9f 30 0d 06 09 2a 86 48 86 f7
+ %% 0d 01 01 01 05 00 03 81 8d 00 30 81 89 02 81 81 00 b4 bb 49 8f
+ %% 82 79 30 3d 98 08 36 39 9b 36 c6 98 8c 0c 68 de 55 e1 bd b8 26
+ %% d3 90 1a 24 61 ea fd 2d e4 9a 91 d0 15 ab bc 9a 95 13 7a ce 6c
+ %% 1a f1 9e aa 6a f9 8c 7c ed 43 12 09 98 e1 87 a8 0e e0 cc b0 52
+ %% 4b 1b 01 8c 3e 0b 63 26 4d 44 9a 6d 38 e2 2a 5f da 43 08 46 74
+ %% 80 30 53 0e f0 46 1c 8c a9 d9 ef bf ae 8e a6 d1 d0 3e 2b d1 93
+ %% ef f0 ab 9a 80 02 c4 74 28 a6 d3 5a 8d 88 d7 9f 7f 1e 3f 02 03
+ %% 01 00 01 a3 1a 30 18 30 09 06 03 55 1d 13 04 02 30 00 30 0b 06
+ %% 03 55 1d 0f 04 04 03 02 05 a0 30 0d 06 09 2a 86 48 86 f7 0d 01
+ %% 01 0b 05 00 03 81 81 00 85 aa d2 a0 e5 b9 27 6b 90 8c 65 f7 3a
+ %% 72 67 17 06 18 a5 4c 5f 8a 7b 33 7d 2d f7 a5 94 36 54 17 f2 ea
+ %% e8 f8 a5 8c 8f 81 72 f9 31 9c f3 6b 7f d6 c5 5b 80 f2 1a 03 01
+ %% 51 56 72 60 96 fd 33 5e 5e 67 f2 db f1 02 70 2e 60 8c ca e6 be
+ %% c1 fc 63 a4 2a 99 be 5c 3e b7 10 7c 3c 54 e9 b9 eb 2b d5 20 3b
+ %% 1c 3b 84 e0 a8 b2 f7 59 40 9b a3 ea c9 d9 1d 40 2d cc 0c c8 f8
+ %% 96 12 29 ac 91 87 b4 2b 4d e1 00 00
+ %%
+ %% {server} construct a CertificateVerify handshake message:
+ %%
+ %% CertificateVerify (136 octets): 0f 00 00 84 08 04 00 80 5a 74 7c
+ %% 5d 88 fa 9b d2 e5 5a b0 85 a6 10 15 b7 21 1f 82 4c d4 84 14 5a
+ %% b3 ff 52 f1 fd a8 47 7b 0b 7a bc 90 db 78 e2 d3 3a 5c 14 1a 07
+ %% 86 53 fa 6b ef 78 0c 5e a2 48 ee aa a7 85 c4 f3 94 ca b6 d3 0b
+ %% be 8d 48 59 ee 51 1f 60 29 57 b1 54 11 ac 02 76 71 45 9e 46 44
+ %% 5c 9e a5 8c 18 1e 81 8e 95 b8 c3 fb 0b f3 27 84 09 d3 be 15 2a
+ %% 3d a5 04 3e 06 3d da 65 cd f5 ae a2 0d 53 df ac d4 2f 74 f3
+ EncryptedExtensions =
+ hexstr2bin("08 00 00 24 00 22 00 0a 00 14 00
+ 12 00 1d 00 17 00 18 00 19 01 00 01 01 01 02 01 03 01 04 00 1c
+ 00 02 40 01 00 00 00 00"),
+
+ Certificate =
+ hexstr2bin("0b 00 01 b9 00 00 01 b5 00 01 b0 30 82
+ 01 ac 30 82 01 15 a0 03 02 01 02 02 01 02 30 0d 06 09 2a 86 48
+ 86 f7 0d 01 01 0b 05 00 30 0e 31 0c 30 0a 06 03 55 04 03 13 03
+ 72 73 61 30 1e 17 0d 31 36 30 37 33 30 30 31 32 33 35 39 5a 17
+ 0d 32 36 30 37 33 30 30 31 32 33 35 39 5a 30 0e 31 0c 30 0a 06
+ 03 55 04 03 13 03 72 73 61 30 81 9f 30 0d 06 09 2a 86 48 86 f7
+ 0d 01 01 01 05 00 03 81 8d 00 30 81 89 02 81 81 00 b4 bb 49 8f
+ 82 79 30 3d 98 08 36 39 9b 36 c6 98 8c 0c 68 de 55 e1 bd b8 26
+ d3 90 1a 24 61 ea fd 2d e4 9a 91 d0 15 ab bc 9a 95 13 7a ce 6c
+ 1a f1 9e aa 6a f9 8c 7c ed 43 12 09 98 e1 87 a8 0e e0 cc b0 52
+ 4b 1b 01 8c 3e 0b 63 26 4d 44 9a 6d 38 e2 2a 5f da 43 08 46 74
+ 80 30 53 0e f0 46 1c 8c a9 d9 ef bf ae 8e a6 d1 d0 3e 2b d1 93
+ ef f0 ab 9a 80 02 c4 74 28 a6 d3 5a 8d 88 d7 9f 7f 1e 3f 02 03
+ 01 00 01 a3 1a 30 18 30 09 06 03 55 1d 13 04 02 30 00 30 0b 06
+ 03 55 1d 0f 04 04 03 02 05 a0 30 0d 06 09 2a 86 48 86 f7 0d 01
+ 01 0b 05 00 03 81 81 00 85 aa d2 a0 e5 b9 27 6b 90 8c 65 f7 3a
+ 72 67 17 06 18 a5 4c 5f 8a 7b 33 7d 2d f7 a5 94 36 54 17 f2 ea
+ e8 f8 a5 8c 8f 81 72 f9 31 9c f3 6b 7f d6 c5 5b 80 f2 1a 03 01
+ 51 56 72 60 96 fd 33 5e 5e 67 f2 db f1 02 70 2e 60 8c ca e6 be
+ c1 fc 63 a4 2a 99 be 5c 3e b7 10 7c 3c 54 e9 b9 eb 2b d5 20 3b
+ 1c 3b 84 e0 a8 b2 f7 59 40 9b a3 ea c9 d9 1d 40 2d cc 0c c8 f8
+ 96 12 29 ac 91 87 b4 2b 4d e1 00 00"),
+
+ CertificateVerify =
+ hexstr2bin("0f 00 00 84 08 04 00 80 5a 74 7c
+ 5d 88 fa 9b d2 e5 5a b0 85 a6 10 15 b7 21 1f 82 4c d4 84 14 5a
+ b3 ff 52 f1 fd a8 47 7b 0b 7a bc 90 db 78 e2 d3 3a 5c 14 1a 07
+ 86 53 fa 6b ef 78 0c 5e a2 48 ee aa a7 85 c4 f3 94 ca b6 d3 0b
+ be 8d 48 59 ee 51 1f 60 29 57 b1 54 11 ac 02 76 71 45 9e 46 44
+ 5c 9e a5 8c 18 1e 81 8e 95 b8 c3 fb 0b f3 27 84 09 d3 be 15 2a
+ 3d a5 04 3e 06 3d da 65 cd f5 ae a2 0d 53 df ac d4 2f 74 f3"),
+
+ %% {server} calculate finished "tls13 finished":
+ %%
+ %% PRK (32 octets): b6 7b 7d 69 0c c1 6c 4e 75 e5 42 13 cb 2d 37 b4
+ %% e9 c9 12 bc de d9 10 5d 42 be fd 59 d3 91 ad 38
+ %%
+ %% hash (0 octets): (empty)
+ %%
+ %% info (18 octets): 00 20 0e 74 6c 73 31 33 20 66 69 6e 69 73 68 65
+ %% 64 00
+ %%
+ %% expanded (32 octets): 00 8d 3b 66 f8 16 ea 55 9f 96 b5 37 e8 85
+ %% c3 1f c0 68 bf 49 2c 65 2f 01 f2 88 a1 d8 cd c1 9f c8
+ %%
+ %% finished (32 octets): 9b 9b 14 1d 90 63 37 fb d2 cb dc e7 1d f4
+ %% de da 4a b4 2c 30 95 72 cb 7f ff ee 54 54 b7 8f 07 18
+
+ %% PRK = SHSTrafficSecret
+ FInfo =
+ hexstr2bin("00 20 0e 74 6c 73 31 33 20 66 69 6e 69 73 68 65
+ 64 00"),
+
+ FExpanded =
+ hexstr2bin("00 8d 3b 66 f8 16 ea 55 9f 96 b5 37 e8 85
+ c3 1f c0 68 bf 49 2c 65 2f 01 f2 88 a1 d8 cd c1 9f c8"),
+
+ FinishedVerifyData =
+ hexstr2bin("9b 9b 14 1d 90 63 37 fb d2 cb dc e7 1d f4
+ de da 4a b4 2c 30 95 72 cb 7f ff ee 54 54 b7 8f 07 18"),
+
+ FInfo = tls_v1:create_info(<<"finished">>, <<>>, ssl_cipher:hash_size(HKDFAlgo)),
+
+ FExpanded = tls_v1:finished_key(SHSTrafficSecret, HKDFAlgo),
+
+ MessageHistory0 = [CertificateVerify,
+ Certificate,
+ EncryptedExtensions,
+ ServerHello,
+ ClientHello],
+
+ FinishedVerifyData = tls_v1:finished_verify_data(FExpanded, HKDFAlgo, MessageHistory0),
+
+ %% {server} construct a Finished handshake message:
+ %%
+ %% Finished (36 octets): 14 00 00 20 9b 9b 14 1d 90 63 37 fb d2 cb
+ %% dc e7 1d f4 de da 4a b4 2c 30 95 72 cb 7f ff ee 54 54 b7 8f 07
+ %% 18
+ FinishedHSBin =
+ hexstr2bin("14 00 00 20 9b 9b 14 1d 90 63 37 fb d2 cb
+ dc e7 1d f4 de da 4a b4 2c 30 95 72 cb 7f ff ee 54 54 b7 8f 07
+ 18"),
+
+ FinishedHS = #finished{verify_data = FinishedVerifyData},
+
+ FinishedIOList = tls_handshake:encode_handshake(FinishedHS, {3,4}),
+ FinishedHSBin = iolist_to_binary(FinishedIOList),
+
+ %% {server} derive secret "tls13 c ap traffic":
+ %%
+ %% PRK (32 octets): 18 df 06 84 3d 13 a0 8b f2 a4 49 84 4c 5f 8a 47
+ %% 80 01 bc 4d 4c 62 79 84 d5 a4 1d a8 d0 40 29 19
+ %%
+ %% hash (32 octets): 96 08 10 2a 0f 1c cc 6d b6 25 0b 7b 7e 41 7b 1a
+ %% 00 0e aa da 3d aa e4 77 7a 76 86 c9 ff 83 df 13
+ %%
+ %% info (54 octets): 00 20 12 74 6c 73 31 33 20 63 20 61 70 20 74 72
+ %% 61 66 66 69 63 20 96 08 10 2a 0f 1c cc 6d b6 25 0b 7b 7e 41 7b
+ %% 1a 00 0e aa da 3d aa e4 77 7a 76 86 c9 ff 83 df 13
+ %%
+ %% expanded (32 octets): 9e 40 64 6c e7 9a 7f 9d c0 5a f8 88 9b ce
+ %% 65 52 87 5a fa 0b 06 df 00 87 f7 92 eb b7 c1 75 04 a5
+
+ %% PRK = MasterSecret
+ CAPTHash =
+ hexstr2bin("96 08 10 2a 0f 1c cc 6d b6 25 0b 7b 7e 41 7b 1a
+ 00 0e aa da 3d aa e4 77 7a 76 86 c9 ff 83 df 13"),
+ CAPTInfo =
+ hexstr2bin("00 20 12 74 6c 73 31 33 20 63 20 61 70 20 74 72
+ 61 66 66 69 63 20 96 08 10 2a 0f 1c cc 6d b6 25 0b 7b 7e 41 7b
+ 1a 00 0e aa da 3d aa e4 77 7a 76 86 c9 ff 83 df 13"),
+
+ CAPTrafficSecret =
+ hexstr2bin("9e 40 64 6c e7 9a 7f 9d c0 5a f8 88 9b ce
+ 65 52 87 5a fa 0b 06 df 00 87 f7 92 eb b7 c1 75 04 a5"),
+
+ CHSF = <<ClientHello/binary,
+ ServerHello/binary,
+ EncryptedExtensions/binary,
+ Certificate/binary,
+ CertificateVerify/binary,
+ FinishedHSBin/binary>>,
+
+ CAPTHash = crypto:hash(HKDFAlgo, CHSF),
+
+ CAPTInfo =
+ tls_v1:create_info(<<"c ap traffic">>, CAPTHash, ssl_cipher:hash_size(HKDFAlgo)),
+
+ CAPTrafficSecret =
+ tls_v1:client_application_traffic_secret_0(HKDFAlgo, {master_secret, MasterSecret}, CHSF),
+
+ %% {server} derive secret "tls13 s ap traffic":
+ %%
+ %% PRK (32 octets): 18 df 06 84 3d 13 a0 8b f2 a4 49 84 4c 5f 8a 47
+ %% 80 01 bc 4d 4c 62 79 84 d5 a4 1d a8 d0 40 29 19
+ %%
+ %% hash (32 octets): 96 08 10 2a 0f 1c cc 6d b6 25 0b 7b 7e 41 7b 1a
+ %% 00 0e aa da 3d aa e4 77 7a 76 86 c9 ff 83 df 13
+ %%
+ %% info (54 octets): 00 20 12 74 6c 73 31 33 20 73 20 61 70 20 74 72
+ %% 61 66 66 69 63 20 96 08 10 2a 0f 1c cc 6d b6 25 0b 7b 7e 41 7b
+ %% 1a 00 0e aa da 3d aa e4 77 7a 76 86 c9 ff 83 df 13
+ %%
+ %% expanded (32 octets): a1 1a f9 f0 55 31 f8 56 ad 47 11 6b 45 a9
+ %% 50 32 82 04 b4 f4 4b fb 6b 3a 4b 4f 1f 3f cb 63 16 43
+
+ %% PRK = MasterSecret
+ %% hash = CAPTHash
+ SAPTInfo =
+ hexstr2bin(" 00 20 12 74 6c 73 31 33 20 73 20 61 70 20 74 72
+ 61 66 66 69 63 20 96 08 10 2a 0f 1c cc 6d b6 25 0b 7b 7e 41 7b
+ 1a 00 0e aa da 3d aa e4 77 7a 76 86 c9 ff 83 df 13"),
+
+ SAPTrafficSecret =
+ hexstr2bin("a1 1a f9 f0 55 31 f8 56 ad 47 11 6b 45 a9
+ 50 32 82 04 b4 f4 4b fb 6b 3a 4b 4f 1f 3f cb 63 16 43"),
+
+ SAPTInfo =
+ tls_v1:create_info(<<"s ap traffic">>, CAPTHash, ssl_cipher:hash_size(HKDFAlgo)),
+
+ SAPTrafficSecret =
+ tls_v1:server_application_traffic_secret_0(HKDFAlgo, {master_secret, MasterSecret}, CHSF),
+
+ %% {server} derive secret "tls13 exp master":
+ %%
+ %% PRK (32 octets): 18 df 06 84 3d 13 a0 8b f2 a4 49 84 4c 5f 8a 47
+ %% 80 01 bc 4d 4c 62 79 84 d5 a4 1d a8 d0 40 29 19
+ %%
+ %% hash (32 octets): 96 08 10 2a 0f 1c cc 6d b6 25 0b 7b 7e 41 7b 1a
+ %% 00 0e aa da 3d aa e4 77 7a 76 86 c9 ff 83 df 13
+ %%
+ %% info (52 octets): 00 20 10 74 6c 73 31 33 20 65 78 70 20 6d 61 73
+ %% 74 65 72 20 96 08 10 2a 0f 1c cc 6d b6 25 0b 7b 7e 41 7b 1a 00
+ %% 0e aa da 3d aa e4 77 7a 76 86 c9 ff 83 df 13
+ %%
+ %% expanded (32 octets): fe 22 f8 81 17 6e da 18 eb 8f 44 52 9e 67
+ %% 92 c5 0c 9a 3f 89 45 2f 68 d8 ae 31 1b 43 09 d3 cf 50
+
+ %% PRK = MasterSecret
+ %% hash = CAPTHash
+ ExporterInfo =
+ hexstr2bin("00 20 10 74 6c 73 31 33 20 65 78 70 20 6d 61 73
+ 74 65 72 20 96 08 10 2a 0f 1c cc 6d b6 25 0b 7b 7e 41 7b 1a 00
+ 0e aa da 3d aa e4 77 7a 76 86 c9 ff 83 df 13"),
+
+ ExporterMasterSecret =
+ hexstr2bin("fe 22 f8 81 17 6e da 18 eb 8f 44 52 9e 67
+ 92 c5 0c 9a 3f 89 45 2f 68 d8 ae 31 1b 43 09 d3 cf 50"),
+
+ ExporterInfo =
+ tls_v1:create_info(<<"exp master">>, CAPTHash, ssl_cipher:hash_size(HKDFAlgo)),
+
+ ExporterMasterSecret =
+ tls_v1:exporter_master_secret(HKDFAlgo, {master_secret, MasterSecret}, CHSF),
+
+ %% {server} derive write traffic keys for application data:
+ %%
+ %% PRK (32 octets): a1 1a f9 f0 55 31 f8 56 ad 47 11 6b 45 a9 50 32
+ %% 82 04 b4 f4 4b fb 6b 3a 4b 4f 1f 3f cb 63 16 43
+ %%
+ %% key info (13 octets): 00 10 09 74 6c 73 31 33 20 6b 65 79 00
+ %%
+ %% key expanded (16 octets): 9f 02 28 3b 6c 9c 07 ef c2 6b b9 f2 ac
+ %% 92 e3 56
+ %%
+ %% iv info (12 octets): 00 0c 08 74 6c 73 31 33 20 69 76 00
+ %%
+ %% iv expanded (12 octets): cf 78 2b 88 dd 83 54 9a ad f1 e9 84
+
+ %% PRK = SAPTrafficsecret
+ %% key info = WriteKeyInfo
+ %% iv info = WrtieIVInfo
+ SWKey =
+ hexstr2bin("9f 02 28 3b 6c 9c 07 ef c2 6b b9 f2 ac 92 e3 56"),
+
+ SWIV =
+ hexstr2bin("cf 78 2b 88 dd 83 54 9a ad f1 e9 84"),
+
+ {SWKey, SWIV} = tls_v1:calculate_traffic_keys(HKDFAlgo, Cipher, SAPTrafficSecret),
+
+ %% {server} derive read traffic keys for handshake data:
+ %%
+ %% PRK (32 octets): b3 ed db 12 6e 06 7f 35 a7 80 b3 ab f4 5e 2d 8f
+ %% 3b 1a 95 07 38 f5 2e 96 00 74 6a 0e 27 a5 5a 21
+ %%
+ %% key info (13 octets): 00 10 09 74 6c 73 31 33 20 6b 65 79 00
+ %%
+ %% key expanded (16 octets): db fa a6 93 d1 76 2c 5b 66 6a f5 d9 50
+ %% 25 8d 01
+ %%
+ %% iv info (12 octets): 00 0c 08 74 6c 73 31 33 20 69 76 00
+ %%
+ %% iv expanded (12 octets): 5b d3 c7 1b 83 6e 0b 76 bb 73 26 5f
+
+ %% PRK = CHSTrafficsecret
+ %% key info = WriteKeyInfo
+ %% iv info = WrtieIVInfo
+ SRKey =
+ hexstr2bin("db fa a6 93 d1 76 2c 5b 66 6a f5 d9 50 25 8d 01"),
+
+ SRIV =
+ hexstr2bin("5b d3 c7 1b 83 6e 0b 76 bb 73 26 5f"),
+
+ {SRKey, SRIV} = tls_v1:calculate_traffic_keys(HKDFAlgo, Cipher, CHSTrafficSecret).
+
+%%--------------------------------------------------------------------
+finished_verify_data() ->
+ [{doc,"Test TLS 1.3 Finished message handling"}].
+
+finished_verify_data(_Config) ->
+ ClientHello =
+ hexstr2bin("01 00 00 c6 03 03 00 01 02 03 04 05 06 07 08 09
+ 0a 0b 0c 0d 0e 0f 10 11 12 13 14 15 16 17 18 19
+ 1a 1b 1c 1d 1e 1f 20 e0 e1 e2 e3 e4 e5 e6 e7 e8
+ e9 ea eb ec ed ee ef f0 f1 f2 f3 f4 f5 f6 f7 f8
+ f9 fa fb fc fd fe ff 00 06 13 01 13 02 13 03 01
+ 00 00 77 00 00 00 18 00 16 00 00 13 65 78 61 6d
+ 70 6c 65 2e 75 6c 66 68 65 69 6d 2e 6e 65 74 00
+ 0a 00 08 00 06 00 1d 00 17 00 18 00 0d 00 14 00
+ 12 04 03 08 04 04 01 05 03 08 05 05 01 08 06 06
+ 01 02 01 00 33 00 26 00 24 00 1d 00 20 35 80 72
+ d6 36 58 80 d1 ae ea 32 9a df 91 21 38 38 51 ed
+ 21 a2 8e 3b 75 e9 65 d0 d2 cd 16 62 54 00 2d 00
+ 02 01 01 00 2b 00 03 02 03 04"),
+
+ ServerHello =
+ hexstr2bin("02 00 00 76 03 03 70 71 72 73 74 75 76 77 78 79
+ 7a 7b 7c 7d 7e 7f 80 81 82 83 84 85 86 87 88 89
+ 8a 8b 8c 8d 8e 8f 20 e0 e1 e2 e3 e4 e5 e6 e7 e8
+ e9 ea eb ec ed ee ef f0 f1 f2 f3 f4 f5 f6 f7 f8
+ f9 fa fb fc fd fe ff 13 01 00 00 2e 00 33 00 24
+ 00 1d 00 20 9f d7 ad 6d cf f4 29 8d d3 f9 6d 5b
+ 1b 2a f9 10 a0 53 5b 14 88 d7 f8 fa bb 34 9a 98
+ 28 80 b6 15 00 2b 00 02 03 04"),
+
+ EncryptedExtensions =
+ hexstr2bin("08 00 00 02 00 00"),
+
+ Certificate =
+ hexstr2bin("0b 00 03 2e 00 00 03 2a 00 03 25 30 82 03 21 30
+ 82 02 09 a0 03 02 01 02 02 08 15 5a 92 ad c2 04
+ 8f 90 30 0d 06 09 2a 86 48 86 f7 0d 01 01 0b 05
+ 00 30 22 31 0b 30 09 06 03 55 04 06 13 02 55 53
+ 31 13 30 11 06 03 55 04 0a 13 0a 45 78 61 6d 70
+ 6c 65 20 43 41 30 1e 17 0d 31 38 31 30 30 35 30
+ 31 33 38 31 37 5a 17 0d 31 39 31 30 30 35 30 31
+ 33 38 31 37 5a 30 2b 31 0b 30 09 06 03 55 04 06
+ 13 02 55 53 31 1c 30 1a 06 03 55 04 03 13 13 65
+ 78 61 6d 70 6c 65 2e 75 6c 66 68 65 69 6d 2e 6e
+ 65 74 30 82 01 22 30 0d 06 09 2a 86 48 86 f7 0d
+ 01 01 01 05 00 03 82 01 0f 00 30 82 01 0a 02 82
+ 01 01 00 c4 80 36 06 ba e7 47 6b 08 94 04 ec a7
+ b6 91 04 3f f7 92 bc 19 ee fb 7d 74 d7 a8 0d 00
+ 1e 7b 4b 3a 4a e6 0f e8 c0 71 fc 73 e7 02 4c 0d
+ bc f4 bd d1 1d 39 6b ba 70 46 4a 13 e9 4a f8 3d
+ f3 e1 09 59 54 7b c9 55 fb 41 2d a3 76 52 11 e1
+ f3 dc 77 6c aa 53 37 6e ca 3a ec be c3 aa b7 3b
+ 31 d5 6c b6 52 9c 80 98 bc c9 e0 28 18 e2 0b f7
+ f8 a0 3a fd 17 04 50 9e ce 79 bd 9f 39 f1 ea 69
+ ec 47 97 2e 83 0f b5 ca 95 de 95 a1 e6 04 22 d5
+ ee be 52 79 54 a1 e7 bf 8a 86 f6 46 6d 0d 9f 16
+ 95 1a 4c f7 a0 46 92 59 5c 13 52 f2 54 9e 5a fb
+ 4e bf d7 7a 37 95 01 44 e4 c0 26 87 4c 65 3e 40
+ 7d 7d 23 07 44 01 f4 84 ff d0 8f 7a 1f a0 52 10
+ d1 f4 f0 d5 ce 79 70 29 32 e2 ca be 70 1f df ad
+ 6b 4b b7 11 01 f4 4b ad 66 6a 11 13 0f e2 ee 82
+ 9e 4d 02 9d c9 1c dd 67 16 db b9 06 18 86 ed c1
+ ba 94 21 02 03 01 00 01 a3 52 30 50 30 0e 06 03
+ 55 1d 0f 01 01 ff 04 04 03 02 05 a0 30 1d 06 03
+ 55 1d 25 04 16 30 14 06 08 2b 06 01 05 05 07 03
+ 02 06 08 2b 06 01 05 05 07 03 01 30 1f 06 03 55
+ 1d 23 04 18 30 16 80 14 89 4f de 5b cc 69 e2 52
+ cf 3e a3 00 df b1 97 b8 1d e1 c1 46 30 0d 06 09
+ 2a 86 48 86 f7 0d 01 01 0b 05 00 03 82 01 01 00
+ 59 16 45 a6 9a 2e 37 79 e4 f6 dd 27 1a ba 1c 0b
+ fd 6c d7 55 99 b5 e7 c3 6e 53 3e ff 36 59 08 43
+ 24 c9 e7 a5 04 07 9d 39 e0 d4 29 87 ff e3 eb dd
+ 09 c1 cf 1d 91 44 55 87 0b 57 1d d1 9b df 1d 24
+ f8 bb 9a 11 fe 80 fd 59 2b a0 39 8c de 11 e2 65
+ 1e 61 8c e5 98 fa 96 e5 37 2e ef 3d 24 8a fd e1
+ 74 63 eb bf ab b8 e4 d1 ab 50 2a 54 ec 00 64 e9
+ 2f 78 19 66 0d 3f 27 cf 20 9e 66 7f ce 5a e2 e4
+ ac 99 c7 c9 38 18 f8 b2 51 07 22 df ed 97 f3 2e
+ 3e 93 49 d4 c6 6c 9e a6 39 6d 74 44 62 a0 6b 42
+ c6 d5 ba 68 8e ac 3a 01 7b dd fc 8e 2c fc ad 27
+ cb 69 d3 cc dc a2 80 41 44 65 d3 ae 34 8c e0 f3
+ 4a b2 fb 9c 61 83 71 31 2b 19 10 41 64 1c 23 7f
+ 11 a5 d6 5c 84 4f 04 04 84 99 38 71 2b 95 9e d6
+ 85 bc 5c 5d d6 45 ed 19 90 94 73 40 29 26 dc b4
+ 0e 34 69 a1 59 41 e8 e2 cc a8 4b b6 08 46 36 a0
+ 00 00"),
+
+ CertificateVerify =
+ hexstr2bin("0f 00 01 04 08 04 01 00 17 fe b5 33 ca 6d 00 7d
+ 00 58 25 79 68 42 4b bc 3a a6 90 9e 9d 49 55 75
+ 76 a5 20 e0 4a 5e f0 5f 0e 86 d2 4f f4 3f 8e b8
+ 61 ee f5 95 22 8d 70 32 aa 36 0f 71 4e 66 74 13
+ 92 6e f4 f8 b5 80 3b 69 e3 55 19 e3 b2 3f 43 73
+ df ac 67 87 06 6d cb 47 56 b5 45 60 e0 88 6e 9b
+ 96 2c 4a d2 8d ab 26 ba d1 ab c2 59 16 b0 9a f2
+ 86 53 7f 68 4f 80 8a ef ee 73 04 6c b7 df 0a 84
+ fb b5 96 7a ca 13 1f 4b 1c f3 89 79 94 03 a3 0c
+ 02 d2 9c bd ad b7 25 12 db 9c ec 2e 5e 1d 00 e5
+ 0c af cf 6f 21 09 1e bc 4f 25 3c 5e ab 01 a6 79
+ ba ea be ed b9 c9 61 8f 66 00 6b 82 44 d6 62 2a
+ aa 56 88 7c cf c6 6a 0f 38 51 df a1 3a 78 cf f7
+ 99 1e 03 cb 2c 3a 0e d8 7d 73 67 36 2e b7 80 5b
+ 00 b2 52 4f f2 98 a4 da 48 7c ac de af 8a 23 36
+ c5 63 1b 3e fa 93 5b b4 11 e7 53 ca 13 b0 15 fe
+ c7 e4 a7 30 f1 36 9f 9e"),
+
+ BaseKey =
+ hexstr2bin("a2 06 72 65 e7 f0 65 2a 92 3d 5d 72 ab 04 67 c4
+ 61 32 ee b9 68 b6 a3 2d 31 1c 80 58 68 54 88 14"),
+
+ VerifyData =
+ hexstr2bin("ea 6e e1 76 dc cc 4a f1 85 9e 9e 4e 93 f7 97 ea
+ c9 a7 8c e4 39 30 1e 35 27 5a d4 3f 3c dd bd e3"),
+
+ Messages = [CertificateVerify,
+ Certificate,
+ EncryptedExtensions,
+ ServerHello,
+ ClientHello],
+
+ FinishedKey = tls_v1:finished_key(BaseKey, sha256),
+ VerifyData = tls_v1:finished_verify_data(FinishedKey, sha256, Messages).
+
+%%--------------------------------------------------------------------
+%% Internal functions ------------------------------------------------
+%%--------------------------------------------------------------------
+
+hexstr2int(S) ->
+ B = hexstr2bin(S),
+ Bits = size(B) * 8,
+ <<Integer:Bits/integer>> = B,
+ Integer.
+
+hexstr2bin(S) when is_binary(S) ->
+ hexstr2bin(S, <<>>);
+hexstr2bin(S) ->
+ hexstr2bin(list_to_binary(S), <<>>).
+%%
+hexstr2bin(<<>>, Acc) ->
+ Acc;
+hexstr2bin(<<C,T/binary>>, Acc) when C =:= 32; %% SPACE
+ C =:= 10; %% LF
+ C =:= 13 -> %% CR
+ hexstr2bin(T, Acc);
+hexstr2bin(<<X,Y,T/binary>>, Acc) ->
+ I = hex2int(X) * 16 + hex2int(Y),
+ hexstr2bin(T, <<Acc/binary,I>>).
+
+hex2int(C) when $0 =< C, C =< $9 ->
+ C - $0;
+hex2int(C) when $A =< C, C =< $F ->
+ C - $A + 10;
+hex2int(C) when $a =< C, C =< $f ->
+ C - $a + 10.
diff --git a/lib/ssl/test/tls_1_3_version_SUITE.erl b/lib/ssl/test/tls_1_3_version_SUITE.erl
new file mode 100644
index 0000000000..f0b224d4e5
--- /dev/null
+++ b/lib/ssl/test/tls_1_3_version_SUITE.erl
@@ -0,0 +1,153 @@
+%%
+%% %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(tls_1_3_version_SUITE).
+
+%% Note: This directive should only be used in test suites.
+-compile(export_all).
+
+-include_lib("common_test/include/ct.hrl").
+-include_lib("public_key/include/public_key.hrl").
+
+%%--------------------------------------------------------------------
+%% Common Test interface functions -----------------------------------
+%%--------------------------------------------------------------------
+all() ->
+ [
+ {group, 'tlsv1.3'}
+ ].
+
+groups() ->
+ [
+ {'tlsv1.3', [], cert_groups()},
+ {rsa, [], tests()},
+ {ecdsa, [], tests()}
+ ].
+
+cert_groups() ->
+ [{group, rsa},
+ {group, ecdsa}].
+
+tests() ->
+ [tls13_client_tls12_server,
+ tls13_client_with_ext_tls12_server,
+ tls12_client_tls13_server].
+
+init_per_suite(Config) ->
+ catch crypto:stop(),
+ try crypto:start() of
+ ok ->
+ ssl_test_lib:clean_start(),
+ [{client_type, erlang}, {server_type, erlang} |
+ Config]
+ catch _:_ ->
+ {skip, "Crypto did not start"}
+ end.
+
+end_per_suite(_Config) ->
+ ssl:stop(),
+ application:stop(crypto).
+
+init_per_group(rsa, Config0) ->
+ Config = ssl_test_lib:make_rsa_cert(Config0),
+ COpts = proplists:get_value(client_rsa_opts, Config),
+ SOpts = proplists:get_value(server_rsa_opts, Config),
+ [{client_cert_opts, COpts}, {server_cert_opts, SOpts} |
+ lists:delete(server_cert_opts, lists:delete(client_cert_opts, Config))];
+init_per_group(ecdsa, Config0) ->
+ PKAlg = crypto:supports(public_keys),
+ case lists:member(ecdsa, PKAlg) andalso
+ (lists:member(ecdh, PKAlg) orelse lists:member(dh, PKAlg)) of
+ true ->
+ Config = ssl_test_lib:make_ecdsa_cert(Config0),
+ COpts = proplists:get_value(client_ecdsa_opts, Config),
+ SOpts = proplists:get_value(server_ecdsa_opts, Config),
+ [{client_cert_opts, COpts}, {server_cert_opts, SOpts} |
+ lists:delete(server_cert_opts, lists:delete(client_cert_opts, Config))];
+ false ->
+ {skip, "Missing EC crypto support"}
+ end;
+init_per_group(GroupName, Config) ->
+ ssl_test_lib:clean_tls_version(Config),
+ case ssl_test_lib:is_tls_version(GroupName) andalso
+ ssl_test_lib:sufficient_crypto_support(GroupName) of
+ true ->
+ ssl_test_lib:init_tls_version(GroupName, Config);
+ _ ->
+ case ssl_test_lib:sufficient_crypto_support(GroupName) of
+ true ->
+ ssl:start(),
+ Config;
+ false ->
+ {skip, "Missing crypto support"}
+ end
+ 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.
+
+%%--------------------------------------------------------------------
+%% Test Cases --------------------------------------------------------
+%%--------------------------------------------------------------------
+
+tls13_client_tls12_server() ->
+ [{doc,"Test that a TLS 1.3 client can connect to a TLS 1.2 server."}].
+
+tls13_client_tls12_server(Config) when is_list(Config) ->
+ ClientOpts = [{versions,
+ ['tlsv1.3', 'tlsv1.2']} | ssl_test_lib:ssl_options(client_cert_opts, Config)],
+ ServerOpts = [{versions,
+ ['tlsv1.1', 'tlsv1.2']} | ssl_test_lib:ssl_options(server_cert_opts, Config)],
+ ssl_test_lib:basic_test(ClientOpts, ServerOpts, Config).
+
+tls13_client_with_ext_tls12_server() ->
+ [{doc,"Test basic connection between TLS 1.2 server and TLS 1.3 client when "
+ "client has TLS 1.3 specsific extensions"}].
+
+tls13_client_with_ext_tls12_server(Config) ->
+ ClientOpts0 = ssl_test_lib:ssl_options(client_cert_opts, Config),
+ ServerOpts0 = ssl_test_lib:ssl_options(server_cert_opts, Config),
+
+ ServerOpts = [{versions, ['tlsv1.2']}|ServerOpts0],
+ ClientOpts = [{versions, ['tlsv1.2','tlsv1.3']},
+ {signature_algs_cert, [ecdsa_secp384r1_sha384,
+ ecdsa_secp256r1_sha256,
+ rsa_pss_rsae_sha256,
+ rsa_pkcs1_sha256,
+ {sha256,rsa},{sha256,dsa}]}|ClientOpts0],
+ ssl_test_lib:basic_test(ClientOpts, ServerOpts, Config).
+
+tls12_client_tls13_server() ->
+ [{doc,"Test that a TLS 1.2 client can connect to a TLS 1.3 server."}].
+
+tls12_client_tls13_server(Config) when is_list(Config) ->
+ ClientOpts = [{versions,
+ ['tlsv1.1', 'tlsv1.2']} | ssl_test_lib:ssl_options(client_cert_opts, Config)],
+ ServerOpts = [{versions,
+ ['tlsv1.3', 'tlsv1.2']} | ssl_test_lib:ssl_options(server_cert_opts, Config)],
+ ssl_test_lib:basic_test(ClientOpts, ServerOpts, Config).
+
diff --git a/lib/ssl/test/tls_api_SUITE.erl b/lib/ssl/test/tls_api_SUITE.erl
new file mode 100644
index 0000000000..5a74ec1892
--- /dev/null
+++ b/lib/ssl/test/tls_api_SUITE.erl
@@ -0,0 +1,880 @@
+%%
+%% %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(tls_api_SUITE).
+
+%% Note: This directive should only be used in test suites.
+-compile(export_all).
+-include_lib("common_test/include/ct.hrl").
+-include_lib("ssl/src/ssl_record.hrl").
+-include_lib("ssl/src/ssl_internal.hrl").
+-include_lib("ssl/src/ssl_api.hrl").
+-include_lib("ssl/src/tls_handshake.hrl").
+
+-define(SLEEP, 500).
+
+%%--------------------------------------------------------------------
+%% Common Test interface functions -----------------------------------
+%%--------------------------------------------------------------------
+
+all() ->
+ [
+ {group, 'tlsv1.3'},
+ {group, 'tlsv1.2'},
+ {group, 'tlsv1.1'},
+ {group, 'tlsv1'},
+ {group, 'sslv3'}
+ ].
+
+groups() ->
+ [
+ {'tlsv1.3', [], api_tests() -- [sockname]},
+ {'tlsv1.2', [], api_tests()},
+ {'tlsv1.1', [], api_tests()},
+ {'tlsv1', [], api_tests()},
+ {'sslv3', [], api_tests() ++ [ssl3_cipher_suite_limitation]}
+ ].
+
+api_tests() ->
+ [
+ tls_upgrade,
+ tls_upgrade_with_timeout,
+ tls_downgrade,
+ tls_shutdown,
+ tls_shutdown_write,
+ tls_shutdown_both,
+ tls_shutdown_error,
+ tls_client_closes_socket,
+ tls_closed_in_active_once,
+ tls_tcp_msg,
+ tls_tcp_msg_big,
+ tls_dont_crash_on_handshake_garbage,
+ tls_tcp_error_propagation_in_active_mode,
+ peername,
+ sockname,
+ tls_server_handshake_timeout,
+ transport_close,
+ emulated_options,
+ accept_pool,
+ reuseaddr
+ ].
+
+init_per_suite(Config0) ->
+ catch crypto:stop(),
+ try crypto:start() of
+ ok ->
+ ssl_test_lib:clean_start(),
+ ssl_test_lib:make_rsa_cert(Config0)
+ catch _:_ ->
+ {skip, "Crypto did not start"}
+ end.
+
+end_per_suite(_Config) ->
+ ssl:stop(),
+ application:unload(ssl),
+ application:stop(crypto).
+
+
+init_per_group(GroupName, Config) ->
+ case ssl_test_lib:is_tls_version(GroupName) of
+ true ->
+ case ssl_test_lib:sufficient_crypto_support(GroupName) of
+ true ->
+ ssl_test_lib:init_tls_version(GroupName, Config);
+ false ->
+ {skip, "Missing crypto support"}
+ end;
+ _ ->
+ ssl:start(),
+ Config
+ 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) ->
+ ssl_test_lib:ct_log_supported_protocol_versions(Config),
+ ct:timetrap({seconds, 10}),
+ Config.
+
+end_per_testcase(_TestCase, Config) ->
+ Config.
+
+%%--------------------------------------------------------------------
+%% Test Cases --------------------------------------------------------
+%%--------------------------------------------------------------------
+tls_upgrade() ->
+ [{doc,"Test that you can upgrade an tcp connection to an ssl connection"}].
+
+tls_upgrade(Config) when is_list(Config) ->
+ ClientOpts = ssl_test_lib:ssl_options(client_rsa_opts, Config),
+ ServerOpts = ssl_test_lib:ssl_options(server_rsa_opts, Config),
+ {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
+ TcpOpts = [binary, {reuseaddr, true}],
+
+ Server = ssl_test_lib:start_upgrade_server([{node, ServerNode}, {port, 0},
+ {from, self()},
+ {mfa, {?MODULE,
+ upgrade_result, []}},
+ {tcp_options,
+ [{active, false} | TcpOpts]},
+ {ssl_options, [{verify, verify_peer} | ServerOpts]}]),
+ Port = ssl_test_lib:inet_port(Server),
+ Client = ssl_test_lib:start_upgrade_client([{node, ClientNode},
+ {port, Port},
+ {host, Hostname},
+ {from, self()},
+ {mfa, {?MODULE, upgrade_result, []}},
+ {tcp_options, [binary]},
+ {ssl_options, [{verify, verify_peer},
+ {server_name_indication, Hostname} | ClientOpts]}]),
+
+ ct:log("Testcase ~p, Client ~p Server ~p ~n",
+ [self(), Client, Server]),
+
+ ssl_test_lib:check_result(Server, ok, Client, ok),
+
+ ssl_test_lib:close(Server),
+ ssl_test_lib:close(Client).
+%%--------------------------------------------------------------------
+tls_upgrade_with_timeout() ->
+ [{doc,"Test ssl_accept/3"}].
+
+tls_upgrade_with_timeout(Config) when is_list(Config) ->
+ ClientOpts = ssl_test_lib:ssl_options(client_rsa_opts, Config),
+ ServerOpts = ssl_test_lib:ssl_options(server_rsa_opts, Config),
+ {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
+ TcpOpts = [binary, {reuseaddr, true}],
+
+ Server = ssl_test_lib:start_upgrade_server([{node, ServerNode}, {port, 0},
+ {from, self()},
+ {timeout, 5000},
+ {mfa, {?MODULE,
+ upgrade_result, []}},
+ {tcp_options,
+ [{active, false} | TcpOpts]},
+ {ssl_options, [{verify, verify_peer} | ServerOpts]}]),
+ Port = ssl_test_lib:inet_port(Server),
+ Client = ssl_test_lib:start_upgrade_client([{node, ClientNode},
+ {port, Port},
+ {host, Hostname},
+ {from, self()},
+ {mfa, {?MODULE, upgrade_result, []}},
+ {tcp_options, TcpOpts},
+ {ssl_options, [{verify, verify_peer},
+ {server_name_indication, Hostname} | ClientOpts]}]),
+
+ ct:log("Testcase ~p, Client ~p Server ~p ~n",
+ [self(), Client, Server]),
+
+ ssl_test_lib:check_result(Server, ok, Client, ok),
+
+ ssl_test_lib:close(Server),
+ ssl_test_lib:close(Client).
+
+%%--------------------------------------------------------------------
+tls_downgrade() ->
+ [{doc,"Test that you can downgarde an ssl connection to an tcp connection"}].
+tls_downgrade(Config) when is_list(Config) ->
+ ClientOpts = ssl_test_lib:ssl_options(client_rsa_opts, Config),
+ ServerOpts = ssl_test_lib:ssl_options(server_rsa_opts, Config),
+
+ {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
+
+ Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0},
+ {from, self()},
+ {mfa, {?MODULE, tls_downgrade_result, [self()]}},
+ {options, [{active, false}, {verify, verify_peer} | ServerOpts]}]),
+ Port = ssl_test_lib:inet_port(Server),
+ Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port},
+ {host, Hostname},
+ {from, self()},
+ {mfa, {?MODULE, tls_downgrade_result, [self()]}},
+ {options, [{active, false}, {verify, verify_peer} | ClientOpts]}]),
+
+ ssl_test_lib:check_result(Server, ready, Client, ready),
+
+ Server ! go,
+ Client ! go,
+
+ ssl_test_lib:check_result(Server, ok, Client, ok),
+ ssl_test_lib:close(Server),
+ ssl_test_lib:close(Client).
+
+
+%%--------------------------------------------------------------------
+tls_shutdown() ->
+ [{doc,"Test API function ssl:shutdown/2"}].
+tls_shutdown(Config) when is_list(Config) ->
+ ClientOpts = ssl_test_lib:ssl_options(client_rsa_opts, Config),
+ ServerOpts = ssl_test_lib:ssl_options(server_rsa_opts, Config),
+ {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
+ Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0},
+ {from, self()},
+ {mfa, {?MODULE, tls_shutdown_result, [server]}},
+ {options, [{exit_on_close, false},
+ {active, false} | ServerOpts]}]),
+ Port = ssl_test_lib:inet_port(Server),
+ Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port},
+ {host, Hostname},
+ {from, self()},
+ {mfa,
+ {?MODULE, tls_shutdown_result, [client]}},
+ {options,
+ [{exit_on_close, false},
+ {active, false} | ClientOpts]}]),
+
+ ssl_test_lib:check_result(Server, ok, Client, ok),
+
+ ssl_test_lib:close(Server),
+ ssl_test_lib:close(Client).
+
+%%--------------------------------------------------------------------
+tls_shutdown_write() ->
+ [{doc,"Test API function ssl:shutdown/2 with option write."}].
+tls_shutdown_write(Config) when is_list(Config) ->
+ ClientOpts = ssl_test_lib:ssl_options(client_rsa_opts, Config),
+ ServerOpts = ssl_test_lib:ssl_options(server_rsa_opts, Config),
+ {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
+ Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0},
+ {from, self()},
+ {mfa, {?MODULE, tls_shutdown_write_result, [server]}},
+ {options, [{active, false} | ServerOpts]}]),
+ Port = ssl_test_lib:inet_port(Server),
+ Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port},
+ {host, Hostname},
+ {from, self()},
+ {mfa, {?MODULE, tls_shutdown_write_result, [client]}},
+ {options, [{active, false} | ClientOpts]}]),
+
+ ssl_test_lib:check_result(Server, ok, Client, {error, closed}).
+
+%%--------------------------------------------------------------------
+tls_shutdown_both() ->
+ [{doc,"Test API function ssl:shutdown/2 with option both."}].
+tls_shutdown_both(Config) when is_list(Config) ->
+ ClientOpts = ssl_test_lib:ssl_options(client_rsa_opts, Config),
+ ServerOpts = ssl_test_lib:ssl_options(server_rsa_opts, Config),
+ {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
+ Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0},
+ {from, self()},
+ {mfa, {?MODULE, tls_shutdown_both_result, [server]}},
+ {options, [{active, false} | ServerOpts]}]),
+ Port = ssl_test_lib:inet_port(Server),
+ Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port},
+ {host, Hostname},
+ {from, self()},
+ {mfa, {?MODULE, tls_shutdown_both_result, [client]}},
+ {options, [{active, false} | ClientOpts]}]),
+
+ ssl_test_lib:check_result(Server, ok, Client, {error, closed}).
+
+%%--------------------------------------------------------------------
+tls_shutdown_error() ->
+ [{doc,"Test ssl:shutdown/2 error handling"}].
+tls_shutdown_error(Config) when is_list(Config) ->
+ ServerOpts = ssl_test_lib:ssl_options(server_rsa_opts, Config),
+ Port = ssl_test_lib:inet_port(node()),
+ {ok, Listen} = ssl:listen(Port, ServerOpts),
+ {error, enotconn} = ssl:shutdown(Listen, read_write),
+ ok = ssl:close(Listen),
+ {error, closed} = ssl:shutdown(Listen, read_write).
+%%--------------------------------------------------------------------
+tls_client_closes_socket() ->
+ [{doc,"Test what happens when client closes socket before handshake is compleated"}].
+
+tls_client_closes_socket(Config) when is_list(Config) ->
+ ServerOpts = ssl_test_lib:ssl_options(server_opts, Config),
+ {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
+ TcpOpts = [binary, {reuseaddr, true}],
+
+ Server = ssl_test_lib:start_upgrade_server_error([{node, ServerNode}, {port, 0},
+ {from, self()},
+ {tcp_options, TcpOpts},
+ {ssl_options, ServerOpts}]),
+ Port = ssl_test_lib:inet_port(Server),
+
+ Connect = fun() ->
+ {ok, _Socket} = rpc:call(ClientNode, gen_tcp, connect,
+ [Hostname, Port, [binary]]),
+ %% Make sure that ssl_accept is called before
+ %% client process ends and closes socket.
+ ct:sleep(?SLEEP)
+ end,
+
+ _Client = spawn_link(Connect),
+
+ ssl_test_lib:check_result(Server, {error,closed}).
+
+%%--------------------------------------------------------------------
+tls_closed_in_active_once() ->
+ [{doc, "Test that ssl_closed is delivered in active once with non-empty buffer, check ERL-420."}].
+
+tls_closed_in_active_once(Config) when is_list(Config) ->
+ ClientOpts = ssl_test_lib:ssl_options(client_rsa_opts, Config),
+ ServerOpts = ssl_test_lib:ssl_options(server_rsa_opts, Config),
+ {_ClientNode, _ServerNode, Hostname} = ssl_test_lib:run_where(Config),
+ TcpOpts = [binary, {reuseaddr, true}],
+ Port = ssl_test_lib:inet_port(node()),
+ Server = fun() ->
+ {ok, Listen} = gen_tcp:listen(Port, TcpOpts),
+ {ok, TcpServerSocket} = gen_tcp:accept(Listen),
+ {ok, ServerSocket} = ssl:handshake(TcpServerSocket, ServerOpts),
+ lists:foreach(
+ fun(_) ->
+ ssl:send(ServerSocket, "some random message\r\n")
+ end, lists:seq(1, 20)),
+ %% Close TCP instead of SSL socket to trigger the bug:
+ gen_tcp:close(TcpServerSocket),
+ gen_tcp:close(Listen)
+ end,
+ spawn_link(Server),
+ {ok, Socket} = ssl:connect(Hostname, Port, [{active, false} | ClientOpts]),
+ Result = tls_closed_in_active_once_loop(Socket),
+ ssl:close(Socket),
+ case Result of
+ ok -> ok;
+ _ -> ct:fail(Result)
+ end.
+%%--------------------------------------------------------------------
+tls_tcp_msg() ->
+ [{doc,"Test what happens when a tcp tries to connect, i,e. a bad (ssl) packet is sent first"}].
+
+tls_tcp_msg(Config) when is_list(Config) ->
+ ServerOpts = ssl_test_lib:ssl_options(server_rsa_opts, Config),
+ {_, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
+ TcpOpts = [binary, {reuseaddr, true}, {active, false}],
+
+ Server = ssl_test_lib:start_upgrade_server_error([{node, ServerNode}, {port, 0},
+ {from, self()},
+ {timeout, 5000},
+ {mfa, {?MODULE, dummy, []}},
+ {tcp_options, TcpOpts},
+ {ssl_options, ServerOpts}]),
+ Port = ssl_test_lib:inet_port(Server),
+
+ {ok, Socket} = gen_tcp:connect(Hostname, Port, [binary, {packet, 0}]),
+ ct:log("Testcase ~p connected to Server ~p ~n", [self(), Server]),
+ gen_tcp:send(Socket, "<SOME GARBLED NON SSL MESSAGE>"),
+
+ receive
+ {tcp_closed, Socket} ->
+ receive
+ {Server, {error, Error}} ->
+ ct:log("Error ~p", [Error])
+ end
+ end.
+%%--------------------------------------------------------------------
+tls_tcp_msg_big() ->
+ [{doc,"Test what happens when a tcp tries to connect, i,e. a bad big (ssl) packet is sent first"}].
+
+tls_tcp_msg_big(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),
+ TcpOpts = [binary, {reuseaddr, true}],
+
+ Rand = crypto:strong_rand_bytes(?MAX_CIPHER_TEXT_LENGTH+1),
+ Server = ssl_test_lib:start_upgrade_server_error([{node, ServerNode}, {port, 0},
+ {from, self()},
+ {timeout, 5000},
+ {mfa, {?MODULE, dummy, []}},
+ {tcp_options, TcpOpts},
+ {ssl_options, ServerOpts}]),
+ Port = ssl_test_lib:inet_port(Server),
+
+ {ok, Socket} = gen_tcp:connect(Hostname, Port, [binary, {packet, 0}]),
+ ct:log("Testcase ~p connected to Server ~p ~n", [self(), Server]),
+
+ gen_tcp:send(Socket, <<?BYTE(0),
+ ?BYTE(3), ?BYTE(1), ?UINT16(?MAX_CIPHER_TEXT_LENGTH), Rand/binary>>),
+
+ receive
+ {tcp_closed, Socket} ->
+ receive
+ {Server, {error, timeout}} ->
+ ct:fail("hangs");
+ {Server, {error, Error}} ->
+ ct:log("Error ~p", [Error]);
+ {'EXIT', Server, _} ->
+ ok
+ end
+ end.
+
+%%--------------------------------------------------------------------
+tls_dont_crash_on_handshake_garbage() ->
+ [{doc, "Ensure SSL server worker thows an alert on garbage during handshake "
+ "instead of crashing and exposing state to user code"}].
+
+tls_dont_crash_on_handshake_garbage(Config) ->
+ ServerOpts = ssl_test_lib:ssl_options(server_rsa_opts, Config),
+
+ {_ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
+
+ Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0},
+ {from, self()},
+ {mfa, {ssl_test_lib, send_recv_result_active, []}},
+ {options, ServerOpts}]),
+ unlink(Server), monitor(process, Server),
+ Port = ssl_test_lib:inet_port(Server),
+
+ {ok, Socket} = gen_tcp:connect(Hostname, Port, [binary, {active, false}]),
+
+ % Send hello and garbage record
+ ok = gen_tcp:send(Socket,
+ [<<22, 3,3, 49:16, 1, 45:24, 3,3, % client_hello
+ 16#deadbeef:256, % 32 'random' bytes = 256 bits
+ 0, 6:16, 0,255, 0,61, 0,57, 1, 0 >>, % some hello values
+
+ <<22, 3,3, 5:16, 92,64,37,228,209>> % garbage
+ ]),
+ % Send unexpected change_cipher_spec
+ ok = gen_tcp:send(Socket, <<20, 3,3, 12:16, 111,40,244,7,137,224,16,109,197,110,249,152>>),
+
+ % Ensure we receive an alert, not sudden disconnect
+ {ok, <<21, _/binary>>} = drop_handshakes(Socket, 1000).
+
+%%--------------------------------------------------------------------
+tls_tcp_error_propagation_in_active_mode() ->
+ [{doc,"Test that process recives {ssl_error, Socket, closed} when tcp error ocurres"}].
+tls_tcp_error_propagation_in_active_mode(Config) when is_list(Config) ->
+ ClientOpts = ssl_test_lib:ssl_options(client_rsa_opts, Config),
+ ServerOpts = ssl_test_lib:ssl_options(server_rsa_opts, Config),
+
+ {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
+
+ Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0},
+ {from, self()},
+ {mfa, {ssl_test_lib, no_result, []}},
+ {options, ServerOpts}]),
+ Port = ssl_test_lib:inet_port(Server),
+ {Client, #sslsocket{pid=[Pid|_]} = SslSocket} = ssl_test_lib:start_client([return_socket,
+ {node, ClientNode}, {port, Port},
+ {host, Hostname},
+ {from, self()},
+ {mfa, {?MODULE, receive_msg, []}},
+ {options, ClientOpts}]),
+
+ {status, _, _, StatusInfo} = sys:get_status(Pid),
+ [_, _,_, _, Prop] = StatusInfo,
+ State = ssl_test_lib:state(Prop),
+ StaticEnv = element(2, State),
+ Socket = element(11, StaticEnv),
+ %% Fake tcp error
+ Pid ! {tcp_error, Socket, etimedout},
+
+ ssl_test_lib:check_result(Client, {ssl_closed, SslSocket}).
+
+%%--------------------------------------------------------------------
+peername() ->
+ [{doc,"Test API function peername/1"}].
+
+peername(Config) when is_list(Config) ->
+ ClientOpts = ssl_test_lib:ssl_options(client_rsa_opts, Config),
+ ServerOpts = ssl_test_lib:ssl_options(server_rsa_opts, Config),
+ {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
+ Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0},
+ {from, self()},
+ {mfa, {?MODULE, peername_result, []}},
+ {options, ServerOpts}]),
+ Port = ssl_test_lib:inet_port(Server),
+ Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port},
+ {host, Hostname},
+ {from, self()},
+ {mfa, {?MODULE, peername_result, []}},
+ {options, [{port, 0} | ClientOpts]}]),
+
+ ClientPort = ssl_test_lib:inet_port(Client),
+ ServerIp = ssl_test_lib:node_to_hostip(ServerNode, server),
+ ClientIp = ssl_test_lib:node_to_hostip(ClientNode, client),
+ ServerMsg = {ok, {ClientIp, ClientPort}},
+ ClientMsg = {ok, {ServerIp, Port}},
+
+ ct:log("Testcase ~p, Client ~p Server ~p ~n",
+ [self(), Client, Server]),
+
+ ssl_test_lib:check_result(Server, ServerMsg, Client, ClientMsg),
+
+ ssl_test_lib:close(Server),
+ ssl_test_lib:close(Client).
+
+%%--------------------------------------------------------------------
+sockname() ->
+ [{doc,"Test API function sockname/1"}].
+sockname(Config) when is_list(Config) ->
+ ClientOpts = ssl_test_lib:ssl_options(client_rsa_opts, Config),
+ ServerOpts = ssl_test_lib:ssl_options(server_rsa_opts, Config),
+ {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
+ Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0},
+ {from, self()},
+ {mfa, {?MODULE, sockname_result, []}},
+ {options, ServerOpts}]),
+ Port = ssl_test_lib:inet_port(Server),
+ Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port},
+ {host, Hostname},
+ {from, self()},
+ {mfa, {?MODULE, sockname_result, []}},
+ {options, [{port, 0} | ClientOpts]}]),
+
+ ClientPort = ssl_test_lib:inet_port(Client),
+ ServerIp = ssl_test_lib:node_to_hostip(ServerNode, server),
+ ClientIp = ssl_test_lib:node_to_hostip(ClientNode, client),
+ ServerMsg = {ok, {ServerIp, Port}},
+ ClientMsg = {ok, {ClientIp, ClientPort}},
+
+ ct:log("Testcase ~p, Client ~p Server ~p ~n",
+ [self(), Client, Server]),
+
+ ssl_test_lib:check_result(Server, ServerMsg, Client, ClientMsg),
+
+ ssl_test_lib:close(Server),
+ ssl_test_lib:close(Client).
+%%--------------------------------------------------------------------
+tls_server_handshake_timeout() ->
+ [{doc,"Test server handshake timeout"}].
+
+tls_server_handshake_timeout(Config) ->
+ process_flag(trap_exit, true),
+ ServerOpts = ssl_test_lib:ssl_options(server_rsa_opts, Config),
+ {_, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
+ Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0},
+ {from, self()},
+ {timeout, 5000},
+ {mfa, {ssl_test_lib,
+ no_result_msg, []}},
+ {options, ServerOpts}]),
+ Port = ssl_test_lib:inet_port(Server),
+ {ok, CSocket} = gen_tcp:connect(Hostname, Port, [binary, {active, true}]),
+
+ receive
+ {tcp_closed, CSocket} ->
+ ssl_test_lib:check_result(Server, {error, timeout}),
+ receive
+ {'EXIT', Server, _} ->
+ %% Make sure supervisor had time to react on process exit
+ %% Could we come up with a better solution to this?
+ ct:sleep(500),
+ [] = supervisor:which_children(tls_connection_sup)
+ end
+ end.
+transport_close() ->
+ [{doc, "Test what happens if socket is closed on TCP level after a while of normal operation"}].
+transport_close(Config) when is_list(Config) ->
+ ClientOpts = ssl_test_lib:ssl_options(client_rsa_opts, Config),
+ ServerOpts = ssl_test_lib:ssl_options(server_rsa_opts, Config),
+ {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
+ Server =
+ ssl_test_lib:start_server([{node, ServerNode}, {port, 0},
+ {from, self()},
+ {mfa, {ssl_test_lib, send_recv_result, []}},
+ {options, [{active, false} | ServerOpts]}]),
+ Port = ssl_test_lib:inet_port(Server),
+ {ok, TcpS} = rpc:call(ClientNode, gen_tcp, connect,
+ [Hostname,Port,[binary, {active, false}]]),
+ {ok, SslS} = rpc:call(ClientNode, ssl, connect,
+ [TcpS,[{active, false}|ClientOpts]]),
+
+ ct:log("Testcase ~p, Client ~p Server ~p ~n",
+ [self(), self(), Server]),
+ ok = ssl:send(SslS, "Hello world"),
+ {ok,<<"Hello world">>} = ssl:recv(SslS, 11),
+ gen_tcp:close(TcpS),
+ {error, _} = ssl:send(SslS, "Hello world").
+
+%%--------------------------------------------------------------------
+ssl3_cipher_suite_limitation() ->
+ [{doc,"Test a SSLv3 client cannot negotiate a TLSv* cipher suite."}].
+ssl3_cipher_suite_limitation(Config) when is_list(Config) ->
+
+ {_ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
+ ServerOpts = ssl_test_lib:ssl_options(server_rsa_opts, Config),
+
+ Server = ssl_test_lib:start_server_error([{node, ServerNode}, {port, 0},
+ {from, self()},
+ {options, ServerOpts}]),
+ Port = ssl_test_lib:inet_port(Server),
+
+ {ok, Socket} = gen_tcp:connect(Hostname, Port, [binary, {active, false}]),
+ ok = gen_tcp:send(Socket,
+ <<22, 3,0, 49:16, % handshake, SSL 3.0, length
+ 1, 45:24, % client_hello, length
+ 3,0, % SSL 3.0
+ 16#deadbeef:256, % 32 'random' bytes = 256 bits
+ 0, % no session ID
+ %% three cipher suites -- null, one with sha256 hash and one with sha hash
+ 6:16, 0,255, 0,61, 0,57,
+ 1, 0 % no compression
+ >>),
+ {ok, <<22, RecMajor:8, RecMinor:8, _RecLen:16, 2, HelloLen:24>>} = gen_tcp:recv(Socket, 9, 10000),
+ {ok, <<HelloBin:HelloLen/binary>>} = gen_tcp:recv(Socket, HelloLen, 5000),
+ ServerHello = tls_handshake:decode_handshake({RecMajor, RecMinor}, 2, HelloBin),
+ case ServerHello of
+ #server_hello{server_version = {3,0}, cipher_suite = <<0,57>>} ->
+ ok;
+ _ ->
+ ct:fail({unexpected_server_hello, ServerHello})
+ end.
+%%--------------------------------------------------------------------
+emulated_options() ->
+ [{doc,"Test API function getopts/2 and setopts/2"}].
+
+emulated_options(Config) when is_list(Config) ->
+ ClientOpts = ssl_test_lib:ssl_options(client_rsa_opts, Config),
+ ServerOpts = ssl_test_lib:ssl_options(server_rsa_opts, Config),
+ {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
+ Values = [{mode, list}, {packet, 0}, {header, 0},
+ {active, true}],
+ %% Shall be the reverse order of Values!
+ Options = [active, header, packet, mode],
+
+ NewValues = [{mode, binary}, {active, once}],
+ %% Shall be the reverse order of NewValues!
+ NewOptions = [active, mode],
+
+ Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0},
+ {from, self()},
+ {mfa, {?MODULE, tls_socket_options_result,
+ [Options, Values, NewOptions, NewValues]}},
+ {options, ServerOpts}]),
+ Port = ssl_test_lib:inet_port(Server),
+ Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port},
+ {host, Hostname},
+ {from, self()},
+ {mfa, {?MODULE, tls_socket_options_result,
+ [Options, Values, NewOptions, NewValues]}},
+ {options, ClientOpts}]),
+
+ ssl_test_lib:check_result(Server, ok, Client, ok),
+
+ ssl_test_lib:close(Server),
+
+ {ok, Listen} = ssl:listen(0, ServerOpts),
+ {ok,[{mode,list}]} = ssl:getopts(Listen, [mode]),
+ ok = ssl:setopts(Listen, [{mode, binary}]),
+ {ok,[{mode, binary}]} = ssl:getopts(Listen, [mode]),
+ {ok,[{recbuf, _}]} = ssl:getopts(Listen, [recbuf]),
+ ssl:close(Listen).
+accept_pool() ->
+ [{doc,"Test having an accept pool."}].
+accept_pool(Config) when is_list(Config) ->
+ ClientOpts = ssl_test_lib:ssl_options(client_rsa_opts, Config),
+ ServerOpts = ssl_test_lib:ssl_options(server_rsa_opts, Config),
+
+ {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
+ Server0 = ssl_test_lib:start_server([{node, ServerNode}, {port, 0},
+ {from, self()},
+ {accepters, 3},
+ {mfa, {ssl_test_lib, send_recv_result_active, []}},
+ {options, ServerOpts}]),
+ Port = ssl_test_lib:inet_port(Server0),
+ [Server1, Server2] = ssl_test_lib:accepters(2),
+
+ Client0 = ssl_test_lib:start_client([{node, ClientNode}, {port, Port},
+ {host, Hostname},
+ {from, self()},
+ {mfa, {ssl_test_lib, send_recv_result_active, []}},
+ {options, ClientOpts}
+ ]),
+
+ Client1 = ssl_test_lib:start_client([{node, ClientNode}, {port, Port},
+ {host, Hostname},
+ {from, self()},
+ {mfa, {ssl_test_lib, send_recv_result_active, []}},
+ {options, ClientOpts}
+ ]),
+
+ Client2 = ssl_test_lib:start_client([{node, ClientNode}, {port, Port},
+ {host, Hostname},
+ {from, self()},
+ {mfa, {ssl_test_lib, send_recv_result_active, []}},
+ {options, ClientOpts}
+ ]),
+
+ ssl_test_lib:check_ok([Server0, Server1, Server2, Client0, Client1, Client2]),
+
+ ssl_test_lib:close(Server0),
+ ssl_test_lib:close(Server1),
+ ssl_test_lib:close(Server2),
+ ssl_test_lib:close(Client0),
+ ssl_test_lib:close(Client1),
+ ssl_test_lib:close(Client2).
+
+%%--------------------------------------------------------------------
+reuseaddr() ->
+ [{doc,"Test reuseaddr option"}].
+
+reuseaddr(Config) when is_list(Config) ->
+ ClientOpts = ssl_test_lib:ssl_options(client_rsa_opts, Config),
+ ServerOpts = ssl_test_lib:ssl_options(server_rsa_opts, Config),
+ {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
+ Server =
+ ssl_test_lib:start_server([{node, ServerNode}, {port, 0},
+ {from, self()},
+ {mfa, {ssl_test_lib, no_result, []}},
+ {options, [{active, false}, {reuseaddr, true}| 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, no_result, []}},
+ {options, [{active, false} | ClientOpts]}]),
+ ssl_test_lib:close(Server),
+ ssl_test_lib:close(Client),
+
+ Server1 =
+ ssl_test_lib:start_server([{node, ServerNode}, {port, Port},
+ {from, self()},
+ {mfa, {ssl_test_lib, send_recv_result, []}},
+ {options, [{active, false}, {reuseaddr, true} | ServerOpts]}]),
+ Client1 =
+ ssl_test_lib:start_client([{node, ClientNode}, {port, Port},
+ {host, Hostname},
+ {from, self()},
+ {mfa, {ssl_test_lib, send_recv_result, []}},
+ {options, [{active, false} | ClientOpts]}]),
+
+ ssl_test_lib:check_result(Server1, ok, Client1, ok),
+ ssl_test_lib:close(Server1),
+ ssl_test_lib:close(Client1).
+
+%%--------------------------------------------------------------------
+%% Internal functions ------------------------------------------------
+%%--------------------------------------------------------------------
+
+upgrade_result(Socket) ->
+ ssl:setopts(Socket, [{active, true}]),
+ ok = ssl:send(Socket, "Hello world"),
+ %% Make sure binary is inherited from tcp socket and that we do
+ %% not get the list default!
+ receive
+ {ssl, _, <<"H">>} ->
+ receive
+ {ssl, _, <<"ello world">>} ->
+ ok
+ end;
+ {ssl, _, <<"Hello world">>} ->
+ ok
+ end.
+tls_downgrade_result(Socket, Pid) ->
+ ok = ssl_test_lib:send_recv_result(Socket),
+ Pid ! {self(), ready},
+ receive
+ go ->
+ ok
+ end,
+ case ssl:close(Socket, {self(), 10000}) of
+ {ok, TCPSocket} ->
+ inet:setopts(TCPSocket, [{active, true}]),
+ gen_tcp:send(TCPSocket, "Downgraded"),
+ receive
+ {tcp, TCPSocket, <<"Downgraded">>} ->
+ ok;
+ {tcp_closed, TCPSocket} ->
+ ct:fail("Peer timed out, downgrade aborted"),
+ ok;
+ Other ->
+ {error, Other}
+ end;
+ {error, timeout} ->
+ ct:fail("Timed out, downgrade aborted"),
+ ok;
+ Fail ->
+ {error, Fail}
+ end.
+
+tls_shutdown_result(Socket, server) ->
+ ssl:send(Socket, "Hej"),
+ ok = ssl:shutdown(Socket, write),
+ {ok, "Hej hopp"} = ssl:recv(Socket, 8),
+ ok;
+
+tls_shutdown_result(Socket, client) ->
+ ssl:send(Socket, "Hej hopp"),
+ ok = ssl:shutdown(Socket, write),
+ {ok, "Hej"} = ssl:recv(Socket, 3),
+ ok.
+
+tls_shutdown_write_result(Socket, server) ->
+ ct:sleep(?SLEEP),
+ ssl:shutdown(Socket, write);
+tls_shutdown_write_result(Socket, client) ->
+ ssl:recv(Socket, 0).
+
+tls_shutdown_both_result(Socket, server) ->
+ ct:sleep(?SLEEP),
+ ssl:shutdown(Socket, read_write);
+tls_shutdown_both_result(Socket, client) ->
+ ssl:recv(Socket, 0).
+
+tls_closed_in_active_once_loop(Socket) ->
+ case ssl:setopts(Socket, [{active, once}]) of
+ ok ->
+ receive
+ {ssl, Socket, _} ->
+ tls_closed_in_active_once_loop(Socket);
+ {ssl_closed, Socket} ->
+ ok
+ after 5000 ->
+ no_ssl_closed_received
+ end;
+ {error, closed} ->
+ ok
+ end.
+
+drop_handshakes(Socket, Timeout) ->
+ {ok, <<RecType:8, _RecMajor:8, _RecMinor:8, RecLen:16>> = Header} = gen_tcp:recv(Socket, 5, Timeout),
+ {ok, <<Frag:RecLen/binary>>} = gen_tcp:recv(Socket, RecLen, Timeout),
+ case RecType of
+ 22 -> drop_handshakes(Socket, Timeout);
+ _ -> {ok, <<Header/binary, Frag/binary>>}
+ end.
+
+receive_msg(_) ->
+ receive
+ Msg ->
+ Msg
+ end.
+
+sockname_result(S) ->
+ ssl:sockname(S).
+
+peername_result(S) ->
+ ssl:peername(S).
+
+tls_socket_options_result(Socket, Options, DefaultValues, NewOptions, NewValues) ->
+ %% Test get/set emulated opts
+ {ok, DefaultValues} = ssl:getopts(Socket, Options),
+ ssl:setopts(Socket, NewValues),
+ {ok, NewValues} = ssl:getopts(Socket, NewOptions),
+ %% Test get/set inet opts
+ {ok,[{nodelay,false}]} = ssl:getopts(Socket, [nodelay]),
+ ssl:setopts(Socket, [{nodelay, true}]),
+ {ok,[{nodelay, true}]} = ssl:getopts(Socket, [nodelay]),
+ {ok, All} = ssl:getopts(Socket, []),
+ ct:log("All opts ~p~n", [All]),
+ ok.
+