aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--bootstrap/lib/stdlib/ebin/epp.beambin27416 -> 27416 bytes
-rw-r--r--erts/configure.in16
-rw-r--r--erts/doc/src/crash_dump.xml4
-rw-r--r--erts/emulator/Makefile.in13
-rw-r--r--erts/emulator/beam/beam_load.c14
-rw-r--r--erts/emulator/beam/bif.tab6
-rw-r--r--erts/emulator/beam/big.c23
-rw-r--r--erts/emulator/beam/break.c1
-rw-r--r--erts/emulator/beam/dist.c16
-rw-r--r--erts/emulator/beam/erl_alloc.c89
-rw-r--r--erts/emulator/beam/erl_alloc.h20
-rw-r--r--erts/emulator/beam/erl_alloc.types1
-rw-r--r--erts/emulator/beam/erl_alloc_util.c89
-rwxr-xr-xerts/emulator/beam/erl_bif_info.c68
-rw-r--r--erts/emulator/beam/erl_bif_port.c173
-rw-r--r--erts/emulator/beam/erl_bif_trace.c4
-rw-r--r--erts/emulator/beam/erl_instrument.c97
-rw-r--r--erts/emulator/beam/erl_lock_check.c4
-rw-r--r--erts/emulator/beam/erl_monitors.c20
-rw-r--r--erts/emulator/beam/erl_monitors.h2
-rw-r--r--erts/emulator/beam/erl_mtrace.c44
-rw-r--r--erts/emulator/beam/erl_node_tables.c6
-rw-r--r--erts/emulator/beam/erl_port.h22
-rw-r--r--erts/emulator/beam/erl_port_task.c28
-rw-r--r--erts/emulator/beam/erl_port_task.h2
-rw-r--r--erts/emulator/beam/erl_process.c2
-rw-r--r--erts/emulator/beam/erl_process.h3
-rw-r--r--erts/emulator/beam/erl_process_dump.c37
-rw-r--r--erts/emulator/beam/external.c15
-rw-r--r--erts/emulator/beam/io.c323
-rw-r--r--erts/emulator/drivers/common/inet_drv.c131
-rw-r--r--erts/emulator/drivers/unix/ttsl_drv.c41
-rw-r--r--erts/emulator/drivers/win32/ttsl_drv.c4
-rw-r--r--erts/emulator/hipe/hipe_x86_signal.c1
-rw-r--r--erts/emulator/sys/unix/sys_float.c4
-rwxr-xr-xerts/emulator/sys/win32/sys.c26
-rw-r--r--erts/emulator/sys/win32/sys_float.c4
-rw-r--r--erts/emulator/test/busy_port_SUITE.erl2
-rw-r--r--erts/etc/unix/cerl.src5
-rw-r--r--erts/lib_src/Makefile.in8
-rw-r--r--erts/preloaded/ebin/erlang.beambin93388 -> 92912 bytes
-rw-r--r--erts/preloaded/ebin/erts_internal.beambin3644 -> 3276 bytes
-rw-r--r--erts/preloaded/ebin/prim_inet.beambin70084 -> 70072 bytes
-rw-r--r--erts/preloaded/src/erlang.erl22
-rw-r--r--erts/preloaded/src/erts_internal.erl16
-rw-r--r--erts/preloaded/src/prim_inet.erl8
-rw-r--r--lib/crypto/c_src/crypto.c863
-rw-r--r--[-rwxr-xr-x]lib/crypto/doc/src/crypto.xml1548
-rw-r--r--lib/crypto/doc/src/crypto_app.xml79
-rw-r--r--lib/crypto/src/crypto.erl692
-rw-r--r--lib/crypto/test/crypto_SUITE.erl312
-rw-r--r--lib/erl_interface/src/connect/ei_connect.c3
-rw-r--r--lib/ic/java_src/com/ericsson/otp/ic/Environment.java4
-rw-r--r--lib/ic/src/icparse.yrl3
-rw-r--r--lib/kernel/doc/src/inet.xml4
-rw-r--r--lib/kernel/src/gen_sctp.erl4
-rw-r--r--lib/kernel/src/gen_udp.erl4
-rw-r--r--lib/kernel/src/inet.erl5
-rw-r--r--lib/kernel/src/inet_int.hrl4
-rw-r--r--lib/kernel/test/inet_sockopt_SUITE.erl8
-rw-r--r--lib/mnesia/src/mnesia_index.erl10
-rw-r--r--lib/mnesia/src/mnesia_loader.erl14
-rw-r--r--lib/mnesia/test/mnesia_evil_coverage_test.erl51
-rw-r--r--lib/public_key/asn1/ECPrivateKey.asn124
-rw-r--r--lib/public_key/asn1/OTP-PKIX.asn130
-rw-r--r--lib/public_key/asn1/OTP-PUB-KEY.set.asn1
-rw-r--r--lib/public_key/asn1/PKCS-1.asn132
-rw-r--r--lib/public_key/asn1/PKIX1Algorithms88.asn1118
-rw-r--r--lib/public_key/doc/src/public_key.xml47
-rw-r--r--lib/public_key/include/public_key.hrl8
-rw-r--r--lib/public_key/src/pubkey_cert_records.erl88
-rw-r--r--lib/public_key/src/pubkey_pem.erl16
-rw-r--r--lib/public_key/src/public_key.erl185
-rw-r--r--lib/public_key/test/erl_make_certs.erl67
-rw-r--r--lib/public_key/test/pkits_SUITE.erl11
-rw-r--r--lib/public_key/test/public_key_SUITE.erl2
-rw-r--r--lib/reltool/src/reltool_utils.erl2
-rw-r--r--lib/ssl/doc/src/ssl.xml15
-rw-r--r--lib/ssl/src/ssl.erl18
-rw-r--r--lib/ssl/src/ssl_certificate.erl15
-rw-r--r--lib/ssl/src/ssl_certificate_db.erl2
-rw-r--r--lib/ssl/src/ssl_cipher.erl450
-rw-r--r--lib/ssl/src/ssl_cipher.hrl120
-rw-r--r--lib/ssl/src/ssl_connection.erl207
-rw-r--r--lib/ssl/src/ssl_handshake.erl348
-rw-r--r--lib/ssl/src/ssl_handshake.hrl52
-rw-r--r--lib/ssl/src/ssl_internal.hrl6
-rw-r--r--lib/ssl/src/ssl_manager.erl4
-rw-r--r--lib/ssl/src/ssl_record.erl10
-rw-r--r--lib/ssl/src/ssl_ssl3.erl10
-rw-r--r--lib/ssl/src/ssl_tls1.erl115
-rw-r--r--lib/ssl/test/erl_make_certs.erl65
-rw-r--r--lib/ssl/test/ssl_basic_SUITE.erl171
-rw-r--r--lib/ssl/test/ssl_certificate_verify_SUITE.erl18
-rw-r--r--lib/ssl/test/ssl_npn_handshake_SUITE.erl12
-rw-r--r--lib/ssl/test/ssl_npn_hello_SUITE.erl16
-rw-r--r--lib/ssl/test/ssl_packet_SUITE.erl4
-rw-r--r--lib/ssl/test/ssl_payload_SUITE.erl12
-rw-r--r--lib/ssl/test/ssl_session_cache_SUITE.erl2
-rw-r--r--lib/ssl/test/ssl_test_lib.erl268
-rw-r--r--lib/ssl/test/ssl_to_openssl_SUITE.erl129
-rw-r--r--lib/stdlib/src/epp.erl2
-rw-r--r--lib/stdlib/src/erl_pp.erl33
-rw-r--r--lib/stdlib/src/otp_internal.erl133
-rw-r--r--lib/stdlib/test/epp_SUITE.erl4
-rw-r--r--lib/stdlib/test/erl_pp_SUITE.erl43
-rw-r--r--lib/stdlib/test/ets_SUITE.erl68
-rw-r--r--make/run_make.mk2
108 files changed, 5241 insertions, 2766 deletions
diff --git a/bootstrap/lib/stdlib/ebin/epp.beam b/bootstrap/lib/stdlib/ebin/epp.beam
index 0e3672e3b0..879370ef87 100644
--- a/bootstrap/lib/stdlib/ebin/epp.beam
+++ b/bootstrap/lib/stdlib/ebin/epp.beam
Binary files differ
diff --git a/erts/configure.in b/erts/configure.in
index 2ee907b6e4..b9c9a76ef6 100644
--- a/erts/configure.in
+++ b/erts/configure.in
@@ -1342,6 +1342,17 @@ if test "x$TERMCAP_LIB" != "x"; then
AC_DEFINE(HAVE_TERMCAP, 1, [Define if termcap functions exists])
fi
+if test "X$host" != "Xwin32"; then
+ AC_MSG_CHECKING(for wcwidth)
+ AC_TRY_LINK([#include <wchar.h>], [wcwidth(0);],
+ have_wcwidth=yes, have_wcwidth=no)
+ if test $have_wcwidth = yes; then
+ AC_MSG_RESULT([yes])
+ AC_DEFINE(HAVE_WCWIDTH, [1],
+ [Define to 1 if you have a `wcwidth' function.])
+ fi
+fi
+
dnl -------------
dnl zlib
dnl -------------
@@ -3576,10 +3587,7 @@ DED_EXT=so
case $host_os in
win32) DED_EXT=dll;;
darwin*)
- DED_CFLAGS="$DED_CFLAGS -fno-common"
- if test "X$STATIC_CFLAGS" = "X"; then
- STATIC_CFLAGS="-mdynamic-no-pic"
- fi;;
+ DED_CFLAGS="$DED_CFLAGS -fno-common";;
*)
;;
esac
diff --git a/erts/doc/src/crash_dump.xml b/erts/doc/src/crash_dump.xml
index b3c4671c3d..73212e6143 100644
--- a/erts/doc/src/crash_dump.xml
+++ b/erts/doc/src/crash_dump.xml
@@ -290,6 +290,10 @@
<em>Stack+heap</em>, <em>OldHeap</em>, <em>Heap unused</em>
and <em>OldHeap unused</em> do not exist. Instead this field
presents the size of the process' stack.</item>
+ <tag><em>Memory</em></tag>
+ <item>The total memory used by this process. This includes call stack,
+ heap and internal structures. Same as <seealso marker="erlang#process_info-2">erlang:process_info(Pid,memory)</seealso>.
+ </item>
<tag><em>Program counter</em></tag>
<item>The current instruction pointer. This is only interesting for
runtime system developers. The function into which the program
diff --git a/erts/emulator/Makefile.in b/erts/emulator/Makefile.in
index 4f2f647742..2031ec3a4c 100644
--- a/erts/emulator/Makefile.in
+++ b/erts/emulator/Makefile.in
@@ -48,6 +48,7 @@ CREATE_DIRS=
LDFLAGS=@LDFLAGS@
ARFLAGS=rc
+OMIT_OMIT_FP=no
ifeq ($(TYPE),debug)
PURIFY =
@@ -113,6 +114,13 @@ TYPEMARKER = .lcnt
TYPE_FLAGS = @CFLAGS@ -DERTS_ENABLE_LOCK_COUNT
else
+ifeq ($(TYPE),frmptr)
+PURIFY =
+OMIT_OMIT_FP=yes
+TYPEMARKER = .frmptr
+TYPE_FLAGS = @CFLAGS@ -DERTS_FRMPTR
+else
+
# If type isn't one of the above, it *is* opt type...
override TYPE=opt
PURIFY =
@@ -126,6 +134,7 @@ endif
endif
endif
endif
+endif
#
# NOTE: When adding a new type update ERL_BUILD_TYPE_MARKER in sys/unix/sys.c
@@ -219,8 +228,6 @@ LIB_PREFIX=lib
LIB_SUFFIX=.a
endif
-OMIT_OMIT_FP=no
-
ifeq (@EMU_LOCK_CHECKING@,yes)
NO_INLINE_FUNCTIONS=true
endif
@@ -238,7 +245,7 @@ ifeq ($(NO_INLINE_FUNCTIONS),true)
GEN_OPT_FLGS = $(OPT_LEVEL) -fno-inline-functions
else
ifeq ($(OMIT_OMIT_FP),yes)
-GEN_OPT_FLGS = $(OPT_LEVEL)
+GEN_OPT_FLGS = $(OPT_LEVEL) -fno-omit-frame-pointer
else
GEN_OPT_FLGS = $(OPT_LEVEL) -fomit-frame-pointer
endif
diff --git a/erts/emulator/beam/beam_load.c b/erts/emulator/beam/beam_load.c
index bd4e5a52d0..4193eb4f3f 100644
--- a/erts/emulator/beam/beam_load.c
+++ b/erts/emulator/beam/beam_load.c
@@ -2964,19 +2964,19 @@ gen_put_integer(LoaderState* stp, GenOpArg Fail, GenOpArg Size,
NEW_GENOP(stp, op);
NATIVE_ENDIAN(Flags);
- if (Size.type == TAG_i && Size.val < 0) {
- error:
/* Negative size must fail */
- op->op = genop_badarg_1;
- op->arity = 1;
- op->a[0] = Fail;
- } else if (Size.type == TAG_i) {
+ if (Size.type == TAG_i) {
op->op = genop_i_new_bs_put_integer_imm_4;
op->arity = 4;
op->a[0] = Fail;
op->a[1].type = TAG_u;
if (!safe_mul(Size.val, Unit.val, &op->a[1].val)) {
- goto error;
+ error:
+ op->op = genop_badarg_1;
+ op->arity = 1;
+ op->a[0] = Fail;
+ op->next = NULL;
+ return op;
}
op->a[1].val = Size.val * Unit.val;
op->a[2].type = Flags.type;
diff --git a/erts/emulator/beam/bif.tab b/erts/emulator/beam/bif.tab
index 8bc994c8c3..dc8e9101de 100644
--- a/erts/emulator/beam/bif.tab
+++ b/erts/emulator/beam/bif.tab
@@ -154,8 +154,10 @@ bif erts_internal:port_command/3
bif erts_internal:port_control/3
bif erts_internal:port_close/1
bif erts_internal:port_connect/2
-bif erts_internal:port_set_data/2
-bif erts_internal:port_get_data/1
+
+# inet_db support
+bif erlang:port_set_data/2
+bif erlang:port_get_data/1
# Tracing & debugging.
bif erlang:trace_pattern/2
diff --git a/erts/emulator/beam/big.c b/erts/emulator/beam/big.c
index 9260c0c4b8..6f9b171224 100644
--- a/erts/emulator/beam/big.c
+++ b/erts/emulator/beam/big.c
@@ -2528,17 +2528,18 @@ const byte d_base_exp_lookup[] = { 31, 19, 15, 13, 11, 11, 10, 9, 9, 8, 8, 8, 8,
* end
* How much can the characters which fit in 31 bit represent
*/
-const Uint d_base_base_lookup[] = { 2147483648, 1162261467, 1073741824,
- 1220703125, 362797056, 1977326743, 1073741824, 387420489, 1000000000,
- 214358881, 429981696, 815730721, 1475789056, 170859375, 268435456,
- 410338673, 612220032, 893871739, 1280000000, 1801088541, 113379904,
- 148035889, 191102976, 244140625, 308915776, 387420489, 481890304,
- 594823321, 729000000, 887503681, 1073741824, 1291467969, 1544804416,
- 1838265625, 60466176, 69343957, 79235168, 90224199, 102400000,
- 115856201, 130691232, 147008443, 164916224, 184528125, 205962976,
- 229345007, 254803968, 282475249, 312500000, 345025251, 380204032,
- 418195493, 459165024, 503284375, 550731776, 601692057, 656356768,
- 714924299, 777600000, 844596301, 916132832, 992436543, 1073741824 };
+const Uint d_base_base_lookup[] = { 2147483648u, 1162261467u, 1073741824u,
+ 1220703125u, 362797056u, 1977326743u, 1073741824u, 387420489u,
+ 1000000000u, 214358881u, 429981696u, 815730721u, 1475789056u,
+ 170859375u, 268435456u, 410338673u, 612220032u, 893871739u, 1280000000u,
+ 1801088541u, 113379904u, 148035889u, 191102976u, 244140625u, 308915776u,
+ 387420489u, 481890304u, 594823321u, 729000000u, 887503681u, 1073741824u,
+ 1291467969u, 1544804416u, 1838265625u, 60466176u, 69343957u, 79235168u,
+ 90224199u, 102400000u, 115856201u, 130691232u, 147008443u, 164916224u,
+ 184528125u, 205962976u, 229345007u, 254803968u, 282475249u, 312500000u,
+ 345025251u, 380204032u, 418195493u, 459165024u, 503284375u, 550731776u,
+ 601692057u, 656356768u, 714924299u, 777600000u, 844596301u, 916132832u,
+ 992436543u, 1073741824u };
Eterm erts_chars_to_integer(Process *BIF_P, char *bytes,
Uint size, const int base) {
diff --git a/erts/emulator/beam/break.c b/erts/emulator/beam/break.c
index 9aa1e5f30d..e34fc8388c 100644
--- a/erts/emulator/beam/break.c
+++ b/erts/emulator/beam/break.c
@@ -331,6 +331,7 @@ print_process_info(int to, void *to_arg, Process *p)
erts_print(to, to_arg, "Heap unused: %bpu\n", (p->hend - p->htop));
erts_print(to, to_arg, "OldHeap unused: %bpu\n",
(OLD_HEAP(p) == NULL) ? 0 : (OLD_HEND(p) - OLD_HTOP(p)) );
+ erts_print(to, to_arg, "Memory: %beu\n", erts_process_memory(p));
if (garbing) {
print_garb_info(to, to_arg, p);
diff --git a/erts/emulator/beam/dist.c b/erts/emulator/beam/dist.c
index 0781665f05..44f4eb9d43 100644
--- a/erts/emulator/beam/dist.c
+++ b/erts/emulator/beam/dist.c
@@ -455,7 +455,7 @@ int erts_do_net_exits(DistEntry *dep, Eterm reason)
Eterm nd_reason = (reason == am_no_network
? am_no_network
: am_net_kernel_terminated);
- erts_smp_rwmtx_rwlock(&erts_dist_table_rwmtx);
+ erts_smp_rwmtx_rlock(&erts_dist_table_rwmtx);
for (tdep = erts_hidden_dist_entries; tdep; tdep = tdep->next)
no_dist_port++;
@@ -464,7 +464,7 @@ int erts_do_net_exits(DistEntry *dep, Eterm reason)
/* KILL all port controllers */
if (no_dist_port == 0)
- erts_smp_rwmtx_rwunlock(&erts_dist_table_rwmtx);
+ erts_smp_rwmtx_runlock(&erts_dist_table_rwmtx);
else {
Eterm def_buf[128];
int i = 0;
@@ -483,7 +483,7 @@ int erts_do_net_exits(DistEntry *dep, Eterm reason)
ASSERT(is_internal_port(tdep->cid));
dist_port[i++] = tdep->cid;
}
- erts_smp_rwmtx_rwunlock(&erts_dist_table_rwmtx);
+ erts_smp_rwmtx_runlock(&erts_dist_table_rwmtx);
for (i = 0; i < no_dist_port; i++) {
Port *prt = erts_port_lookup(dist_port[i],
@@ -2560,9 +2560,9 @@ BIF_RETTYPE setnode_2(BIF_ALIST_2)
erts_smp_proc_unlock(net_kernel, ERTS_PROC_LOCK_MAIN);
#ifdef DEBUG
- erts_smp_rwmtx_rwlock(&erts_dist_table_rwmtx);
+ erts_smp_rwmtx_rlock(&erts_dist_table_rwmtx);
ASSERT(!erts_visible_dist_entries && !erts_hidden_dist_entries);
- erts_smp_rwmtx_rwunlock(&erts_dist_table_rwmtx);
+ erts_smp_rwmtx_runlock(&erts_dist_table_rwmtx);
#endif
erts_smp_proc_unlock(BIF_P, ERTS_PROC_LOCK_MAIN);
@@ -2912,7 +2912,7 @@ BIF_RETTYPE nodes_1(BIF_ALIST_1)
length = 0;
- erts_smp_rwmtx_rwlock(&erts_dist_table_rwmtx);
+ erts_smp_rwmtx_rlock(&erts_dist_table_rwmtx);
ASSERT(erts_no_of_not_connected_dist_entries >= 0);
ASSERT(erts_no_of_hidden_dist_entries >= 0);
@@ -2929,7 +2929,7 @@ BIF_RETTYPE nodes_1(BIF_ALIST_1)
result = NIL;
if (length == 0) {
- erts_smp_rwmtx_rwunlock(&erts_dist_table_rwmtx);
+ erts_smp_rwmtx_runlock(&erts_dist_table_rwmtx);
goto done;
}
@@ -2958,7 +2958,7 @@ BIF_RETTYPE nodes_1(BIF_ALIST_1)
hp += 2;
}
ASSERT(endp == hp);
- erts_smp_rwmtx_rwunlock(&erts_dist_table_rwmtx);
+ erts_smp_rwmtx_runlock(&erts_dist_table_rwmtx);
done:
UnUseTmpHeap(2,BIF_P);
diff --git a/erts/emulator/beam/erl_alloc.c b/erts/emulator/beam/erl_alloc.c
index d748f86d75..c19a2647e4 100644
--- a/erts/emulator/beam/erl_alloc.c
+++ b/erts/emulator/beam/erl_alloc.c
@@ -495,6 +495,38 @@ refuse_af_strategy(struct au_init *init)
static void hdbg_init(void);
#endif
+static void adjust_fix_alloc_sizes(UWord extra_block_size)
+{
+
+ if (extra_block_size && erts_allctrs_info[ERTS_ALC_A_FIXED_SIZE].enabled) {
+ int j;
+
+#ifdef ERTS_SMP
+ if (erts_allctrs_info[ERTS_ALC_A_FIXED_SIZE].thr_spec) {
+ int i;
+ ErtsAllocatorThrSpec_t* tspec;
+
+ tspec = &erts_allctr_thr_spec[ERTS_ALC_A_FIXED_SIZE];
+ ASSERT(tspec->enabled);
+
+ for (i=0; i < tspec->size; i++) {
+ Allctr_t* allctr = tspec->allctr[i];
+ for (j=0; j < ERTS_ALC_NO_FIXED_SIZES; ++j) {
+ allctr->fix[j].type_size += extra_block_size;
+ }
+ }
+ }
+ else
+#endif
+ {
+ Allctr_t* allctr = erts_allctrs_info[ERTS_ALC_A_FIXED_SIZE].extra;
+ for (j=0; j < ERTS_ALC_NO_FIXED_SIZES; ++j) {
+ allctr->fix[j].type_size += extra_block_size;
+ }
+ }
+ }
+}
+
void
erts_alloc_init(int *argc, char **argv, ErtsAllocInitOpts *eaiop)
{
@@ -515,9 +547,9 @@ erts_alloc_init(int *argc, char **argv, ErtsAllocInitOpts *eaiop)
= sizeof(Process);
#if !HALFWORD_HEAP
fix_type_sizes[ERTS_ALC_FIX_TYPE_IX(ERTS_ALC_T_MONITOR_SH)]
- = ERTS_MONITOR_SH_SIZE;
+ = ERTS_MONITOR_SH_SIZE * sizeof(Uint);
fix_type_sizes[ERTS_ALC_FIX_TYPE_IX(ERTS_ALC_T_NLINK_SH)]
- = ERTS_LINK_SH_SIZE;
+ = ERTS_LINK_SH_SIZE * sizeof(Uint);
#endif
fix_type_sizes[ERTS_ALC_FIX_TYPE_IX(ERTS_ALC_T_DRV_EV_D_STATE)]
= sizeof(ErtsDrvEventDataState);
@@ -538,6 +570,8 @@ erts_alloc_init(int *argc, char **argv, ErtsAllocInitOpts *eaiop)
if (ncpu < 1)
ncpu = 1;
+ erts_tsd_key_create(&erts_allctr_prelock_tsd_key);
+
erts_sys_alloc_init();
erts_init_utils_mem();
@@ -768,7 +802,7 @@ erts_alloc_init(int *argc, char **argv, ErtsAllocInitOpts *eaiop)
#ifdef DEBUG
extra_block_size += install_debug_functions();
#endif
-
+ adjust_fix_alloc_sizes(extra_block_size);
}
void
@@ -3107,6 +3141,55 @@ erts_request_alloc_info(struct process *c_p,
return 1;
}
+/*
+ * The allocator wrapper prelocking stuff below is about the locking order.
+ * It only affects wrappers (erl_mtrace.c and erl_instrument.c) that keep locks
+ * during alloc/realloc/free.
+ *
+ * Some query functions in erl_alloc_util.c lock the allocator mutex and then
+ * use erts_printf that in turn may call the sys allocator through the wrappers.
+ * To avoid breaking locking order these query functions first "pre-locks" all
+ * allocator wrappers.
+ */
+ErtsAllocatorWrapper_t *erts_allctr_wrappers;
+int erts_allctr_wrapper_prelocked = 0;
+erts_tsd_key_t erts_allctr_prelock_tsd_key;
+
+void erts_allctr_wrapper_prelock_init(ErtsAllocatorWrapper_t* wrapper)
+{
+ ASSERT(wrapper->lock && wrapper->unlock);
+ wrapper->next = erts_allctr_wrappers;
+ erts_allctr_wrappers = wrapper;
+}
+
+void erts_allctr_wrapper_pre_lock(void)
+{
+ if (erts_allctr_wrappers) {
+ ErtsAllocatorWrapper_t* wrapper = erts_allctr_wrappers;
+ for ( ; wrapper; wrapper = wrapper->next) {
+ wrapper->lock();
+ }
+ ASSERT(!erts_allctr_wrapper_prelocked);
+ erts_allctr_wrapper_prelocked = 1;
+ erts_tsd_set(erts_allctr_prelock_tsd_key, (void*)1);
+ }
+}
+
+void erts_allctr_wrapper_pre_unlock(void)
+{
+ if (erts_allctr_wrappers) {
+ ErtsAllocatorWrapper_t* wrapper = erts_allctr_wrappers;
+
+ erts_allctr_wrapper_prelocked = 0;
+ erts_tsd_set(erts_allctr_prelock_tsd_key, (void*)0);
+ for ( ; wrapper; wrapper = wrapper->next) {
+ wrapper->unlock();
+ }
+ }
+}
+
+
+
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *\
* Deprecated functions *
* *
diff --git a/erts/emulator/beam/erl_alloc.h b/erts/emulator/beam/erl_alloc.h
index ba5ec9c367..9cafd8ddc8 100644
--- a/erts/emulator/beam/erl_alloc.h
+++ b/erts/emulator/beam/erl_alloc.h
@@ -135,6 +135,18 @@ typedef struct {
extern ErtsAllocatorThrSpec_t erts_allctr_thr_spec[ERTS_ALC_A_MAX+1];
+typedef struct ErtsAllocatorWrapper_t_ {
+ void (*lock)(void);
+ void (*unlock)(void);
+ struct ErtsAllocatorWrapper_t_* next;
+}ErtsAllocatorWrapper_t;
+ErtsAllocatorWrapper_t *erts_allctr_wrappers;
+extern int erts_allctr_wrapper_prelocked;
+extern erts_tsd_key_t erts_allctr_prelock_tsd_key;
+void erts_allctr_wrapper_prelock_init(ErtsAllocatorWrapper_t* wrapper);
+void erts_allctr_wrapper_pre_lock(void);
+void erts_allctr_wrapper_pre_unlock(void);
+
void erts_alloc_register_scheduler(void *vesdp);
#ifdef ERTS_SMP
void erts_alloc_scheduler_handle_delayed_dealloc(void *vesdp,
@@ -188,6 +200,7 @@ void *erts_realloc(ErtsAlcType_t type, void *ptr, Uint size);
void erts_free(ErtsAlcType_t type, void *ptr);
void *erts_alloc_fnf(ErtsAlcType_t type, Uint size);
void *erts_realloc_fnf(ErtsAlcType_t type, void *ptr, Uint size);
+int erts_is_allctr_wrapper_prelocked(void);
#endif /* #if !ERTS_ALC_DO_INLINE */
@@ -258,6 +271,13 @@ void *erts_realloc_fnf(ErtsAlcType_t type, void *ptr, Uint size)
size);
}
+ERTS_ALC_INLINE
+int erts_is_allctr_wrapper_prelocked(void)
+{
+ return erts_allctr_wrapper_prelocked /* locked */
+ && !!erts_tsd_get(erts_allctr_prelock_tsd_key); /* by me */
+}
+
#endif /* #if ERTS_ALC_DO_INLINE || defined(ERTS_ALC_INTERNAL__) */
#define ERTS_ALC_GET_THR_IX() ((int) erts_get_scheduler_id())
diff --git a/erts/emulator/beam/erl_alloc.types b/erts/emulator/beam/erl_alloc.types
index 5e3615ccc2..5a92ab7f24 100644
--- a/erts/emulator/beam/erl_alloc.types
+++ b/erts/emulator/beam/erl_alloc.types
@@ -272,6 +272,7 @@ type CODE_IX_LOCK_Q SHORT_LIVED SYSTEM code_ix_lock_q
type PROC_INTERVAL LONG_LIVED SYSTEM process_interval
type BUSY_CALLER_TAB SHORT_LIVED SYSTEM busy_caller_table
type BUSY_CALLER SHORT_LIVED SYSTEM busy_caller
+type PORT_DATA_HEAP STANDARD SYSTEM port_data_heap
+if threads_no_smp
# Need thread safe allocs, but std_alloc and fix_alloc are not;
diff --git a/erts/emulator/beam/erl_alloc_util.c b/erts/emulator/beam/erl_alloc_util.c
index ac7f420708..cbeb2c1e3a 100644
--- a/erts/emulator/beam/erl_alloc_util.c
+++ b/erts/emulator/beam/erl_alloc_util.c
@@ -588,17 +588,21 @@ do { \
#ifdef DEBUG
#ifdef USE_THREADS
+# ifdef ERTS_SMP
+# define IS_ACTUALLY_BLOCKING (erts_thr_progress_is_blocking())
+# else
+# define IS_ACTUALLY_BLOCKING 0
+# endif
#define ERTS_ALCU_DBG_CHK_THR_ACCESS(A) \
do { \
- if (!(A)->thread_safe) { \
- if (!(A)->debug.saved_tid) { \
+ if (!(A)->thread_safe && !IS_ACTUALLY_BLOCKING) { \
+ if (!(A)->debug.saved_tid) { \
(A)->debug.tid = erts_thr_self(); \
(A)->debug.saved_tid = 1; \
} \
else { \
ERTS_SMP_LC_ASSERT( \
- ethr_equal_tids((A)->debug.tid, erts_thr_self()) \
- || erts_thr_progress_is_blocking()); \
+ ethr_equal_tids((A)->debug.tid, erts_thr_self())); \
} \
} \
} while (0)
@@ -878,8 +882,10 @@ erts_alcu_fix_alloc_shrink(Allctr_t *allctr, erts_aint32_t flgs)
#ifdef ERTS_SMP
-#define ERTS_ALCU_DD_FIX_TYPE_OFFS \
- ((sizeof(ErtsAllctrDDBlock_t)-1)/sizeof(UWord) + 1)
+typedef struct {
+ ErtsAllctrDDBlock_t ddblock__; /* must be first */
+ ErtsAlcType_t fix_type;
+}ErtsAllctrFixDDBlock_t;
static ERTS_INLINE Allctr_t*
@@ -1180,7 +1186,7 @@ handle_delayed_dealloc(Allctr_t *allctr,
if (fix) {
ErtsAlcType_t type;
- type = (ErtsAlcType_t) ((UWord *) ptr)[ERTS_ALCU_DD_FIX_TYPE_OFFS];
+ type = ((ErtsAllctrFixDDBlock_t*) ptr)->fix_type;
ix = type - ERTS_ALC_N_MIN_A_FIXED_SIZE;
ERTS_DBG_CHK_FIX_LIST(allctr, fix, ix, 1);
fix[ix].used--;
@@ -1242,7 +1248,7 @@ enqueue_dealloc_other_instance(ErtsAlcType_t type,
int cinit)
{
if (allctr->fix)
- ((UWord *) ptr)[ERTS_ALCU_DD_FIX_TYPE_OFFS] = (UWord) type;
+ ((ErtsAllctrFixDDBlock_t*) ptr)->fix_type = type;
if (ddq_enqueue(type, &allctr->dd.q, ptr, cinit))
erts_alloc_notify_delayed_dealloc(allctr->ix);
@@ -2508,12 +2514,6 @@ static erts_mtx_t init_atoms_mtx;
static void
init_atoms(Allctr_t *allctr)
{
-
-#ifdef USE_THREADS
- if (allctr && allctr->thread_safe)
- erts_mtx_unlock(&allctr->mutex);
-#endif
-
erts_mtx_lock(&init_atoms_mtx);
if (!atoms_initialized) {
@@ -2604,18 +2604,13 @@ init_atoms(Allctr_t *allctr)
fix_type_atoms[ix] = am_atom_put(name, len);
}
}
-
- if (allctr) {
+ if (allctr && !allctr->atoms_initialized) {
make_name_atoms(allctr);
(*allctr->init_atoms)();
-#ifdef USE_THREADS
- if (allctr->thread_safe)
- erts_mtx_lock(&allctr->mutex);
-#endif
allctr->atoms_initialized = 1;
}
@@ -3243,17 +3238,21 @@ erts_alcu_info_options(Allctr_t *allctr,
{
Eterm res;
+ if (hpp || szp)
+ ensure_atoms_initialized(allctr);
#ifdef USE_THREADS
- if (allctr->thread_safe)
+ if (allctr->thread_safe) {
+ erts_allctr_wrapper_pre_lock();
erts_mtx_lock(&allctr->mutex);
+ }
#endif
- if (hpp || szp)
- ensure_atoms_initialized(allctr);
res = info_options(allctr, print_to_p, print_to_arg, hpp, szp);
#ifdef USE_THREADS
- if (allctr->thread_safe)
+ if (allctr->thread_safe) {
erts_mtx_unlock(&allctr->mutex);
+ erts_allctr_wrapper_pre_unlock();
+ }
#endif
return res;
}
@@ -3280,16 +3279,18 @@ erts_alcu_sz_info(Allctr_t *allctr,
return am_false;
}
+ if (hpp || szp)
+ ensure_atoms_initialized(allctr);
+
#ifdef USE_THREADS
- if (allctr->thread_safe)
+ if (allctr->thread_safe) {
+ erts_allctr_wrapper_pre_lock();
erts_mtx_lock(&allctr->mutex);
+ }
#endif
ERTS_ALCU_DBG_CHK_THR_ACCESS(allctr);
- if (hpp || szp)
- ensure_atoms_initialized(allctr);
-
/* Update sbc values not continously updated */
allctr->sbcs.blocks.curr.no
= allctr->sbcs.curr.norm.mseg.no + allctr->sbcs.curr.norm.sys_alloc.no;
@@ -3325,13 +3326,16 @@ erts_alcu_sz_info(Allctr_t *allctr,
#ifdef USE_THREADS
- if (allctr->thread_safe)
+ if (allctr->thread_safe) {
erts_mtx_unlock(&allctr->mutex);
+ erts_allctr_wrapper_pre_unlock();
+ }
#endif
return res;
}
+
Eterm
erts_alcu_info(Allctr_t *allctr,
int begin_max_period,
@@ -3352,16 +3356,18 @@ erts_alcu_info(Allctr_t *allctr,
return am_false;
}
+ if (hpp || szp)
+ ensure_atoms_initialized(allctr);
+
#ifdef USE_THREADS
- if (allctr->thread_safe)
+ if (allctr->thread_safe) {
+ erts_allctr_wrapper_pre_lock();
erts_mtx_lock(&allctr->mutex);
+ }
#endif
ERTS_ALCU_DBG_CHK_THR_ACCESS(allctr);
- if (hpp || szp)
- ensure_atoms_initialized(allctr);
-
/* Update sbc values not continously updated */
allctr->sbcs.blocks.curr.no
= allctr->sbcs.curr.norm.mseg.no + allctr->sbcs.curr.norm.sys_alloc.no;
@@ -3414,8 +3420,10 @@ erts_alcu_info(Allctr_t *allctr,
#ifdef USE_THREADS
- if (allctr->thread_safe)
+ if (allctr->thread_safe) {
erts_mtx_unlock(&allctr->mutex);
+ erts_allctr_wrapper_pre_unlock();
+ }
#endif
return res;
@@ -3487,7 +3495,9 @@ do_erts_alcu_alloc(ErtsAlcType_t type, void *extra, Uint size)
fix = allctr->fix;
if (fix) {
int ix = type - ERTS_ALC_N_MIN_A_FIXED_SIZE;
+ ASSERT((unsigned)ix < ERTS_ALC_NO_FIXED_SIZES);
ERTS_DBG_CHK_FIX_LIST(allctr, fix, ix, 1);
+ ASSERT(size <= fix[ix].type_size);
fix[ix].used++;
res = fix[ix].list;
if (res) {
@@ -3508,8 +3518,7 @@ do_erts_alcu_alloc(ErtsAlcType_t type, void *extra, Uint size)
ERTS_DBG_CHK_FIX_LIST(allctr, fix, ix, 0);
return res;
}
- if (size < 2*sizeof(UWord))
- size += sizeof(UWord);
+ size = fix[ix].type_size;
if (fix[ix].limit < fix[ix].used)
fix[ix].limit = fix[ix].used;
if (fix[ix].max_used < fix[ix].used)
@@ -4198,9 +4207,8 @@ erts_alcu_start(Allctr_t *allctr, AllctrInit_t *init)
#if ERTS_SMP
if (init->tpref) {
Uint sz = ABLK_HDR_SZ;
- sz += ERTS_ALCU_DD_FIX_TYPE_OFFS*sizeof(UWord);
- if (init->fix)
- sz += sizeof(UWord);
+ sz += (init->fix ?
+ sizeof(ErtsAllctrFixDDBlock_t) : sizeof(ErtsAllctrDDBlock_t));
sz = UNIT_CEILING(sz);
if (sz > allctr->min_block_size)
allctr->min_block_size = sz;
@@ -4325,6 +4333,9 @@ erts_alcu_start(Allctr_t *allctr, AllctrInit_t *init)
allctr->fix[i].list = NULL;
allctr->fix[i].allocated = 0;
allctr->fix[i].used = 0;
+#ifdef ERTS_SMP
+ ASSERT(allctr->fix[i].type_size >= sizeof(ErtsAllctrFixDDBlock_t));
+#endif
}
}
diff --git a/erts/emulator/beam/erl_bif_info.c b/erts/emulator/beam/erl_bif_info.c
index 379d3eecc6..54eefe8d12 100755
--- a/erts/emulator/beam/erl_bif_info.c
+++ b/erts/emulator/beam/erl_bif_info.c
@@ -114,6 +114,9 @@ static char erts_system_version[] = ("Erlang " ERLANG_OTP_RELEASE
#ifdef VALGRIND
" [valgrind-compiled]"
#endif
+#ifdef ERTS_FRMPTR
+ " [frame-pointer]"
+#endif
#ifdef USE_DTRACE
" [dtrace]"
#endif
@@ -486,27 +489,6 @@ collect_one_suspend_monitor(ErtsSuspendMonitor *smon, void *vsmicp)
}
}
-
-static void one_link_size(ErtsLink *lnk, void *vpu)
-{
- Uint *pu = vpu;
- *pu += ERTS_LINK_SIZE*sizeof(Uint);
- if(!IS_CONST(lnk->pid))
- *pu += NC_HEAP_SIZE(lnk->pid)*sizeof(Uint);
- if (lnk->type != LINK_NODE && ERTS_LINK_ROOT(lnk) != NULL) {
- erts_doforall_links(ERTS_LINK_ROOT(lnk),&one_link_size,vpu);
- }
-}
-static void one_mon_size(ErtsMonitor *mon, void *vpu)
-{
- Uint *pu = vpu;
- *pu += ERTS_MONITOR_SIZE*sizeof(Uint);
- if(!IS_CONST(mon->pid))
- *pu += NC_HEAP_SIZE(mon->pid)*sizeof(Uint);
- if(!IS_CONST(mon->ref))
- *pu += NC_HEAP_SIZE(mon->ref)*sizeof(Uint);
-}
-
/*
* process_info/[1,2]
*/
@@ -1420,41 +1402,8 @@ process_info_aux(Process *BIF_P,
}
case am_memory: { /* Memory consumed in bytes */
- ErlMessage *mp;
- Uint size = 0;
Uint hsz = 3;
- struct saved_calls *scb;
- size += sizeof(Process);
-
- ERTS_SMP_MSGQ_MV_INQ2PRIVQ(rp);
-
- erts_doforall_links(ERTS_P_LINKS(rp), &one_link_size, &size);
- erts_doforall_monitors(ERTS_P_MONITORS(rp), &one_mon_size, &size);
- size += (rp->heap_sz + rp->mbuf_sz) * sizeof(Eterm);
- if (rp->old_hend && rp->old_heap)
- size += (rp->old_hend - rp->old_heap) * sizeof(Eterm);
-
- size += rp->msg.len * sizeof(ErlMessage);
-
- for (mp = rp->msg.first; mp; mp = mp->next)
- if (mp->data.attached)
- size += erts_msg_attached_data_size(mp)*sizeof(Eterm);
-
- if (rp->arg_reg != rp->def_arg_reg) {
- size += rp->arity * sizeof(rp->arg_reg[0]);
- }
-
- if (rp->psd)
- size += sizeof(ErtsPSD);
-
- scb = ERTS_PROC_GET_SAVED_CALLS_BUF(rp);
- if (scb) {
- size += (sizeof(struct saved_calls)
- + (scb->len-1) * sizeof(scb->ct[0]));
- }
-
- size += erts_dicts_mem_size(rp);
-
+ Uint size = erts_process_memory(rp);
(void) erts_bld_uint(NULL, &hsz, size);
hp = HAlloc(BIF_P, hsz);
res = erts_bld_uint(&hp, NULL, size);
@@ -2096,6 +2045,9 @@ BIF_RETTYPE system_info_1(BIF_ALIST_1)
#elif defined(ERTS_ENABLE_LOCK_COUNT)
ERTS_DECL_AM(lcnt);
BIF_RET(AM_lcnt);
+#elif defined(ERTS_FRMPTR)
+ ERTS_DECL_AM(frmptr);
+ BIF_RET(AM_frmptr);
#else
BIF_RET(am_opt);
#endif
@@ -2861,12 +2813,10 @@ erts_bld_port_info(Eterm **hpp, ErlOffHeap *ohp, Uint *szp, Port *prt, Eterm ite
included though).
*/
Uint size = 0;
- ErlHeapFragment* bp;
- erts_doforall_links(ERTS_P_LINKS(prt), &one_link_size, &size);
+ erts_doforall_links(ERTS_P_LINKS(prt), &erts_one_link_size, &size);
- for (bp = prt->bp; bp; bp = bp->next)
- size += sizeof(ErlHeapFragment) + (bp->alloc_size - 1)*sizeof(Eterm);
+ size += erts_port_data_size(prt);
if (prt->linebuf)
size += sizeof(LineBuf) + prt->linebuf->ovsiz;
diff --git a/erts/emulator/beam/erl_bif_port.c b/erts/emulator/beam/erl_bif_port.c
index 44fa41c7b6..109c54fd7f 100644
--- a/erts/emulator/beam/erl_bif_port.c
+++ b/erts/emulator/beam/erl_bif_port.c
@@ -423,57 +423,164 @@ BIF_RETTYPE erts_internal_port_info_2(BIF_ALIST_2)
}
}
+/*
+ * The erlang:port_set_data()/erlang:port_get_data() operations should
+ * be viewed as operations on a table (inet_db) with data values
+ * associated with port identifier keys. That is, these operations are
+ * *not* signals to/from ports.
+ */
+
+#if (TAG_PRIMARY_IMMED1 & 0x3) == 0
+# error "erlang:port_set_data()/erlang:port_get_data() needs to be rewritten!"
+#endif
+
+typedef struct {
+ ErtsThrPrgrLaterOp later_op;
+ Uint hsize;
+ Eterm data;
+ ErlOffHeap off_heap;
+ Eterm heap[1];
+} ErtsPortDataHeap;
-BIF_RETTYPE erts_internal_port_set_data_2(BIF_ALIST_2)
+static void
+free_port_data_heap(void *vpdhp)
{
- Eterm ref;
+ erts_cleanup_offheap(&((ErtsPortDataHeap *) vpdhp)->off_heap);
+ erts_free(ERTS_ALC_T_PORT_DATA_HEAP, vpdhp);
+}
+
+static ERTS_INLINE void
+cleanup_old_port_data(erts_aint_t data)
+{
+ if ((data & 0x3) != 0) {
+ ASSERT(is_immed((Eterm) data));
+ }
+ else {
+#ifdef ERTS_SMP
+ ErtsPortDataHeap *pdhp = (ErtsPortDataHeap *) data;
+ size_t size;
+ ERTS_SMP_DATA_DEPENDENCY_READ_MEMORY_BARRIER;
+ size = sizeof(ErtsPortDataHeap) + pdhp->hsize*(sizeof(Eterm) - 1);
+ erts_schedule_thr_prgr_later_cleanup_op(free_port_data_heap,
+ (void *) pdhp,
+ &pdhp->later_op,
+ size);
+#else
+ free_port_data_heap((void *) data);
+#endif
+ }
+}
+
+void
+erts_init_port_data(Port *prt)
+{
+ erts_smp_atomic_init_nob(&prt->data, (erts_aint_t) am_undefined);
+}
+
+void
+erts_cleanup_port_data(Port *prt)
+{
+ ASSERT(erts_atomic32_read_nob(&prt->state) & ERTS_PORT_SFLGS_INVALID_LOOKUP);
+ cleanup_old_port_data(erts_smp_atomic_read_nob(&prt->data));
+ erts_smp_atomic_set_nob(&prt->data, (erts_aint_t) THE_NON_VALUE);
+}
+
+Uint
+erts_port_data_size(Port *prt)
+{
+ erts_aint_t data = erts_smp_atomic_read_ddrb(&prt->data);
+
+ if ((data & 0x3) != 0) {
+ ASSERT(is_immed((Eterm) (UWord) data));
+ return (Uint) 0;
+ }
+ else {
+ ErtsPortDataHeap *pdhp = (ErtsPortDataHeap *) data;
+ return (Uint) sizeof(ErtsPortDataHeap) + pdhp->hsize*(sizeof(Eterm)-1);
+ }
+}
+
+ErlOffHeap *
+erts_port_data_offheap(Port *prt)
+{
+ erts_aint_t data = erts_smp_atomic_read_ddrb(&prt->data);
+
+ if ((data & 0x3) != 0) {
+ ASSERT(is_immed((Eterm) (UWord) data));
+ return NULL;
+ }
+ else {
+ ErtsPortDataHeap *pdhp = (ErtsPortDataHeap *) data;
+ return &pdhp->off_heap;
+ }
+}
+
+BIF_RETTYPE port_set_data_2(BIF_ALIST_2)
+{
+ /*
+ * This is not a signal. See comment above.
+ */
+ erts_aint_t data;
Port* prt;
prt = lookup_port(BIF_P, BIF_ARG_1);
if (!prt)
- BIF_RET(am_badarg);
+ BIF_ERROR(BIF_P, BADARG);
- switch (erts_port_set_data(BIF_P, prt, BIF_ARG_2, &ref)) {
- case ERTS_PORT_OP_CALLER_EXIT:
- case ERTS_PORT_OP_BADARG:
- case ERTS_PORT_OP_DROPPED:
- BIF_RET(am_badarg);
- case ERTS_PORT_OP_SCHEDULED:
- ASSERT(is_internal_ref(ref));
- BIF_RET(ref);
- case ERTS_PORT_OP_DONE:
- BIF_RET(am_true);
- default:
- ERTS_INTERNAL_ERROR("Unexpected erts_port_set_data() result");
- BIF_RET(am_internal_error);
+ if (is_immed(BIF_ARG_2)) {
+ data = (erts_aint_t) BIF_ARG_2;
+ ASSERT((data & 0x3) != 0);
}
+ else {
+ ErtsPortDataHeap *pdhp;
+ Uint hsize;
+ Eterm *hp;
+
+ hsize = size_object(BIF_ARG_2);
+ pdhp = erts_alloc(ERTS_ALC_T_PORT_DATA_HEAP,
+ sizeof(ErtsPortDataHeap) + hsize*(sizeof(Eterm)-1));
+ hp = &pdhp->heap[0];
+ pdhp->off_heap.first = NULL;
+ pdhp->off_heap.overhead = 0;
+ pdhp->data = copy_struct(BIF_ARG_2, hsize, &hp, &pdhp->off_heap);
+ data = (erts_aint_t) pdhp;
+ ASSERT((data & 0x3) == 0);
+ }
+
+ data = erts_smp_atomic_xchg_wb(&prt->data, data);
+
+ cleanup_old_port_data(data);
+
+ BIF_RET(am_true);
}
-BIF_RETTYPE erts_internal_port_get_data_1(BIF_ALIST_1)
+BIF_RETTYPE port_get_data_1(BIF_ALIST_1)
{
- Eterm retval;
+ /*
+ * This is not a signal. See comment above.
+ */
+ Eterm res;
+ erts_aint_t data;
Port* prt;
prt = lookup_port(BIF_P, BIF_ARG_1);
if (!prt)
- BIF_RET(am_badarg);
+ BIF_ERROR(BIF_P, BADARG);
- switch (erts_port_get_data(BIF_P, prt, &retval)) {
- case ERTS_PORT_OP_CALLER_EXIT:
- case ERTS_PORT_OP_BADARG:
- case ERTS_PORT_OP_DROPPED:
- BIF_RET(am_badarg);
- case ERTS_PORT_OP_SCHEDULED:
- ASSERT(is_internal_ref(retval));
- BIF_RET(retval);
- case ERTS_PORT_OP_DONE:
- ASSERT(is_not_internal_ref(retval));
- BIF_RET(retval);
- default:
- ERTS_INTERNAL_ERROR("Unexpected erts_port_get_data() result");
- BIF_RET(am_internal_error);
+ data = erts_smp_atomic_read_ddrb(&prt->data);
+
+ if ((data & 0x3) != 0) {
+ res = (Eterm) (UWord) data;
+ ASSERT(is_immed(res));
+ }
+ else {
+ ErtsPortDataHeap *pdhp = (ErtsPortDataHeap *) data;
+ Eterm *hp = HAlloc(BIF_P, pdhp->hsize);
+ res = copy_struct(pdhp->data, pdhp->hsize, &hp, &MSO(BIF_P));
}
+
+ BIF_RET(res);
}
/*
diff --git a/erts/emulator/beam/erl_bif_trace.c b/erts/emulator/beam/erl_bif_trace.c
index 41c98bbffb..559cb3efa1 100644
--- a/erts/emulator/beam/erl_bif_trace.c
+++ b/erts/emulator/beam/erl_bif_trace.c
@@ -1224,9 +1224,7 @@ trace_info_func(Process* p, Eterm func_spec, Eterm key)
match_spec_meta = NIL;
}
if (r & FUNC_TRACE_COUNT_TRACE) {
- c = count < 0 ?
- erts_make_integer(-count-1, p) :
- erts_make_integer(count, p);
+ c = erts_make_integer(count, p);
}
if (r & FUNC_TRACE_TIME_TRACE) {
ct = call_time;
diff --git a/erts/emulator/beam/erl_instrument.c b/erts/emulator/beam/erl_instrument.c
index b5b245288b..1aea3f65bc 100644
--- a/erts/emulator/beam/erl_instrument.c
+++ b/erts/emulator/beam/erl_instrument.c
@@ -271,6 +271,18 @@ stat_upd_realloc(ErtsAlcType_t n, Uint size, Uint old_size)
* stat instrumentation callback functions
*/
+static void stat_pre_lock(void)
+{
+ erts_mtx_lock(&instr_mutex);
+}
+
+static void stat_pre_unlock(void)
+{
+ erts_mtx_unlock(&instr_mutex);
+}
+
+static ErtsAllocatorWrapper_t instr_wrapper;
+
static void *
stat_alloc(ErtsAlcType_t n, void *extra, Uint size)
{
@@ -278,7 +290,9 @@ stat_alloc(ErtsAlcType_t n, void *extra, Uint size)
Uint ssize;
void *res;
- erts_mtx_lock(&instr_mutex);
+ if (!erts_is_allctr_wrapper_prelocked()) {
+ erts_mtx_lock(&instr_mutex);
+ }
ssize = size + STAT_BLOCK_HEADER_SIZE;
res = (*real_af->alloc)(n, real_af->extra, ssize);
@@ -293,7 +307,9 @@ stat_alloc(ErtsAlcType_t n, void *extra, Uint size)
res = (void *) ((StatBlock_t *) res)->mem;
}
- erts_mtx_unlock(&instr_mutex);
+ if (!erts_is_allctr_wrapper_prelocked()) {
+ erts_mtx_unlock(&instr_mutex);
+ }
return res;
}
@@ -307,7 +323,9 @@ stat_realloc(ErtsAlcType_t n, void *extra, void *ptr, Uint size)
void *sptr;
void *res;
- erts_mtx_lock(&instr_mutex);
+ if (!erts_is_allctr_wrapper_prelocked()) {
+ erts_mtx_lock(&instr_mutex);
+ }
if (ptr) {
sptr = (void *) (((char *) ptr) - STAT_BLOCK_HEADER_SIZE);
@@ -329,7 +347,9 @@ stat_realloc(ErtsAlcType_t n, void *extra, void *ptr, Uint size)
res = (void *) ((StatBlock_t *) res)->mem;
}
- erts_mtx_unlock(&instr_mutex);
+ if (!erts_is_allctr_wrapper_prelocked()) {
+ erts_mtx_unlock(&instr_mutex);
+ }
return res;
}
@@ -340,7 +360,9 @@ stat_free(ErtsAlcType_t n, void *extra, void *ptr)
ErtsAllocatorFunctions_t *real_af = (ErtsAllocatorFunctions_t *) extra;
void *sptr;
- erts_mtx_lock(&instr_mutex);
+ if (!erts_is_allctr_wrapper_prelocked()) {
+ erts_mtx_lock(&instr_mutex);
+ }
if (ptr) {
sptr = (void *) (((char *) ptr) - STAT_BLOCK_HEADER_SIZE);
@@ -352,7 +374,9 @@ stat_free(ErtsAlcType_t n, void *extra, void *ptr)
(*real_af->free)(n, real_af->extra, sptr);
- erts_mtx_unlock(&instr_mutex);
+ if (!erts_is_allctr_wrapper_prelocked()) {
+ erts_mtx_unlock(&instr_mutex);
+ }
}
@@ -360,6 +384,18 @@ stat_free(ErtsAlcType_t n, void *extra, void *ptr)
* map stat instrumentation callback functions
*/
+static void map_stat_pre_lock(void)
+{
+ erts_mtx_lock(&instr_x_mutex);
+ erts_mtx_lock(&instr_mutex);
+}
+
+static void map_stat_pre_unlock(void)
+{
+ erts_mtx_unlock(&instr_mutex);
+ erts_mtx_unlock(&instr_x_mutex);
+}
+
static void *
map_stat_alloc(ErtsAlcType_t n, void *extra, Uint size)
{
@@ -367,7 +403,9 @@ map_stat_alloc(ErtsAlcType_t n, void *extra, Uint size)
Uint msize;
void *res;
- erts_mtx_lock(&instr_mutex);
+ if (!erts_is_allctr_wrapper_prelocked()) {
+ erts_mtx_lock(&instr_mutex);
+ }
msize = size + MAP_STAT_BLOCK_HEADER_SIZE;
res = (*real_af->alloc)(n, real_af->extra, msize);
@@ -388,7 +426,9 @@ map_stat_alloc(ErtsAlcType_t n, void *extra, Uint size)
res = (void *) mb->mem;
}
- erts_mtx_unlock(&instr_mutex);
+ if (!erts_is_allctr_wrapper_prelocked()) {
+ erts_mtx_unlock(&instr_mutex);
+ }
return res;
}
@@ -402,8 +442,10 @@ map_stat_realloc(ErtsAlcType_t n, void *extra, void *ptr, Uint size)
void *mptr;
void *res;
- erts_mtx_lock(&instr_x_mutex);
- erts_mtx_lock(&instr_mutex);
+ if (!erts_is_allctr_wrapper_prelocked()) {
+ erts_mtx_lock(&instr_x_mutex);
+ erts_mtx_lock(&instr_mutex);
+ }
if (ptr) {
mptr = (void *) (((char *) ptr) - MAP_STAT_BLOCK_HEADER_SIZE);
@@ -449,9 +491,10 @@ map_stat_realloc(ErtsAlcType_t n, void *extra, void *ptr, Uint size)
res = (void *) mb->mem;
}
-
- erts_mtx_unlock(&instr_mutex);
- erts_mtx_unlock(&instr_x_mutex);
+ if (!erts_is_allctr_wrapper_prelocked()) {
+ erts_mtx_unlock(&instr_mutex);
+ erts_mtx_unlock(&instr_x_mutex);
+ }
return res;
}
@@ -462,8 +505,10 @@ map_stat_free(ErtsAlcType_t n, void *extra, void *ptr)
ErtsAllocatorFunctions_t *real_af = (ErtsAllocatorFunctions_t *) extra;
void *mptr;
- erts_mtx_lock(&instr_x_mutex);
- erts_mtx_lock(&instr_mutex);
+ if (!erts_is_allctr_wrapper_prelocked()) {
+ erts_mtx_lock(&instr_x_mutex);
+ erts_mtx_lock(&instr_mutex);
+ }
if (ptr) {
MapStatBlock_t *mb;
@@ -486,8 +531,10 @@ map_stat_free(ErtsAlcType_t n, void *extra, void *ptr)
(*real_af->free)(n, real_af->extra, mptr);
- erts_mtx_unlock(&instr_mutex);
- erts_mtx_unlock(&instr_x_mutex);
+ if (!erts_is_allctr_wrapper_prelocked()) {
+ erts_mtx_unlock(&instr_mutex);
+ erts_mtx_unlock(&instr_x_mutex);
+ }
}
@@ -496,8 +543,10 @@ static void dump_memory_map_to_stream(FILE *fp)
ErtsAlcType_t n;
MapStatBlock_t *bp;
int lock = !ERTS_IS_CRASH_DUMPING;
- if (lock)
+ if (lock) {
+ ASSERT(!erts_is_allctr_wrapper_prelocked());
erts_mtx_lock(&instr_mutex);
+ }
/* Write header */
@@ -1155,6 +1204,7 @@ erts_instr_get_type_info(Process *proc)
Uint
erts_instr_init(int stat, int map_stat)
{
+ Uint extra_sz;
int i;
am_tot = NULL;
@@ -1208,7 +1258,9 @@ erts_instr_init(int stat, int map_stat)
erts_allctrs[i].free = map_stat_free;
erts_allctrs[i].extra = (void *) &real_allctrs[i];
}
- return MAP_STAT_BLOCK_HEADER_SIZE;
+ instr_wrapper.lock = map_stat_pre_lock;
+ instr_wrapper.unlock = map_stat_pre_unlock;
+ extra_sz = MAP_STAT_BLOCK_HEADER_SIZE;
}
else {
erts_instr_stat = 1;
@@ -1220,8 +1272,11 @@ erts_instr_init(int stat, int map_stat)
erts_allctrs[i].free = stat_free;
erts_allctrs[i].extra = (void *) &real_allctrs[i];
}
- return STAT_BLOCK_HEADER_SIZE;
+ instr_wrapper.lock = stat_pre_lock;
+ instr_wrapper.unlock = stat_pre_unlock;
+ extra_sz = STAT_BLOCK_HEADER_SIZE;
}
-
+ erts_allctr_wrapper_prelock_init(&instr_wrapper);
+ return extra_sz;
}
diff --git a/erts/emulator/beam/erl_lock_check.c b/erts/emulator/beam/erl_lock_check.c
index 69bb4be717..a1d270adba 100644
--- a/erts/emulator/beam/erl_lock_check.c
+++ b/erts/emulator/beam/erl_lock_check.c
@@ -143,6 +143,8 @@ static erts_lc_lock_order_t erts_lock_order[] = {
{ "ptimer_pre_alloc_lock", "address", },
{ "btm_pre_alloc_lock", NULL, },
{ "dist_entry_out_queue", "address" },
+ { "port_sched_lock", "port_id" },
+ { "port_table", NULL },
#endif
{ "mtrace_op", NULL },
{ "instr_x", NULL },
@@ -154,10 +156,8 @@ static erts_lc_lock_order_t erts_lock_order[] = {
{ "pmmap", NULL },
#endif
#ifdef ERTS_SMP
- { "port_sched_lock", "port_id" },
{ "port_task_pre_alloc_lock", "address" },
{ "proclist_pre_alloc_lock", "address" },
- { "port_table", NULL },
{ "xports_list_pre_alloc_lock", "address" },
{ "inet_buffer_stack_lock", NULL },
{ "gc_info", NULL },
diff --git a/erts/emulator/beam/erl_monitors.c b/erts/emulator/beam/erl_monitors.c
index 70e592cc5f..244a2b26db 100644
--- a/erts/emulator/beam/erl_monitors.c
+++ b/erts/emulator/beam/erl_monitors.c
@@ -1024,3 +1024,23 @@ Eterm erts_debug_dump_links_1(BIF_ALIST_1)
}
}
}
+
+void erts_one_link_size(ErtsLink *lnk, void *vpu)
+{
+ Uint *pu = vpu;
+ *pu += ERTS_LINK_SIZE*sizeof(Uint);
+ if(!IS_CONST(lnk->pid))
+ *pu += NC_HEAP_SIZE(lnk->pid)*sizeof(Uint);
+ if (lnk->type != LINK_NODE && ERTS_LINK_ROOT(lnk) != NULL) {
+ erts_doforall_links(ERTS_LINK_ROOT(lnk),&erts_one_link_size,vpu);
+ }
+}
+void erts_one_mon_size(ErtsMonitor *mon, void *vpu)
+{
+ Uint *pu = vpu;
+ *pu += ERTS_MONITOR_SIZE*sizeof(Uint);
+ if(!IS_CONST(mon->pid))
+ *pu += NC_HEAP_SIZE(mon->pid)*sizeof(Uint);
+ if(!IS_CONST(mon->ref))
+ *pu += NC_HEAP_SIZE(mon->ref)*sizeof(Uint);
+}
diff --git a/erts/emulator/beam/erl_monitors.h b/erts/emulator/beam/erl_monitors.h
index 6a360a2336..fb11dbbd22 100644
--- a/erts/emulator/beam/erl_monitors.h
+++ b/erts/emulator/beam/erl_monitors.h
@@ -170,6 +170,8 @@ ErtsSuspendMonitor *erts_lookup_suspend_monitor(ErtsSuspendMonitor *root,
Eterm pid);
void erts_delete_suspend_monitor(ErtsSuspendMonitor **root, Eterm pid);
void erts_init_monitors(void);
+void erts_one_link_size(ErtsLink *lnk, void *vpu);
+void erts_one_mon_size(ErtsMonitor *mon, void *vpu);
#define erts_doforall_monitors erts_sweep_monitors
#define erts_doforall_links erts_sweep_links
diff --git a/erts/emulator/beam/erl_mtrace.c b/erts/emulator/beam/erl_mtrace.c
index e538ba30c2..c8bb126687 100644
--- a/erts/emulator/beam/erl_mtrace.c
+++ b/erts/emulator/beam/erl_mtrace.c
@@ -222,6 +222,8 @@ static byte *tracep;
static byte *endp;
static SysTimeval last_tv;
+static ErtsAllocatorWrapper_t mtrace_wrapper;
+
#if ERTS_MTRACE_SEGMENT_ID >= ERTS_ALC_A_MIN || ERTS_MTRACE_SEGMENT_ID < 0
#error ERTS_MTRACE_SEGMENT_ID >= ERTS_ALC_A_MIN || ERTS_MTRACE_SEGMENT_ID < 0
#endif
@@ -555,6 +557,8 @@ write_trace_header(char *nodename, char *pid, char *hostname)
return 1;
}
+static void mtrace_pre_lock(void);
+static void mtrace_pre_unlock(void);
static void *mtrace_alloc(ErtsAlcType_t, void *, Uint);
static void *mtrace_realloc(ErtsAlcType_t, void *, void *, Uint);
static void mtrace_free(ErtsAlcType_t, void *, void *);
@@ -635,12 +639,16 @@ erts_mtrace_install_wrapper_functions(void)
erts_allctrs[i].free = mtrace_free;
erts_allctrs[i].extra = (void *) &real_allctrs[i];
}
+ mtrace_wrapper.lock = mtrace_pre_lock;
+ mtrace_wrapper.unlock = mtrace_pre_unlock;
+ erts_allctr_wrapper_prelock_init(&mtrace_wrapper);
}
}
void
erts_mtrace_stop(void)
{
+ ASSERT(!erts_is_allctr_wrapper_prelocked());
erts_mtx_lock(&mtrace_op_mutex);
erts_mtx_lock(&mtrace_buf_mutex);
if (erts_mtrace_enabled) {
@@ -677,6 +685,7 @@ erts_mtrace_stop(void)
void
erts_mtrace_exit(Uint32 exit_value)
{
+ ASSERT(!erts_is_allctr_wrapper_prelocked());
erts_mtx_lock(&mtrace_op_mutex);
erts_mtx_lock(&mtrace_buf_mutex);
if (erts_mtrace_enabled) {
@@ -935,18 +944,33 @@ write_free_entry(byte tag,
erts_mtx_unlock(&mtrace_buf_mutex);
}
+static void mtrace_pre_lock(void)
+{
+ erts_mtx_lock(&mtrace_op_mutex);
+}
+
+static void mtrace_pre_unlock(void)
+{
+ erts_mtx_unlock(&mtrace_op_mutex);
+}
+
+
static void *
mtrace_alloc(ErtsAlcType_t n, void *extra, Uint size)
{
ErtsAllocatorFunctions_t *real_af = (ErtsAllocatorFunctions_t *) extra;
void *res;
- erts_mtx_lock(&mtrace_op_mutex);
+ if (!erts_is_allctr_wrapper_prelocked()) {
+ erts_mtx_lock(&mtrace_op_mutex);
+ }
res = (*real_af->alloc)(n, real_af->extra, size);
write_alloc_entry(ERTS_MT_ALLOC_BDY_TAG, res, n, 0, size);
- erts_mtx_unlock(&mtrace_op_mutex);
+ if (!erts_is_allctr_wrapper_prelocked()) {
+ erts_mtx_unlock(&mtrace_op_mutex);
+ }
return res;
}
@@ -957,12 +981,16 @@ mtrace_realloc(ErtsAlcType_t n, void *extra, void *ptr, Uint size)
ErtsAllocatorFunctions_t *real_af = (ErtsAllocatorFunctions_t *) extra;
void *res;
- erts_mtx_lock(&mtrace_op_mutex);
+ if (!erts_is_allctr_wrapper_prelocked()) {
+ erts_mtx_lock(&mtrace_op_mutex);
+ }
res = (*real_af->realloc)(n, real_af->extra, ptr, size);
write_realloc_entry(ERTS_MT_REALLOC_BDY_TAG, res, n, 0, ptr, size);
- erts_mtx_unlock(&mtrace_op_mutex);
+ if (!erts_is_allctr_wrapper_prelocked()) {
+ erts_mtx_unlock(&mtrace_op_mutex);
+ }
return res;
@@ -973,10 +1001,14 @@ mtrace_free(ErtsAlcType_t n, void *extra, void *ptr)
{
ErtsAllocatorFunctions_t *real_af = (ErtsAllocatorFunctions_t *) extra;
- erts_mtx_lock(&mtrace_op_mutex);
+ if (!erts_is_allctr_wrapper_prelocked()) {
+ erts_mtx_lock(&mtrace_op_mutex);
+ }
(*real_af->free)(n, real_af->extra, ptr);
- write_free_entry(ERTS_MT_FREE_BDY_TAG, n, 0, ptr);
+ if (!erts_is_allctr_wrapper_prelocked()) {
+ write_free_entry(ERTS_MT_FREE_BDY_TAG, n, 0, ptr);
+ }
erts_mtx_unlock(&mtrace_op_mutex);
}
diff --git a/erts/emulator/beam/erl_node_tables.c b/erts/emulator/beam/erl_node_tables.c
index ebfba065d1..e688e55c88 100644
--- a/erts/emulator/beam/erl_node_tables.c
+++ b/erts/emulator/beam/erl_node_tables.c
@@ -1371,6 +1371,7 @@ setup_reference_table(void)
/* Insert all ports */
max = erts_ptab_max(&erts_port);
for (i = 0; i < max; i++) {
+ ErlOffHeap *ohp;
erts_aint32_t state;
Port *prt;
@@ -1389,8 +1390,9 @@ setup_reference_table(void)
if (ERTS_P_MONITORS(prt))
insert_monitors(ERTS_P_MONITORS(prt), prt->common.id);
/* Insert port data */
- for(hfp = prt->bp; hfp; hfp = hfp->next)
- insert_offheap(&(hfp->off_heap), HEAP_REF, prt->common.id);
+ ohp = erts_port_data_offheap(prt);
+ if (ohp)
+ insert_offheap(ohp, HEAP_REF, prt->common.id);
/* Insert controller */
if (prt->dist_entry)
insert_dist_entry(prt->dist_entry,
diff --git a/erts/emulator/beam/erl_port.h b/erts/emulator/beam/erl_port.h
index 377aa72ed5..ad3f104a68 100644
--- a/erts/emulator/beam/erl_port.h
+++ b/erts/emulator/beam/erl_port.h
@@ -167,8 +167,7 @@ struct _erl_drv_port {
#endif
erts_atomic_t connected; /* A connected process */
Eterm caller; /* Current caller. */
- Eterm data; /* Data associated with port. */
- ErlHeapFragment* bp; /* Heap fragment holding data (NULL if imm data). */
+ erts_smp_atomic_t data; /* Data associated with port. */
Uint bytes_in; /* Number of bytes read */
Uint bytes_out; /* Number of bytes written */
@@ -189,6 +188,12 @@ struct _erl_drv_port {
int reds; /* Only used while executing driver callbacks */
};
+
+void erts_init_port_data(Port *);
+void erts_cleanup_port_data(Port *);
+Uint erts_port_data_size(Port *);
+ErlOffHeap *erts_port_data_offheap(Port *);
+
#define ERTS_PORT_GET_CONNECTED(PRT) \
((Eterm) erts_atomic_read_nob(&(PRT)->connected))
#define ERTS_PORT_SET_CONNECTED(PRT, PID) \
@@ -326,8 +331,6 @@ extern erts_smp_atomic_t erts_bytes_in; /* no bytes sent into the system */
#define ERTS_PORT_REDS_CONTROL (CONTEXT_REDS/100)
#define ERTS_PORT_REDS_CALL (CONTEXT_REDS/50)
#define ERTS_PORT_REDS_INFO (CONTEXT_REDS/100)
-#define ERTS_PORT_REDS_SET_DATA (CONTEXT_REDS/100)
-#define ERTS_PORT_REDS_GET_DATA (CONTEXT_REDS/100)
#define ERTS_PORT_REDS_TERMINATE (CONTEXT_REDS/50)
void print_port_info(Port *, int, void *);
@@ -794,8 +797,6 @@ struct binary;
#define ERTS_P2P_SIG_TYPE_INFO 7
#define ERTS_P2P_SIG_TYPE_LINK 8
#define ERTS_P2P_SIG_TYPE_UNLINK 9
-#define ERTS_P2P_SIG_TYPE_SET_DATA 10
-#define ERTS_P2P_SIG_TYPE_GET_DATA 11
#define ERTS_P2P_SIG_TYPE_BITS 4
#define ERTS_P2P_SIG_TYPE_MASK \
@@ -810,6 +811,7 @@ struct binary;
#define ERTS_P2P_SIG_DATA_FLG_BAD_OUTPUT ERTS_P2P_SIG_DATA_FLG(4)
#define ERTS_P2P_SIG_DATA_FLG_BROKEN_LINK ERTS_P2P_SIG_DATA_FLG(5)
#define ERTS_P2P_SIG_DATA_FLG_SCHED ERTS_P2P_SIG_DATA_FLG(6)
+#define ERTS_P2P_SIG_DATA_FLG_ASYNC ERTS_P2P_SIG_DATA_FLG(7)
struct ErtsProc2PortSigData_ {
int flags;
@@ -856,10 +858,6 @@ struct ErtsProc2PortSigData_ {
struct {
Eterm from;
} unlink;
- struct {
- ErlHeapFragment *bp;
- Eterm data;
- } set_data;
} u;
} ;
@@ -919,6 +917,7 @@ erts_schedule_proc2port_signal(Process *,
Eterm *,
ErtsProc2PortSigData *,
int,
+ ErtsPortTaskHandle *,
ErtsProc2PortSigCallback);
int erts_deliver_port_exit(Port *, Eterm, Eterm, int);
@@ -932,6 +931,7 @@ int erts_deliver_port_exit(Port *, Eterm, Eterm, int);
#define ERTS_PORT_SIG_FLG_BROKEN_LINK ERTS_P2P_SIG_DATA_FLG_BROKEN_LINK
#define ERTS_PORT_SIG_FLG_BAD_OUTPUT ERTS_P2P_SIG_DATA_FLG_BAD_OUTPUT
#define ERTS_PORT_SIG_FLG_FORCE_SCHED ERTS_P2P_SIG_DATA_FLG_SCHED
+#define ERTS_PORT_SIG_FLG_ASYNC ERTS_P2P_SIG_DATA_FLG_ASYNC
/* ERTS_PORT_SIG_FLG_FORCE_IMM_CALL only when crash dumping... */
#define ERTS_PORT_SIG_FLG_FORCE_IMM_CALL ERTS_P2P_SIG_DATA_FLG_BAD_OUTPUT
@@ -953,7 +953,5 @@ ErtsPortOpResult erts_port_unlink(Process *, Port *, Eterm, Eterm *);
ErtsPortOpResult erts_port_control(Process *, Port *, unsigned int, Eterm, Eterm *);
ErtsPortOpResult erts_port_call(Process *, Port *, unsigned int, Eterm, Eterm *);
ErtsPortOpResult erts_port_info(Process *, Port *, Eterm, Eterm *);
-ErtsPortOpResult erts_port_set_data(Process *, Port *, Eterm, Eterm *);
-ErtsPortOpResult erts_port_get_data(Process *, Port *, Eterm *);
#endif
diff --git a/erts/emulator/beam/erl_port_task.c b/erts/emulator/beam/erl_port_task.c
index 0ed08bee01..53cb01a8c6 100644
--- a/erts/emulator/beam/erl_port_task.c
+++ b/erts/emulator/beam/erl_port_task.c
@@ -552,6 +552,19 @@ set_handle(ErtsPortTask *ptp, ErtsPortTaskHandle *pthp)
}
}
+static ERTS_INLINE void
+set_tmp_handle(ErtsPortTask *ptp, ErtsPortTaskHandle *pthp)
+{
+ ptp->u.alive.handle = NULL;
+ if (pthp) {
+ /*
+ * IMPORTANT! Task either need to be aborted, or task handle
+ * need to be detached before thread progress has been made.
+ */
+ erts_smp_atomic_set_relb(pthp, (erts_aint_t) ptp);
+ }
+}
+
/*
* Busy port queue management
@@ -1182,6 +1195,13 @@ erl_drv_consume_timeslice(ErlDrvPort dprt, int percent)
return 1;
}
+void
+erts_port_task_tmp_handle_detach(ErtsPortTaskHandle *pthp)
+{
+ ERTS_SMP_LC_ASSERT(erts_thr_progress_lc_is_delaying());
+ reset_port_task_handle(pthp);
+}
+
/*
* Abort a scheduled task.
*/
@@ -1206,7 +1226,7 @@ erts_port_task_abort(ErtsPortTaskHandle *pthp)
ERTS_SMP_READ_MEMORY_BARRIER;
old_state = erts_smp_atomic32_read_nob(&ptp->state);
if (old_state == ERTS_PT_STATE_SCHEDULED) {
- ASSERT(saved_pthp == pthp);
+ ASSERT(!saved_pthp || saved_pthp == pthp);
}
#endif
@@ -1227,9 +1247,6 @@ erts_port_task_abort(ErtsPortTaskHandle *pthp)
&erts_port_task_outstanding_io_tasks) > 0);
erts_smp_atomic_dec_relb(&erts_port_task_outstanding_io_tasks);
break;
- case ERTS_PORT_TASK_PROC_SIG:
- ERTS_INTERNAL_ERROR("Aborted process to port signal");
- break;
default:
break;
}
@@ -1404,7 +1421,6 @@ erts_port_task_schedule(Eterm id,
}
case ERTS_PORT_TASK_PROC_SIG: {
va_list argp;
- ASSERT(!pthp);
va_start(argp, type);
sigdp = va_arg(argp, ErtsProc2PortSigData *);
ptp = p2p_sig_data_to_task(sigdp);
@@ -1412,7 +1428,7 @@ erts_port_task_schedule(Eterm id,
ptp->u.alive.flags |= va_arg(argp, int);
va_end(argp);
if (!(ptp->u.alive.flags & ERTS_PT_FLG_NOSUSPEND))
- set_handle(ptp, pthp);
+ set_tmp_handle(ptp, pthp);
else {
ns_pthlp = erts_alloc(ERTS_ALC_T_PT_HNDL_LIST,
sizeof(ErtsPortTaskHandleList));
diff --git a/erts/emulator/beam/erl_port_task.h b/erts/emulator/beam/erl_port_task.h
index ae6cd69ae2..d35a15c27b 100644
--- a/erts/emulator/beam/erl_port_task.h
+++ b/erts/emulator/beam/erl_port_task.h
@@ -243,7 +243,9 @@ int erts_port_task_execute(ErtsRunQueue *, Port **);
void erts_port_task_init(void);
#endif
+void erts_port_task_tmp_handle_detach(ErtsPortTaskHandle *);
int erts_port_task_abort(ErtsPortTaskHandle *);
+
void erts_port_task_abort_nosuspend_tasks(Port *);
int erts_port_task_schedule(Eterm,
diff --git a/erts/emulator/beam/erl_process.c b/erts/emulator/beam/erl_process.c
index 5d9c5af55f..7415a5721f 100644
--- a/erts/emulator/beam/erl_process.c
+++ b/erts/emulator/beam/erl_process.c
@@ -4670,6 +4670,8 @@ erts_init_scheduling(int no_schedulers, int no_schedulers_online)
esdp->reductions = 0;
init_sched_wall_time(&esdp->sched_wall_time);
+
+ erts_port_task_handle_init(&esdp->nosuspend_port_task_handle);
}
init_misc_aux_work();
diff --git a/erts/emulator/beam/erl_process.h b/erts/emulator/beam/erl_process.h
index 3d3579fa7e..5a1f6bbe8d 100644
--- a/erts/emulator/beam/erl_process.h
+++ b/erts/emulator/beam/erl_process.h
@@ -507,6 +507,7 @@ struct ErtsSchedulerData_ {
Uint64 reductions;
ErtsSchedWallTime sched_wall_time;
+ ErtsPortTaskHandle nosuspend_port_task_handle;
#ifdef ERTS_DO_VERIFY_UNUSED_TEMP_ALLOC
erts_alloc_verify_func_t verify_unused_temp_alloc;
@@ -1421,6 +1422,8 @@ Eterm erts_debug_reader_groups_map(Process *c_p, int groups);
Uint erts_debug_nbalance(void);
int erts_debug_wait_deallocations(Process *c_p);
+Uint erts_process_memory(Process *c_p);
+
#ifdef ERTS_SMP
# define ERTS_GET_SCHEDULER_DATA_FROM_PROC(PROC) ((PROC)->scheduler_data)
# define ERTS_PROC_GET_SCHDATA(PROC) ((PROC)->scheduler_data)
diff --git a/erts/emulator/beam/erl_process_dump.c b/erts/emulator/beam/erl_process_dump.c
index a93229c473..6cd0d23b97 100644
--- a/erts/emulator/beam/erl_process_dump.c
+++ b/erts/emulator/beam/erl_process_dump.c
@@ -76,6 +76,43 @@ erts_deep_process_dump(int to, void *to_arg)
dump_binaries(to, to_arg, all_binaries);
}
+Uint erts_process_memory(Process *p) {
+ ErlMessage *mp;
+ Uint size = 0;
+ struct saved_calls *scb;
+ size += sizeof(Process);
+
+ ERTS_SMP_MSGQ_MV_INQ2PRIVQ(p);
+
+ erts_doforall_links(ERTS_P_LINKS(p), &erts_one_link_size, &size);
+ erts_doforall_monitors(ERTS_P_MONITORS(p), &erts_one_mon_size, &size);
+ size += (p->heap_sz + p->mbuf_sz) * sizeof(Eterm);
+ if (p->old_hend && p->old_heap)
+ size += (p->old_hend - p->old_heap) * sizeof(Eterm);
+
+ size += p->msg.len * sizeof(ErlMessage);
+
+ for (mp = p->msg.first; mp; mp = mp->next)
+ if (mp->data.attached)
+ size += erts_msg_attached_data_size(mp)*sizeof(Eterm);
+
+ if (p->arg_reg != p->def_arg_reg) {
+ size += p->arity * sizeof(p->arg_reg[0]);
+ }
+
+ if (p->psd)
+ size += sizeof(ErtsPSD);
+
+ scb = ERTS_PROC_GET_SAVED_CALLS_BUF(p);
+ if (scb) {
+ size += (sizeof(struct saved_calls)
+ + (scb->len-1) * sizeof(scb->ct[0]));
+ }
+
+ size += erts_dicts_mem_size(p);
+ return size;
+}
+
static void
dump_process_info(int to, void *to_arg, Process *p)
{
diff --git a/erts/emulator/beam/external.c b/erts/emulator/beam/external.c
index 5ce0d97c74..8420cfae24 100644
--- a/erts/emulator/beam/external.c
+++ b/erts/emulator/beam/external.c
@@ -3147,17 +3147,6 @@ encode_size_struct2(ErtsAtomCacheMap *acmp, Eterm obj, unsigned dflags)
return result;
}
-static int is_valid_utf8_atom(byte* bytes, Uint nbytes)
-{
- byte* err_pos;
- Uint num_chars;
-
- /*SVERK Do we really need to validate correct utf8? */
- return nbytes <= MAX_ATOM_SZ_LIMIT
- && erts_analyze_utf8(bytes, nbytes, &err_pos, &num_chars, NULL) == ERTS_UTF8_OK
- && num_chars <= MAX_ATOM_CHARACTERS;
-}
-
static Sint
decoded_size(byte *ep, byte* endp, int internal_tags)
{
@@ -3235,7 +3224,7 @@ decoded_size(byte *ep, byte* endp, int internal_tags)
CHKSIZE(2);
n = get_int16(ep);
ep += 2;
- if (!is_valid_utf8_atom(ep, n)) {
+ if (n > MAX_ATOM_SZ_LIMIT) {
return -1;
}
SKIP(n+atom_extra_skip);
@@ -3254,7 +3243,7 @@ decoded_size(byte *ep, byte* endp, int internal_tags)
CHKSIZE(1);
n = get_int8(ep);
ep++;
- if (!is_valid_utf8_atom(ep, n)) {
+ if (n > MAX_ATOM_SZ_LIMIT) {
return -1;
}
SKIP(n+atom_extra_skip);
diff --git a/erts/emulator/beam/io.c b/erts/emulator/beam/io.c
index 7cadd4aaad..b6b7b47bd6 100644
--- a/erts/emulator/beam/io.c
+++ b/erts/emulator/beam/io.c
@@ -364,9 +364,8 @@ static Port *create_port(char *name,
ERTS_P_LINKS(prt) = NULL;
ERTS_P_MONITORS(prt) = NULL;
prt->linebuf = NULL;
- prt->bp = NULL;
prt->suspended = NULL;
- prt->data = am_undefined;
+ erts_init_port_data(prt);
prt->port_data_lock = NULL;
prt->control_flags = 0;
prt->bytes_in = 0;
@@ -1442,6 +1441,7 @@ erts_schedule_proc2port_signal(Process *c_p,
Eterm *refp,
ErtsProc2PortSigData *sigdp,
int task_flags,
+ ErtsPortTaskHandle *pthp,
ErtsProc2PortSigCallback callback)
{
int sched_res;
@@ -1491,7 +1491,7 @@ erts_schedule_proc2port_signal(Process *c_p,
/* Schedule port close call for later execution... */
sched_res = erts_port_task_schedule(prt->common.id,
- NULL,
+ pthp,
ERTS_PORT_TASK_PROC_SIG,
sigdp,
callback,
@@ -1629,6 +1629,7 @@ bad_port_signal(Process *c_p,
refp,
sigdp,
0,
+ NULL,
port_badsig);
}
@@ -1838,8 +1839,11 @@ erts_port_output(Process *c_p,
ErlIOVec *evp = NULL;
char *buf = NULL;
int force_immediate_call = (flags & ERTS_PORT_SIG_FLG_FORCE_IMM_CALL);
+ int async_nosuspend;
+ ErtsPortTaskHandle *ns_pthp;
ASSERT((flags & ~(ERTS_PORT_SIG_FLG_BANG_OP
+ | ERTS_PORT_SIG_FLG_ASYNC
| ERTS_PORT_SIG_FLG_NOSUSPEND
| ERTS_PORT_SIG_FLG_FORCE
| ERTS_PORT_SIG_FLG_FORCE_IMM_CALL)) == 0);
@@ -1861,6 +1865,12 @@ erts_port_output(Process *c_p,
? ERTS_PORT_OP_DROPPED
: ERTS_PORT_OP_BUSY);
+ async_nosuspend = ((flags & (ERTS_PORT_SIG_FLG_ASYNC
+ | ERTS_PORT_SIG_FLG_NOSUSPEND
+ | ERTS_PORT_SIG_FLG_FORCE))
+ == (ERTS_PORT_SIG_FLG_ASYNC
+ | ERTS_PORT_SIG_FLG_NOSUSPEND));
+
try_call = (force_immediate_call /* crash dumping */
|| !(sched_flags & (invalid_flags
| ERTS_PTS_FLGS_FORCE_SCHEDULE_OP)));
@@ -1995,6 +2005,15 @@ erts_port_output(Process *c_p,
return ERTS_PORT_OP_DONE;
case ERTS_TRY_IMM_DRV_CALL_INVALID_SCHED_FLAGS:
sched_flags = try_call_state.sched_flags;
+ if (async_nosuspend
+ && (sched_flags & (busy_flgs|ERTS_PTS_FLG_EXIT))) {
+ driver_free_binary(cbin);
+ if (evp != &ev)
+ erts_free(ERTS_ALC_T_TMP, evp);
+ return ((sched_flags & ERTS_PTS_FLG_EXIT)
+ ? ERTS_PORT_OP_DROPPED
+ : ERTS_PORT_OP_BUSY);
+ }
case ERTS_TRY_IMM_DRV_CALL_BUSY_LOCK:
/* Schedule outputv() call instead... */
break;
@@ -2142,6 +2161,13 @@ erts_port_output(Process *c_p,
return ERTS_PORT_OP_DONE;
case ERTS_TRY_IMM_DRV_CALL_INVALID_SCHED_FLAGS:
sched_flags = try_call_state.sched_flags;
+ if (async_nosuspend
+ && (sched_flags & (busy_flgs|ERTS_PTS_FLG_EXIT))) {
+ erts_free(ERTS_ALC_T_TMP, buf);
+ return ((sched_flags & ERTS_PTS_FLG_EXIT)
+ ? ERTS_PORT_OP_DROPPED
+ : ERTS_PORT_OP_BUSY);
+ }
case ERTS_TRY_IMM_DRV_CALL_BUSY_LOCK:
/* Schedule outputv() call instead... */
break;
@@ -2163,20 +2189,33 @@ erts_port_output(Process *c_p,
task_flags = ERTS_PT_FLG_WAIT_BUSY;
sigdp->flags |= flags;
+ ns_pthp = NULL;
if (flags & (ERTS_P2P_SIG_DATA_FLG_FORCE|ERTS_P2P_SIG_DATA_FLG_NOSUSPEND)) {
task_flags = 0;
if (flags & ERTS_P2P_SIG_DATA_FLG_FORCE)
sigdp->flags &= ~ERTS_P2P_SIG_DATA_FLG_NOSUSPEND;
+ else if (async_nosuspend) {
+ ErtsSchedulerData *esdp = (c_p
+ ? ERTS_PROC_GET_SCHDATA(c_p)
+ : erts_get_scheduler_data());
+ ASSERT(esdp);
+ ns_pthp = &esdp->nosuspend_port_task_handle;
+ sigdp->flags &= ~ERTS_P2P_SIG_DATA_FLG_NOSUSPEND;
+ }
else if (flags & ERTS_P2P_SIG_DATA_FLG_NOSUSPEND)
task_flags = ERTS_PT_FLG_NOSUSPEND;
}
+ ASSERT(ns_pthp || !async_nosuspend);
+ ASSERT(async_nosuspend || !ns_pthp);
+
res = erts_schedule_proc2port_signal(c_p,
prt,
c_p ? c_p->common.id : ERTS_INVALID_PID,
refp,
sigdp,
task_flags,
+ ns_pthp,
port_sig_callback);
if (res != ERTS_PORT_OP_SCHEDULED) {
@@ -2187,9 +2226,23 @@ erts_port_output(Process *c_p,
return res;
}
- if (!(sched_flags & ERTS_PTS_FLG_EXIT) && (sched_flags & busy_flgs))
- return ERTS_PORT_OP_BUSY_SCHEDULED;
-
+ if (!(flags & ERTS_PORT_SIG_FLG_FORCE)) {
+ sched_flags = erts_smp_atomic32_read_acqb(&prt->sched.flags);
+ if (!(sched_flags & ERTS_PTS_FLG_BUSY_PORT)) {
+ if (async_nosuspend)
+ erts_port_task_tmp_handle_detach(ns_pthp);
+ }
+ else {
+ if (!async_nosuspend)
+ return ERTS_PORT_OP_BUSY_SCHEDULED;
+ else {
+ if (erts_port_task_abort(ns_pthp) == 0)
+ return ERTS_PORT_OP_BUSY;
+ else
+ erts_port_task_tmp_handle_detach(ns_pthp);
+ }
+ }
+ }
return res;
bad_value:
@@ -2285,6 +2338,7 @@ erts_port_exit(Process *c_p,
ErlHeapFragment *bp = NULL;
ASSERT((flags & ~(ERTS_PORT_SIG_FLG_BANG_OP
+ | ERTS_PORT_SIG_FLG_ASYNC
| ERTS_PORT_SIG_FLG_BROKEN_LINK
| ERTS_PORT_SIG_FLG_FORCE_SCHED)) == 0);
@@ -2345,6 +2399,7 @@ erts_port_exit(Process *c_p,
refp,
sigdp,
0,
+ NULL,
port_sig_exit);
if (res == ERTS_PORT_OP_DROPPED) {
@@ -2460,7 +2515,8 @@ erts_port_connect(Process *c_p,
!refp,
am_connect);
- ASSERT((flags & ~ERTS_PORT_SIG_FLG_BANG_OP) == 0);
+ ASSERT((flags & ~(ERTS_PORT_SIG_FLG_BANG_OP
+ | ERTS_PORT_SIG_FLG_ASYNC)) == 0);
if (is_not_internal_pid(connect))
connect_id = NIL; /* Fail in op (for signal order) */
@@ -2499,6 +2555,7 @@ erts_port_connect(Process *c_p,
refp,
sigdp,
0,
+ NULL,
port_sig_connect);
}
@@ -2555,6 +2612,7 @@ erts_port_unlink(Process *c_p, Port *prt, Eterm from, Eterm *refp)
refp,
sigdp,
0,
+ NULL,
port_sig_unlink);
}
@@ -2644,6 +2702,7 @@ erts_port_link(Process *c_p, Port *prt, Eterm to, Eterm *refp)
refp,
sigdp,
0,
+ NULL,
port_sig_link);
}
@@ -3371,11 +3430,8 @@ terminate_port(Port *prt)
erts_free(ERTS_ALC_T_LINEBUF, (void *) prt->linebuf);
prt->linebuf = NULL;
}
- if (prt->bp != NULL) {
- free_message_buffer(prt->bp);
- prt->bp = NULL;
- prt->data = am_undefined;
- }
+
+ erts_cleanup_port_data(prt);
if (prt->psd)
erts_free(ERTS_ALC_T_PRTSD, prt->psd);
@@ -3625,6 +3681,10 @@ erts_port_command(Process *c_p,
ASSERT(port);
flags |= ERTS_PORT_SIG_FLG_BANG_OP;
+ if (!erts_port_synchronous_ops) {
+ flags |= ERTS_PORT_SIG_FLG_ASYNC;
+ refp = NULL;
+ }
if (is_tuple_arity(command, 2)) {
Eterm cntd;
@@ -3632,21 +3692,14 @@ erts_port_command(Process *c_p,
cntd = tp[1];
if (is_internal_pid(cntd)) {
if (tp[2] == am_close) {
- if (!erts_port_synchronous_ops)
- refp = NULL;
flags &= ~ERTS_PORT_SIG_FLG_NOSUSPEND;
return erts_port_exit(c_p, flags, port, cntd, am_normal, refp);
} else if (is_tuple_arity(tp[2], 2)) {
tp = tuple_val(tp[2]);
if (tp[1] == am_command) {
- if (!(flags & ERTS_PORT_SIG_FLG_NOSUSPEND)
- && !erts_port_synchronous_ops)
- refp = NULL;
return erts_port_output(c_p, flags, port, cntd, tp[2], refp);
}
else if (tp[1] == am_connect) {
- if (!erts_port_synchronous_ops)
- refp = NULL;
flags &= ~ERTS_PORT_SIG_FLG_NOSUSPEND;
return erts_port_connect(c_p, flags, port, cntd, tp[2], refp);
}
@@ -3655,8 +3708,6 @@ erts_port_command(Process *c_p,
}
/* badsig */
- if (!erts_port_synchronous_ops)
- refp = NULL;
flags &= ~ERTS_PORT_SIG_FLG_NOSUSPEND;
return bad_port_signal(c_p, flags, port, c_p->common.id, refp, am_command);
}
@@ -4053,6 +4104,7 @@ erts_port_control(Process* c_p,
retvalp,
sigdp,
0,
+ NULL,
port_sig_control);
if (res != ERTS_PORT_OP_SCHEDULED) {
cleanup_scheduled_control(binp, bufp);
@@ -4147,7 +4199,7 @@ port_sig_call(Port *prt,
ErlOffHeap *ohp;
Process *rp;
ErtsProcLocks rp_locks = 0;
- Uint hsz;
+ Sint hsz;
rp = erts_proc_lookup_raw(sigdp->caller);
if (!rp)
@@ -4264,7 +4316,7 @@ erts_port_call(Process* c_p,
switch (try_call_res) {
case ERTS_TRY_IMM_DRV_CALL_OK: {
Eterm *hp, *hp_end;
- Uint hsz;
+ Sint hsz;
unsigned ret_flags = 0U;
Eterm term;
@@ -4333,6 +4385,7 @@ erts_port_call(Process* c_p,
retvalp,
sigdp,
0,
+ NULL,
port_sig_call);
if (res != ERTS_PORT_OP_SCHEDULED) {
cleanup_scheduled_call(bufp);
@@ -4499,228 +4552,10 @@ erts_port_info(Process* c_p,
retvalp,
sigdp,
0,
+ NULL,
port_sig_info);
}
-static int
-port_sig_set_data(Port *prt,
- erts_aint32_t state,
- int op,
- ErtsProc2PortSigData *sigdp)
-{
- ASSERT(sigdp->flags & ERTS_P2P_SIG_DATA_FLG_REPLY);
-
- if (op == ERTS_PROC2PORT_SIG_EXEC) {
- if (prt->bp)
- free_message_buffer(prt->bp);
- prt->bp = sigdp->u.set_data.bp;
- prt->data = sigdp->u.set_data.data;
- port_sched_op_reply(sigdp->caller, sigdp->ref, am_true);
- }
- else {
- if (sigdp->u.set_data.bp)
- free_message_buffer(sigdp->u.set_data.bp);
- port_sched_op_reply(sigdp->caller, sigdp->ref, am_badarg);
- }
- return ERTS_PORT_REDS_SET_DATA;
-}
-
-ErtsPortOpResult
-erts_port_set_data(Process* c_p,
- Port *prt,
- Eterm data,
- Eterm *refp)
-{
- ErtsPortOpResult res;
- Eterm set_data;
- ErlHeapFragment *bp;
- ErtsProc2PortSigData *sigdp;
- ErtsTryImmDrvCallResult try_call_res;
- ErtsTryImmDrvCallState try_call_state
- = ERTS_INIT_TRY_IMM_DRV_CALL_STATE(
- c_p,
- prt,
- ERTS_PORT_SFLGS_INVALID_LOOKUP,
- 0,
- !refp,
- am_set_data);
-
- if (is_immed(data)) {
- set_data = data;
- bp = NULL;
- }
- else {
- Eterm *hp;
- Uint sz = size_object(data);
- bp = new_message_buffer(sz);
- hp = bp->mem;
- set_data = copy_struct(data, sz, &hp, &bp->off_heap);
- }
-
- try_call_res = try_imm_drv_call(&try_call_state);
- switch (try_call_res) {
- case ERTS_TRY_IMM_DRV_CALL_OK:
- if (prt->bp)
- free_message_buffer(prt->bp);
- prt->bp = bp;
- prt->data = set_data;
- finalize_imm_drv_call(&try_call_state);
- BUMP_REDS(c_p, ERTS_PORT_REDS_SET_DATA);
- return ERTS_PORT_OP_DONE;
- case ERTS_TRY_IMM_DRV_CALL_INVALID_PORT:
- return ERTS_PORT_OP_DROPPED;
- case ERTS_TRY_IMM_DRV_CALL_INVALID_SCHED_FLAGS:
- case ERTS_TRY_IMM_DRV_CALL_BUSY_LOCK:
- /* Schedule call instead... */
- break;
- }
-
- sigdp = erts_port_task_alloc_p2p_sig_data();
- sigdp->flags = ERTS_P2P_SIG_TYPE_SET_DATA;
- sigdp->u.set_data.data = set_data;
- sigdp->u.set_data.bp = bp;
-
- res = erts_schedule_proc2port_signal(c_p,
- prt,
- c_p->common.id,
- refp,
- sigdp,
- 0,
- port_sig_set_data);
- if (res != ERTS_PORT_OP_SCHEDULED && bp)
- free_message_buffer(bp);
- return res;
-}
-
-static int
-port_sig_get_data(Port *prt,
- erts_aint32_t state,
- int op,
- ErtsProc2PortSigData *sigdp)
-{
- ASSERT(sigdp->flags & ERTS_P2P_SIG_DATA_FLG_REPLY);
- if (op != ERTS_PROC2PORT_SIG_EXEC)
- port_sched_op_reply(sigdp->caller, sigdp->ref, am_badarg);
- else {
- Process *rp;
- ErtsProcLocks rp_locks = 0;
-
- rp = erts_proc_lookup_raw(sigdp->caller);
- if (rp) {
- Uint hsz;
- Eterm *hp, *hp_start;
- Eterm data, msg;
- ErlHeapFragment *bp;
- ErlOffHeap *ohp;
-
- hsz = ERTS_QUEUE_PORT_SCHED_OP_REPLY_SIZE;
- hsz += 3;
- if (prt->bp)
- hsz += prt->bp->used_size;
-
- hp_start = hp = erts_alloc_message_heap(hsz,
- &bp,
- &ohp,
- rp,
- &rp_locks);
-
- if (is_immed(prt->data))
- data = prt->data;
- else
- data = copy_struct(prt->data,
- prt->bp->used_size,
- &hp,
- &bp->off_heap);
-
-
-
- msg = TUPLE2(hp, am_ok, data);
- hp += 3;
-
- queue_port_sched_op_reply(rp,
- &rp_locks,
- hp_start,
- hp,
- hsz,
- bp,
- sigdp->ref,
- msg);
- if (rp_locks)
- erts_smp_proc_unlock(rp, rp_locks);
- }
- }
- return ERTS_PORT_REDS_GET_DATA;
-}
-
-ErtsPortOpResult
-erts_port_get_data(Process* c_p,
- Port *prt,
- Eterm *retvalp)
-{
- ErtsProc2PortSigData *sigdp;
- ErtsTryImmDrvCallResult try_call_res;
- ErtsTryImmDrvCallState try_call_state
- = ERTS_INIT_TRY_IMM_DRV_CALL_STATE(
- c_p,
- prt,
- ERTS_PORT_SFLGS_INVALID_LOOKUP,
- 0,
- 0,
- am_get_data);
-
- try_call_res = try_imm_drv_call(&try_call_state);
- switch (try_call_res) {
- case ERTS_TRY_IMM_DRV_CALL_OK: {
- Eterm *hp;
- Eterm data;
- ErlHeapFragment *bp;
- Uint sz;
- if (is_immed(prt->data)) {
- bp = NULL;
- data = prt->data;
- }
- else {
- bp = new_message_buffer(prt->bp->used_size);
- data = copy_struct(prt->data,
- prt->bp->used_size,
- &hp,
- &bp->off_heap);
- }
- finalize_imm_drv_call(&try_call_state);
- if (is_immed(data))
- sz = 0;
- else
- sz = bp->used_size;
-
- hp = HAlloc(c_p, sz + 3);
- if (is_not_immed(data)) {
- data = copy_struct(data, bp->used_size, &hp, &MSO(c_p));
- free_message_buffer(bp);
- }
- *retvalp = TUPLE2(hp, am_ok, data);
- BUMP_REDS(c_p, ERTS_PORT_REDS_GET_DATA);
- return ERTS_PORT_OP_DONE;
- }
- case ERTS_TRY_IMM_DRV_CALL_INVALID_PORT:
- return ERTS_PORT_OP_DROPPED;
- case ERTS_TRY_IMM_DRV_CALL_INVALID_SCHED_FLAGS:
- case ERTS_TRY_IMM_DRV_CALL_BUSY_LOCK:
- /* Schedule call instead... */
- break;
- }
-
- sigdp = erts_port_task_alloc_p2p_sig_data();
- sigdp->flags = ERTS_P2P_SIG_TYPE_GET_DATA;
-
- return erts_schedule_proc2port_signal(c_p,
- prt,
- c_p->common.id,
- retvalp,
- sigdp,
- 0,
- port_sig_get_data);
-}
-
typedef struct {
int to;
void *arg;
@@ -5941,10 +5776,6 @@ int driver_outputv(ErlDrvPort ix, char* hbuf, ErlDrvSizeT hlen,
return driver_output2(ix, hbuf, hlen, NULL, 0);
size = vec->size - skip; /* Size of remaining bytes in vector */
- ASSERT(hlen >= 0); /* debug only */
- if (hlen < 0)
- hlen = 0;
-
prt = erts_drvport2port_state(ix, &state);
if (prt == ERTS_INVALID_ERL_DRV_PORT)
return -1;
diff --git a/erts/emulator/drivers/common/inet_drv.c b/erts/emulator/drivers/common/inet_drv.c
index 2451f41a82..301ce2d0e2 100644
--- a/erts/emulator/drivers/common/inet_drv.c
+++ b/erts/emulator/drivers/common/inet_drv.c
@@ -678,8 +678,8 @@ static int my_strncasecmp(const char *s1, const char *s2, size_t n)
#define INET_LOPT_UDP_READ_PACKETS 33 /* Number of packets to read */
#define INET_OPT_RAW 34 /* Raw socket options */
#define INET_LOPT_TCP_SEND_TIMEOUT_CLOSE 35 /* auto-close on send timeout or not */
-#define INET_LOPT_TCP_MSGQ_HIWTRMRK 36 /* set local high watermark */
-#define INET_LOPT_TCP_MSGQ_LOWTRMRK 37 /* set local low watermark */
+#define INET_LOPT_MSGQ_HIWTRMRK 36 /* set local msgq high watermark */
+#define INET_LOPT_MSGQ_LOWTRMRK 37 /* set local msgq low watermark */
/* SCTP options: a separate range, from 100: */
#define SCTP_OPT_RTOINFO 100
#define SCTP_OPT_ASSOCINFO 101
@@ -5476,27 +5476,25 @@ static int inet_set_opts(inet_descriptor* desc, char* ptr, int len)
}
continue;
- case INET_LOPT_TCP_MSGQ_HIWTRMRK:
- if (desc->stype == SOCK_STREAM) {
- ErlDrvSizeT high;
- if (ival < ERL_DRV_BUSY_MSGQ_LIM_MIN
- || ERL_DRV_BUSY_MSGQ_LIM_MAX < ival)
- return -1;
- high = (ErlDrvSizeT) ival;
- erl_drv_busy_msgq_limits(desc->port, NULL, &high);
- }
+ case INET_LOPT_MSGQ_HIWTRMRK: {
+ ErlDrvSizeT high;
+ if (ival < ERL_DRV_BUSY_MSGQ_LIM_MIN
+ || ERL_DRV_BUSY_MSGQ_LIM_MAX < ival)
+ return -1;
+ high = (ErlDrvSizeT) ival;
+ erl_drv_busy_msgq_limits(desc->port, NULL, &high);
continue;
+ }
- case INET_LOPT_TCP_MSGQ_LOWTRMRK:
- if (desc->stype == SOCK_STREAM) {
- ErlDrvSizeT low;
- if (ival < ERL_DRV_BUSY_MSGQ_LIM_MIN
- || ERL_DRV_BUSY_MSGQ_LIM_MAX < ival)
- return -1;
- low = (ErlDrvSizeT) ival;
- erl_drv_busy_msgq_limits(desc->port, &low, NULL);
- }
+ case INET_LOPT_MSGQ_LOWTRMRK: {
+ ErlDrvSizeT low;
+ if (ival < ERL_DRV_BUSY_MSGQ_LIM_MIN
+ || ERL_DRV_BUSY_MSGQ_LIM_MAX < ival)
+ return -1;
+ low = (ErlDrvSizeT) ival;
+ erl_drv_busy_msgq_limits(desc->port, &low, NULL);
continue;
+ }
case INET_LOPT_TCP_SEND_TIMEOUT:
if (desc->stype == SOCK_STREAM) {
@@ -6398,31 +6396,23 @@ static ErlDrvSSizeT inet_fill_opts(inet_descriptor* desc,
}
continue;
- case INET_LOPT_TCP_MSGQ_HIWTRMRK:
- if (desc->stype == SOCK_STREAM) {
- ErlDrvSizeT high = ERL_DRV_BUSY_MSGQ_READ_ONLY;
- *ptr++ = opt;
- erl_drv_busy_msgq_limits(desc->port, NULL, &high);
- ival = high > INT_MAX ? INT_MAX : (int) high;
- put_int32(ival, ptr);
- }
- else {
- TRUNCATE_TO(0,ptr);
- }
+ case INET_LOPT_MSGQ_HIWTRMRK: {
+ ErlDrvSizeT high = ERL_DRV_BUSY_MSGQ_READ_ONLY;
+ *ptr++ = opt;
+ erl_drv_busy_msgq_limits(desc->port, NULL, &high);
+ ival = high > INT_MAX ? INT_MAX : (int) high;
+ put_int32(ival, ptr);
continue;
+ }
- case INET_LOPT_TCP_MSGQ_LOWTRMRK:
- if (desc->stype == SOCK_STREAM) {
- ErlDrvSizeT low = ERL_DRV_BUSY_MSGQ_READ_ONLY;
- *ptr++ = opt;
- erl_drv_busy_msgq_limits(desc->port, &low, NULL);
- ival = low > INT_MAX ? INT_MAX : (int) low;
- put_int32(ival, ptr);
- }
- else {
- TRUNCATE_TO(0,ptr);
- }
+ case INET_LOPT_MSGQ_LOWTRMRK: {
+ ErlDrvSizeT low = ERL_DRV_BUSY_MSGQ_READ_ONLY;
+ *ptr++ = opt;
+ erl_drv_busy_msgq_limits(desc->port, &low, NULL);
+ ival = low > INT_MAX ? INT_MAX : (int) low;
+ put_int32(ival, ptr);
continue;
+ }
case INET_LOPT_TCP_SEND_TIMEOUT:
if (desc->stype == SOCK_STREAM) {
@@ -7471,6 +7461,20 @@ static void inet_stop(inet_descriptor* desc)
FREE(desc);
}
+static void set_default_msgq_limits(ErlDrvPort port)
+{
+ ErlDrvSizeT q_high = INET_HIGH_MSGQ_WATERMARK;
+ ErlDrvSizeT q_low = INET_LOW_MSGQ_WATERMARK;
+ if (q_low < ERL_DRV_BUSY_MSGQ_LIM_MIN)
+ q_low = ERL_DRV_BUSY_MSGQ_LIM_MIN;
+ else if (q_low > ERL_DRV_BUSY_MSGQ_LIM_MAX)
+ q_low = ERL_DRV_BUSY_MSGQ_LIM_MAX;
+ if (q_high < ERL_DRV_BUSY_MSGQ_LIM_MIN)
+ q_high = ERL_DRV_BUSY_MSGQ_LIM_MIN;
+ else if (q_high > ERL_DRV_BUSY_MSGQ_LIM_MAX)
+ q_high = ERL_DRV_BUSY_MSGQ_LIM_MAX;
+ erl_drv_busy_msgq_limits(port, &q_low, &q_high);
+}
/* Allocate descriptor */
static ErlDrvData inet_start(ErlDrvPort port, int size, int protocol)
@@ -8091,9 +8095,8 @@ static int tcp_inet_init(void)
/* initialize the TCP descriptor */
-static ErlDrvData tcp_inet_start(ErlDrvPort port, char* args)
+static ErlDrvData prep_tcp_inet_start(ErlDrvPort port, char* args)
{
- ErlDrvSizeT q_low, q_high;
tcp_descriptor* desc;
DEBUGF(("tcp_inet_start(%ld) {\r\n", (long)port));
@@ -8103,17 +8106,6 @@ static ErlDrvData tcp_inet_start(ErlDrvPort port, char* args)
return ERL_DRV_ERROR_ERRNO;
desc->high = INET_HIGH_WATERMARK;
desc->low = INET_LOW_WATERMARK;
- q_high = INET_HIGH_MSGQ_WATERMARK;
- q_low = INET_LOW_MSGQ_WATERMARK;
- if (q_low < ERL_DRV_BUSY_MSGQ_LIM_MIN)
- q_low = ERL_DRV_BUSY_MSGQ_LIM_MIN;
- else if (q_low > ERL_DRV_BUSY_MSGQ_LIM_MAX)
- q_low = ERL_DRV_BUSY_MSGQ_LIM_MAX;
- if (q_high < ERL_DRV_BUSY_MSGQ_LIM_MIN)
- q_high = ERL_DRV_BUSY_MSGQ_LIM_MIN;
- else if (q_high > ERL_DRV_BUSY_MSGQ_LIM_MAX)
- q_high = ERL_DRV_BUSY_MSGQ_LIM_MAX;
- erl_drv_busy_msgq_limits(port, &q_low, &q_high);
desc->send_timeout = INET_INFINITY;
desc->send_timeout_close = 0;
desc->busy_on_send = 0;
@@ -8130,6 +8122,12 @@ static ErlDrvData tcp_inet_start(ErlDrvPort port, char* args)
return (ErlDrvData) desc;
}
+static ErlDrvData tcp_inet_start(ErlDrvPort port, char* args)
+{
+ ErlDrvData data = prep_tcp_inet_start(port, args);
+ set_default_msgq_limits(port);
+ return data;
+}
/* Copy a descriptor, by creating a new port with same settings
* as the descriptor desc.
* return NULL on error (SYSTEM_LIMIT no ports avail)
@@ -8141,7 +8139,7 @@ static tcp_descriptor* tcp_inet_copy(tcp_descriptor* desc,SOCKET s,
ErlDrvPort port = desc->inet.port;
tcp_descriptor* copy_desc;
- copy_desc = (tcp_descriptor*) tcp_inet_start(port, NULL);
+ copy_desc = (tcp_descriptor*) prep_tcp_inet_start(port, NULL);
/* Setup event if needed */
if ((copy_desc->inet.s = s) != INVALID_SOCKET) {
@@ -9864,12 +9862,15 @@ static int should_use_so_bsdcompat(void)
* as the descriptor desc.
* return NULL on error (ENFILE no ports avail)
*/
+static ErlDrvData packet_inet_start(ErlDrvPort port, char* args, int protocol);
+
static udp_descriptor* sctp_inet_copy(udp_descriptor* desc, SOCKET s, int* err)
{
+ ErlDrvSizeT q_low, q_high;
ErlDrvPort port = desc->inet.port;
udp_descriptor* copy_desc;
- copy_desc = (udp_descriptor*) sctp_inet_start(port, NULL);
+ copy_desc = (udp_descriptor*) packet_inet_start(port, NULL, IPPROTO_SCTP);
/* Setup event if needed */
if ((copy_desc->inet.s = s) != INVALID_SOCKET) {
@@ -9900,9 +9901,17 @@ static udp_descriptor* sctp_inet_copy(udp_descriptor* desc, SOCKET s, int* err)
FREE(copy_desc);
return NULL;
}
+
+ /* Read busy msgq limits of parent */
+ q_low = q_high = ERL_DRV_BUSY_MSGQ_READ_ONLY;
+ erl_drv_busy_msgq_limits(desc->inet.port, &q_low, &q_high);
+ /* Write same busy msgq limits to child */
+ erl_drv_busy_msgq_limits(port, &q_low, &q_high);
+
copy_desc->inet.port = port;
copy_desc->inet.dport = driver_mk_port(port);
*err = 0;
+
return copy_desc;
}
#endif
@@ -9935,13 +9944,17 @@ static ErlDrvData packet_inet_start(ErlDrvPort port, char* args, int protocol)
static ErlDrvData udp_inet_start(ErlDrvPort port, char *args)
{
- return packet_inet_start(port, args, IPPROTO_UDP);
+ ErlDrvData data = packet_inet_start(port, args, IPPROTO_UDP);
+ set_default_msgq_limits(port);
+ return data;
}
#ifdef HAVE_SCTP
static ErlDrvData sctp_inet_start(ErlDrvPort port, char *args)
{
- return packet_inet_start(port, args, IPPROTO_SCTP);
+ ErlDrvData data = packet_inet_start(port, args, IPPROTO_SCTP);
+ set_default_msgq_limits(port);
+ return data;
}
#endif
diff --git a/erts/emulator/drivers/unix/ttsl_drv.c b/erts/emulator/drivers/unix/ttsl_drv.c
index bedb5ef784..d76401a790 100644
--- a/erts/emulator/drivers/unix/ttsl_drv.c
+++ b/erts/emulator/drivers/unix/ttsl_drv.c
@@ -42,6 +42,9 @@ static ErlDrvData ttysl_start(ErlDrvPort, char*);
#include <locale.h>
#include <unistd.h>
#include <termios.h>
+#ifdef HAVE_WCWIDTH
+#include <wchar.h>
+#endif
#ifdef HAVE_FCNTL_H
#include <fcntl.h>
#endif
@@ -95,6 +98,9 @@ static int lpos; /* The current "cursor position" in the line buf
*/
#define CONTROL_TAG 0x10000000U /* Control character, value in first position */
#define ESCAPED_TAG 0x01000000U /* Escaped character, value in first position */
+#ifdef HAVE_WCWIDTH
+#define WIDE_TAG 0x02000000U /* Wide character, value in first position */
+#endif
#define TAG_MASK 0xFF000000U
#define MAXSIZE (1 << 16)
@@ -597,12 +603,20 @@ static int check_buf_size(byte *s, int n)
}
if (utf8_mode) { /* That is, terminal is UTF8 compliant */
if (ch >= 128 || isprint(ch)) {
- DEBUGLOG(("Printable(UTF-8:%d):%d",(pos - opos),ch));
- size++; /* Buffer contains wide characters... */
+#ifdef HAVE_WCWIDTH
+ int width;
+#endif
+ DEBUGLOG(("Printable(UTF-8:%d):%d",pos,ch));
+ size++;
+#ifdef HAVE_WCWIDTH
+ if ((width = wcwidth(ch)) > 1) {
+ size += width - 1;
+ }
+#endif
} else if (ch == '\t') {
size += 8;
} else {
- DEBUGLOG(("Magic(UTF-8:%d):%d",(pos - opos),ch));
+ DEBUGLOG(("Magic(UTF-8:%d):%d",pos,ch));
size += 2;
}
} else {
@@ -868,12 +882,22 @@ static int step_over_chars(int n)
end = lbuf + llen;
c = lbuf + lpos;
for ( ; n > 0 && c < end; --n) {
+#ifdef HAVE_WCWIDTH
+ while (*c & WIDE_TAG) {
+ c++;
+ }
+#endif
c++;
while (c < end && (*c & TAG_MASK) && ((*c & ~TAG_MASK) == 0))
c++;
}
for ( ; n < 0 && c > beg; n++) {
--c;
+#ifdef HAVE_WCWIDTH
+ while (c > beg + 1 && (c[-1] & WIDE_TAG)) {
+ --c;
+ }
+#endif
while (c > beg && (*c & TAG_MASK) && ((*c & ~TAG_MASK) == 0))
--c;
}
@@ -899,6 +923,15 @@ static int insert_buf(byte *s, int n)
++pos;
}
if ((utf8_mode && (ch >= 128 || isprint(ch))) || (ch <= 255 && isprint(ch))) {
+#ifdef HAVE_WCWIDTH
+ int width;
+ if ((width = wcwidth(ch)) > 1) {
+ while (--width) {
+ DEBUGLOG(("insert_buf: Wide(UTF-8):%d,%d",width,ch));
+ lbuf[lpos++] = (WIDE_TAG | ((Uint32) ch));
+ }
+ }
+#endif
DEBUGLOG(("insert_buf: Printable(UTF-8):%d",ch));
lbuf[lpos++] = (Uint32) ch;
} else if (ch >= 128) { /* not utf8 mode */
@@ -1006,6 +1039,8 @@ static int write_buf(Uint32 *s, int n)
if (octbuff != octtmp) {
driver_free(octbuff);
}
+ } else if (*s & WIDE_TAG) {
+ --n; s++;
} else {
DEBUGLOG(("Very unexpected character %d",(int) *s));
++n;
diff --git a/erts/emulator/drivers/win32/ttsl_drv.c b/erts/emulator/drivers/win32/ttsl_drv.c
index 1a74d21e99..8b5e3eeefd 100644
--- a/erts/emulator/drivers/win32/ttsl_drv.c
+++ b/erts/emulator/drivers/win32/ttsl_drv.c
@@ -414,12 +414,12 @@ static int check_buf_size(byte *s, int n)
}
if (utf8_mode) { /* That is, terminal is UTF8 compliant */
if (ch >= 128 || isprint(ch)) {
- DEBUGLOG(("Printable(UTF-8:%d):%d",(pos - opos),ch));
+ DEBUGLOG(("Printable(UTF-8:%d):%d",pos,ch));
size++; /* Buffer contains wide characters... */
} else if (ch == '\t') {
size += 8;
} else {
- DEBUGLOG(("Magic(UTF-8:%d):%d",(pos - opos),ch));
+ DEBUGLOG(("Magic(UTF-8:%d):%d",pos,ch));
size += 2;
}
} else {
diff --git a/erts/emulator/hipe/hipe_x86_signal.c b/erts/emulator/hipe/hipe_x86_signal.c
index 64c0e0da3e..19fc448742 100644
--- a/erts/emulator/hipe/hipe_x86_signal.c
+++ b/erts/emulator/hipe/hipe_x86_signal.c
@@ -183,6 +183,7 @@ static void do_init(void)
#include <dlfcn.h>
static int (*__next_sigaction)(int, const struct sigaction*, struct sigaction*);
#define init_done() (__next_sigaction != 0)
+extern int _sigaction(int, const struct sigaction*, struct sigaction*);
#define __SIGACTION _sigaction
static void do_init(void)
{
diff --git a/erts/emulator/sys/unix/sys_float.c b/erts/emulator/sys/unix/sys_float.c
index 787f8d6728..689be98969 100644
--- a/erts/emulator/sys/unix/sys_float.c
+++ b/erts/emulator/sys/unix/sys_float.c
@@ -832,6 +832,8 @@ sys_chars_to_double(char* buf, double* fp)
return 0;
}
+#ifdef USE_MATHERR
+
int
matherr(struct exception *exc)
{
@@ -842,3 +844,5 @@ matherr(struct exception *exc)
#endif
return 1;
}
+
+#endif
diff --git a/erts/emulator/sys/win32/sys.c b/erts/emulator/sys/win32/sys.c
index e0422de026..922967c698 100755
--- a/erts/emulator/sys/win32/sys.c
+++ b/erts/emulator/sys/win32/sys.c
@@ -399,11 +399,12 @@ int* pBuild; /* Pointer to build number. */
* Definitions for driver flags.
*/
-#define DF_OVR_READY 1 /* Overlapped result is ready. */
-#define DF_EXIT_THREAD 2 /* The thread should exit. */
-#define DF_XLAT_CR 4 /* The thread should translate CRs. */
-#define DF_DROP_IF_INVH 8 /* Drop packages instead of crash if
+#define DF_OVR_READY 1 /* Overlapped result is ready. */
+#define DF_EXIT_THREAD 2 /* The thread should exit. */
+#define DF_XLAT_CR 4 /* The thread should translate CRs. */
+#define DF_DROP_IF_INVH 8 /* Drop packages instead of crash if
invalid handle (stderr) */
+#define DF_THREAD_FLUSHED 16 /* The thread should exit. */
#define OV_BUFFER_PTR(dp) ((LPVOID) ((dp)->ov.Internal))
#define OV_NUM_TO_READ(dp) ((dp)->ov.InternalHigh)
@@ -2141,8 +2142,9 @@ threaded_writer(LPVOID param)
for (;;) {
handle = WaitForMultipleObjects(2, handles, FALSE, INFINITE);
- if (aio->flags & DF_EXIT_THREAD)
+ if (aio->flags & DF_EXIT_THREAD) {
break;
+ }
buf = OV_BUFFER_PTR(aio);
numToWrite = OV_NUM_TO_READ(aio);
@@ -2150,6 +2152,7 @@ threaded_writer(LPVOID param)
if (handle == (WAIT_OBJECT_0 + 1) && numToWrite == 0) {
SetEvent(aio->flushReplyEvent);
+ aio->flags |= DF_THREAD_FLUSHED;
continue;
}
@@ -2197,6 +2200,7 @@ threaded_writer(LPVOID param)
if (aio->flags & DF_EXIT_THREAD)
break;
}
+ aio->flags |= DF_THREAD_FLUSHED;
CloseHandle(aio->fd);
aio->fd = INVALID_HANDLE_VALUE;
unrefer_driver_data(aio->dp);
@@ -2340,9 +2344,11 @@ static void fd_stop(ErlDrvData data)
(void) driver_select(dp->port_num,
(ErlDrvEvent)dp->out.ov.hEvent,
ERL_DRV_WRITE, 0);
- ASSERT(dp->out.flushEvent);
- SetEvent(dp->out.flushEvent);
- WaitForSingleObject(dp->out.flushReplyEvent, INFINITE);
+ do {
+ ASSERT(dp->out.flushEvent);
+ SetEvent(dp->out.flushEvent);
+ } while (WaitForSingleObject(dp->out.flushReplyEvent, 10) == WAIT_TIMEOUT
+ || !(dp->out.flags & DF_THREAD_FLUSHED));
}
}
@@ -2433,12 +2439,12 @@ threaded_exiter(LPVOID param)
*/
i = 0;
if (dp->out.thread != (HANDLE) -1) {
- dp->out.flags = DF_EXIT_THREAD;
+ dp->out.flags |= DF_EXIT_THREAD;
SetEvent(dp->out.ioAllowed);
handles[i++] = dp->out.thread;
}
if (dp->in.thread != (HANDLE) -1) {
- dp->in.flags = DF_EXIT_THREAD;
+ dp->in.flags |= DF_EXIT_THREAD;
SetEvent(dp->in.ioAllowed);
handles[i++] = dp->in.thread;
}
diff --git a/erts/emulator/sys/win32/sys_float.c b/erts/emulator/sys/win32/sys_float.c
index fb1ffc3089..e2a777d182 100644
--- a/erts/emulator/sys/win32/sys_float.c
+++ b/erts/emulator/sys/win32/sys_float.c
@@ -133,6 +133,8 @@ sys_double_to_chars_ext(double fp, char *buffer, size_t buffer_size, size_t deci
return s-buffer; /* i.e strlen(buffer) */
}
+#ifdef USE_MATHERR
+
int
matherr(struct _exception *exc)
{
@@ -141,6 +143,8 @@ matherr(struct _exception *exc)
return 1;
}
+#endif
+
static void
fpe_exception(int sig)
{
diff --git a/erts/emulator/test/busy_port_SUITE.erl b/erts/emulator/test/busy_port_SUITE.erl
index 2c63296b83..4b4af0babe 100644
--- a/erts/emulator/test/busy_port_SUITE.erl
+++ b/erts/emulator/test/busy_port_SUITE.erl
@@ -170,6 +170,7 @@ send_3(Config) when is_list(Config) ->
?line {Owner,Slave} = get_slave(),
?line ok = erlang:send(Slave, {Owner,{command,"set busy"}},
[nosuspend]),
+ receive after 100 -> ok end, % ensure command reached port
?line nosuspend = erlang:send(Slave, {Owner,{command,"busy"}},
[nosuspend]),
?line unlock_slave(),
@@ -563,6 +564,7 @@ scheduling_delay_busy_nosuspend(Config) ->
{2,{call,[{var,1},open_port]}},
{0,{cast,[{var,1},{command,1,100}]}},
{0,{cast,[{var,1},{busy,2}]}},
+ {0,{timer,sleep,[200]}}, % ensure reached port
{10,{call,[{var,1},{command,3,[nosuspend]}]}},
{0,{timer,sleep,[200]}},
{0,{erlang,port_command,[{var,2},<<$N>>,[force]]}},
diff --git a/erts/etc/unix/cerl.src b/erts/etc/unix/cerl.src
index cc7d77fd9a..f99059cb72 100644
--- a/erts/etc/unix/cerl.src
+++ b/erts/etc/unix/cerl.src
@@ -171,6 +171,11 @@ while [ $# -gt 0 ]; do
cargs="$cargs -debug"
TYPE=.debug
;;
+ "-frmptr")
+ shift
+ cargs="$cargs -frmptr"
+ TYPE=.frmptr
+ ;;
"-gdb")
shift
GDB=gdb
diff --git a/erts/lib_src/Makefile.in b/erts/lib_src/Makefile.in
index 0fc3ac6efc..4f0a5e5202 100644
--- a/erts/lib_src/Makefile.in
+++ b/erts/lib_src/Makefile.in
@@ -86,6 +86,12 @@ CFLAGS += -DERTS_ENABLE_LOCK_COUNT
OMIT_FP=true
PRE_LD=
else
+ifeq ($(TYPE),frmptr)
+TYPE_SUFFIX = .frmptr
+CFLAGS += -DERTS_FRMPTR
+OMIT_OMIT_FP=yes
+PRE_LD=
+else
override TYPE=opt
OMIT_FP=true
TYPE_SUFFIX=
@@ -98,6 +104,7 @@ endif
endif
endif
endif
+endif
OPSYS=@OPSYS@
sol2CFLAGS=
@@ -110,6 +117,7 @@ ultrasparcCFLAGS=-Wa,-xarch=v8plusa
ARCHCFLAGS=$($(ARCH)CFLAGS)
ifeq ($(OMIT_OMIT_FP),yes)
+CFLAGS += -fno-omit-frame-pointer
OMIT_FP=false
endif
diff --git a/erts/preloaded/ebin/erlang.beam b/erts/preloaded/ebin/erlang.beam
index 29fb8aaebf..308cb99be5 100644
--- a/erts/preloaded/ebin/erlang.beam
+++ b/erts/preloaded/ebin/erlang.beam
Binary files differ
diff --git a/erts/preloaded/ebin/erts_internal.beam b/erts/preloaded/ebin/erts_internal.beam
index c907ead38a..1b47509a53 100644
--- a/erts/preloaded/ebin/erts_internal.beam
+++ b/erts/preloaded/ebin/erts_internal.beam
Binary files differ
diff --git a/erts/preloaded/ebin/prim_inet.beam b/erts/preloaded/ebin/prim_inet.beam
index 7b9da42e4f..43cbc17dbf 100644
--- a/erts/preloaded/ebin/prim_inet.beam
+++ b/erts/preloaded/ebin/prim_inet.beam
Binary files differ
diff --git a/erts/preloaded/src/erlang.erl b/erts/preloaded/src/erlang.erl
index fefe0f21e0..7106c0a4fb 100644
--- a/erts/preloaded/src/erlang.erl
+++ b/erts/preloaded/src/erlang.erl
@@ -2086,7 +2086,7 @@ tuple_to_list(_Tuple) ->
({allocator_sizes, Alloc}) -> [_] when %% More or less anything
Alloc :: atom();
(build_type) -> opt | debug | purify | quantify | purecov |
- gcov | valgrind | gprof | lcnt;
+ gcov | valgrind | gprof | lcnt | frmptr;
(c_compiler_used) -> {atom(), term()};
(check_io) -> [_];
(compat_rel) -> integer();
@@ -2705,26 +2705,14 @@ port_info(Port, Item) ->
Port :: port() | atom(),
Data :: term().
-port_set_data(Port, Data) ->
- case case erts_internal:port_set_data(Port, Data) of
- Ref when erlang:is_reference(Ref) -> receive {Ref, Res} -> Res end;
- Res -> Res
- end of
- badarg -> erlang:error(badarg, [Port, Data]);
- Result -> Result
- end.
+port_set_data(_Port, _Data) ->
+ erlang:nif_error(undefined).
-spec erlang:port_get_data(Port) -> term() when
Port :: port() | atom().
-port_get_data(Port) ->
- case case erts_internal:port_get_data(Port) of
- Ref when erlang:is_reference(Ref) -> receive {Ref, Res} -> Res end;
- Res -> Res
- end of
- {ok, Data} -> Data;
- Error -> erlang:error(Error, [Port])
- end.
+port_get_data(_Port) ->
+ erlang:nif_error(undefined).
%%
%% If the emulator wants to perform a distributed command and
diff --git a/erts/preloaded/src/erts_internal.erl b/erts/preloaded/src/erts_internal.erl
index f1c83f4518..507bc3afb9 100644
--- a/erts/preloaded/src/erts_internal.erl
+++ b/erts/preloaded/src/erts_internal.erl
@@ -31,8 +31,7 @@
-export([await_port_send_result/3]).
-export([port_command/3, port_connect/2, port_close/1,
- port_control/3, port_call/3, port_set_data/2, port_get_data/1,
- port_info/1, port_info/2]).
+ port_control/3, port_call/3, port_info/1, port_info/2]).
%%
%% Await result of send to port
@@ -86,19 +85,6 @@ port_control(_Port, _Operation, _Data) ->
port_call(_Port, _Operation, _Data) ->
erlang:nif_error(undefined).
--spec erts_internal:port_get_data(P1) -> Result when
- P1 :: port() | atom(),
- Result :: {ok, term()} | reference() | badarg.
-port_get_data(_P1) ->
- erlang:nif_error(undefined).
-
--spec erts_internal:port_set_data(P1, P2) -> Result when
- P1 :: port() | atom(),
- P2 :: term(),
- Result :: true | reference() | badarg.
-port_set_data(_P1, _P2) ->
- erlang:nif_error(undefined).
-
-type port_info_1_result_item() ::
{registered_name, RegName :: atom()} |
{id, Index :: non_neg_integer()} |
diff --git a/erts/preloaded/src/prim_inet.erl b/erts/preloaded/src/prim_inet.erl
index 21d23159f0..d0e70aa95c 100644
--- a/erts/preloaded/src/prim_inet.erl
+++ b/erts/preloaded/src/prim_inet.erl
@@ -1072,8 +1072,8 @@ enc_opt(deliver) -> ?INET_LOPT_DELIVER;
enc_opt(exit_on_close) -> ?INET_LOPT_EXITONCLOSE;
enc_opt(high_watermark) -> ?INET_LOPT_TCP_HIWTRMRK;
enc_opt(low_watermark) -> ?INET_LOPT_TCP_LOWTRMRK;
-enc_opt(high_msgq_watermark) -> ?INET_LOPT_TCP_MSGQ_HIWTRMRK;
-enc_opt(low_msgq_watermark) -> ?INET_LOPT_TCP_MSGQ_LOWTRMRK;
+enc_opt(high_msgq_watermark) -> ?INET_LOPT_MSGQ_HIWTRMRK;
+enc_opt(low_msgq_watermark) -> ?INET_LOPT_MSGQ_LOWTRMRK;
enc_opt(send_timeout) -> ?INET_LOPT_TCP_SEND_TIMEOUT;
enc_opt(send_timeout_close) -> ?INET_LOPT_TCP_SEND_TIMEOUT_CLOSE;
enc_opt(delay_send) -> ?INET_LOPT_TCP_DELAY_SEND;
@@ -1128,8 +1128,8 @@ dec_opt(?INET_LOPT_DELIVER) -> deliver;
dec_opt(?INET_LOPT_EXITONCLOSE) -> exit_on_close;
dec_opt(?INET_LOPT_TCP_HIWTRMRK) -> high_watermark;
dec_opt(?INET_LOPT_TCP_LOWTRMRK) -> low_watermark;
-dec_opt(?INET_LOPT_TCP_MSGQ_HIWTRMRK) -> high_msgq_watermark;
-dec_opt(?INET_LOPT_TCP_MSGQ_LOWTRMRK) -> low_msgq_watermark;
+dec_opt(?INET_LOPT_MSGQ_HIWTRMRK) -> high_msgq_watermark;
+dec_opt(?INET_LOPT_MSGQ_LOWTRMRK) -> low_msgq_watermark;
dec_opt(?INET_LOPT_TCP_SEND_TIMEOUT) -> send_timeout;
dec_opt(?INET_LOPT_TCP_SEND_TIMEOUT_CLOSE) -> send_timeout_close;
dec_opt(?INET_LOPT_TCP_DELAY_SEND) -> delay_send;
diff --git a/lib/crypto/c_src/crypto.c b/lib/crypto/c_src/crypto.c
index fac77308f6..9d43a1d907 100644
--- a/lib/crypto/c_src/crypto.c
+++ b/lib/crypto/c_src/crypto.c
@@ -74,6 +74,19 @@
# define HAVE_DES_ede3_cfb_encrypt
#endif
+#if OPENSSL_VERSION_NUMBER >= 0x009080ffL \
+ && !defined(OPENSSL_NO_EC) \
+ && !defined(OPENSSL_NO_ECDH) \
+ && !defined(OPENSSL_NO_ECDSA)
+# define HAVE_EC
+#endif
+
+#if defined(HAVE_EC)
+#include <openssl/ec.h>
+#include <openssl/ecdh.h>
+#include <openssl/ecdsa.h>
+#endif
+
#ifdef VALGRIND
# include <valgrind/memcheck.h>
@@ -192,7 +205,7 @@ static ERL_NIF_TERM rand_bytes_3(ErlNifEnv* env, int argc, const ERL_NIF_TERM ar
static ERL_NIF_TERM strong_rand_mpint_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
static ERL_NIF_TERM rand_uniform_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
static ERL_NIF_TERM mod_exp_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
-static ERL_NIF_TERM dss_verify(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
+static ERL_NIF_TERM dss_verify_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
static ERL_NIF_TERM rsa_verify_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
static ERL_NIF_TERM aes_cbc_crypt(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
static ERL_NIF_TERM exor(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
@@ -209,13 +222,19 @@ static ERL_NIF_TERM dh_check(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]
static ERL_NIF_TERM dh_generate_key_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
static ERL_NIF_TERM dh_compute_key_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
static ERL_NIF_TERM srp_value_B_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
-static ERL_NIF_TERM srp_client_secret_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
-static ERL_NIF_TERM srp_server_secret_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
+static ERL_NIF_TERM srp_user_secret_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
+static ERL_NIF_TERM srp_host_secret_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
static ERL_NIF_TERM bf_cfb64_crypt(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
static ERL_NIF_TERM bf_cbc_crypt(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
static ERL_NIF_TERM bf_ecb_crypt(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
static ERL_NIF_TERM blowfish_ofb64_encrypt(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
+static ERL_NIF_TERM ec_key_to_term_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
+static ERL_NIF_TERM term_to_ec_key_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
+static ERL_NIF_TERM ec_key_generate(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
+static ERL_NIF_TERM ecdsa_sign_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
+static ERL_NIF_TERM ecdsa_verify_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
+static ERL_NIF_TERM ecdh_compute_key_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
/* helpers */
@@ -247,6 +266,11 @@ static void hmac_sha512(unsigned char *key, int klen,
unsigned char *dbuf, int dlen,
unsigned char *hmacbuf);
#endif
+#ifdef HAVE_EC
+static EC_KEY* ec_key_new(ErlNifEnv* env, ERL_NIF_TERM curve_arg);
+static int term2point(ErlNifEnv* env, ERL_NIF_TERM term,
+ EC_GROUP *group, EC_POINT **pptr);
+#endif
static int library_refc = 0; /* number of users of this dynamic library */
@@ -311,7 +335,7 @@ static ErlNifFunc nif_funcs[] = {
{"strong_rand_mpint_nif", 3, strong_rand_mpint_nif},
{"rand_uniform_nif", 2, rand_uniform_nif},
{"mod_exp_nif", 4, mod_exp_nif},
- {"dss_verify", 4, dss_verify},
+ {"dss_verify_nif", 4, dss_verify_nif},
{"rsa_verify_nif", 4, rsa_verify_nif},
{"aes_cbc_crypt", 4, aes_cbc_crypt},
{"exor", 2, exor},
@@ -325,16 +349,120 @@ static ErlNifFunc nif_funcs[] = {
{"rsa_private_crypt", 4, rsa_private_crypt},
{"dh_generate_parameters_nif", 2, dh_generate_parameters_nif},
{"dh_check", 1, dh_check},
- {"dh_generate_key_nif", 2, dh_generate_key_nif},
+ {"dh_generate_key_nif", 3, dh_generate_key_nif},
{"dh_compute_key_nif", 3, dh_compute_key_nif},
{"srp_value_B_nif", 5, srp_value_B_nif},
- {"srp_client_secret_nif", 7, srp_client_secret_nif},
- {"srp_server_secret_nif", 5, srp_server_secret_nif},
+ {"srp_user_secret_nif", 7, srp_user_secret_nif},
+ {"srp_host_secret_nif", 5, srp_host_secret_nif},
{"bf_cfb64_crypt", 4, bf_cfb64_crypt},
{"bf_cbc_crypt", 4, bf_cbc_crypt},
{"bf_ecb_crypt", 3, bf_ecb_crypt},
- {"blowfish_ofb64_encrypt", 3, blowfish_ofb64_encrypt}
+ {"blowfish_ofb64_encrypt", 3, blowfish_ofb64_encrypt},
+
+ {"ec_key_to_term_nif", 1, ec_key_to_term_nif},
+ {"term_to_ec_key_nif", 3, term_to_ec_key_nif},
+ {"ec_key_generate", 1, ec_key_generate},
+ {"ecdsa_sign_nif", 3, ecdsa_sign_nif},
+ {"ecdsa_verify_nif", 4, ecdsa_verify_nif},
+ {"ecdh_compute_key_nif", 2, ecdh_compute_key_nif}
+};
+
+#if defined(HAVE_EC)
+struct nid_map {
+ char *name;
+ int nid;
+ ERL_NIF_TERM atom;
+};
+
+static struct nid_map ec_curves[] = {
+ /* prime field curves */
+ /* secg curves */
+ { "secp112r1", NID_secp112r1 },
+ { "secp112r2", NID_secp112r2 },
+ { "secp128r1", NID_secp128r1 },
+ { "secp128r2", NID_secp128r2 },
+ { "secp160k1", NID_secp160k1 },
+ { "secp160r1", NID_secp160r1 },
+ { "secp160r2", NID_secp160r2 },
+ /* SECG secp192r1 is the same as X9.62 prime192v1 */
+ { "secp192r1", NID_X9_62_prime192v1 },
+ { "secp192k1", NID_secp192k1 },
+ { "secp224k1", NID_secp224k1 },
+ { "secp224r1", NID_secp224r1 },
+ { "secp256k1", NID_secp256k1 },
+ /* SECG secp256r1 is the same as X9.62 prime256v1 */
+ { "secp256r1", NID_X9_62_prime256v1 },
+ { "secp384r1", NID_secp384r1 },
+ { "secp521r1", NID_secp521r1 },
+ /* X9.62 curves */
+ { "prime192v1", NID_X9_62_prime192v1 },
+ { "prime192v2", NID_X9_62_prime192v2 },
+ { "prime192v3", NID_X9_62_prime192v3 },
+ { "prime239v1", NID_X9_62_prime239v1 },
+ { "prime239v2", NID_X9_62_prime239v2 },
+ { "prime239v3", NID_X9_62_prime239v3 },
+ { "prime256v1", NID_X9_62_prime256v1 },
+ /* characteristic two field curves */
+ /* NIST/SECG curves */
+ { "sect113r1", NID_sect113r1 },
+ { "sect113r2", NID_sect113r2 },
+ { "sect131r1", NID_sect131r1 },
+ { "sect131r2", NID_sect131r2 },
+ { "sect163k1", NID_sect163k1 },
+ { "sect163r1", NID_sect163r1 },
+ { "sect163r2", NID_sect163r2 },
+ { "sect193r1", NID_sect193r1 },
+ { "sect193r2", NID_sect193r2 },
+ { "sect233k1", NID_sect233k1 },
+ { "sect233r1", NID_sect233r1 },
+ { "sect239k1", NID_sect239k1 },
+ { "sect283k1", NID_sect283k1 },
+ { "sect283r1", NID_sect283r1 },
+ { "sect409k1", NID_sect409k1 },
+ { "sect409r1", NID_sect409r1 },
+ { "sect571k1", NID_sect571k1 },
+ { "sect571r1", NID_sect571r1 },
+ /* X9.62 curves */
+ { "c2pnb163v1", NID_X9_62_c2pnb163v1 },
+ { "c2pnb163v2", NID_X9_62_c2pnb163v2 },
+ { "c2pnb163v3", NID_X9_62_c2pnb163v3 },
+ { "c2pnb176v1", NID_X9_62_c2pnb176v1 },
+ { "c2tnb191v1", NID_X9_62_c2tnb191v1 },
+ { "c2tnb191v2", NID_X9_62_c2tnb191v2 },
+ { "c2tnb191v3", NID_X9_62_c2tnb191v3 },
+ { "c2pnb208w1", NID_X9_62_c2pnb208w1 },
+ { "c2tnb239v1", NID_X9_62_c2tnb239v1 },
+ { "c2tnb239v2", NID_X9_62_c2tnb239v2 },
+ { "c2tnb239v3", NID_X9_62_c2tnb239v3 },
+ { "c2pnb272w1", NID_X9_62_c2pnb272w1 },
+ { "c2pnb304w1", NID_X9_62_c2pnb304w1 },
+ { "c2tnb359v1", NID_X9_62_c2tnb359v1 },
+ { "c2pnb368w1", NID_X9_62_c2pnb368w1 },
+ { "c2tnb431r1", NID_X9_62_c2tnb431r1 },
+ /* the WAP/WTLS curves
+ * [unlike SECG, spec has its own OIDs for curves from X9.62] */
+ { "wtls1", NID_wap_wsg_idm_ecid_wtls1 },
+ { "wtls3", NID_wap_wsg_idm_ecid_wtls3 },
+ { "wtls4", NID_wap_wsg_idm_ecid_wtls4 },
+ { "wtls5", NID_wap_wsg_idm_ecid_wtls5 },
+ { "wtls6", NID_wap_wsg_idm_ecid_wtls6 },
+ { "wtls7", NID_wap_wsg_idm_ecid_wtls7 },
+ { "wtls8", NID_wap_wsg_idm_ecid_wtls8 },
+ { "wtls9", NID_wap_wsg_idm_ecid_wtls9 },
+ { "wtls10", NID_wap_wsg_idm_ecid_wtls10 },
+ { "wtls11", NID_wap_wsg_idm_ecid_wtls11 },
+ { "wtls12", NID_wap_wsg_idm_ecid_wtls12 },
+ /* IPSec curves */
+ { "ipsec3", NID_ipsec3 },
+ { "ipsec4", NID_ipsec4 }
+};
+
+#define EC_CURVES_CNT (sizeof(ec_curves)/sizeof(struct nid_map))
+
+struct nif_ec_key {
+ EC_KEY *key;
};
+#endif
ERL_NIF_INIT(crypto,nif_funcs,load,NULL,upgrade,unload)
@@ -368,6 +496,7 @@ static ERL_NIF_TERM atom_sha256;
static ERL_NIF_TERM atom_sha384;
static ERL_NIF_TERM atom_sha512;
static ERL_NIF_TERM atom_md5;
+static ERL_NIF_TERM atom_md4;
static ERL_NIF_TERM atom_ripemd160;
static ERL_NIF_TERM atom_error;
static ERL_NIF_TERM atom_rsa_pkcs1_padding;
@@ -386,6 +515,19 @@ static ERL_NIF_TERM atom_none;
static ERL_NIF_TERM atom_notsup;
static ERL_NIF_TERM atom_digest;
+static ERL_NIF_TERM atom_ec;
+
+#if defined(HAVE_EC)
+static ERL_NIF_TERM atom_prime_field;
+static ERL_NIF_TERM atom_characteristic_two_field;
+static ERL_NIF_TERM atom_tpbasis;
+static ERL_NIF_TERM atom_ppbasis;
+static ERL_NIF_TERM atom_onbasis;
+
+static ErlNifResourceType* res_type_ec_key;
+static void ec_key_dtor(ErlNifEnv* env, void* obj);
+#endif
+
/*
#define PRINTF_ERR0(FMT) enif_fprintf(stderr, FMT "\n")
#define PRINTF_ERR1(FMT, A1) enif_fprintf(stderr, FMT "\n", A1)
@@ -415,6 +557,7 @@ static void error_handler(void* null, const char* errstr)
static int init(ErlNifEnv* env, ERL_NIF_TERM load_info)
{
+ int i;
ErlNifSysInfo sys_info;
get_crypto_callbacks_t* funcp;
struct crypto_callbacks* ccb;
@@ -448,6 +591,7 @@ static int init(ErlNifEnv* env, ERL_NIF_TERM load_info)
atom_sha256 = enif_make_atom(env,"sha256");
atom_sha384 = enif_make_atom(env,"sha384");
atom_sha512 = enif_make_atom(env,"sha512");
+ atom_md4 = enif_make_atom(env,"md4");
atom_md5 = enif_make_atom(env,"md5");
atom_ripemd160 = enif_make_atom(env,"ripemd160");
atom_error = enif_make_atom(env,"error");
@@ -466,6 +610,23 @@ static int init(ErlNifEnv* env, ERL_NIF_TERM load_info)
atom_notsup = enif_make_atom(env,"notsup");
atom_digest = enif_make_atom(env,"digest");
+#if defined(HAVE_EC)
+ atom_ec = enif_make_atom(env,"ec");
+ atom_prime_field = enif_make_atom(env,"prime_field");
+ atom_characteristic_two_field = enif_make_atom(env,"characteristic_two_field");
+ atom_tpbasis = enif_make_atom(env,"tpbasis");
+ atom_ppbasis = enif_make_atom(env,"ppbasis");
+ atom_onbasis = enif_make_atom(env,"onbasis");
+
+ for (i = 0; i < EC_CURVES_CNT; i++)
+ ec_curves[i].atom = enif_make_atom(env,ec_curves[i].name);
+
+ res_type_ec_key = enif_open_resource_type(env,NULL,"crypto.EC_KEY",
+ ec_key_dtor,
+ ERL_NIF_RT_CREATE|ERL_NIF_RT_TAKEOVER,
+ NULL);
+#endif
+
init_digest_types(env);
init_algorithms_types();
@@ -549,12 +710,12 @@ static void unload(ErlNifEnv* env, void* priv_data)
}
static int algos_cnt;
-static ERL_NIF_TERM algos[7]; /* increase when extending the list */
+static ERL_NIF_TERM algos[9]; /* increase when extending the list */
static void init_algorithms_types(void)
{
algos_cnt = 0;
-
+ algos[algos_cnt++] = atom_md4;
algos[algos_cnt++] = atom_md5;
algos[algos_cnt++] = atom_sha;
algos[algos_cnt++] = atom_ripemd160;
@@ -570,6 +731,9 @@ static void init_algorithms_types(void)
#ifdef HAVE_SHA512
algos[algos_cnt++] = atom_sha512;
#endif
+#if defined(HAVE_EC)
+ algos[algos_cnt++] = atom_ec;
+#endif
}
static ERL_NIF_TERM algorithms(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
@@ -1631,13 +1795,7 @@ static ERL_NIF_TERM mod_exp_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM arg
return ret;
}
-static int inspect_mpint(ErlNifEnv* env, ERL_NIF_TERM term, ErlNifBinary* bin)
-{
- return enif_inspect_binary(env, term, bin) &&
- bin->size >= 4 && get_int32(bin->data) == bin->size-4;
-}
-
-static ERL_NIF_TERM dss_verify(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
+static ERL_NIF_TERM dss_verify_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
{/* (DigestType|none, Data|{digest,Digest}, Signature,Key=[P, Q, G, Y]) */
ErlNifBinary data_bin, sign_bin;
BIGNUM *dsa_p = NULL, *dsa_q = NULL, *dsa_g = NULL, *dsa_y = NULL;
@@ -1660,10 +1818,10 @@ static ERL_NIF_TERM dss_verify(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv
digest = data_bin.data;
}
else {
- if (!inspect_mpint(env, argv[1], &data_bin)) {
+ if (!enif_inspect_binary(env, argv[1], &data_bin)) {
return enif_make_badarg(env);
}
- SHA1(data_bin.data+4, data_bin.size-4, hmacbuf);
+ SHA1(data_bin.data, data_bin.size, hmacbuf);
digest = hmacbuf;
}
}
@@ -1675,15 +1833,15 @@ static ERL_NIF_TERM dss_verify(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv
return enif_make_badarg(env);
}
- if (!inspect_mpint(env, argv[2], &sign_bin)
+ if (!enif_inspect_binary(env, argv[2], &sign_bin)
|| !enif_get_list_cell(env, argv[3], &head, &tail)
- || !get_bn_from_mpint(env, head, &dsa_p)
+ || !get_bn_from_bin(env, head, &dsa_p)
|| !enif_get_list_cell(env, tail, &head, &tail)
- || !get_bn_from_mpint(env, head, &dsa_q)
+ || !get_bn_from_bin(env, head, &dsa_q)
|| !enif_get_list_cell(env, tail, &head, &tail)
- || !get_bn_from_mpint(env, head, &dsa_g)
+ || !get_bn_from_bin(env, head, &dsa_g)
|| !enif_get_list_cell(env, tail, &head, &tail)
- || !get_bn_from_mpint(env, head, &dsa_y)
+ || !get_bn_from_bin(env, head, &dsa_y)
|| !enif_is_empty_list(env,tail)) {
if (dsa_p) BN_free(dsa_p);
@@ -1700,7 +1858,7 @@ static ERL_NIF_TERM dss_verify(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv
dsa->priv_key = NULL;
dsa->pub_key = dsa_y;
i = DSA_verify(0, digest, SHA_DIGEST_LENGTH,
- sign_bin.data+4, sign_bin.size-4, dsa);
+ sign_bin.data, sign_bin.size, dsa);
DSA_free(dsa);
return(i > 0) ? atom_true : atom_false;
}
@@ -1826,11 +1984,11 @@ static ERL_NIF_TERM rsa_verify_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM
rsa = RSA_new();
- if (!inspect_mpint(env, argv[2], &sign_bin)
+ if (!enif_inspect_binary(env, argv[2], &sign_bin)
|| !enif_get_list_cell(env, argv[3], &head, &tail)
- || !get_bn_from_mpint(env, head, &rsa->e)
+ || !get_bn_from_bin(env, head, &rsa->e)
|| !enif_get_list_cell(env, tail, &head, &tail)
- || !get_bn_from_mpint(env, head, &rsa->n)
+ || !get_bn_from_bin(env, head, &rsa->n)
|| !enif_is_empty_list(env, tail)) {
ret = enif_make_badarg(env);
@@ -1846,9 +2004,9 @@ static ERL_NIF_TERM rsa_verify_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM
}
digest = data_bin.data;
}
- else if (inspect_mpint(env, argv[1], &data_bin)) {
+ else if (enif_inspect_binary(env, argv[1], &data_bin)) {
digest = hmacbuf;
- digp->funcp(data_bin.data+4, data_bin.size-4, digest);
+ digp->funcp(data_bin.data, data_bin.size, digest);
}
else {
ret = enif_make_badarg(env);
@@ -1856,7 +2014,7 @@ static ERL_NIF_TERM rsa_verify_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM
}
i = RSA_verify(digp->NID_type, digest, digp->len,
- sign_bin.data+4, sign_bin.size-4, rsa);
+ sign_bin.data, sign_bin.size, rsa);
ret = (i==1 ? atom_true : atom_false);
@@ -2001,22 +2159,22 @@ static int get_rsa_private_key(ErlNifEnv* env, ERL_NIF_TERM key, RSA *rsa)
ERL_NIF_TERM head, tail;
if (!enif_get_list_cell(env, key, &head, &tail)
- || !get_bn_from_mpint(env, head, &rsa->e)
+ || !get_bn_from_bin(env, head, &rsa->e)
|| !enif_get_list_cell(env, tail, &head, &tail)
- || !get_bn_from_mpint(env, head, &rsa->n)
+ || !get_bn_from_bin(env, head, &rsa->n)
|| !enif_get_list_cell(env, tail, &head, &tail)
- || !get_bn_from_mpint(env, head, &rsa->d)
+ || !get_bn_from_bin(env, head, &rsa->d)
|| (!enif_is_empty_list(env, tail) &&
(!enif_get_list_cell(env, tail, &head, &tail)
- || !get_bn_from_mpint(env, head, &rsa->p)
+ || !get_bn_from_bin(env, head, &rsa->p)
|| !enif_get_list_cell(env, tail, &head, &tail)
- || !get_bn_from_mpint(env, head, &rsa->q)
+ || !get_bn_from_bin(env, head, &rsa->q)
|| !enif_get_list_cell(env, tail, &head, &tail)
- || !get_bn_from_mpint(env, head, &rsa->dmp1)
+ || !get_bn_from_bin(env, head, &rsa->dmp1)
|| !enif_get_list_cell(env, tail, &head, &tail)
- || !get_bn_from_mpint(env, head, &rsa->dmq1)
+ || !get_bn_from_bin(env, head, &rsa->dmq1)
|| !enif_get_list_cell(env, tail, &head, &tail)
- || !get_bn_from_mpint(env, head, &rsa->iqmp)
+ || !get_bn_from_bin(env, head, &rsa->iqmp)
|| !enif_is_empty_list(env, tail)))) {
return 0;
}
@@ -2053,11 +2211,11 @@ static ERL_NIF_TERM rsa_sign_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM ar
digest = data_bin.data;
}
else {
- if (!inspect_mpint(env,argv[1],&data_bin)) {
+ if (!enif_inspect_binary(env,argv[1],&data_bin)) {
return enif_make_badarg(env);
}
digest = hmacbuf;
- digp->funcp(data_bin.data+4, data_bin.size-4, digest);
+ digp->funcp(data_bin.data, data_bin.size, digest);
}
rsa = RSA_new();
@@ -2112,10 +2270,10 @@ static ERL_NIF_TERM dss_sign_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM ar
digest = data_bin.data;
}
else {
- if (!inspect_mpint(env,argv[1],&data_bin)) {
+ if (!enif_inspect_binary(env,argv[1],&data_bin)) {
return enif_make_badarg(env);
}
- SHA1(data_bin.data+4, data_bin.size-4, hmacbuf);
+ SHA1(data_bin.data, data_bin.size, hmacbuf);
digest = hmacbuf;
}
}
@@ -2133,13 +2291,13 @@ static ERL_NIF_TERM dss_sign_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM ar
dsa->pub_key = NULL;
if (!enif_get_list_cell(env, argv[2], &head, &tail)
- || !get_bn_from_mpint(env, head, &dsa->p)
+ || !get_bn_from_bin(env, head, &dsa->p)
|| !enif_get_list_cell(env, tail, &head, &tail)
- || !get_bn_from_mpint(env, head, &dsa->q)
+ || !get_bn_from_bin(env, head, &dsa->q)
|| !enif_get_list_cell(env, tail, &head, &tail)
- || !get_bn_from_mpint(env, head, &dsa->g)
+ || !get_bn_from_bin(env, head, &dsa->g)
|| !enif_get_list_cell(env, tail, &head, &tail)
- || !get_bn_from_mpint(env, head, &dsa->priv_key)
+ || !get_bn_from_bin(env, head, &dsa->priv_key)
|| !enif_is_empty_list(env,tail)) {
DSA_free(dsa);
return enif_make_badarg(env);
@@ -2187,9 +2345,9 @@ static ERL_NIF_TERM rsa_public_crypt(ErlNifEnv* env, int argc, const ERL_NIF_TER
if (!enif_inspect_binary(env, argv[0], &data_bin)
|| !enif_get_list_cell(env, argv[1], &head, &tail)
- || !get_bn_from_mpint(env, head, &rsa->e)
+ || !get_bn_from_bin(env, head, &rsa->e)
|| !enif_get_list_cell(env, tail, &head, &tail)
- || !get_bn_from_mpint(env, head, &rsa->n)
+ || !get_bn_from_bin(env, head, &rsa->n)
|| !enif_is_empty_list(env,tail)
|| !rsa_pad(argv[2], &padding)) {
@@ -2286,14 +2444,12 @@ static ERL_NIF_TERM dh_generate_parameters_nif(ErlNifEnv* env, int argc, const E
}
p_len = BN_num_bytes(dh_params->p);
g_len = BN_num_bytes(dh_params->g);
- p_ptr = enif_make_new_binary(env, p_len+4, &ret_p);
- g_ptr = enif_make_new_binary(env, g_len+4, &ret_g);
- put_int32(p_ptr, p_len);
- put_int32(g_ptr, g_len);
- BN_bn2bin(dh_params->p, p_ptr+4);
- BN_bn2bin(dh_params->g, g_ptr+4);
- ERL_VALGRIND_MAKE_MEM_DEFINED(p_ptr+4, p_len);
- ERL_VALGRIND_MAKE_MEM_DEFINED(g_ptr+4, g_len);
+ p_ptr = enif_make_new_binary(env, p_len, &ret_p);
+ g_ptr = enif_make_new_binary(env, g_len, &ret_g);
+ BN_bn2bin(dh_params->p, p_ptr);
+ BN_bn2bin(dh_params->g, g_ptr);
+ ERL_VALGRIND_MAKE_MEM_DEFINED(p_ptr, p_len);
+ ERL_VALGRIND_MAKE_MEM_DEFINED(g_ptr, g_len);
DH_free(dh_params);
return enif_make_list2(env, ret_p, ret_g);
}
@@ -2305,9 +2461,9 @@ static ERL_NIF_TERM dh_check(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]
ERL_NIF_TERM ret, head, tail;
if (!enif_get_list_cell(env, argv[0], &head, &tail)
- || !get_bn_from_mpint(env, head, &dh_params->p)
+ || !get_bn_from_bin(env, head, &dh_params->p)
|| !enif_get_list_cell(env, tail, &head, &tail)
- || !get_bn_from_mpint(env, head, &dh_params->g)
+ || !get_bn_from_bin(env, head, &dh_params->g)
|| !enif_is_empty_list(env,tail)) {
DH_free(dh_params);
@@ -2329,19 +2485,21 @@ static ERL_NIF_TERM dh_check(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]
}
static ERL_NIF_TERM dh_generate_key_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
-{/* (PrivKey, DHParams=[P,G]) */
+{/* (PrivKey, DHParams=[P,G], Mpint) */
DH* dh_params = DH_new();
int pub_len, prv_len;
unsigned char *pub_ptr, *prv_ptr;
ERL_NIF_TERM ret, ret_pub, ret_prv, head, tail;
+ int mpint; /* 0 or 4 */
- if (!(get_bn_from_mpint(env, argv[0], &dh_params->priv_key)
+ if (!(get_bn_from_bin(env, argv[0], &dh_params->priv_key)
|| argv[0] == atom_undefined)
|| !enif_get_list_cell(env, argv[1], &head, &tail)
- || !get_bn_from_mpint(env, head, &dh_params->p)
+ || !get_bn_from_bin(env, head, &dh_params->p)
|| !enif_get_list_cell(env, tail, &head, &tail)
- || !get_bn_from_mpint(env, head, &dh_params->g)
- || !enif_is_empty_list(env, tail)) {
+ || !get_bn_from_bin(env, head, &dh_params->g)
+ || !enif_is_empty_list(env, tail)
+ || !enif_get_int(env, argv[2], &mpint) || (mpint & ~4)) {
DH_free(dh_params);
return enif_make_badarg(env);
}
@@ -2349,14 +2507,16 @@ static ERL_NIF_TERM dh_generate_key_nif(ErlNifEnv* env, int argc, const ERL_NIF_
if (DH_generate_key(dh_params)) {
pub_len = BN_num_bytes(dh_params->pub_key);
prv_len = BN_num_bytes(dh_params->priv_key);
- pub_ptr = enif_make_new_binary(env, pub_len+4, &ret_pub);
- prv_ptr = enif_make_new_binary(env, prv_len+4, &ret_prv);
- put_int32(pub_ptr, pub_len);
- put_int32(prv_ptr, prv_len);
- BN_bn2bin(dh_params->pub_key, pub_ptr+4);
- BN_bn2bin(dh_params->priv_key, prv_ptr+4);
- ERL_VALGRIND_MAKE_MEM_DEFINED(pub_ptr+4, pub_len);
- ERL_VALGRIND_MAKE_MEM_DEFINED(prv_ptr+4, prv_len);
+ pub_ptr = enif_make_new_binary(env, pub_len+mpint, &ret_pub);
+ prv_ptr = enif_make_new_binary(env, prv_len+mpint, &ret_prv);
+ if (mpint) {
+ put_int32(pub_ptr, pub_len); pub_ptr += 4;
+ put_int32(prv_ptr, prv_len); prv_ptr += 4;
+ }
+ BN_bn2bin(dh_params->pub_key, pub_ptr);
+ BN_bn2bin(dh_params->priv_key, prv_ptr);
+ ERL_VALGRIND_MAKE_MEM_DEFINED(pub_ptr, pub_len);
+ ERL_VALGRIND_MAKE_MEM_DEFINED(prv_ptr, prv_len);
ret = enif_make_tuple2(env, ret_pub, ret_prv);
}
else {
@@ -2374,12 +2534,12 @@ static ERL_NIF_TERM dh_compute_key_nif(ErlNifEnv* env, int argc, const ERL_NIF_T
ErlNifBinary ret_bin;
ERL_NIF_TERM ret, head, tail;
- if (!get_bn_from_mpint(env, argv[0], &pubkey)
- || !get_bn_from_mpint(env, argv[1], &dh_params->priv_key)
+ if (!get_bn_from_bin(env, argv[0], &pubkey)
+ || !get_bn_from_bin(env, argv[1], &dh_params->priv_key)
|| !enif_get_list_cell(env, argv[2], &head, &tail)
- || !get_bn_from_mpint(env, head, &dh_params->p)
+ || !get_bn_from_bin(env, head, &dh_params->p)
|| !enif_get_list_cell(env, tail, &head, &tail)
- || !get_bn_from_mpint(env, head, &dh_params->g)
+ || !get_bn_from_bin(env, head, &dh_params->g)
|| !enif_is_empty_list(env, tail)) {
ret = enif_make_badarg(env);
@@ -2457,7 +2617,7 @@ static ERL_NIF_TERM srp_value_B_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM
return ret;
}
-static ERL_NIF_TERM srp_client_secret_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
+static ERL_NIF_TERM srp_user_secret_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
{/* (a, u, B, Multiplier, Prime, Exponent, Generator) */
/*
<premaster secret> = (B - (k * g^x)) ^ (a + (u * x)) % N
@@ -2537,7 +2697,7 @@ static ERL_NIF_TERM srp_client_secret_nif(ErlNifEnv* env, int argc, const ERL_NI
return ret;
}
-static ERL_NIF_TERM srp_server_secret_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
+static ERL_NIF_TERM srp_host_secret_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
{/* (Verifier, b, u, A, Prime) */
/*
<premaster secret> = (A * v^u) ^ b % N
@@ -2686,7 +2846,554 @@ static ERL_NIF_TERM blowfish_ofb64_encrypt(ErlNifEnv* env, int argc, const ERL_N
return ret;
}
+#if defined(HAVE_EC)
+static int term2curve_id(ERL_NIF_TERM nid)
+{
+ int i;
+
+ for (i = 0; i < EC_CURVES_CNT; i++)
+ if (ec_curves[i].atom == nid)
+ return ec_curves[i].nid;
+
+ return 0;
+}
+static EC_KEY* ec_key_new(ErlNifEnv* env, ERL_NIF_TERM curve_arg)
+{
+ EC_KEY *key = NULL;
+ int nid = 0;
+ int c_arity = -1;
+ const ERL_NIF_TERM* curve;
+ ErlNifBinary seed;
+ BIGNUM *p = NULL;
+ BIGNUM *a = NULL;
+ BIGNUM *b = NULL;
+ BIGNUM *bn_order = NULL;
+ BIGNUM *cofactor = NULL;
+ EC_GROUP *group = NULL;
+ EC_POINT *point = NULL;
+
+ if (enif_is_atom(env, curve_arg)) {
+ nid = term2curve_id(curve_arg);
+ if (nid == 0)
+ return NULL;
+ key = EC_KEY_new_by_curve_name(nid);
+ }
+ else if (enif_is_tuple(env, curve_arg)
+ && enif_get_tuple(env,curve_arg,&c_arity,&curve)
+ && c_arity == 5
+ && get_bn_from_bin(env, curve[3], &bn_order)
+ && (curve[4] != atom_none && get_bn_from_bin(env, curve[4], &cofactor))) {
+ //* {Field, Prime, Point, Order, CoFactor} = Curve */
+
+ int f_arity = -1;
+ const ERL_NIF_TERM* field;
+ int p_arity = -1;
+ const ERL_NIF_TERM* prime;
+
+ long field_bits;
+
+ /* {A, B, Seed} = Prime */
+ if (!enif_get_tuple(env,curve[1],&p_arity,&prime)
+ || !get_bn_from_bin(env, prime[0], &a)
+ || !get_bn_from_bin(env, prime[1], &b))
+ goto out_err;
+
+ if (!enif_get_tuple(env,curve[0],&f_arity,&field))
+ goto out_err;
+
+ if (f_arity == 2 && field[0] == atom_prime_field) {
+ /* {prime_field, Prime} */
+
+ if (!get_bn_from_bin(env, field[1], &p))
+ goto out_err;
+
+ if (BN_is_negative(p) || BN_is_zero(p))
+ goto out_err;
+
+ field_bits = BN_num_bits(p);
+ if (field_bits > OPENSSL_ECC_MAX_FIELD_BITS)
+ goto out_err;
+
+ /* create the EC_GROUP structure */
+ group = EC_GROUP_new_curve_GFp(p, a, b, NULL);
+
+ } else if (f_arity == 3 && field[0] == atom_characteristic_two_field) {
+ /* {characteristic_two_field, M, Basis} */
+
+ int b_arity = -1;
+ const ERL_NIF_TERM* basis;
+ unsigned int k1, k2, k3;
+
+ if ((p = BN_new()) == NULL)
+ goto out_err;
+
+ if (!enif_get_long(env, field[1], &field_bits)
+ || field_bits > OPENSSL_ECC_MAX_FIELD_BITS)
+ goto out_err;
+
+ if (enif_get_tuple(env,field[2],&b_arity,&basis)) {
+ if (b_arity == 2
+ && basis[0] == atom_tpbasis
+ && enif_get_uint(env, basis[1], &k1)) {
+ /* {tpbasis, k} = Basis */
+
+ if (!(field_bits > k1 && k1 > 0))
+ goto out_err;
+
+ /* create the polynomial */
+ if (!BN_set_bit(p, (int)field_bits)
+ || !BN_set_bit(p, (int)k1)
+ || !BN_set_bit(p, 0))
+ goto out_err;
+
+ } else if (b_arity == 4
+ && basis[0] == atom_ppbasis
+ && enif_get_uint(env, basis[1], &k1)
+ && enif_get_uint(env, basis[2], &k2)
+ && enif_get_uint(env, basis[3], &k3)) {
+ /* {ppbasis, k1, k2, k3} = Basis */
+
+ if (!(field_bits > k3 && k3 > k2 && k2 > k1 && k1 > 0))
+ goto out_err;
+
+ /* create the polynomial */
+ if (!BN_set_bit(p, (int)field_bits)
+ || !BN_set_bit(p, (int)k1)
+ || !BN_set_bit(p, (int)k2)
+ || !BN_set_bit(p, (int)k3)
+ || !BN_set_bit(p, 0))
+ goto out_err;
+
+ } else
+ goto out_err;
+ } else if (field[2] == atom_onbasis) {
+ /* onbasis = Basis */
+ /* no parameters */
+ goto out_err;
+
+ } else
+ goto out_err;
+
+ group = EC_GROUP_new_curve_GF2m(p, a, b, NULL);
+ } else
+ goto out_err;
+
+ if (enif_inspect_binary(env, prime[2], &seed)) {
+ EC_GROUP_set_seed(group, seed.data, seed.size);
+ }
+
+ if (!term2point(env, curve[2], group, &point))
+ goto out_err;
+
+ if (BN_is_negative(bn_order)
+ || BN_is_zero(bn_order)
+ || BN_num_bits(bn_order) > (int)field_bits + 1)
+ goto out_err;
+
+ if (!EC_GROUP_set_generator(group, point, bn_order, cofactor))
+ goto out_err;
+
+ EC_GROUP_set_asn1_flag(group, 0x0);
+
+ key = EC_KEY_new();
+ if (!key)
+ goto out_err;
+ EC_KEY_set_group(key, group);
+ }
+ else {
+ goto out_err;
+ }
+
+
+ goto out;
+
+out_err:
+ if (key) EC_KEY_free(key);
+ key = NULL;
+
+out:
+ /* some OpenSSL structures are mem-dup'ed into the key,
+ so we have to free our copies here */
+ if (p) BN_free(p);
+ if (a) BN_free(a);
+ if (b) BN_free(b);
+ if (bn_order) BN_free(bn_order);
+ if (cofactor) BN_free(cofactor);
+ if (group) EC_GROUP_free(group);
+
+ return key;
+}
+
+
+static ERL_NIF_TERM bn2term(ErlNifEnv* env, const BIGNUM *bn)
+{
+ unsigned dlen;
+ unsigned char* ptr;
+ ERL_NIF_TERM ret;
+
+ if (!bn)
+ return atom_undefined;
+
+ dlen = BN_num_bytes(bn);
+ ptr = enif_make_new_binary(env, dlen, &ret);
+ BN_bn2bin(bn, ptr);
+
+ return ret;
+}
+
+static ERL_NIF_TERM point2term(ErlNifEnv* env,
+ const EC_GROUP *group,
+ const EC_POINT *point,
+ point_conversion_form_t form)
+{
+ unsigned dlen;
+ ErlNifBinary bin;
+
+ dlen = EC_POINT_point2oct(group, point, form, NULL, 0, NULL);
+ if (dlen == 0)
+ return atom_undefined;
+
+ if (!enif_alloc_binary(dlen, &bin))
+ return enif_make_badarg(env);
+
+ if (!EC_POINT_point2oct(group, point, form, bin.data, bin.size, NULL)) {
+ enif_release_binary(&bin);
+ return enif_make_badarg(env);
+ }
+
+ return enif_make_binary(env, &bin);
+}
+#endif
+
+static ERL_NIF_TERM ec_key_to_term_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
+{
+#if defined(HAVE_EC)
+ struct nif_ec_key *obj;
+ const EC_GROUP *group;
+ const EC_POINT *public_key;
+ const BIGNUM *priv_key = NULL;
+ ERL_NIF_TERM pub_key = atom_undefined;
+
+ if (!enif_get_resource(env, argv[0], res_type_ec_key, (void **)&obj))
+ return enif_make_badarg(env);
+
+ group = EC_KEY_get0_group(obj->key);
+ public_key = EC_KEY_get0_public_key(obj->key);
+ priv_key = EC_KEY_get0_private_key(obj->key);
+
+ if (group) {
+ if (public_key)
+ pub_key = point2term(env, group, public_key, EC_KEY_get_conv_form(obj->key));
+ }
+
+ return enif_make_tuple2(env, bn2term(env, priv_key), pub_key);
+#else
+ return atom_notsup;
+#endif
+}
+
+#if defined(HAVE_EC)
+static int term2point(ErlNifEnv* env, ERL_NIF_TERM term,
+ EC_GROUP *group, EC_POINT **pptr)
+{
+ int ret = 0;
+ ErlNifBinary bin;
+ EC_POINT *point;
+
+ if (!enif_inspect_binary(env,term,&bin)) {
+ return 0;
+ }
+
+ if ((*pptr = point = EC_POINT_new(group)) == NULL) {
+ return 0;
+ }
+
+ /* set the point conversion form */
+ EC_GROUP_set_point_conversion_form(group, (point_conversion_form_t)(bin.data[0] & ~0x01));
+
+ /* extract the ec point */
+ if (!EC_POINT_oct2point(group, point, bin.data, bin.size, NULL)) {
+ EC_POINT_free(point);
+ *pptr = NULL;
+ } else
+ ret = 1;
+
+ return ret;
+}
+#endif
+
+static ERL_NIF_TERM term_to_ec_key_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
+{
+#if defined(HAVE_EC)
+ ERL_NIF_TERM ret;
+ EC_KEY *key = NULL;
+ BIGNUM *priv_key = NULL;
+ EC_POINT *pub_key = NULL;
+ struct nif_ec_key *obj;
+ EC_GROUP *group = NULL;
+
+ if (!(argv[1] == atom_undefined || get_bn_from_bin(env, argv[1], &priv_key))
+ || !(argv[2] == atom_undefined || enif_is_binary(env, argv[2]))) {
+ goto out_err;
+ }
+
+ key = ec_key_new(env, argv[0]);
+
+ if (!key) {
+ goto out_err;
+ }
+
+ if (!group)
+ group = EC_GROUP_dup(EC_KEY_get0_group(key));
+
+ if (term2point(env, argv[2], group, &pub_key)) {
+ if (!EC_KEY_set_public_key(key, pub_key)) {
+ goto out_err;
+ }
+ }
+ if (argv[1] != atom_undefined
+ && !BN_is_zero(priv_key)) {
+ if (!EC_KEY_set_private_key(key, priv_key))
+ goto out_err;
+
+ /* calculate public key (if necessary) */
+ if (EC_KEY_get0_public_key(key) == NULL)
+ {
+ /* the public key was not included in the SEC1 private
+ * key => calculate the public key */
+ pub_key = EC_POINT_new(group);
+ if (pub_key == NULL
+ || !EC_POINT_copy(pub_key, EC_GROUP_get0_generator(group))
+ || !EC_POINT_mul(group, pub_key, priv_key, NULL, NULL, NULL)
+ || !EC_KEY_set_public_key(key, pub_key))
+ goto out_err;
+ }
+ }
+
+ obj = enif_alloc_resource(res_type_ec_key, sizeof(struct nif_ec_key));
+ if (!obj)
+ goto out_err;
+
+ obj->key = key;
+ ret = enif_make_resource(env, obj);
+ enif_release_resource(obj);
+
+ goto out;
+
+out_err:
+ if (key) EC_KEY_free(key);
+ ret = enif_make_badarg(env);
+
+out:
+ /* some OpenSSL structures are mem-dup'ed into the key,
+ so we have to free our copies here */
+ if (priv_key) BN_clear_free(priv_key);
+ if (pub_key) EC_POINT_free(pub_key);
+ if (group) EC_GROUP_free(group);
+ return ret;
+#else
+ return atom_notsup;
+#endif
+}
+
+static ERL_NIF_TERM ec_key_generate(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
+{
+#if defined(HAVE_EC)
+ EC_KEY *key = ec_key_new(env, argv[0]);
+
+ if (key && EC_KEY_generate_key(key)) {
+ ERL_NIF_TERM term;
+ struct nif_ec_key *obj = enif_alloc_resource(res_type_ec_key, sizeof(struct nif_ec_key));
+ if (!obj)
+ return atom_error;
+ obj->key = key;
+ term = enif_make_resource(env, obj);
+ enif_release_resource(obj);
+ return term;
+ }
+ else
+ return enif_make_badarg(env);
+#else
+ return atom_notsup;
+#endif
+}
+
+#if defined(HAVE_EC)
+static void ec_key_dtor(ErlNifEnv* env, void* obj)
+{
+ struct nif_ec_key *key = (struct nif_ec_key*) obj;
+ EC_KEY_free(key->key);
+}
+#endif
+
+static ERL_NIF_TERM ecdsa_sign_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
+{/* (Type, Data|{digest,Digest}, Key) */
+#if defined(HAVE_EC)
+ ErlNifBinary data_bin, ret_bin;
+ unsigned char hmacbuf[SHA_DIGEST_LENGTH];
+ unsigned int dsa_s_len;
+ struct nif_ec_key *obj;
+ int i;
+ const ERL_NIF_TERM* tpl_terms;
+ int tpl_arity;
+ struct digest_type_t *digp;
+ unsigned char* digest;
+
+ digp = get_digest_type(argv[0]);
+ if (!digp) {
+ return enif_make_badarg(env);
+ }
+ if (!digp->len) {
+ return atom_notsup;
+ }
+
+ if (!enif_get_resource(env, argv[2], res_type_ec_key, (void **)&obj))
+ return enif_make_badarg(env);
+
+ if (enif_get_tuple(env, argv[1], &tpl_arity, &tpl_terms)) {
+ if (tpl_arity != 2 || tpl_terms[0] != atom_digest
+ || !enif_inspect_binary(env, tpl_terms[1], &data_bin)
+ || data_bin.size != digp->len) {
+
+ return enif_make_badarg(env);
+ }
+ digest = data_bin.data;
+ }
+ else {
+ if (!enif_inspect_binary(env,argv[1],&data_bin)) {
+ return enif_make_badarg(env);
+ }
+ digest = hmacbuf;
+ digp->funcp(data_bin.data, data_bin.size, digest);
+ }
+
+ enif_alloc_binary(ECDSA_size(obj->key), &ret_bin);
+
+ i = ECDSA_sign(digp->NID_type, digest, digp->len,
+ ret_bin.data, &dsa_s_len, obj->key);
+ if (i) {
+ if (dsa_s_len != ret_bin.size) {
+ enif_realloc_binary(&ret_bin, dsa_s_len);
+ }
+ return enif_make_binary(env, &ret_bin);
+ }
+ else {
+ enif_release_binary(&ret_bin);
+ return atom_error;
+ }
+#else
+ return atom_notsup;
+#endif
+}
+
+static ERL_NIF_TERM ecdsa_verify_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
+{/* (Type, Data|{digest,Digest}, Signature, Key) */
+#if defined(HAVE_EC)
+ ErlNifBinary data_bin, sign_bin;
+ unsigned char hmacbuf[SHA512_LEN];
+ int i;
+ struct nif_ec_key *obj;
+ const ERL_NIF_TERM type = argv[0];
+ const ERL_NIF_TERM* tpl_terms;
+ int tpl_arity;
+ struct digest_type_t* digp = NULL;
+ unsigned char* digest = NULL;
+
+ digp = get_digest_type(type);
+ if (!digp) {
+ return enif_make_badarg(env);
+ }
+ if (!digp->len) {
+ return atom_notsup;
+ }
+
+ if (!enif_inspect_binary(env, argv[2], &sign_bin)
+ || !enif_get_resource(env, argv[3], res_type_ec_key, (void **)&obj))
+ return enif_make_badarg(env);
+
+ if (enif_get_tuple(env, argv[1], &tpl_arity, &tpl_terms)) {
+ if (tpl_arity != 2 || tpl_terms[0] != atom_digest
+ || !enif_inspect_binary(env, tpl_terms[1], &data_bin)
+ || data_bin.size != digp->len) {
+
+ return enif_make_badarg(env);
+ }
+ digest = data_bin.data;
+ }
+ else if (enif_inspect_binary(env, argv[1], &data_bin)) {
+ digest = hmacbuf;
+ digp->funcp(data_bin.data, data_bin.size, digest);
+ }
+ else {
+ return enif_make_badarg(env);
+ }
+
+ i = ECDSA_verify(digp->NID_type, digest, digp->len,
+ sign_bin.data, sign_bin.size, obj->key);
+
+ return (i==1 ? atom_true : atom_false);
+#else
+ return atom_notsup;
+#endif
+}
+
+/*
+ (_OthersPublicKey, _MyPrivateKey)
+ (_OthersPublicKey, _MyEC_Point)
+*/
+static ERL_NIF_TERM ecdh_compute_key_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
+{
+#if defined(HAVE_EC)
+ ERL_NIF_TERM ret;
+ unsigned char *p;
+ struct nif_ec_key *other_key;
+ int field_size = 0;
+ int i;
+
+ EC_GROUP *group;
+ const BIGNUM *priv_key;
+ EC_POINT *my_ecpoint;
+ EC_KEY *other_ecdh = NULL;
+
+ if (!enif_get_resource(env, argv[1], res_type_ec_key, (void **)&other_key))
+ return enif_make_badarg(env);
+
+ group = EC_GROUP_dup(EC_KEY_get0_group(other_key->key));
+ priv_key = EC_KEY_get0_private_key(other_key->key);
+
+ if (!term2point(env, argv[0], group, &my_ecpoint)) {
+ goto out_err;
+ }
+
+ if ((other_ecdh = EC_KEY_new()) == NULL
+ || !EC_KEY_set_group(other_ecdh, group)
+ || !EC_KEY_set_private_key(other_ecdh, priv_key))
+ goto out_err;
+
+ field_size = EC_GROUP_get_degree(group);
+ if (field_size <= 0)
+ goto out_err;
+
+ p = enif_make_new_binary(env, (field_size+7)/8, &ret);
+ i = ECDH_compute_key(p, (field_size+7)/8, my_ecpoint, other_ecdh, NULL);
+
+ if (i < 0)
+ goto out_err;
+out:
+ if (group) EC_GROUP_free(group);
+ if (my_ecpoint) EC_POINT_free(my_ecpoint);
+ if (other_ecdh) EC_KEY_free(other_ecdh);
+
+ return ret;
+
+out_err:
+ ret = enif_make_badarg(env);
+ goto out;
+#else
+ return atom_notsup;
+#endif
+}
/* HMAC */
diff --git a/lib/crypto/doc/src/crypto.xml b/lib/crypto/doc/src/crypto.xml
index 7eca4557d9..df765ade87 100755..100644
--- a/lib/crypto/doc/src/crypto.xml
+++ b/lib/crypto/doc/src/crypto.xml
@@ -22,263 +22,222 @@
</legalnotice>
<title>crypto</title>
- <prepared>Peter H&ouml;gfeldt</prepared>
- <docno></docno>
- <date>2000-06-20</date>
- <rev>B</rev>
</header>
<module>crypto</module>
<modulesummary>Crypto Functions</modulesummary>
<description>
<p>This module provides a set of cryptographic functions.
</p>
- <p>References:</p>
<list type="bulleted">
<item>
- <p>md4: The MD4 Message Digest Algorithm (RFC 1320)</p>
- </item>
- <item>
- <p>md5: The MD5 Message Digest Algorithm (RFC 1321)</p>
- </item>
- <item>
- <p>sha: Secure Hash Standard (FIPS 180-2)</p>
- </item>
- <item>
- <p>hmac: Keyed-Hashing for Message Authentication (RFC 2104)</p>
- </item>
- <item>
- <p>des: Data Encryption Standard (FIPS 46-3)</p>
+ <p>Hash functions -
+ <url href="http://csrc.nist.gov/publications/fips/fips180-4/fips-180-4.pdf"> Secure Hash Standard</url>,
+ <url href="http://www.ietf.org/rfc/rfc1321.txt"> The MD5 Message Digest Algorithm (RFC 1321)</url> and
+ <url href="http://www.ietf.org/rfc/rfc1320.txt">The MD4 Message Digest Algorithm (RFC 1320)</url>
+ </p>
</item>
<item>
- <p>aes: Advanced Encryption Standard (AES) (FIPS 197) </p>
+ <p>Hmac functions - <url href="http://www.ietf.org/rfc/rfc2104.txt"> Keyed-Hashing for Message Authentication (RFC 2104) </url></p>
</item>
<item>
- <p>ecb, cbc, cfb, ofb, ctr: Recommendation for Block Cipher Modes
- of Operation (NIST SP 800-38A).</p>
+ <p>Block ciphers - <url href="http://csrc.nist.gov/groups/ST/toolkit/block_ciphers.html"> </url> DES and AES in
+ Block Cipher Modes - <url href="http://csrc.nist.gov/groups/ST/toolkit/BCM/index.html"> ECB, CBC, CFB, OFB and CTR </url></p>
</item>
<item>
- <p>rsa: Recommendation for Block Cipher Modes of Operation
- (NIST 800-38A)</p>
+ <p><url href="http://www.ietf.org/rfc/rfc1321.txt"> RSA encryption RFC 1321 </url> </p>
</item>
<item>
- <p>dss: Digital Signature Standard (FIPS 186-2)</p>
+ <p>Digital signatures <url href="http://csrc.nist.gov/publications/drafts/fips186-3/fips_186-3.pdf">Digital Signature Standard (DSS)</url> and<url href="http://csrc.nist.gov/groups/STM/cavp/documents/dss2/ecdsa2vs.pdf"> Elliptic Curve Digital
+ Signature Algorithm (ECDSA) </url> </p>
</item>
<item>
- <p>srp: Secure Remote Password Protocol (RFC 2945)</p>
+ <p><url href="http://www.ietf.org/rfc/rfc2945.txt"> Secure Remote Password Protocol (SRP - RFC 2945) </url></p>
</item>
-
-
</list>
- <p>The above publications can be found at <url href="http://csrc.nist.gov/publications">NIST publications</url>, at <url href="http://www.ietf.org">IETF</url>.
- </p>
- <p><em>Types</em></p>
- <pre>
-byte() = 0 ... 255
-ioelem() = byte() | binary() | iolist()
-iolist() = [ioelem()]
-Mpint() = <![CDATA[<<ByteLen:32/integer-big, Bytes:ByteLen/binary>>]]>
- </pre>
- <p></p>
</description>
+
+ <section>
+ <title>DATA TYPES </title>
+
+ <p><code>key_value() = integer() | binary() </code></p>
+
+ <p><code>rsa_public() = [key_value()] = [E, N] </code></p>
+ <p> Where E is the public exponent and N is public modulus. </p>
+
+ <p><code>rsa_private() = [key_value()] = [E, N, D] | [E, N, D, P1, P2, E1, E2, C] </code></p>
+ <p>Where E is the public exponent, N is public modulus and D is
+ the private exponent.The longer key format contains redundant
+ information that will make the calculation faster. P1,P2 are first
+ and second prime factors. E1,E2 are first and second exponents. C
+ is the CRT coefficient. Terminology is taken from <url href="http://www.ietf.org/rfc/rfc3477.txt"> RFC 3447</url>.</p>
+
+ <p><code>dss_public() = [key_value()] = [P, Q, G, Y] </code></p>
+ <p>Where P, Q and G are the dss parameters and Y is the public key.</p>
+
+ <p><code>dss_private() = [key_value()] = [P, Q, G, X] </code></p>
+ <p>Where P, Q and G are the dss parameters and X is the private key.</p>
+
+ <p><code>dss_public() = [key_value()] =[P, Q, G, Y] </code></p>
+
+ <p><code>srp_public() = key_value() </code></p>
+ <p>Where is <c>A</c> or <c>B</c> from <url href="http://srp.stanford.edu/design.html">SRP design</url></p>
+
+ <p><code>srp_private() = key_value() </code></p>
+ <p>Where is <c>a</c> or <c>b</c> from <url href="http://srp.stanford.edu/design.html">SRP design</url></p>
+
+ <p><code>srp_params() = {user, [Generator::binary(), Prime::binary(), Version::atom()]} |
+ {host, [Verifier::binary(), Generator::binary(), Prime::binary(), Version::atom()]}
+ | {user, [DerivedKey::binary(), Prime::binary(), Generator::binary(), Version::atom() | [Scrambler:binary()]]}
+ | {host,[Verifier::binary(), Prime::binary(), Version::atom() | [Scrambler::binary]]} </code></p>
+
+ <p>Where Verifier is <c>v</c>, Generator is <c>g</c> and Prime is<c> N</c>, DerivedKey is <c>X</c>, and Scrambler is
+ <c>u</c> (optional will be genrated if not provided) from <url href="http://srp.stanford.edu/design.html">SRP design</url>
+ Version = '3' | '6' | '6a'
+ </p>
+
+ <p><code>dh_public() = key_value() </code></p>
+
+ <p><code>dh_private() = key_value() </code></p>
+
+ <p><code>dh_params() = [key_value()] = [P, G] </code></p>
+
+ <p><code>ecdh_public() = key_value() </code></p>
+
+ <p><code>ecdh_private() = key_value() </code></p>
+
+ <p><code>ecdh_params() = ec_named_curve() |
+ {ec_field(), Prime :: key_value(), Point :: key_value(), Order :: integer(), CoFactor :: none | integer()} </code></p>
+
+ <p><code>ec_field() = {prime_field, Prime :: integer()} |
+ {characteristic_two_field, M :: integer(), Basis :: ec_basis()}</code></p>
+
+ <p><code>ec_basis() = {tpbasis, K :: non_neg_integer()} |
+ {ppbasis, K1 :: non_neg_integer(), K2 :: non_neg_integer(), K3 :: non_neg_integer()} |
+ onbasis</code></p>
+
+ <p><code>ec_named_curve() ->
+ sect571r1| sect571k1| sect409r1| sect409k1| secp521r1| secp384r1| secp224r1| secp224k1|
+ secp192k1| secp160r2| secp128r2| secp128r1| sect233r1| sect233k1| sect193r2| sect193r1|
+ sect131r2| sect131r1| sect283r1| sect283k1| sect163r2| secp256k1| secp160k1| secp160r1|
+ secp112r2| secp112r1| sect113r2| sect113r1| sect239k1| sect163r1| sect163k1| secp256r1|
+ secp192r1 </code></p>
+
+ <p><code>stream_cipher() = rc4 | aes_ctr </code></p>
+
+ <p><code>block_cipher() = aes_cbc128 | aes_cfb128 | blowfish_cbc |
+ blowfish_cfb64 | des_cbc | des_cfb | des3_cbc | des3_cbf
+ | des_ede3 | rc2_cbc </code></p>
+
+ <p><code>stream_key() = aes_key() | rc4_key() </code></p>
+
+ <p><code>block_key() = aes_key() | blowfish_key() | des_key()| des3_key() </code></p>
+
+ <p><code>aes_key() = iodata() </code> Key length is 128, 192 or 256 bits</p>
+
+ <p><code>rc4_key() = iodata() </code> Variable key length from 8 bits up to 2048 bits (usually between 40 and 256)</p>
+
+ <p><code>blowfish_key() = iodata() </code> Variable key length from 32 bits up to 448 bits</p>
+
+ <p><code>des_key() = iodata() </code> Key length is 64 bits (in CBC mode only 8 bits are used)</p>
+
+ <p><code>des3_key() = [binary(), binary(), binary()] </code> Each key part is 64 bits (in CBC mode only 8 bits are used)</p>
+
+ <p><code> message_digest_algorithms() = md5 | ripemd160 | sha | sha224 | sha256 | sha384 | sha512 </code> md4 is aslo supported for hash_init/1 and hash/2.
+ Note that both md4 and md5 are recommended only for compatibility with existing applications.
+ </p>
+ </section>
+
<funcs>
<func>
- <name>start() -> ok</name>
- <fsummary>Start the crypto server.</fsummary>
- <desc>
- <p>Starts the crypto server.</p>
- </desc>
- </func>
- <func>
- <name>stop() -> ok</name>
- <fsummary>Stop the crypto server.</fsummary>
- <desc>
- <p>Stops the crypto server.</p>
- </desc>
- </func>
- <func>
- <name>info() -> [atom()]</name>
- <fsummary>Provide a list of available crypto functions.</fsummary>
- <desc>
- <p>Provides the available crypto functions in terms of a list
- of atoms.</p>
- </desc>
- </func>
- <func>
- <name>algorithms() -> [atom()]</name>
+ <name>algorithms() -> [message_digest_algorithms() | md4 | ec]</name>
<fsummary>Provide a list of available crypto algorithms.</fsummary>
<desc>
- <p>Provides the available crypto algorithms in terms of a list
- of atoms.</p>
- </desc>
- </func>
- <func>
- <name>info_lib() -> [{Name,VerNum,VerStr}]</name>
- <fsummary>Provides information about the libraries used by crypto.</fsummary>
- <type>
- <v>Name = binary()</v>
- <v>VerNum = integer()</v>
- <v>VerStr = binary()</v>
- </type>
- <desc>
- <p>Provides the name and version of the libraries used by crypto.</p>
- <p><c>Name</c> is the name of the library. <c>VerNum</c> is
- the numeric version according to the library's own versioning
- scheme. <c>VerStr</c> contains a text variant of the version.</p>
- <pre>
-> <input>info_lib().</input>
-[{&lt;&lt;"OpenSSL"&gt;&gt;,9469983,&lt;&lt;"OpenSSL 0.9.8a 11 Oct 2005"&gt;&gt;}]
- </pre>
- <note><p>
- From OTP R16 the <em>numeric version</em> represents the version of the OpenSSL
- <em>header files</em> (<c>openssl/opensslv.h</c>) used when crypto was compiled.
- The text variant represents the OpenSSL library used at runtime.
- In earlier OTP versions both numeric and text was taken from the library.
- </p></note>
- </desc>
- </func>
- <func>
- <name>md4(Data) -> Digest</name>
- <fsummary>Compute an <c>MD4</c>message digest from <c>Data</c></fsummary>
- <type>
- <v>Data = iolist() | binary()</v>
- <v>Digest = binary()</v>
- </type>
- <desc>
- <p>Computes an <c>MD4</c> message digest from <c>Data</c>, where
- the length of the digest is 128 bits (16 bytes).</p>
- </desc>
- </func>
- <func>
- <name>md4_init() -> Context</name>
- <fsummary>Creates an MD4 context</fsummary>
- <type>
- <v>Context = binary()</v>
- </type>
- <desc>
- <p>Creates an MD4 context, to be used in subsequent calls to
- <c>md4_update/2</c>.</p>
- </desc>
- </func>
- <func>
- <name>md4_update(Context, Data) -> NewContext</name>
- <fsummary>Update an MD4 <c>Context</c>with <c>Data</c>, and return a <c>NewContext</c></fsummary>
- <type>
- <v>Data = iolist() | binary()</v>
- <v>Context = NewContext = binary()</v>
- </type>
- <desc>
- <p>Updates an MD4 <c>Context</c> with <c>Data</c>, and returns
- a <c>NewContext</c>.</p>
- </desc>
- </func>
- <func>
- <name>md4_final(Context) -> Digest</name>
- <fsummary>Finish the update of an MD4 <c>Context</c>and return the computed <c>MD4</c>message digest</fsummary>
- <type>
- <v>Context = Digest = binary()</v>
- </type>
- <desc>
- <p>Finishes the update of an MD4 <c>Context</c> and returns
- the computed <c>MD4</c> message digest.</p>
- </desc>
- </func>
- <func>
- <name>md5(Data) -> Digest</name>
- <fsummary>Compute an <c>MD5</c>message digest from <c>Data</c></fsummary>
- <type>
- <v>Data = iolist() | binary()</v>
- <v>Digest = binary()</v>
- </type>
- <desc>
- <p>Computes an <c>MD5</c> message digest from <c>Data</c>, where
- the length of the digest is 128 bits (16 bytes).</p>
+ <p> Can be used to determine if the crypto library has support for elliptic curve (ec) and
+ which message digest algorithms that are supported.</p>
</desc>
</func>
- <func>
- <name>md5_init() -> Context</name>
- <fsummary>Creates an MD5 context</fsummary>
- <type>
- <v>Context = binary()</v>
- </type>
- <desc>
- <p>Creates an MD5 context, to be used in subsequent calls to
- <c>md5_update/2</c>.</p>
- </desc>
- </func>
- <func>
- <name>md5_update(Context, Data) -> NewContext</name>
- <fsummary>Update an MD5 <c>Context</c>with <c>Data</c>, and return a <c>NewContext</c></fsummary>
- <type>
- <v>Data = iolist() | binary()</v>
- <v>Context = NewContext = binary()</v>
- </type>
- <desc>
- <p>Updates an MD5 <c>Context</c> with <c>Data</c>, and returns
- a <c>NewContext</c>.</p>
- </desc>
- </func>
- <func>
- <name>md5_final(Context) -> Digest</name>
- <fsummary>Finish the update of an MD5 <c>Context</c>and return the computed <c>MD5</c>message digest</fsummary>
+
+ <func>
+ <name>block_encrypt(Type, Key, Ivec, PlainText) -> CipherText</name>
+ <fsummary>Encrypt <c>PlainText</c>according to <c>Type</c> block cipher</fsummary>
<type>
- <v>Context = Digest = binary()</v>
+ <v>Key = block_key() </v>
+ <v>PlainText = iodata() </v>
+ <v>IVec = CipherText = binary()</v>
</type>
<desc>
- <p>Finishes the update of an MD5 <c>Context</c> and returns
- the computed <c>MD5</c> message digest.</p>
+ <p>Encrypt <c>PlainText</c>according to <c>Type</c> block cipher.
+ <c>IVec</c> is an arbitrary initializing vector.
+ </p>
</desc>
</func>
+
<func>
- <name>sha(Data) -> Digest</name>
- <fsummary>Compute an <c>SHA</c>message digest from <c>Data</c></fsummary>
+ <name>block_decrypt(Type, Key, Ivec, CipherText) -> PlainText</name>
+ <fsummary>Decrypt <c>CipherText</c>according to <c>Type</c> block cipher</fsummary>
<type>
- <v>Data = iolist() | binary()</v>
- <v>Digest = binary()</v>
+ <v>Key = block_key() </v>
+ <v>PlainText = iodata() </v>
+ <v>IVec = CipherText = binary()</v>
</type>
<desc>
- <p>Computes an <c>SHA</c> message digest from <c>Data</c>, where
- the length of the digest is 160 bits (20 bytes).</p>
+ <p>Decrypt <c>CipherText</c>according to <c>Type</c> block cipher.
+ <c>IVec</c> is an arbitrary initializing vector.
+ </p>
</desc>
</func>
+
<func>
- <name>sha_init() -> Context</name>
- <fsummary>Create an SHA context</fsummary>
+ <name>compute_key(Type, OthersPublicKey, MyPrivateKey, Params) -> SharedSecret</name>
+ <fsummary>Computes the shared secret</fsummary>
<type>
- <v>Context = binary()</v>
+ <v> Type = dh | ecdh | srp </v>
+ <v>OthersPublicKey = dh_public() | ecdh_public() | srp_public() </v>
+ <v>MyPrivate = dh_private() | ecdh_private() | srp_private() </v>
+ <v>Params = dh_params() | edhc_params() | srp_params() </v>
+ <v>SharedSecret = binary()</v>
</type>
<desc>
- <p>Creates an SHA context, to be used in subsequent calls to
- <c>sha_update/2</c>.</p>
+ <p>Computes the shared secret from the private key and the other party's public key.
+ See also <seealso marker="public_key:public_key#compute_key/2">public_key:compute_key/2</seealso>
+ </p>
</desc>
</func>
+
<func>
- <name>sha_update(Context, Data) -> NewContext</name>
- <fsummary>Update an SHA context</fsummary>
+ <name>exor(Data1, Data2) -> Result</name>
+ <fsummary>XOR data</fsummary>
<type>
- <v>Data = iolist() | binary()</v>
- <v>Context = NewContext = binary()</v>
+ <v>Data1, Data2 = iodata()</v>
+ <v>Result = binary()</v>
</type>
<desc>
- <p>Updates an SHA <c>Context</c> with <c>Data</c>, and returns
- a <c>NewContext</c>.</p>
+ <p>Performs bit-wise XOR (exclusive or) on the data supplied.</p>
</desc>
</func>
- <func>
- <name>sha_final(Context) -> Digest</name>
- <fsummary>Finish the update of an SHA context</fsummary>
+
+ <func>
+ <name>generate_key(Type, Params) -> {PublicKey, PrivateKey} </name>
+ <name>generate_key(Type, Params, PrivateKey) -> {PublicKey, PrivateKey} </name>
+ <fsummary>Generates a public keys of type <c>Type</c></fsummary>
<type>
- <v>Context = Digest = binary()</v>
+ <v> Type = dh | ecdh | srp </v>
+ <v>Params = dh_params() | edhc_params() | srp_params() </v>
+ <v>PublicKey = dh_public() | ecdh_public() | srp_public() </v>
+ <v>PrivateKey = dh_private() | ecdh_private() | srp_private() </v>
</type>
<desc>
- <p>Finishes the update of an SHA <c>Context</c> and returns
- the computed <c>SHA</c> message digest.</p>
+ <p>Generates public keys of type <c>Type</c>.
+ See also <seealso marker="public_key:public_key#generate_key/1">public_key:generate_key/1</seealso>
+ </p>
</desc>
</func>
- <func>
+
+ <func>
<name>hash(Type, Data) -> Digest</name>
<fsummary></fsummary>
<type>
- <v>Type = md4 | md5 | ripemd160 | sha | sha224 | sha256 | sha384 | sha512</v>
+ <v>Type = md4 | message_digest_algorithms()</v>
<v>Data = iodata()</v>
<v>Digest = binary()</v>
</type>
@@ -288,11 +247,12 @@ Mpint() = <![CDATA[<<ByteLen:32/integer-big, Bytes:ByteLen/binary>>]]>
is not supported by the underlying OpenSSL implementation.</p>
</desc>
</func>
+
<func>
<name>hash_init(Type) -> Context</name>
<fsummary></fsummary>
<type>
- <v>Type = md4 | md5 | ripemd160 | sha | sha224 | sha256 | sha384 | sha512</v>
+ <v>Type = md4 | message_digest_algorithms()</v>
</type>
<desc>
<p>Initializes the context for streaming hash operations. <c>Type</c> determines
@@ -302,6 +262,7 @@ Mpint() = <![CDATA[<<ByteLen:32/integer-big, Bytes:ByteLen/binary>>]]>
is not supported by the underlying OpenSSL implementation.</p>
</desc>
</func>
+
<func>
<name>hash_update(Context, Data) -> NewContext</name>
<fsummary></fsummary>
@@ -329,38 +290,13 @@ Mpint() = <![CDATA[<<ByteLen:32/integer-big, Bytes:ByteLen/binary>>]]>
function used to generate it.</p>
</desc>
</func>
- <func>
- <name>md5_mac(Key, Data) -> Mac</name>
- <fsummary>Compute an <c>MD5 MAC</c>message authentification code</fsummary>
- <type>
- <v>Key = Data = iolist() | binary()</v>
- <v>Mac = binary()</v>
- </type>
- <desc>
- <p>Computes an <c>MD5 MAC</c> message authentification code
- from <c>Key</c> and <c>Data</c>, where the the length of the
- Mac is 128 bits (16 bytes).</p>
- </desc>
- </func>
- <func>
- <name>md5_mac_96(Key, Data) -> Mac</name>
- <fsummary>Compute an <c>MD5 MAC</c>message authentification code</fsummary>
- <type>
- <v>Key = Data = iolist() | binary()</v>
- <v>Mac = binary()</v>
- </type>
- <desc>
- <p>Computes an <c>MD5 MAC</c> message authentification code
- from <c>Key</c> and <c>Data</c>, where the length of the Mac
- is 96 bits (12 bytes).</p>
- </desc>
- </func>
+
<func>
<name>hmac(Type, Key, Data) -> Mac</name>
<name>hmac(Type, Key, Data, MacLength) -> Mac</name>
<fsummary></fsummary>
<type>
- <v>Type = md5 | sha | sha224 | sha256 | sha384 | sha512</v>
+ <v>Type = message_digest_algorithms() </v>
<v>Key = iodata()</v>
<v>Data = iodata()</v>
<v>MacLength = integer()</v>
@@ -372,12 +308,13 @@ Mpint() = <![CDATA[<<ByteLen:32/integer-big, Bytes:ByteLen/binary>>]]>
will limit the size of the resultant <c>Mac</c>.
</desc>
</func>
+
<func>
<name>hmac_init(Type, Key) -> Context</name>
<fsummary></fsummary>
<type>
- <v>Type = md5 | ripemd160 | sha | sha224 | sha256 | sha384 | sha512</v>
- <v>Key = iolist() | binary()</v>
+ <v>Type = message_digest_algorithms()</v>
+ <v>Key = iodata()</v>
<v>Context = binary()</v>
</type>
<desc>
@@ -386,20 +323,26 @@ Mpint() = <![CDATA[<<ByteLen:32/integer-big, Bytes:ByteLen/binary>>]]>
key. The key can be any length.</p>
</desc>
</func>
+
<func>
<name>hmac_update(Context, Data) -> NewContext</name>
<fsummary></fsummary>
<type>
<v>Context = NewContext = binary()</v>
- <v>Data = iolist() | binary()</v>
+ <v>Data = iodata()</v>
</type>
<desc>
<p>Updates the HMAC represented by <c>Context</c> using the given <c>Data</c>. <c>Context</c>
must have been generated using an HMAC init function (such as
<seealso marker="#hmac_init/2">hmac_init</seealso>). <c>Data</c> can be any length. <c>NewContext</c>
- must be passed into the next call to <c>hmac_update</c>.</p>
+ must be passed into the next call to <c>hmac_update</c>
+ or to one of the functions <seealso marker="#hmac_final/1">hmac_final</seealso> and
+ <seealso marker="#hmac_final_n/1">hmac_final_n</seealso>
+ </p>
+
</desc>
</func>
+
<func>
<name>hmac_final(Context) -> Mac</name>
<fsummary></fsummary>
@@ -411,6 +354,7 @@ Mpint() = <![CDATA[<<ByteLen:32/integer-big, Bytes:ByteLen/binary>>]]>
determined by the type of hash function used to generate it.</p>
</desc>
</func>
+
<func>
<name>hmac_final_n(Context, HashLen) -> Mac</name>
<fsummary></fsummary>
@@ -423,705 +367,88 @@ Mpint() = <![CDATA[<<ByteLen:32/integer-big, Bytes:ByteLen/binary>>]]>
zero. <c>Mac</c> will be a binary with at most <c>HashLen</c> bytes. Note that if HashLen is greater than the actual number of bytes returned from the underlying hash, the returned hash will have fewer than <c>HashLen</c> bytes.</p>
</desc>
</func>
- <func>
- <name>sha_mac(Key, Data) -> Mac</name>
- <name>sha_mac(Key, Data, MacLength) -> Mac</name>
- <fsummary>Compute an <c>MD5 MAC</c>message authentification code</fsummary>
- <type>
- <v>Key = Data = iolist() | binary()</v>
- <v>Mac = binary()</v>
- <v>MacLenength = integer() =&lt; 20 </v>
- </type>
- <desc>
- <p>Computes an <c>SHA MAC</c> message authentification code
- from <c>Key</c> and <c>Data</c>, where the default length of the Mac
- is 160 bits (20 bytes).</p>
- </desc>
- </func>
- <func>
- <name>sha_mac_96(Key, Data) -> Mac</name>
- <fsummary>Compute an <c>SHA MAC</c>message authentification code</fsummary>
- <type>
- <v>Key = Data = iolist() | binary()</v>
- <v>Mac = binary()</v>
- </type>
- <desc>
- <p>Computes an <c>SHA MAC</c> message authentification code
- from <c>Key</c> and <c>Data</c>, where the length of the Mac
- is 96 bits (12 bytes).</p>
- </desc>
- </func>
- <func>
- <name>des_cbc_encrypt(Key, IVec, Text) -> Cipher</name>
- <fsummary>Encrypt <c>Text</c>according to DES in CBC mode</fsummary>
- <type>
- <v>Key = Text = iolist() | binary()</v>
- <v>IVec = Cipher = binary()</v>
- </type>
- <desc>
- <p>Encrypts <c>Text</c> according to DES in CBC
- mode. <c>Text</c> must be a multiple of 64 bits (8
- bytes). <c>Key</c> is the DES key, and <c>IVec</c> is an
- arbitrary initializing vector. The lengths of <c>Key</c> and
- <c>IVec</c> must be 64 bits (8 bytes).</p>
- </desc>
- </func>
- <func>
- <name>des_cbc_decrypt(Key, IVec, Cipher) -> Text</name>
- <fsummary>Decrypt <c>Cipher</c>according to DES in CBC mode</fsummary>
- <type>
- <v>Key = Cipher = iolist() | binary()</v>
- <v>IVec = Text = binary()</v>
- </type>
- <desc>
- <p>Decrypts <c>Cipher</c> according to DES in CBC mode.
- <c>Key</c> is the DES key, and <c>IVec</c> is an arbitrary
- initializing vector. <c>Key</c> and <c>IVec</c> must have
- the same values as those used when encrypting. <c>Cipher</c>
- must be a multiple of 64 bits (8 bytes). The lengths of
- <c>Key</c> and <c>IVec</c> must be 64 bits (8 bytes).</p>
- </desc>
- </func>
- <func>
- <name>des_cbc_ivec(Data) -> IVec</name>
- <fsummary>Get <c>IVec</c> to be used in next iteration of
- <c>des_cbc_[ecrypt|decrypt]</c></fsummary>
- <type>
- <v>Data = iolist() | binary()</v>
- <v>IVec = binary()</v>
- </type>
- <desc>
- <p>Returns the <c>IVec</c> to be used in a next iteration of
- <c>des_cbc_[encrypt|decrypt]</c>. <c>Data</c> is the encrypted
- data from the previous iteration step.</p>
- </desc>
- </func>
- <func>
- <name>des_cfb_encrypt(Key, IVec, Text) -> Cipher</name>
- <fsummary>Encrypt <c>Text</c>according to DES in CFB mode</fsummary>
- <type>
- <v>Key = Text = iolist() | binary()</v>
- <v>IVec = Cipher = binary()</v>
- </type>
- <desc>
- <p>Encrypts <c>Text</c> according to DES in 8-bit CFB
- mode. <c>Key</c> is the DES key, and <c>IVec</c> is an
- arbitrary initializing vector. The lengths of <c>Key</c> and
- <c>IVec</c> must be 64 bits (8 bytes).</p>
- </desc>
- </func>
- <func>
- <name>des_cfb_decrypt(Key, IVec, Cipher) -> Text</name>
- <fsummary>Decrypt <c>Cipher</c>according to DES in CFB mode</fsummary>
- <type>
- <v>Key = Cipher = iolist() | binary()</v>
- <v>IVec = Text = binary()</v>
- </type>
- <desc>
- <p>Decrypts <c>Cipher</c> according to DES in 8-bit CFB mode.
- <c>Key</c> is the DES key, and <c>IVec</c> is an arbitrary
- initializing vector. <c>Key</c> and <c>IVec</c> must have
- the same values as those used when encrypting. The lengths of
- <c>Key</c> and <c>IVec</c> must be 64 bits (8 bytes).</p>
- </desc>
- </func>
- <func>
- <name>des_cfb_ivec(IVec, Data) -> NextIVec</name>
- <fsummary>Get <c>IVec</c> to be used in next iteration of
- <c>des_cfb_[ecrypt|decrypt]</c></fsummary>
- <type>
- <v>IVec = iolist() | binary()</v>
- <v>Data = iolist() | binary()</v>
- <v>NextIVec = binary()</v>
- </type>
- <desc>
- <p>Returns the <c>IVec</c> to be used in a next iteration of
- <c>des_cfb_[encrypt|decrypt]</c>. <c>IVec</c> is the vector
- used in the previous iteration step. <c>Data</c> is the encrypted
- data from the previous iteration step.</p>
- </desc>
- </func>
- <func>
- <name>des3_cbc_encrypt(Key1, Key2, Key3, IVec, Text) -> Cipher</name>
- <fsummary>Encrypt <c>Text</c>according to DES3 in CBC mode</fsummary>
- <type>
- <v>Key1 =Key2 = Key3 Text = iolist() | binary()</v>
- <v>IVec = Cipher = binary()</v>
- </type>
- <desc>
- <p>Encrypts <c>Text</c> according to DES3 in CBC
- mode. <c>Text</c> must be a multiple of 64 bits (8
- bytes). <c>Key1</c>, <c>Key2</c>, <c>Key3</c>, are the DES
- keys, and <c>IVec</c> is an arbitrary initializing
- vector. The lengths of each of <c>Key1</c>, <c>Key2</c>,
- <c>Key3</c> and <c>IVec</c> must be 64 bits (8 bytes).</p>
- </desc>
- </func>
- <func>
- <name>des3_cbc_decrypt(Key1, Key2, Key3, IVec, Cipher) -> Text</name>
- <fsummary>Decrypt <c>Cipher</c>according to DES3 in CBC mode</fsummary>
- <type>
- <v>Key1 = Key2 = Key3 = Cipher = iolist() | binary()</v>
- <v>IVec = Text = binary()</v>
- </type>
- <desc>
- <p>Decrypts <c>Cipher</c> according to DES3 in CBC mode.
- <c>Key1</c>, <c>Key2</c>, <c>Key3</c> are the DES key, and
- <c>IVec</c> is an arbitrary initializing vector.
- <c>Key1</c>, <c>Key2</c>, <c>Key3</c> and <c>IVec</c> must
- and <c>IVec</c> must have the same values as those used when
- encrypting. <c>Cipher</c> must be a multiple of 64 bits (8
- bytes). The lengths of <c>Key1</c>, <c>Key2</c>,
- <c>Key3</c>, and <c>IVec</c> must be 64 bits (8 bytes).</p>
- </desc>
- </func>
- <func>
- <name>des3_cfb_encrypt(Key1, Key2, Key3, IVec, Text) -> Cipher</name>
- <fsummary>Encrypt <c>Text</c>according to DES3 in CFB mode</fsummary>
- <type>
- <v>Key1 =Key2 = Key3 Text = iolist() | binary()</v>
- <v>IVec = Cipher = binary()</v>
- </type>
- <desc>
- <p>Encrypts <c>Text</c> according to DES3 in 8-bit CFB
- mode. <c>Key1</c>, <c>Key2</c>, <c>Key3</c>, are the DES
- keys, and <c>IVec</c> is an arbitrary initializing
- vector. The lengths of each of <c>Key1</c>, <c>Key2</c>,
- <c>Key3</c> and <c>IVec</c> must be 64 bits (8 bytes).</p>
- <p>May throw exception <c>notsup</c> for old OpenSSL
- versions (0.9.7) that does not support this encryption mode.</p>
- </desc>
- </func>
- <func>
- <name>des3_cfb_decrypt(Key1, Key2, Key3, IVec, Cipher) -> Text</name>
- <fsummary>Decrypt <c>Cipher</c>according to DES3 in CFB mode</fsummary>
- <type>
- <v>Key1 = Key2 = Key3 = Cipher = iolist() | binary()</v>
- <v>IVec = Text = binary()</v>
- </type>
- <desc>
- <p>Decrypts <c>Cipher</c> according to DES3 in 8-bit CFB mode.
- <c>Key1</c>, <c>Key2</c>, <c>Key3</c> are the DES key, and
- <c>IVec</c> is an arbitrary initializing vector.
- <c>Key1</c>, <c>Key2</c>, <c>Key3</c> and <c>IVec</c> must
- and <c>IVec</c> must have the same values as those used when
- encrypting. The lengths of <c>Key1</c>, <c>Key2</c>,
- <c>Key3</c>, and <c>IVec</c> must be 64 bits (8 bytes).</p>
- <p>May throw exception <c>notsup</c> for old OpenSSL
- versions (0.9.7) that does not support this encryption mode.</p>
- </desc>
- </func>
-
- <func>
- <name>des_ecb_encrypt(Key, Text) -> Cipher</name>
- <fsummary>Encrypt <c>Text</c>according to DES in ECB mode</fsummary>
- <type>
- <v>Key = Text = iolist() | binary()</v>
- <v>Cipher = binary()</v>
- </type>
- <desc>
- <p>Encrypts <c>Text</c> according to DES in ECB mode.
- <c>Key</c> is the DES key. The lengths of <c>Key</c> and
- <c>Text</c> must be 64 bits (8 bytes).</p>
- </desc>
- </func>
- <func>
- <name>des_ecb_decrypt(Key, Cipher) -> Text</name>
- <fsummary>Decrypt <c>Cipher</c>according to DES in ECB mode</fsummary>
- <type>
- <v>Key = Cipher = iolist() | binary()</v>
- <v>Text = binary()</v>
- </type>
- <desc>
- <p>Decrypts <c>Cipher</c> according to DES in ECB mode.
- <c>Key</c> is the DES key. The lengths of <c>Key</c> and
- <c>Cipher</c> must be 64 bits (8 bytes).</p>
- </desc>
- </func>
-
- <func>
- <name>blowfish_ecb_encrypt(Key, Text) -> Cipher</name>
- <fsummary>Encrypt the first 64 bits of <c>Text</c> using Blowfish in ECB mode</fsummary>
- <type>
- <v>Key = Text = iolist() | binary()</v>
- <v>Cipher = binary()</v>
- </type>
- <desc>
- <p>Encrypts the first 64 bits of <c>Text</c> using Blowfish in ECB mode. <c>Key</c> is the Blowfish key. The length of <c>Text</c> must be at least 64 bits (8 bytes).</p>
- </desc>
- </func>
- <func>
- <name>blowfish_ecb_decrypt(Key, Text) -> Cipher</name>
- <fsummary>Decrypt the first 64 bits of <c>Text</c> using Blowfish in ECB mode</fsummary>
- <type>
- <v>Key = Text = iolist() | binary()</v>
- <v>Cipher = binary()</v>
- </type>
- <desc>
- <p>Decrypts the first 64 bits of <c>Text</c> using Blowfish in ECB mode. <c>Key</c> is the Blowfish key. The length of <c>Text</c> must be at least 64 bits (8 bytes).</p>
- </desc>
- </func>
-
- <func>
- <name>blowfish_cbc_encrypt(Key, IVec, Text) -> Cipher</name>
- <fsummary>Encrypt <c>Text</c> using Blowfish in CBC mode</fsummary>
- <type>
- <v>Key = Text = iolist() | binary()</v>
- <v>IVec = Cipher = binary()</v>
- </type>
- <desc>
- <p>Encrypts <c>Text</c> using Blowfish in CBC mode. <c>Key</c> is the Blowfish key, and <c>IVec</c> is an
- arbitrary initializing vector. The length of <c>IVec</c>
- must be 64 bits (8 bytes). The length of <c>Text</c> must be a multiple of 64 bits (8 bytes).</p>
- </desc>
- </func>
- <func>
- <name>blowfish_cbc_decrypt(Key, IVec, Text) -> Cipher</name>
- <fsummary>Decrypt <c>Text</c> using Blowfish in CBC mode</fsummary>
- <type>
- <v>Key = Text = iolist() | binary()</v>
- <v>IVec = Cipher = binary()</v>
- </type>
- <desc>
- <p>Decrypts <c>Text</c> using Blowfish in CBC mode. <c>Key</c> is the Blowfish key, and <c>IVec</c> is an
- arbitrary initializing vector. The length of <c>IVec</c>
- must be 64 bits (8 bytes). The length of <c>Text</c> must be a multiple 64 bits (8 bytes).</p>
- </desc>
- </func>
-
- <func>
- <name>blowfish_cfb64_encrypt(Key, IVec, Text) -> Cipher</name>
- <fsummary>Encrypt <c>Text</c>using Blowfish in CFB mode with 64
- bit feedback</fsummary>
- <type>
- <v>Key = Text = iolist() | binary()</v>
- <v>IVec = Cipher = binary()</v>
- </type>
- <desc>
- <p>Encrypts <c>Text</c> using Blowfish in CFB mode with 64 bit
- feedback. <c>Key</c> is the Blowfish key, and <c>IVec</c> is an
- arbitrary initializing vector. The length of <c>IVec</c>
- must be 64 bits (8 bytes).</p>
- </desc>
- </func>
- <func>
- <name>blowfish_cfb64_decrypt(Key, IVec, Text) -> Cipher</name>
- <fsummary>Decrypt <c>Text</c>using Blowfish in CFB mode with 64
- bit feedback</fsummary>
- <type>
- <v>Key = Text = iolist() | binary()</v>
- <v>IVec = Cipher = binary()</v>
- </type>
- <desc>
- <p>Decrypts <c>Text</c> using Blowfish in CFB mode with 64 bit
- feedback. <c>Key</c> is the Blowfish key, and <c>IVec</c> is an
- arbitrary initializing vector. The length of <c>IVec</c>
- must be 64 bits (8 bytes).</p>
- </desc>
- </func>
<func>
- <name>blowfish_ofb64_encrypt(Key, IVec, Text) -> Cipher</name>
- <fsummary>Encrypt <c>Text</c>using Blowfish in OFB mode with 64
- bit feedback</fsummary>
+ <name>info_lib() -> [{Name,VerNum,VerStr}]</name>
+ <fsummary>Provides information about the libraries used by crypto.</fsummary>
<type>
- <v>Key = Text = iolist() | binary()</v>
- <v>IVec = Cipher = binary()</v>
+ <v>Name = binary()</v>
+ <v>VerNum = integer()</v>
+ <v>VerStr = binary()</v>
</type>
<desc>
- <p>Encrypts <c>Text</c> using Blowfish in OFB mode with 64 bit
- feedback. <c>Key</c> is the Blowfish key, and <c>IVec</c> is an
- arbitrary initializing vector. The length of <c>IVec</c>
- must be 64 bits (8 bytes).</p>
+ <p>Provides the name and version of the libraries used by crypto.</p>
+ <p><c>Name</c> is the name of the library. <c>VerNum</c> is
+ the numeric version according to the library's own versioning
+ scheme. <c>VerStr</c> contains a text variant of the version.</p>
+ <pre>
+> <input>info_lib().</input>
+[{&lt;&lt;"OpenSSL"&gt;&gt;,9469983,&lt;&lt;"OpenSSL 0.9.8a 11 Oct 2005"&gt;&gt;}]
+ </pre>
+ <note><p>
+ From OTP R16 the <em>numeric version</em> represents the version of the OpenSSL
+ <em>header files</em> (<c>openssl/opensslv.h</c>) used when crypto was compiled.
+ The text variant represents the OpenSSL library used at runtime.
+ In earlier OTP versions both numeric and text was taken from the library.
+ </p></note>
</desc>
</func>
<func>
- <name>aes_cfb_128_encrypt(Key, IVec, Text) -> Cipher</name>
- <fsummary>Encrypt <c>Text</c>according to AES in Cipher Feedback mode</fsummary>
- <type>
- <v>Key = Text = iolist() | binary()</v>
- <v>IVec = Cipher = binary()</v>
- </type>
- <desc>
- <p>Encrypts <c>Text</c> according to AES in Cipher Feedback
- mode (CFB). <c>Key</c> is the
- AES key, and <c>IVec</c> is an arbitrary initializing vector.
- The lengths of <c>Key</c> and <c>IVec</c> must be 128 bits
- (16 bytes).</p>
- </desc>
- </func>
- <func>
- <name>aes_cfb_128_decrypt(Key, IVec, Cipher) -> Text</name>
- <fsummary>Decrypt <c>Cipher</c>according to AES in Cipher Feedback mode</fsummary>
- <type>
- <v>Key = Cipher = iolist() | binary()</v>
- <v>IVec = Text = binary()</v>
- </type>
- <desc>
- <p>Decrypts <c>Cipher</c> according to AES in Cipher Feedback Mode (CFB).
- <c>Key</c> is the AES key, and <c>IVec</c> is an arbitrary
- initializing vector. <c>Key</c> and <c>IVec</c> must have
- the same values as those used when encrypting. The lengths of
- <c>Key</c> and <c>IVec</c> must be 128 bits (16 bytes).</p>
- </desc>
- </func>
- <func>
- <name>aes_cbc_128_encrypt(Key, IVec, Text) -> Cipher</name>
- <fsummary>Encrypt <c>Text</c>according to AES in Cipher Block Chaining mode</fsummary>
- <type>
- <v>Key = Text = iolist() | binary()</v>
- <v>IVec = Cipher = binary()</v>
- </type>
- <desc>
- <p>Encrypts <c>Text</c> according to AES in Cipher Block Chaining
- mode (CBC). <c>Text</c>
- must be a multiple of 128 bits (16 bytes). <c>Key</c> is the
- AES key, and <c>IVec</c> is an arbitrary initializing vector.
- The lengths of <c>Key</c> and <c>IVec</c> must be 128 bits
- (16 bytes).</p>
- </desc>
- </func>
- <func>
- <name>aes_cbc_128_decrypt(Key, IVec, Cipher) -> Text</name>
- <fsummary>Decrypt <c>Cipher</c>according to AES in Cipher Block Chaining mode</fsummary>
- <type>
- <v>Key = Cipher = iolist() | binary()</v>
- <v>IVec = Text = binary()</v>
- </type>
- <desc>
- <p>Decrypts <c>Cipher</c> according to AES in Cipher Block
- Chaining mode (CBC).
- <c>Key</c> is the AES key, and <c>IVec</c> is an arbitrary
- initializing vector. <c>Key</c> and <c>IVec</c> must have
- the same values as those used when encrypting. <c>Cipher</c>
- must be a multiple of 128 bits (16 bytes). The lengths of
- <c>Key</c> and <c>IVec</c> must be 128 bits (16 bytes).</p>
- </desc>
- </func>
- <func>
- <name>aes_cbc_ivec(Data) -> IVec</name>
- <fsummary>Get <c>IVec</c> to be used in next iteration of
- <c>aes_cbc_*_[ecrypt|decrypt]</c></fsummary>
- <type>
- <v>Data = iolist() | binary()</v>
- <v>IVec = binary()</v>
- </type>
- <desc>
- <p>Returns the <c>IVec</c> to be used in a next iteration of
- <c>aes_cbc_*_[encrypt|decrypt]</c>. <c>Data</c> is the encrypted
- data from the previous iteration step.</p>
- </desc>
- </func>
- <func>
- <name>aes_ctr_encrypt(Key, IVec, Text) -> Cipher</name>
- <fsummary>Encrypt <c>Text</c>according to AES in Counter mode</fsummary>
- <type>
- <v>Key = Text = iolist() | binary()</v>
- <v>IVec = Cipher = binary()</v>
- </type>
- <desc>
- <p>Encrypts <c>Text</c> according to AES in Counter mode (CTR). <c>Text</c>
- can be any number of bytes. <c>Key</c> is the AES key and must be either
- 128, 192 or 256 bits long. <c>IVec</c> is an arbitrary initializing vector of 128 bits
- (16 bytes).</p>
- </desc>
- </func>
- <func>
- <name>aes_ctr_decrypt(Key, IVec, Cipher) -> Text</name>
- <fsummary>Decrypt <c>Cipher</c>according to AES in Counter mode</fsummary>
- <type>
- <v>Key = Cipher = iolist() | binary()</v>
- <v>IVec = Text = binary()</v>
- </type>
- <desc>
- <p>Decrypts <c>Cipher</c> according to AES in Counter mode (CTR). <c>Cipher</c>
- can be any number of bytes. <c>Key</c> is the AES key and must be either
- 128, 192 or 256 bits long. <c>IVec</c> is an arbitrary initializing vector of 128 bits
- (16 bytes).</p>
- </desc>
- </func>
- <func>
- <name>aes_ctr_stream_init(Key, IVec) -> State</name>
- <fsummary></fsummary>
- <type>
- <v>State = { K, I, E, C }</v>
- <v>Key = K = iolist()</v>
- <v>IVec = I = E = binary()</v>
- <v>C = integer()</v>
- </type>
- <desc>
- <p>Initializes the state for use in streaming AES encryption using Counter mode (CTR).
- <c>Key</c> is the AES key and must be either 128, 192, or 256 bts long. <c>IVec</c> is
- an arbitrary initializing vector of 128 bits (16 bytes). This state is for use with
- <seealso marker="#aes_ctr_stream_encrypt/2">aes_ctr_stream_encrypt</seealso> and
- <seealso marker="#aes_ctr_stream_decrypt/2">aes_ctr_stream_decrypt</seealso>.</p>
- </desc>
- </func>
- <func>
- <name>aes_ctr_stream_encrypt(State, Text) -> { NewState, Cipher}</name>
- <fsummary></fsummary>
- <type>
- <v>Text = iolist() | binary()</v>
- <v>Cipher = binary()</v>
- </type>
- <desc>
- <p>Encrypts <c>Text</c> according to AES in Counter mode (CTR). This function can be
- used to encrypt a stream of text using a series of calls instead of requiring all
- text to be in memory. <c>Text</c> can be any number of bytes. State is initialized using
- <seealso marker="#aes_ctr_stream_init/2">aes_ctr_stream_init</seealso>. <c>NewState</c> is the new streaming
- encryption state that must be passed to the next call to <c>aes_ctr_stream_encrypt</c>.
- <c>Cipher</c> is the encrypted cipher text.</p>
- </desc>
- </func>
- <func>
- <name>aes_ctr_stream_decrypt(State, Cipher) -> { NewState, Text }</name>
- <fsummary></fsummary>
- <type>
- <v>Cipher = iolist() | binary()</v>
- <v>Text = binary()</v>
- </type>
- <desc>
- <p>Decrypts <c>Cipher</c> according to AES in Counter mode (CTR). This function can be
- used to decrypt a stream of ciphertext using a series of calls instead of requiring all
- ciphertext to be in memory. <c>Cipher</c> can be any number of bytes. State is initialized using
- <seealso marker="#aes_ctr_stream_init/2">aes_ctr_stream_init</seealso>. <c>NewState</c> is the new streaming
- encryption state that must be passed to the next call to <c>aes_ctr_stream_encrypt</c>.
- <c>Text</c> is the decrypted data.</p>
- </desc>
- </func>
- <func>
- <name>erlint(Mpint) -> N</name>
- <name>mpint(N) -> Mpint</name>
- <fsummary>Convert between binary multi-precision integer and erlang big integer</fsummary>
- <type>
- <v>Mpint = binary()</v>
- <v>N = integer()</v>
- </type>
- <desc>
- <p>Convert a binary multi-precision integer <c>Mpint</c> to and from
- an erlang big integer. A multi-precision integer is a binary
- with the following form:
- <c><![CDATA[<<ByteLen:32/integer, Bytes:ByteLen/binary>>]]></c> where both
- <c>ByteLen</c> and <c>Bytes</c> are big-endian. Mpints are used in
- some of the functions in <c>crypto</c> and are not translated
- in the API for performance reasons.</p>
- </desc>
- </func>
- <func>
- <name>rand_bytes(N) -> binary()</name>
- <fsummary>Generate a binary of random bytes</fsummary>
- <type>
- <v>N = integer()</v>
- </type>
- <desc>
- <p>Generates N bytes randomly uniform 0..255, and returns the
- result in a binary. Uses the <c>crypto</c> library pseudo-random
- number generator.</p>
- </desc>
- </func>
- <func>
- <name>strong_rand_bytes(N) -> binary()</name>
- <fsummary>Generate a binary of random bytes</fsummary>
- <type>
- <v>N = integer()</v>
- </type>
- <desc>
- <p>Generates N bytes randomly uniform 0..255, and returns the
- result in a binary. Uses a cryptographically secure prng seeded and
- periodically mixed with operating system provided entropy. By default
- this is the <c>RAND_bytes</c> method from OpenSSL.</p>
- <p>May throw exception <c>low_entropy</c> in case the random generator
- failed due to lack of secure "randomness".</p>
- </desc>
- </func>
- <func>
- <name>rand_uniform(Lo, Hi) -> N</name>
- <fsummary>Generate a random number</fsummary>
- <type>
- <v>Lo, Hi, N = Mpint | integer()</v>
- <v>Mpint = binary()</v>
- </type>
- <desc>
- <p>Generate a random number <c><![CDATA[N, Lo =< N < Hi.]]></c> Uses the
- <c>crypto</c> library pseudo-random number generator. The
- arguments (and result) can be either erlang integers or binary
- multi-precision integers. <c>Hi</c> must be larger than <c>Lo</c>.</p>
- </desc>
- </func>
- <func>
- <name>strong_rand_mpint(N, Top, Bottom) -> Mpint</name>
- <fsummary>Generate an N bit random number</fsummary>
- <type>
- <v>N = non_neg_integer()</v>
- <v>Top = -1 | 0 | 1</v>
- <v>Bottom = 0 | 1</v>
- <v>Mpint = binary()</v>
- </type>
- <desc>
- <p>Generate an N bit random number using OpenSSL's
- cryptographically strong pseudo random number generator
- <c>BN_rand</c>.</p>
- <p>The parameter <c>Top</c> places constraints on the most
- significant bits of the generated number. If <c>Top</c> is 1, then the
- two most significant bits will be set to 1, if <c>Top</c> is 0, the
- most significant bit will be 1, and if <c>Top</c> is -1 then no
- constraints are applied and thus the generated number may be less than
- N bits long.</p>
- <p>If <c>Bottom</c> is 1, then the generated number is
- constrained to be odd.</p>
- <p>May throw exception <c>low_entropy</c> in case the random generator
- failed due to lack of secure "randomness".</p>
- </desc>
- </func>
- <func>
- <name>mod_exp(N, P, M) -> Result</name>
- <fsummary>Perform N ^ P mod M</fsummary>
- <type>
- <v>N, P, M, Result = Mpint</v>
- <v>Mpint = binary()</v>
- </type>
- <desc>
- <p>This function performs the exponentiation <c>N ^ P mod M</c>,
- using the <c>crypto</c> library.</p>
- </desc>
- </func>
- <func>
- <name>mod_exp_prime(N, P, M) -> Result</name>
+ <name>mod_pow(N, P, M) -> Result</name>
<fsummary>Computes the function: N^P mod M</fsummary>
<type>
- <v>N, P, M = binary()</v>
+ <v>N, P, M = binary() | integer()</v>
<v>Result = binary() | error</v>
</type>
<desc>
<p>Computes the function <c>N^P mod M</c>.</p>
</desc>
</func>
- <func>
- <name>rsa_sign(DataOrDigest, Key) -> Signature</name>
- <name>rsa_sign(DigestType, DataOrDigest, Key) -> Signature</name>
- <fsummary>Sign the data using rsa with the given key.</fsummary>
- <type>
- <v>DataOrDigest = Data | {digest,Digest}</v>
- <v>Data = Mpint</v>
- <v>Digest = binary()</v>
- <v>Key = [E, N, D] | [E, N, D, P1, P2, E1, E2, C]</v>
- <v>E, N, D = Mpint</v>
- <d>Where <c>E</c> is the public exponent, <c>N</c> is public modulus and
- <c>D</c> is the private exponent.</d>
- <v>P1, P2, E1, E2, C = Mpint</v>
- <d>The longer key format contains redundant information that will make
- the calculation faster. <c>P1,P2</c> are first and second prime factors.
- <c>E1,E2</c> are first and second exponents. <c>C</c> is the CRT coefficient.
- Terminology is taken from RFC 3447.</d>
- <v>DigestType = md5 | sha | sha224 | sha256 | sha384 | sha512</v>
- <d>The default <c>DigestType</c> is sha.</d>
- <v>Mpint = binary()</v>
- <v>Signature = binary()</v>
- </type>
- <desc>
- <p>Creates a RSA signature with the private key <c>Key</c>
- of a digest. The digest is either calculated as a
- <c>DigestType</c> digest of <c>Data</c> or a precalculated
- binary <c>Digest</c>.</p>
- </desc>
- </func>
<func>
- <name>rsa_verify(DataOrDigest, Signature, Key) -> Verified</name>
- <name>rsa_verify(DigestType, DataOrDigest, Signature, Key) -> Verified </name>
- <fsummary>Verify the digest and signature using rsa with given public key.</fsummary>
- <type>
- <v>Verified = boolean()</v>
- <v>DataOrDigest = Data | {digest|Digest}</v>
- <v>Data, Signature = Mpint</v>
- <v>Digest = binary()</v>
- <v>Key = [E, N]</v>
- <v>E, N = Mpint</v>
- <d>Where <c>E</c> is the public exponent and <c>N</c> is public modulus.</d>
- <v>DigestType = md5 | sha | sha224 | sha256 | sha384 | sha512</v>
- <d>The default <c>DigestType</c> is sha.</d>
- <v>Mpint = binary()</v>
- </type>
- <desc>
- <p>Verifies that a digest matches the RSA signature using the
- signer's public key <c>Key</c>.
- The digest is either calculated as a <c>DigestType</c>
- digest of <c>Data</c> or a precalculated binary <c>Digest</c>.</p>
- <p>May throw exception <c>notsup</c> in case the chosen <c>DigestType</c>
- is not supported by the underlying OpenSSL implementation.</p>
- </desc>
- </func>
-
- <func>
- <name>rsa_public_encrypt(PlainText, PublicKey, Padding) -> ChipherText</name>
- <fsummary>Encrypts Msg using the public Key.</fsummary>
- <type>
- <v>PlainText = binary()</v>
- <v>PublicKey = [E, N]</v>
- <v>E, N = Mpint</v>
- <d>Where <c>E</c> is the public exponent and <c>N</c> is public modulus.</d>
- <v>Padding = rsa_pkcs1_padding | rsa_pkcs1_oaep_padding | rsa_no_padding</v>
- <v>ChipherText = binary()</v>
- </type>
- <desc>
- <p>Encrypts the <c>PlainText</c> (usually a session key) using the <c>PublicKey</c>
- and returns the cipher. The <c>Padding</c> decides what padding mode is used,
- <c>rsa_pkcs1_padding</c> is PKCS #1 v1.5 currently the most
- used mode and <c>rsa_pkcs1_oaep_padding</c> is EME-OAEP as
- defined in PKCS #1 v2.0 with SHA-1, MGF1 and an empty encoding
- parameter. This mode is recommended for all new applications.
- The size of the <c>Msg</c> must be less
- than <c>byte_size(N)-11</c> if
- <c>rsa_pkcs1_padding</c> is used, <c>byte_size(N)-41</c> if
- <c>rsa_pkcs1_oaep_padding</c> is used and <c>byte_size(N)</c> if <c>rsa_no_padding</c>
- is used.
- Where byte_size(N) is the size part of an <c>Mpint-1</c>.
- </p>
- </desc>
+ <name>next_iv(Type, Data) -> </name>
+ <fsummary></fsummary>
+ <type>
+ <v>Type = des_cbc | aes_cbc</v>
+ <v>Data = iodata()</v>
+ </type>
+ <desc>
+ <p>Returns the initialization vector to be used in the next
+ iteration of encrypt/decrypt of type <c>Type</c>. Data is the
+ encrypted data from the previous iteration step.</p>
+ </desc>
</func>
<func>
- <name>rsa_private_decrypt(ChipherText, PrivateKey, Padding) -> PlainText</name>
+ <name>private_decrypt(Type, ChipherText, PrivateKey, Padding) -> PlainText</name>
<fsummary>Decrypts ChipherText using the private Key.</fsummary>
<type>
+ <v>Type = rsa</v>
<v>ChipherText = binary()</v>
- <v>PrivateKey = [E, N, D] | [E, N, D, P1, P2, E1, E2, C]</v>
- <v>E, N, D = Mpint</v>
- <d>Where <c>E</c> is the public exponent, <c>N</c> is public modulus and
- <c>D</c> is the private exponent.</d>
- <v>P1, P2, E1, E2, C = Mpint</v>
- <d>The longer key format contains redundant information that will make
- the calculation faster. <c>P1,P2</c> are first and second prime factors.
- <c>E1,E2</c> are first and second exponents. <c>C</c> is the CRT coefficient.
- Terminology is taken from RFC 3447.</d>
+ <v>PrivateKey = rsa_private()</v>
<v>Padding = rsa_pkcs1_padding | rsa_pkcs1_oaep_padding | rsa_no_padding</v>
<v>PlainText = binary()</v>
</type>
<desc>
- <p>Decrypts the <c>ChipherText</c> (usually a session key encrypted with
- <seealso marker="#rsa_public_encrypt/3">rsa_public_encrypt/3</seealso>)
+ <p>Decrypts the <c>ChipherText</c> (usually a session key encrypted with
+ <seealso marker="#public_encrypt/3">public_encrypt/3</seealso>)
using the <c>PrivateKey</c> and returns the
message. The <c>Padding</c> is the padding mode that was
- used to encrypt the data,
- see <seealso marker="#rsa_public_encrypt/3">rsa_public_encrypt/3</seealso>.
+ used to encrypt the data,
+ see <seealso marker="#public_encrypt/3">public_encrypt/3</seealso>.
+ See also <seealso marker="public_key:public_key#decrypt_private/2">public_key:decrypt_private/[2,3]</seealso>
</p>
</desc>
</func>
+
<func>
- <name>rsa_private_encrypt(PlainText, PrivateKey, Padding) -> ChipherText</name>
+ <name>private_encrypt(Type, PlainText, PrivateKey, Padding) -> ChipherText</name>
<fsummary>Encrypts Msg using the private Key.</fsummary>
<type>
+ <v>Type = rsa</v>
<v>PlainText = binary()</v>
- <v>PrivateKey = [E, N, D] | [E, N, D, P1, P2, E1, E2, C]</v>
- <v>E, N, D = Mpint</v>
- <d>Where <c>E</c> is the public exponent, <c>N</c> is public modulus and
- <c>D</c> is the private exponent.</d>
- <v>P1, P2, E1, E2, C = Mpint</v>
- <d>The longer key format contains redundant information that will make
- the calculation faster. <c>P1,P2</c> are first and second prime factors.
- <c>E1,E2</c> are first and second exponents. <c>C</c> is the CRT coefficient.
- Terminology is taken from RFC 3447.</d>
+ <v>PrivateKey = rsa_private()</v>
<v>Padding = rsa_pkcs1_padding | rsa_no_padding</v>
<v>ChipherText = binary()</v>
</type>
@@ -1131,316 +458,289 @@ Mpint() = <![CDATA[<<ByteLen:32/integer-big, Bytes:ByteLen/binary>>]]>
<c>rsa_pkcs1_padding</c> is PKCS #1 v1.5 currently the most
used mode.
The size of the <c>Msg</c> must be less than <c>byte_size(N)-11</c> if
- <c>rsa_pkcs1_padding</c> is used, and <c>byte_size(N)</c> if <c>rsa_no_padding</c>
- is used. Where byte_size(N) is the size part of an <c>Mpint-1</c>.
+ <c>rsa_pkcs1_padding</c> is used, and <c>byte_size(N)</c> if <c>rsa_no_padding</c>
+ is used.
+ See also <seealso marker="public_key:public_key#encrypt_private/2">public_key:encrypt_private/[2,3]</seealso>
</p>
</desc>
</func>
-
<func>
- <name>rsa_public_decrypt(ChipherText, PublicKey, Padding) -> PlainText</name>
+ <name>public_decrypt(Type, ChipherText, PublicKey, Padding) -> PlainText</name>
<fsummary>Decrypts ChipherText using the public Key.</fsummary>
<type>
+ <v>Type = rsa</v>
<v>ChipherText = binary()</v>
- <v>PublicKey = [E, N]</v>
- <v>E, N = Mpint</v>
- <d>Where <c>E</c> is the public exponent and <c>N</c> is public modulus</d>
+ <v>PublicKey = rsa_public() </v>
<v>Padding = rsa_pkcs1_padding | rsa_no_padding</v>
<v>PlainText = binary()</v>
</type>
<desc>
- <p>Decrypts the <c>ChipherText</c> (encrypted with
- <seealso marker="#rsa_private_encrypt/3">rsa_private_encrypt/3</seealso>)
+ <p>Decrypts the <c>ChipherText</c> (encrypted with
+ <seealso marker="#private_encrypt/3">private_encrypt/3</seealso>)
using the <c>PrivateKey</c> and returns the
message. The <c>Padding</c> is the padding mode that was
- used to encrypt the data,
- see <seealso marker="#rsa_private_encrypt/3">rsa_private_encrypt/3</seealso>.
+ used to encrypt the data,
+ see <seealso marker="#private_encrypt/3">private_encrypt/3</seealso>.
+ See also <seealso marker="public_key:public_key#decrypt_public/2">public_key:decrypt_public/[2,3]</seealso>
</p>
</desc>
</func>
-
+
<func>
- <name>dss_sign(DataOrDigest, Key) -> Signature</name>
- <name>dss_sign(DigestType, DataOrDigest, Key) -> Signature</name>
- <fsummary>Sign the data using dsa with given private key.</fsummary>
+ <name>public_encrypt(Type, PlainText, PublicKey, Padding) -> ChipherText</name>
+ <fsummary>Encrypts Msg using the public Key.</fsummary>
<type>
- <v>DigestType = sha</v>
- <v>DataOrDigest = Mpint | {digest,Digest}</v>
- <v>Key = [P, Q, G, X]</v>
- <v>P, Q, G, X = Mpint</v>
- <d> Where <c>P</c>, <c>Q</c> and <c>G</c> are the dss
- parameters and <c>X</c> is the private key.</d>
- <v>Digest = binary() with length 20 bytes</v>
- <v>Signature = binary()</v>
+ <v>Type = rsa</v>
+ <v>PlainText = binary()</v>
+ <v>PublicKey = rsa_public()</v>
+ <v>Padding = rsa_pkcs1_padding | rsa_pkcs1_oaep_padding | rsa_no_padding</v>
+ <v>ChipherText = binary()</v>
</type>
<desc>
- <p>Creates a DSS signature with the private key <c>Key</c> of
- a digest. The digest is either calculated as a SHA1
- digest of <c>Data</c> or a precalculated binary <c>Digest</c>.</p>
- <p>A deprecated feature is having <c>DigestType = 'none'</c>
- in which case <c>DataOrDigest</c> is a precalculated SHA1
- digest.</p>
+ <p>Encrypts the <c>PlainText</c> (usually a session key) using the <c>PublicKey</c>
+ and returns the <c>CipherText</c>. The <c>Padding</c> decides what padding mode is used,
+ <c>rsa_pkcs1_padding</c> is PKCS #1 v1.5 currently the most
+ used mode and <c>rsa_pkcs1_oaep_padding</c> is EME-OAEP as
+ defined in PKCS #1 v2.0 with SHA-1, MGF1 and an empty encoding
+ parameter. This mode is recommended for all new applications.
+ The size of the <c>Msg</c> must be less
+ than <c>byte_size(N)-11</c> if
+ <c>rsa_pkcs1_padding</c> is used, <c>byte_size(N)-41</c> if
+ <c>rsa_pkcs1_oaep_padding</c> is used and <c>byte_size(N)</c> if <c>rsa_no_padding</c>
+ is used.
+ See also <seealso marker="public_key:public_key#encrypt_public/2">public_key:encrypt_public/[2,3]</seealso>
+ </p>
</desc>
</func>
<func>
- <name>dss_verify(DataOrDigest, Signature, Key) -> Verified</name>
- <name>dss_verify(DigestType, DataOrDigest, Signature, Key) -> Verified</name>
- <fsummary>Verify the data and signature using dsa with given public key.</fsummary>
+ <name>rand_bytes(N) -> binary()</name>
+ <fsummary>Generate a binary of random bytes</fsummary>
<type>
- <v>Verified = boolean()</v>
- <v>DigestType = sha</v>
- <v>DataOrDigest = Mpint | {digest,Digest}</v>
- <v>Data = Mpint | ShaDigest</v>
- <v>Signature = Mpint</v>
- <v>Key = [P, Q, G, Y]</v>
- <v>P, Q, G, Y = Mpint</v>
- <d> Where <c>P</c>, <c>Q</c> and <c>G</c> are the dss
- parameters and <c>Y</c> is the public key.</d>
- <v>Digest = binary() with length 20 bytes</v>
+ <v>N = integer()</v>
</type>
<desc>
- <p>Verifies that a digest matches the DSS signature using the
- public key <c>Key</c>. The digest is either calculated as a SHA1
- digest of <c>Data</c> or is a precalculated binary <c>Digest</c>.</p>
- <p>A deprecated feature is having <c>DigestType = 'none'</c>
- in which case <c>DataOrDigest</c> is a precalculated SHA1
- digest binary.</p>
+ <p>Generates N bytes randomly uniform 0..255, and returns the
+ result in a binary. Uses the <c>crypto</c> library pseudo-random
+ number generator.</p>
</desc>
</func>
- <func>
- <name>rc2_cbc_encrypt(Key, IVec, Text) -> Cipher</name>
- <fsummary>Encrypt <c>Text</c>according to RC2 in CBC mode</fsummary>
+ <func>
+ <name>rand_uniform(Lo, Hi) -> N</name>
+ <fsummary>Generate a random number</fsummary>
<type>
- <v>Key = Text = iolist() | binary()</v>
- <v>Ivec = Cipher = binary()</v>
+ <v>Lo, Hi, N = integer()</v>
</type>
<desc>
- <p>Encrypts <c>Text</c> according to RC2 in CBC mode.</p>
+ <p>Generate a random number <c><![CDATA[N, Lo =< N < Hi.]]></c> Uses the
+ <c>crypto</c> library pseudo-random number generator.
+ <c>Hi</c> must be larger than <c>Lo</c>.</p>
</desc>
</func>
<func>
- <name>rc2_cbc_decrypt(Key, IVec, Cipher) -> Text</name>
- <fsummary>Decrypts <c>Cipher</c>according to RC2 in CBC mode</fsummary>
+ <name>sign(Algorithm, DigestType, Msg, Key) -> binary()</name>
+ <fsummary> Create digital signature.</fsummary>
<type>
- <v>Key = Text = iolist() | binary()</v>
- <v>Ivec = Cipher = binary()</v>
+ <v>Algorithm = rsa | dss | ecdsa </v>
+ <v>Msg = binary() | {digest,binary()}</v>
+ <d>The msg is either the binary "plain text" data to be
+ signed or it is the hashed value of "plain text" i.e. the
+ digest.</d>
+ <v>DigestType = digest_type()</v>
+ <v>Key = rsa_private_key() | dsa_private_key() | ec_private_key()</v>
</type>
<desc>
- <p>Decrypts <c>Cipher</c> according to RC2 in CBC mode.</p>
+ <p> Creates a digital signature.</p>
+ See also <seealso marker="public_key:public_key#sign/3">public_key:sign/3</seealso>
</desc>
</func>
-
+
<func>
- <name>rc4_encrypt(Key, Data) -> Result</name>
- <fsummary>Encrypt data using RC4</fsummary>
+ <name>start() -> ok</name>
+ <fsummary> Equivalent to application:start(crypto). </fsummary>
+ <desc>
+ <p> Equivalent to application:start(crypto).</p>
+ </desc>
+ </func>
+ <func>
+ <name>stop() -> ok</name>
+ <fsummary> Equivalent to application:stop(crypto).</fsummary>
+ <desc>
+ <p> Equivalent to application:stop(crypto).</p>
+ </desc>
+ </func>
+
+ <func>
+ <name>strong_rand_bytes(N) -> binary()</name>
+ <fsummary>Generate a binary of random bytes</fsummary>
<type>
- <v>Key, Data = iolist() | binary()</v>
- <v>Result = binary()</v>
+ <v>N = integer()</v>
</type>
<desc>
- <p>Encrypts the data with RC4 symmetric stream encryption.
- Since it is symmetric, the same function is used for
- decryption.</p>
+ <p>Generates N bytes randomly uniform 0..255, and returns the
+ result in a binary. Uses a cryptographically secure prng seeded and
+ periodically mixed with operating system provided entropy. By default
+ this is the <c>RAND_bytes</c> method from OpenSSL.</p>
+ <p>May throw exception <c>low_entropy</c> in case the random generator
+ failed due to lack of secure "randomness".</p>
</desc>
</func>
-
<func>
- <name>dh_generate_key(DHParams) -> {PublicKey,PrivateKey} </name>
- <name>dh_generate_key(PrivateKey, DHParams) -> {PublicKey,PrivateKey} </name>
- <fsummary>Generates a Diffie-Hellman public key</fsummary>
+ <name>stream_init(Type, Key) -> State</name>
+ <fsummary></fsummary>
<type>
- <v>DHParameters = [P, G]</v>
- <v>P, G = Mpint</v>
- <d> Where <c>P</c> is the shared prime number and <c>G</c> is the shared generator.</d>
- <v>PublicKey, PrivateKey = Mpint()</v>
+ <v>Type rc4 </v>
+ <v>State = opaque() </v>
+ <v>Key = iodata()</v>
+ <v>IVec = binary()</v>
</type>
<desc>
- <p>Generates a Diffie-Hellman <c>PublicKey</c> and <c>PrivateKey</c> (if not given).
- </p>
+ <p>Initializes the state for use in RC4 stream encryption
+ <seealso marker="#stream_encrypt/2">stream_encrypt</seealso> and
+ <seealso marker="#stream_decrypt/2">stream_decrypt</seealso></p>
</desc>
</func>
- <func>
- <name>dh_compute_key(OthersPublicKey, MyPrivateKey, DHParams) -> SharedSecret</name>
- <fsummary>Computes the shared secret</fsummary>
+ <func>
+ <name>stream_init(Type, Key, IVec) -> State</name>
+ <fsummary></fsummary>
<type>
- <v>DHParameters = [P, G]</v>
- <v>P, G = Mpint</v>
- <d> Where <c>P</c> is the shared prime number and <c>G</c> is the shared generator.</d>
- <v>OthersPublicKey, MyPrivateKey = Mpint()</v>
- <v>SharedSecret = binary()</v>
+ <v>Type aes_ctr </v>
+ <v>State = opaque() </v>
+ <v>Key = iodata()</v>
+ <v>IVec = binary()</v>
</type>
<desc>
- <p>Computes the shared secret from the private key and the other party's public key.
- </p>
+ <p>Initializes the state for use in streaming AES encryption using Counter mode (CTR).
+ <c>Key</c> is the AES key and must be either 128, 192, or 256 bts long. <c>IVec</c> is
+ an arbitrary initializing vector of 128 bits (16 bytes). This state is for use with
+ <seealso marker="#stream_encrypt/2">stream_encrypt</seealso> and
+ <seealso marker="#stream_decrypt/2">stream_decrypt</seealso>.</p>
</desc>
</func>
-
+
<func>
- <name>srp_generate_key(Generator, Prime, Version) -> {PublicKey, PrivateKey} </name>
- <name>srp_generate_key(Generator, Prime, Version, Private) -> {PublicKey, PrivateKey} </name>
- <name>srp_generate_key(Verifier, Generator, Prime, Version) -> {PublicKey, PrivateKey} </name>
- <name>srp_generate_key(Verifier, Generator, Prime, Version, Private) -> {PublicKey, PrivateKey} </name>
- <fsummary>Generates SRP public keys</fsummary>
+ <name>stream_encrypt(State, PlainText) -> { NewState, CipherText}</name>
+ <fsummary></fsummary>
<type>
- <v>Verifier = binary()</v>
- <d>Parameter v from <url href="http://srp.stanford.edu/design.html">SRP design</url>
- </d>
- <v>Generator = binary() </v>
- <d>Parameter g from <url href="http://srp.stanford.edu/design.html">SRP design</url>
- </d>
- <v>Prime = binary() </v>
- <d>Parameter N from <url href="http://srp.stanford.edu/design.html">SRP design</url>
- </d>
- <v>Version = '3' | '6' | '6a' </v>
- <d>SRP version, TLS SRP cipher suites uses '6a'.</d>
- <v>PublicKey = binary()</v>
- <d> Parameter A or B from <url href="http://srp.stanford.edu/design.html">SRP design</url></d>
- <v>Private = PrivateKey = binary() - generated if not supplied</v>
- <d>Parameter a or b from <url href="http://srp.stanford.edu/design.html">SRP design</url></d>
+ <v>Text = iodata()</v>
+ <v>CipherText = binary()</v>
</type>
<desc>
- <p>Generates SRP public keys for the client side (first argument is Generator)
- or for the server side (first argument is Verifier).</p>
+ <p>Encrypts <c>PlainText</c> according to the stream cipher <c>Type</c> specified in stream_init/3.
+ <c>Text</c> can be any number of bytes. The initial <c>State</c> is created using
+ <seealso marker="#stream_init/2">stream_init</seealso>.
+ <c>NewState</c> must be passed into the next call to <c>stream_encrypt</c>.</p>
</desc>
</func>
<func>
- <name>srp_compute_key(DerivedKey, Prime, Generator,
- ClientPublic, ClientPrivate, ServerPublic, Version) -> SessionKey</name>
- <name>srp_compute_key(DerivedKey, Prime, Generator,
- ClientPublic, ClientPrivate, ServerPublic, Version, Scrambler) -> SessionKey</name>
- <name>srp_compute_key(Verifier, Prime,
- ClientPublic, ServerPublic, ServerPrivate, Version, Scrambler)-> SessionKey</name>
- <name>srp_compute_key(Verifier, Prime,
- ClientPublic, ServerPublic, ServerPrivate, Version) -> SessionKey</name>
-
- <fsummary>Computes SRP session key</fsummary>
+ <name>stream_decrypt(State, CipherText) -> { NewState, PlainText }</name>
+ <fsummary></fsummary>
<type>
- <v>DerivedKey = binary()</v>
- <d>Parameter x from <url href="http://srp.stanford.edu/design.html">SRP design</url>
- </d>
- <v>Verifier = binary()</v>
- <d>Parameter v from <url href="http://srp.stanford.edu/design.html">SRP design</url>
- </d>
- <v>Prime = binary() </v>
- <d>Parameter N from <url href="http://srp.stanford.edu/design.html">SRP design</url>
- </d>
- <v>Generator = binary() </v>
- <d>Parameter g from <url href="http://srp.stanford.edu/design.html">SRP design</url>
- </d>
- <v>ClientPublic = binary() </v>
- <d>Parameter A from <url href="http://srp.stanford.edu/design.html">SRP design</url>
- </d>
- <v>ClientPrivate = binary() </v>
- <d>Parameter a from <url href="http://srp.stanford.edu/design.html">SRP design</url>
- </d>
- <v>ServerPublic = binary() </v>
- <d>Parameter B from <url href="http://srp.stanford.edu/design.html">SRP design</url>
- </d>
- <v>ServerPrivate = binary() </v>
- <d>Parameter b from <url href="http://srp.stanford.edu/design.html">SRP design</url>
- </d>
- <v>Version = '3' | '6' | '6a' </v>
- <d>SRP version, TLS SRP cipher suites uses '6a'.</d>
- <v>SessionKey = binary()</v>
- <d>Result K from <url href="http://srp.stanford.edu/design.html">SRP design</url>
- </d>
+ <v>CipherText = iodata()</v>
+ <v>PlainText = binary()</v>
</type>
<desc>
- <p>
- Computes the SRP session key (shared secret) for the client side (first argument is DerivedKey)
- or for the server side (first argument is Verifier). Also used
- as premaster secret by TLS-SRP cipher suites.
- </p>
+ <p>Decrypts <c>CipherText</c> according to the stream cipher <c>Type</c> specified in stream_init/3.
+ <c>PlainText</c> can be any number of bytes. The initial <c>State</c> is created using
+ <seealso marker="#stream_init/2">stream_init</seealso>.
+ <c>NewState</c> must be passed into the next call to <c>stream_encrypt</c>.</p>
</desc>
</func>
-
- <func>
- <name>exor(Data1, Data2) -> Result</name>
- <fsummary>XOR data</fsummary>
+
+ <func>
+ <name>verify(Algorithm, DigestType, Msg, Signature, Key) -> boolean()</name>
+ <fsummary>Verifies a digital signature.</fsummary>
<type>
- <v>Data1, Data2 = iolist() | binary()</v>
- <v>Result = binary()</v>
+ <v> Algorithm = rsa | dss | ecdsa </v>
+ <v>Msg = binary() | {digest,binary()}</v>
+ <d>The msg is either the binary "plain text" data
+ or it is the hashed value of "plain text" i.e. the digest.</d>
+ <v>DigestType = digest_type()</v>
+ <v>Signature = binary()</v>
+ <v>Key = rsa_public_key() | dsa_public_key() | ec_public_key()</v>
</type>
<desc>
- <p>Performs bit-wise XOR (exclusive or) on the data supplied.</p>
+ <p>Verifies a digital signature</p>
+ See also <seealso marker="public_key:public_key#sign/3">public_key:verify/3</seealso>
</desc>
</func>
- </funcs>
- <section>
- <title>DES in CBC mode</title>
- <p>The Data Encryption Standard (DES) defines an algorithm for
- encrypting and decrypting an 8 byte quantity using an 8 byte key
- (actually only 56 bits of the key is used).
- </p>
- <p>When it comes to encrypting and decrypting blocks that are
- multiples of 8 bytes various modes are defined (NIST SP
- 800-38A). One of those modes is the Cipher Block Chaining (CBC)
- mode, where the encryption of an 8 byte segment depend not only
- of the contents of the segment itself, but also on the result of
- encrypting the previous segment: the encryption of the previous
- segment becomes the initializing vector of the encryption of the
- current segment.
- </p>
- <p>Thus the encryption of every segment depends on the encryption
- key (which is secret) and the encryption of the previous
- segment, except the first segment which has to be provided with
- an initial initializing vector. That vector could be chosen at
- random, or be a counter of some kind. It does not have to be
- secret.
- </p>
- <p>The following example is drawn from the old FIPS 81 standard
- (replaced by NIST SP 800-38A), where both the plain text and the
- resulting cipher text is settled. The following code fragment
- returns `true'.
- </p>
- <pre><![CDATA[
-
- Key = <<16#01,16#23,16#45,16#67,16#89,16#ab,16#cd,16#ef>>,
- IVec = <<16#12,16#34,16#56,16#78,16#90,16#ab,16#cd,16#ef>>,
- P = "Now is the time for all ",
- C = crypto:des_cbc_encrypt(Key, IVec, P),
- % Which is the same as
- P1 = "Now is t", P2 = "he time ", P3 = "for all ",
- C1 = crypto:des_cbc_encrypt(Key, IVec, P1),
- C2 = crypto:des_cbc_encrypt(Key, C1, P2),
- C3 = crypto:des_cbc_encrypt(Key, C2, P3),
-
- C = <<C1/binary, C2/binary, C3/binary>>,
- C = <<16#e5,16#c7,16#cd,16#de,16#87,16#2b,16#f2,16#7c,
- 16#43,16#e9,16#34,16#00,16#8c,16#38,16#9c,16#0f,
- 16#68,16#37,16#88,16#49,16#9a,16#7c,16#05,16#f6>>,
- <<"Now is the time for all ">> ==
- crypto:des_cbc_decrypt(Key, IVec, C).
- ]]></pre>
- <p>The following is true for the DES CBC mode. For all
- decompositions <c>P1 ++ P2 = P</c> of a plain text message
- <c>P</c> (where the length of all quantities are multiples of 8
- bytes), the encryption <c>C</c> of <c>P</c> is equal to <c>C1 ++
- C2</c>, where <c>C1</c> is obtained by encrypting <c>P1</c> with
- <c>Key</c> and the initializing vector <c>IVec</c>, and where
- <c>C2</c> is obtained by encrypting <c>P2</c> with <c>Key</c>
- and the initializing vector <c>last8(C1)</c>,
- where <c>last(Binary)</c> denotes the last 8 bytes of the
- binary <c>Binary</c>.
- </p>
- <p>Similarly, for all decompositions <c>C1 ++ C2 = C</c> of a
- cipher text message <c>C</c> (where the length of all quantities
- are multiples of 8 bytes), the decryption <c>P</c> of <c>C</c>
- is equal to <c>P1 ++ P2</c>, where <c>P1</c> is obtained by
- decrypting <c>C1</c> with <c>Key</c> and the initializing vector
- <c>IVec</c>, and where <c>P2</c> is obtained by decrypting
- <c>C2</c> with <c>Key</c> and the initializing vector
- <c>last8(C1)</c>, where <c>last8(Binary)</c> is as above.
- </p>
- <p>For DES3 (which uses three 64 bit keys) the situation is the
- same.
- </p>
- </section>
+ </funcs>
+
+ <!-- Maybe put this in the users guide -->
+ <!-- <section> -->
+ <!-- <title>DES in CBC mode</title> -->
+ <!-- <p>The Data Encryption Standard (DES) defines an algorithm for -->
+ <!-- encrypting and decrypting an 8 byte quantity using an 8 byte key -->
+ <!-- (actually only 56 bits of the key is used). -->
+ <!-- </p> -->
+ <!-- <p>When it comes to encrypting and decrypting blocks that are -->
+ <!-- multiples of 8 bytes various modes are defined (NIST SP -->
+ <!-- 800-38A). One of those modes is the Cipher Block Chaining (CBC) -->
+ <!-- mode, where the encryption of an 8 byte segment depend not only -->
+ <!-- of the contents of the segment itself, but also on the result of -->
+ <!-- encrypting the previous segment: the encryption of the previous -->
+ <!-- segment becomes the initializing vector of the encryption of the -->
+ <!-- current segment. -->
+ <!-- </p> -->
+ <!-- <p>Thus the encryption of every segment depends on the encryption -->
+ <!-- key (which is secret) and the encryption of the previous -->
+ <!-- segment, except the first segment which has to be provided with -->
+ <!-- an initial initializing vector. That vector could be chosen at -->
+ <!-- random, or be a counter of some kind. It does not have to be -->
+ <!-- secret. -->
+ <!-- </p> -->
+ <!-- <p>The following example is drawn from the old FIPS 81 standard -->
+ <!-- (replaced by NIST SP 800-38A), where both the plain text and the -->
+ <!-- resulting cipher text is settled. The following code fragment -->
+ <!-- returns `true'. -->
+ <!-- </p> -->
+ <!-- <pre><![CDATA[ -->
+
+ <!-- Key = <<16#01,16#23,16#45,16#67,16#89,16#ab,16#cd,16#ef>>, -->
+ <!-- IVec = <<16#12,16#34,16#56,16#78,16#90,16#ab,16#cd,16#ef>>, -->
+ <!-- P = "Now is the time for all ", -->
+ <!-- C = crypto:des_cbc_encrypt(Key, IVec, P), -->
+ <!-- % Which is the same as -->
+ <!-- P1 = "Now is t", P2 = "he time ", P3 = "for all ", -->
+ <!-- C1 = crypto:des_cbc_encrypt(Key, IVec, P1), -->
+ <!-- C2 = crypto:des_cbc_encrypt(Key, C1, P2), -->
+ <!-- C3 = crypto:des_cbc_encrypt(Key, C2, P3), -->
+
+ <!-- C = <<C1/binary, C2/binary, C3/binary>>, -->
+ <!-- C = <<16#e5,16#c7,16#cd,16#de,16#87,16#2b,16#f2,16#7c, -->
+ <!-- 16#43,16#e9,16#34,16#00,16#8c,16#38,16#9c,16#0f, -->
+ <!-- 16#68,16#37,16#88,16#49,16#9a,16#7c,16#05,16#f6>>, -->
+ <!-- <<"Now is the time for all ">> == -->
+ <!-- crypto:des_cbc_decrypt(Key, IVec, C). -->
+ <!-- ]]></pre> -->
+ <!-- <p>The following is true for the DES CBC mode. For all -->
+ <!-- decompositions <c>P1 ++ P2 = P</c> of a plain text message -->
+ <!-- <c>P</c> (where the length of all quantities are multiples of 8 -->
+ <!-- bytes), the encryption <c>C</c> of <c>P</c> is equal to <c>C1 ++ -->
+ <!-- C2</c>, where <c>C1</c> is obtained by encrypting <c>P1</c> with -->
+ <!-- <c>Key</c> and the initializing vector <c>IVec</c>, and where -->
+ <!-- <c>C2</c> is obtained by encrypting <c>P2</c> with <c>Key</c> -->
+ <!-- and the initializing vector <c>last8(C1)</c>, -->
+ <!-- where <c>last(Binary)</c> denotes the last 8 bytes of the -->
+ <!-- binary <c>Binary</c>. -->
+ <!-- </p> -->
+ <!-- <p>Similarly, for all decompositions <c>C1 ++ C2 = C</c> of a -->
+ <!-- cipher text message <c>C</c> (where the length of all quantities -->
+ <!-- are multiples of 8 bytes), the decryption <c>P</c> of <c>C</c> -->
+ <!-- is equal to <c>P1 ++ P2</c>, where <c>P1</c> is obtained by -->
+ <!-- decrypting <c>C1</c> with <c>Key</c> and the initializing vector -->
+ <!-- <c>IVec</c>, and where <c>P2</c> is obtained by decrypting -->
+ <!-- <c>C2</c> with <c>Key</c> and the initializing vector -->
+ <!-- <c>last8(C1)</c>, where <c>last8(Binary)</c> is as above. -->
+ <!-- </p> -->
+ <!-- <p>For DES3 (which uses three 64 bit keys) the situation is the -->
+ <!-- same. -->
+ <!-- </p> -->
+ <!-- </section> -->
</erlref>
diff --git a/lib/crypto/doc/src/crypto_app.xml b/lib/crypto/doc/src/crypto_app.xml
index 8371db1ff2..6d26076c04 100644
--- a/lib/crypto/doc/src/crypto_app.xml
+++ b/lib/crypto/doc/src/crypto_app.xml
@@ -1,4 +1,4 @@
-<?xml version="1.0" encoding="latin1" ?>
+<?xml version="1.0" encoding="iso-8859-1" ?>
<!DOCTYPE appref SYSTEM "appref.dtd">
<appref>
@@ -24,81 +24,28 @@
</legalnotice>
<title>crypto</title>
- <prepared>Peter H&ouml;gfeldt</prepared>
- <responsible>Peter H&ouml;gfeldt</responsible>
- <docno></docno>
- <approved>Peter H&ouml;gfeldt</approved>
- <checked>Peter H&ouml;gfeldt</checked>
- <date>2003-06-01</date>
- <rev>B</rev>
<file>crypto_app.sgml</file>
</header>
<app>crypto</app>
<appsummary>The Crypto Application</appsummary>
<description>
- <p>The purpose of the Crypto application is to provide message
- digest and DES encryption for SMNPv3. It provides computation of
- message digests MD5 and SHA, and CBC-DES encryption and
- decryption.</p>
- <p></p>
+ <p>The purpose of the Crypto application is to provide an Erlang API
+ to cryptographic functions, see <seealso marker="crypto">crypto(3)</seealso>.
+ Note that the API is on a fairly low level and there are some
+ corresponding API functions available in <seealso marker="public_key:public_key">public_key(3)</seealso>,
+ on a higher abstraction level, that uses the crypto application in its implementation.
+ </p>
</description>
<section>
- <title>Configuration</title>
- <p>The following environment configuration parameters are defined
- for the Crypto application. Refer to application(3) for more
- information about configuration parameters.
- </p>
- <taglist>
- <tag><c><![CDATA[debug = true | false <optional>]]></c></tag>
- <item>
- <p>Causes debug information to be written to standard
- error or standard output. Default is <c>false</c>.
- </p>
- </item>
- </taglist>
- </section>
+ <title>DEPENDENCIES</title>
- <section>
- <title>OpenSSL libraries</title>
- <p>The current implementation of the Erlang Crypto application is
- based on the <em>OpenSSL</em> package version 0.9.8 or higher.
- There are source and binary releases on the web.
- </p>
+ <p>The current crypto implementation uses nifs to interface OpenSSLs crypto library
+ and requires <em>OpenSSL</em> package version 0.9.8 or higher.</p>
<p>Source releases of OpenSSL can be downloaded from the <url href="http://www.openssl.org">OpenSSL</url> project home page,
- or mirror sites listed there.
- </p>
- <p>The same URL also contains links to some compiled binaries and
- libraries of OpenSSL (see the <c>Related/Binaries</c> menu) of
- which the <url href="http://www.shininglightpro.com/search.php?searchname=Win32+OpenSSL">Shining Light Productions Win32 and OpenSSL</url> pages are of
- interest for the Win32 user.
- </p>
- <p>For some Unix flavours there are binary packages available
- on the net.
- </p>
- <p>If you cannot find a suitable binary OpenSSL package, you
- have to fetch an OpenSSL source release and compile it.
- </p>
- <p>You then have to compile and install the library
- <c>libcrypto.so</c> (Unix), or the library <c>libeay32.dll</c>
- (Win32).
- </p>
- <p>For Unix The <c>crypto_drv</c> dynamic driver is delivered linked
- to OpenSSL libraries in <c>/usr/local/lib</c>, but the default
- dynamic linking will also accept libraries in <c>/lib</c> and
- <c>/usr/lib</c>.
- </p>
- <p>If that is not applicable to the particular Unix operating
- system used, the example <c>Makefile</c> in the Crypto
- <c>priv/obj</c> directory, should be used as a basis for
- relinking the final version of the port program.
- </p>
- <p>For <c>Win32</c> it is only required that the library can be
- found from the <c>PATH</c> environment variable, or that they
- reside in the appropriate <c>SYSTEM32</c> directory; hence no
- particular relinking is need. Hence no example <c>Makefile</c>
- for Win32 is provided.</p>
- </section>
+ or mirror sites listed there.
+ </p>
+ </section>
<section>
<title>SEE ALSO</title>
diff --git a/lib/crypto/src/crypto.erl b/lib/crypto/src/crypto.erl
index 1d0a9943c3..f4e157198c 100644
--- a/lib/crypto/src/crypto.erl
+++ b/lib/crypto/src/crypto.erl
@@ -21,104 +21,220 @@
-module(crypto).
--export([start/0, stop/0, info/0, info_lib/0, algorithms/0, version/0]).
+-export([start/0, stop/0, info_lib/0, algorithms/0, version/0]).
-export([hash/2, hash_init/1, hash_update/2, hash_final/1]).
+-export([sign/4, verify/5]).
+-export([generate_key/2, generate_key/3, compute_key/4]).
+-export([hmac/3, hmac/4, hmac_init/2, hmac_update/2, hmac_final/1, hmac_final_n/2]).
+-export([exor/2, strong_rand_bytes/1, mod_pow/3]).
+-export([rand_bytes/1, rand_bytes/3, rand_uniform/2]).
+-export([block_encrypt/3, block_decrypt/3, block_encrypt/4, block_decrypt/4]).
+-export([next_iv/2, next_iv/3]).
+-export([stream_init/2, stream_init/3, stream_encrypt/2, stream_decrypt/2]).
+-export([public_encrypt/4, private_decrypt/4]).
+-export([private_encrypt/4, public_decrypt/4]).
+
+-export([dh_generate_parameters/2, dh_check/1]). %% Testing see
+
+%% DEPRECATED
+%% Replaced by hash_*
-export([md4/1, md4_init/0, md4_update/2, md4_final/1]).
-export([md5/1, md5_init/0, md5_update/2, md5_final/1]).
-export([sha/1, sha_init/0, sha_update/2, sha_final/1]).
--export([sha224/1, sha224_init/0, sha224_update/2, sha224_final/1]).
--export([sha256/1, sha256_init/0, sha256_update/2, sha256_final/1]).
--export([sha384/1, sha384_init/0, sha384_update/2, sha384_final/1]).
--export([sha512/1, sha512_init/0, sha512_update/2, sha512_final/1]).
+-deprecated({md4, 1, next_major_release}).
+-deprecated({md5, 1, next_major_release}).
+-deprecated({sha, 1, next_major_release}).
+-deprecated({md4_init, 0, next_major_release}).
+-deprecated({md5_init, 0, next_major_release}).
+-deprecated({sha_init, 0, next_major_release}).
+-deprecated({md4_update, 2, next_major_release}).
+-deprecated({md5_update, 2, next_major_release}).
+-deprecated({sha_update, 2, next_major_release}).
+-deprecated({md4_final, 1, next_major_release}).
+-deprecated({md5_final, 1, next_major_release}).
+-deprecated({sha_final, 1, next_major_release}).
+
+%% Replaced by hmac_*
-export([md5_mac/2, md5_mac_96/2, sha_mac/2, sha_mac/3, sha_mac_96/2]).
--export([sha224_mac/2, sha224_mac/3]).
--export([sha256_mac/2, sha256_mac/3]).
--export([sha384_mac/2, sha384_mac/3]).
--export([sha512_mac/2, sha512_mac/3]).
--export([hmac/3, hmac/4, hmac_init/2, hmac_update/2, hmac_final/1, hmac_final_n/2]).
+-deprecated({md5_mac, 2, next_major_release}).
+-deprecated({md5_mac_96, 2, next_major_release}).
+-deprecated({sha_mac, 2, next_major_release}).
+-deprecated({sha_mac, 3, next_major_release}).
+-deprecated({sha_mac_96, 2, next_major_release}).
+
+%% Replaced by sign/verify
+-export([dss_verify/3, dss_verify/4, rsa_verify/3, rsa_verify/4]).
+-export([dss_sign/2, dss_sign/3, rsa_sign/2, rsa_sign/3]).
+-deprecated({dss_verify, 3, next_major_release}).
+-deprecated({dss_verify, 4, next_major_release}).
+-deprecated({rsa_verify, 3, next_major_release}).
+-deprecated({rsa_verify, 4, next_major_release}).
+-deprecated({dss_sign, 2, next_major_release}).
+-deprecated({dss_sign, 3, next_major_release}).
+-deprecated({rsa_sign, 2, next_major_release}).
+-deprecated({rsa_sign, 3, next_major_release}).
+
+%% Replaced by generate_key
+-export([dh_generate_key/1, dh_generate_key/2, dh_compute_key/3]).
+-deprecated({dh_generate_key, 1, next_major_release}).
+-deprecated({dh_generate_key, 2, next_major_release}).
+-deprecated({dh_compute_key, 3, next_major_release}).
+
+%% Replaced by mod_exp_prim and no longer needed
+-export([mod_exp/3, mpint/1, erlint/1, strong_rand_mpint/3]).
+-deprecated({mod_exp, 3, next_major_release}).
+-deprecated({mpint, 1, next_major_release}).
+-deprecated({erlint, 1, next_major_release}).
+-deprecated({strong_rand_mpint, 3, next_major_release}).
+
+%% Replaced by block_*
-export([des_cbc_encrypt/3, des_cbc_decrypt/3, des_cbc_ivec/1]).
+-export([des3_cbc_encrypt/5, des3_cbc_decrypt/5]).
-export([des_ecb_encrypt/2, des_ecb_decrypt/2]).
+-export([des_ede3_cbc_encrypt/5, des_ede3_cbc_decrypt/5]).
-export([des_cfb_encrypt/3, des_cfb_decrypt/3, des_cfb_ivec/2]).
--export([des3_cbc_encrypt/5, des3_cbc_decrypt/5]).
-export([des3_cfb_encrypt/5, des3_cfb_decrypt/5]).
+-deprecated({des_cbc_encrypt, 3, next_major_release}).
+-deprecated({des_cbc_decrypt, 3, next_major_release}).
+-deprecated({des_cbc_ivec, 1, next_major_release}).
+-deprecated({des3_cbc_encrypt, 5, next_major_release}).
+-deprecated({des3_cbc_decrypt, 5, next_major_release}).
+-deprecated({des_ecb_encrypt, 2, next_major_release}).
+-deprecated({des_ecb_decrypt, 2, next_major_release}).
+-deprecated({des_ede3_cbc_encrypt, 5, next_major_release}).
+-deprecated({des_ede3_cbc_decrypt, 5, next_major_release}).
+-deprecated({des_cfb_encrypt, 3, next_major_release}).
+-deprecated({des_cfb_decrypt, 3, next_major_release}).
+-deprecated({des_cfb_ivec, 2, next_major_release}).
+-deprecated({des3_cfb_encrypt, 5, next_major_release}).
+-deprecated({des3_cfb_decrypt, 5, next_major_release}).
-export([blowfish_ecb_encrypt/2, blowfish_ecb_decrypt/2]).
-export([blowfish_cbc_encrypt/3, blowfish_cbc_decrypt/3]).
-export([blowfish_cfb64_encrypt/3, blowfish_cfb64_decrypt/3]).
-export([blowfish_ofb64_encrypt/3]).
--export([des_ede3_cbc_encrypt/5, des_ede3_cbc_decrypt/5]).
+-deprecated({blowfish_ecb_encrypt, 2, next_major_release}).
+-deprecated({blowfish_ecb_decrypt, 2, next_major_release}).
+-deprecated({blowfish_cbc_encrypt, 3, next_major_release}).
+-deprecated({blowfish_cbc_decrypt, 3, next_major_release}).
+-deprecated({blowfish_cfb64_encrypt, 3, next_major_release}).
+-deprecated({blowfish_cfb64_decrypt, 3, next_major_release}).
+-deprecated({blowfish_ofb64_encrypt, 3, next_major_release}).
-export([aes_cfb_128_encrypt/3, aes_cfb_128_decrypt/3]).
--export([exor/2]).
--export([rc4_encrypt/2, rc4_set_key/1, rc4_encrypt_with_state/2]).
--export([rc2_cbc_encrypt/3, rc2_cbc_decrypt/3, rc2_40_cbc_encrypt/3, rc2_40_cbc_decrypt/3]).
--export([dss_verify/3, dss_verify/4, rsa_verify/3, rsa_verify/4]).
--export([dss_sign/2, dss_sign/3, rsa_sign/2, rsa_sign/3]).
--export([rsa_public_encrypt/3, rsa_private_decrypt/3]).
--export([rsa_private_encrypt/3, rsa_public_decrypt/3]).
--export([dh_generate_key/1, dh_generate_key/2, dh_compute_key/3]).
--export([rand_bytes/1, rand_bytes/3, rand_uniform/2]).
--export([strong_rand_bytes/1, strong_rand_mpint/3]).
--export([mod_exp/3, mod_exp_prime/3, mpint/1, erlint/1]).
--export([srp_generate_key/4, srp_generate_key/3,
- srp_generate_key/5, srp_compute_key/6, srp_compute_key/7, srp_compute_key/8]).
-
-%% -export([idea_cbc_encrypt/3, idea_cbc_decrypt/3]).
-export([aes_cbc_128_encrypt/3, aes_cbc_128_decrypt/3]).
-export([aes_cbc_256_encrypt/3, aes_cbc_256_decrypt/3]).
-export([aes_cbc_ivec/1]).
--export([aes_ctr_encrypt/3, aes_ctr_decrypt/3]).
+-deprecated({aes_cfb_128_encrypt, 3, next_major_release}).
+-deprecated({aes_cfb_128_decrypt, 3, next_major_release}).
+-deprecated({aes_cbc_128_encrypt, 3, next_major_release}).
+-deprecated({aes_cbc_128_decrypt, 3, next_major_release}).
+-deprecated({aes_cbc_256_encrypt, 3, next_major_release}).
+-deprecated({aes_cbc_256_decrypt, 3, next_major_release}).
+-deprecated({aes_cbc_ivec, 1, next_major_release}).
+-export([rc2_cbc_encrypt/3, rc2_cbc_decrypt/3]).
+-export([rc2_40_cbc_encrypt/3, rc2_40_cbc_decrypt/3]).
+-deprecated({rc2_cbc_encrypt, 3, next_major_release}).
+-deprecated({rc2_cbc_decrypt, 3, next_major_release}).
+%% allready replaced by above!
+-deprecated({rc2_40_cbc_encrypt, 3, next_major_release}).
+-deprecated({rc2_40_cbc_decrypt, 3, next_major_release}).
+
+%% Replaced by stream_*
-export([aes_ctr_stream_init/2, aes_ctr_stream_encrypt/2, aes_ctr_stream_decrypt/2]).
-
--export([dh_generate_parameters/2, dh_check/1]). %% Testing see below
-
-
--define(FUNC_LIST, [md4, md4_init, md4_update, md4_final,
+-export([rc4_set_key/1, rc4_encrypt_with_state/2]).
+-deprecated({aes_ctr_stream_init, 2, next_major_release}).
+-deprecated({aes_ctr_stream_encrypt, 2, next_major_release}).
+-deprecated({aes_ctr_stream_decrypt, 2, next_major_release}).
+-deprecated({rc4_set_key, 1, next_major_release}).
+-deprecated({rc4_encrypt_with_state, 2, next_major_release}).
+
+%% Not needed special case of stream_*
+-export([aes_ctr_encrypt/3, aes_ctr_decrypt/3, rc4_encrypt/2]).
+-deprecated({aes_ctr_encrypt, 3, next_major_release}).
+-deprecated({aes_ctr_decrypt, 3, next_major_release}).
+-deprecated({rc4_encrypt, 2, next_major_release}).
+
+%% Replace by public/private_encrypt/decrypt
+-export([rsa_public_encrypt/3, rsa_private_decrypt/3]).
+-export([rsa_private_encrypt/3, rsa_public_decrypt/3]).
+-deprecated({rsa_public_encrypt, 3, next_major_release}).
+-deprecated({rsa_private_decrypt, 3, next_major_release}).
+-deprecated({rsa_public_decrypt, 3, next_major_release}).
+-deprecated({rsa_private_encrypt, 3, next_major_release}).
+
+%% Replaced by crypto:module_info()
+-export([info/0]).
+-deprecated({info, 0, next_major_release}).
+
+-define(FUNC_LIST, [hash, hash_init, hash_update, hash_final,
+ hmac, hmac_init, hmac_update, hmac_final, hmac_final_n,
+ %% deprecated
+ md4, md4_init, md4_update, md4_final,
md5, md5_init, md5_update, md5_final,
sha, sha_init, sha_update, sha_final,
- sha224, sha224_init, sha224_update, sha224_final,
- sha256, sha256_init, sha256_update, sha256_final,
- sha384, sha384_init, sha384_update, sha384_final,
- sha512, sha512_init, sha512_update, sha512_final,
md5_mac, md5_mac_96,
sha_mac, sha_mac_96,
- sha224_mac, sha256_mac, sha384_mac, sha512_mac,
+ %%
+ block_encrypt, block_decrypt,
+ %% deprecated
des_cbc_encrypt, des_cbc_decrypt,
des_cfb_encrypt, des_cfb_decrypt,
des_ecb_encrypt, des_ecb_decrypt,
des3_cbc_encrypt, des3_cbc_decrypt,
des3_cfb_encrypt, des3_cfb_decrypt,
aes_cfb_128_encrypt, aes_cfb_128_decrypt,
+ rc2_cbc_encrypt, rc2_cbc_decrypt,
+ rc2_40_cbc_encrypt, rc2_40_cbc_decrypt,
+ aes_cbc_128_encrypt, aes_cbc_128_decrypt,
+ aes_cbc_256_encrypt, aes_cbc_256_decrypt,
+ blowfish_cbc_encrypt, blowfish_cbc_decrypt,
+ blowfish_cfb64_encrypt, blowfish_cfb64_decrypt,
+ blowfish_ecb_encrypt, blowfish_ecb_decrypt, blowfish_ofb64_encrypt,
+ %%
rand_bytes,
strong_rand_bytes,
- strong_rand_mpint,
rand_uniform,
- mod_exp, mod_exp_prime,
+ mod_pow,
+ exor,
+ %% deprecated
+ mod_exp,strong_rand_mpint,erlint, mpint,
+ %%
+ sign, verify, generate_key, compute_key,
+ %% deprecated
dss_verify,dss_sign,
rsa_verify,rsa_sign,
rsa_public_encrypt,rsa_private_decrypt,
rsa_private_encrypt,rsa_public_decrypt,
dh_generate_key, dh_compute_key,
- aes_cbc_128_encrypt, aes_cbc_128_decrypt,
- exor,
+ %%
+ stream_init, stream_encrypt, stream_decrypt,
+ %% deprecated
rc4_encrypt, rc4_set_key, rc4_encrypt_with_state,
- rc2_40_cbc_encrypt, rc2_40_cbc_decrypt,
- %% idea_cbc_encrypt, idea_cbc_decrypt,
- aes_cbc_256_encrypt, aes_cbc_256_decrypt,
aes_ctr_encrypt, aes_ctr_decrypt,
aes_ctr_stream_init, aes_ctr_stream_encrypt, aes_ctr_stream_decrypt,
- aes_cbc_ivec, blowfish_cbc_encrypt, blowfish_cbc_decrypt,
- blowfish_cfb64_encrypt, blowfish_cfb64_decrypt,
- blowfish_ecb_encrypt, blowfish_ecb_decrypt, blowfish_ofb64_encrypt,
- des_cbc_ivec, des_cfb_ivec, erlint, mpint,
- hash, hash_init, hash_update, hash_final,
- hmac, hmac_init, hmac_update, hmac_final, hmac_final_n, info,
- rc2_cbc_encrypt, rc2_cbc_decrypt,
- srp_generate_key, srp_compute_key,
+ %%
+ next_iv,
+ %% deprecated
+ aes_cbc_ivec,
+ des_cbc_ivec, des_cfb_ivec,
+ info,
+ %%
info_lib, algorithms]).
+-type mpint() :: binary().
-type rsa_digest_type() :: 'md5' | 'sha' | 'sha224' | 'sha256' | 'sha384' | 'sha512'.
-type dss_digest_type() :: 'none' | 'sha'.
+%%-type ecdsa_digest_type() :: 'md5' | 'sha' | 'sha256' | 'sha384' | 'sha512'.
-type data_or_digest() :: binary() | {digest, binary()}.
-type crypto_integer() :: binary() | integer().
+-type ec_key_res() :: any(). %% nif resource
+-type ec_named_curve() :: atom().
+-type ec_point() :: crypto_integer().
+-type ec_basis() :: {tpbasis, K :: non_neg_integer()} | {ppbasis, K1 :: non_neg_integer(), K2 :: non_neg_integer(), K3 :: non_neg_integer()} | onbasis.
+-type ec_field() :: {prime_field, Prime :: integer()} | {characteristic_two_field, M :: integer(), Basis :: ec_basis()}.
+-type ec_prime() :: {A :: crypto_integer(), B :: crypto_integer(), Seed :: binary() | none}.
+-type ec_curve_spec() :: {Field :: ec_field(), Prime :: ec_prime(), Point :: crypto_integer(), Order :: integer(), CoFactor :: none | integer()}.
+-type ec_curve() :: ec_named_curve() | ec_curve_spec().
+-type ec_key() :: {Curve :: ec_curve(), PrivKey :: binary() | undefined, PubKey :: ec_point() | undefined}.
-define(nif_stub,nif_stub_error(?LINE)).
@@ -565,6 +681,110 @@ sha512_mac(Key, Data, MacSz) ->
sha512_mac_nif(_Key,_Data,_MacSz) -> ?nif_stub.
+
+%% Ecrypt/decrypt %%%
+
+-spec block_encrypt(des_cbc | des_cfb | des3_cbc | des3_cbf | des_ede3 | blowfish_cbc |
+ blowfish_cfb64 | aes_cbc128 | aes_cfb128 | aes_cbc256 | rc2_cbc,
+ Key::iodata(), Ivec::binary(), Data::iodata()) -> binary().
+
+block_encrypt(des_cbc, Key, Ivec, Data) ->
+ des_cbc_encrypt(Key, Ivec, Data);
+block_encrypt(des_cfb, Key, Ivec, Data) ->
+ des_cfb_encrypt(Key, Ivec, Data);
+block_encrypt(des3_cbc, [Key1, Key2, Key3], Ivec, Data) ->
+ des3_cbc_encrypt(Key1, Key2, Key3, Ivec, Data);
+block_encrypt(des3_cbf, [Key1, Key2, Key3], Ivec, Data) ->
+ des3_cfb_encrypt(Key1, Key2, Key3, Ivec, Data);
+block_encrypt(des_ede3, [Key1, Key2, Key3], Ivec, Data) ->
+ des_ede3_cbc_encrypt(Key1, Key2, Key3, Ivec, Data);
+block_encrypt(blowfish_cbc, Key, Ivec, Data) ->
+ blowfish_cbc_encrypt(Key, Ivec, Data);
+block_encrypt(blowfish_cfb64, Key, Ivec, Data) ->
+ blowfish_cfb64_encrypt(Key, Ivec, Data);
+block_encrypt(blowfish_ofb64, Key, Ivec, Data) ->
+ blowfish_ofb64_encrypt(Key, Ivec, Data);
+block_encrypt(aes_cbc128, Key, Ivec, Data) ->
+ aes_cbc_128_encrypt(Key, Ivec, Data);
+block_encrypt(aes_cbc256, Key, Ivec, Data) ->
+ aes_cbc_256_encrypt(Key, Ivec, Data);
+block_encrypt(aes_cfb128, Key, Ivec, Data) ->
+ aes_cfb_128_encrypt(Key, Ivec, Data);
+block_encrypt(rc2_cbc, Key, Ivec, Data) ->
+ rc2_cbc_encrypt(Key, Ivec, Data).
+
+-spec block_decrypt(des_cbc | des_cfb | des3_cbc | des3_cbf | des_ede3 | blowfish_cbc |
+ blowfish_cfb64 | blowfish_ofb64 | aes_cbc128 | aes_cbc256 | aes_cfb128 | rc2_cbc,
+ Key::iodata(), Ivec::binary(), Data::iodata()) -> binary().
+
+block_decrypt(des_cbc, Key, Ivec, Data) ->
+ des_cbc_decrypt(Key, Ivec, Data);
+block_decrypt(des_cfb, Key, Ivec, Data) ->
+ des_cfb_decrypt(Key, Ivec, Data);
+block_decrypt(des3_cbc, [Key1, Key2, Key3], Ivec, Data) ->
+ des3_cbc_decrypt(Key1, Key2, Key3, Ivec, Data);
+block_decrypt(des3_cbf, [Key1, Key2, Key3], Ivec, Data) ->
+ des3_cfb_decrypt(Key1, Key2, Key3, Ivec, Data);
+block_decrypt(des_ede3, [Key1, Key2, Key3], Ivec, Data) ->
+ des_ede3_cbc_decrypt(Key1, Key2, Key3, Ivec, Data);
+block_decrypt(blowfish_cbc, Key, Ivec, Data) ->
+ blowfish_cbc_decrypt(Key, Ivec, Data);
+block_decrypt(blowfish_cfb64, Key, Ivec, Data) ->
+ blowfish_cfb64_decrypt(Key, Ivec, Data);
+block_decrypt(blowfish_ofb, Key, Ivec, Data) ->
+ blowfish_ofb64_decrypt(Key, Ivec, Data);
+block_decrypt(aes_cbc128, Key, Ivec, Data) ->
+ aes_cbc_128_decrypt(Key, Ivec, Data);
+block_decrypt(aes_cbc256, Key, Ivec, Data) ->
+ aes_cbc_256_decrypt(Key, Ivec, Data);
+block_decrypt(aes_cfb128, Key, Ivec, Data) ->
+ aes_cfb_128_decrypt(Key, Ivec, Data);
+block_decrypt(rc2_cbc, Key, Ivec, Data) ->
+ rc2_cbc_decrypt(Key, Ivec, Data).
+
+-spec block_encrypt(des_ecb | blowfish_ecb, Key::iodata(), Data::iodata()) -> binary().
+
+block_encrypt(des_ecb, Key, Data) ->
+ des_ecb_encrypt(Key, Data);
+block_encrypt(blowfish_ecb, Key, Data) ->
+ blowfish_ecb_encrypt(Key, Data).
+
+-spec block_decrypt(des_ecb | blowfish_ecb, Key::iodata(), Data::iodata()) -> binary().
+
+block_decrypt(des_ecb, Key, Data) ->
+ des_ecb_decrypt(Key, Data);
+block_decrypt(blowfish_ecb, Key, Data) ->
+ blowfish_ecb_decrypt(Key, Data).
+
+-spec next_iv(des_cbc | aes_cbc, Data::iodata()) -> binary().
+
+next_iv(des_cbc, Data) ->
+ des_cbc_ivec(Data);
+next_iv(aes_cbc, Data) ->
+ aes_cbc_ivec(Data).
+
+-spec next_iv(des_cbf, Ivec::binary(), Data::iodata()) -> binary().
+
+next_iv(des_cbf, Ivec, Data) ->
+ des_cfb_ivec(Ivec, Data).
+
+stream_init(aes_ctr, Key, Ivec) ->
+ {aes_ctr, aes_ctr_stream_init(Key, Ivec)}.
+stream_init(rc4, Key) ->
+ {rc4, rc4_set_key(Key)}.
+stream_encrypt({aes_ctr, State}, Data) ->
+ {State, Cipher} = aes_ctr_stream_encrypt(State, Data),
+ {{aes_ctr, State}, Cipher};
+stream_encrypt({rc4, State0}, Data) ->
+ {State, Cipher} = rc4_encrypt_with_state(State0, Data),
+ {{rc4, State}, Cipher}.
+stream_decrypt({aes_ctr, State0}, Data) ->
+ {State, Text} = aes_ctr_stream_decrypt(State0, Data),
+ {{aes_ctr, State}, Text};
+stream_decrypt({rc4, State0}, Data) ->
+ {State, Text} = rc4_encrypt_with_state (State0, Data),
+ {{rc4, State}, Text}.
+
%%
%% CRYPTO FUNCTIONS
%%
@@ -713,8 +933,12 @@ blowfish_cfb64_decrypt(Key, IVec, Data) ->
bf_cfb64_crypt(_Key, _IVec, _Data, _IsEncrypt) -> ?nif_stub.
+blowfish_ofb64_decrypt(Key, Ivec, Data) ->
+ blowfish_ofb64_encrypt(Key, Ivec, Data).
+
blowfish_ofb64_encrypt(_Key, _IVec, _Data) -> ?nif_stub.
+
%%
%% AES in cipher feedback mode (CFB)
%%
@@ -798,9 +1022,9 @@ mod_exp(Base, Exponent, Modulo)
mod_exp(Base, Exponent, Modulo) ->
mod_exp_nif(mpint_to_bin(Base),mpint_to_bin(Exponent),mpint_to_bin(Modulo), 4).
--spec mod_exp_prime(binary(), binary(), binary()) -> binary() | error.
-mod_exp_prime(Base, Exponent, Prime) ->
- case mod_exp_nif(Base, Exponent, Prime, 0) of
+-spec mod_pow(binary()|integer(), binary()|integer(), binary()|integer()) -> binary() | error.
+mod_pow(Base, Exponent, Prime) ->
+ case mod_exp_nif(ensure_int_as_bin(Base), ensure_int_as_bin(Exponent), ensure_int_as_bin(Prime), 0) of
<<0>> -> error;
R -> R
end.
@@ -819,19 +1043,40 @@ mod_exp_nif(_Base,_Exp,_Mod,_bin_hdr) -> ?nif_stub.
%% Key = [P,Q,G,Y] P,Q,G=DSSParams Y=PublicKey
dss_verify(Data,Signature,Key) ->
- dss_verify(sha, Data, Signature, Key).
-dss_verify(_Type,_Data,_Signature,_Key) -> ?nif_stub.
+ dss_verify(sha, Data, Signature, Key).
+
+dss_verify(Type,Data,Signature,Key) when is_binary(Data), Type=/=none ->
+ verify(dss,Type,mpint_to_bin(Data),mpint_to_bin(Signature),map_mpint_to_bin(Key));
+dss_verify(Type,Digest,Signature,Key) ->
+ verify(dss,Type,Digest,mpint_to_bin(Signature),map_mpint_to_bin(Key)).
% Key = [E,N] E=PublicExponent N=PublicModulus
rsa_verify(Data,Signature,Key) ->
- rsa_verify_nif(sha, Data,Signature,Key).
-rsa_verify(Type, DataOrDigest, Signature, Key) ->
- case rsa_verify_nif(Type, DataOrDigest, Signature, Key) of
+ rsa_verify(sha, Data,Signature,Key).
+rsa_verify(Type, Data, Signature, Key) when is_binary(Data) ->
+ verify(rsa, Type, mpint_to_bin(Data), mpint_to_bin(Signature), map_mpint_to_bin(Key));
+rsa_verify(Type, Digest, Signature, Key) ->
+ verify(rsa, Type, Digest, mpint_to_bin(Signature), map_mpint_to_bin(Key)).
+
+
+verify(dss, Type, Data, Signature, Key) ->
+ dss_verify_nif(Type, Data, Signature, map_ensure_int_as_bin(Key));
+
+verify(rsa, Type, DataOrDigest, Signature, Key) ->
+ case rsa_verify_nif(Type, DataOrDigest, Signature, map_ensure_int_as_bin(Key)) of
notsup -> erlang:error(notsup);
Bool -> Bool
+ end;
+verify(ecdsa, Type, DataOrDigest, Signature, [Key, Curve]) ->
+ case ecdsa_verify_nif(Type, DataOrDigest, Signature, term_to_ec_key({Curve, undefined, Key})) of
+ notsup -> erlang:error(notsup);
+ Bool -> Bool
end.
+
+dss_verify_nif(_Type, _Data, _Signature, _Key) -> ?nif_stub.
rsa_verify_nif(_Type, _Data, _Signature, _Key) -> ?nif_stub.
+ecdsa_verify_nif(_Type, _DataOrDigest, _Signature, _Key) -> ?nif_stub.
%%
@@ -845,24 +1090,103 @@ rsa_verify_nif(_Type, _Data, _Signature, _Key) -> ?nif_stub.
dss_sign(DataOrDigest,Key) ->
dss_sign(sha,DataOrDigest,Key).
-dss_sign(Type, DataOrDigest, Key) ->
- case dss_sign_nif(Type,DataOrDigest,Key) of
- error -> erlang:error(badkey, [DataOrDigest, Key]);
- Sign -> Sign
- end.
+dss_sign(Type, Data, Key) when is_binary(Data), Type=/=none ->
+ sign(dss, Type, mpint_to_bin(Data), map_mpint_to_bin(Key));
+dss_sign(Type, Digest, Key) ->
+ sign(dss, Type, Digest, map_mpint_to_bin(Key)).
-dss_sign_nif(_Type,_Data,_Key) -> ?nif_stub.
%% Key = [E,N,D] E=PublicExponent N=PublicModulus D=PrivateExponent
rsa_sign(DataOrDigest,Key) ->
rsa_sign(sha, DataOrDigest, Key).
-rsa_sign(Type, DataOrDigest, Key) ->
- case rsa_sign_nif(Type,DataOrDigest,Key) of
+
+rsa_sign(Type, Data, Key) when is_binary(Data) ->
+ sign(rsa, Type, mpint_to_bin(Data), map_mpint_to_bin(Key));
+rsa_sign(Type, Digest, Key) ->
+ sign(rsa, Type, Digest, map_mpint_to_bin(Key)).
+
+map_mpint_to_bin(List) ->
+ lists:map(fun(E) -> mpint_to_bin(E) end, List ).
+
+map_ensure_int_as_bin([H|_]=List) when is_integer(H) ->
+ lists:map(fun(E) -> int_to_bin(E) end, List);
+map_ensure_int_as_bin(List) ->
+ List.
+
+ensure_int_as_bin(Int) when is_integer(Int) ->
+ int_to_bin(Int);
+ensure_int_as_bin(Bin) ->
+ Bin.
+
+map_to_norm_bin([H|_]=List) when is_integer(H) ->
+ lists:map(fun(E) -> int_to_bin(E) end, List);
+map_to_norm_bin(List) ->
+ lists:map(fun(E) -> mpint_to_bin(E) end, List).
+
+
+sign(rsa, Type, DataOrDigest, Key) ->
+ case rsa_sign_nif(Type, DataOrDigest, map_ensure_int_as_bin(Key)) of
+ error -> erlang:error(badkey, [Type,DataOrDigest,Key]);
+ Sign -> Sign
+ end;
+sign(dss, Type, DataOrDigest, Key) ->
+ case dss_sign_nif(Type, DataOrDigest, map_ensure_int_as_bin(Key)) of
+ error -> erlang:error(badkey, [DataOrDigest, Key]);
+ Sign -> Sign
+ end;
+sign(ecdsa, Type, DataOrDigest, [Key, Curve]) ->
+ case ecdsa_sign_nif(Type, DataOrDigest, term_to_ec_key({Curve, Key, undefined})) of
error -> erlang:error(badkey, [Type,DataOrDigest,Key]);
Sign -> Sign
end.
rsa_sign_nif(_Type,_Data,_Key) -> ?nif_stub.
+dss_sign_nif(_Type,_Data,_Key) -> ?nif_stub.
+ecdsa_sign_nif(_Type, _DataOrDigest, _Key) -> ?nif_stub.
+
+
+
+
+-spec public_encrypt(rsa, binary(), [binary()], rsa_padding()) ->
+ binary().
+-spec public_decrypt(rsa, binary(), [integer() | binary()], rsa_padding()) ->
+ binary().
+-spec private_encrypt(rsa, binary(), [integer() | binary()], rsa_padding()) ->
+ binary().
+-spec private_decrypt(rsa, binary(), [integer() | binary()], rsa_padding()) ->
+ binary().
+
+public_encrypt(rsa, BinMesg, Key, Padding) ->
+ case rsa_public_crypt(BinMesg, map_ensure_int_as_bin(Key), Padding, true) of
+ error ->
+ erlang:error(encrypt_failed, [BinMesg,Key, Padding]);
+ Sign -> Sign
+ end.
+
+%% Binary, Key = [E,N,D]
+private_decrypt(rsa, BinMesg, Key, Padding) ->
+ case rsa_private_crypt(BinMesg, map_ensure_int_as_bin(Key), Padding, false) of
+ error ->
+ erlang:error(decrypt_failed, [BinMesg,Key, Padding]);
+ Sign -> Sign
+ end.
+
+
+%% Binary, Key = [E,N,D]
+private_encrypt(rsa, BinMesg, Key, Padding) ->
+ case rsa_private_crypt(BinMesg, map_ensure_int_as_bin(Key), Padding, true) of
+ error ->
+ erlang:error(encrypt_failed, [BinMesg,Key, Padding]);
+ Sign -> Sign
+ end.
+
+%% Binary, Key = [E,N]
+public_decrypt(rsa, BinMesg, Key, Padding) ->
+ case rsa_public_crypt(BinMesg, map_ensure_int_as_bin(Key), Padding, false) of
+ error ->
+ erlang:error(decrypt_failed, [BinMesg,Key, Padding]);
+ Sign -> Sign
+ end.
%%
@@ -872,16 +1196,16 @@ rsa_sign_nif(_Type,_Data,_Key) -> ?nif_stub.
-spec rsa_public_encrypt(binary(), [binary()], rsa_padding()) ->
binary().
--spec rsa_public_decrypt(binary(), [binary()], rsa_padding()) ->
+-spec rsa_public_decrypt(binary(), [integer() | mpint()], rsa_padding()) ->
binary().
--spec rsa_private_encrypt(binary(), [binary()], rsa_padding()) ->
+-spec rsa_private_encrypt(binary(), [integer() | mpint()], rsa_padding()) ->
binary().
--spec rsa_private_decrypt(binary(), [binary()], rsa_padding()) ->
+-spec rsa_private_decrypt(binary(), [integer() | mpint()], rsa_padding()) ->
binary().
%% Binary, Key = [E,N]
rsa_public_encrypt(BinMesg, Key, Padding) ->
- case rsa_public_crypt(BinMesg, Key, Padding, true) of
+ case rsa_public_crypt(BinMesg, map_to_norm_bin(Key), Padding, true) of
error ->
erlang:error(encrypt_failed, [BinMesg,Key, Padding]);
Sign -> Sign
@@ -891,7 +1215,7 @@ rsa_public_crypt(_BinMsg, _Key, _Padding, _IsEncrypt) -> ?nif_stub.
%% Binary, Key = [E,N,D]
rsa_private_decrypt(BinMesg, Key, Padding) ->
- case rsa_private_crypt(BinMesg, Key, Padding, false) of
+ case rsa_private_crypt(BinMesg, map_to_norm_bin(Key), Padding, false) of
error ->
erlang:error(decrypt_failed, [BinMesg,Key, Padding]);
Sign -> Sign
@@ -902,7 +1226,7 @@ rsa_private_crypt(_BinMsg, _Key, _Padding, _IsEncrypt) -> ?nif_stub.
%% Binary, Key = [E,N,D]
rsa_private_encrypt(BinMesg, Key, Padding) ->
- case rsa_private_crypt(BinMesg, Key, Padding, true) of
+ case rsa_private_crypt(BinMesg, map_to_norm_bin(Key), Padding, true) of
error ->
erlang:error(encrypt_failed, [BinMesg,Key, Padding]);
Sign -> Sign
@@ -910,7 +1234,7 @@ rsa_private_encrypt(BinMesg, Key, Padding) ->
%% Binary, Key = [E,N]
rsa_public_decrypt(BinMesg, Key, Padding) ->
- case rsa_public_crypt(BinMesg, Key, Padding, false) of
+ case rsa_public_crypt(BinMesg, map_to_norm_bin(Key), Padding, false) of
error ->
erlang:error(decrypt_failed, [BinMesg,Key, Padding]);
Sign -> Sign
@@ -1052,120 +1376,142 @@ dh_check([_Prime,_Gen]) -> ?nif_stub.
{binary(),binary()}.
dh_generate_key(DHParameters) ->
- dh_generate_key(undefined, DHParameters).
+ dh_generate_key_nif(undefined, map_mpint_to_bin(DHParameters), 4).
dh_generate_key(PrivateKey, DHParameters) ->
- case dh_generate_key_nif(PrivateKey, DHParameters) of
- error -> erlang:error(generation_failed, [PrivateKey,DHParameters]);
- Res -> Res
- end.
+ dh_generate_key_nif(mpint_to_bin(PrivateKey), map_mpint_to_bin(DHParameters), 4).
-dh_generate_key_nif(_PrivateKey, _DHParameters) -> ?nif_stub.
+dh_generate_key_nif(_PrivateKey, _DHParameters, _Mpint) -> ?nif_stub.
%% DHParameters = [P (Prime)= mpint(), G(Generator) = mpint()]
-%% MyPrivKey, OthersPublicKey = mpint()
+%% MyPrivKey, OthersPublicKey = mpint()
-spec dh_compute_key(binary(), binary(), [binary()]) -> binary().
dh_compute_key(OthersPublicKey, MyPrivateKey, DHParameters) ->
- case dh_compute_key_nif(OthersPublicKey,MyPrivateKey,DHParameters) of
- error -> erlang:error(computation_failed, [OthersPublicKey,MyPrivateKey,DHParameters]);
- Ret -> Ret
- end.
+ compute_key(dh, mpint_to_bin(OthersPublicKey), mpint_to_bin(MyPrivateKey),
+ map_mpint_to_bin(DHParameters)).
+
dh_compute_key_nif(_OthersPublicKey, _MyPrivateKey, _DHParameters) -> ?nif_stub.
+generate_key(Type, Params) ->
+ generate_key(Type, Params, undefined).
+
+generate_key(dh, DHParameters, PrivateKey) ->
+ dh_generate_key_nif(PrivateKey, map_ensure_int_as_bin(DHParameters), 0);
+
+generate_key(srp, {host, [Verifier, Generator, Prime, Version]}, PrivArg)
+ when is_binary(Verifier), is_binary(Generator), is_binary(Prime), is_atom(Version) ->
+ Private = case PrivArg of
+ undefined -> random_bytes(32);
+ _ -> PrivArg
+ end,
+ host_srp_gen_key(Private, Verifier, Generator, Prime, Version);
+
+generate_key(srp, {user, [Generator, Prime, Version]}, PrivateArg)
+ when is_binary(Generator), is_binary(Prime), is_atom(Version) ->
+ Private = case PrivateArg of
+ undefined -> random_bytes(32);
+ _ -> PrivateArg
+ end,
+ user_srp_gen_key(Private, Generator, Prime);
-%%% SRP
--spec srp_generate_key(binary(), binary(), atom() | binary(), atom() | binary() ) -> {Public::binary(), Private::binary()}.
-srp_generate_key(Verifier, Generator, Prime, Version) when is_binary(Verifier),
- is_binary(Generator),
- is_binary(Prime),
- is_atom(Version) ->
- Private = random_bytes(32),
- server_srp_gen_key(Private, Verifier, Generator, Prime, Version);
-
-srp_generate_key(Generator, Prime, Version, Private) when is_binary(Generator),
- is_binary(Prime),
- is_atom(Version),
- is_binary(Private) ->
- client_srp_gen_key(Private, Generator, Prime).
-
--spec srp_generate_key(binary(), binary(), binary(), atom(), binary()) -> {Public::binary(), Private::binary()}.
-srp_generate_key(Verifier, Generator, Prime, Version, Private) when is_binary(Verifier),
- is_binary(Generator),
- is_binary(Prime),
- is_atom(Version),
- is_binary(Private)
- ->
- server_srp_gen_key(Private, Verifier, Generator, Prime, Version).
-
--spec srp_generate_key(binary(), binary(), atom()) -> {Public::binary(), Private::binary()}.
-srp_generate_key(Generator, Prime, Version) when is_binary(Generator),
- is_binary(Prime),
- is_atom(Version) ->
- Private = random_bytes(32),
- client_srp_gen_key(Private, Generator, Prime).
-
--spec srp_compute_key(binary(), binary(), binary(), binary(), binary(), atom()| binary(), atom() | binary() ) -> binary().
-srp_compute_key(DerivedKey, Prime, Generator, ClientPublic, ClientPrivate, ServerPublic, Version) when
- is_binary(Prime),
+generate_key(ecdh, Curve, undefined) ->
+ ec_key_to_term(ec_key_generate(Curve)).
+
+
+ec_key_generate(_Key) -> ?nif_stub.
+
+
+compute_key(dh, OthersPublicKey, MyPrivateKey, DHParameters) ->
+ case dh_compute_key_nif(OthersPublicKey,MyPrivateKey, map_ensure_int_as_bin(DHParameters)) of
+ error -> erlang:error(computation_failed,
+ [OthersPublicKey,MyPrivateKey,DHParameters]);
+ Ret -> Ret
+ end;
+
+compute_key(srp, HostPublic, {UserPublic, UserPrivate},
+ {user, [DerivedKey, Prime, Generator, Version | ScramblerArg]}) when
+ is_binary(Prime),
is_binary(Generator),
- is_binary(ClientPublic),
- is_binary(ClientPrivate),
- is_binary(ServerPublic),
+ is_binary(UserPublic),
+ is_binary(UserPrivate),
+ is_binary(HostPublic),
is_atom(Version) ->
Multiplier = srp_multiplier(Version, Generator, Prime),
- Scrambler = srp_scrambler(Version, ClientPublic, ServerPublic, Prime),
- srp_client_secret_nif(ClientPrivate, Scrambler, ServerPublic, Multiplier,
- Generator, DerivedKey, Prime);
-
-srp_compute_key(Verifier, Prime, ClientPublic, ServerPublic, ServerPrivate, Version, Scrambler) when
+ Scrambler = case ScramblerArg of
+ [] -> srp_scrambler(Version, UserPublic, HostPublic, Prime);
+ [S] -> S
+ end,
+ srp_user_secret_nif(UserPrivate, Scrambler, HostPublic, Multiplier,
+ Generator, DerivedKey, Prime);
+
+compute_key(srp, UserPublic, {HostPublic, HostPrivate},
+ {host,[Verifier, Prime, Version | ScramblerArg]}) when
is_binary(Verifier),
- is_binary(Prime),
- is_binary(ClientPublic),
- is_binary(ServerPublic),
- is_binary(ServerPrivate),
- is_atom(Version),
- is_binary(Scrambler) ->
- srp_server_secret_nif(Verifier, ServerPrivate, Scrambler, ClientPublic, Prime).
-
--spec srp_compute_key(binary(), binary(), binary(), binary(), binary(), binary(), atom(), binary()) -> binary().
-srp_compute_key(DerivedKey, Prime, Generator, ClientPublic, ClientPrivate,
- ServerPublic, Version, Scrambler) when is_binary(DerivedKey),
- is_binary(Prime),
- is_binary(Generator),
- is_binary(ClientPublic),
- is_binary(ClientPrivate),
- is_binary(ServerPublic),
- is_atom(Version),
- is_binary(Scrambler) ->
- Multiplier = srp_multiplier(Version, Generator, Prime),
- srp_client_secret_nif(ClientPrivate, Scrambler, ServerPublic, Multiplier,
- Generator, DerivedKey, Prime).
-
--spec srp_compute_key(binary(), binary(), binary(), binary(), binary(), atom()) -> binary().
-srp_compute_key(Verifier, Prime, ClientPublic, ServerPublic, ServerPrivate, Version) when
- is_binary(Verifier),
- is_binary(Prime),
- is_binary(ClientPublic),
- is_binary(ServerPublic),
- is_binary(ServerPrivate),
+ is_binary(Prime),
+ is_binary(UserPublic),
+ is_binary(HostPublic),
+ is_binary(HostPrivate),
is_atom(Version) ->
- Scrambler = srp_scrambler(Version, ClientPublic, ServerPublic, Prime),
- srp_server_secret_nif(Verifier, ServerPrivate, Scrambler, ClientPublic, Prime).
+ Scrambler = case ScramblerArg of
+ [] -> srp_scrambler(Version, UserPublic, HostPublic, Prime);
+ [S] -> S
+ end,
+ srp_host_secret_nif(Verifier, HostPrivate, Scrambler, UserPublic, Prime);
+
+compute_key(ecdh, Others, My, Curve) ->
+ ecdh_compute_key_nif(Others, term_to_ec_key({Curve,My,undefined})).
+
+ecdh_compute_key_nif(_Others, _My) -> ?nif_stub.
+
%%
+%% EC
+%%
+ec_key_to_term(Key) ->
+ case ec_key_to_term_nif(Key) of
+ {PrivKey, PubKey} ->
+ {bin_to_int(PrivKey), PubKey};
+ _ ->
+ erlang:error(conversion_failed)
+ end.
+
+ec_key_to_term_nif(_Key) -> ?nif_stub.
+
+term_to_nif_prime({prime_field, Prime}) ->
+ {prime_field, int_to_bin(Prime)};
+term_to_nif_prime(PrimeField) ->
+ PrimeField.
+term_to_nif_curve({A, B, Seed}) ->
+ {ensure_int_as_bin(A), ensure_int_as_bin(B), Seed}.
+term_to_nif_curve_parameters({PrimeField, Curve, BasePoint, Order, CoFactor}) ->
+ {term_to_nif_prime(PrimeField), term_to_nif_curve(Curve), ensure_int_as_bin(BasePoint), int_to_bin(Order), int_to_bin(CoFactor)};
+term_to_nif_curve_parameters(Curve) when is_atom(Curve) ->
+ %% named curve
+ Curve.
+
+-spec term_to_ec_key(ec_key()) -> ec_key_res().
+term_to_ec_key({Curve, undefined, PubKey}) ->
+ term_to_ec_key_nif(term_to_nif_curve_parameters(Curve), undefined, PubKey);
+term_to_ec_key({Curve, PrivKey, PubKey}) ->
+ term_to_ec_key_nif(term_to_nif_curve_parameters(Curve), int_to_bin(PrivKey), PubKey).
+
+term_to_ec_key_nif(_Curve, _PrivKey, _PubKey) -> ?nif_stub.
+
+
+
%% LOCAL FUNCTIONS
%%
-client_srp_gen_key(Private, Generator, Prime) ->
- case mod_exp_prime(Generator, Private, Prime) of
+user_srp_gen_key(Private, Generator, Prime) ->
+ case mod_pow(Generator, Private, Prime) of
error ->
error;
Public ->
{Public, Private}
end.
-server_srp_gen_key(Private, Verifier, Generator, Prime, Version) ->
+host_srp_gen_key(Private, Verifier, Generator, Prime, Version) ->
Multiplier = srp_multiplier(Version, Generator, Prime),
case srp_value_B_nif(Multiplier, Verifier, Generator, Private, Prime) of
error ->
@@ -1185,17 +1531,17 @@ srp_multiplier('6', _, _) ->
srp_multiplier('3', _, _) ->
<<1/integer>>.
-srp_scrambler(Version, ClientPublic, ServerPublic, Prime) when Version == '6'; Version == '6a'->
+srp_scrambler(Version, UserPublic, HostPublic, Prime) when Version == '6'; Version == '6a'->
%% SHA1(PAD(A) | PAD(B)) from http://srp.stanford.edu/design.html
PadLength = erlang:byte_size(Prime),
C0 = sha_init(),
- C1 = sha_update(C0, srp_pad_to(PadLength, ClientPublic)),
- C2 = sha_update(C1, srp_pad_to(PadLength, ServerPublic)),
+ C1 = sha_update(C0, srp_pad_to(PadLength, UserPublic)),
+ C2 = sha_update(C1, srp_pad_to(PadLength, HostPublic)),
sha_final(C2);
-srp_scrambler('3', _, ServerPublic, _Prime) ->
+srp_scrambler('3', _, HostPublic, _Prime) ->
%% The parameter u is a 32-bit unsigned integer which takes its value
%% from the first 32 bits of the SHA1 hash of B, MSB first.
- <<U:32/bits, _/binary>> = sha(ServerPublic),
+ <<U:32/bits, _/binary>> = sha(HostPublic),
U.
srp_pad_length(Width, Length) ->
@@ -1207,9 +1553,9 @@ srp_pad_to(Width, Binary) ->
N -> << 0:(N*8), Binary/binary>>
end.
-srp_server_secret_nif(_Verifier, _B, _U, _A, _Prime) -> ?nif_stub.
+srp_host_secret_nif(_Verifier, _B, _U, _A, _Prime) -> ?nif_stub.
-srp_client_secret_nif(_A, _U, _B, _Multiplier, _Generator, _Exponent, _Prime) -> ?nif_stub.
+srp_user_secret_nif(_A, _U, _B, _Multiplier, _Generator, _Exponent, _Prime) -> ?nif_stub.
srp_value_B_nif(_Multiplier, _Verifier, _Generator, _Exponent, _Prime) -> ?nif_stub.
@@ -1253,10 +1599,12 @@ int_to_bin_neg(X,Ds) ->
int_to_bin_neg(X bsr 8, [(X band 255)|Ds]).
-bin_to_int(Bin) ->
+bin_to_int(Bin) when is_binary(Bin) ->
Bits = bit_size(Bin),
<<Integer:Bits/integer>> = Bin,
- Integer.
+ Integer;
+bin_to_int(undefined) ->
+ undefined.
%% int from integer in a binary with 32bit length
erlint(<<MPIntSize:32/integer,MPIntValue/binary>>) ->
diff --git a/lib/crypto/test/crypto_SUITE.erl b/lib/crypto/test/crypto_SUITE.erl
index 08ecad3233..eddb6b83f9 100644
--- a/lib/crypto/test/crypto_SUITE.erl
+++ b/lib/crypto/test/crypto_SUITE.erl
@@ -76,6 +76,7 @@
rsa_encrypt_decrypt/1,
dh/1,
srp3/1, srp6/1, srp6a/1,
+ ec/1,
exor_test/1,
rc4_test/1,
rc4_stream_test/1,
@@ -105,7 +106,7 @@ groups() ->
rand_uniform_test, strong_rand_test,
rsa_verify_test, dsa_verify_test, rsa_sign_test,
rsa_sign_hash_test, dsa_sign_test, dsa_sign_hash_test,
- rsa_encrypt_decrypt, dh, srp3, srp6, srp6a, exor_test,
+ rsa_encrypt_decrypt, dh, srp3, srp6, srp6a, ec, exor_test,
rc4_test, rc4_stream_test, mod_exp_test, blowfish_cfb64,
smp]}].
@@ -190,8 +191,8 @@ ldd_program() ->
Ldd when is_list(Ldd) -> Ldd
end.
-%%
-%%
+
+
info(doc) ->
["Call the info function."];
info(suite) ->
@@ -207,10 +208,10 @@ info(Config) when is_list(Config) ->
?line [] = Info -- Exports,
?line NotInInfo = Exports -- Info,
io:format("NotInInfo = ~p\n", [NotInInfo]),
- BlackList = lists:sort([des_ede3_cbc_decrypt, des_ede3_cbc_encrypt,
- dh_check, dh_generate_parameters,
- module_info, start, stop, version]),
- ?line BlackList = NotInInfo,
+ %% BlackList = lists:sort([des_ede3_cbc_decrypt, des_ede3_cbc_encrypt,
+ %% dh_check, dh_generate_parameters,
+ %% module_info, start, stop, version]),
+ %% ?line BlackList = NotInInfo,
?line InfoLib = crypto:info_lib(),
?line [_|_] = InfoLib,
@@ -221,10 +222,10 @@ info(Config) when is_list(Config) ->
Me(T,Me);
([],_) ->
ok
- end,
+ end,
?line F(InfoLib,F),
?line crypto:stop()
- end.
+ end.
%%
%%
@@ -359,7 +360,7 @@ hmac_update_sha(Config) when is_list(Config) ->
?line Ctx2 = crypto:hmac_update(Ctx, Data),
?line Ctx3 = crypto:hmac_update(Ctx2, Data2),
?line Mac = crypto:hmac_final(Ctx3),
- ?line Exp = crypto:sha_mac(Key, lists:flatten([Data, Data2])),
+ ?line Exp = crypto:hmac(sha, Key, lists:flatten([Data, Data2])),
?line m(Exp, Mac).
hmac_update_sha256(doc) ->
@@ -381,7 +382,7 @@ hmac_update_sha256_do() ->
?line Ctx2 = crypto:hmac_update(Ctx, Data),
?line Ctx3 = crypto:hmac_update(Ctx2, Data2),
?line Mac = crypto:hmac_final(Ctx3),
- ?line Exp = crypto:sha256_mac(Key, lists:flatten([Data, Data2])),
+ ?line Exp = crypto:hmac(sha256, Key, lists:flatten([Data, Data2])),
?line m(Exp, Mac).
hmac_update_sha512(doc) ->
@@ -403,7 +404,7 @@ hmac_update_sha512_do() ->
?line Ctx2 = crypto:hmac_update(Ctx, Data),
?line Ctx3 = crypto:hmac_update(Ctx2, Data2),
?line Mac = crypto:hmac_final(Ctx3),
- ?line Exp = crypto:sha512_mac(Key, lists:flatten([Data, Data2])),
+ ?line Exp = crypto:hmac(sha512, Key, lists:flatten([Data, Data2])),
?line m(Exp, Mac).
hmac_update_md5(doc) ->
@@ -618,68 +619,64 @@ hmac_rfc4231_sha512(suite) ->
hmac_rfc4231_sha512(Config) when is_list(Config) ->
if_supported(sha512, fun() -> hmac_rfc4231_sha512_do() end).
-hmac_rfc4231_case(Hash, HashFun, case1, Exp) ->
+hmac_rfc4231_case(Hash, case1, Exp) ->
%% Test 1
Key = binary:copy(<<16#0b>>, 20),
Data = <<"Hi There">>,
- hmac_rfc4231_case(Hash, HashFun, Key, Data, Exp);
+ hmac_rfc4231_case(Hash, Key, Data, Exp);
-hmac_rfc4231_case(Hash, HashFun, case2, Exp) ->
+hmac_rfc4231_case(Hash, case2, Exp) ->
%% Test 2
Key = <<"Jefe">>,
Data = <<"what do ya want for nothing?">>,
- hmac_rfc4231_case(Hash, HashFun, Key, Data, Exp);
+ hmac_rfc4231_case(Hash, Key, Data, Exp);
-hmac_rfc4231_case(Hash, HashFun, case3, Exp) ->
+hmac_rfc4231_case(Hash, case3, Exp) ->
%% Test 3
Key = binary:copy(<<16#aa>>, 20),
Data = binary:copy(<<16#dd>>, 50),
- hmac_rfc4231_case(Hash, HashFun, Key, Data, Exp);
+ hmac_rfc4231_case(Hash, Key, Data, Exp);
-hmac_rfc4231_case(Hash, HashFun, case4, Exp) ->
+hmac_rfc4231_case(Hash, case4, Exp) ->
%% Test 4
Key = list_to_binary(lists:seq(1, 16#19)),
Data = binary:copy(<<16#cd>>, 50),
- hmac_rfc4231_case(Hash, HashFun, Key, Data, Exp);
+ hmac_rfc4231_case(Hash, Key, Data, Exp);
-hmac_rfc4231_case(Hash, HashFun, case5, Exp) ->
+hmac_rfc4231_case(Hash, case5, Exp) ->
%% Test 5
Key = binary:copy(<<16#0c>>, 20),
Data = <<"Test With Truncation">>,
- hmac_rfc4231_case(Hash, HashFun, Key, Data, 16, Exp);
+ hmac_rfc4231_case(Hash, Key, Data, 16, Exp);
-hmac_rfc4231_case(Hash, HashFun, case6, Exp) ->
+hmac_rfc4231_case(Hash, case6, Exp) ->
%% Test 6
Key = binary:copy(<<16#aa>>, 131),
Data = <<"Test Using Larger Than Block-Size Key - Hash Key First">>,
- hmac_rfc4231_case(Hash, HashFun, Key, Data, Exp);
+ hmac_rfc4231_case(Hash, Key, Data, Exp);
-hmac_rfc4231_case(Hash, HashFun, case7, Exp) ->
+hmac_rfc4231_case(Hash, case7, Exp) ->
%% Test Case 7
Key = binary:copy(<<16#aa>>, 131),
Data = <<"This is a test using a larger than block-size key and a larger t",
"han block-size data. The key needs to be hashed before being use",
"d by the HMAC algorithm.">>,
- hmac_rfc4231_case(Hash, HashFun, Key, Data, Exp).
+ hmac_rfc4231_case(Hash, Key, Data, Exp).
-hmac_rfc4231_case(Hash, HashFun, Key, Data, Exp) ->
+hmac_rfc4231_case(Hash, Key, Data, Exp) ->
?line Ctx = crypto:hmac_init(Hash, Key),
?line Ctx2 = crypto:hmac_update(Ctx, Data),
?line Mac1 = crypto:hmac_final(Ctx2),
- ?line Mac2 = crypto:HashFun(Key, Data),
?line Mac3 = crypto:hmac(Hash, Key, Data),
?line m(Exp, Mac1),
- ?line m(Exp, Mac2),
?line m(Exp, Mac3).
-hmac_rfc4231_case(Hash, HashFun, Key, Data, Trunc, Exp) ->
+hmac_rfc4231_case(Hash, Key, Data, Trunc, Exp) ->
?line Ctx = crypto:hmac_init(Hash, Key),
?line Ctx2 = crypto:hmac_update(Ctx, Data),
?line Mac1 = crypto:hmac_final_n(Ctx2, Trunc),
- ?line Mac2 = crypto:HashFun(Key, Data, Trunc),
?line Mac3 = crypto:hmac(Hash, Key, Data, Trunc),
?line m(Exp, Mac1),
- ?line m(Exp, Mac2),
?line m(Exp, Mac3).
hmac_rfc4231_sha224_do() ->
@@ -696,7 +693,7 @@ hmac_rfc4231_sha224_do() ->
"d499f112f2d2b7273fa6870e"),
Case7 = hexstr2bin("3a854166ac5d9f023f54d517d0b39dbd"
"946770db9c2b95c9f6f565d1"),
- hmac_rfc4231_cases_do(sha224, sha224_mac, [Case1, Case2, Case3, Case4, Case5, Case6, Case7]).
+ hmac_rfc4231_cases_do(sha224, [Case1, Case2, Case3, Case4, Case5, Case6, Case7]).
hmac_rfc4231_sha256_do() ->
Case1 = hexstr2bin("b0344c61d8db38535ca8afceaf0bf12b"
@@ -712,7 +709,7 @@ hmac_rfc4231_sha256_do() ->
"8e0bc6213728c5140546040f0ee37f54"),
Case7 = hexstr2bin("9b09ffa71b942fcb27635fbcd5b0e944"
"bfdc63644f0713938a7f51535c3a35e2"),
- hmac_rfc4231_cases_do(sha256, sha256_mac, [Case1, Case2, Case3, Case4, Case5, Case6, Case7]).
+ hmac_rfc4231_cases_do(sha256, [Case1, Case2, Case3, Case4, Case5, Case6, Case7]).
hmac_rfc4231_sha384_do() ->
Case1 = hexstr2bin("afd03944d84895626b0825f4ab46907f"
@@ -734,7 +731,7 @@ hmac_rfc4231_sha384_do() ->
Case7 = hexstr2bin("6617178e941f020d351e2f254e8fd32c"
"602420feb0b8fb9adccebb82461e99c5"
"a678cc31e799176d3860e6110c46523e"),
- hmac_rfc4231_cases_do(sha384, sha384_mac, [Case1, Case2, Case3, Case4, Case5, Case6, Case7]).
+ hmac_rfc4231_cases_do(sha384, [Case1, Case2, Case3, Case4, Case5, Case6, Case7]).
hmac_rfc4231_sha512_do() ->
Case1 = hexstr2bin("87aa7cdea5ef619d4ff0b4241a1d6cb0"
@@ -762,16 +759,16 @@ hmac_rfc4231_sha512_do() ->
"debd71f8867289865df5a32d20cdc944"
"b6022cac3c4982b10d5eeb55c3e4de15"
"134676fb6de0446065c97440fa8c6a58"),
- hmac_rfc4231_cases_do(sha512, sha512_mac, [Case1, Case2, Case3, Case4, Case5, Case6, Case7]).
+ hmac_rfc4231_cases_do(sha512, [Case1, Case2, Case3, Case4, Case5, Case6, Case7]).
-hmac_rfc4231_cases_do(Hash, HashFun, CasesData) ->
- hmac_rfc4231_cases_do(Hash, HashFun, [case1, case2, case3, case4, case5, case6, case7], CasesData).
+hmac_rfc4231_cases_do(Hash, CasesData) ->
+ hmac_rfc4231_cases_do(Hash, [case1, case2, case3, case4, case5, case6, case7], CasesData).
-hmac_rfc4231_cases_do(_Hash, _HashFun, _, []) ->
+hmac_rfc4231_cases_do(_Hash, _, []) ->
ok;
-hmac_rfc4231_cases_do(Hash, HashFun, [C|Cases], [D|CasesData]) ->
- hmac_rfc4231_case(Hash, HashFun, C, D),
- hmac_rfc4231_cases_do(Hash, HashFun, Cases, CasesData).
+hmac_rfc4231_cases_do(Hash, [C|Cases], [D|CasesData]) ->
+ hmac_rfc4231_case(Hash, C, D),
+ hmac_rfc4231_cases_do(Hash, Cases, CasesData).
hmac_update_md5_io(doc) ->
["Generate an MD5 HMAC using hmac_init, hmac_update, and hmac_final. "
@@ -858,10 +855,10 @@ sha256(Config) when is_list(Config) ->
if_supported(sha256, fun() -> sha256_do() end).
sha256_do() ->
- ?line m(crypto:sha256("abc"),
+ ?line m(crypto:hash(sha256, "abc"),
hexstr2bin("BA7816BF8F01CFEA4141"
"40DE5DAE2223B00361A396177A9CB410FF61F20015AD")),
- ?line m(crypto:sha256("abcdbcdecdefdefgefghfghighijhijkijkljklmklm"
+ ?line m(crypto:hash(sha256, "abcdbcdecdefdefgefghfghighijhijkijkljklmklm"
"nlmnomnopnopq"),
hexstr2bin("248D6A61D20638B8"
"E5C026930C3E6039A33CE45964FF2167F6ECEDD419DB06C1")).
@@ -877,10 +874,10 @@ sha256_update(Config) when is_list(Config) ->
if_supported(sha256, fun() -> sha256_update_do() end).
sha256_update_do() ->
- ?line Ctx = crypto:sha256_init(),
- ?line Ctx1 = crypto:sha256_update(Ctx, "abcdbcdecdefdefgefghfghighi"),
- ?line Ctx2 = crypto:sha256_update(Ctx1, "jhijkijkljklmklmnlmnomnopnopq"),
- ?line m(crypto:sha256_final(Ctx2),
+ ?line Ctx = crypto:hash_init(sha256),
+ ?line Ctx1 = crypto:hash_update(Ctx, "abcdbcdecdefdefgefghfghighi"),
+ ?line Ctx2 = crypto:hash_update(Ctx1, "jhijkijkljklmklmnlmnomnopnopq"),
+ ?line m(crypto:hash_final(Ctx2),
hexstr2bin("248D6A61D20638B8"
"E5C026930C3E6039A33CE45964FF2167F6ECEDD419DB06C1")).
@@ -896,11 +893,11 @@ sha512(Config) when is_list(Config) ->
if_supported(sha512, fun() -> sha512_do() end).
sha512_do() ->
- ?line m(crypto:sha512("abc"),
+ ?line m(crypto:hash(sha512, "abc"),
hexstr2bin("DDAF35A193617ABACC417349AE20413112E6FA4E89A97EA2"
"0A9EEEE64B55D39A2192992A274FC1A836BA3C23A3FEEBBD"
"454D4423643CE80E2A9AC94FA54CA49F")),
- ?line m(crypto:sha512("abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmn"
+ ?line m(crypto:hash(sha512, "abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmn"
"hijklmnoijklmnopjklmnopqklmnopqrlmnopqrsmnopqrstnopqrstu"),
hexstr2bin("8E959B75DAE313DA8CF4F72814FC143F8F7779C6EB9F7FA1"
"7299AEADB6889018501D289E4900F7E4331B99DEC4B5433A"
@@ -917,10 +914,10 @@ sha512_update(Config) when is_list(Config) ->
if_supported(sha512, fun() -> sha512_update_do() end).
sha512_update_do() ->
- ?line Ctx = crypto:sha512_init(),
- ?line Ctx1 = crypto:sha512_update(Ctx, "abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmn"),
- ?line Ctx2 = crypto:sha512_update(Ctx1, "hijklmnoijklmnopjklmnopqklmnopqrlmnopqrsmnopqrstnopqrstu"),
- ?line m(crypto:sha512_final(Ctx2),
+ ?line Ctx = crypto:hash_init(sha512),
+ ?line Ctx1 = crypto:hash_update(Ctx, "abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmn"),
+ ?line Ctx2 = crypto:hash_update(Ctx1, "hijklmnoijklmnopjklmnopqklmnopqrlmnopqrsmnopqrstnopqrstu"),
+ ?line m(crypto:hash_final(Ctx2),
hexstr2bin("8E959B75DAE313DA8CF4F72814FC143F8F7779C6EB9F7FA1"
"7299AEADB6889018501D289E4900F7E4331B99DEC4B5433A"
"C7D329EEB6DD26545E96E55B874BE909")).
@@ -1629,8 +1626,11 @@ dsa_verify_test(Config) when is_list(Config) ->
BadArg = (catch my_dss_verify(sized_binary(Msg), <<SizeErr:32, SigBlob/binary>>,
ValidKey)),
- ?line m(element(1,element(2,BadArg)), badarg),
-
+ badarg = case element(1,element(2,BadArg)) of
+ badarg -> badarg;
+ function_clause -> badarg;
+ X -> X
+ end,
InValidKey = [crypto:mpint(P_p),
crypto:mpint(Q_p),
crypto:mpint(G_p),
@@ -1663,20 +1663,29 @@ rsa_sign_test(Config) when is_list(Config) ->
Msg = <<"7896345786348756234 Hejsan Svejsan, erlang crypto debugger"
"09812312908312378623487263487623412039812 huagasd">>,
- PrivKey = [crypto:mpint(PubEx), crypto:mpint(Mod), crypto:mpint(PrivEx)],
- PubKey = [crypto:mpint(PubEx), crypto:mpint(Mod)],
- ?line Sig1 = crypto:rsa_sign(sized_binary(Msg), PrivKey),
- ?line m(crypto:rsa_verify(sized_binary(Msg), sized_binary(Sig1),PubKey), true),
+ PrivKey = [PubEx, Mod, PrivEx],
+ PubKey = [PubEx, Mod],
+ PubKeyMpint = map_int_to_mpint(PubKey),
+ Sig1 = crypto:rsa_sign(sized_binary(Msg), map_int_to_mpint(PrivKey)),
+ Sig1 = crypto:sign(rsa, sha, Msg, PrivKey),
+ true = crypto:rsa_verify(sized_binary(Msg), sized_binary(Sig1), PubKeyMpint),
+ true = crypto:verify(rsa, sha, Msg, Sig1, PubKey),
- ?line Sig2 = crypto:rsa_sign(md5, sized_binary(Msg), PrivKey),
- ?line m(crypto:rsa_verify(md5, sized_binary(Msg), sized_binary(Sig2),PubKey), true),
+ Sig2 = crypto:rsa_sign(md5, sized_binary(Msg), map_int_to_mpint(PrivKey)),
+ Sig2 = crypto:sign(rsa, md5, Msg, PrivKey),
+ true = crypto:rsa_verify(md5, sized_binary(Msg), sized_binary(Sig2), PubKeyMpint),
+ true = crypto:verify(rsa, md5, Msg, Sig2, PubKey),
- ?line m(Sig1 =:= Sig2, false),
- ?line m(crypto:rsa_verify(md5, sized_binary(Msg), sized_binary(Sig1),PubKey), false),
- ?line m(crypto:rsa_verify(sha, sized_binary(Msg), sized_binary(Sig1),PubKey), true),
-
+ false = (Sig1 =:= Sig2),
+ false = crypto:rsa_verify(md5, sized_binary(Msg), sized_binary(Sig1), PubKeyMpint),
+ false = crypto:verify(rsa, md5, Msg, Sig1, PubKey),
+ true = crypto:rsa_verify(sha, sized_binary(Msg), sized_binary(Sig1), PubKeyMpint),
+ true = crypto:verify(rsa, sha, Msg, Sig1, PubKey),
+
ok.
-
+map_int_to_mpint(List) ->
+ lists:map(fun(E) -> crypto:mpint(E) end, List).
+
rsa_sign_hash_test(doc) ->
"rsa_sign_hash testing";
rsa_sign_hash_test(suite) ->
@@ -1774,46 +1783,65 @@ rsa_encrypt_decrypt(Config) when is_list(Config) ->
PrivEx = 7531712708607620783801185371644749935066152052780368689827275932079815492940396744378735701395659435842364793962992309884847527234216715366607660219930945,
Mod = 7919488123861148172698919999061127847747888703039837999377650217570191053151807772962118671509138346758471459464133273114654252861270845708312601272799123,
- PrivKey = [crypto:mpint(PubEx), crypto:mpint(Mod), crypto:mpint(PrivEx)],
- PubKey = [crypto:mpint(PubEx), crypto:mpint(Mod)],
+ PrivKey = [PubEx, Mod, PrivEx],
+ PubKey = [PubEx, Mod],
Msg = <<"7896345786348 Asldi">>,
- ?line PKCS1 = crypto:rsa_public_encrypt(Msg, PubKey, rsa_pkcs1_padding),
- ?line PKCS1Dec = crypto:rsa_private_decrypt(PKCS1, PrivKey, rsa_pkcs1_padding),
+ ?line PKCS1 = rsa_public_encrypt(Msg, PubKey, rsa_pkcs1_padding),
+ ?line PKCS1Dec = rsa_private_decrypt(PKCS1, PrivKey, rsa_pkcs1_padding),
io:format("PKCS1Dec ~p~n",[PKCS1Dec]),
?line Msg = PKCS1Dec,
- ?line OAEP = crypto:rsa_public_encrypt(Msg, PubKey, rsa_pkcs1_oaep_padding),
- ?line Msg = crypto:rsa_private_decrypt(OAEP, PrivKey, rsa_pkcs1_oaep_padding),
+ ?line OAEP = rsa_public_encrypt(Msg, PubKey, rsa_pkcs1_oaep_padding),
+ ?line Msg = rsa_private_decrypt(OAEP, PrivKey, rsa_pkcs1_oaep_padding),
<<Msg2Len:32,_/binary>> = crypto:mpint(Mod),
Msg2 = list_to_binary(lists:duplicate(Msg2Len-1, $X)),
- ?line NoPad = crypto:rsa_public_encrypt(Msg2, PubKey, rsa_no_padding),
- ?line NoPadDec = crypto:rsa_private_decrypt(NoPad, PrivKey, rsa_no_padding),
+ ?line NoPad = rsa_public_encrypt(Msg2, PubKey, rsa_no_padding),
+ ?line NoPadDec = rsa_private_decrypt(NoPad, PrivKey, rsa_no_padding),
?line NoPadDec = Msg2,
- ShouldBeError = (catch crypto:rsa_public_encrypt(Msg, PubKey, rsa_no_padding)),
+ ShouldBeError = (catch rsa_public_encrypt(Msg, PubKey, rsa_no_padding)),
?line {'EXIT', {encrypt_failed,_}} = ShouldBeError,
-%% ?line SSL = crypto:rsa_public_encrypt(Msg, PubKey, rsa_sslv23_padding),
-%% ?line Msg = crypto:rsa_private_decrypt(SSL, PrivKey, rsa_sslv23_padding),
+%% ?line SSL = rsa_public_encrypt(Msg, PubKey, rsa_sslv23_padding),
+%% ?line Msg = rsa_private_decrypt(SSL, PrivKey, rsa_sslv23_padding),
- ?line PKCS1_2 = crypto:rsa_private_encrypt(Msg, PrivKey, rsa_pkcs1_padding),
- ?line PKCS1_2Dec = crypto:rsa_public_decrypt(PKCS1_2, PubKey, rsa_pkcs1_padding),
+ ?line PKCS1_2 = rsa_private_encrypt(Msg, PrivKey, rsa_pkcs1_padding),
+ ?line PKCS1_2Dec = rsa_public_decrypt(PKCS1_2, PubKey, rsa_pkcs1_padding),
io:format("PKCS2Dec ~p~n",[PKCS1_2Dec]),
?line Msg = PKCS1_2Dec,
- ?line PKCS1_3 = crypto:rsa_private_encrypt(Msg2, PrivKey, rsa_no_padding),
- ?line PKCS1_3Dec = crypto:rsa_public_decrypt(PKCS1_3, PubKey, rsa_no_padding),
+ ?line PKCS1_3 = rsa_private_encrypt(Msg2, PrivKey, rsa_no_padding),
+ ?line PKCS1_3Dec = rsa_public_decrypt(PKCS1_3, PubKey, rsa_no_padding),
io:format("PKCS2Dec ~p~n",[PKCS1_3Dec]),
?line Msg2 = PKCS1_3Dec,
?line {'EXIT', {encrypt_failed,_}} =
- (catch crypto:rsa_private_encrypt(Msg, PrivKey, rsa_no_padding)),
+ (catch rsa_private_encrypt(Msg, PrivKey, rsa_no_padding)),
ok.
+rsa_public_encrypt(Msg, Key, Pad) ->
+ C1 = crypto:rsa_public_encrypt(Msg, Key, Pad),
+ C2 = crypto:rsa_public_encrypt(Msg, lists:map(fun(E) -> crypto:mpint(E) end, Key), Pad),
+ {C1,C2}.
+
+rsa_public_decrypt(Msg, Key, Pad) ->
+ R = crypto:rsa_public_decrypt(Msg, Key, Pad),
+ R = crypto:rsa_public_decrypt(Msg, lists:map(fun(E) -> crypto:mpint(E) end, Key), Pad).
+
+rsa_private_encrypt(Msg, Key, Pad) ->
+ R = crypto:rsa_private_encrypt(Msg, Key, Pad),
+ R = crypto:rsa_private_encrypt(Msg, lists:map(fun(E) -> crypto:mpint(E) end, Key), Pad).
+
+rsa_private_decrypt({C1,C2}, Key, Pad) ->
+ R = crypto:rsa_private_decrypt(C1, Key, Pad),
+ R = crypto:rsa_private_decrypt(C2, Key, Pad),
+ R = crypto:rsa_private_decrypt(C1, lists:map(fun(E) -> crypto:mpint(E) end, Key), Pad),
+ R = crypto:rsa_private_decrypt(C2, lists:map(fun(E) -> crypto:mpint(E) end, Key), Pad).
+
dh(doc) ->
["Test dh (Diffie-Hellman) functions."];
@@ -1832,13 +1860,16 @@ dh(Config) when is_list(Config) ->
{param, DHPs} ->
timer:sleep(100),
io:format("DHP ~p~n", [DHPs]),
- ?line {Pub1,Priv1} = crypto:dh_generate_key(DHPs),
+ DHPs_mpint = lists:map(fun(E) -> sized_binary(E) end, DHPs),
+ ?line {Pub1,Priv1} = crypto:generate_key(dh, DHPs),
io:format("Key1:~n~p~n~p~n~n", [Pub1,Priv1]),
- ?line {Pub2,Priv2} = crypto:dh_generate_key(DHPs),
+ ?line {Pub2,Priv2} = crypto:dh_generate_key(DHPs_mpint),
io:format("Key2:~n~p~n~p~n~n", [Pub2,Priv2]),
- ?line A = crypto:dh_compute_key(Pub1, Priv2, DHPs),
+ ?line A = crypto:compute_key(dh, Pub1, unsized_binary(Priv2), DHPs),
+ ?line A = crypto:dh_compute_key(sized_binary(Pub1), Priv2, DHPs_mpint),
timer:sleep(100), %% Get another thread see if that triggers problem
- ?line B = crypto:dh_compute_key(Pub2, Priv1, DHPs),
+ ?line B = crypto:compute_key(dh, unsized_binary(Pub2), Priv1, DHPs),
+ ?line B = crypto:dh_compute_key(Pub2, sized_binary(Priv1), DHPs_mpint),
io:format("A ~p~n",[A]),
io:format("B ~p~n",[B]),
?line A = B
@@ -1847,6 +1878,64 @@ dh(Config) when is_list(Config) ->
exit(Pid, kill)
end.
+
+ec(doc) ->
+ ["Test ec (Ecliptic Curve) functions."];
+ec(suite) -> [];
+ec(Config) when is_list(Config) ->
+ if_supported(ec, fun() -> ec_do() end).
+
+ec_do() ->
+ %% test for a name curve
+ {D2_priv, D2_pub} = crypto:generate_key(ecdh, sect113r2),
+ PrivECDH = [D2_priv, sect113r2],
+ PubECDH = [D2_pub, sect113r2],
+ %%TODO: find a published test case for a EC key
+
+ %% test for a full specified curve and public key,
+ %% taken from csca-germany_013_self_signed_cer.pem
+ PubKey = <<16#04, 16#4a, 16#94, 16#49, 16#81, 16#77, 16#9d, 16#df,
+ 16#1d, 16#a5, 16#e7, 16#c5, 16#27, 16#e2, 16#7d, 16#24,
+ 16#71, 16#a9, 16#28, 16#eb, 16#4d, 16#7b, 16#67, 16#75,
+ 16#ae, 16#09, 16#0a, 16#51, 16#45, 16#19, 16#9b, 16#d4,
+ 16#7e, 16#a0, 16#81, 16#e5, 16#5e, 16#d4, 16#a4, 16#3f,
+ 16#60, 16#7c, 16#6a, 16#50, 16#ee, 16#36, 16#41, 16#8a,
+ 16#87, 16#ff, 16#cd, 16#a6, 16#10, 16#39, 16#ca, 16#95,
+ 16#76, 16#7d, 16#ae, 16#ca, 16#c3, 16#44, 16#3f, 16#e3, 16#2c>>,
+ <<P:264/integer>> = <<16#00, 16#a9, 16#fb, 16#57, 16#db, 16#a1, 16#ee, 16#a9,
+ 16#bc, 16#3e, 16#66, 16#0a, 16#90, 16#9d, 16#83, 16#8d,
+ 16#72, 16#6e, 16#3b, 16#f6, 16#23, 16#d5, 16#26, 16#20,
+ 16#28, 16#20, 16#13, 16#48, 16#1d, 16#1f, 16#6e, 16#53, 16#77>>,
+ <<A:256/integer>> = <<16#7d, 16#5a, 16#09, 16#75, 16#fc, 16#2c, 16#30, 16#57,
+ 16#ee, 16#f6, 16#75, 16#30, 16#41, 16#7a, 16#ff, 16#e7,
+ 16#fb, 16#80, 16#55, 16#c1, 16#26, 16#dc, 16#5c, 16#6c,
+ 16#e9, 16#4a, 16#4b, 16#44, 16#f3, 16#30, 16#b5, 16#d9>>,
+ <<B:256/integer>> = <<16#26, 16#dc, 16#5c, 16#6c, 16#e9, 16#4a, 16#4b, 16#44,
+ 16#f3, 16#30, 16#b5, 16#d9, 16#bb, 16#d7, 16#7c, 16#bf,
+ 16#95, 16#84, 16#16, 16#29, 16#5c, 16#f7, 16#e1, 16#ce,
+ 16#6b, 16#cc, 16#dc, 16#18, 16#ff, 16#8c, 16#07, 16#b6>>,
+ BasePoint = <<16#04, 16#8b, 16#d2, 16#ae, 16#b9, 16#cb, 16#7e, 16#57,
+ 16#cb, 16#2c, 16#4b, 16#48, 16#2f, 16#fc, 16#81, 16#b7,
+ 16#af, 16#b9, 16#de, 16#27, 16#e1, 16#e3, 16#bd, 16#23,
+ 16#c2, 16#3a, 16#44, 16#53, 16#bd, 16#9a, 16#ce, 16#32,
+ 16#62, 16#54, 16#7e, 16#f8, 16#35, 16#c3, 16#da, 16#c4,
+ 16#fd, 16#97, 16#f8, 16#46, 16#1a, 16#14, 16#61, 16#1d,
+ 16#c9, 16#c2, 16#77, 16#45, 16#13, 16#2d, 16#ed, 16#8e,
+ 16#54, 16#5c, 16#1d, 16#54, 16#c7, 16#2f, 16#04, 16#69, 16#97>>,
+ <<Order:264/integer>> = <<16#00, 16#a9, 16#fb, 16#57, 16#db, 16#a1, 16#ee, 16#a9,
+ 16#bc, 16#3e, 16#66, 16#0a, 16#90, 16#9d, 16#83, 16#8d,
+ 16#71, 16#8c, 16#39, 16#7a, 16#a3, 16#b5, 16#61, 16#a6,
+ 16#f7, 16#90, 16#1e, 16#0e, 16#82, 16#97, 16#48, 16#56, 16#a7>>,
+ CoFactor = 1,
+ Curve = {{prime_field,P},{A,B,none},BasePoint, Order,CoFactor},
+
+ Msg = <<99,234,6,64,190,237,201,99,80,248,58,40,70,45,149,218,5,246,242,63>>,
+ Sign = crypto:sign(ecdsa, sha, Msg, PrivECDH),
+ ?line true = crypto:verify(ecdsa, sha, Msg, Sign, PubECDH),
+ ?line false = crypto:verify(ecdsa, sha, Msg, <<10,20>>, PubECDH),
+
+ ok.
+
srp3(doc) ->
["SRP-3 test vectors generated by http://srp.stanford.edu/demo/demo.html"];
srp3(suite) -> [];
@@ -1890,15 +1979,15 @@ srp3(Config) when is_list(Config) ->
"9176A9192615DC0277AE7C12F1F6A7F6563FCA11675D809AF578BDE5"
"2B51E05D440B63099A017A0B45044801"),
UserPassHash = crypto:sha([Salt, crypto:sha([Username, <<$:>>, Password])]),
- Verifier = crypto:mod_exp_prime(Generator, UserPassHash, Prime),
- ClientPublic = crypto:mod_exp_prime(Generator, ClientPrivate, Prime),
+ Verifier = crypto:mod_pow(Generator, UserPassHash, Prime),
+ ClientPublic = crypto:mod_pow(Generator, ClientPrivate, Prime),
- {ClientPublic, ClientPrivate} = crypto:srp_generate_key(Generator, Prime, Version, ClientPrivate),
- {ServerPublic, ServerPrivate} = crypto:srp_generate_key(Verifier, Generator, Prime, Version, ServerPrivate),
- SessionKey = crypto:srp_compute_key(UserPassHash, Prime, Generator, ClientPublic,
- ClientPrivate, ServerPublic, Version, Scrambler),
- SessionKey = crypto:srp_compute_key(Verifier, Prime, ClientPublic,
- ServerPublic, ServerPrivate, Version, Scrambler).
+ {ClientPublic, ClientPrivate} = crypto:generate_key(srp, {user, [Generator, Prime, Version]}, ClientPrivate),
+ {ServerPublic, ServerPrivate} = crypto:generate_key(srp, {host, [Verifier, Generator, Prime, Version]}, ServerPrivate),
+ SessionKey = crypto:compute_key(srp, ServerPublic, {ClientPublic, ClientPrivate},
+ {user, [UserPassHash, Prime, Generator, Version, Scrambler]}),
+ SessionKey = crypto:compute_key(srp, ClientPublic, {ServerPublic, ServerPrivate},
+ {host, [Verifier, Prime, Version, Scrambler]}).
srp6(doc) ->
["SRP-6 test vectors generated by http://srp.stanford.edu/demo/demo.html"];
@@ -1941,15 +2030,15 @@ srp6(Config) when is_list(Config) ->
"72E992AAD89095A84B6A5FADA152369AB1E350A03693BEF044DF3EDF"
"0C34741F4696C30E9F675D09F58ACBEB"),
UserPassHash = crypto:sha([Salt, crypto:sha([Username, <<$:>>, Password])]),
- Verifier = crypto:mod_exp_prime(Generator, UserPassHash, Prime),
- ClientPublic = crypto:mod_exp_prime(Generator, ClientPrivate, Prime),
+ Verifier = crypto:mod_pow(Generator, UserPassHash, Prime),
+ ClientPublic = crypto:mod_pow(Generator, ClientPrivate, Prime),
- {ClientPublic, ClientPrivate} = crypto:srp_generate_key(Generator, Prime, Version, ClientPrivate),
- {ServerPublic, ServerPrivate} = crypto:srp_generate_key(Verifier, Generator, Prime, Version, ServerPrivate),
- SessionKey = crypto:srp_compute_key(UserPassHash, Prime, Generator, ClientPublic,
- ClientPrivate, ServerPublic, Version, Scrambler),
- SessionKey = crypto:srp_compute_key(Verifier, Prime, ClientPublic,
- ServerPublic, ServerPrivate, Version, Scrambler).
+ {ClientPublic, ClientPrivate} = crypto:generate_key(srp, {user, [Generator, Prime, Version]}, ClientPrivate),
+ {ServerPublic, ServerPrivate} = crypto:generate_key(srp, {host, [Verifier, Generator, Prime, Version]}, ServerPrivate),
+ SessionKey = crypto:compute_key(srp, ServerPublic, {ClientPublic, ClientPrivate},
+ {user, [UserPassHash, Prime, Generator, Version, Scrambler]}),
+ SessionKey = crypto:compute_key(srp, ClientPublic, {ServerPublic, ServerPrivate},
+ {host, [Verifier, Prime, Version, Scrambler]}).
srp6a(doc) ->
["SRP-6a test vectors from RFC5054."];
@@ -1992,15 +2081,15 @@ srp6a(Config) when is_list(Config) ->
"3499B200210DCC1F10EB33943CD67FC88A2F39A4BE5BEC4EC0A3212D"
"C346D7E474B29EDE8A469FFECA686E5A"),
UserPassHash = crypto:sha([Salt, crypto:sha([Username, <<$:>>, Password])]),
- Verifier = crypto:mod_exp_prime(Generator, UserPassHash, Prime),
+ Verifier = crypto:mod_pow(Generator, UserPassHash, Prime),
- {ClientPublic, ClientPrivate} = crypto:srp_generate_key(Generator, Prime, Version, ClientPrivate),
- {ServerPublic, ServerPrivate} = crypto:srp_generate_key(Verifier, Generator, Prime, Version, ServerPrivate),
+ {ClientPublic, ClientPrivate} = crypto:generate_key(srp, {user, [Generator, Prime, Version]}, ClientPrivate),
+ {ServerPublic, ServerPrivate} = crypto:generate_key(srp, {host, [Verifier, Generator, Prime, Version]}, ServerPrivate),
- SessionKey = crypto:srp_compute_key(UserPassHash, Prime, Generator, ClientPublic,
- ClientPrivate, ServerPublic, Version, Scrambler),
- SessionKey = crypto:srp_compute_key(Verifier, Prime, ClientPublic,
- ServerPublic, ServerPrivate, Version, Scrambler).
+ SessionKey = crypto:compute_key(srp, ServerPublic, {ClientPublic, ClientPrivate},
+ {user, [UserPassHash, Prime, Generator, Version, Scrambler]}),
+ SessionKey = crypto:compute_key(srp, ClientPublic, {ServerPublic, ServerPrivate},
+ {host, [Verifier, Prime, Version, Scrambler]}).
%%
%%
@@ -2195,6 +2284,9 @@ sized_binary(Binary) when is_binary(Binary) ->
sized_binary(List) ->
sized_binary(list_to_binary(List)).
+unsized_binary(<<Sz:32/integer, Binary:Sz/binary>>) ->
+ Binary.
+
xor_bytes(Bin1, Bin2) when is_binary(Bin1), is_binary(Bin2) ->
L1 = binary_to_list(Bin1),
L2 = binary_to_list(Bin2),
diff --git a/lib/erl_interface/src/connect/ei_connect.c b/lib/erl_interface/src/connect/ei_connect.c
index 3ab86bb340..8f1f231b82 100644
--- a/lib/erl_interface/src/connect/ei_connect.c
+++ b/lib/erl_interface/src/connect/ei_connect.c
@@ -830,7 +830,8 @@ int ei_accept_tmo(ei_cnode* ec, int lfd, ErlConnect *conp, unsigned ms)
error:
EI_TRACE_ERR0("ei_accept","<- ACCEPT failed");
- closesocket(fd);
+ if (fd>=0)
+ closesocket(fd);
return ERL_ERROR;
} /* ei_accept */
diff --git a/lib/ic/java_src/com/ericsson/otp/ic/Environment.java b/lib/ic/java_src/com/ericsson/otp/ic/Environment.java
index fff854a5f8..4b321fbce7 100644
--- a/lib/ic/java_src/com/ericsson/otp/ic/Environment.java
+++ b/lib/ic/java_src/com/ericsson/otp/ic/Environment.java
@@ -135,8 +135,8 @@ public class Environment {
if (connection == null)
connection = self.connect(peer);
- clientP = new com.ericsson.otp.erlang.OtpErlangPid(self); /* This is not perfect */
- send_ref = new com.ericsson.otp.erlang.OtpErlangRef(self);
+ clientP = self.createPid(); /* This is not perfect */
+ send_ref = self.createRef();
}
diff --git a/lib/ic/src/icparse.yrl b/lib/ic/src/icparse.yrl
index d0dd6cde4c..b0286d57f4 100644
--- a/lib/ic/src/icparse.yrl
+++ b/lib/ic/src/icparse.yrl
@@ -230,6 +230,9 @@ Terminals
Rootsymbol '<specification>'.
+Expect 9.
+
+
%%------------------------------------------------------------
%% Clauses
%%
diff --git a/lib/kernel/doc/src/inet.xml b/lib/kernel/doc/src/inet.xml
index 541500a300..7cd98914d1 100644
--- a/lib/kernel/doc/src/inet.xml
+++ b/lib/kernel/doc/src/inet.xml
@@ -559,7 +559,7 @@ fe80::204:acff:fe17:bf38
<c>[Byte1,Byte2|Binary]</c>.</p>
</item>
- <tag><c>{high_msgq_watermark, Size}</c> (TCP/IP sockets)</tag>
+ <tag><c>{high_msgq_watermark, Size}</c></tag>
<item>
<p>The socket message queue will be set into a busy
state when the amount of data queued on the message
@@ -674,7 +674,7 @@ fe80::204:acff:fe17:bf38
the flushing time-out in seconds.</p>
</item>
- <tag><c>{low_msgq_watermark, Size}</c> (TCP/IP sockets)</tag>
+ <tag><c>{low_msgq_watermark, Size}</c></tag>
<item>
<p>If the socket message queue is in a busy state, the
socket message queue will be set in a not busy state when
diff --git a/lib/kernel/src/gen_sctp.erl b/lib/kernel/src/gen_sctp.erl
index 74ad192802..acc116df84 100644
--- a/lib/kernel/src/gen_sctp.erl
+++ b/lib/kernel/src/gen_sctp.erl
@@ -39,7 +39,9 @@
{active, true | false | once} |
{buffer, non_neg_integer()} |
{dontroute, boolean()} |
+ {high_msgq_watermark, pos_integer()} |
{linger, {boolean(), non_neg_integer()}} |
+ {low_msgq_watermark, pos_integer()} |
{mode, list | binary} | list | binary |
{priority, non_neg_integer()} |
{recbuf, non_neg_integer()} |
@@ -68,7 +70,9 @@
active |
buffer |
dontroute |
+ high_msgq_watermark |
linger |
+ low_msgq_watermark |
mode |
priority |
recbuf |
diff --git a/lib/kernel/src/gen_udp.erl b/lib/kernel/src/gen_udp.erl
index c5a1173575..fb5737f82e 100644
--- a/lib/kernel/src/gen_udp.erl
+++ b/lib/kernel/src/gen_udp.erl
@@ -34,6 +34,8 @@
{dontroute, boolean()} |
{drop_membership, {inet:ip_address(), inet:ip_address()}} |
{header, non_neg_integer()} |
+ {high_msgq_watermark, pos_integer()} |
+ {low_msgq_watermark, pos_integer()} |
{mode, list | binary} | list | binary |
{multicast_if, inet:ip_address()} |
{multicast_loop, boolean()} |
@@ -56,6 +58,8 @@
deliver |
dontroute |
header |
+ high_msgq_watermark |
+ low_msgq_watermark |
mode |
multicast_if |
multicast_loop |
diff --git a/lib/kernel/src/inet.erl b/lib/kernel/src/inet.erl
index 9670271b2e..aada1252ad 100644
--- a/lib/kernel/src/inet.erl
+++ b/lib/kernel/src/inet.erl
@@ -712,7 +712,8 @@ udp_options() ->
[tos, priority, reuseaddr, sndbuf, recbuf, header, active, buffer, mode,
deliver, ipv6_v6only,
broadcast, dontroute, multicast_if, multicast_ttl, multicast_loop,
- add_membership, drop_membership, read_packets,raw].
+ add_membership, drop_membership, read_packets,raw,
+ high_msgq_watermark, low_msgq_watermark].
udp_options(Opts, Family) ->
@@ -766,7 +767,7 @@ udp_add(Name, Val, R, Opts, As) ->
sctp_options() ->
[ % The following are generic inet options supported for SCTP sockets:
mode, active, buffer, tos, priority, dontroute, reuseaddr, linger, sndbuf,
- recbuf, ipv6_v6only,
+ recbuf, ipv6_v6only, high_msgq_watermark, low_msgq_watermark,
% Other options are SCTP-specific (though they may be similar to their
% TCP and UDP counter-parts):
diff --git a/lib/kernel/src/inet_int.hrl b/lib/kernel/src/inet_int.hrl
index 000119bc74..a01c733d81 100644
--- a/lib/kernel/src/inet_int.hrl
+++ b/lib/kernel/src/inet_int.hrl
@@ -141,8 +141,8 @@
-define(INET_LOPT_READ_PACKETS, 33).
-define(INET_OPT_RAW, 34).
-define(INET_LOPT_TCP_SEND_TIMEOUT_CLOSE, 35).
--define(INET_LOPT_TCP_MSGQ_HIWTRMRK, 36).
--define(INET_LOPT_TCP_MSGQ_LOWTRMRK, 37).
+-define(INET_LOPT_MSGQ_HIWTRMRK, 36).
+-define(INET_LOPT_MSGQ_LOWTRMRK, 37).
% Specific SCTP options: separate range:
-define(SCTP_OPT_RTOINFO, 100).
-define(SCTP_OPT_ASSOCINFO, 101).
diff --git a/lib/kernel/test/inet_sockopt_SUITE.erl b/lib/kernel/test/inet_sockopt_SUITE.erl
index 75496ce745..185751fead 100644
--- a/lib/kernel/test/inet_sockopt_SUITE.erl
+++ b/lib/kernel/test/inet_sockopt_SUITE.erl
@@ -772,8 +772,10 @@ all_listen_options() ->
{mode,list,binary,true,true},
{deliver,term,port,true,true},
{exit_on_close, true, false, true, true},
- %{high_watermark,4096,8192,true,true},
- %{low_watermark,2048,4096,true,true},
+ {high_watermark,4096,8192,true,true},
+ {low_watermark,2048,4096,true,true},
+ {high_msgq_watermark,4096,8192,true,true},
+ {low_msgq_watermark,2048,4096,true,true},
{send_timeout,infinity,1000,true,true},
{send_timeout_close,false,true,true,true},
{delay_send,false,true,true,true},
@@ -797,6 +799,8 @@ all_connect_options() ->
{exit_on_close, true, false, true, true},
{high_watermark,4096,8192,false,true},
{low_watermark,2048,4096,false,true},
+ {high_msgq_watermark,4096,8192,true,true},
+ {low_msgq_watermark,2048,4096,true,true},
{send_timeout,infinity,1000,true,true},
{send_timeout_close,false,true,true,true},
{delay_send,false,true,true,true},
diff --git a/lib/mnesia/src/mnesia_index.erl b/lib/mnesia/src/mnesia_index.erl
index f9f3ce2ea4..6f9f575d93 100644
--- a/lib/mnesia/src/mnesia_index.erl
+++ b/lib/mnesia/src/mnesia_index.erl
@@ -301,7 +301,13 @@ make_ram_index(Tab, [Pos | Tail]) ->
add_ram_index(Tab, Pos) when is_integer(Pos) ->
verbose("Creating index for ~w ~n", [Tab]),
- Index = mnesia_monitor:mktab(mnesia_index, [bag, public]),
+ SetOrBag = val({Tab, setorbag}),
+ IndexType = case SetOrBag of
+ set -> duplicate_bag;
+ ordered_set -> duplicate_bag;
+ bag -> bag
+ end,
+ Index = mnesia_monitor:mktab(mnesia_index, [IndexType, public]),
Insert = fun(Rec, _Acc) ->
true = ?ets_insert(Index, {element(Pos, Rec), element(2, Rec)})
end,
@@ -309,7 +315,7 @@ add_ram_index(Tab, Pos) when is_integer(Pos) ->
true = ets:foldl(Insert, true, Tab),
mnesia_lib:db_fixtable(ram_copies, Tab, false),
mnesia_lib:set({Tab, {index, Pos}}, Index),
- add_index_info(Tab, val({Tab, setorbag}), {Pos, {ram, Index}});
+ add_index_info(Tab, SetOrBag, {Pos, {ram, Index}});
add_ram_index(_Tab, snmp) ->
ok.
diff --git a/lib/mnesia/src/mnesia_loader.erl b/lib/mnesia/src/mnesia_loader.erl
index 4ba400fbbf..4afbea1cc2 100644
--- a/lib/mnesia/src/mnesia_loader.erl
+++ b/lib/mnesia/src/mnesia_loader.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1998-2011. All Rights Reserved.
+%% Copyright Ericsson AB 1998-2013. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -487,7 +487,8 @@ finish_copy(Storage,Tab,Cs,SenderPid,DatBin,OrigTabRec) ->
subscr_receiver(TabRef = {_, Tab}, RecName) ->
receive
- {mnesia_table_event, {Op, Val, _Tid}} ->
+ {mnesia_table_event, {Op, Val, _Tid}}
+ when element(1, Val) =:= Tab ->
if
Tab == RecName ->
handle_event(TabRef, Op, Val);
@@ -496,6 +497,15 @@ subscr_receiver(TabRef = {_, Tab}, RecName) ->
end,
subscr_receiver(TabRef, RecName);
+ {mnesia_table_event, {Op, Val, _Tid}} when element(1, Val) =:= schema ->
+ %% clear_table is faked via two schema events
+ %% a schema record delete and a write
+ case Op of
+ delete -> handle_event(TabRef, clear_table, {Tab, all});
+ _ -> ok
+ end,
+ subscr_receiver(TabRef, RecName);
+
{'EXIT', Pid, Reason} ->
handle_exit(Pid, Reason),
subscr_receiver(TabRef, RecName)
diff --git a/lib/mnesia/test/mnesia_evil_coverage_test.erl b/lib/mnesia/test/mnesia_evil_coverage_test.erl
index 64b61288ef..0df245b75d 100644
--- a/lib/mnesia/test/mnesia_evil_coverage_test.erl
+++ b/lib/mnesia/test/mnesia_evil_coverage_test.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1996-2011. All Rights Reserved.
+%% Copyright Ericsson AB 1996-2013. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -39,7 +39,7 @@ all() ->
db_node_lifecycle, evil_delete_db_node, start_and_stop,
checkpoint, table_lifecycle, storage_options,
add_copy_conflict,
- add_copy_when_going_down, replica_management,
+ add_copy_when_going_down, replica_management, clear_table_during_load,
schema_availability, local_content,
{group, table_access_modifications}, replica_location,
{group, table_sync}, user_properties, unsupp_user_props,
@@ -569,7 +569,50 @@ storage_options(Config) when is_list(Config) ->
?verify_mnesia(Nodes, []).
+clear_table_during_load(suite) -> [];
+clear_table_during_load(doc) ->
+ ["Clear table caused during load caused a schema entry in the actual tab"];
+clear_table_during_load(Config) when is_list(Config) ->
+ Nodes = [_, Node2] = ?acquire_nodes(2, Config ++ [{tc_timeout, timer:minutes(2)}]),
+ ?match({atomic,ok}, mnesia:create_table(cleartab, [{ram_copies, Nodes}])),
+ Tester = self(),
+ Bin = <<"Testingasdasd", 0:32000>>,
+ Fill = fun() -> [mnesia:write({cleartab, N, Bin}) || N <- lists:seq(1, 3000)], ok end,
+ ?match({atomic, ok}, mnesia:sync_transaction(Fill)),
+
+ StopAndStart = fun() ->
+ stopped = mnesia:stop(),
+ Tester ! {self(), stopped},
+ receive start_node -> ok end,
+ ok = mnesia:start(),
+ ok = mnesia:wait_for_tables([cleartab], 2000),
+ lists:foreach(fun({cleartab,_,_}) -> ok;
+ (What) -> Tester ! {failed, What},
+ unlink(Tester),
+ exit(foo)
+ end,
+ ets:tab2list(cleartab)),
+ Tester ! {self(), ok},
+ normal
+ end,
+ Test = fun(N) ->
+ Pid = spawn_link(Node2, StopAndStart),
+ receive {Pid, stopped} -> ok end,
+ Pid ! start_node,
+ timer:sleep(N*10),
+ {atomic, ok} = mnesia:clear_table(cleartab),
+ receive
+ {Pid, ok} -> ok;
+ {failed, What} ->
+ io:format("Failed in ~p tries, with ~p~n",[N, What]),
+ exit({error, What});
+ {'EXIT', Pid, Reason} ->
+ exit({died, Reason})
+ end
+ end,
+ [Test(N) || N <- lists:seq(1, 10)],
+ ?verify_mnesia(Nodes, []).
add_copy_conflict(suite) -> [];
@@ -599,7 +642,7 @@ add_copy_conflict(Config) when is_list(Config) ->
mnesia_controller:unblock_controller(),
?match_receive({test, {atomic,ok}}),
-
+ ?match(ok, mnesia:wait_for_tables([a,b], 3000)),
?verify_mnesia(Nodes, []),
?cleanup(1, Config).
@@ -635,7 +678,7 @@ add_copy_when_going_down(Config) ->
end,
_Lock = spawn(fun() -> mnesia:transaction(WriteAndWait) end),
Tester = self(),
- spawn_link(fun() -> Res = rpc:call(Node2,mnesia, add_table_copy,
+ spawn_link(fun() -> Res = rpc:call(Node2, mnesia, add_table_copy,
[a, Node2, ram_copies]),
Tester ! {test, Res}
end),
diff --git a/lib/public_key/asn1/ECPrivateKey.asn1 b/lib/public_key/asn1/ECPrivateKey.asn1
new file mode 100644
index 0000000000..a20fa4009c
--- /dev/null
+++ b/lib/public_key/asn1/ECPrivateKey.asn1
@@ -0,0 +1,24 @@
+ECPrivateKey { iso(1) identified-organization(3) dod(6)
+ internet(1) security(5) mechanisms(5) pkix(7) id-mod(0)
+ id-mod-ecprivateKey(65) }
+
+DEFINITIONS EXPLICIT TAGS ::=
+
+BEGIN
+
+-- EXPORTS ALL;
+
+IMPORTS
+
+-- FROM New PKIX ASN.1 [RFC5912]
+
+EcpkParameters FROM PKIX1Algorithms88;
+
+ECPrivateKey ::= SEQUENCE {
+ version INTEGER,
+ privateKey OCTET STRING,
+ parameters [0] EcpkParameters OPTIONAL,
+ publicKey [1] BIT STRING OPTIONAL
+}
+
+END
diff --git a/lib/public_key/asn1/OTP-PKIX.asn1 b/lib/public_key/asn1/OTP-PKIX.asn1
index a90fe2840c..911a156d6c 100644
--- a/lib/public_key/asn1/OTP-PKIX.asn1
+++ b/lib/public_key/asn1/OTP-PKIX.asn1
@@ -103,15 +103,16 @@ IMPORTS
md5WithRSAEncryption,
sha1WithRSAEncryption,
rsaEncryption, RSAPublicKey,
- dhpublicnumber, DomainParameters, DHPublicKey,
+ dhpublicnumber, DomainParameters, DHPublicKey,
id-keyExchangeAlgorithm, KEA-Parms-Id, --KEA-PublicKey,
- ecdsa-with-SHA1,
+ ecdsa-with-SHA1, ecdsa-with-SHA224,
+ ecdsa-with-SHA256, ecdsa-with-SHA384, ecdsa-with-SHA512,
prime-field, Prime-p,
characteristic-two-field, --Characteristic-two,
gnBasis,
tpBasis, Trinomial,
ppBasis, Pentanomial,
- id-ecPublicKey, EcpkParameters, ECPoint
+ id-ecPublicKey, EcpkParameters, ECParameters, ECPoint
FROM PKIX1Algorithms88 { iso(1) identified-organization(3) dod(6)
internet(1) security(5) mechanisms(5) pkix(7) id-mod(0)
id-mod-pkix1-algorithms(17) }
@@ -321,7 +322,11 @@ SupportedSignatureAlgorithms SIGNATURE-ALGORITHM-CLASS ::= {
sha256-with-rsa-encryption |
sha384-with-rsa-encryption |
sha512-with-rsa-encryption |
- ecdsa-with-sha1 }
+ ecdsa-with-sha1 |
+ ecdsa-with-sha224 |
+ ecdsa-with-sha256 |
+ ecdsa-with-sha384 |
+ ecdsa-with-sha512 }
SupportedPublicKeyAlgorithms PUBLIC-KEY-ALGORITHM-CLASS ::= {
dsa | rsa-encryption | dh | kea | ec-public-key }
@@ -439,6 +444,22 @@ SupportedPublicKeyAlgorithms PUBLIC-KEY-ALGORITHM-CLASS ::= {
ID ecdsa-with-SHA1
TYPE NULL } -- XXX Must be empty and not NULL
+ ecdsa-with-sha224 SIGNATURE-ALGORITHM-CLASS ::= {
+ ID ecdsa-with-SHA224
+ TYPE NULL } -- XXX Must be empty and not NULL
+
+ ecdsa-with-sha256 SIGNATURE-ALGORITHM-CLASS ::= {
+ ID ecdsa-with-SHA256
+ TYPE NULL } -- XXX Must be empty and not NULL
+
+ ecdsa-with-sha384 SIGNATURE-ALGORITHM-CLASS ::= {
+ ID ecdsa-with-SHA384
+ TYPE NULL } -- XXX Must be empty and not NULL
+
+ ecdsa-with-sha512 SIGNATURE-ALGORITHM-CLASS ::= {
+ ID ecdsa-with-SHA512
+ TYPE NULL } -- XXX Must be empty and not NULL
+
FIELD-ID-CLASS ::= CLASS {
&id OBJECT IDENTIFIER UNIQUE,
&Type }
@@ -489,6 +510,7 @@ SupportedPublicKeyAlgorithms PUBLIC-KEY-ALGORITHM-CLASS ::= {
ID ppBasis
TYPE Pentanomial }
+
-- SubjectPublicKeyInfo.algorithm
ec-public-key PUBLIC-KEY-ALGORITHM-CLASS ::= {
diff --git a/lib/public_key/asn1/OTP-PUB-KEY.set.asn b/lib/public_key/asn1/OTP-PUB-KEY.set.asn
index f8fb318c93..e94f428e4b 100644
--- a/lib/public_key/asn1/OTP-PUB-KEY.set.asn
+++ b/lib/public_key/asn1/OTP-PUB-KEY.set.asn
@@ -6,5 +6,6 @@ PKIX1Algorithms88.asn1
PKCS-1.asn1
PKCS-3.asn1
DSS.asn1
+ECPrivateKey.asn1
PKCS-7.asn1
PKCS-10.asn1
diff --git a/lib/public_key/asn1/PKCS-1.asn1 b/lib/public_key/asn1/PKCS-1.asn1
index b5754790e7..117eacd8ad 100644
--- a/lib/public_key/asn1/PKCS-1.asn1
+++ b/lib/public_key/asn1/PKCS-1.asn1
@@ -52,8 +52,40 @@ id-md5 OBJECT IDENTIFIER ::= {
iso(1) member-body(2) us(840) rsadsi(113549) digestAlgorithm(2) 5
}
+id-hmacWithSHA224 OBJECT IDENTIFIER ::= {
+ iso(1) member-body(2) us(840) rsadsi(113549) digestAlgorithm(2) 8
+}
+
+id-hmacWithSHA256 OBJECT IDENTIFIER ::= {
+ iso(1) member-body(2) us(840) rsadsi(113549) digestAlgorithm(2) 9
+}
+
+id-hmacWithSHA384 OBJECT IDENTIFIER ::= {
+ iso(1) member-body(2) us(840) rsadsi(113549) digestAlgorithm(2) 10
+}
+
+id-hmacWithSHA512 OBJECT IDENTIFIER ::= {
+ iso(1) member-body(2) us(840) rsadsi(113549) digestAlgorithm(2) 11
+}
+
id-mgf1 OBJECT IDENTIFIER ::= { pkcs-1 8 }
+id-sha224 OBJECT IDENTIFIER ::= { joint-iso-itu-t(2)
+ country(16) us(840) organization(1) gov(101) csor(3)
+ nistalgorithm(4) hashalgs(2) 4 }
+
+id-sha256 OBJECT IDENTIFIER ::= { joint-iso-itu-t(2)
+ country(16) us(840) organization(1) gov(101) csor(3)
+ nistalgorithm(4) hashalgs(2) 1 }
+
+id-sha384 OBJECT IDENTIFIER ::= { joint-iso-itu-t(2)
+ country(16) us(840) organization(1) gov(101) csor(3)
+ nistalgorithm(4) hashalgs(2) 2 }
+
+id-sha512 OBJECT IDENTIFIER ::= { joint-iso-itu-t(2)
+ country(16) us(840) organization(1) gov(101) csor(3)
+ nistalgorithm(4) hashalgs(2) 3 }
+
RSAPublicKey ::= SEQUENCE {
modulus INTEGER, -- n
diff --git a/lib/public_key/asn1/PKIX1Algorithms88.asn1 b/lib/public_key/asn1/PKIX1Algorithms88.asn1
index 74225747d3..6cc6745af6 100644
--- a/lib/public_key/asn1/PKIX1Algorithms88.asn1
+++ b/lib/public_key/asn1/PKIX1Algorithms88.asn1
@@ -98,6 +98,11 @@
-- OID for ECDSA signatures with SHA-1
ecdsa-with-SHA1 OBJECT IDENTIFIER ::= { id-ecSigType 1 }
+ ecdsa-with-SHA2 OBJECT IDENTIFIER ::= { id-ecSigType 3 }
+ ecdsa-with-SHA224 OBJECT IDENTIFIER ::= { ecdsa-with-SHA2 1 }
+ ecdsa-with-SHA256 OBJECT IDENTIFIER ::= { ecdsa-with-SHA2 2 }
+ ecdsa-with-SHA384 OBJECT IDENTIFIER ::= { ecdsa-with-SHA2 3 }
+ ecdsa-with-SHA512 OBJECT IDENTIFIER ::= { ecdsa-with-SHA2 4 }
-- OID for an elliptic curve signature
-- format for the value of an ECDSA signature value
@@ -199,40 +204,83 @@
-- Named Elliptic Curves in ANSI X9.62.
- ellipticCurve OBJECT IDENTIFIER ::= { ansi-X9-62 curves(3) }
-
- c-TwoCurve OBJECT IDENTIFIER ::= {
- ellipticCurve characteristicTwo(0) }
-
- c2pnb163v1 OBJECT IDENTIFIER ::= { c-TwoCurve 1 }
- c2pnb163v2 OBJECT IDENTIFIER ::= { c-TwoCurve 2 }
- c2pnb163v3 OBJECT IDENTIFIER ::= { c-TwoCurve 3 }
- c2pnb176w1 OBJECT IDENTIFIER ::= { c-TwoCurve 4 }
- c2tnb191v1 OBJECT IDENTIFIER ::= { c-TwoCurve 5 }
- c2tnb191v2 OBJECT IDENTIFIER ::= { c-TwoCurve 6 }
- c2tnb191v3 OBJECT IDENTIFIER ::= { c-TwoCurve 7 }
- c2onb191v4 OBJECT IDENTIFIER ::= { c-TwoCurve 8 }
- c2onb191v5 OBJECT IDENTIFIER ::= { c-TwoCurve 9 }
- c2pnb208w1 OBJECT IDENTIFIER ::= { c-TwoCurve 10 }
- c2tnb239v1 OBJECT IDENTIFIER ::= { c-TwoCurve 11 }
- c2tnb239v2 OBJECT IDENTIFIER ::= { c-TwoCurve 12 }
- c2tnb239v3 OBJECT IDENTIFIER ::= { c-TwoCurve 13 }
- c2onb239v4 OBJECT IDENTIFIER ::= { c-TwoCurve 14 }
- c2onb239v5 OBJECT IDENTIFIER ::= { c-TwoCurve 15 }
- c2pnb272w1 OBJECT IDENTIFIER ::= { c-TwoCurve 16 }
- c2pnb304w1 OBJECT IDENTIFIER ::= { c-TwoCurve 17 }
- c2tnb359v1 OBJECT IDENTIFIER ::= { c-TwoCurve 18 }
- c2pnb368w1 OBJECT IDENTIFIER ::= { c-TwoCurve 19 }
- c2tnb431r1 OBJECT IDENTIFIER ::= { c-TwoCurve 20 }
-
- primeCurve OBJECT IDENTIFIER ::= { ellipticCurve prime(1) }
-
- prime192v1 OBJECT IDENTIFIER ::= { primeCurve 1 }
- prime192v2 OBJECT IDENTIFIER ::= { primeCurve 2 }
- prime192v3 OBJECT IDENTIFIER ::= { primeCurve 3 }
- prime239v1 OBJECT IDENTIFIER ::= { primeCurve 4 }
- prime239v2 OBJECT IDENTIFIER ::= { primeCurve 5 }
- prime239v3 OBJECT IDENTIFIER ::= { primeCurve 6 }
- prime256v1 OBJECT IDENTIFIER ::= { primeCurve 7 }
+ -- ellipticCurve OBJECT IDENTIFIER ::= { ansi-X9-62 curves(3) }
+
+ -- c-TwoCurve OBJECT IDENTIFIER ::= {
+ -- ansi-ellipticCurve characteristicTwo(0) }
+
+ -- c2pnb163v1 OBJECT IDENTIFIER ::= { c-TwoCurve 1 }
+ -- c2pnb163v2 OBJECT IDENTIFIER ::= { c-TwoCurve 2 }
+ -- c2pnb163v3 OBJECT IDENTIFIER ::= { c-TwoCurve 3 }
+ -- c2pnb176w1 OBJECT IDENTIFIER ::= { c-TwoCurve 4 }
+ -- c2tnb191v1 OBJECT IDENTIFIER ::= { c-TwoCurve 5 }
+ -- c2tnb191v2 OBJECT IDENTIFIER ::= { c-TwoCurve 6 }
+ -- c2tnb191v3 OBJECT IDENTIFIER ::= { c-TwoCurve 7 }
+ -- c2onb191v4 OBJECT IDENTIFIER ::= { c-TwoCurve 8 }
+ -- c2onb191v5 OBJECT IDENTIFIER ::= { c-TwoCurve 9 }
+ -- c2pnb208w1 OBJECT IDENTIFIER ::= { c-TwoCurve 10 }
+ -- c2tnb239v1 OBJECT IDENTIFIER ::= { c-TwoCurve 11 }
+ -- c2tnb239v2 OBJECT IDENTIFIER ::= { c-TwoCurve 12 }
+ -- c2tnb239v3 OBJECT IDENTIFIER ::= { c-TwoCurve 13 }
+ -- c2onb239v4 OBJECT IDENTIFIER ::= { c-TwoCurve 14 }
+ -- c2onb239v5 OBJECT IDENTIFIER ::= { c-TwoCurve 15 }
+ -- c2pnb272w1 OBJECT IDENTIFIER ::= { c-TwoCurve 16 }
+ -- c2pnb304w1 OBJECT IDENTIFIER ::= { c-TwoCurve 17 }
+ -- c2tnb359v1 OBJECT IDENTIFIER ::= { c-TwoCurve 18 }
+ -- c2pnb368w1 OBJECT IDENTIFIER ::= { c-TwoCurve 19 }
+ -- c2tnb431r1 OBJECT IDENTIFIER ::= { c-TwoCurve 20 }
+
+ -- primeCurve OBJECT IDENTIFIER ::= { ansi-ellipticCurve prime(1) }
+
+ -- prime192v1 OBJECT IDENTIFIER ::= { primeCurve 1 }
+ -- prime192v2 OBJECT IDENTIFIER ::= { primeCurve 2 }
+ -- prime192v3 OBJECT IDENTIFIER ::= { primeCurve 3 }
+ -- prime239v1 OBJECT IDENTIFIER ::= { primeCurve 4 }
+ -- prime239v2 OBJECT IDENTIFIER ::= { primeCurve 5 }
+ -- prime239v3 OBJECT IDENTIFIER ::= { primeCurve 6 }
+ -- prime256v1 OBJECT IDENTIFIER ::= { primeCurve 7 }
+
+ certicom-arc OBJECT IDENTIFIER ::= {
+ iso(1) identified-organization(3) certicom(132)
+ }
+
+ ellipticCurve OBJECT IDENTIFIER ::= {
+ iso(1) identified-organization(3) certicom(132) curve(0)
+ }
+
+ secp192r1 OBJECT IDENTIFIER ::= { ansi-X9-62 curves(3) prime(1) 1 }
+ secp256r1 OBJECT IDENTIFIER ::= { ansi-X9-62 curves(3) prime(1) 7 }
+
+ sect163k1 OBJECT IDENTIFIER ::= { ellipticCurve 1 }
+ sect163r1 OBJECT IDENTIFIER ::= { ellipticCurve 2 }
+ sect239k1 OBJECT IDENTIFIER ::= { ellipticCurve 3 }
+ sect113r1 OBJECT IDENTIFIER ::= { ellipticCurve 4 }
+ sect113r2 OBJECT IDENTIFIER ::= { ellipticCurve 5 }
+ secp112r1 OBJECT IDENTIFIER ::= { ellipticCurve 6 }
+ secp112r2 OBJECT IDENTIFIER ::= { ellipticCurve 7 }
+ secp160r1 OBJECT IDENTIFIER ::= { ellipticCurve 8 }
+ secp160k1 OBJECT IDENTIFIER ::= { ellipticCurve 9 }
+ secp256k1 OBJECT IDENTIFIER ::= { ellipticCurve 10 }
+ sect163r2 OBJECT IDENTIFIER ::= { ellipticCurve 15 }
+ sect283k1 OBJECT IDENTIFIER ::= { ellipticCurve 16 }
+ sect283r1 OBJECT IDENTIFIER ::= { ellipticCurve 17 }
+ sect131r1 OBJECT IDENTIFIER ::= { ellipticCurve 22 }
+ sect131r2 OBJECT IDENTIFIER ::= { ellipticCurve 23 }
+ sect193r1 OBJECT IDENTIFIER ::= { ellipticCurve 24 }
+ sect193r2 OBJECT IDENTIFIER ::= { ellipticCurve 25 }
+ sect233k1 OBJECT IDENTIFIER ::= { ellipticCurve 26 }
+ sect233r1 OBJECT IDENTIFIER ::= { ellipticCurve 27 }
+ secp128r1 OBJECT IDENTIFIER ::= { ellipticCurve 28 }
+ secp128r2 OBJECT IDENTIFIER ::= { ellipticCurve 29 }
+ secp160r2 OBJECT IDENTIFIER ::= { ellipticCurve 30 }
+ secp192k1 OBJECT IDENTIFIER ::= { ellipticCurve 31 }
+ secp224k1 OBJECT IDENTIFIER ::= { ellipticCurve 32 }
+ secp224r1 OBJECT IDENTIFIER ::= { ellipticCurve 33 }
+ secp384r1 OBJECT IDENTIFIER ::= { ellipticCurve 34 }
+ secp521r1 OBJECT IDENTIFIER ::= { ellipticCurve 35 }
+ sect409k1 OBJECT IDENTIFIER ::= { ellipticCurve 36 }
+ sect409r1 OBJECT IDENTIFIER ::= { ellipticCurve 37 }
+ sect571k1 OBJECT IDENTIFIER ::= { ellipticCurve 38 }
+ sect571r1 OBJECT IDENTIFIER ::= { ellipticCurve 39 }
END
diff --git a/lib/public_key/doc/src/public_key.xml b/lib/public_key/doc/src/public_key.xml
index 84300f6e65..10c95a39ac 100644
--- a/lib/public_key/doc/src/public_key.xml
+++ b/lib/public_key/doc/src/public_key.xml
@@ -84,7 +84,8 @@
<p><code>pki_asn1_type() = 'Certificate' | 'RSAPrivateKey'| 'RSAPublicKey' |
'DSAPrivateKey' | 'DSAPublicKey' | 'DHParameter' | 'SubjectPublicKeyInfo' |
- 'PrivateKeyInfo' | 'CertificationRequest'</code></p>
+ 'PrivateKeyInfo' | 'CertificationRequest' | 'ECPrivateKey'|
+ 'EcpkParameters'</code></p>
<p><code>pem_entry () = {pki_asn1_type(), binary(), %% DER or encrypted DER
not_encrypted | cipher_info()} </code></p>
@@ -99,7 +100,11 @@
<p><code>dsa_public_key() = {integer(), #'Dss-Parms'{}} </code></p>
<p><code>dsa_private_key() = #'DSAPrivateKey'{}</code></p>
+
+ <p><code>ec_public_key() = {#'ECPoint'{}, #'EcpkParameters'{} | {namedCurve, oid()}} </code></p>
+ <p><code>ec_private_key() = #'ECPrivateKey'{}</code></p>
+
<p><code> public_crypt_options() = [{rsa_pad, rsa_padding()}]. </code></p>
<p><code> rsa_padding() = 'rsa_pkcs1_padding' | 'rsa_pkcs1_oaep_padding'
@@ -109,6 +114,8 @@
<p><code> dss_digest_type() = 'sha' </code></p>
+ <p><code> ecdsa_digest_type() = 'sha'| 'sha224' | 'sha256' | 'sha384' | 'sha512' </code></p>
+
<p><code> crl_reason() = unspecified | keyCompromise | cACompromise | affiliationChanged | superseded | cessationOfOperation | certificateHold | privilegeWithdrawn | aACompromise
</code></p>
@@ -147,6 +154,19 @@
<funcs>
<func>
+ <name> compute_key(OthersKey, MyKey)-></name>
+ <name> compute_key(OthersKey, MyKey, Params)-></name>
+ <fsummary> Compute shared secret</fsummary>
+ <type>
+ <v>OthersKey = #'ECPoint'{} | binary(), MyKey = #'ECPrivateKey'{} | binary()</v>
+ <v>Params = #'DHParameter'{}</v>
+ </type>
+ <desc>
+ <p> Compute shared secret </p>
+ </desc>
+ </func>
+
+ <func>
<name>decrypt_private(CipherText, Key) -> binary()</name>
<name>decrypt_private(CipherText, Key, Options) -> binary()</name>
<fsummary>Public key decryption.</fsummary>
@@ -204,6 +224,17 @@
</func>
<func>
+ <name>generate_key(Params) -> {Public::binary(), Private::binary()} | #'ECPrivateKey'{} </name>
+ <fsummary>Generates a new keypair</fsummary>
+ <type>
+ <v> Params = #'DHParameter'{} | {namedCurve, oid()} | #'ECParameters'{} </v>
+ </type>
+ <desc>
+ <p>Generates a new keypair</p>
+ </desc>
+ </func>
+
+ <func>
<name>pem_decode(PemBin) -> [pem_entry()]</name>
<fsummary>Decode PEM binary data and return
entries as ASN.1 DER encoded entities. </fsummary>
@@ -528,8 +559,8 @@ fun(OtpCert :: #'OTPCertificate'{}, Event :: {bad_cert, Reason :: atom()} |
<d>The msg is either the binary "plain text" data to be
signed or it is the hashed value of "plain text" i.e. the
digest.</d>
- <v>DigestType = rsa_digest_type() | dss_digest_type()</v>
- <v>Key = rsa_private_key() | dsa_private_key()</v>
+ <v>DigestType = rsa_digest_type() | dss_digest_type() | ecdsa_digest_type()</v>
+ <v>Key = rsa_private_key() | dsa_private_key() | ec_private_key()</v>
</type>
<desc>
<p> Creates a digital signature.</p>
@@ -592,12 +623,12 @@ fun(OtpCert :: #'OTPCertificate'{}, Event :: {bad_cert, Reason :: atom()} |
<v>Msg = binary() | {digest,binary()}</v>
<d>The msg is either the binary "plain text" data
or it is the hashed value of "plain text" i.e. the digest.</d>
- <v>DigestType = rsa_digest_type() | dss_digest_type()</v>
+ <v>DigestType = rsa_digest_type() | dss_digest_type() | ecdsa_digest_type()</v>
<v>Signature = binary()</v>
- <v>Key = rsa_public_key() | dsa_public_key()</v>
- </type>
- <desc>
- <p>Verifies a digital signature</p>
+ <v>Key = rsa_public_key() | dsa_public_key() | ec_public_key()</v>
+ </type>
+ <desc>
+ <p>Verifies a digital signature</p>
</desc>
</func>
diff --git a/lib/public_key/include/public_key.hrl b/lib/public_key/include/public_key.hrl
index 4d1d510f29..1e882e76ee 100644
--- a/lib/public_key/include/public_key.hrl
+++ b/lib/public_key/include/public_key.hrl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2008-2012. All Rights Reserved.
+%% Copyright Ericsson AB 2008-2013. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -72,6 +72,10 @@
valid_ext
}).
+-record('ECPoint', {
+ point
+ }).
+
-define(unspecified, 0).
-define(keyCompromise, 1).
@@ -89,6 +93,8 @@
-type rsa_private_key() :: #'RSAPrivateKey'{}.
-type dsa_private_key() :: #'DSAPrivateKey'{}.
-type dsa_public_key() :: {integer(), #'Dss-Parms'{}}.
+-type ec_public_key() :: {#'ECPoint'{},{namedCurve, Oid::tuple()} | #'ECParameters'{}}.
+-type ec_private_key() :: #'ECPrivateKey'{}.
-type der_encoded() :: binary().
-type decrypt_der() :: binary().
-type pki_asn1_type() :: 'Certificate' | 'RSAPrivateKey' | 'RSAPublicKey'
diff --git a/lib/public_key/src/pubkey_cert_records.erl b/lib/public_key/src/pubkey_cert_records.erl
index 98004c71a3..0449129809 100644
--- a/lib/public_key/src/pubkey_cert_records.erl
+++ b/lib/public_key/src/pubkey_cert_records.erl
@@ -23,7 +23,8 @@
-include("public_key.hrl").
--export([decode_cert/1, transform/2, supportedPublicKeyAlgorithms/1]).
+-export([decode_cert/1, transform/2, supportedPublicKeyAlgorithms/1,
+ supportedCurvesTypes/1, namedCurves/1]).
%%====================================================================
%% Internal application API
@@ -101,6 +102,77 @@ supportedPublicKeyAlgorithms(?'dhpublicnumber') -> 'DHPublicKey';
supportedPublicKeyAlgorithms(?'id-keyExchangeAlgorithm') -> 'KEA-PublicKey';
supportedPublicKeyAlgorithms(?'id-ecPublicKey') -> 'ECPoint'.
+supportedCurvesTypes(?'characteristic-two-field') -> characteristic_two_field;
+supportedCurvesTypes(?'prime-field') -> prime_field.
+
+namedCurves(?'sect571r1') -> sect571r1;
+namedCurves(?'sect571k1') -> sect571k1;
+namedCurves(?'sect409r1') -> sect409r1;
+namedCurves(?'sect409k1') -> sect409k1;
+namedCurves(?'secp521r1') -> secp521r1;
+namedCurves(?'secp384r1') -> secp384r1;
+namedCurves(?'secp224r1') -> secp224r1;
+namedCurves(?'secp224k1') -> secp224k1;
+namedCurves(?'secp192k1') -> secp192k1;
+namedCurves(?'secp160r2') -> secp160r2;
+namedCurves(?'secp128r2') -> secp128r2;
+namedCurves(?'secp128r1') -> secp128r1;
+namedCurves(?'sect233r1') -> sect233r1;
+namedCurves(?'sect233k1') -> sect233k1;
+namedCurves(?'sect193r2') -> sect193r2;
+namedCurves(?'sect193r1') -> sect193r1;
+namedCurves(?'sect131r2') -> sect131r2;
+namedCurves(?'sect131r1') -> sect131r1;
+namedCurves(?'sect283r1') -> sect283r1;
+namedCurves(?'sect283k1') -> sect283k1;
+namedCurves(?'sect163r2') -> sect163r2;
+namedCurves(?'secp256k1') -> secp256k1;
+namedCurves(?'secp160k1') -> secp160k1;
+namedCurves(?'secp160r1') -> secp160r1;
+namedCurves(?'secp112r2') -> secp112r2;
+namedCurves(?'secp112r1') -> secp112r1;
+namedCurves(?'sect113r2') -> sect113r2;
+namedCurves(?'sect113r1') -> sect113r1;
+namedCurves(?'sect239k1') -> sect239k1;
+namedCurves(?'sect163r1') -> sect163r1;
+namedCurves(?'sect163k1') -> sect163k1;
+namedCurves(?'secp256r1') -> secp256r1;
+namedCurves(?'secp192r1') -> secp192r1;
+
+namedCurves(sect571r1) -> ?'sect571r1';
+namedCurves(sect571k1) -> ?'sect571k1';
+namedCurves(sect409r1) -> ?'sect409r1';
+namedCurves(sect409k1) -> ?'sect409k1';
+namedCurves(secp521r1) -> ?'secp521r1';
+namedCurves(secp384r1) -> ?'secp384r1';
+namedCurves(secp224r1) -> ?'secp224r1';
+namedCurves(secp224k1) -> ?'secp224k1';
+namedCurves(secp192k1) -> ?'secp192k1';
+namedCurves(secp160r2) -> ?'secp160r2';
+namedCurves(secp128r2) -> ?'secp128r2';
+namedCurves(secp128r1) -> ?'secp128r1';
+namedCurves(sect233r1) -> ?'sect233r1';
+namedCurves(sect233k1) -> ?'sect233k1';
+namedCurves(sect193r2) -> ?'sect193r2';
+namedCurves(sect193r1) -> ?'sect193r1';
+namedCurves(sect131r2) -> ?'sect131r2';
+namedCurves(sect131r1) -> ?'sect131r1';
+namedCurves(sect283r1) -> ?'sect283r1';
+namedCurves(sect283k1) -> ?'sect283k1';
+namedCurves(sect163r2) -> ?'sect163r2';
+namedCurves(secp256k1) -> ?'secp256k1';
+namedCurves(secp160k1) -> ?'secp160k1';
+namedCurves(secp160r1) -> ?'secp160r1';
+namedCurves(secp112r2) -> ?'secp112r2';
+namedCurves(secp112r1) -> ?'secp112r1';
+namedCurves(sect113r2) -> ?'sect113r2';
+namedCurves(sect113r1) -> ?'sect113r1';
+namedCurves(sect239k1) -> ?'sect239k1';
+namedCurves(sect163r1) -> ?'sect163r1';
+namedCurves(sect163k1) -> ?'sect163k1';
+namedCurves(secp256r1) -> ?'secp256r1';
+namedCurves(secp192r1) -> ?'secp192r1'.
+
%%--------------------------------------------------------------------
%%% Internal functions
%%--------------------------------------------------------------------
@@ -111,14 +183,24 @@ decode_supportedPublicKey(#'OTPSubjectPublicKeyInfo'{algorithm= PA =
#'PublicKeyAlgorithm'{algorithm=Algo},
subjectPublicKey = {0,SPK0}}) ->
Type = supportedPublicKeyAlgorithms(Algo),
- {ok, SPK} = 'OTP-PUB-KEY':decode(Type, SPK0),
+ SPK = case Type of
+ 'ECPoint' -> #'ECPoint'{point = SPK0};
+ _ -> {ok, SPK1} = 'OTP-PUB-KEY':decode(Type, SPK0),
+ SPK1
+ end,
#'OTPSubjectPublicKeyInfo'{subjectPublicKey = SPK, algorithm=PA}.
encode_supportedPublicKey(#'OTPSubjectPublicKeyInfo'{algorithm= PA =
#'PublicKeyAlgorithm'{algorithm=Algo},
subjectPublicKey = SPK0}) ->
Type = supportedPublicKeyAlgorithms(Algo),
- {ok, SPK} = 'OTP-PUB-KEY':encode(Type, SPK0),
+ SPK = case Type of
+ 'ECPoint' ->
+ SPK0#'ECPoint'.point;
+ _ ->
+ {ok, SPK1} = 'OTP-PUB-KEY':encode(Type, SPK0),
+ SPK1
+ end,
#'OTPSubjectPublicKeyInfo'{subjectPublicKey = {0,SPK}, algorithm=PA}.
%%% Extensions
diff --git a/lib/public_key/src/pubkey_pem.erl b/lib/public_key/src/pubkey_pem.erl
index 6bdc35fb79..746d142ec3 100644
--- a/lib/public_key/src/pubkey_pem.erl
+++ b/lib/public_key/src/pubkey_pem.erl
@@ -202,7 +202,11 @@ pem_start('CertificationRequest') ->
pem_start('ContentInfo') ->
<<"-----BEGIN PKCS7-----">>;
pem_start('CertificateList') ->
- <<"-----BEGIN X509 CRL-----">>.
+ <<"-----BEGIN X509 CRL-----">>;
+pem_start('OTPEcpkParameters') ->
+ <<"-----BEGIN EC PARAMETERS-----">>;
+pem_start('ECPrivateKey') ->
+ <<"-----BEGIN EC PRIVATE KEY-----">>.
pem_end(<<"-----BEGIN CERTIFICATE-----">>) ->
<<"-----END CERTIFICATE-----">>;
@@ -226,6 +230,10 @@ pem_end(<<"-----BEGIN PKCS7-----">>) ->
<<"-----END PKCS7-----">>;
pem_end(<<"-----BEGIN X509 CRL-----">>) ->
<<"-----END X509 CRL-----">>;
+pem_end(<<"-----BEGIN EC PARAMETERS-----">>) ->
+ <<"-----END EC PARAMETERS-----">>;
+pem_end(<<"-----BEGIN EC PRIVATE KEY-----">>) ->
+ <<"-----END EC PRIVATE KEY-----">>;
pem_end(_) ->
undefined.
@@ -250,7 +258,11 @@ asn1_type(<<"-----BEGIN CERTIFICATE REQUEST-----">>) ->
asn1_type(<<"-----BEGIN PKCS7-----">>) ->
'ContentInfo';
asn1_type(<<"-----BEGIN X509 CRL-----">>) ->
- 'CertificateList'.
+ 'CertificateList';
+asn1_type(<<"-----BEGIN EC PARAMETERS-----">>) ->
+ 'OTPEcpkParameters';
+asn1_type(<<"-----BEGIN EC PRIVATE KEY-----">>) ->
+ 'ECPrivateKey'.
pem_decrypt() ->
<<"Proc-Type: 4,ENCRYPTED">>.
diff --git a/lib/public_key/src/public_key.erl b/lib/public_key/src/public_key.erl
index 736c18cdd4..648dba3d5a 100644
--- a/lib/public_key/src/public_key.erl
+++ b/lib/public_key/src/public_key.erl
@@ -35,6 +35,8 @@
encrypt_public/2, encrypt_public/3,
decrypt_public/2, decrypt_public/3,
sign/3, verify/4,
+ generate_key/1,
+ compute_key/2, compute_key/3,
pkix_sign/2, pkix_verify/2,
pkix_sign_types/1,
pkix_is_self_signed/1,
@@ -52,6 +54,7 @@
-type public_crypt_options() :: [{rsa_pad, rsa_padding()}].
-type rsa_digest_type() :: 'md5' | 'sha'| 'sha224' | 'sha256' | 'sha384' | 'sha512'.
-type dss_digest_type() :: 'none' | 'sha'. %% None is for backwards compatibility
+-type ecdsa_digest_type() :: 'sha'| 'sha224' | 'sha256' | 'sha384' | 'sha512'.
-type crl_reason() :: unspecified | keyCompromise | cACompromise | affiliationChanged | superseded
| cessationOfOperation | certificateHold | privilegeWithdrawn | aACompromise.
-type oid() :: tuple().
@@ -94,7 +97,9 @@ pem_entry_decode({'SubjectPublicKeyInfo', Der, _}) ->
der_decode(KeyType, Key0);
'DSAPublicKey' ->
{params, DssParams} = der_decode('DSAParams', Params),
- {der_decode(KeyType, Key0), DssParams}
+ {der_decode(KeyType, Key0), DssParams};
+ 'ECPoint' ->
+ der_decode(KeyType, Key0)
end;
pem_entry_decode({Asn1Type, Der, not_encrypted}) when is_atom(Asn1Type),
is_binary(Der) ->
@@ -251,10 +256,9 @@ decrypt_private(CipherText,
privateExponent = D} = Key,
Options)
when is_binary(CipherText),
- is_integer(N), is_integer(E), is_integer(D),
is_list(Options) ->
Padding = proplists:get_value(rsa_pad, Options, rsa_pkcs1_padding),
- crypto:rsa_private_decrypt(CipherText, format_rsa_private_key(Key), Padding).
+ crypto:private_decrypt(rsa, CipherText, format_rsa_private_key(Key), Padding).
%%--------------------------------------------------------------------
-spec decrypt_public(CipherText :: binary(), rsa_public_key() | rsa_private_key()) ->
@@ -318,30 +322,41 @@ encrypt_private(PlainText,
Options)
when is_binary(PlainText),
is_integer(N), is_integer(E), is_integer(D),
- is_list(Options) ->
+ is_list(Options) ->
Padding = proplists:get_value(rsa_pad, Options, rsa_pkcs1_padding),
- crypto:rsa_private_encrypt(PlainText, format_rsa_private_key(Key), Padding).
+ crypto:private_encrypt(rsa, PlainText, format_rsa_private_key(Key), Padding).
+%%--------------------------------------------------------------------
+-spec generate_key(#'DHParameter'{} | {namedCurve, Name ::atom()} |
+ #'ECParameters'{}) -> {Public::binary(), Private::binary()} |
+ #'ECPrivateKey'{}.
+%% Description: Generates a new keypair
+%%--------------------------------------------------------------------
+generate_key(#'DHParameter'{prime = P, base = G}) ->
+ crypto:generate_key(dh, [P, G]);
+generate_key({namedCurve, _} = Params) ->
+ ec_generate_key(Params);
+generate_key(#'ECParameters'{} = Params) ->
+ ec_generate_key(Params).
-format_rsa_private_key(#'RSAPrivateKey'{modulus = N, publicExponent = E,
- privateExponent = D,
- prime1 = P1, prime2 = P2,
- exponent1 = E1, exponent2 = E2,
- coefficient = C})
- when is_integer(P1), is_integer(P2),
- is_integer(E1), is_integer(E2), is_integer(C) ->
- [crypto:mpint(K) || K <- [E, N, D, P1, P2, E1, E2, C]];
+%%--------------------------------------------------------------------
+-spec compute_key(#'ECPoint'{} , #'ECPrivateKey'{}) -> binary().
+-spec compute_key(OthersKey ::binary(), MyKey::binary(), #'DHParameter'{}) -> binary().
+%% Description: Compute shared secret
+%%--------------------------------------------------------------------
+compute_key(#'ECPoint'{point = Point}, #'ECPrivateKey'{privateKey = PrivKey,
+ parameters = Param}) ->
+ ECCurve = ec_curve_spec(Param),
+ crypto:compute_key(ecdh, Point, list2int(PrivKey), ECCurve).
-format_rsa_private_key(#'RSAPrivateKey'{modulus = N, publicExponent = E,
- privateExponent = D}) ->
- [crypto:mpint(K) || K <- [E, N, D]].
+compute_key(PubKey, PrivKey, #'DHParameter'{prime = P, base = G}) ->
+ crypto:compute_key(dh, PubKey, PrivKey, [P, G]).
%%--------------------------------------------------------------------
-
-spec pkix_sign_types(SignatureAlg::oid()) ->
%% Relevant dsa digest type is subpart of rsa digest type
{ DigestType :: rsa_digest_type(),
- SignatureType :: rsa | dsa
+ SignatureType :: rsa | dsa | ecdsa
}.
%% Description:
%%--------------------------------------------------------------------
@@ -362,68 +377,60 @@ pkix_sign_types(?md5WithRSAEncryption) ->
pkix_sign_types(?'id-dsa-with-sha1') ->
{sha, dsa};
pkix_sign_types(?'id-dsaWithSHA1') ->
- {sha, dsa}.
+ {sha, dsa};
+pkix_sign_types(?'ecdsa-with-SHA1') ->
+ {sha, ecdsa};
+pkix_sign_types(?'ecdsa-with-SHA256') ->
+ {sha256, ecdsa};
+pkix_sign_types(?'ecdsa-with-SHA384') ->
+ {sha384, ecdsa};
+pkix_sign_types(?'ecdsa-with-SHA512') ->
+ {sha512, ecdsa}.
%%--------------------------------------------------------------------
--spec sign(binary() | {digest, binary()}, rsa_digest_type() | dss_digest_type(),
+-spec sign(binary() | {digest, binary()}, rsa_digest_type() | dss_digest_type() | ecdsa_digest_type(),
rsa_private_key() |
- dsa_private_key()) -> Signature :: binary().
+ dsa_private_key() | ec_private_key()) -> Signature :: binary().
%% Description: Create digital signature.
%%--------------------------------------------------------------------
-sign({digest,_}=Digest, DigestType, Key = #'RSAPrivateKey'{}) ->
- crypto:rsa_sign(DigestType, Digest, format_rsa_private_key(Key));
+sign(DigestOrPlainText, DigestType, Key = #'RSAPrivateKey'{}) ->
+ crypto:sign(rsa, DigestType, DigestOrPlainText, format_rsa_private_key(Key));
-sign(PlainText, DigestType, Key = #'RSAPrivateKey'{}) ->
- crypto:rsa_sign(DigestType, sized_binary(PlainText), format_rsa_private_key(Key));
+sign(DigestOrPlainText, sha, #'DSAPrivateKey'{p = P, q = Q, g = G, x = X}) ->
+ crypto:sign(dss, sha, DigestOrPlainText, [P, Q, G, X]);
-sign({digest,_}=Digest, sha, #'DSAPrivateKey'{p = P, q = Q, g = G, x = X}) ->
- crypto:dss_sign(Digest,
- [crypto:mpint(P), crypto:mpint(Q),
- crypto:mpint(G), crypto:mpint(X)]);
-
-sign(PlainText, sha, #'DSAPrivateKey'{p = P, q = Q, g = G, x = X}) ->
- crypto:dss_sign(sized_binary(PlainText),
- [crypto:mpint(P), crypto:mpint(Q),
- crypto:mpint(G), crypto:mpint(X)]);
+sign(DigestOrPlainText, DigestType, #'ECPrivateKey'{privateKey = PrivKey,
+ parameters = Param}) ->
+ ECCurve = ec_curve_spec(Param),
+ crypto:sign(ecdsa, DigestType, DigestOrPlainText, [list2int(PrivKey), ECCurve]);
%% Backwards compatible
sign(Digest, none, #'DSAPrivateKey'{} = Key) ->
sign({digest,Digest}, sha, Key).
%%--------------------------------------------------------------------
--spec verify(binary() | {digest, binary()}, rsa_digest_type() | dss_digest_type(),
+-spec verify(binary() | {digest, binary()}, rsa_digest_type() | dss_digest_type() | ecdsa_digest_type(),
Signature :: binary(), rsa_public_key()
- | dsa_public_key()) -> boolean().
+ | dsa_public_key() | ec_public_key()) -> boolean().
%% Description: Verifies a digital signature.
%%--------------------------------------------------------------------
-verify({digest,_}=Digest, DigestType, Signature,
+verify(DigestOrPlainText, DigestType, Signature,
#'RSAPublicKey'{modulus = Mod, publicExponent = Exp}) ->
- crypto:rsa_verify(DigestType, Digest,
- sized_binary(Signature),
- [crypto:mpint(Exp), crypto:mpint(Mod)]);
+ crypto:verify(rsa, DigestType, DigestOrPlainText, Signature,
+ [Exp, Mod]);
-verify(PlainText, DigestType, Signature,
- #'RSAPublicKey'{modulus = Mod, publicExponent = Exp}) ->
- crypto:rsa_verify(DigestType,
- sized_binary(PlainText),
- sized_binary(Signature),
- [crypto:mpint(Exp), crypto:mpint(Mod)]);
+verify(DigestOrPlaintext, DigestType, Signature, {#'ECPoint'{point = Point}, Param}) ->
+ ECCurve = ec_curve_spec(Param),
+ crypto:verify(ecdsa, DigestType, DigestOrPlaintext, Signature, [Point, ECCurve]);
-verify({digest,_}=Digest, sha, Signature, {Key, #'Dss-Parms'{p = P, q = Q, g = G}})
- when is_integer(Key), is_binary(Signature) ->
- crypto:dss_verify(Digest, sized_binary(Signature),
- [crypto:mpint(P), crypto:mpint(Q),
- crypto:mpint(G), crypto:mpint(Key)]);
%% Backwards compatibility
verify(Digest, none, Signature, {_, #'Dss-Parms'{}} = Key ) ->
verify({digest,Digest}, sha, Signature, Key);
-verify(PlainText, sha, Signature, {Key, #'Dss-Parms'{p = P, q = Q, g = G}})
- when is_integer(Key), is_binary(PlainText), is_binary(Signature) ->
- crypto:dss_verify(sized_binary(PlainText),
- sized_binary(Signature),
- [crypto:mpint(P), crypto:mpint(Q),
- crypto:mpint(G), crypto:mpint(Key)]).
+verify(DigestOrPlainText, sha = DigestType, Signature, {Key, #'Dss-Parms'{p = P, q = Q, g = G}})
+ when is_integer(Key), is_binary(Signature) ->
+ crypto:verify(dss, DigestType, DigestOrPlainText, Signature, [P, Q, G, Key]).
+
%%--------------------------------------------------------------------
-spec pkix_sign(#'OTPTBSCertificate'{},
rsa_private_key() | dsa_private_key()) -> Der::binary().
@@ -446,7 +453,7 @@ pkix_sign(#'OTPTBSCertificate'{signature =
%%--------------------------------------------------------------------
-spec pkix_verify(Cert::binary(), rsa_public_key()|
- dsa_public_key()) -> boolean().
+ dsa_public_key() | ec_public_key()) -> boolean().
%%
%% Description: Verify pkix x.509 certificate signature.
%%--------------------------------------------------------------------
@@ -458,7 +465,12 @@ pkix_verify(DerCert, {Key, #'Dss-Parms'{}} = DSAKey)
pkix_verify(DerCert, #'RSAPublicKey'{} = RSAKey)
when is_binary(DerCert) ->
{DigestType, PlainText, Signature} = pubkey_cert:verify_data(DerCert),
- verify(PlainText, DigestType, Signature, RSAKey).
+ verify(PlainText, DigestType, Signature, RSAKey);
+
+pkix_verify(DerCert, Key = {#'ECPoint'{}, _})
+ when is_binary(DerCert) ->
+ {DigestType, PlainText, Signature} = pubkey_cert:verify_data(DerCert),
+ verify(PlainText, DigestType, Signature, Key).
%%--------------------------------------------------------------------
-spec pkix_is_issuer(Cert :: der_encoded()| #'OTPCertificate'{} | #'CertificateList'{},
@@ -640,13 +652,11 @@ do_pem_entry_decode({Asn1Type,_, _} = PemEntry, Password) ->
encrypt_public(PlainText, N, E, Options)->
Padding = proplists:get_value(rsa_pad, Options, rsa_pkcs1_padding),
- crypto:rsa_public_encrypt(PlainText, [crypto:mpint(E),crypto:mpint(N)],
- Padding).
+ crypto:public_encrypt(rsa, PlainText, [E,N], Padding).
-decrypt_public(CipherText, N,E, Options) ->
+decrypt_public(CipherText, N,E, Options) ->
Padding = proplists:get_value(rsa_pad, Options, rsa_pkcs1_padding),
- crypto:rsa_public_decrypt(CipherText,[crypto:mpint(E), crypto:mpint(N)],
- Padding).
+ crypto:public_decrypt(rsa, CipherText,[E, N], Padding).
path_validation([], #path_validation_state{working_public_key_algorithm
= Algorithm,
@@ -732,10 +742,6 @@ validate(Cert, #path_validation_state{working_issuer_name = Issuer,
pubkey_cert:prepare_for_next_cert(OtpCert, ValidationState).
-sized_binary(Binary) ->
- Size = size(Binary),
- <<?UINT32(Size), Binary/binary>>.
-
otp_cert(Der) when is_binary(Der) ->
pkix_decode_cert(Der, otp);
otp_cert(#'OTPCertificate'{} =Cert) ->
@@ -842,3 +848,46 @@ combine(CRL, DeltaCRLs) ->
end,
lists:foldl(Fun, hd(Deltas), tl(Deltas))
end.
+
+format_rsa_private_key(#'RSAPrivateKey'{modulus = N, publicExponent = E,
+ privateExponent = D,
+ prime1 = P1, prime2 = P2,
+ exponent1 = E1, exponent2 = E2,
+ coefficient = C})
+ when is_integer(N), is_integer(E), is_integer(D),
+ is_integer(P1), is_integer(P2),
+ is_integer(E1), is_integer(E2), is_integer(C) ->
+ [E, N, D, P1, P2, E1, E2, C];
+
+format_rsa_private_key(#'RSAPrivateKey'{modulus = N, publicExponent = E,
+ privateExponent = D}) when is_integer(N),
+ is_integer(E),
+ is_integer(D) ->
+ [E, N, D].
+
+ec_generate_key(Params) ->
+ Curve = ec_curve_spec(Params),
+ Term = crypto:generate_key(ecdh, Curve),
+ ec_key(Term, Params).
+
+ec_curve_spec( #'ECParameters'{fieldID = FieldId, curve = PCurve, base = Base, order = Order, cofactor = CoFactor }) ->
+ Field = {pubkey_cert_records:supportedCurvesTypes(FieldId#'FieldID'.fieldType),
+ FieldId#'FieldID'.parameters},
+ Curve = {erlang:list_to_binary(PCurve#'Curve'.a), erlang:list_to_binary(PCurve#'Curve'.b), none},
+ {Field, Curve, erlang:list_to_binary(Base), Order, CoFactor};
+ec_curve_spec({namedCurve, OID}) ->
+ pubkey_cert_records:namedCurves(OID).
+
+ec_key({PrivateKey, PubKey}, Params) ->
+ #'ECPrivateKey'{version = 1,
+ privateKey = int2list(PrivateKey),
+ parameters = Params,
+ publicKey = {0, PubKey}}.
+
+list2int(L) ->
+ S = length(L) * 8,
+ <<R:S/integer>> = erlang:iolist_to_binary(L),
+ R.
+int2list(I) ->
+ L = (length(integer_to_list(I, 16)) + 1) div 2,
+ binary_to_list(<<I:(L*8)>>).
diff --git a/lib/public_key/test/erl_make_certs.erl b/lib/public_key/test/erl_make_certs.erl
index 897cf2f350..14efbcc7e0 100644
--- a/lib/public_key/test/erl_make_certs.erl
+++ b/lib/public_key/test/erl_make_certs.erl
@@ -45,7 +45,7 @@
%% {dnQualifer, DnQ}
%% issuer = {Issuer, IssuerKey} true (i.e. a ca cert is created)
%% (obs IssuerKey migth be {Key, Password}
-%% key = KeyFile|KeyBin|rsa|dsa Subject PublicKey rsa or dsa generates key
+%% key = KeyFile|KeyBin|rsa|dsa|ec Subject PublicKey rsa, dsa or ec generates key
%%
%%
%% (OBS: The generated keys are for testing only)
@@ -91,6 +91,16 @@ gen_dsa(LSize,NSize) when is_integer(LSize), is_integer(NSize) ->
{Key, encode_key(Key)}.
%%--------------------------------------------------------------------
+%% @doc Creates a ec key (OBS: for testing only)
+%% the sizes are in bytes
+%% @spec (::integer()) -> {::atom(), ::binary(), ::opaque()}
+%% @end
+%%--------------------------------------------------------------------
+gen_ec(Curve) when is_atom(Curve) ->
+ Key = gen_ec2(Curve),
+ {Key, encode_key(Key)}.
+
+%%--------------------------------------------------------------------
%% @doc Verifies cert signatures
%% @spec (::binary(), ::tuple()) -> ::boolean()
%% @end
@@ -102,7 +112,10 @@ verify_signature(DerEncodedCert, DerKey, _KeyParams) ->
public_key:pkix_verify(DerEncodedCert,
#'RSAPublicKey'{modulus=Mod, publicExponent=Exp});
#'DSAPrivateKey'{p=P, q=Q, g=G, y=Y} ->
- public_key:pkix_verify(DerEncodedCert, {Y, #'Dss-Parms'{p=P, q=Q, g=G}})
+ public_key:pkix_verify(DerEncodedCert, {Y, #'Dss-Parms'{p=P, q=Q, g=G}});
+ #'ECPrivateKey'{version = _Version, privateKey = _PrivKey,
+ parameters = _Params, publicKey = _PubKey} ->
+ public_key:pkix_verify(DerEncodedCert, Key)
end.
%%%%%%%%%%%%%%%%%%%%%%%%% Implementation %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
@@ -112,6 +125,7 @@ get_key(Opts) ->
undefined -> make_key(rsa, Opts);
rsa -> make_key(rsa, Opts);
dsa -> make_key(dsa, Opts);
+ ec -> make_key(ec, Opts);
Key ->
Password = proplists:get_value(password, Opts, no_passwd),
decode_key(Key, Password)
@@ -129,6 +143,8 @@ decode_key(#'RSAPrivateKey'{} = Key,_) ->
Key;
decode_key(#'DSAPrivateKey'{} = Key,_) ->
Key;
+decode_key(#'ECPrivateKey'{} = Key,_) ->
+ Key;
decode_key(PemEntry = {_,_,_}, Pw) ->
public_key:pem_entry_decode(PemEntry, Pw);
decode_key(PemBin, Pw) ->
@@ -140,7 +156,10 @@ encode_key(Key = #'RSAPrivateKey'{}) ->
{'RSAPrivateKey', Der, not_encrypted};
encode_key(Key = #'DSAPrivateKey'{}) ->
{ok, Der} = 'OTP-PUB-KEY':encode('DSAPrivateKey', Key),
- {'DSAPrivateKey', Der, not_encrypted}.
+ {'DSAPrivateKey', Der, not_encrypted};
+encode_key(Key = #'ECPrivateKey'{}) ->
+ {ok, Der} = 'OTP-PUB-KEY':encode('ECPrivateKey', Key),
+ {'ECPrivateKey', Der, not_encrypted}.
make_tbs(SubjectKey, Opts) ->
Version = list_to_atom("v"++integer_to_list(proplists:get_value(version, Opts, 3))),
@@ -282,7 +301,14 @@ publickey(#'RSAPrivateKey'{modulus=N, publicExponent=E}) ->
publickey(#'DSAPrivateKey'{p=P, q=Q, g=G, y=Y}) ->
Algo = #'PublicKeyAlgorithm'{algorithm= ?'id-dsa',
parameters={params, #'Dss-Parms'{p=P, q=Q, g=G}}},
- #'OTPSubjectPublicKeyInfo'{algorithm = Algo, subjectPublicKey = Y}.
+ #'OTPSubjectPublicKeyInfo'{algorithm = Algo, subjectPublicKey = Y};
+publickey(#'ECPrivateKey'{version = _Version,
+ privateKey = _PrivKey,
+ parameters = Params,
+ publicKey = {0, PubKey}}) ->
+ Algo = #'PublicKeyAlgorithm'{algorithm= ?'id-ecPublicKey', parameters=Params},
+ #'OTPSubjectPublicKeyInfo'{algorithm = Algo,
+ subjectPublicKey = #'ECPoint'{point = PubKey}}.
validity(Opts) ->
DefFrom0 = calendar:gregorian_days_to_date(calendar:date_to_gregorian_days(date())-1),
@@ -303,13 +329,24 @@ sign_algorithm(#'RSAPrivateKey'{}, Opts) ->
end,
{Type, 'NULL'};
sign_algorithm(#'DSAPrivateKey'{p=P, q=Q, g=G}, _Opts) ->
- {?'id-dsa-with-sha1', {params,#'Dss-Parms'{p=P, q=Q, g=G}}}.
+ {?'id-dsa-with-sha1', {params,#'Dss-Parms'{p=P, q=Q, g=G}}};
+sign_algorithm(#'ECPrivateKey'{}, Opts) ->
+ Type = case proplists:get_value(digest, Opts, sha1) of
+ sha1 -> ?'ecdsa-with-SHA1';
+ sha512 -> ?'ecdsa-with-SHA512';
+ sha384 -> ?'ecdsa-with-SHA384';
+ sha256 -> ?'ecdsa-with-SHA256'
+ end,
+ {Type, 'NULL'}.
make_key(rsa, _Opts) ->
%% (OBS: for testing only)
gen_rsa2(64);
make_key(dsa, _Opts) ->
- gen_dsa2(128, 20). %% Bytes i.e. {1024, 160}
+ gen_dsa2(128, 20); %% Bytes i.e. {1024, 160}
+make_key(ec, _Opts) ->
+ %% (OBS: for testing only)
+ gen_ec2(secp256k1).
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%% RSA key generation (OBS: for testing only)
@@ -368,6 +405,24 @@ gen_dsa2(LSize, NSize) ->
#'DSAPrivateKey'{version=0, p=P, q=Q, g=G, y=Y, x=X}
end.
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%% EC key generation (OBS: for testing only)
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+int2list(I) ->
+ L = (length(integer_to_list(I, 16)) + 1) div 2,
+ binary_to_list(<<I:(L*8)>>).
+
+gen_ec2(CurveId) ->
+ Key = crypto:ec_key_new(CurveId),
+ crypto:ec_key_generate(Key),
+ {_Curve, PrivKey, PubKey} = crypto:ec_key_to_term(Key),
+
+ #'ECPrivateKey'{version = 1,
+ privateKey = int2list(PrivKey),
+ parameters = {namedCurve, pubkey_cert_records:namedCurves(CurveId)},
+ publicKey = {0, PubKey}}.
+
%% See fips_186-3.pdf
dsa_search(T, P0, Q, Iter) when Iter > 0 ->
P = 2*T*Q*P0 + 1,
diff --git a/lib/public_key/test/pkits_SUITE.erl b/lib/public_key/test/pkits_SUITE.erl
index d901adaadd..8cdf0aaae3 100644
--- a/lib/public_key/test/pkits_SUITE.erl
+++ b/lib/public_key/test/pkits_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2008-2012. All Rights Reserved.
+%% Copyright Ericsson AB 2008-2013. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -758,11 +758,10 @@ warning(Format, Args, File0, Line) ->
io:format("~s(~p): Warning "++Format, [File,Line|Args]).
crypto_support_check(Config) ->
- try crypto:sha256(<<"Test">>) of
- _ ->
- Config
- catch error:notsup ->
- crypto:stop(),
+ case proplists:get_bool(sha256, crypto:algorithms()) of
+ true ->
+ Config;
+ false ->
{skip, "To old version of openssl"}
end.
diff --git a/lib/public_key/test/public_key_SUITE.erl b/lib/public_key/test/public_key_SUITE.erl
index 0de80edeac..5a64140c67 100644
--- a/lib/public_key/test/public_key_SUITE.erl
+++ b/lib/public_key/test/public_key_SUITE.erl
@@ -551,7 +551,7 @@ dsa_sign_verify(Config) when is_list(Config) ->
false = public_key:verify(Msg, sha, <<1:8, DSASign/binary>>,
{DSAPublicKey, DSAParams}),
- Digest = crypto:sha(Msg),
+ Digest = crypto:hash(sha,Msg),
DigestSign = public_key:sign(Digest, none, DSAPrivateKey),
true = public_key:verify(Digest, none, DigestSign, {DSAPublicKey, DSAParams}),
<<_:8, RestDigest/binary>> = Digest,
diff --git a/lib/reltool/src/reltool_utils.erl b/lib/reltool/src/reltool_utils.erl
index edccb889b1..9af8f6bae8 100644
--- a/lib/reltool/src/reltool_utils.erl
+++ b/lib/reltool/src/reltool_utils.erl
@@ -572,7 +572,7 @@ copy_file(From, To) ->
FromMode = FromInfo#file_info.mode,
ToMode = ToInfo#file_info.mode,
ToMode2 = FromMode bor ToMode,
- FileInfo = FromInfo#file_info{mode = ToMode2},
+ FileInfo = ToInfo#file_info{mode = ToMode2},
write_file_info(To, FileInfo),
ok;
{error, Reason} ->
diff --git a/lib/ssl/doc/src/ssl.xml b/lib/ssl/doc/src/ssl.xml
index d5615fecfc..1645eb15f3 100644
--- a/lib/ssl/doc/src/ssl.xml
+++ b/lib/ssl/doc/src/ssl.xml
@@ -37,17 +37,21 @@
<list type="bulleted">
<item>ssl requires the crypto and public_key applications.</item>
<item>Supported SSL/TLS-versions are SSL-3.0, TLS-1.0,
- TLS-1.1 and TLS-1.2 (no support for elliptic curve cipher suites yet).</item>
+ TLS-1.1 and TLS-1.2.</item>
<item>For security reasons sslv2 is not supported.</item>
<item>Ephemeral Diffie-Hellman cipher suites are supported
but not Diffie Hellman Certificates cipher suites.</item>
+ <item>Elliptic Curve cipher suites are supported if crypto
+ supports it and named curves are used.
+ </item>
<item>Export cipher suites are not supported as the
U.S. lifted its export restrictions in early 2000.</item>
<item>IDEA cipher suites are not supported as they have
become deprecated by the latest TLS spec so there is not any
real motivation to implement them.</item>
- <item>CRL and policy certificate
- extensions are not supported yet. </item>
+ <item>CRL and policy certificate extensions are not supported
+ yet. However CRL verification is supported by public_key, only not integrated
+ in ssl yet. </item>
</list>
</section>
@@ -75,7 +79,7 @@
{fail_if_no_peer_cert, boolean()}
{depth, integer()} |
{cert, der_encoded()}| {certfile, path()} |
- {key, {'RSAPrivateKey'| 'DSAPrivateKey' | 'PrivateKeyInfo', der_encoded()}} |
+ {key, {'RSAPrivateKey'| 'DSAPrivateKey' | 'ECPrivateKey' |'PrivateKeyInfo', der_encoded()}} |
{keyfile, path()} | {password, string()} |
{cacerts, [der_encoded()]} | {cacertfile, path()} |
|{dh, der_encoded()} | {dhfile, path()} | {ciphers, ciphers()} |
@@ -125,6 +129,7 @@
<p><c>key_exchange() = rsa | dhe_dss | dhe_rsa | dh_anon
| psk | dhe_psk | rsa_psk | srp_anon | srp_dss | srp_rsa
+ | ecdh_anon | ecdh_ecdsa | ecdhe_ecdsa | ecdh_rsa | ecdhe_rsa
</c></p>
<p><c>cipher() = rc4_128 | des_cbc | '3des_ede_cbc'
@@ -157,7 +162,7 @@
<tag>{certfile, path()}</tag>
<item>Path to a file containing the user's certificate.</item>
- <tag>{key, {'RSAPrivateKey'| 'DSAPrivateKey' | 'PrivateKeyInfo', der_encoded()}}</tag>
+ <tag>{key, {'RSAPrivateKey'| 'DSAPrivateKey' | 'ECPrivateKey' |'PrivateKeyInfo', der_encoded()}}</tag>
<item> The DER encoded users private key. If this option
is supplied it will override the keyfile option.</item>
diff --git a/lib/ssl/src/ssl.erl b/lib/ssl/src/ssl.erl
index 70f3b4f050..f52862729a 100644
--- a/lib/ssl/src/ssl.erl
+++ b/lib/ssl/src/ssl.erl
@@ -364,11 +364,11 @@ cipher_suites() ->
cipher_suites(erlang) ->
Version = ssl_record:highest_protocol_version([]),
- [suite_definition(S) || S <- ssl_cipher:suites(Version)];
+ [suite_definition(S) || S <- cipher_suites(Version, [])];
cipher_suites(openssl) ->
Version = ssl_record:highest_protocol_version([]),
- [ssl_cipher:openssl_suite_name(S) || S <- ssl_cipher:suites(Version)];
+ [ssl_cipher:openssl_suite_name(S) || S <- cipher_suites(Version, [])];
cipher_suites(all) ->
Version = ssl_record:highest_protocol_version([]),
@@ -739,6 +739,7 @@ validate_option(key, {KeyType, Value}) when is_binary(Value),
KeyType == dsa; %% Backwards compatibility
KeyType == 'RSAPrivateKey';
KeyType == 'DSAPrivateKey';
+ KeyType == 'ECPrivateKey';
KeyType == 'PrivateKeyInfo' ->
{KeyType, Value};
@@ -947,21 +948,22 @@ emulated_options([], Inet,Emulated) ->
{Inet, Emulated}.
cipher_suites(Version, []) ->
- ssl_cipher:suites(Version);
+ ssl_cipher:filter_suites(ssl_cipher:suites(Version));
cipher_suites(Version, [{_,_,_,_}| _] = Ciphers0) -> %% Backwards compatibility
Ciphers = [{KeyExchange, Cipher, Hash} || {KeyExchange, Cipher, Hash, _} <- Ciphers0],
- cipher_suites(Version, Ciphers);
+ ssl_cipher:filter_suites(cipher_suites(Version, Ciphers));
cipher_suites(Version, [{_,_,_}| _] = Ciphers0) ->
Ciphers = [ssl_cipher:suite(C) || C <- Ciphers0],
- cipher_suites(Version, Ciphers);
+ ssl_cipher:filter_suites(cipher_suites(Version, Ciphers));
cipher_suites(Version, [Cipher0 | _] = Ciphers0) when is_binary(Cipher0) ->
- Supported = ssl_cipher:suites(Version)
+ Supported0 = ssl_cipher:suites(Version)
++ ssl_cipher:anonymous_suites()
++ ssl_cipher:psk_suites(Version)
++ ssl_cipher:srp_suites(),
- case [Cipher || Cipher <- Ciphers0, lists:member(Cipher, Supported)] of
+ Supported1 = ssl_cipher:filter_suites(Supported0),
+ case [Cipher || Cipher <- Ciphers0, lists:member(Cipher, Supported1)] of
[] ->
- Supported;
+ Supported1;
Ciphers ->
Ciphers
end;
diff --git a/lib/ssl/src/ssl_certificate.erl b/lib/ssl/src/ssl_certificate.erl
index 01a7cd93b5..9e1c3a09bf 100644
--- a/lib/ssl/src/ssl_certificate.erl
+++ b/lib/ssl/src/ssl_certificate.erl
@@ -37,7 +37,8 @@
is_valid_extkey_usage/2,
is_valid_key_usage/2,
select_extension/2,
- extensions_list/1
+ extensions_list/1,
+ public_key_type/1
]).
%%====================================================================
@@ -166,6 +167,18 @@ extensions_list(Extensions) ->
Extensions.
%%--------------------------------------------------------------------
+-spec public_key_type(term()) -> rsa | dsa | ec.
+%%
+%% Description:
+%%--------------------------------------------------------------------
+public_key_type(?'rsaEncryption') ->
+ rsa;
+public_key_type(?'id-dsa') ->
+ dsa;
+public_key_type(?'id-ecPublicKey') ->
+ ec.
+
+%%--------------------------------------------------------------------
%%% Internal functions
%%--------------------------------------------------------------------
certificate_chain(OtpCert, _Cert, CertDbHandle, CertsDbRef, Chain) ->
diff --git a/lib/ssl/src/ssl_certificate_db.erl b/lib/ssl/src/ssl_certificate_db.erl
index ff36b5ee26..cdff73336e 100644
--- a/lib/ssl/src/ssl_certificate_db.erl
+++ b/lib/ssl/src/ssl_certificate_db.erl
@@ -100,7 +100,7 @@ add_trusted_certs(_Pid, {der, DerList}, [CerDb, _,_]) ->
{ok, NewRef};
add_trusted_certs(_Pid, File, [CertsDb, RefDb, PemChache] = Db) ->
- MD5 = crypto:md5(File),
+ MD5 = crypto:hash(md5, File),
case lookup_cached_pem(Db, MD5) of
[{_Content, Ref}] ->
ref_count(Ref, RefDb, 1),
diff --git a/lib/ssl/src/ssl_cipher.erl b/lib/ssl/src/ssl_cipher.erl
index 173c53709b..dc413d6dfc 100644
--- a/lib/ssl/src/ssl_cipher.erl
+++ b/lib/ssl/src/ssl_cipher.erl
@@ -35,7 +35,7 @@
-export([security_parameters/3, suite_definition/1,
decipher/5, cipher/5,
suite/1, suites/1, anonymous_suites/0, psk_suites/1, srp_suites/0,
- openssl_suite/1, openssl_suite_name/1, filter/2,
+ openssl_suite/1, openssl_suite_name/1, filter/2, filter_suites/1,
hash_algorithm/1, sign_algorithm/1]).
-compile(inline).
@@ -73,25 +73,25 @@ cipher(?NULL, CipherState, <<>>, Fragment, _Version) ->
{GenStreamCipherList, CipherState};
cipher(?RC4, CipherState, Mac, Fragment, _Version) ->
State0 = case CipherState#cipher_state.state of
- undefined -> crypto:rc4_set_key(CipherState#cipher_state.key);
+ undefined -> crypto:stream_init(rc4, CipherState#cipher_state.key);
S -> S
end,
GenStreamCipherList = [Fragment, Mac],
- {State1, T} = crypto:rc4_encrypt_with_state(State0, GenStreamCipherList),
+ {State1, T} = crypto:stream_encrypt(State0, GenStreamCipherList),
{T, CipherState#cipher_state{state = State1}};
cipher(?DES, CipherState, Mac, Fragment, Version) ->
block_cipher(fun(Key, IV, T) ->
- crypto:des_cbc_encrypt(Key, IV, T)
+ crypto:block_encrypt(des_cbc, Key, IV, T)
end, block_size(des_cbc), CipherState, Mac, Fragment, Version);
cipher(?'3DES', CipherState, Mac, Fragment, Version) ->
block_cipher(fun(<<K1:8/binary, K2:8/binary, K3:8/binary>>, IV, T) ->
- crypto:des3_cbc_encrypt(K1, K2, K3, IV, T)
+ crypto:block_encrypt(des3_cbc, [K1, K2, K3], IV, T)
end, block_size(des_cbc), CipherState, Mac, Fragment, Version);
cipher(?AES, CipherState, Mac, Fragment, Version) ->
block_cipher(fun(Key, IV, T) when byte_size(Key) =:= 16 ->
- crypto:aes_cbc_128_encrypt(Key, IV, T);
+ crypto:block_encrypt(aes_cbc128, Key, IV, T);
(Key, IV, T) when byte_size(Key) =:= 32 ->
- crypto:aes_cbc_256_encrypt(Key, IV, T)
+ crypto:block_encrypt(aes_cbc256, Key, IV, T)
end, block_size(aes_128_cbc), CipherState, Mac, Fragment, Version).
build_cipher_block(BlockSz, Mac, Fragment) ->
@@ -127,10 +127,10 @@ decipher(?NULL, _HashSz, CipherState, Fragment, _) ->
{Fragment, <<>>, CipherState};
decipher(?RC4, HashSz, CipherState, Fragment, _) ->
State0 = case CipherState#cipher_state.state of
- undefined -> crypto:rc4_set_key(CipherState#cipher_state.key);
+ undefined -> crypto:stream_init(rc4, CipherState#cipher_state.key);
S -> S
end,
- try crypto:rc4_encrypt_with_state(State0, Fragment) of
+ try crypto:stream_decrypt(State0, Fragment) of
{State, Text} ->
GSC = generic_stream_cipher_from_bin(Text, HashSz),
#generic_stream_cipher{content = Content, mac = Mac} = GSC,
@@ -147,17 +147,17 @@ decipher(?RC4, HashSz, CipherState, Fragment, _) ->
decipher(?DES, HashSz, CipherState, Fragment, Version) ->
block_decipher(fun(Key, IV, T) ->
- crypto:des_cbc_decrypt(Key, IV, T)
+ crypto:block_decrypt(des_cbc, Key, IV, T)
end, CipherState, HashSz, Fragment, Version);
decipher(?'3DES', HashSz, CipherState, Fragment, Version) ->
block_decipher(fun(<<K1:8/binary, K2:8/binary, K3:8/binary>>, IV, T) ->
- crypto:des3_cbc_decrypt(K1, K2, K3, IV, T)
+ crypto:block_decrypt(des3_cbc, [K1, K2, K3], IV, T)
end, CipherState, HashSz, Fragment, Version);
decipher(?AES, HashSz, CipherState, Fragment, Version) ->
block_decipher(fun(Key, IV, T) when byte_size(Key) =:= 16 ->
- crypto:aes_cbc_128_decrypt(Key, IV, T);
+ crypto:block_decrypt(aes_cbc128, Key, IV, T);
(Key, IV, T) when byte_size(Key) =:= 32 ->
- crypto:aes_cbc_256_decrypt(Key, IV, T)
+ crypto:block_decrypt(aes_cbc256, Key, IV, T)
end, CipherState, HashSz, Fragment, Version).
block_decipher(Fun, #cipher_state{key=Key, iv=IV} = CipherState0,
@@ -212,10 +212,14 @@ anonymous_suites() ->
?TLS_DH_anon_WITH_AES_128_CBC_SHA,
?TLS_DH_anon_WITH_AES_256_CBC_SHA,
?TLS_DH_anon_WITH_AES_128_CBC_SHA256,
- ?TLS_DH_anon_WITH_AES_256_CBC_SHA256].
+ ?TLS_DH_anon_WITH_AES_256_CBC_SHA256,
+ ?TLS_ECDH_anon_WITH_RC4_128_SHA,
+ ?TLS_ECDH_anon_WITH_3DES_EDE_CBC_SHA,
+ ?TLS_ECDH_anon_WITH_AES_128_CBC_SHA,
+ ?TLS_ECDH_anon_WITH_AES_256_CBC_SHA].
%%--------------------------------------------------------------------
--spec psk_suites(tls_version()) -> [cipher_suite()].
+-spec psk_suites(tls_version() | integer()) -> [cipher_suite()].
%%
%% Description: Returns a list of the PSK cipher suites, only supported
%% if explicitly set by user.
@@ -274,6 +278,11 @@ srp_suites() ->
%% TLS v1.1 suites
suite_definition(?TLS_NULL_WITH_NULL_NULL) ->
{null, null, null, null};
+%% RFC 5746 - Not a real cipher suite used to signal empty "renegotiation_info" extension
+%% to avoid handshake failure from old servers that do not ignore
+%% hello extension data as they should.
+suite_definition(?TLS_EMPTY_RENEGOTIATION_INFO_SCSV) ->
+ {null, null, null, null};
%% suite_definition(?TLS_RSA_WITH_NULL_MD5) ->
%% {rsa, null, md5, default_prf};
%% suite_definition(?TLS_RSA_WITH_NULL_SHA) ->
@@ -423,8 +432,81 @@ suite_definition(?TLS_SRP_SHA_WITH_AES_256_CBC_SHA) ->
suite_definition(?TLS_SRP_SHA_RSA_WITH_AES_256_CBC_SHA) ->
{srp_rsa, aes_256_cbc, sha, default_prf};
suite_definition(?TLS_SRP_SHA_DSS_WITH_AES_256_CBC_SHA) ->
- {srp_dss, aes_256_cbc, sha, default_prf}.
-
+ {srp_dss, aes_256_cbc, sha, default_prf};
+
+%% RFC 4492 EC TLS suites
+suite_definition(?TLS_ECDH_ECDSA_WITH_NULL_SHA) ->
+ {ecdh_ecdsa, null, sha, default_prf};
+suite_definition(?TLS_ECDH_ECDSA_WITH_RC4_128_SHA) ->
+ {ecdh_ecdsa, rc4_128, sha, default_prf};
+suite_definition(?TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA) ->
+ {ecdh_ecdsa, '3des_ede_cbc', sha, default_prf};
+suite_definition(?TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA) ->
+ {ecdh_ecdsa, aes_128_cbc, sha, default_prf};
+suite_definition(?TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA) ->
+ {ecdh_ecdsa, aes_256_cbc, sha, default_prf};
+
+suite_definition(?TLS_ECDHE_ECDSA_WITH_NULL_SHA) ->
+ {ecdhe_ecdsa, null, sha, default_prf};
+suite_definition(?TLS_ECDHE_ECDSA_WITH_RC4_128_SHA) ->
+ {ecdhe_ecdsa, rc4_128, sha, default_prf};
+suite_definition(?TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA) ->
+ {ecdhe_ecdsa, '3des_ede_cbc', sha, default_prf};
+suite_definition(?TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA) ->
+ {ecdhe_ecdsa, aes_128_cbc, sha, default_prf};
+suite_definition(?TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA) ->
+ {ecdhe_ecdsa, aes_256_cbc, sha, default_prf};
+
+suite_definition(?TLS_ECDH_RSA_WITH_NULL_SHA) ->
+ {ecdh_rsa, null, sha, default_prf};
+suite_definition(?TLS_ECDH_RSA_WITH_RC4_128_SHA) ->
+ {ecdh_rsa, rc4_128, sha, default_prf};
+suite_definition(?TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA) ->
+ {ecdh_rsa, '3des_ede_cbc', sha, default_prf};
+suite_definition(?TLS_ECDH_RSA_WITH_AES_128_CBC_SHA) ->
+ {ecdh_rsa, aes_128_cbc, sha, default_prf};
+suite_definition(?TLS_ECDH_RSA_WITH_AES_256_CBC_SHA) ->
+ {ecdh_rsa, aes_256_cbc, sha, default_prf};
+
+suite_definition(?TLS_ECDHE_RSA_WITH_NULL_SHA) ->
+ {ecdhe_rsa, null, sha, default_prf};
+suite_definition(?TLS_ECDHE_RSA_WITH_RC4_128_SHA) ->
+ {ecdhe_rsa, rc4_128, sha, default_prf};
+suite_definition(?TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA) ->
+ {ecdhe_rsa, '3des_ede_cbc', sha, default_prf};
+suite_definition(?TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA) ->
+ {ecdhe_rsa, aes_128_cbc, sha, default_prf};
+suite_definition(?TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA) ->
+ {ecdhe_rsa, aes_256_cbc, sha, default_prf};
+
+suite_definition(?TLS_ECDH_anon_WITH_NULL_SHA) ->
+ {ecdh_anon, null, sha, default_prf};
+suite_definition(?TLS_ECDH_anon_WITH_RC4_128_SHA) ->
+ {ecdh_anon, rc4_128, sha, default_prf};
+suite_definition(?TLS_ECDH_anon_WITH_3DES_EDE_CBC_SHA) ->
+ {ecdh_anon, '3des_ede_cbc', sha, default_prf};
+suite_definition(?TLS_ECDH_anon_WITH_AES_128_CBC_SHA) ->
+ {ecdh_anon, aes_128_cbc, sha, default_prf};
+suite_definition(?TLS_ECDH_anon_WITH_AES_256_CBC_SHA) ->
+ {ecdh_anon, aes_256_cbc, sha, default_prf};
+
+%% RFC 5289 EC TLS suites
+suite_definition(?TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256) ->
+ {ecdhe_ecdsa, aes_128_cbc, sha256, sha256};
+suite_definition(?TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384) ->
+ {ecdhe_ecdsa, aes_256_cbc, sha384, sha384};
+suite_definition(?TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA256) ->
+ {ecdh_ecdsa, aes_128_cbc, sha256, sha256};
+suite_definition(?TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA384) ->
+ {ecdh_ecdsa, aes_256_cbc, sha384, sha384};
+suite_definition(?TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256) ->
+ {ecdhe_rsa, aes_128_cbc, sha256, sha256};
+suite_definition(?TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384) ->
+ {ecdhe_rsa, aes_256_cbc, sha384, sha384};
+suite_definition(?TLS_ECDH_RSA_WITH_AES_128_CBC_SHA256) ->
+ {ecdh_rsa, aes_128_cbc, sha256, sha256};
+suite_definition(?TLS_ECDH_RSA_WITH_AES_256_CBC_SHA384) ->
+ {ecdh_rsa, aes_256_cbc, sha384, sha384}.
%%--------------------------------------------------------------------
-spec suite(erl_cipher_suite()) -> cipher_suite().
@@ -573,7 +655,81 @@ suite({srp_anon, aes_256_cbc, sha}) ->
suite({srp_rsa, aes_256_cbc, sha}) ->
?TLS_SRP_SHA_RSA_WITH_AES_256_CBC_SHA;
suite({srp_dss, aes_256_cbc, sha}) ->
- ?TLS_SRP_SHA_DSS_WITH_AES_256_CBC_SHA.
+ ?TLS_SRP_SHA_DSS_WITH_AES_256_CBC_SHA;
+
+%%% RFC 4492 EC TLS suites
+suite({ecdh_ecdsa, null, sha}) ->
+ ?TLS_ECDH_ECDSA_WITH_NULL_SHA;
+suite({ecdh_ecdsa, rc4_128, sha}) ->
+ ?TLS_ECDH_ECDSA_WITH_RC4_128_SHA;
+suite({ecdh_ecdsa, '3des_ede_cbc', sha}) ->
+ ?TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA;
+suite({ecdh_ecdsa, aes_128_cbc, sha}) ->
+ ?TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA;
+suite({ecdh_ecdsa, aes_256_cbc, sha}) ->
+ ?TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA;
+
+suite({ecdhe_ecdsa, null, sha}) ->
+ ?TLS_ECDHE_ECDSA_WITH_NULL_SHA;
+suite({ecdhe_ecdsa, rc4_128, sha}) ->
+ ?TLS_ECDHE_ECDSA_WITH_RC4_128_SHA;
+suite({ecdhe_ecdsa, '3des_ede_cbc', sha}) ->
+ ?TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA;
+suite({ecdhe_ecdsa, aes_128_cbc, sha}) ->
+ ?TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA;
+suite({ecdhe_ecdsa, aes_256_cbc, sha}) ->
+ ?TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA;
+
+suite({ecdh_rsa, null, sha}) ->
+ ?TLS_ECDH_RSA_WITH_NULL_SHA;
+suite({ecdh_rsa, rc4_128, sha}) ->
+ ?TLS_ECDH_RSA_WITH_RC4_128_SHA;
+suite({ecdh_rsa, '3des_ede_cbc', sha}) ->
+ ?TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA;
+suite({ecdh_rsa, aes_128_cbc, sha}) ->
+ ?TLS_ECDH_RSA_WITH_AES_128_CBC_SHA;
+suite({ecdh_rsa, aes_256_cbc, sha}) ->
+ ?TLS_ECDH_RSA_WITH_AES_256_CBC_SHA;
+
+suite({ecdhe_rsa, null, sha}) ->
+ ?TLS_ECDHE_RSA_WITH_NULL_SHA;
+suite({ecdhe_rsa, rc4_128, sha}) ->
+ ?TLS_ECDHE_RSA_WITH_RC4_128_SHA;
+suite({ecdhe_rsa, '3des_ede_cbc', sha}) ->
+ ?TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA;
+suite({ecdhe_rsa, aes_128_cbc, sha}) ->
+ ?TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA;
+suite({ecdhe_rsa, aes_256_cbc, sha}) ->
+ ?TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA;
+
+suite({ecdh_anon, null, sha}) ->
+ ?TLS_ECDH_anon_WITH_NULL_SHA;
+suite({ecdh_anon, rc4_128, sha}) ->
+ ?TLS_ECDH_anon_WITH_RC4_128_SHA;
+suite({ecdh_anon, '3des_ede_cbc', sha}) ->
+ ?TLS_ECDH_anon_WITH_3DES_EDE_CBC_SHA;
+suite({ecdh_anon, aes_128_cbc, sha}) ->
+ ?TLS_ECDH_anon_WITH_AES_128_CBC_SHA;
+suite({ecdh_anon, aes_256_cbc, sha}) ->
+ ?TLS_ECDH_anon_WITH_AES_256_CBC_SHA;
+
+%%% RFC 5289 EC TLS suites
+suite({ecdhe_ecdsa, aes_128_cbc, sha256}) ->
+ ?TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256;
+suite({ecdhe_ecdsa, aes_256_cbc, sha384}) ->
+ ?TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384;
+suite({ecdh_ecdsa, aes_128_cbc, sha256}) ->
+ ?TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA256;
+suite({ecdh_ecdsa, aes_256_cbc, sha384}) ->
+ ?TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA384;
+suite({ecdhe_rsa, aes_128_cbc, sha256}) ->
+ ?TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256;
+suite({ecdhe_rsa, aes_256_cbc, sha384}) ->
+ ?TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384;
+suite({ecdh_rsa, aes_128_cbc, sha256}) ->
+ ?TLS_ECDH_RSA_WITH_AES_128_CBC_SHA256;
+suite({ecdh_rsa, aes_256_cbc, sha384}) ->
+ ?TLS_ECDH_RSA_WITH_AES_256_CBC_SHA384.
%%--------------------------------------------------------------------
-spec openssl_suite(openssl_cipher_suite()) -> cipher_suite().
@@ -633,8 +789,62 @@ openssl_suite("SRP-RSA-3DES-EDE-CBC-SHA") ->
openssl_suite("SRP-DSS-AES-128-CBC-SHA") ->
?TLS_SRP_SHA_DSS_WITH_AES_128_CBC_SHA;
openssl_suite("SRP-RSA-AES-128-CBC-SHA") ->
- ?TLS_SRP_SHA_RSA_WITH_AES_128_CBC_SHA.
+ ?TLS_SRP_SHA_RSA_WITH_AES_128_CBC_SHA;
+%% RFC 4492 EC TLS suites
+openssl_suite("ECDH-ECDSA-RC4-SHA") ->
+ ?TLS_ECDH_ECDSA_WITH_RC4_128_SHA;
+openssl_suite("ECDH-ECDSA-DES-CBC3-SHA") ->
+ ?TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA;
+openssl_suite("ECDH-ECDSA-AES128-SHA") ->
+ ?TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA;
+openssl_suite("ECDH-ECDSA-AES256-SHA") ->
+ ?TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA;
+
+openssl_suite("ECDHE-ECDSA-RC4-SHA") ->
+ ?TLS_ECDHE_ECDSA_WITH_RC4_128_SHA;
+openssl_suite("ECDHE-ECDSA-DES-CBC3-SHA") ->
+ ?TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA;
+openssl_suite("ECDHE-ECDSA-AES128-SHA") ->
+ ?TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA;
+openssl_suite("ECDHE-ECDSA-AES256-SHA") ->
+ ?TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA;
+
+openssl_suite("ECDHE-RSA-RC4-SHA") ->
+ ?TLS_ECDHE_RSA_WITH_RC4_128_SHA;
+openssl_suite("ECDHE-RSA-DES-CBC3-SHA") ->
+ ?TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA;
+openssl_suite("ECDHE-RSA-AES128-SHA") ->
+ ?TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA;
+openssl_suite("ECDHE-RSA-AES256-SHA") ->
+ ?TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA;
+
+openssl_suite("ECDH-RSA-RC4-SHA") ->
+ ?TLS_ECDH_RSA_WITH_RC4_128_SHA;
+openssl_suite("ECDH-RSA-DES-CBC3-SHA") ->
+ ?TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA;
+openssl_suite("ECDH-RSA-AES128-SHA") ->
+ ?TLS_ECDH_RSA_WITH_AES_128_CBC_SHA;
+openssl_suite("ECDH-RSA-AES256-SHA") ->
+ ?TLS_ECDH_RSA_WITH_AES_256_CBC_SHA;
+
+%% RFC 5289 EC TLS suites
+openssl_suite("ECDHE-ECDSA-AES128-SHA256") ->
+ ?TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256;
+openssl_suite("ECDHE-ECDSA-AES256-SHA384") ->
+ ?TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384;
+openssl_suite("ECDH-ECDSA-AES128-SHA256") ->
+ ?TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA256;
+openssl_suite("ECDH-ECDSA-AES256-SHA384") ->
+ ?TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA384;
+openssl_suite("ECDHE-RSA-AES128-SHA256") ->
+ ?TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256;
+openssl_suite("ECDHE-RSA-AES256-SHA384") ->
+ ?TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384;
+openssl_suite("ECDH-RSA-AES128-SHA256") ->
+ ?TLS_ECDH_RSA_WITH_AES_128_CBC_SHA256;
+openssl_suite("ECDH-RSA-AES256-SHA384") ->
+ ?TLS_ECDH_RSA_WITH_AES_256_CBC_SHA384.
%%--------------------------------------------------------------------
-spec openssl_suite_name(cipher_suite()) -> openssl_cipher_suite().
@@ -716,6 +926,61 @@ openssl_suite_name(?TLS_SRP_SHA_RSA_WITH_AES_256_CBC_SHA) ->
openssl_suite_name(?TLS_SRP_SHA_DSS_WITH_AES_256_CBC_SHA) ->
"SRP-DSS-AES-256-CBC-SHA";
+%% RFC 4492 EC TLS suites
+openssl_suite_name(?TLS_ECDH_ECDSA_WITH_RC4_128_SHA) ->
+ "ECDH-ECDSA-RC4-SHA";
+openssl_suite_name(?TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA) ->
+ "ECDH-ECDSA-DES-CBC3-SHA";
+openssl_suite_name(?TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA) ->
+ "ECDH-ECDSA-AES128-SHA";
+openssl_suite_name(?TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA) ->
+ "ECDH-ECDSA-AES256-SHA";
+
+openssl_suite_name(?TLS_ECDHE_ECDSA_WITH_RC4_128_SHA) ->
+ "ECDHE-ECDSA-RC4-SHA";
+openssl_suite_name(?TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA) ->
+ "ECDHE-ECDSA-DES-CBC3-SHA";
+openssl_suite_name(?TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA) ->
+ "ECDHE-ECDSA-AES128-SHA";
+openssl_suite_name(?TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA) ->
+ "ECDHE-ECDSA-AES256-SHA";
+
+openssl_suite_name(?TLS_ECDH_RSA_WITH_RC4_128_SHA) ->
+ "ECDH-RSA-RC4-SHA";
+openssl_suite_name(?TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA) ->
+ "ECDH-RSA-DES-CBC3-SHA";
+openssl_suite_name(?TLS_ECDH_RSA_WITH_AES_128_CBC_SHA) ->
+ "ECDH-RSA-AES128-SHA";
+openssl_suite_name(?TLS_ECDH_RSA_WITH_AES_256_CBC_SHA) ->
+ "ECDH-RSA-AES256-SHA";
+
+openssl_suite_name(?TLS_ECDHE_RSA_WITH_RC4_128_SHA) ->
+ "ECDHE-RSA-RC4-SHA";
+openssl_suite_name(?TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA) ->
+ "ECDHE-RSA-DES-CBC3-SHA";
+openssl_suite_name(?TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA) ->
+ "ECDHE-RSA-AES128-SHA";
+openssl_suite_name(?TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA) ->
+ "ECDHE-RSA-AES256-SHA";
+
+%% RFC 5289 EC TLS suites
+openssl_suite_name(?TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256) ->
+ "ECDHE-ECDSA-AES128-SHA256";
+openssl_suite_name(?TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384) ->
+ "ECDHE-ECDSA-AES256-SHA384";
+openssl_suite_name(?TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA256) ->
+ "ECDH-ECDSA-AES128-SHA256";
+openssl_suite_name(?TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA384) ->
+ "ECDH-ECDSA-AES256-SHA384";
+openssl_suite_name(?TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256) ->
+ "ECDHE-RSA-AES128-SHA256";
+openssl_suite_name(?TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384) ->
+ "ECDHE-RSA-AES256-SHA384";
+openssl_suite_name(?TLS_ECDH_RSA_WITH_AES_128_CBC_SHA256) ->
+ "ECDH-RSA-AES128-SHA256";
+openssl_suite_name(?TLS_ECDH_RSA_WITH_AES_256_CBC_SHA384) ->
+ "ECDH-RSA-AES256-SHA384";
+
%% No oppenssl name
openssl_suite_name(Cipher) ->
suite_definition(Cipher).
@@ -730,14 +995,85 @@ filter(undefined, Ciphers) ->
filter(DerCert, Ciphers) ->
OtpCert = public_key:pkix_decode_cert(DerCert, otp),
SigAlg = OtpCert#'OTPCertificate'.signatureAlgorithm,
+ PubKeyInfo = OtpCert#'OTPCertificate'.tbsCertificate#'OTPTBSCertificate'.subjectPublicKeyInfo,
+ PubKeyAlg = PubKeyInfo#'OTPSubjectPublicKeyInfo'.algorithm,
+
+ Ciphers1 =
+ case ssl_certificate:public_key_type(PubKeyAlg#'PublicKeyAlgorithm'.algorithm) of
+ rsa ->
+ filter_keyuse(OtpCert, ((Ciphers -- dsa_signed_suites()) -- ec_keyed_suites()) -- ecdh_suites(),
+ rsa_suites(), dhe_rsa_suites() ++ ecdhe_rsa_suites());
+ dsa ->
+ (Ciphers -- rsa_keyed_suites()) -- ec_keyed_suites();
+ ec ->
+ filter_keyuse(OtpCert, (Ciphers -- rsa_keyed_suites()) -- dsa_signed_suites(),
+ [], ecdhe_ecdsa_suites())
+ end,
case public_key:pkix_sign_types(SigAlg#'SignatureAlgorithm'.algorithm) of
{_, rsa} ->
- filter_rsa(OtpCert, Ciphers -- dsa_signed_suites());
+ Ciphers1 -- ecdsa_signed_suites();
{_, dsa} ->
- Ciphers -- rsa_signed_suites()
+ Ciphers1;
+ {_, ecdsa} ->
+ Ciphers1 -- rsa_signed_suites()
end.
%%--------------------------------------------------------------------
+-spec filter_suites([cipher_suite()]) -> [cipher_suite()].
+%%
+%% Description: filter suites for algorithms
+%%-------------------------------------------------------------------
+filter_suites(Suites = [{_,_,_}|_]) ->
+ Algos = crypto:algorithms(),
+ lists:filter(fun({KeyExchange, Cipher, Hash}) ->
+ is_acceptable_keyexchange(KeyExchange, Algos) andalso
+ is_acceptable_cipher(Cipher, Algos) andalso
+ is_acceptable_hash(Hash, Algos)
+ end, Suites);
+
+filter_suites(Suites = [{_,_,_,_}|_]) ->
+ Algos = crypto:algorithms(),
+ lists:filter(fun({KeyExchange, Cipher, Hash, Prf}) ->
+ is_acceptable_keyexchange(KeyExchange, Algos) andalso
+ is_acceptable_cipher(Cipher, Algos) andalso
+ is_acceptable_hash(Hash, Algos) andalso
+ is_acceptable_prf(Prf, Algos)
+ end, Suites);
+
+filter_suites(Suites) ->
+ Algos = crypto:algorithms(),
+ lists:filter(fun(Suite) ->
+ {KeyExchange, Cipher, Hash, Prf} = ssl_cipher:suite_definition(Suite),
+ is_acceptable_keyexchange(KeyExchange, Algos) andalso
+ is_acceptable_cipher(Cipher, Algos) andalso
+ is_acceptable_hash(Hash, Algos) andalso
+ is_acceptable_prf(Prf, Algos)
+ end, Suites).
+
+is_acceptable_keyexchange(KeyExchange, Algos)
+ when KeyExchange == ecdh_ecdsa;
+ KeyExchange == ecdhe_ecdsa;
+ KeyExchange == ecdh_rsa;
+ KeyExchange == ecdhe_rsa;
+ KeyExchange == ecdh_anon ->
+ proplists:get_bool(ec, Algos);
+is_acceptable_keyexchange(_, _) ->
+ true.
+
+is_acceptable_cipher(_, _) ->
+ true.
+
+is_acceptable_hash(null, _Algos) ->
+ true;
+is_acceptable_hash(Hash, Algos) ->
+ proplists:get_bool(Hash, Algos).
+
+is_acceptable_prf(default_prf, _) ->
+ true;
+is_acceptable_prf(Prf, Algos) ->
+ proplists:get_bool(Prf, Algos).
+
+%%--------------------------------------------------------------------
%%% Internal functions
%%--------------------------------------------------------------------
@@ -950,7 +1286,13 @@ next_iv(Bin, IV) ->
rsa_signed_suites() ->
dhe_rsa_suites() ++ rsa_suites() ++
- psk_rsa_suites() ++ srp_rsa_suites().
+ psk_rsa_suites() ++ srp_rsa_suites() ++
+ ecdh_rsa_suites().
+
+rsa_keyed_suites() ->
+ dhe_rsa_suites() ++ rsa_suites() ++
+ psk_rsa_suites() ++ srp_rsa_suites() ++
+ ecdhe_rsa_suites().
dhe_rsa_suites() ->
[?TLS_DHE_RSA_WITH_AES_256_CBC_SHA256,
@@ -982,7 +1324,25 @@ rsa_suites() ->
?TLS_RSA_WITH_RC4_128_SHA,
?TLS_RSA_WITH_RC4_128_MD5,
?TLS_RSA_WITH_DES_CBC_SHA].
-
+
+ecdh_rsa_suites() ->
+ [?TLS_ECDH_RSA_WITH_NULL_SHA,
+ ?TLS_ECDH_RSA_WITH_RC4_128_SHA,
+ ?TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA,
+ ?TLS_ECDH_RSA_WITH_AES_128_CBC_SHA,
+ ?TLS_ECDH_RSA_WITH_AES_256_CBC_SHA,
+ ?TLS_ECDH_RSA_WITH_AES_128_CBC_SHA256,
+ ?TLS_ECDH_RSA_WITH_AES_256_CBC_SHA384].
+
+ecdhe_rsa_suites() ->
+ [?TLS_ECDHE_RSA_WITH_NULL_SHA,
+ ?TLS_ECDHE_RSA_WITH_RC4_128_SHA,
+ ?TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA,
+ ?TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA,
+ ?TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA,
+ ?TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256,
+ ?TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384].
+
dsa_signed_suites() ->
dhe_dss_suites() ++ srp_dss_suites().
@@ -999,24 +1359,52 @@ srp_dss_suites() ->
?TLS_SRP_SHA_DSS_WITH_AES_128_CBC_SHA,
?TLS_SRP_SHA_DSS_WITH_AES_256_CBC_SHA].
-filter_rsa(OtpCert, RsaCiphers) ->
+ec_keyed_suites() ->
+ ecdh_ecdsa_suites() ++ ecdhe_ecdsa_suites()
+ ++ ecdh_rsa_suites().
+
+ecdsa_signed_suites() ->
+ ecdh_ecdsa_suites() ++ ecdhe_ecdsa_suites().
+
+ecdh_suites() ->
+ ecdh_rsa_suites() ++ ecdh_ecdsa_suites().
+
+ecdh_ecdsa_suites() ->
+ [?TLS_ECDH_ECDSA_WITH_NULL_SHA,
+ ?TLS_ECDH_ECDSA_WITH_RC4_128_SHA,
+ ?TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA,
+ ?TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA,
+ ?TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA,
+ ?TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA256,
+ ?TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA384].
+
+ecdhe_ecdsa_suites() ->
+ [?TLS_ECDHE_ECDSA_WITH_NULL_SHA,
+ ?TLS_ECDHE_ECDSA_WITH_RC4_128_SHA,
+ ?TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA,
+ ?TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA,
+ ?TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA,
+ ?TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256,
+ ?TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384].
+
+filter_keyuse(OtpCert, Ciphers, Suites, SignSuites) ->
TBSCert = OtpCert#'OTPCertificate'.tbsCertificate,
TBSExtensions = TBSCert#'OTPTBSCertificate'.extensions,
Extensions = ssl_certificate:extensions_list(TBSExtensions),
case ssl_certificate:select_extension(?'id-ce-keyUsage', Extensions) of
undefined ->
- RsaCiphers;
+ Ciphers;
#'Extension'{extnValue = KeyUse} ->
- Result = filter_rsa_suites(keyEncipherment,
- KeyUse, RsaCiphers, rsa_suites()),
- filter_rsa_suites(digitalSignature,
- KeyUse, Result, dhe_rsa_suites())
+ Result = filter_keyuse_suites(keyEncipherment,
+ KeyUse, Ciphers, Suites),
+ filter_keyuse_suites(digitalSignature,
+ KeyUse, Result, SignSuites)
end.
-filter_rsa_suites(Use, KeyUse, CipherSuits, RsaSuites) ->
+filter_keyuse_suites(Use, KeyUse, CipherSuits, Suites) ->
case ssl_certificate:is_valid_key_usage(KeyUse, Use) of
true ->
CipherSuits;
false ->
- CipherSuits -- RsaSuites
+ CipherSuits -- Suites
end.
diff --git a/lib/ssl/src/ssl_cipher.hrl b/lib/ssl/src/ssl_cipher.hrl
index 90d3704efd..c7c71ee1a7 100644
--- a/lib/ssl/src/ssl_cipher.hrl
+++ b/lib/ssl/src/ssl_cipher.hrl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2007-2012. All Rights Reserved.
+%% Copyright Ericsson AB 2007-2013. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -28,9 +28,9 @@
-type cipher() :: null |rc4_128 | idea_cbc | des40_cbc | des_cbc | '3des_ede_cbc'
| aes_128_cbc | aes_256_cbc.
--type hash() :: null | sha | md5 | sha256 | sha384 | sha512.
+-type hash() :: null | sha | md5 | ssh224 | sha256 | sha384 | sha512.
-type erl_cipher_suite() :: {key_algo(), cipher(), hash()}.
--type int_cipher_suite() :: {key_algo(), cipher(), hash(), hash()}.
+-type int_cipher_suite() :: {key_algo(), cipher(), hash(), hash() | default_prf}.
-type cipher_suite() :: binary().
-type cipher_enum() :: integer().
-type openssl_cipher_suite() :: string().
@@ -219,6 +219,120 @@
%% TLS_DH_anon_WITH_AES_256_CBC_SHA256 = { 0x00,0x6D };
-define(TLS_DH_anon_WITH_AES_256_CBC_SHA256, <<?BYTE(16#00), ?BYTE(16#6D)>>).
+%% RFC 4492 EC TLS suites
+
+%% ECDH_ECDSA
+
+%% TLS_ECDH_ECDSA_WITH_NULL_SHA = { 0xC0, 0x01 }
+-define(TLS_ECDH_ECDSA_WITH_NULL_SHA, <<?BYTE(16#C0), ?BYTE(16#01)>>).
+
+%% TLS_ECDH_ECDSA_WITH_RC4_128_SHA = { 0xC0, 0x02 }
+-define(TLS_ECDH_ECDSA_WITH_RC4_128_SHA, <<?BYTE(16#C0), ?BYTE(16#02)>>).
+
+%% TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA = { 0xC0, 0x03 }
+-define(TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA, <<?BYTE(16#C0), ?BYTE(16#03)>>).
+
+%% TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA = { 0xC0, 0x04 }
+-define(TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA, <<?BYTE(16#C0), ?BYTE(16#04)>>).
+
+%% TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA = { 0xC0, 0x05 }
+-define(TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA, <<?BYTE(16#C0), ?BYTE(16#05)>>).
+
+%% ECDHE_ECDSA
+
+%% TLS_ECDHE_ECDSA_WITH_NULL_SHA = { 0xC0, 0x06 }
+-define(TLS_ECDHE_ECDSA_WITH_NULL_SHA, <<?BYTE(16#C0), ?BYTE(16#06)>>).
+
+%% TLS_ECDHE_ECDSA_WITH_RC4_128_SHA = { 0xC0, 0x07 }
+-define(TLS_ECDHE_ECDSA_WITH_RC4_128_SHA, <<?BYTE(16#C0), ?BYTE(16#07)>>).
+
+%% TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA = { 0xC0, 0x08 }
+-define(TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA, <<?BYTE(16#C0), ?BYTE(16#08)>>).
+
+%% TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA = { 0xC0, 0x09 }
+-define(TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA, <<?BYTE(16#C0), ?BYTE(16#09)>>).
+
+%% TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA = { 0xC0, 0x0A }
+-define(TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA, <<?BYTE(16#C0), ?BYTE(16#0A)>>).
+
+%% ECDH_RSA
+
+%% TLS_ECDH_RSA_WITH_NULL_SHA = { 0xC0, 0x0B }
+-define(TLS_ECDH_RSA_WITH_NULL_SHA, <<?BYTE(16#C0), ?BYTE(16#0B)>>).
+
+%% TLS_ECDH_RSA_WITH_RC4_128_SHA = { 0xC0, 0x0C }
+-define(TLS_ECDH_RSA_WITH_RC4_128_SHA, <<?BYTE(16#C0), ?BYTE(16#0C)>>).
+
+%% TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA = { 0xC0, 0x0D }
+-define(TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA, <<?BYTE(16#C0), ?BYTE(16#0D)>>).
+
+%% TLS_ECDH_RSA_WITH_AES_128_CBC_SHA = { 0xC0, 0x0E }
+-define(TLS_ECDH_RSA_WITH_AES_128_CBC_SHA, <<?BYTE(16#C0), ?BYTE(16#0E)>>).
+
+%% TLS_ECDH_RSA_WITH_AES_256_CBC_SHA = { 0xC0, 0x0F }
+-define(TLS_ECDH_RSA_WITH_AES_256_CBC_SHA, <<?BYTE(16#C0), ?BYTE(16#0F)>>).
+
+%% ECDHE_RSA
+
+%% TLS_ECDHE_RSA_WITH_NULL_SHA = { 0xC0, 0x10 }
+-define(TLS_ECDHE_RSA_WITH_NULL_SHA, <<?BYTE(16#C0), ?BYTE(16#10)>>).
+
+%% TLS_ECDHE_RSA_WITH_RC4_128_SHA = { 0xC0, 0x11 }
+-define(TLS_ECDHE_RSA_WITH_RC4_128_SHA, <<?BYTE(16#C0), ?BYTE(16#11)>>).
+
+%% TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA = { 0xC0, 0x12 }
+-define(TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA, <<?BYTE(16#C0), ?BYTE(16#12)>>).
+
+%% TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA = { 0xC0, 0x13 }
+-define(TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA, <<?BYTE(16#C0), ?BYTE(16#13)>>).
+
+%% TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA = { 0xC0, 0x14 }
+-define(TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA, <<?BYTE(16#C0), ?BYTE(16#14)>>).
+
+%% ECDH_anon
+
+%% TLS_ECDH_anon_WITH_NULL_SHA = { 0xC0, 0x15 }
+-define(TLS_ECDH_anon_WITH_NULL_SHA, <<?BYTE(16#C0), ?BYTE(16#15)>>).
+
+%% TLS_ECDH_anon_WITH_RC4_128_SHA = { 0xC0, 0x16 }
+-define(TLS_ECDH_anon_WITH_RC4_128_SHA, <<?BYTE(16#C0), ?BYTE(16#16)>>).
+
+%% TLS_ECDH_anon_WITH_3DES_EDE_CBC_SHA = { 0xC0, 0x17 }
+-define(TLS_ECDH_anon_WITH_3DES_EDE_CBC_SHA, <<?BYTE(16#C0), ?BYTE(16#17)>>).
+
+%% TLS_ECDH_anon_WITH_AES_128_CBC_SHA = { 0xC0, 0x18 }
+-define(TLS_ECDH_anon_WITH_AES_128_CBC_SHA, <<?BYTE(16#C0), ?BYTE(16#18)>>).
+
+%% TLS_ECDH_anon_WITH_AES_256_CBC_SHA = { 0xC0, 0x19 }
+-define(TLS_ECDH_anon_WITH_AES_256_CBC_SHA, <<?BYTE(16#C0), ?BYTE(16#19)>>).
+
+
+%% RFC 5289 EC TLS suites
+
+%% TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256 = {0xC0,0x23};
+-define(TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256, <<?BYTE(16#C0), ?BYTE(16#23)>>).
+
+%% TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384 = {0xC0,0x24};
+-define(TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384, <<?BYTE(16#C0), ?BYTE(16#24)>>).
+
+%% TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA256 = {0xC0,0x25};
+-define(TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA256, <<?BYTE(16#C0), ?BYTE(16#25)>>).
+
+%% TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA384 = {0xC0,0x26};
+-define(TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA384, <<?BYTE(16#C0), ?BYTE(16#26)>>).
+
+%% TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256 = {0xC0,0x27};
+-define(TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256, <<?BYTE(16#C0), ?BYTE(16#27)>>).
+
+%% TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384 = {0xC0,0x28};
+-define(TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384, <<?BYTE(16#C0), ?BYTE(16#28)>>).
+
+%% TLS_ECDH_RSA_WITH_AES_128_CBC_SHA256 = {0xC0,0x29};
+-define(TLS_ECDH_RSA_WITH_AES_128_CBC_SHA256, <<?BYTE(16#C0), ?BYTE(16#29)>>).
+
+%% TLS_ECDH_RSA_WITH_AES_256_CBC_SHA384 = {0xC0,0x2A};
+-define(TLS_ECDH_RSA_WITH_AES_256_CBC_SHA384, <<?BYTE(16#C0), ?BYTE(16#2A)>>).
+
%%% Kerberos Cipher Suites
%% TLS_KRB5_WITH_DES_CBC_SHA = { 0x00,0x1E };
diff --git a/lib/ssl/src/ssl_connection.erl b/lib/ssl/src/ssl_connection.erl
index fa64915fd0..54eed03d3c 100644
--- a/lib/ssl/src/ssl_connection.erl
+++ b/lib/ssl/src/ssl_connection.erl
@@ -98,7 +98,8 @@
terminated = false, %
allow_renegotiate = true,
expecting_next_protocol_negotiation = false :: boolean(),
- next_protocol = undefined :: undefined | binary()
+ next_protocol = undefined :: undefined | binary(),
+ client_ecc % {Curves, PointFmt}
}).
-define(DEFAULT_DIFFIE_HELLMAN_PARAMS,
@@ -416,11 +417,14 @@ hello(Hello = #client_hello{client_version = ClientVersion},
ssl_options = SslOpts}) ->
case ssl_handshake:hello(Hello, SslOpts, {Port, Session0, Cache, CacheCb,
ConnectionStates0, Cert}, Renegotiation) of
- {Version, {Type, Session}, ConnectionStates, ProtocolsToAdvertise} ->
- do_server_hello(Type, ProtocolsToAdvertise, State#state{connection_states =
- ConnectionStates,
- negotiated_version = Version,
- session = Session});
+ {Version, {Type, Session}, ConnectionStates, ProtocolsToAdvertise,
+ EcPointFormats, EllipticCurves} ->
+ do_server_hello(Type, ProtocolsToAdvertise,
+ EcPointFormats, EllipticCurves,
+ State#state{connection_states = ConnectionStates,
+ negotiated_version = Version,
+ session = Session,
+ client_ecc = {EllipticCurves, EcPointFormats}});
#alert{} = Alert ->
handle_own_alert(Alert, ClientVersion, hello, State)
end;
@@ -533,7 +537,9 @@ certify(#certificate{} = Cert,
certify(#server_key_exchange{} = KeyExchangeMsg,
#state{role = client, negotiated_version = Version,
key_algorithm = Alg} = State0)
- when Alg == dhe_dss; Alg == dhe_rsa; Alg == dh_anon;
+ when Alg == dhe_dss; Alg == dhe_rsa;
+ Alg == ecdhe_rsa; Alg == ecdhe_ecdsa;
+ Alg == dh_anon; Alg == ecdh_anon;
Alg == psk; Alg == dhe_psk; Alg == rsa_psk;
Alg == srp_dss; Alg == srp_rsa; Alg == srp_anon ->
case handle_server_key(KeyExchangeMsg, State0) of
@@ -669,9 +675,20 @@ certify_client_key_exchange(#encrypted_premaster_secret{premaster_secret= EncPMS
certify_client_key_exchange(#client_diffie_hellman_public{dh_public = ClientPublicDhKey},
#state{negotiated_version = Version,
diffie_hellman_params = #'DHParameter'{prime = P,
- base = G},
+ base = G} = Params,
diffie_hellman_keys = {_, ServerDhPrivateKey}} = State0) ->
- case dh_master_secret(crypto:mpint(P), crypto:mpint(G), ClientPublicDhKey, ServerDhPrivateKey, State0) of
+ case dh_master_secret(Params, ClientPublicDhKey, ServerDhPrivateKey, State0) of
+ #state{} = State1 ->
+ {Record, State} = next_record(State1),
+ next_state(certify, cipher, Record, State);
+ #alert{} = Alert ->
+ handle_own_alert(Alert, Version, certify, State0)
+ end;
+
+certify_client_key_exchange(#client_ec_diffie_hellman_public{dh_public = ClientPublicEcDhPoint},
+ #state{negotiated_version = Version,
+ diffie_hellman_keys = ECDHKey} = State0) ->
+ case ec_dh_master_secret(ECDHKey, #'ECPoint'{point = ClientPublicEcDhPoint}, State0) of
#state{} = State1 ->
{Record, State} = next_record(State1),
next_state(certify, cipher, Record, State);
@@ -696,7 +713,7 @@ certify_client_key_exchange(#client_dhe_psk_identity{
diffie_hellman_params = #'DHParameter'{prime = P,
base = G},
diffie_hellman_keys = {_, ServerDhPrivateKey}} = State0) ->
- case dhe_psk_master_secret(ClientPSKIdentity, crypto:mpint(P), crypto:mpint(G), ClientPublicDhKey, ServerDhPrivateKey, State0) of
+ case dhe_psk_master_secret(ClientPSKIdentity, P, G, ClientPublicDhKey, ServerDhPrivateKey, State0) of
#state{} = State1 ->
{Record, State} = next_record(State1),
next_state(certify, cipher, Record, State);
@@ -1278,6 +1295,7 @@ init_private_key(DbHandle, undefined, KeyFile, Password, _) ->
[PemEntry] = [PemEntry || PemEntry = {PKey, _ , _} <- List,
PKey =:= 'RSAPrivateKey' orelse
PKey =:= 'DSAPrivateKey' orelse
+ PKey =:= 'ECPrivateKey' orelse
PKey =:= 'PrivateKeyInfo'
],
private_key(public_key:pem_entry_decode(PemEntry, Password))
@@ -1291,6 +1309,8 @@ init_private_key(_,{rsa, PrivateKey}, _, _,_) ->
init_private_key('RSAPrivateKey', PrivateKey);
init_private_key(_,{dsa, PrivateKey},_,_,_) ->
init_private_key('DSAPrivateKey', PrivateKey);
+init_private_key(_,{ec, PrivateKey},_,_,_) ->
+ init_private_key('ECPrivateKey', PrivateKey);
init_private_key(_,{Asn1Type, PrivateKey},_,_,_) ->
private_key(init_private_key(Asn1Type, PrivateKey)).
@@ -1306,6 +1326,7 @@ private_key(#'PrivateKeyInfo'{privateKeyAlgorithm =
#'PrivateKeyInfo_privateKeyAlgorithm'{algorithm = ?'id-dsa'},
privateKey = Key}) ->
public_key:der_decode('DSAPrivateKey', iolist_to_binary(Key));
+
private_key(Key) ->
Key.
@@ -1357,7 +1378,15 @@ handle_peer_cert(PeerCert, PublicKeyInfo,
State1 = State0#state{session =
Session#session{peer_certificate = PeerCert},
public_key_info = PublicKeyInfo},
- {Record, State} = next_record(State1),
+ State2 = case PublicKeyInfo of
+ {?'id-ecPublicKey', #'ECPoint'{point = _ECPoint} = PublicKey, PublicKeyParams} ->
+ ECDHKey = public_key:generate_key(PublicKeyParams),
+ State3 = State1#state{diffie_hellman_keys = ECDHKey},
+ ec_dh_master_secret(ECDHKey, PublicKey, State3);
+
+ _ -> State1
+ end,
+ {Record, State} = next_record(State2),
next_state(certify, certify, Record, State).
certify_client(#state{client_certificate_requested = true, role = client,
@@ -1407,15 +1436,18 @@ verify_client_cert(#state{client_certificate_requested = true, role = client,
verify_client_cert(#state{client_certificate_requested = false} = State) ->
State.
-do_server_hello(Type, NextProtocolsToSend, #state{negotiated_version = Version,
- session = #session{session_id = SessId},
- connection_states = ConnectionStates0,
- renegotiation = {Renegotiation, _}}
+do_server_hello(Type, NextProtocolsToSend,
+ EcPointFormats, EllipticCurves,
+ #state{negotiated_version = Version,
+ session = #session{session_id = SessId},
+ connection_states = ConnectionStates0,
+ renegotiation = {Renegotiation, _}}
= State0) when is_atom(Type) ->
ServerHello =
ssl_handshake:server_hello(SessId, Version,
- ConnectionStates0, Renegotiation, NextProtocolsToSend),
+ ConnectionStates0, Renegotiation,
+ NextProtocolsToSend, EcPointFormats, EllipticCurves),
State = server_hello(ServerHello,
State0#state{expecting_next_protocol_negotiation =
NextProtocolsToSend =/= undefined}),
@@ -1547,7 +1579,7 @@ server_hello_done(#state{transport_cb = Transport,
tls_handshake_history = Handshake}.
certify_server(#state{key_algorithm = Algo} = State)
- when Algo == dh_anon; Algo == psk; Algo == dhe_psk; Algo == srp_anon ->
+ when Algo == dh_anon; Algo == ecdh_anon; Algo == psk; Algo == dhe_psk; Algo == srp_anon ->
State;
certify_server(#state{transport_cb = Transport,
@@ -1574,7 +1606,7 @@ key_exchange(#state{role = server, key_algorithm = rsa} = State) ->
State;
key_exchange(#state{role = server, key_algorithm = Algo,
hashsign_algorithm = HashSignAlgo,
- diffie_hellman_params = #'DHParameter'{prime = P, base = G} = Params,
+ diffie_hellman_params = #'DHParameter'{} = Params,
private_key = PrivateKey,
connection_states = ConnectionStates0,
negotiated_version = Version,
@@ -1585,13 +1617,13 @@ key_exchange(#state{role = server, key_algorithm = Algo,
when Algo == dhe_dss;
Algo == dhe_rsa;
Algo == dh_anon ->
- Keys = crypto:dh_generate_key([crypto:mpint(P), crypto:mpint(G)]),
+ DHKeys = public_key:generate_key(Params),
ConnectionState =
ssl_record:pending_connection_state(ConnectionStates0, read),
SecParams = ConnectionState#connection_state.security_parameters,
#security_parameters{client_random = ClientRandom,
server_random = ServerRandom} = SecParams,
- Msg = ssl_handshake:key_exchange(server, Version, {dh, Keys, Params,
+ Msg = ssl_handshake:key_exchange(server, Version, {dh, DHKeys, Params,
HashSignAlgo, ClientRandom,
ServerRandom,
PrivateKey}),
@@ -1599,9 +1631,41 @@ key_exchange(#state{role = server, key_algorithm = Algo,
encode_handshake(Msg, Version, ConnectionStates0, Handshake0),
Transport:send(Socket, BinMsg),
State#state{connection_states = ConnectionStates,
- diffie_hellman_keys = Keys,
+ diffie_hellman_keys = DHKeys,
tls_handshake_history = Handshake};
+key_exchange(#state{role = server, private_key = Key, key_algorithm = Algo} = State)
+ when Algo == ecdh_ecdsa; Algo == ecdh_rsa ->
+ State#state{diffie_hellman_keys = Key};
+key_exchange(#state{role = server, key_algorithm = Algo,
+ hashsign_algorithm = HashSignAlgo,
+ private_key = PrivateKey,
+ connection_states = ConnectionStates0,
+ negotiated_version = Version,
+ tls_handshake_history = Handshake0,
+ socket = Socket,
+ transport_cb = Transport
+ } = State)
+ when Algo == ecdhe_ecdsa; Algo == ecdhe_rsa;
+ Algo == ecdh_anon ->
+
+ ECDHKeys = public_key:generate_key(select_curve(State)),
+ ConnectionState =
+ ssl_record:pending_connection_state(ConnectionStates0, read),
+ SecParams = ConnectionState#connection_state.security_parameters,
+ #security_parameters{client_random = ClientRandom,
+ server_random = ServerRandom} = SecParams,
+ Msg = ssl_handshake:key_exchange(server, Version, {ecdh, ECDHKeys,
+ HashSignAlgo, ClientRandom,
+ ServerRandom,
+ PrivateKey}),
+ {BinMsg, ConnectionStates, Handshake1} =
+ encode_handshake(Msg, Version, ConnectionStates0, Handshake0),
+ Transport:send(Socket, BinMsg),
+ State#state{connection_states = ConnectionStates,
+ diffie_hellman_keys = ECDHKeys,
+ tls_handshake_history = Handshake1};
+
key_exchange(#state{role = server, key_algorithm = psk,
ssl_options = #ssl_options{psk_identity = undefined}} = State) ->
State;
@@ -1633,7 +1697,7 @@ key_exchange(#state{role = server, key_algorithm = psk,
key_exchange(#state{role = server, key_algorithm = dhe_psk,
ssl_options = #ssl_options{psk_identity = PskIdentityHint},
hashsign_algorithm = HashSignAlgo,
- diffie_hellman_params = #'DHParameter'{prime = P, base = G} = Params,
+ diffie_hellman_params = #'DHParameter'{} = Params,
private_key = PrivateKey,
connection_states = ConnectionStates0,
negotiated_version = Version,
@@ -1641,13 +1705,13 @@ key_exchange(#state{role = server, key_algorithm = dhe_psk,
socket = Socket,
transport_cb = Transport
} = State) ->
- Keys = crypto:dh_generate_key([crypto:mpint(P), crypto:mpint(G)]),
+ DHKeys = public_key:generate_key(Params),
ConnectionState =
ssl_record:pending_connection_state(ConnectionStates0, read),
SecParams = ConnectionState#connection_state.security_parameters,
#security_parameters{client_random = ClientRandom,
server_random = ServerRandom} = SecParams,
- Msg = ssl_handshake:key_exchange(server, Version, {dhe_psk, PskIdentityHint, Keys, Params,
+ Msg = ssl_handshake:key_exchange(server, Version, {dhe_psk, PskIdentityHint, DHKeys, Params,
HashSignAlgo, ClientRandom,
ServerRandom,
PrivateKey}),
@@ -1655,7 +1719,7 @@ key_exchange(#state{role = server, key_algorithm = dhe_psk,
encode_handshake(Msg, Version, ConnectionStates0, Handshake0),
Transport:send(Socket, BinMsg),
State#state{connection_states = ConnectionStates,
- diffie_hellman_keys = Keys,
+ diffie_hellman_keys = DHKeys,
tls_handshake_history = Handshake};
key_exchange(#state{role = server, key_algorithm = rsa_psk,
@@ -1756,6 +1820,23 @@ key_exchange(#state{role = client,
tls_handshake_history = Handshake};
key_exchange(#state{role = client,
+ connection_states = ConnectionStates0,
+ key_algorithm = Algorithm,
+ negotiated_version = Version,
+ diffie_hellman_keys = Keys,
+ socket = Socket, transport_cb = Transport,
+ tls_handshake_history = Handshake0} = State)
+ when Algorithm == ecdhe_ecdsa; Algorithm == ecdhe_rsa;
+ Algorithm == ecdh_ecdsa; Algorithm == ecdh_rsa;
+ Algorithm == ecdh_anon ->
+ Msg = ssl_handshake:key_exchange(client, Version, {ecdh, Keys}),
+ {BinMsg, ConnectionStates, Handshake} =
+ encode_handshake(Msg, Version, ConnectionStates0, Handshake0),
+ Transport:send(Socket, BinMsg),
+ State#state{connection_states = ConnectionStates,
+ tls_handshake_history = Handshake};
+
+key_exchange(#state{role = client,
ssl_options = SslOpts,
connection_states = ConnectionStates0,
key_algorithm = psk,
@@ -1936,7 +2017,7 @@ handle_server_key(#server_key_exchange{exchange_keys = Keys},
Params = ssl_handshake:decode_server_key(Keys, KeyAlg, Version),
HashSign = connection_hashsign(Params#server_key_params.hashsign, State),
case HashSign of
- {_, anon} ->
+ {_, SignAlgo} when SignAlgo == anon; SignAlgo == ecdh_anon ->
server_master_secret(Params#server_key_params.params, State);
_ ->
verify_server_key(Params, HashSign, State)
@@ -1969,6 +2050,11 @@ server_master_secret(#server_dh_params{dh_p = P, dh_g = G, dh_y = ServerPublicDh
State) ->
dh_master_secret(P, G, ServerPublicDhKey, undefined, State);
+server_master_secret(#server_ecdh_params{curve = ECCurve, public = ECServerPubKey},
+ State) ->
+ ECDHKeys = public_key:generate_key(ECCurve),
+ ec_dh_master_secret(ECDHKeys, #'ECPoint'{point = ECServerPubKey}, State#state{diffie_hellman_keys = ECDHKeys});
+
server_master_secret(#server_psk_params{
hint = IdentityHint},
State) ->
@@ -2000,17 +2086,23 @@ master_from_premaster_secret(PremasterSecret,
Alert
end.
+dh_master_secret(#'DHParameter'{} = Params, OtherPublicDhKey, MyPrivateKey, State) ->
+ PremasterSecret =
+ public_key:compute_key(OtherPublicDhKey, MyPrivateKey, Params),
+ master_from_premaster_secret(PremasterSecret, State).
+
dh_master_secret(Prime, Base, PublicDhKey, undefined, State) ->
- PMpint = mpint_binary(Prime),
- GMpint = mpint_binary(Base),
- Keys = {_, PrivateDhKey} =
- crypto:dh_generate_key([PMpint,GMpint]),
- dh_master_secret(PMpint, GMpint, PublicDhKey, PrivateDhKey, State#state{diffie_hellman_keys = Keys});
+ Keys = {_, PrivateDhKey} = crypto:generate_key(dh, [Prime, Base]),
+ dh_master_secret(Prime, Base, PublicDhKey, PrivateDhKey, State#state{diffie_hellman_keys = Keys});
+
+dh_master_secret(Prime, Base, PublicDhKey, PrivateDhKey, State) ->
+ PremasterSecret =
+ crypto:compute_key(dh, PublicDhKey, PrivateDhKey, [Prime, Base]),
+ master_from_premaster_secret(PremasterSecret, State).
-dh_master_secret(PMpint, GMpint, PublicDhKey, PrivateDhKey, State) ->
+ec_dh_master_secret(ECDHKeys, ECPoint, State) ->
PremasterSecret =
- crypto:dh_compute_key(mpint_binary(PublicDhKey), PrivateDhKey,
- [PMpint, GMpint]),
+ public_key:compute_key(ECPoint, ECDHKeys),
master_from_premaster_secret(PremasterSecret, State).
handle_psk_identity(_PSKIdentity, LookupFun)
@@ -2033,20 +2125,18 @@ server_psk_master_secret(ClientPSKIdentity,
end.
dhe_psk_master_secret(PSKIdentity, Prime, Base, PublicDhKey, undefined, State) ->
- PMpint = mpint_binary(Prime),
- GMpint = mpint_binary(Base),
Keys = {_, PrivateDhKey} =
- crypto:dh_generate_key([PMpint,GMpint]),
- dhe_psk_master_secret(PSKIdentity, PMpint, GMpint, PublicDhKey, PrivateDhKey,
+ crypto:generate_key(dh, [Prime, Base]),
+ dhe_psk_master_secret(PSKIdentity, Prime, Base, PublicDhKey, PrivateDhKey,
State#state{diffie_hellman_keys = Keys});
-dhe_psk_master_secret(PSKIdentity, PMpint, GMpint, PublicDhKey, PrivateDhKey,
+dhe_psk_master_secret(PSKIdentity, Prime, Base, PublicDhKey, PrivateDhKey,
#state{ssl_options = SslOpts} = State) ->
case handle_psk_identity(PSKIdentity, SslOpts#ssl_options.user_lookup_fun) of
{ok, PSK} when is_binary(PSK) ->
DHSecret =
- crypto:dh_compute_key(mpint_binary(PublicDhKey), PrivateDhKey,
- [PMpint, GMpint]),
+ crypto:compute_key(dh, PublicDhKey, PrivateDhKey,
+ [Prime, Base]),
DHLen = erlang:byte_size(DHSecret),
Len = erlang:byte_size(PSK),
PremasterSecret = <<?UINT16(DHLen), DHSecret/binary, ?UINT16(Len), PSK/binary>>,
@@ -2075,7 +2165,7 @@ generate_srp_server_keys(_SrpParams, 10) ->
generate_srp_server_keys(SrpParams =
#srp_user{generator = Generator, prime = Prime,
verifier = Verifier}, N) ->
- case crypto:srp_generate_key(Verifier, Generator, Prime, '6a') of
+ case crypto:generate_key(srp, {host, [Verifier, Generator, Prime, '6a']}) of
error ->
generate_srp_server_keys(SrpParams, N+1);
Keys ->
@@ -2086,7 +2176,7 @@ generate_srp_client_keys(_Generator, _Prime, 10) ->
?ALERT_REC(?FATAL, ?ILLEGAL_PARAMETER);
generate_srp_client_keys(Generator, Prime, N) ->
- case crypto:srp_generate_key(Generator, Prime, '6a') of
+ case crypto:generate_key(srp, {user, [Generator, Prime, '6a']}) of
error ->
generate_srp_client_keys(Generator, Prime, N+1);
Keys ->
@@ -2098,7 +2188,7 @@ handle_srp_identity(Username, {Fun, UserState}) ->
{ok, {SRPParams, Salt, DerivedKey}}
when is_atom(SRPParams), is_binary(Salt), is_binary(DerivedKey) ->
{Generator, Prime} = ssl_srp_primes:get_srp_params(SRPParams),
- Verifier = crypto:mod_exp_prime(Generator, DerivedKey, Prime),
+ Verifier = crypto:mod_pow(Generator, DerivedKey, Prime),
#srp_user{generator = Generator, prime = Prime,
salt = Salt, verifier = Verifier};
#alert{} = Alert ->
@@ -2107,8 +2197,8 @@ handle_srp_identity(Username, {Fun, UserState}) ->
throw(?ALERT_REC(?FATAL, ?ILLEGAL_PARAMETER))
end.
-server_srp_master_secret(Verifier, Prime, ClientPub, State = #state{srp_keys = {ServerPub, ServerPriv}}) ->
- case crypto:srp_compute_key(Verifier, Prime, ClientPub, ServerPub, ServerPriv, '6a') of
+server_srp_master_secret(Verifier, Prime, ClientPub, State = #state{srp_keys = ServerKeys}) ->
+ case crypto:compute_key(srp, ClientPub, ServerKeys, {host, [Verifier, Prime, '6a']}) of
error ->
?ALERT_REC(?FATAL, ?ILLEGAL_PARAMETER);
PremasterSecret ->
@@ -2121,14 +2211,13 @@ client_srp_master_secret(Generator, Prime, Salt, ServerPub, undefined, State) ->
Keys = generate_srp_client_keys(Generator, Prime, 0),
client_srp_master_secret(Generator, Prime, Salt, ServerPub, Keys, State#state{srp_keys = Keys});
-client_srp_master_secret(Generator, Prime, Salt, ServerPub, {ClientPub, ClientPriv},
- #state{ssl_options = SslOpts} = State) ->
+client_srp_master_secret(Generator, Prime, Salt, ServerPub, ClientKeys,
+ #state{ssl_options = SslOpts} = State) ->
case ssl_srp_primes:check_srp_params(Generator, Prime) of
ok ->
{Username, Password} = SslOpts#ssl_options.srp_identity,
DerivedKey = crypto:sha([Salt, crypto:sha([Username, <<$:>>, Password])]),
-
- case crypto:srp_compute_key(DerivedKey, Prime, Generator, ClientPub, ClientPriv, ServerPub, '6a') of
+ case crypto:compute_key(srp, ServerPub, ClientKeys, {user, [DerivedKey, Prime, Generator, '6a']}) of
error ->
?ALERT_REC(?FATAL, ?ILLEGAL_PARAMETER);
PremasterSecret ->
@@ -2798,11 +2887,6 @@ make_premaster_secret({MajVer, MinVer}, rsa) ->
make_premaster_secret(_, _) ->
undefined.
-mpint_binary(Binary) ->
- Size = erlang:byte_size(Binary),
- <<?UINT32(Size), Binary/binary>>.
-
-
ack_connection(#state{renegotiation = {true, Initiater}} = State)
when Initiater == internal;
Initiater == peer ->
@@ -2938,21 +3022,29 @@ default_hashsign(_Version = {Major, Minor}, KeyExchange)
(KeyExchange == rsa orelse
KeyExchange == dhe_rsa orelse
KeyExchange == dh_rsa orelse
+ KeyExchange == ecdhe_rsa orelse
KeyExchange == srp_rsa) ->
{sha, rsa};
default_hashsign(_Version, KeyExchange)
when KeyExchange == rsa;
KeyExchange == dhe_rsa;
KeyExchange == dh_rsa;
+ KeyExchange == ecdhe_rsa;
KeyExchange == srp_rsa ->
{md5sha, rsa};
default_hashsign(_Version, KeyExchange)
+ when KeyExchange == ecdhe_ecdsa;
+ KeyExchange == ecdh_ecdsa;
+ KeyExchange == ecdh_rsa ->
+ {sha, ecdsa};
+default_hashsign(_Version, KeyExchange)
when KeyExchange == dhe_dss;
KeyExchange == dh_dss;
KeyExchange == srp_dss ->
{sha, dsa};
default_hashsign(_Version, KeyExchange)
when KeyExchange == dh_anon;
+ KeyExchange == ecdh_anon;
KeyExchange == psk;
KeyExchange == dhe_psk;
KeyExchange == rsa_psk;
@@ -2987,3 +3079,8 @@ handle_close_alert(Data, StateName, State0) ->
_ ->
ok
end.
+
+select_curve(#state{client_ecc = {[Curve|_], _}}) ->
+ {namedCurve, Curve};
+select_curve(_) ->
+ {namedCurve, ?secp256k1}.
diff --git a/lib/ssl/src/ssl_handshake.erl b/lib/ssl/src/ssl_handshake.erl
index 83c0092de2..e358cbe9bb 100644
--- a/lib/ssl/src/ssl_handshake.erl
+++ b/lib/ssl/src/ssl_handshake.erl
@@ -31,7 +31,7 @@
-include("ssl_srp.hrl").
-include_lib("public_key/include/public_key.hrl").
--export([master_secret/4, client_hello/8, server_hello/5, hello/4,
+-export([master_secret/4, client_hello/8, server_hello/7, hello/4,
hello_request/0, certify/7, certificate/4,
client_certificate_verify/6, certificate_verify/6, verify_signature/5,
certificate_request/3, key_exchange/3, server_key_exchange_hash/2,
@@ -47,6 +47,8 @@
#client_key_exchange{} | #finished{} | #certificate_verify{} |
#hello_request{} | #next_protocol{}.
+-define(NAMED_CURVE_TYPE, 3).
+
%%====================================================================
%% Internal application API
%%====================================================================
@@ -67,6 +69,7 @@ client_hello(Host, Port, ConnectionStates,
SecParams = Pending#connection_state.security_parameters,
Ciphers = available_suites(UserSuites, Version),
SRP = srp_user(SslOpts),
+ {EcPointFormats, EllipticCurves} = default_ecc_extensions(Version),
Id = ssl_session:client_id({Host, Port, SslOpts}, Cache, CacheCb, OwnCert),
@@ -80,6 +83,8 @@ client_hello(Host, Port, ConnectionStates,
renegotiation_info(client, ConnectionStates, Renegotiation),
srp = SRP,
hash_signs = default_hash_signs(),
+ ec_point_formats = EcPointFormats,
+ elliptic_curves = EllipticCurves,
next_protocol_negotiation =
encode_client_protocol_negotiation(SslOpts#ssl_options.next_protocol_selector, Renegotiation)
}.
@@ -96,11 +101,14 @@ encode_protocols_advertised_on_server(Protocols) ->
%%--------------------------------------------------------------------
-spec server_hello(session_id(), tls_version(), #connection_states{},
- boolean(), [binary()] | undefined) -> #server_hello{}.
+ boolean(), [binary()] | undefined,
+ #ec_point_formats{} | undefined,
+ #elliptic_curves{} | undefined) -> #server_hello{}.
%%
%% Description: Creates a server hello message.
%%--------------------------------------------------------------------
-server_hello(SessionId, Version, ConnectionStates, Renegotiation, ProtocolsAdvertisedOnServer) ->
+server_hello(SessionId, Version, ConnectionStates, Renegotiation,
+ ProtocolsAdvertisedOnServer, EcPointFormats, EllipticCurves) ->
Pending = ssl_record:pending_connection_state(ConnectionStates, read),
SecParams = Pending#connection_state.security_parameters,
#server_hello{server_version = Version,
@@ -111,6 +119,8 @@ server_hello(SessionId, Version, ConnectionStates, Renegotiation, ProtocolsAdver
session_id = SessionId,
renegotiation_info =
renegotiation_info(server, ConnectionStates, Renegotiation),
+ ec_point_formats = EcPointFormats,
+ elliptic_curves = EllipticCurves,
next_protocol_negotiation = encode_protocols_advertised_on_server(ProtocolsAdvertisedOnServer)
}.
@@ -129,7 +139,8 @@ hello_request() ->
atom(), #connection_states{}, binary()},
boolean()) ->
{tls_version(), session_id(), #connection_states{}, binary() | undefined}|
- {tls_version(), {resumed | new, #session{}}, #connection_states{}, list(binary()) | undefined} |
+ {tls_version(), {resumed | new, #session{}}, #connection_states{}, [binary()] | undefined,
+ [oid()] | undefined, [oid()] | undefined} |
#alert{}.
%%
%% Description: Handles a recieved hello message
@@ -163,44 +174,27 @@ hello(#server_hello{cipher_suite = CipherSuite, server_version = Version,
?ALERT_REC(?FATAL, ?PROTOCOL_VERSION)
end;
-hello(#client_hello{client_version = ClientVersion, random = Random,
- cipher_suites = CipherSuites,
- renegotiation_info = Info,
- srp = SRP} = Hello,
- #ssl_options{versions = Versions,
- secure_renegotiate = SecureRenegotation} = SslOpts,
+hello(#client_hello{client_version = ClientVersion} = Hello,
+ #ssl_options{versions = Versions} = SslOpts,
{Port, Session0, Cache, CacheCb, ConnectionStates0, Cert}, Renegotiation) ->
-%% TODO: select hash and signature algorithm
+ %% TODO: select hash and signature algorithm
Version = select_version(ClientVersion, Versions),
case ssl_record:is_acceptable_version(Version, Versions) of
true ->
- {Type, #session{cipher_suite = CipherSuite,
- compression_method = Compression} = Session1}
+ %% TODO: need to take supported Curves into Account when selecting the CipherSuite....
+ %% if whe have an ECDSA cert with an unsupported curve, we need to drop ECDSA ciphers
+ {Type, #session{cipher_suite = CipherSuite} = Session1}
= select_session(Hello, Port, Session0, Version,
SslOpts, Cache, CacheCb, Cert),
case CipherSuite of
no_suite ->
?ALERT_REC(?FATAL, ?INSUFFICIENT_SECURITY);
_ ->
- Session = handle_srp_info(SRP, Session1),
- case handle_renegotiation_info(server, Info, ConnectionStates0,
- Renegotiation, SecureRenegotation,
- CipherSuites) of
- {ok, ConnectionStates1} ->
- ConnectionStates =
- hello_pending_connection_states(server,
- Version,
- CipherSuite,
- Random,
- Compression,
- ConnectionStates1),
- case handle_next_protocol_on_server(Hello, Renegotiation, SslOpts) of
- #alert{} = Alert ->
- Alert;
- ProtocolsToAdvertise ->
- {Version, {Type, Session}, ConnectionStates, ProtocolsToAdvertise}
- end;
- #alert{} = Alert ->
+ try handle_hello_extensions(Hello, Version, SslOpts, Session1, ConnectionStates0, Renegotiation) of
+ {Session, ConnectionStates, ProtocolsToAdvertise, ECPointFormats, EllipticCurves} ->
+ {Version, {Type, Session}, ConnectionStates,
+ ProtocolsToAdvertise, ECPointFormats, EllipticCurves}
+ catch throw:Alert ->
Alert
end
end;
@@ -350,9 +344,10 @@ verify_signature(_Version, Hash, _HashAlgo, Signature, {?rsaEncryption, PubKey,
_ -> false
end;
verify_signature(_Version, Hash, {HashAlgo, dsa}, Signature, {?'id-dsa', PublicKey, PublicKeyParams}) ->
+ public_key:verify({digest, Hash}, HashAlgo, Signature, {PublicKey, PublicKeyParams});
+verify_signature(_Version, Hash, {HashAlgo, ecdsa}, Signature, {?'id-ecPublicKey', PublicKey, PublicKeyParams}) ->
public_key:verify({digest, Hash}, HashAlgo, Signature, {PublicKey, PublicKeyParams}).
-
%%--------------------------------------------------------------------
-spec certificate_request(#connection_states{}, db_handle(), certdb_ref()) ->
#certificate_request{}.
@@ -378,6 +373,7 @@ certificate_request(ConnectionStates, CertDbHandle, CertDbRef) ->
{dh, binary()} |
{dh, {binary(), binary()}, #'DHParameter'{}, {HashAlgo::atom(), SignAlgo::atom()},
binary(), binary(), private_key()} |
+ {ecdh, #'ECPrivateKey'{}} |
{psk, binary()} |
{dhe_psk, binary(), binary()} |
{srp, {binary(), binary()}, #srp_user{}, {HashAlgo::atom(), SignAlgo::atom()},
@@ -391,19 +387,25 @@ key_exchange(client, _Version, {premaster_secret, Secret, {_, PublicKey, _}}) ->
encrypted_premaster_secret(Secret, PublicKey),
#client_key_exchange{exchange_keys = EncPremasterSecret};
-key_exchange(client, _Version, {dh, <<?UINT32(Len), PublicKey:Len/binary>>}) ->
+key_exchange(client, _Version, {dh, PublicKey}) ->
#client_key_exchange{
exchange_keys = #client_diffie_hellman_public{
dh_public = PublicKey}
};
+key_exchange(client, _Version, {ecdh, #'ECPrivateKey'{publicKey = {0, ECPublicKey}}}) ->
+ #client_key_exchange{
+ exchange_keys = #client_ec_diffie_hellman_public{
+ dh_public = ECPublicKey}
+ };
+
key_exchange(client, _Version, {psk, Identity}) ->
#client_key_exchange{
exchange_keys = #client_psk_identity{
identity = Identity}
};
-key_exchange(client, _Version, {dhe_psk, Identity, <<?UINT32(Len), PublicKey:Len/binary>>}) ->
+key_exchange(client, _Version, {dhe_psk, Identity, PublicKey}) ->
#client_key_exchange{
exchange_keys = #client_dhe_psk_identity{
identity = Identity,
@@ -415,7 +417,7 @@ key_exchange(client, _Version, {psk_premaster_secret, PskIdentity, Secret, {_, P
encrypted_premaster_secret(Secret, PublicKey),
#client_key_exchange{
exchange_keys = #client_rsa_psk_identity{
- identity = PskIdentity,
+ identity = PskIdentity,
exchange_keys = EncPremasterSecret}};
key_exchange(client, _Version, {srp, PublicKey}) ->
@@ -424,31 +426,34 @@ key_exchange(client, _Version, {srp, PublicKey}) ->
srp_a = PublicKey}
};
-key_exchange(server, Version, {dh, {<<?UINT32(Len), PublicKey:Len/binary>>, _},
- #'DHParameter'{prime = P, base = G},
- HashSign, ClientRandom, ServerRandom, PrivateKey}) ->
- <<?UINT32(_), PBin/binary>> = crypto:mpint(P),
- <<?UINT32(_), GBin/binary>> = crypto:mpint(G),
- ServerDHParams = #server_dh_params{dh_p = PBin,
- dh_g = GBin, dh_y = PublicKey},
+key_exchange(server, Version, {dh, {PublicKey, _},
+ #'DHParameter'{prime = P, base = G},
+ HashSign, ClientRandom, ServerRandom, PrivateKey}) ->
+ ServerDHParams = #server_dh_params{dh_p = int_to_bin(P),
+ dh_g = int_to_bin(G), dh_y = PublicKey},
enc_server_key_exchange(Version, ServerDHParams, HashSign,
ClientRandom, ServerRandom, PrivateKey);
+key_exchange(server, Version, {ecdh, #'ECPrivateKey'{publicKey = {0, ECPublicKey},
+ parameters = ECCurve}, HashSign, ClientRandom, ServerRandom,
+ PrivateKey}) ->
+ ServerECParams = #server_ecdh_params{curve = ECCurve, public = ECPublicKey},
+ enc_server_key_exchange(Version, ServerECParams, HashSign,
+ ClientRandom, ServerRandom, PrivateKey);
+
key_exchange(server, Version, {psk, PskIdentityHint,
HashSign, ClientRandom, ServerRandom, PrivateKey}) ->
ServerPSKParams = #server_psk_params{hint = PskIdentityHint},
enc_server_key_exchange(Version, ServerPSKParams, HashSign,
ClientRandom, ServerRandom, PrivateKey);
-key_exchange(server, Version, {dhe_psk, PskIdentityHint, {<<?UINT32(Len), PublicKey:Len/binary>>, _},
+key_exchange(server, Version, {dhe_psk, PskIdentityHint, {PublicKey, _},
#'DHParameter'{prime = P, base = G},
HashSign, ClientRandom, ServerRandom, PrivateKey}) ->
- <<?UINT32(_), PBin/binary>> = crypto:mpint(P),
- <<?UINT32(_), GBin/binary>> = crypto:mpint(G),
ServerEDHPSKParams = #server_dhe_psk_params{
hint = PskIdentityHint,
- dh_params = #server_dh_params{dh_p = PBin,
- dh_g = GBin, dh_y = PublicKey}
+ dh_params = #server_dh_params{dh_p = int_to_bin(P),
+ dh_g = int_to_bin(G), dh_y = PublicKey}
},
enc_server_key_exchange(Version, ServerEDHPSKParams,
HashSign, ClientRandom, ServerRandom, PrivateKey);
@@ -591,6 +596,7 @@ get_tls_handshake(Version, Data, Buffer) ->
-spec decode_client_key(binary(), key_algo(), tls_version()) ->
#encrypted_premaster_secret{}
| #client_diffie_hellman_public{}
+ | #client_ec_diffie_hellman_public{}
| #client_psk_identity{}
| #client_dhe_psk_identity{}
| #client_rsa_psk_identity{}
@@ -661,8 +667,8 @@ decrypt_premaster_secret(Secret, RSAPrivateKey) ->
%% Description: Calculate server key exchange hash
%%--------------------------------------------------------------------
server_key_exchange_hash(md5sha, Value) ->
- MD5 = crypto:md5(Value),
- SHA = crypto:sha(Value),
+ MD5 = crypto:hash(md5, Value),
+ SHA = crypto:hash(sha, Value),
<<MD5/binary, SHA/binary>>;
server_key_exchange_hash(Hash, Value) ->
@@ -833,10 +839,35 @@ select_next_protocol(Protocols, NextProtocolSelector) ->
Protocol
end.
-handle_srp_info(undefined, Session) ->
- Session;
-handle_srp_info(#srp{username = Username}, Session) ->
- Session#session{srp_username = Username}.
+default_ecc_extensions(Version) ->
+ case proplists:get_bool(ec, crypto:algorithms()) of
+ true ->
+ EcPointFormats = #ec_point_formats{ec_point_format_list = [?ECPOINT_UNCOMPRESSED]},
+ EllipticCurves = #elliptic_curves{elliptic_curve_list = ssl_tls1:ecc_curves(Version)},
+ {EcPointFormats, EllipticCurves};
+ _ ->
+ {undefined, undefined}
+ end.
+
+handle_ecc_extensions(Version, EcPointFormats0, EllipticCurves0) ->
+ case proplists:get_bool(ec, crypto:algorithms()) of
+ true ->
+ EcPointFormats1 = handle_ecc_point_fmt_extension(EcPointFormats0),
+ EllipticCurves1 = handle_ecc_curves_extension(Version, EllipticCurves0),
+ {EcPointFormats1, EllipticCurves1};
+ _ ->
+ {undefined, undefined}
+ end.
+
+handle_ecc_point_fmt_extension(undefined) ->
+ undefined;
+handle_ecc_point_fmt_extension(_) ->
+ #ec_point_formats{ec_point_format_list = [?ECPOINT_UNCOMPRESSED]}.
+
+handle_ecc_curves_extension(Version, undefined) ->
+ undefined;
+handle_ecc_curves_extension(Version, _) ->
+ #elliptic_curves{elliptic_curve_list = ssl_tls1:ecc_curves(Version)}.
handle_renegotiation_info(_, #renegotiation_info{renegotiated_connection = ?byte(0)},
ConnectionStates, false, _, _) ->
@@ -1022,6 +1053,8 @@ dec_hs(_Version, ?CLIENT_HELLO, <<?BYTE(Major), ?BYTE(Minor), Random:32/binary,
RenegotiationInfo = proplists:get_value(renegotiation_info, DecodedExtensions, undefined),
SRP = proplists:get_value(srp, DecodedExtensions, undefined),
HashSigns = proplists:get_value(hash_signs, DecodedExtensions, undefined),
+ EllipticCurves = proplists:get_value(elliptic_curves, DecodedExtensions,
+ undefined),
NextProtocolNegotiation = proplists:get_value(next_protocol_negotiation, DecodedExtensions, undefined),
#client_hello{
@@ -1033,6 +1066,7 @@ dec_hs(_Version, ?CLIENT_HELLO, <<?BYTE(Major), ?BYTE(Minor), Random:32/binary,
renegotiation_info = RenegotiationInfo,
srp = SRP,
hash_signs = HashSigns,
+ elliptic_curves = EllipticCurves,
next_protocol_negotiation = NextProtocolNegotiation
};
@@ -1046,7 +1080,8 @@ dec_hs(_Version, ?SERVER_HELLO, <<?BYTE(Major), ?BYTE(Minor), Random:32/binary,
cipher_suite = Cipher_suite,
compression_method = Comp_method,
renegotiation_info = undefined,
- hash_signs = undefined};
+ hash_signs = undefined,
+ elliptic_curves = undefined};
dec_hs(_Version, ?SERVER_HELLO, <<?BYTE(Major), ?BYTE(Minor), Random:32/binary,
?BYTE(SID_length), Session_ID:SID_length/binary,
@@ -1058,6 +1093,8 @@ dec_hs(_Version, ?SERVER_HELLO, <<?BYTE(Major), ?BYTE(Minor), Random:32/binary,
undefined),
HashSigns = proplists:get_value(hash_signs, HelloExtensions,
undefined),
+ EllipticCurves = proplists:get_value(elliptic_curves, HelloExtensions,
+ undefined),
NextProtocolNegotiation = proplists:get_value(next_protocol_negotiation, HelloExtensions, undefined),
#server_hello{
@@ -1068,6 +1105,7 @@ dec_hs(_Version, ?SERVER_HELLO, <<?BYTE(Major), ?BYTE(Minor), Random:32/binary,
compression_method = Comp_method,
renegotiation_info = RenegotiationInfo,
hash_signs = HashSigns,
+ elliptic_curves = EllipticCurves,
next_protocol_negotiation = NextProtocolNegotiation};
dec_hs(_Version, ?CERTIFICATE, <<?UINT24(ACLen), ASN1Certs:ACLen/binary>>) ->
#certificate{asn1_certificates = certs_to_list(ASN1Certs)};
@@ -1111,6 +1149,11 @@ dec_client_key(<<>>, ?KEY_EXCHANGE_DIFFIE_HELLMAN, _) ->
dec_client_key(<<?UINT16(DH_YLen), DH_Y:DH_YLen/binary>>,
?KEY_EXCHANGE_DIFFIE_HELLMAN, _) ->
#client_diffie_hellman_public{dh_public = DH_Y};
+dec_client_key(<<>>, ?KEY_EXCHANGE_EC_DIFFIE_HELLMAN, _) ->
+ throw(?ALERT_REC(?FATAL, ?UNSUPPORTED_CERTIFICATE));
+dec_client_key(<<?BYTE(DH_YLen), DH_Y:DH_YLen/binary>>,
+ ?KEY_EXCHANGE_EC_DIFFIE_HELLMAN, _) ->
+ #client_ec_diffie_hellman_public{dh_public = DH_Y};
dec_client_key(<<?UINT16(Len), Id:Len/binary>>,
?KEY_EXCHANGE_PSK, _) ->
#client_psk_identity{identity = Id};
@@ -1161,6 +1204,19 @@ dec_server_key(<<?UINT16(PLen), P:PLen/binary,
params_bin = BinMsg,
hashsign = HashSign,
signature = Signature};
+%% ECParameters with named_curve
+%% TODO: explicit curve
+dec_server_key(<<?BYTE(?NAMED_CURVE), ?UINT16(CurveID),
+ ?BYTE(PointLen), ECPoint:PointLen/binary,
+ _/binary>> = KeyStruct,
+ ?KEY_EXCHANGE_EC_DIFFIE_HELLMAN, Version) ->
+ Params = #server_ecdh_params{curve = {namedCurve, ssl_tls1:enum_to_oid(CurveID)},
+ public = ECPoint},
+ {BinMsg, HashSign, Signature} = dec_ske_params(PointLen + 4, KeyStruct, Version),
+ #server_key_params{params = Params,
+ params_bin = BinMsg,
+ hashsign = HashSign,
+ signature = Signature};
dec_server_key(<<?UINT16(Len), PskIdentityHint:Len/binary>> = KeyStruct,
KeyExchange, Version)
when KeyExchange == ?KEY_EXCHANGE_PSK; KeyExchange == ?KEY_EXCHANGE_RSA_PSK ->
@@ -1237,6 +1293,22 @@ dec_hello_extensions(<<?UINT16(?SIGNATURE_ALGORITHMS_EXT), ?UINT16(Len),
dec_hello_extensions(Rest, [{hash_signs,
#hash_sign_algos{hash_sign_algos = HashSignAlgos}} | Acc]);
+dec_hello_extensions(<<?UINT16(?ELLIPTIC_CURVES_EXT), ?UINT16(Len),
+ ExtData:Len/binary, Rest/binary>>, Acc) ->
+ EllipticCurveListLen = Len - 2,
+ <<?UINT16(EllipticCurveListLen), EllipticCurveList/binary>> = ExtData,
+ EllipticCurves = [ssl_tls1:enum_to_oid(X) || <<X:16>> <= EllipticCurveList],
+ dec_hello_extensions(Rest, [{elliptic_curves,
+ #elliptic_curves{elliptic_curve_list = EllipticCurves}} | Acc]);
+
+dec_hello_extensions(<<?UINT16(?EC_POINT_FORMATS_EXT), ?UINT16(Len),
+ ExtData:Len/binary, Rest/binary>>, Acc) ->
+ ECPointFormatListLen = Len - 1,
+ <<?BYTE(ECPointFormatListLen), ECPointFormatList/binary>> = ExtData,
+ ECPointFormats = binary_to_list(ECPointFormatList),
+ dec_hello_extensions(Rest, [{ec_point_formats,
+ #ec_point_formats{ec_point_format_list = ECPointFormats}} | Acc]);
+
%% Ignore data following the ClientHello (i.e.,
%% extensions) if not understood.
@@ -1287,13 +1359,17 @@ enc_hs(#client_hello{client_version = {Major, Minor},
renegotiation_info = RenegotiationInfo,
srp = SRP,
hash_signs = HashSigns,
+ ec_point_formats = EcPointFormats,
+ elliptic_curves = EllipticCurves,
next_protocol_negotiation = NextProtocolNegotiation}, _Version) ->
SIDLength = byte_size(SessionID),
BinCompMethods = list_to_binary(CompMethods),
CmLength = byte_size(BinCompMethods),
BinCipherSuites = list_to_binary(CipherSuites),
CsLength = byte_size(BinCipherSuites),
- Extensions0 = hello_extensions(RenegotiationInfo, SRP, NextProtocolNegotiation),
+ Extensions0 = hello_extensions(RenegotiationInfo, SRP, NextProtocolNegotiation)
+ ++ ec_hello_extensions(lists:map(fun ssl_cipher:suite_definition/1, CipherSuites), EcPointFormats)
+ ++ ec_hello_extensions(lists:map(fun ssl_cipher:suite_definition/1, CipherSuites), EllipticCurves),
Extensions1 = if
Major == 3, Minor >=3 -> Extensions0 ++ hello_extensions(HashSigns);
true -> Extensions0
@@ -1308,16 +1384,21 @@ enc_hs(#client_hello{client_version = {Major, Minor},
enc_hs(#server_hello{server_version = {Major, Minor},
random = Random,
session_id = Session_ID,
- cipher_suite = Cipher_suite,
+ cipher_suite = CipherSuite,
compression_method = Comp_method,
renegotiation_info = RenegotiationInfo,
+ ec_point_formats = EcPointFormats,
+ elliptic_curves = EllipticCurves,
next_protocol_negotiation = NextProtocolNegotiation}, _Version) ->
SID_length = byte_size(Session_ID),
- Extensions = hello_extensions(RenegotiationInfo, NextProtocolNegotiation),
+ CipherSuites = [ssl_cipher:suite_definition(CipherSuite)],
+ Extensions = hello_extensions(RenegotiationInfo, NextProtocolNegotiation)
+ ++ ec_hello_extensions(CipherSuites, EcPointFormats)
+ ++ ec_hello_extensions(CipherSuites, EllipticCurves),
ExtensionsBin = enc_hello_extensions(Extensions),
{?SERVER_HELLO, <<?BYTE(Major), ?BYTE(Minor), Random:32/binary,
?BYTE(SID_length), Session_ID/binary,
- Cipher_suite/binary, ?BYTE(Comp_method), ExtensionsBin/binary>>};
+ CipherSuite/binary, ?BYTE(Comp_method), ExtensionsBin/binary>>};
enc_hs(#certificate{asn1_certificates = ASN1CertList}, _Version) ->
ASN1Certs = certs_from_list(ASN1CertList),
ACLen = erlang:iolist_size(ASN1Certs),
@@ -1370,6 +1451,9 @@ enc_cke(#encrypted_premaster_secret{premaster_secret = PKEPMS}, _) ->
enc_cke(#client_diffie_hellman_public{dh_public = DHPublic}, _) ->
Len = byte_size(DHPublic),
<<?UINT16(Len), DHPublic/binary>>;
+enc_cke(#client_ec_diffie_hellman_public{dh_public = DHPublic}, _) ->
+ Len = byte_size(DHPublic),
+ <<?BYTE(Len), DHPublic/binary>>;
enc_cke(#client_psk_identity{identity = undefined}, _) ->
Id = <<"psk_identity">>,
Len = byte_size(Id),
@@ -1398,6 +1482,11 @@ enc_server_key(#server_dh_params{dh_p = P, dh_g = G, dh_y = Y}) ->
GLen = byte_size(G),
YLen = byte_size(Y),
<<?UINT16(PLen), P/binary, ?UINT16(GLen), G/binary, ?UINT16(YLen), Y/binary>>;
+enc_server_key(#server_ecdh_params{curve = {namedCurve, ECCurve}, public = ECPubKey}) ->
+ %%TODO: support arbitrary keys
+ KLen = size(ECPubKey),
+ <<?BYTE(?NAMED_CURVE_TYPE), ?UINT16((ssl_tls1:oid_to_enum(ECCurve))),
+ ?BYTE(KLen), ECPubKey/binary>>;
enc_server_key(#server_psk_params{hint = PskIdentityHint}) ->
Len = byte_size(PskIdentityHint),
<<?UINT16(Len), PskIdentityHint/binary>>;
@@ -1431,11 +1520,46 @@ enc_sign(_HashSign, Sign, _Version) ->
SignLen = byte_size(Sign),
<<?UINT16(SignLen), Sign/binary>>.
+
+ec_hello_extensions(CipherSuites, #elliptic_curves{} = Info) ->
+ case advertises_ec_ciphers(CipherSuites) of
+ true ->
+ [Info];
+ false ->
+ []
+ end;
+ec_hello_extensions(CipherSuites, #ec_point_formats{} = Info) ->
+ case advertises_ec_ciphers(CipherSuites) of
+ true ->
+ [Info];
+ false ->
+ []
+ end;
+ec_hello_extensions(_, undefined) ->
+ [].
+
hello_extensions(RenegotiationInfo, NextProtocolNegotiation) ->
hello_extensions(RenegotiationInfo) ++ next_protocol_extension(NextProtocolNegotiation).
hello_extensions(RenegotiationInfo, SRP, NextProtocolNegotiation) ->
- hello_extensions(RenegotiationInfo) ++ hello_extensions(SRP) ++ next_protocol_extension(NextProtocolNegotiation).
+ hello_extensions(RenegotiationInfo)
+ ++ hello_extensions(SRP)
+ ++ next_protocol_extension(NextProtocolNegotiation).
+
+advertises_ec_ciphers([]) ->
+ false;
+advertises_ec_ciphers([{ecdh_ecdsa, _,_,_} | _]) ->
+ true;
+advertises_ec_ciphers([{ecdhe_ecdsa, _,_,_} | _]) ->
+ true;
+advertises_ec_ciphers([{ecdh_rsa, _,_,_} | _]) ->
+ true;
+advertises_ec_ciphers([{ecdhe_rsa, _,_,_} | _]) ->
+ true;
+advertises_ec_ciphers([{ecdh_anon, _,_,_} | _]) ->
+ true;
+advertises_ec_ciphers([_| Rest]) ->
+ advertises_ec_ciphers(Rest).
%% Renegotiation info
hello_extensions(#renegotiation_info{renegotiated_connection = undefined}) ->
@@ -1473,12 +1597,22 @@ enc_hello_extensions([#renegotiation_info{renegotiated_connection = Info} | Rest
InfoLen = byte_size(Info),
Len = InfoLen +1,
enc_hello_extensions(Rest, <<?UINT16(?RENEGOTIATION_EXT), ?UINT16(Len), ?BYTE(InfoLen), Info/binary, Acc/binary>>);
-
+enc_hello_extensions([#elliptic_curves{elliptic_curve_list = EllipticCurves} | Rest], Acc) ->
+ EllipticCurveList = << <<(ssl_tls1:oid_to_enum(X)):16>> || X <- EllipticCurves>>,
+ ListLen = byte_size(EllipticCurveList),
+ Len = ListLen + 2,
+ enc_hello_extensions(Rest, <<?UINT16(?ELLIPTIC_CURVES_EXT),
+ ?UINT16(Len), ?UINT16(ListLen), EllipticCurveList/binary, Acc/binary>>);
+enc_hello_extensions([#ec_point_formats{ec_point_format_list = ECPointFormats} | Rest], Acc) ->
+ ECPointFormatList = list_to_binary(ECPointFormats),
+ ListLen = byte_size(ECPointFormatList),
+ Len = ListLen + 1,
+ enc_hello_extensions(Rest, <<?UINT16(?EC_POINT_FORMATS_EXT),
+ ?UINT16(Len), ?BYTE(ListLen), ECPointFormatList/binary, Acc/binary>>);
enc_hello_extensions([#srp{username = UserName} | Rest], Acc) ->
SRPLen = byte_size(UserName),
Len = SRPLen + 2,
enc_hello_extensions(Rest, <<?UINT16(?SRP_EXT), ?UINT16(Len), ?BYTE(SRPLen), UserName/binary, Acc/binary>>);
-
enc_hello_extensions([#hash_sign_algos{hash_sign_algos = HashSignAlgos} | Rest], Acc) ->
SignAlgoList = << <<(ssl_cipher:hash_algorithm(Hash)):8, (ssl_cipher:sign_algorithm(Sign)):8>> ||
{Hash, Sign} <- HashSignAlgos >>,
@@ -1513,9 +1647,15 @@ from_2bytes(<<?UINT16(N), Rest/binary>>, Acc) ->
certificate_types({KeyExchange, _, _, _})
when KeyExchange == rsa;
KeyExchange == dhe_dss;
- KeyExchange == dhe_rsa ->
+ KeyExchange == dhe_rsa;
+ KeyExchange == ecdhe_rsa ->
<<?BYTE(?RSA_SIGN), ?BYTE(?DSS_SIGN)>>;
+certificate_types({KeyExchange, _, _, _})
+ when KeyExchange == dh_ecdsa;
+ KeyExchange == dhe_ecdsa ->
+ <<?BYTE(?ECDSA_SIGN)>>;
+
certificate_types(_) ->
<<?BYTE(?RSA_SIGN)>>.
@@ -1532,9 +1672,6 @@ certificate_authorities(CertDbHandle, CertDbRef) ->
Enc = fun(#'OTPCertificate'{tbsCertificate=TBSCert}) ->
OTPSubj = TBSCert#'OTPTBSCertificate'.subject,
DNEncodedBin = public_key:pkix_encode('Name', OTPSubj, otp),
- %%Subj = public_key:pkix_transform(OTPSubj, encode),
- %% {ok, DNEncoded} = 'OTP-PUB-KEY':encode('Name', Subj),
- %% DNEncodedBin = iolist_to_binary(DNEncoded),
DNEncodedLen = byte_size(DNEncodedBin),
<<?UINT16(DNEncodedLen), DNEncodedBin/binary>>
end,
@@ -1555,7 +1692,9 @@ digitally_signed(_Version, Hash, HashAlgo, #'DSAPrivateKey'{} = Key) ->
public_key:sign({digest, Hash}, HashAlgo, Key);
digitally_signed(_Version, Hash, _HashAlgo, #'RSAPrivateKey'{} = Key) ->
public_key:encrypt_private(Hash, Key,
- [{rsa_pad, rsa_pkcs1_padding}]).
+ [{rsa_pad, rsa_pkcs1_padding}]);
+digitally_signed(_Version, Hash, HashAlgo, Key) ->
+ public_key:sign({digest, Hash}, HashAlgo, Key).
calc_master_secret({3,0}, _PrfAlgo, PremasterSecret, ClientRandom, ServerRandom) ->
ssl_ssl3:master_secret(PremasterSecret, ClientRandom, ServerRandom);
@@ -1588,6 +1727,10 @@ key_exchange_alg(rsa) ->
key_exchange_alg(Alg) when Alg == dhe_rsa; Alg == dhe_dss;
Alg == dh_dss; Alg == dh_rsa; Alg == dh_anon ->
?KEY_EXCHANGE_DIFFIE_HELLMAN;
+key_exchange_alg(Alg) when Alg == ecdhe_rsa; Alg == ecdh_rsa;
+ Alg == ecdhe_ecdsa; Alg == ecdh_ecdsa;
+ Alg == ecdh_anon ->
+ ?KEY_EXCHANGE_EC_DIFFIE_HELLMAN;
key_exchange_alg(psk) ->
?KEY_EXCHANGE_PSK;
key_exchange_alg(dhe_psk) ->
@@ -1612,15 +1755,70 @@ apply_user_fun(Fun, OtpCert, ExtensionOrError, UserState0, SslState) ->
-define(TLSEXT_SIGALG_RSA(MD), {MD, rsa}).
-define(TLSEXT_SIGALG_DSA(MD), {MD, dsa}).
+-define(TLSEXT_SIGALG_ECDSA(MD), {MD, ecdsa}).
--define(TLSEXT_SIGALG(MD), ?TLSEXT_SIGALG_RSA(MD)).
+-define(TLSEXT_SIGALG(MD), ?TLSEXT_SIGALG_ECDSA(MD), ?TLSEXT_SIGALG_RSA(MD)).
default_hash_signs() ->
+ HashSigns = [?TLSEXT_SIGALG(sha512),
+ ?TLSEXT_SIGALG(sha384),
+ ?TLSEXT_SIGALG(sha256),
+ ?TLSEXT_SIGALG(sha224),
+ ?TLSEXT_SIGALG(sha),
+ ?TLSEXT_SIGALG_DSA(sha),
+ ?TLSEXT_SIGALG_RSA(md5)],
+ HasECC = proplists:get_bool(ec, crypto:algorithms()),
#hash_sign_algos{hash_sign_algos =
- [?TLSEXT_SIGALG(sha512),
- ?TLSEXT_SIGALG(sha384),
- ?TLSEXT_SIGALG(sha256),
- ?TLSEXT_SIGALG(sha224),
- ?TLSEXT_SIGALG(sha),
- ?TLSEXT_SIGALG_DSA(sha),
- ?TLSEXT_SIGALG_RSA(md5)]}.
+ lists:filter(fun({_, ecdsa}) -> HasECC;
+ (_) -> true end, HashSigns)}.
+
+handle_hello_extensions(#client_hello{random = Random,
+ cipher_suites = CipherSuites,
+ renegotiation_info = Info,
+ srp = SRP,
+ ec_point_formats = EcPointFormats0,
+ elliptic_curves = EllipticCurves0} = Hello, Version,
+ #ssl_options{secure_renegotiate = SecureRenegotation} = Opts,
+ Session0, ConnectionStates0, Renegotiation) ->
+ Session = handle_srp_extension(SRP, Session0),
+ ConnectionStates = handle_renegotiation_extension(Version, Info, Random, Session, ConnectionStates0,
+ Renegotiation, SecureRenegotation, CipherSuites),
+ ProtocolsToAdvertise = handle_next_protocol_extension(Hello, Renegotiation, Opts),
+ {EcPointFormats, EllipticCurves} = handle_ecc_extensions(Version, EcPointFormats0, EllipticCurves0),
+ %%TODO make extensions compund data structure
+ {Session, ConnectionStates, ProtocolsToAdvertise, EcPointFormats, EllipticCurves}.
+
+
+handle_renegotiation_extension(Version, Info, Random, #session{cipher_suite = CipherSuite,
+ compression_method = Compression},
+ ConnectionStates0, Renegotiation, SecureRenegotation, CipherSuites) ->
+ case handle_renegotiation_info(server, Info, ConnectionStates0,
+ Renegotiation, SecureRenegotation,
+ CipherSuites) of
+ {ok, ConnectionStates1} ->
+ hello_pending_connection_states(server,
+ Version,
+ CipherSuite,
+ Random,
+ Compression,
+ ConnectionStates1);
+ #alert{} = Alert ->
+ throw(Alert)
+ end.
+
+handle_next_protocol_extension(Hello, Renegotiation, SslOpts)->
+ case handle_next_protocol_on_server(Hello, Renegotiation, SslOpts) of
+ #alert{} = Alert ->
+ throw(Alert);
+ ProtocolsToAdvertise ->
+ ProtocolsToAdvertise
+ end.
+
+handle_srp_extension(undefined, Session) ->
+ Session;
+handle_srp_extension(#srp{username = Username}, Session) ->
+ Session#session{srp_username = Username}.
+
+int_to_bin(I) ->
+ L = (length(integer_to_list(I, 16)) + 1) div 2,
+ <<I:(L*8)>>.
diff --git a/lib/ssl/src/ssl_handshake.hrl b/lib/ssl/src/ssl_handshake.hrl
index 1fbb88f5f6..b2387a0ee7 100644
--- a/lib/ssl/src/ssl_handshake.hrl
+++ b/lib/ssl/src/ssl_handshake.hrl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2007-2012. All Rights Reserved.
+%% Copyright Ericsson AB 2007-2013. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -28,9 +28,9 @@
-include_lib("public_key/include/public_key.hrl").
--type algo_oid() :: ?'rsaEncryption' | ?'id-dsa'.
--type public_key_params() :: #'Dss-Parms'{} | term().
--type public_key_info() :: {algo_oid(), #'RSAPublicKey'{} | integer() , public_key_params()}.
+-type oid() :: tuple().
+-type public_key_params() :: #'Dss-Parms'{} | {namedCurve, oid()} | #'ECParameters'{} | term().
+-type public_key_info() :: {oid(), #'RSAPublicKey'{} | integer() | #'ECPoint'{}, public_key_params()}.
-type tls_handshake_history() :: {[binary()], [binary()]}.
-define(NO_PROTOCOL, <<>>).
@@ -102,6 +102,8 @@
renegotiation_info,
srp, % srp username to send
hash_signs, % supported combinations of hashes/signature algos
+ ec_point_formats, % supported ec point formats
+ elliptic_curves, % supported elliptic curver
next_protocol_negotiation = undefined % [binary()]
}).
@@ -113,6 +115,8 @@
compression_method, % compression_method
renegotiation_info,
hash_signs, % supported combinations of hashes/signature algos
+ ec_point_formats, % supported ec point formats
+ elliptic_curves, % supported elliptic curver
next_protocol_negotiation = undefined % [binary()]
}).
@@ -130,6 +134,7 @@
-define(KEY_EXCHANGE_RSA, 0).
-define(KEY_EXCHANGE_DIFFIE_HELLMAN, 1).
+-define(KEY_EXCHANGE_EC_DIFFIE_HELLMAN, 6).
-define(KEY_EXCHANGE_PSK, 2).
-define(KEY_EXCHANGE_DHE_PSK, 3).
-define(KEY_EXCHANGE_RSA_PSK, 4).
@@ -146,6 +151,11 @@
dh_y %% opaque DH_Ys<1..2^16-1>
}).
+-record(server_ecdh_params, {
+ curve,
+ public %% opaque encoded ECpoint
+ }).
+
-record(server_psk_params, {
hint
}).
@@ -195,6 +205,9 @@
-define(DSS_SIGN, 2).
-define(RSA_FIXED_DH, 3).
-define(DSS_FIXED_DH, 4).
+-define(ECDSA_SIGN, 64).
+-define(RSA_FIXED_ECDH, 65).
+-define(ECDSA_FIXED_ECDH, 66).
% opaque DistinguishedName<1..2^16-1>;
@@ -231,6 +244,10 @@
dh_public
}).
+-record(client_ec_diffie_hellman_public, {
+ dh_public
+ }).
+
-record(client_psk_identity, {
identity
}).
@@ -304,6 +321,33 @@
-record(next_protocol, {selected_protocol}).
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%% ECC Extensions RFC 4492 section 4 and 5
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+-define(ELLIPTIC_CURVES_EXT, 10).
+-define(EC_POINT_FORMATS_EXT, 11).
+
+-record(elliptic_curves, {
+ elliptic_curve_list
+ }).
+
+-record(ec_point_formats, {
+ ec_point_format_list
+ }).
+
+-define(ECPOINT_UNCOMPRESSED, 0).
+-define(ECPOINT_ANSIX962_COMPRESSED_PRIME, 1).
+-define(ECPOINT_ANSIX962_COMPRESSED_CHAR2, 2).
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%% ECC RFC 4492 Handshake Messages, Section 5
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+-define(EXPLICIT_PRIME, 1).
+-define(EXPLICIT_CHAR2, 2).
+-define(NAMED_CURVE, 3).
+
-endif. % -ifdef(ssl_handshake).
diff --git a/lib/ssl/src/ssl_internal.hrl b/lib/ssl/src/ssl_internal.hrl
index 96a1c8e1ce..14db4a6067 100644
--- a/lib/ssl/src/ssl_internal.hrl
+++ b/lib/ssl/src/ssl_internal.hrl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2007-2012. All Rights Reserved.
+%% Copyright Ericsson AB 2007-2013. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -37,9 +37,9 @@
-type tls_atom_version() :: sslv3 | tlsv1 | 'tlsv1.1' | 'tlsv1.2'.
-type certdb_ref() :: reference().
-type db_handle() :: term().
--type key_algo() :: null | rsa | dhe_rsa | dhe_dss | dh_anon.
+-type key_algo() :: null | rsa | dhe_rsa | dhe_dss | ecdhe_ecdsa| ecdh_ecdsa | ecdh_rsa| srp_rsa| srp_dss | psk | dhe_psk | rsa_psk | dh_anon | ecdh_anon | srp_anon.
-type der_cert() :: binary().
--type private_key() :: #'RSAPrivateKey'{} | #'DSAPrivateKey'{}.
+-type private_key() :: #'RSAPrivateKey'{} | #'DSAPrivateKey'{} | #'ECPrivateKey'{}.
-type issuer() :: tuple().
-type serialnumber() :: integer().
-type cert_key() :: {reference(), integer(), issuer()}.
diff --git a/lib/ssl/src/ssl_manager.erl b/lib/ssl/src/ssl_manager.erl
index aa9da65bb8..caea528a08 100644
--- a/lib/ssl/src/ssl_manager.erl
+++ b/lib/ssl/src/ssl_manager.erl
@@ -103,7 +103,7 @@ connection_init(Trustedcerts, Role) ->
%% Description: Cach a pem file and return its content.
%%--------------------------------------------------------------------
cache_pem_file(File, DbHandle) ->
- MD5 = crypto:md5(File),
+ MD5 = crypto:hash(md5, File),
case ssl_certificate_db:lookup_cached_pem(DbHandle, MD5) of
[{Content,_}] ->
{ok, Content};
@@ -468,7 +468,7 @@ new_id(Port, Tries, Cache, CacheCb) ->
clean_cert_db(Ref, CertDb, RefDb, PemCache, File) ->
case ssl_certificate_db:ref_count(Ref, RefDb, 0) of
0 ->
- MD5 = crypto:md5(File),
+ MD5 = crypto:hash(md5, File),
case ssl_certificate_db:lookup_cached_pem(PemCache, MD5) of
[{Content, Ref}] ->
ssl_certificate_db:insert(MD5, Content, PemCache);
diff --git a/lib/ssl/src/ssl_record.erl b/lib/ssl/src/ssl_record.erl
index 26aca56739..50b1b2cda9 100644
--- a/lib/ssl/src/ssl_record.erl
+++ b/lib/ssl/src/ssl_record.erl
@@ -712,12 +712,4 @@ mac_hash({3, N} = Version, MacAlg, MacSecret, SeqNo, Type, Length, Fragment)
Length, Fragment).
sufficient_tlsv1_2_crypto_support() ->
- Data = "Sampl",
- Data2 = "e #1",
- Key = <<0,1,2,3,16,17,18,19,32,33,34,35,48,49,50,51,4,5,6,7,20,21,22,23,36,37,38,39,
- 52,53,54,55,8,9,10,11,24,25,26,27,40,41,42,43,56,57,58,59>>,
- try
- crypto:sha256_mac(Key, lists:flatten([Data, Data2])),
- true
- catch _:_ -> false
- end.
+ proplists:get_bool(sha256, crypto:algorithms()).
diff --git a/lib/ssl/src/ssl_ssl3.erl b/lib/ssl/src/ssl_ssl3.erl
index a11c5b8c0c..013c27ebb5 100644
--- a/lib/ssl/src/ssl_ssl3.erl
+++ b/lib/ssl/src/ssl_ssl3.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2007-2012. All Rights Reserved.
+%% Copyright Ericsson AB 2007-2013. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -154,9 +154,9 @@ suites() ->
%%--------------------------------------------------------------------
hash(?MD5, Data) ->
- crypto:md5(Data);
+ crypto:hash(md5, Data);
hash(?SHA, Data) ->
- crypto:sha(Data).
+ crypto:hash(sha, Data).
%%pad_1(?NULL) ->
%% "";
@@ -198,6 +198,6 @@ gen(_Secret, _All, Wanted, Len, _C, _N, Acc) when Wanted =< Len ->
Block;
gen(Secret, All, Wanted, Len, C, N, Acc) ->
Prefix = lists:duplicate(N, C),
- SHA = crypto:sha([Prefix, All]),
- MD5 = crypto:md5([Secret, SHA]),
+ SHA = crypto:hash(sha, [Prefix, All]),
+ MD5 = crypto:hash(md5, [Secret, SHA]),
gen(Secret, All, Wanted, Len + 16, C+1, N+1, [MD5 | Acc]).
diff --git a/lib/ssl/src/ssl_tls1.erl b/lib/ssl/src/ssl_tls1.erl
index 41dc1bf0dc..f8fd9efd07 100644
--- a/lib/ssl/src/ssl_tls1.erl
+++ b/lib/ssl/src/ssl_tls1.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2007-2012. All Rights Reserved.
+%% Copyright Ericsson AB 2007-2013. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -29,7 +29,8 @@
-include("ssl_record.hrl").
-export([master_secret/4, finished/5, certificate_verify/3, mac_hash/7,
- setup_keys/8, suites/1, prf/5]).
+ setup_keys/8, suites/1, prf/5,
+ ecc_curves/1, oid_to_enum/1, enum_to_oid/1]).
%%====================================================================
%% Internal application API
@@ -57,8 +58,8 @@ finished(Role, Version, PrfAlgo, MasterSecret, Handshake)
%% verify_data
%% PRF(master_secret, finished_label, MD5(handshake_messages) +
%% SHA-1(handshake_messages)) [0..11];
- MD5 = crypto:md5(Handshake),
- SHA = crypto:sha(Handshake),
+ MD5 = crypto:hash(md5, Handshake),
+ SHA = crypto:hash(sha, Handshake),
prf(?MD5SHA, MasterSecret, finished_label(Role), [MD5, SHA], 12);
finished(Role, Version, PrfAlgo, MasterSecret, Handshake)
@@ -76,8 +77,8 @@ finished(Role, Version, PrfAlgo, MasterSecret, Handshake)
-spec certificate_verify(md5sha | sha, integer(), [binary()]) -> binary().
certificate_verify(md5sha, _Version, Handshake) ->
- MD5 = crypto:md5(Handshake),
- SHA = crypto:sha(Handshake),
+ MD5 = crypto:hash(md5, Handshake),
+ SHA = crypto:hash(sha, Handshake),
<<MD5/binary, SHA/binary>>;
certificate_verify(HashAlgo, _Version, Handshake) ->
@@ -184,27 +185,56 @@ mac_hash(Method, Mac_write_secret, Seq_num, Type, {Major, Minor},
suites(Minor) when Minor == 1; Minor == 2->
[
+ ?TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA,
+ ?TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA,
?TLS_DHE_RSA_WITH_AES_256_CBC_SHA,
?TLS_DHE_DSS_WITH_AES_256_CBC_SHA,
+ ?TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA,
+ ?TLS_ECDH_RSA_WITH_AES_256_CBC_SHA,
?TLS_RSA_WITH_AES_256_CBC_SHA,
+
+ ?TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA,
+ ?TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA,
?TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA,
?TLS_DHE_DSS_WITH_3DES_EDE_CBC_SHA,
+ ?TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA,
+ ?TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA,
?TLS_RSA_WITH_3DES_EDE_CBC_SHA,
+
+ ?TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA,
+ ?TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA,
?TLS_DHE_RSA_WITH_AES_128_CBC_SHA,
?TLS_DHE_DSS_WITH_AES_128_CBC_SHA,
+ ?TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA,
+ ?TLS_ECDH_RSA_WITH_AES_128_CBC_SHA,
?TLS_RSA_WITH_AES_128_CBC_SHA,
%%?TLS_RSA_WITH_IDEA_CBC_SHA,
+ ?TLS_ECDHE_ECDSA_WITH_RC4_128_SHA,
+ ?TLS_ECDHE_RSA_WITH_RC4_128_SHA,
?TLS_RSA_WITH_RC4_128_SHA,
?TLS_RSA_WITH_RC4_128_MD5,
?TLS_DHE_RSA_WITH_DES_CBC_SHA,
+ ?TLS_ECDH_ECDSA_WITH_RC4_128_SHA,
+ ?TLS_ECDH_RSA_WITH_RC4_128_SHA,
?TLS_RSA_WITH_DES_CBC_SHA
];
suites(Minor) when Minor == 3 ->
[
+ ?TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384,
+ ?TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384,
+ ?TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA384,
+ ?TLS_ECDH_RSA_WITH_AES_256_CBC_SHA384,
+
?TLS_DHE_RSA_WITH_AES_256_CBC_SHA256,
?TLS_DHE_DSS_WITH_AES_256_CBC_SHA256,
?TLS_RSA_WITH_AES_256_CBC_SHA256,
+
+ ?TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256,
+ ?TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256,
+ ?TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA256,
+ ?TLS_ECDH_RSA_WITH_AES_128_CBC_SHA256,
+
?TLS_DHE_RSA_WITH_AES_128_CBC_SHA256,
?TLS_DHE_DSS_WITH_AES_128_CBC_SHA256,
?TLS_RSA_WITH_AES_128_CBC_SHA256
@@ -218,16 +248,8 @@ suites(Minor) when Minor == 3 ->
%%%% HMAC and the Pseudorandom Functions RFC 2246 & 4346 - 5.%%%%
hmac_hash(?NULL, _, _) ->
<<>>;
-hmac_hash(?MD5, Key, Value) ->
- crypto:md5_mac(Key, Value);
-hmac_hash(?SHA, Key, Value) ->
- crypto:sha_mac(Key, Value);
-hmac_hash(?SHA256, Key, Value) ->
- crypto:sha256_mac(Key, Value);
-hmac_hash(?SHA384, Key, Value) ->
- crypto:sha384_mac(Key, Value);
-hmac_hash(?SHA512, Key, Value) ->
- crypto:sha512_mac(Key, Value).
+hmac_hash(Alg, Key, Value) ->
+ crypto:hmac(mac_algo(Alg), Key, Value).
mac_algo(?MD5) -> md5;
mac_algo(?SHA) -> sha;
@@ -303,3 +325,64 @@ finished_label(client) ->
<<"client finished">>;
finished_label(server) ->
<<"server finished">>.
+
+%% list ECC curves in prefered order
+ecc_curves(_Minor) ->
+ [?sect571r1,?sect571k1,?secp521r1,?sect409k1,?sect409r1,
+ ?secp384r1,?sect283k1,?sect283r1,?secp256k1,?secp256r1,
+ ?sect239k1,?sect233k1,?sect233r1,?secp224k1,?secp224r1,
+ ?sect193r1,?sect193r2,?secp192k1,?secp192r1,?sect163k1,
+ ?sect163r1,?sect163r2,?secp160k1,?secp160r1,?secp160r2].
+
+%% ECC curves from draft-ietf-tls-ecc-12.txt (Oct. 17, 2005)
+oid_to_enum(?sect163k1) -> 1;
+oid_to_enum(?sect163r1) -> 2;
+oid_to_enum(?sect163r2) -> 3;
+oid_to_enum(?sect193r1) -> 4;
+oid_to_enum(?sect193r2) -> 5;
+oid_to_enum(?sect233k1) -> 6;
+oid_to_enum(?sect233r1) -> 7;
+oid_to_enum(?sect239k1) -> 8;
+oid_to_enum(?sect283k1) -> 9;
+oid_to_enum(?sect283r1) -> 10;
+oid_to_enum(?sect409k1) -> 11;
+oid_to_enum(?sect409r1) -> 12;
+oid_to_enum(?sect571k1) -> 13;
+oid_to_enum(?sect571r1) -> 14;
+oid_to_enum(?secp160k1) -> 15;
+oid_to_enum(?secp160r1) -> 16;
+oid_to_enum(?secp160r2) -> 17;
+oid_to_enum(?secp192k1) -> 18;
+oid_to_enum(?secp192r1) -> 19;
+oid_to_enum(?secp224k1) -> 20;
+oid_to_enum(?secp224r1) -> 21;
+oid_to_enum(?secp256k1) -> 22;
+oid_to_enum(?secp256r1) -> 23;
+oid_to_enum(?secp384r1) -> 24;
+oid_to_enum(?secp521r1) -> 25.
+
+enum_to_oid(1) -> ?sect163k1;
+enum_to_oid(2) -> ?sect163r1;
+enum_to_oid(3) -> ?sect163r2;
+enum_to_oid(4) -> ?sect193r1;
+enum_to_oid(5) -> ?sect193r2;
+enum_to_oid(6) -> ?sect233k1;
+enum_to_oid(7) -> ?sect233r1;
+enum_to_oid(8) -> ?sect239k1;
+enum_to_oid(9) -> ?sect283k1;
+enum_to_oid(10) -> ?sect283r1;
+enum_to_oid(11) -> ?sect409k1;
+enum_to_oid(12) -> ?sect409r1;
+enum_to_oid(13) -> ?sect571k1;
+enum_to_oid(14) -> ?sect571r1;
+enum_to_oid(15) -> ?secp160k1;
+enum_to_oid(16) -> ?secp160r1;
+enum_to_oid(17) -> ?secp160r2;
+enum_to_oid(18) -> ?secp192k1;
+enum_to_oid(19) -> ?secp192r1;
+enum_to_oid(20) -> ?secp224k1;
+enum_to_oid(21) -> ?secp224r1;
+enum_to_oid(22) -> ?secp256k1;
+enum_to_oid(23) -> ?secp256r1;
+enum_to_oid(24) -> ?secp384r1;
+enum_to_oid(25) -> ?secp521r1.
diff --git a/lib/ssl/test/erl_make_certs.erl b/lib/ssl/test/erl_make_certs.erl
index 71aa985c4f..723ccf4496 100644
--- a/lib/ssl/test/erl_make_certs.erl
+++ b/lib/ssl/test/erl_make_certs.erl
@@ -45,7 +45,7 @@
%% {dnQualifer, DnQ}
%% issuer = {Issuer, IssuerKey} true (i.e. a ca cert is created)
%% (obs IssuerKey migth be {Key, Password}
-%% key = KeyFile|KeyBin|rsa|dsa Subject PublicKey rsa or dsa generates key
+%% key = KeyFile|KeyBin|rsa|dsa|ec Subject PublicKey rsa, dsa or ec generates key
%%
%%
%% (OBS: The generated keys are for testing only)
@@ -91,6 +91,16 @@ gen_dsa(LSize,NSize) when is_integer(LSize), is_integer(NSize) ->
{Key, encode_key(Key)}.
%%--------------------------------------------------------------------
+%% @doc Creates a ec key (OBS: for testing only)
+%% the sizes are in bytes
+%% @spec (::integer()) -> {::atom(), ::binary(), ::opaque()}
+%% @end
+%%--------------------------------------------------------------------
+gen_ec(Curve) when is_atom(Curve) ->
+ Key = gen_ec2(Curve),
+ {Key, encode_key(Key)}.
+
+%%--------------------------------------------------------------------
%% @doc Verifies cert signatures
%% @spec (::binary(), ::tuple()) -> ::boolean()
%% @end
@@ -102,7 +112,10 @@ verify_signature(DerEncodedCert, DerKey, _KeyParams) ->
public_key:pkix_verify(DerEncodedCert,
#'RSAPublicKey'{modulus=Mod, publicExponent=Exp});
#'DSAPrivateKey'{p=P, q=Q, g=G, y=Y} ->
- public_key:pkix_verify(DerEncodedCert, {Y, #'Dss-Parms'{p=P, q=Q, g=G}})
+ public_key:pkix_verify(DerEncodedCert, {Y, #'Dss-Parms'{p=P, q=Q, g=G}});
+ #'ECPrivateKey'{version = _Version, privateKey = _PrivKey,
+ parameters = Params, publicKey = {0, PubKey}} ->
+ public_key:pkix_verify(DerEncodedCert, {#'ECPoint'{point = PubKey}, Params})
end.
%%%%%%%%%%%%%%%%%%%%%%%%% Implementation %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
@@ -112,6 +125,7 @@ get_key(Opts) ->
undefined -> make_key(rsa, Opts);
rsa -> make_key(rsa, Opts);
dsa -> make_key(dsa, Opts);
+ ec -> make_key(ec, Opts);
Key ->
Password = proplists:get_value(password, Opts, no_passwd),
decode_key(Key, Password)
@@ -129,6 +143,8 @@ decode_key(#'RSAPrivateKey'{} = Key,_) ->
Key;
decode_key(#'DSAPrivateKey'{} = Key,_) ->
Key;
+decode_key(#'ECPrivateKey'{} = Key,_) ->
+ Key;
decode_key(PemEntry = {_,_,_}, Pw) ->
public_key:pem_entry_decode(PemEntry, Pw);
decode_key(PemBin, Pw) ->
@@ -140,7 +156,10 @@ encode_key(Key = #'RSAPrivateKey'{}) ->
{'RSAPrivateKey', Der, not_encrypted};
encode_key(Key = #'DSAPrivateKey'{}) ->
{ok, Der} = 'OTP-PUB-KEY':encode('DSAPrivateKey', Key),
- {'DSAPrivateKey', Der, not_encrypted}.
+ {'DSAPrivateKey', Der, not_encrypted};
+encode_key(Key = #'ECPrivateKey'{}) ->
+ {ok, Der} = 'OTP-PUB-KEY':encode('ECPrivateKey', Key),
+ {'ECPrivateKey', Der, not_encrypted}.
make_tbs(SubjectKey, Opts) ->
Version = list_to_atom("v"++integer_to_list(proplists:get_value(version, Opts, 3))),
@@ -277,7 +296,14 @@ publickey(#'RSAPrivateKey'{modulus=N, publicExponent=E}) ->
publickey(#'DSAPrivateKey'{p=P, q=Q, g=G, y=Y}) ->
Algo = #'PublicKeyAlgorithm'{algorithm= ?'id-dsa',
parameters={params, #'Dss-Parms'{p=P, q=Q, g=G}}},
- #'OTPSubjectPublicKeyInfo'{algorithm = Algo, subjectPublicKey = Y}.
+ #'OTPSubjectPublicKeyInfo'{algorithm = Algo, subjectPublicKey = Y};
+publickey(#'ECPrivateKey'{version = _Version,
+ privateKey = _PrivKey,
+ parameters = Params,
+ publicKey = {0, PubKey}}) ->
+ Algo = #'PublicKeyAlgorithm'{algorithm= ?'id-ecPublicKey', parameters=Params},
+ #'OTPSubjectPublicKeyInfo'{algorithm = Algo,
+ subjectPublicKey = #'ECPoint'{point = PubKey}}.
validity(Opts) ->
DefFrom0 = calendar:gregorian_days_to_date(calendar:date_to_gregorian_days(date())-1),
@@ -298,13 +324,24 @@ sign_algorithm(#'RSAPrivateKey'{}, Opts) ->
end,
{Type, 'NULL'};
sign_algorithm(#'DSAPrivateKey'{p=P, q=Q, g=G}, _Opts) ->
- {?'id-dsa-with-sha1', {params,#'Dss-Parms'{p=P, q=Q, g=G}}}.
+ {?'id-dsa-with-sha1', {params,#'Dss-Parms'{p=P, q=Q, g=G}}};
+sign_algorithm(#'ECPrivateKey'{}, Opts) ->
+ Type = case proplists:get_value(digest, Opts, sha1) of
+ sha1 -> ?'ecdsa-with-SHA1';
+ sha512 -> ?'ecdsa-with-SHA512';
+ sha384 -> ?'ecdsa-with-SHA384';
+ sha256 -> ?'ecdsa-with-SHA256'
+ end,
+ {Type, 'NULL'}.
make_key(rsa, _Opts) ->
%% (OBS: for testing only)
gen_rsa2(64);
make_key(dsa, _Opts) ->
- gen_dsa2(128, 20). %% Bytes i.e. {1024, 160}
+ gen_dsa2(128, 20); %% Bytes i.e. {1024, 160}
+make_key(ec, _Opts) ->
+ %% (OBS: for testing only)
+ gen_ec2(secp256k1).
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%% RSA key generation (OBS: for testing only)
@@ -363,6 +400,22 @@ gen_dsa2(LSize, NSize) ->
#'DSAPrivateKey'{version=0, p=P, q=Q, g=G, y=Y, x=X}
end.
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%% EC key generation (OBS: for testing only)
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+int2list(I) ->
+ L = (length(integer_to_list(I, 16)) + 1) div 2,
+ binary_to_list(<<I:(L*8)>>).
+
+gen_ec2(CurveId) ->
+ {PrivKey, PubKey} = crypto:generate_key(ecdh, CurveId),
+
+ #'ECPrivateKey'{version = 1,
+ privateKey = int2list(PrivKey),
+ parameters = {namedCurve, pubkey_cert_records:namedCurves(CurveId)},
+ publicKey = {0, PubKey}}.
+
%% See fips_186-3.pdf
dsa_search(T, P0, Q, Iter) when Iter > 0 ->
P = 2*T*Q*P0 + 1,
diff --git a/lib/ssl/test/ssl_basic_SUITE.erl b/lib/ssl/test/ssl_basic_SUITE.erl
index 10bbd4d88b..165a8a5fcc 100644
--- a/lib/ssl/test/ssl_basic_SUITE.erl
+++ b/lib/ssl/test/ssl_basic_SUITE.erl
@@ -69,6 +69,7 @@ groups() ->
{session, [], session_tests()},
{renegotiate, [], renegotiate_tests()},
{ciphers, [], cipher_tests()},
+ {ciphers_ec, [], cipher_tests_ec()},
{error_handling_tests, [], error_handling_tests()}
].
@@ -76,6 +77,7 @@ all_versions_groups ()->
[{group, api},
{group, renegotiate},
{group, ciphers},
+ {group, ciphers_ec},
{group, error_handling_tests}].
@@ -163,6 +165,12 @@ cipher_tests() ->
srp_dsa_cipher_suites,
default_reject_anonymous].
+cipher_tests_ec() ->
+ [ciphers_ecdsa_signed_certs,
+ ciphers_ecdsa_signed_certs_openssl_names,
+ ciphers_ecdh_rsa_signed_certs,
+ ciphers_ecdh_rsa_signed_certs_openssl_names].
+
error_handling_tests()->
[controller_dies,
client_closes_socket,
@@ -188,10 +196,12 @@ init_per_suite(Config0) ->
Result =
(catch make_certs:all(?config(data_dir, Config0),
?config(priv_dir, Config0))),
- ct:print("Make certs ~p~n", [Result]),
+ ct:log("Make certs ~p~n", [Result]),
Config1 = ssl_test_lib:make_dsa_cert(Config0),
- Config = ssl_test_lib:cert_options(Config1),
+ Config2 = ssl_test_lib:make_ecdsa_cert(Config1),
+ Config3 = ssl_test_lib:make_ecdh_rsa_cert(Config2),
+ Config = ssl_test_lib:cert_options(Config3),
[{watchdog, Dog} | Config]
catch _:_ ->
{skip, "Crypto did not start"}
@@ -256,7 +266,7 @@ init_per_testcase(empty_protocol_versions, Config) ->
%% ssl_test_lib:make_mix_cert(Config0);
init_per_testcase(_TestCase, Config0) ->
- ct:print("TLS/SSL version ~p~n ", [ssl_record:supported_protocol_versions()]),
+ ct:log("TLS/SSL version ~p~n ", [ssl_record:supported_protocol_versions()]),
Config = lists:keydelete(watchdog, 1, Config0),
Dog = ct:timetrap(?TIMEOUT),
[{watchdog, Dog} | Config].
@@ -319,7 +329,7 @@ connection_info(Config) when is_list(Config) ->
[{ciphers,[{rsa,rc4_128,sha,no_export}]} |
ClientOpts]}]),
- ct:print("Testcase ~p, Client ~p Server ~p ~n",
+ ct:log("Testcase ~p, Client ~p Server ~p ~n",
[self(), Client, Server]),
Version =
@@ -372,7 +382,7 @@ controlling_process(Config) when is_list(Config) ->
ClientMsg]}},
{options, ClientOpts}]),
- ct:print("Testcase ~p, Client ~p Server ~p ~n",
+ ct:log("Testcase ~p, Client ~p Server ~p ~n",
[self(), Client, Server]),
receive
@@ -422,7 +432,7 @@ controller_dies(Config) when is_list(Config) ->
ClientMsg]}},
{options, ClientOpts}]),
- ct:print("Testcase ~p, Client ~p Server ~p ~n", [self(), Client, Server]),
+ ct:log("Testcase ~p, Client ~p Server ~p ~n", [self(), Client, Server]),
ct:sleep(?SLEEP), %% so that they are connected
process_flag(trap_exit, true),
@@ -460,12 +470,12 @@ controller_dies(Config) when is_list(Config) ->
Client3 ! die_nice
end,
- ct:print("Wating on exit ~p~n",[Client3]),
+ ct:log("Wating on exit ~p~n",[Client3]),
receive {'EXIT', Client3, normal} -> ok end,
receive %% Client3 is dead but that doesn't matter, socket should not be closed.
Unexpected ->
- ct:print("Unexpected ~p~n",[Unexpected]),
+ ct:log("Unexpected ~p~n",[Unexpected]),
ct:fail({line, ?LINE-1})
after 1000 ->
ok
@@ -596,7 +606,7 @@ peername(Config) when is_list(Config) ->
ServerMsg = {ok, {ClientIp, ClientPort}},
ClientMsg = {ok, {ServerIp, Port}},
- ct:print("Testcase ~p, Client ~p Server ~p ~n",
+ ct:log("Testcase ~p, Client ~p Server ~p ~n",
[self(), Client, Server]),
ssl_test_lib:check_result(Server, ServerMsg, Client, ClientMsg),
@@ -629,7 +639,7 @@ peercert(Config) when is_list(Config) ->
ServerMsg = {error, no_peercert},
ClientMsg = {ok, BinCert},
- ct:print("Testcase ~p, Client ~p Server ~p ~n",
+ ct:log("Testcase ~p, Client ~p Server ~p ~n",
[self(), Client, Server]),
ssl_test_lib:check_result(Server, ServerMsg, Client, ClientMsg),
@@ -667,7 +677,7 @@ peercert_with_client_cert(Config) when is_list(Config) ->
ServerMsg = {ok, ClientBinCert},
ClientMsg = {ok, ServerBinCert},
- ct:print("Testcase ~p, Client ~p Server ~p ~n",
+ ct:log("Testcase ~p, Client ~p Server ~p ~n",
[self(), Client, Server]),
ssl_test_lib:check_result(Server, ServerMsg, Client, ClientMsg),
@@ -699,7 +709,7 @@ sockname(Config) when is_list(Config) ->
ServerMsg = {ok, {ServerIp, Port}},
ClientMsg = {ok, {ClientIp, ClientPort}},
- ct:print("Testcase ~p, Client ~p Server ~p ~n",
+ ct:log("Testcase ~p, Client ~p Server ~p ~n",
[self(), Client, Server]),
ssl_test_lib:check_result(Server, ServerMsg, Client, ClientMsg),
@@ -772,7 +782,7 @@ socket_options_result(Socket, Options, DefaultValues, NewOptions, NewValues) ->
ssl:setopts(Socket, [{nodelay, true}]),
{ok,[{nodelay, true}]} = ssl:getopts(Socket, [nodelay]),
{ok, All} = ssl:getopts(Socket, []),
- ct:print("All opts ~p~n", [All]),
+ ct:log("All opts ~p~n", [All]),
ok.
@@ -795,7 +805,7 @@ invalid_inet_get_option(Config) when is_list(Config) ->
{mfa, {ssl_test_lib, no_result, []}},
{options, ClientOpts}]),
- ct:print("Testcase ~p, Client ~p Server ~p ~n",
+ ct:log("Testcase ~p, Client ~p Server ~p ~n",
[self(), Client, Server]),
ssl_test_lib:check_result(Server, ok),
@@ -821,7 +831,7 @@ invalid_inet_get_option_not_list(Config) when is_list(Config) ->
{mfa, {ssl_test_lib, no_result, []}},
{options, ClientOpts}]),
- ct:print("Testcase ~p, Client ~p Server ~p ~n",
+ ct:log("Testcase ~p, Client ~p Server ~p ~n",
[self(), Client, Server]),
ssl_test_lib:check_result(Server, ok),
@@ -853,7 +863,7 @@ invalid_inet_get_option_improper_list(Config) when is_list(Config) ->
{mfa, {ssl_test_lib, no_result, []}},
{options, ClientOpts}]),
- ct:print("Testcase ~p, Client ~p Server ~p ~n",
+ ct:log("Testcase ~p, Client ~p Server ~p ~n",
[self(), Client, Server]),
ssl_test_lib:check_result(Server, ok),
@@ -884,7 +894,7 @@ invalid_inet_set_option(Config) when is_list(Config) ->
{mfa, {ssl_test_lib, no_result, []}},
{options, ClientOpts}]),
- ct:print("Testcase ~p, Client ~p Server ~p ~n",
+ ct:log("Testcase ~p, Client ~p Server ~p ~n",
[self(), Client, Server]),
ssl_test_lib:check_result(Server, ok),
@@ -916,7 +926,7 @@ invalid_inet_set_option_not_list(Config) when is_list(Config) ->
{mfa, {ssl_test_lib, no_result, []}},
{options, ClientOpts}]),
- ct:print("Testcase ~p, Client ~p Server ~p ~n",
+ ct:log("Testcase ~p, Client ~p Server ~p ~n",
[self(), Client, Server]),
ssl_test_lib:check_result(Server, ok),
@@ -948,7 +958,7 @@ invalid_inet_set_option_improper_list(Config) when is_list(Config) ->
{mfa, {ssl_test_lib, no_result, []}},
{options, ClientOpts}]),
- ct:print("Testcase ~p, Client ~p Server ~p ~n",
+ ct:log("Testcase ~p, Client ~p Server ~p ~n",
[self(), Client, Server]),
ssl_test_lib:check_result(Server, ok),
@@ -989,7 +999,7 @@ misc_ssl_options(Config) when is_list(Config) ->
{mfa, {ssl_test_lib, send_recv_result_active, []}},
{options, TestOpts ++ ClientOpts}]),
- ct:print("Testcase ~p, Client ~p Server ~p ~n",
+ ct:log("Testcase ~p, Client ~p Server ~p ~n",
[self(), Client, Server]),
ssl_test_lib:check_result(Server, ok, Client, ok),
@@ -1002,7 +1012,7 @@ versions() ->
versions(Config) when is_list(Config) ->
[_|_] = Versions = ssl:versions(),
- ct:print("~p~n", [Versions]).
+ ct:log("~p~n", [Versions]).
%%--------------------------------------------------------------------
send_recv() ->
@@ -1024,7 +1034,7 @@ send_recv(Config) when is_list(Config) ->
{mfa, {ssl_test_lib, send_recv_result, []}},
{options, [{active, false} | ClientOpts]}]),
- ct:print("Testcase ~p, Client ~p Server ~p ~n",
+ ct:log("Testcase ~p, Client ~p Server ~p ~n",
[self(), Client, Server]),
ssl_test_lib:check_result(Server, ok, Client, ok),
@@ -1050,7 +1060,7 @@ send_close(Config) when is_list(Config) ->
{ok, SslS} = rpc:call(ClientNode, ssl, connect,
[TcpS,[{active, false}|ClientOpts]]),
- ct:print("Testcase ~p, Client ~p Server ~p ~n",
+ ct:log("Testcase ~p, Client ~p Server ~p ~n",
[self(), self(), Server]),
ok = ssl:send(SslS, "Hello world"),
{ok,<<"Hello world">>} = ssl:recv(SslS, 11),
@@ -1135,7 +1145,7 @@ upgrade(Config) when is_list(Config) ->
{tcp_options, TcpOpts},
{ssl_options, ClientOpts}]),
- ct:print("Testcase ~p, Client ~p Server ~p ~n",
+ ct:log("Testcase ~p, Client ~p Server ~p ~n",
[self(), Client, Server]),
ssl_test_lib:check_result(Server, ok, Client, ok),
@@ -1185,7 +1195,7 @@ upgrade_with_timeout(Config) when is_list(Config) ->
{tcp_options, TcpOpts},
{ssl_options, ClientOpts}]),
- ct:print("Testcase ~p, Client ~p Server ~p ~n",
+ ct:log("Testcase ~p, Client ~p Server ~p ~n",
[self(), Client, Server]),
ssl_test_lib:check_result(Server, ok, Client, ok),
@@ -1211,14 +1221,14 @@ tcp_connect(Config) when is_list(Config) ->
Port = ssl_test_lib:inet_port(Server),
{ok, Socket} = gen_tcp:connect(Hostname, Port, [binary, {packet, 0}]),
- ct:print("Testcase ~p connected to Server ~p ~n", [self(), Server]),
+ ct:log("Testcase ~p connected to Server ~p ~n", [self(), Server]),
gen_tcp:send(Socket, "<SOME GARBLED NON SSL MESSAGE>"),
receive
{tcp_closed, Socket} ->
receive
{Server, {error, Error}} ->
- ct:print("Error ~p", [Error])
+ ct:log("Error ~p", [Error])
end
end.
%%--------------------------------------------------------------------
@@ -1239,7 +1249,7 @@ tcp_connect_big(Config) when is_list(Config) ->
Port = ssl_test_lib:inet_port(Server),
{ok, Socket} = gen_tcp:connect(Hostname, Port, [binary, {packet, 0}]),
- ct:print("Testcase ~p connected to Server ~p ~n", [self(), Server]),
+ ct:log("Testcase ~p connected to Server ~p ~n", [self(), Server]),
Rand = crypto:rand_bytes(?MAX_CIPHER_TEXT_LENGTH+1),
gen_tcp:send(Socket, <<?BYTE(0),
@@ -1251,7 +1261,7 @@ tcp_connect_big(Config) when is_list(Config) ->
{Server, {error, timeout}} ->
ct:fail("hangs");
{Server, {error, Error}} ->
- ct:print("Error ~p", [Error])
+ ct:log("Error ~p", [Error])
end
end.
@@ -1281,7 +1291,7 @@ ipv6(Config) when is_list(Config) ->
{options,
[inet6, {active, false} | ClientOpts]}]),
- ct:print("Testcase ~p, Client ~p Server ~p ~n",
+ ct:log("Testcase ~p, Client ~p Server ~p ~n",
[self(), Client, Server]),
ssl_test_lib:check_result(Server, ok, Client, ok),
@@ -1539,8 +1549,8 @@ ciphers_rsa_signed_certs(Config) when is_list(Config) ->
Version =
ssl_record:protocol_version(ssl_record:highest_protocol_version([])),
- Ciphers = ssl_test_lib:rsa_suites(),
- ct:print("~p erlang cipher suites ~p~n", [Version, Ciphers]),
+ Ciphers = ssl_test_lib:rsa_suites(erlang),
+ ct:log("~p erlang cipher suites ~p~n", [Version, Ciphers]),
run_suites(Ciphers, Version, Config, rsa).
%%-------------------------------------------------------------------
ciphers_rsa_signed_certs_openssl_names() ->
@@ -1550,7 +1560,7 @@ ciphers_rsa_signed_certs_openssl_names(Config) when is_list(Config) ->
Version =
ssl_record:protocol_version(ssl_record:highest_protocol_version([])),
Ciphers = ssl_test_lib:openssl_rsa_suites(),
- ct:print("tls1 openssl cipher suites ~p~n", [Ciphers]),
+ ct:log("tls1 openssl cipher suites ~p~n", [Ciphers]),
run_suites(Ciphers, Version, Config, rsa).
%%-------------------------------------------------------------------
@@ -1562,7 +1572,7 @@ ciphers_dsa_signed_certs(Config) when is_list(Config) ->
ssl_record:protocol_version(ssl_record:highest_protocol_version([])),
Ciphers = ssl_test_lib:dsa_suites(),
- ct:print("~p erlang cipher suites ~p~n", [Version, Ciphers]),
+ ct:log("~p erlang cipher suites ~p~n", [Version, Ciphers]),
run_suites(Ciphers, Version, Config, dsa).
%%-------------------------------------------------------------------
ciphers_dsa_signed_certs_openssl_names() ->
@@ -1573,7 +1583,7 @@ ciphers_dsa_signed_certs_openssl_names(Config) when is_list(Config) ->
ssl_record:protocol_version(ssl_record:highest_protocol_version([])),
Ciphers = ssl_test_lib:openssl_dsa_suites(),
- ct:print("tls1 openssl cipher suites ~p~n", [Ciphers]),
+ ct:log("tls1 openssl cipher suites ~p~n", [Ciphers]),
run_suites(Ciphers, Version, Config, dsa).
%%-------------------------------------------------------------------
anonymous_cipher_suites()->
@@ -1656,6 +1666,48 @@ default_reject_anonymous(Config) when is_list(Config) ->
Client, {error, {tls_alert, "insufficient security"}}).
%%--------------------------------------------------------------------
+ciphers_ecdsa_signed_certs() ->
+ [{doc, "Test all ecdsa ssl cipher suites in highest support ssl/tls version"}].
+
+ciphers_ecdsa_signed_certs(Config) when is_list(Config) ->
+ Version =
+ ssl_record:protocol_version(ssl_record:highest_protocol_version([])),
+
+ Ciphers = ssl_test_lib:ecdsa_suites(),
+ ct:log("~p erlang cipher suites ~p~n", [Version, Ciphers]),
+ run_suites(Ciphers, Version, Config, ecdsa).
+%%--------------------------------------------------------------------
+ciphers_ecdsa_signed_certs_openssl_names() ->
+ [{doc, "Test all ecdsa ssl cipher suites in highest support ssl/tls version"}].
+
+ciphers_ecdsa_signed_certs_openssl_names(Config) when is_list(Config) ->
+ Version =
+ ssl_record:protocol_version(ssl_record:highest_protocol_version([])),
+ Ciphers = ssl_test_lib:openssl_ecdsa_suites(),
+ ct:log("tls1 openssl cipher suites ~p~n", [Ciphers]),
+ run_suites(Ciphers, Version, Config, ecdsa).
+%%--------------------------------------------------------------------
+ciphers_ecdh_rsa_signed_certs() ->
+ [{doc, "Test all ecdh_rsa ssl cipher suites in highest support ssl/tls version"}].
+
+ciphers_ecdh_rsa_signed_certs(Config) when is_list(Config) ->
+ Version =
+ ssl_record:protocol_version(ssl_record:highest_protocol_version([])),
+
+ Ciphers = ssl_test_lib:ecdh_rsa_suites(),
+ ct:log("~p erlang cipher suites ~p~n", [Version, Ciphers]),
+ run_suites(Ciphers, Version, Config, ecdh_rsa).
+%%--------------------------------------------------------------------
+ciphers_ecdh_rsa_signed_certs_openssl_names() ->
+ [{doc, "Test all ecdh_rsa ssl cipher suites in highest support ssl/tls version"}].
+
+ciphers_ecdh_rsa_signed_certs_openssl_names(Config) when is_list(Config) ->
+ Version =
+ ssl_record:protocol_version(ssl_record:highest_protocol_version([])),
+ Ciphers = ssl_test_lib:openssl_ecdh_rsa_suites(),
+ ct:log("tls1 openssl cipher suites ~p~n", [Ciphers]),
+ run_suites(Ciphers, Version, Config, ecdh_rsa).
+%%--------------------------------------------------------------------
reuse_session() ->
[{doc,"Test reuse of sessions (short handshake)"}].
reuse_session(Config) when is_list(Config) ->
@@ -1694,7 +1746,7 @@ reuse_session(Config) when is_list(Config) ->
{Client1, SessionInfo} ->
ok;
{Client1, Other} ->
- ct:print("Expected: ~p, Unexpected: ~p~n",
+ ct:log("Expected: ~p, Unexpected: ~p~n",
[SessionInfo, Other]),
ct:fail(session_not_reused)
end,
@@ -1752,7 +1804,7 @@ reuse_session(Config) when is_list(Config) ->
ct:fail(
session_reused_when_session_reuse_disabled_by_server);
{Client4, _Other} ->
- ct:print("OTHER: ~p ~n", [_Other]),
+ ct:log("OTHER: ~p ~n", [_Other]),
ok
end,
@@ -1802,7 +1854,7 @@ reuse_session_expired(Config) when is_list(Config) ->
{Client1, SessionInfo} ->
ok;
{Client1, Other} ->
- ct:print("Expected: ~p, Unexpected: ~p~n",
+ ct:log("Expected: ~p, Unexpected: ~p~n",
[SessionInfo, Other]),
ct:fail(session_not_reused)
end,
@@ -2505,7 +2557,7 @@ connect_twice(Config) when is_list(Config) ->
{options, [{keepalive, true},{active, false}
| ClientOpts]}]),
- ct:print("Testcase ~p, Client ~p Server ~p ~n",
+ ct:log("Testcase ~p, Client ~p Server ~p ~n",
[self(), Client, Server]),
ssl_test_lib:check_result(Server, ok, Client, ok),
@@ -2851,9 +2903,9 @@ result_ok(_Socket) ->
ok.
renegotiate(Socket, Data) ->
- ct:print("Renegotiating ~n", []),
+ ct:log("Renegotiating ~n", []),
Result = ssl:renegotiate(Socket),
- ct:print("Result ~p~n", [Result]),
+ ct:log("Result ~p~n", [Result]),
ssl:send(Socket, Data),
case Result of
ok ->
@@ -2882,7 +2934,7 @@ renegotiate_immediately(Socket) ->
{error, renegotiation_rejected} = ssl:renegotiate(Socket),
ct:sleep(?RENEGOTIATION_DISABLE_TIME +1),
ok = ssl:renegotiate(Socket),
- ct:print("Renegotiated again"),
+ ct:log("Renegotiated again"),
ssl:send(Socket, "Hello world"),
ok.
@@ -2901,7 +2953,7 @@ new_config(PrivDir, ServerOpts0) ->
ServerOpts = proplists:delete(keyfile, ServerOpts2),
{ok, PEM} = file:read_file(NewCaCertFile),
- ct:print("CA file content: ~p~n", [public_key:pem_decode(PEM)]),
+ ct:log("CA file content: ~p~n", [public_key:pem_decode(PEM)]),
[{cacertfile, NewCaCertFile}, {certfile, NewCertFile},
{keyfile, NewKeyFile} | ServerOpts].
@@ -3097,15 +3149,15 @@ get_close(Pid, Where) ->
{'EXIT', Pid, _Reason} ->
receive
{_, {ssl_closed, Socket}} ->
- ct:print("Socket closed ~p~n",[Socket]);
+ ct:log("Socket closed ~p~n",[Socket]);
Unexpected ->
- ct:print("Unexpected ~p~n",[Unexpected]),
+ ct:log("Unexpected ~p~n",[Unexpected]),
ct:fail({line, ?LINE-1})
after 5000 ->
ct:fail({timeout, {line, ?LINE, Where}})
end;
Unexpected ->
- ct:print("Unexpected ~p~n",[Unexpected]),
+ ct:log("Unexpected ~p~n",[Unexpected]),
ct:fail({line, ?LINE-1})
after 5000 ->
ct:fail({timeout, {line, ?LINE, Where}})
@@ -3119,7 +3171,7 @@ run_send_recv_rizzo(Ciphers, Config, Version, Mfa) ->
[] ->
ok;
Error ->
- ct:print("Cipher suite errors: ~p~n", [Error]),
+ ct:log("Cipher suite errors: ~p~n", [Error]),
ct:fail(cipher_suite_failed_see_test_case_log)
end.
@@ -3149,12 +3201,21 @@ rizzo_test(Cipher, Config, Version, Mfa) ->
[{Cipher, Error}]
end.
-client_server_opts({KeyAlgo,_,_}, Config) when KeyAlgo == rsa orelse KeyAlgo == dhe_rsa ->
+client_server_opts({KeyAlgo,_,_}, Config)
+ when KeyAlgo == rsa orelse
+ KeyAlgo == dhe_rsa orelse
+ KeyAlgo == ecdhe_rsa ->
{?config(client_opts, Config),
?config(server_opts, Config)};
client_server_opts({KeyAlgo,_,_}, Config) when KeyAlgo == dss orelse KeyAlgo == dhe_dss ->
{?config(client_dsa_opts, Config),
- ?config(server_dsa_opts, Config)}.
+ ?config(server_dsa_opts, Config)};
+client_server_opts({KeyAlgo,_,_}, Config) when KeyAlgo == ecdh_ecdsa orelse KeyAlgo == ecdhe_ecdsa ->
+ {?config(client_opts, Config),
+ ?config(server_ecdsa_opts, Config)};
+client_server_opts({KeyAlgo,_,_}, Config) when KeyAlgo == ecdh_rsa ->
+ {?config(client_opts, Config),
+ ?config(server_ecdh_rsa_opts, Config)}.
run_suites(Ciphers, Version, Config, Type) ->
{ClientOpts, ServerOpts} =
@@ -3189,7 +3250,13 @@ run_suites(Ciphers, Version, Config, Type) ->
?config(server_srp_anon, Config)};
srp_dsa ->
{?config(client_srp_dsa, Config),
- ?config(server_srp_dsa, Config)}
+ ?config(server_srp_dsa, Config)};
+ ecdsa ->
+ {?config(client_opts, Config),
+ ?config(server_ecdsa_opts, Config)};
+ ecdh_rsa ->
+ {?config(client_opts, Config),
+ ?config(server_ecdh_rsa_opts, Config)}
end,
Result = lists:map(fun(Cipher) ->
@@ -3199,7 +3266,7 @@ run_suites(Ciphers, Version, Config, Type) ->
[] ->
ok;
Error ->
- ct:print("Cipher suite errors: ~p~n", [Error]),
+ ct:log("Cipher suite errors: ~p~n", [Error]),
ct:fail(cipher_suite_failed_see_test_case_log)
end.
@@ -3210,7 +3277,7 @@ erlang_cipher_suite(Suite) ->
cipher(CipherSuite, Version, Config, ClientOpts, ServerOpts) ->
%% process_flag(trap_exit, true),
- ct:print("Testing CipherSuite ~p~n", [CipherSuite]),
+ ct:log("Testing CipherSuite ~p~n", [CipherSuite]),
{ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
ErlangCipherSuite = erlang_cipher_suite(CipherSuite),
diff --git a/lib/ssl/test/ssl_certificate_verify_SUITE.erl b/lib/ssl/test/ssl_certificate_verify_SUITE.erl
index 26938bda50..2703d2d79c 100644
--- a/lib/ssl/test/ssl_certificate_verify_SUITE.erl
+++ b/lib/ssl/test/ssl_certificate_verify_SUITE.erl
@@ -86,7 +86,7 @@ init_per_suite(Config0) ->
Result =
(catch make_certs:all(?config(data_dir, Config0),
?config(priv_dir, Config0))),
- ct:print("Make certs ~p~n", [Result]),
+ ct:log("Make certs ~p~n", [Result]),
Config1 = ssl_test_lib:make_dsa_cert(Config0),
Config = ssl_test_lib:cert_options(Config1),
@@ -297,7 +297,7 @@ verify_fun_always_run_client(Config) when is_list(Config) ->
%% this is not a bug it is a circumstance of how tcp works!
receive
{Server, ServerError} ->
- ct:print("Server Error ~p~n", [ServerError])
+ ct:log("Server Error ~p~n", [ServerError])
end,
ssl_test_lib:check_result(Client, {error, {tls_alert, "handshake failure"}}).
@@ -346,7 +346,7 @@ verify_fun_always_run_server(Config) when is_list(Config) ->
%% this is not a bug it is a circumstance of how tcp works!
receive
{Client, ClientError} ->
- ct:print("Client Error ~p~n", [ClientError])
+ ct:log("Client Error ~p~n", [ClientError])
end,
ssl_test_lib:check_result(Server, {error, {tls_alert, "handshake failure"}}).
@@ -413,7 +413,7 @@ cert_expired(Config) when is_list(Config) ->
two_digits_str(Sec)])),
NewValidity = {'Validity', {generalTime, NotBeforeStr}, {generalTime, NotAfterStr}},
- ct:print("Validity: ~p ~n NewValidity: ~p ~n",
+ ct:log("Validity: ~p ~n NewValidity: ~p ~n",
[OTPTbsCert#'OTPTBSCertificate'.validity, NewValidity]),
NewOTPTbsCert = OTPTbsCert#'OTPTBSCertificate'{validity = NewValidity},
@@ -644,7 +644,7 @@ no_authority_key_identifier(Config) when is_list(Config) ->
NewExtensions = delete_authority_key_extension(Extensions, []),
NewOTPTbsCert = OTPTbsCert#'OTPTBSCertificate'{extensions = NewExtensions},
- ct:print("Extensions ~p~n, NewExtensions: ~p~n", [Extensions, NewExtensions]),
+ ct:log("Extensions ~p~n, NewExtensions: ~p~n", [Extensions, NewExtensions]),
NewDerCert = public_key:pkix_sign(NewOTPTbsCert, Key),
ssl_test_lib:der_to_pem(NewCertFile, [{'Certificate', NewDerCert, not_encrypted}]),
@@ -955,10 +955,10 @@ client_msg(Client, ClientMsg) ->
{Client, ClientMsg} ->
ok;
{Client, {error,closed}} ->
- ct:print("client got close"),
+ ct:log("client got close"),
ok;
{Client, {error, Reason}} ->
- ct:print("client got econnaborted: ~p", [Reason]),
+ ct:log("client got econnaborted: ~p", [Reason]),
ok;
Unexpected ->
ct:fail(Unexpected)
@@ -968,10 +968,10 @@ server_msg(Server, ServerMsg) ->
{Server, ServerMsg} ->
ok;
{Server, {error,closed}} ->
- ct:print("server got close"),
+ ct:log("server got close"),
ok;
{Server, {error, Reason}} ->
- ct:print("server got econnaborted: ~p", [Reason]),
+ ct:log("server got econnaborted: ~p", [Reason]),
ok;
Unexpected ->
ct:fail(Unexpected)
diff --git a/lib/ssl/test/ssl_npn_handshake_SUITE.erl b/lib/ssl/test/ssl_npn_handshake_SUITE.erl
index 8c1b22cf5e..7b271c4d5d 100644
--- a/lib/ssl/test/ssl_npn_handshake_SUITE.erl
+++ b/lib/ssl/test/ssl_npn_handshake_SUITE.erl
@@ -74,7 +74,7 @@ init_per_suite(Config) ->
Result =
(catch make_certs:all(?config(data_dir, Config),
?config(priv_dir, Config))),
- ct:print("Make certs ~p~n", [Result]),
+ ct:log("Make certs ~p~n", [Result]),
ssl_test_lib:cert_options(Config)
catch _:_ ->
{skip, "Crypto did not start"}
@@ -311,13 +311,13 @@ run_npn_handshake(Config, ClientExtraOpts, ServerExtraOpts, ExpectedProtocol) ->
assert_npn(Socket, Protocol) ->
- ct:print("Negotiated Protocol ~p, Expecting: ~p ~n",
+ ct:log("Negotiated Protocol ~p, Expecting: ~p ~n",
[ssl:negotiated_next_protocol(Socket), Protocol]),
Protocol = ssl:negotiated_next_protocol(Socket).
assert_npn_and_renegotiate_and_send_data(Socket, Protocol, Data) ->
assert_npn(Socket, Protocol),
- ct:print("Renegotiating ~n", []),
+ ct:log("Renegotiating ~n", []),
ok = ssl:renegotiate(Socket),
ssl:send(Socket, Data),
assert_npn(Socket, Protocol),
@@ -332,7 +332,7 @@ ssl_receive_and_assert_npn(Socket, Protocol, Data) ->
ssl_receive(Socket, Data).
ssl_send(Socket, Data) ->
- ct:print("Connection info: ~p~n",
+ ct:log("Connection info: ~p~n",
[ssl:connection_info(Socket)]),
ssl:send(Socket, Data).
@@ -340,11 +340,11 @@ ssl_receive(Socket, Data) ->
ssl_receive(Socket, Data, []).
ssl_receive(Socket, Data, Buffer) ->
- ct:print("Connection info: ~p~n",
+ ct:log("Connection info: ~p~n",
[ssl:connection_info(Socket)]),
receive
{ssl, Socket, MoreData} ->
- ct:print("Received ~p~n",[MoreData]),
+ ct:log("Received ~p~n",[MoreData]),
NewBuffer = Buffer ++ MoreData,
case NewBuffer of
Data ->
diff --git a/lib/ssl/test/ssl_npn_hello_SUITE.erl b/lib/ssl/test/ssl_npn_hello_SUITE.erl
index 72768bcb55..43fa72ea28 100644
--- a/lib/ssl/test/ssl_npn_hello_SUITE.erl
+++ b/lib/ssl/test/ssl_npn_hello_SUITE.erl
@@ -25,6 +25,8 @@
-compile(export_all).
-include("ssl_handshake.hrl").
-include("ssl_record.hrl").
+-include("ssl_cipher.hrl").
+-include("ssl_internal.hrl").
-include_lib("common_test/include/ct.hrl").
%%--------------------------------------------------------------------
@@ -75,17 +77,19 @@ encode_and_decode_npn_server_hello_test(_Config) ->
{[{DecodedHandshakeMessage, _Raw}], _} =
ssl_handshake:get_tls_handshake(Version, list_to_binary(HandShakeData), <<>>),
NextProtocolNegotiation = DecodedHandshakeMessage#server_hello.next_protocol_negotiation,
- ct:print("~p ~n", [NextProtocolNegotiation]),
+ ct:log("~p ~n", [NextProtocolNegotiation]),
NextProtocolNegotiation = #next_protocol_negotiation{extension_data = <<6, "spdy/2">>}.
%%--------------------------------------------------------------------
create_server_hello_with_no_advertised_protocols_test(_Config) ->
- Hello = ssl_handshake:server_hello(<<>>, {3, 0}, create_connection_states(), false, undefined),
+ Hello = ssl_handshake:server_hello(<<>>, {3, 0}, create_connection_states(), false,
+ undefined, undefined, undefined),
undefined = Hello#server_hello.next_protocol_negotiation.
%%--------------------------------------------------------------------
create_server_hello_with_advertised_protocols_test(_Config) ->
Hello = ssl_handshake:server_hello(<<>>, {3, 0}, create_connection_states(),
- false, [<<"spdy/1">>, <<"http/1.0">>, <<"http/1.1">>]),
+ false, [<<"spdy/1">>, <<"http/1.0">>, <<"http/1.1">>],
+ undefined, undefined),
#next_protocol_negotiation{extension_data = <<6, "spdy/1", 8, "http/1.0", 8, "http/1.1">>} =
Hello#server_hello.next_protocol_negotiation.
%%--------------------------------------------------------------------
@@ -96,7 +100,7 @@ create_client_handshake(Npn) ->
client_version = {1, 2},
random = <<1:256>>,
session_id = <<>>,
- cipher_suites = "",
+ cipher_suites = [?TLS_DHE_DSS_WITH_DES_CBC_SHA],
compression_methods = "",
next_protocol_negotiation = Npn,
renegotiation_info = #renegotiation_info{}
@@ -107,7 +111,7 @@ create_server_handshake(Npn) ->
server_version = {1, 2},
random = <<1:256>>,
session_id = <<>>,
- cipher_suite = <<1,2>>,
+ cipher_suite = ?TLS_DHE_DSS_WITH_DES_CBC_SHA,
compression_method = 1,
next_protocol_negotiation = Npn,
renegotiation_info = #renegotiation_info{}
@@ -119,7 +123,7 @@ create_connection_states() ->
security_parameters = #security_parameters{
server_random = <<1:256>>,
compression_algorithm = 1,
- cipher_suite = <<1, 2>>
+ cipher_suite = ?TLS_DHE_DSS_WITH_DES_CBC_SHA
}
},
diff --git a/lib/ssl/test/ssl_packet_SUITE.erl b/lib/ssl/test/ssl_packet_SUITE.erl
index 4116bb39d1..5a374e234d 100644
--- a/lib/ssl/test/ssl_packet_SUITE.erl
+++ b/lib/ssl/test/ssl_packet_SUITE.erl
@@ -143,7 +143,7 @@ init_per_suite(Config) ->
Result =
(catch make_certs:all(?config(data_dir, Config),
?config(priv_dir, Config))),
- ct:print("Make certs ~p~n", [Result]),
+ ct:log("Make certs ~p~n", [Result]),
ssl_test_lib:cert_options(Config)
catch _:_ ->
{skip, "Crypto did not start"}
@@ -2069,7 +2069,7 @@ client_packet_decode(Socket, [Head | Tail] = Packet) ->
client_packet_decode(Socket, [Head], Tail, Packet).
client_packet_decode(Socket, P1, P2, Packet) ->
- ct:print("Packet: ~p ~n", [Packet]),
+ ct:log("Packet: ~p ~n", [Packet]),
ok = ssl:send(Socket, P1),
ok = ssl:send(Socket, P2),
receive
diff --git a/lib/ssl/test/ssl_payload_SUITE.erl b/lib/ssl/test/ssl_payload_SUITE.erl
index 77ad546420..5f5166391f 100644
--- a/lib/ssl/test/ssl_payload_SUITE.erl
+++ b/lib/ssl/test/ssl_payload_SUITE.erl
@@ -556,33 +556,33 @@ send(Socket, Data, Size, Repeate,F) ->
sender(Socket, Data, Size) ->
ok = send(Socket, Data, Size, 100, fun() -> do_recv(Socket, Data, Size, <<>>, false) end),
- ct:print("Sender recv: ~p~n", [ssl:getopts(Socket, [active])]),
+ ct:log("Sender recv: ~p~n", [ssl:getopts(Socket, [active])]),
ok.
sender_once(Socket, Data, Size) ->
send(Socket, Data, Size, 100,
fun() -> do_active_once(Socket, Data, Size, <<>>, false) end),
- ct:print("Sender active once: ~p~n",
+ ct:log("Sender active once: ~p~n",
[ssl:getopts(Socket, [active])]),
ok.
sender_active(Socket, Data, Size) ->
F = fun() -> do_active(Socket, Data, Size, <<>>, false) end,
send(Socket, Data, Size, 100, F),
- ct:print("Sender active: ~p~n", [ssl:getopts(Socket, [active])]),
+ ct:log("Sender active: ~p~n", [ssl:getopts(Socket, [active])]),
ok.
echoer(Socket, Data, Size) ->
- ct:print("Echoer recv: ~p~n", [ssl:getopts(Socket, [active])]),
+ ct:log("Echoer recv: ~p~n", [ssl:getopts(Socket, [active])]),
echo(fun() -> do_recv(Socket, Data, Size, <<>>, true) end, 100).
echoer_once(Socket, Data, Size) ->
- ct:print("Echoer active once: ~p ~n",
+ ct:log("Echoer active once: ~p ~n",
[ssl:getopts(Socket, [active])]),
echo(fun() -> do_active_once(Socket, Data, Size, <<>>, true) end, 100).
echoer_active(Socket, Data, Size) ->
- ct:print("Echoer active: ~p~n", [ssl:getopts(Socket, [active])]),
+ ct:log("Echoer active: ~p~n", [ssl:getopts(Socket, [active])]),
echo(fun() -> do_active(Socket, Data, Size, <<>>, true) end, 100).
echo(_Fun, 0) -> ok;
diff --git a/lib/ssl/test/ssl_session_cache_SUITE.erl b/lib/ssl/test/ssl_session_cache_SUITE.erl
index fd9a0a594c..6cc6c4bdb2 100644
--- a/lib/ssl/test/ssl_session_cache_SUITE.erl
+++ b/lib/ssl/test/ssl_session_cache_SUITE.erl
@@ -63,7 +63,7 @@ init_per_suite(Config0) ->
Result =
(catch make_certs:all(?config(data_dir, Config0),
?config(priv_dir, Config0))),
- ct:print("Make certs ~p~n", [Result]),
+ ct:log("Make certs ~p~n", [Result]),
Config1 = ssl_test_lib:make_dsa_cert(Config0),
Config = ssl_test_lib:cert_options(Config1),
diff --git a/lib/ssl/test/ssl_test_lib.erl b/lib/ssl/test/ssl_test_lib.erl
index e4fedcd118..a8ff5187b6 100644
--- a/lib/ssl/test/ssl_test_lib.erl
+++ b/lib/ssl/test/ssl_test_lib.erl
@@ -59,7 +59,7 @@ run_server(Opts) ->
Options = proplists:get_value(options, Opts),
Pid = proplists:get_value(from, Opts),
Transport = proplists:get_value(transport, Opts, ssl),
- ct:print("ssl:listen(~p, ~p)~n", [Port, Options]),
+ ct:log("ssl:listen(~p, ~p)~n", [Port, Options]),
{ok, ListenSocket} = rpc:call(Node, Transport, listen, [Port, Options]),
Pid ! {listen, up},
send_selected_port(Pid, Port, ListenSocket),
@@ -77,13 +77,13 @@ do_run_server(ListenSocket, AcceptSocket, Opts) ->
Pid = proplists:get_value(from, Opts),
Transport = proplists:get_value(transport, Opts, ssl),
{Module, Function, Args} = proplists:get_value(mfa, Opts),
- ct:print("Server: apply(~p,~p,~p)~n",
+ ct:log("Server: apply(~p,~p,~p)~n",
[Module, Function, [AcceptSocket | Args]]),
case rpc:call(Node, Module, Function, [AcceptSocket | Args]) of
no_result_msg ->
ok;
Msg ->
- ct:print("Server Msg: ~p ~n", [Msg]),
+ ct:log("Server Msg: ~p ~n", [Msg]),
Pid ! {self(), Msg}
end,
receive
@@ -92,10 +92,10 @@ do_run_server(ListenSocket, AcceptSocket, Opts) ->
{listen, MFA} ->
run_server(ListenSocket, [MFA | proplists:delete(mfa, Opts)]);
close ->
- ct:print("Server closing ~p ~n", [self()]),
+ ct:log("Server closing ~p ~n", [self()]),
Result = rpc:call(Node, Transport, close, [AcceptSocket], 500),
Result1 = rpc:call(Node, Transport, close, [ListenSocket], 500),
- ct:print("Result ~p : ~p ~n", [Result, Result1]);
+ ct:log("Result ~p : ~p ~n", [Result, Result1]);
{ssl_closed, _} ->
ok
end.
@@ -115,7 +115,7 @@ connect(#sslsocket{} = ListenSocket, Opts) ->
end;
connect(ListenSocket, Opts) ->
Node = proplists:get_value(node, Opts),
- ct:print("gen_tcp:accept(~p)~n", [ListenSocket]),
+ ct:log("gen_tcp:accept(~p)~n", [ListenSocket]),
{ok, AcceptSocket} = rpc:call(Node, gen_tcp, accept,
[ListenSocket]),
AcceptSocket.
@@ -123,10 +123,10 @@ connect(ListenSocket, Opts) ->
connect(_, _, 0, AcceptSocket, _) ->
AcceptSocket;
connect(ListenSocket, Node, N, _, Timeout) ->
- ct:print("ssl:transport_accept(~p)~n", [ListenSocket]),
+ ct:log("ssl:transport_accept(~p)~n", [ListenSocket]),
{ok, AcceptSocket} = rpc:call(Node, ssl, transport_accept,
[ListenSocket]),
- ct:print("ssl:ssl_accept(~p, ~p)~n", [AcceptSocket, Timeout]),
+ ct:log("ssl:ssl_accept(~p, ~p)~n", [AcceptSocket, Timeout]),
case rpc:call(Node, ssl, ssl_accept, [AcceptSocket, Timeout]) of
ok ->
@@ -161,27 +161,27 @@ run_client(Opts) ->
Pid = proplists:get_value(from, Opts),
Transport = proplists:get_value(transport, Opts, ssl),
Options = proplists:get_value(options, Opts),
- ct:print("ssl:connect(~p, ~p, ~p)~n", [Host, Port, Options]),
+ ct:log("ssl:connect(~p, ~p, ~p)~n", [Host, Port, Options]),
case rpc:call(Node, Transport, connect, [Host, Port, Options]) of
{ok, Socket} ->
Pid ! { connected, Socket },
- ct:print("Client: connected~n", []),
+ ct:log("Client: connected~n", []),
%% In special cases we want to know the client port, it will
%% be indicated by sending {port, 0} in options list!
send_selected_port(Pid, proplists:get_value(port, Options), Socket),
{Module, Function, Args} = proplists:get_value(mfa, Opts),
- ct:print("Client: apply(~p,~p,~p)~n",
+ ct:log("Client: apply(~p,~p,~p)~n",
[Module, Function, [Socket | Args]]),
case rpc:call(Node, Module, Function, [Socket | Args]) of
no_result_msg ->
ok;
Msg ->
- ct:print("Client Msg: ~p ~n", [Msg]),
+ ct:log("Client Msg: ~p ~n", [Msg]),
Pid ! {self(), Msg}
end,
receive
close ->
- ct:print("Client closing~n", []),
+ ct:log("Client closing~n", []),
rpc:call(Node, Transport, close, [Socket]);
{ssl_closed, Socket} ->
ok;
@@ -189,18 +189,18 @@ run_client(Opts) ->
ok
end;
{error, Reason} ->
- ct:print("Client: connection failed: ~p ~n", [Reason]),
+ ct:log("Client: connection failed: ~p ~n", [Reason]),
Pid ! {self(), {error, Reason}}
end.
close(Pid) ->
- ct:print("Close ~p ~n", [Pid]),
+ ct:log("Close ~p ~n", [Pid]),
Monitor = erlang:monitor(process, Pid),
Pid ! close,
receive
{'DOWN', Monitor, process, Pid, Reason} ->
erlang:demonitor(Monitor),
- ct:print("Pid: ~p down due to:~p ~n", [Pid, Reason])
+ ct:log("Pid: ~p down due to:~p ~n", [Pid, Reason])
end.
check_result(Server, ServerMsg, Client, ClientMsg) ->
@@ -404,6 +404,49 @@ make_dsa_cert(Config) ->
{certfile, ClientCertFile}, {keyfile, ClientKeyFile}]}
| Config].
+make_ecdsa_cert(Config) ->
+ case proplists:get_bool(ec, crypto:algorithms()) of
+ true ->
+ {ServerCaCertFile, ServerCertFile, ServerKeyFile} = make_cert_files("server", Config, ec, ec, ""),
+ {ClientCaCertFile, ClientCertFile, ClientKeyFile} = make_cert_files("client", Config, ec, ec, ""),
+ [{server_ecdsa_opts, [{ssl_imp, new},{reuseaddr, true},
+ {cacertfile, ServerCaCertFile},
+ {certfile, ServerCertFile}, {keyfile, ServerKeyFile}]},
+ {server_ecdsa_verify_opts, [{ssl_imp, new},{reuseaddr, true},
+ {cacertfile, ClientCaCertFile},
+ {certfile, ServerCertFile}, {keyfile, ServerKeyFile},
+ {verify, verify_peer}]},
+ {client_ecdsa_opts, [{ssl_imp, new},{reuseaddr, true},
+ {cacertfile, ClientCaCertFile},
+ {certfile, ClientCertFile}, {keyfile, ClientKeyFile}]}
+ | Config];
+ _ ->
+ Config
+ end.
+
+%% RFC 4492, Sect. 2.3. ECDH_RSA
+%%
+%% This key exchange algorithm is the same as ECDH_ECDSA except that the
+%% server's certificate MUST be signed with RSA rather than ECDSA.
+make_ecdh_rsa_cert(Config) ->
+ case proplists:get_bool(ec, crypto:algorithms()) of
+ true ->
+ {ServerCaCertFile, ServerCertFile, ServerKeyFile} = make_cert_files("server", Config, rsa, ec, "rsa_"),
+ {ClientCaCertFile, ClientCertFile, ClientKeyFile} = make_cert_files("client", Config, rsa, ec, "rsa_"),
+ [{server_ecdh_rsa_opts, [{ssl_imp, new},{reuseaddr, true},
+ {cacertfile, ServerCaCertFile},
+ {certfile, ServerCertFile}, {keyfile, ServerKeyFile}]},
+ {server_ecdh_rsa_verify_opts, [{ssl_imp, new},{reuseaddr, true},
+ {cacertfile, ClientCaCertFile},
+ {certfile, ServerCertFile}, {keyfile, ServerKeyFile},
+ {verify, verify_peer}]},
+ {client_ecdh_rsa_opts, [{ssl_imp, new},{reuseaddr, true},
+ {cacertfile, ClientCaCertFile},
+ {certfile, ClientCertFile}, {keyfile, ClientKeyFile}]}
+ | Config];
+ _ ->
+ Config
+ end.
make_mix_cert(Config) ->
{ServerCaCertFile, ServerCertFile, ServerKeyFile} = make_cert_files("server", Config, dsa,
@@ -455,33 +498,33 @@ run_upgrade_server(Opts) ->
SslOptions = proplists:get_value(ssl_options, Opts),
Pid = proplists:get_value(from, Opts),
- ct:print("gen_tcp:listen(~p, ~p)~n", [Port, TcpOptions]),
+ ct:log("gen_tcp:listen(~p, ~p)~n", [Port, TcpOptions]),
{ok, ListenSocket} = rpc:call(Node, gen_tcp, listen, [Port, TcpOptions]),
Pid ! {listen, up},
send_selected_port(Pid, Port, ListenSocket),
- ct:print("gen_tcp:accept(~p)~n", [ListenSocket]),
+ ct:log("gen_tcp:accept(~p)~n", [ListenSocket]),
{ok, AcceptSocket} = rpc:call(Node, gen_tcp, accept, [ListenSocket]),
try
{ok, SslAcceptSocket} = case TimeOut of
infinity ->
- ct:print("ssl:ssl_accept(~p, ~p)~n",
+ ct:log("ssl:ssl_accept(~p, ~p)~n",
[AcceptSocket, SslOptions]),
rpc:call(Node, ssl, ssl_accept,
[AcceptSocket, SslOptions]);
_ ->
- ct:print("ssl:ssl_accept(~p, ~p, ~p)~n",
+ ct:log("ssl:ssl_accept(~p, ~p, ~p)~n",
[AcceptSocket, SslOptions, TimeOut]),
rpc:call(Node, ssl, ssl_accept,
[AcceptSocket, SslOptions, TimeOut])
end,
{Module, Function, Args} = proplists:get_value(mfa, Opts),
Msg = rpc:call(Node, Module, Function, [SslAcceptSocket | Args]),
- ct:print("Upgrade Server Msg: ~p ~n", [Msg]),
+ ct:log("Upgrade Server Msg: ~p ~n", [Msg]),
Pid ! {self(), Msg},
receive
close ->
- ct:print("Upgrade Server closing~n", []),
+ ct:log("Upgrade Server closing~n", []),
rpc:call(Node, ssl, close, [SslAcceptSocket])
end
catch error:{badmatch, Error} ->
@@ -499,24 +542,24 @@ run_upgrade_client(Opts) ->
TcpOptions = proplists:get_value(tcp_options, Opts),
SslOptions = proplists:get_value(ssl_options, Opts),
- ct:print("gen_tcp:connect(~p, ~p, ~p)~n",
+ ct:log("gen_tcp:connect(~p, ~p, ~p)~n",
[Host, Port, TcpOptions]),
{ok, Socket} = rpc:call(Node, gen_tcp, connect, [Host, Port, TcpOptions]),
send_selected_port(Pid, Port, Socket),
- ct:print("ssl:connect(~p, ~p)~n", [Socket, SslOptions]),
+ ct:log("ssl:connect(~p, ~p)~n", [Socket, SslOptions]),
{ok, SslSocket} = rpc:call(Node, ssl, connect, [Socket, SslOptions]),
{Module, Function, Args} = proplists:get_value(mfa, Opts),
- ct:print("apply(~p, ~p, ~p)~n",
+ ct:log("apply(~p, ~p, ~p)~n",
[Module, Function, [SslSocket | Args]]),
Msg = rpc:call(Node, Module, Function, [SslSocket | Args]),
- ct:print("Upgrade Client Msg: ~p ~n", [Msg]),
+ ct:log("Upgrade Client Msg: ~p ~n", [Msg]),
Pid ! {self(), Msg},
receive
close ->
- ct:print("Upgrade Client closing~n", []),
+ ct:log("Upgrade Client closing~n", []),
rpc:call(Node, ssl, close, [SslSocket])
end.
@@ -535,20 +578,20 @@ run_upgrade_server_error(Opts) ->
SslOptions = proplists:get_value(ssl_options, Opts),
Pid = proplists:get_value(from, Opts),
- ct:print("gen_tcp:listen(~p, ~p)~n", [Port, TcpOptions]),
+ ct:log("gen_tcp:listen(~p, ~p)~n", [Port, TcpOptions]),
{ok, ListenSocket} = rpc:call(Node, gen_tcp, listen, [Port, TcpOptions]),
Pid ! {listen, up},
send_selected_port(Pid, Port, ListenSocket),
- ct:print("gen_tcp:accept(~p)~n", [ListenSocket]),
+ ct:log("gen_tcp:accept(~p)~n", [ListenSocket]),
{ok, AcceptSocket} = rpc:call(Node, gen_tcp, accept, [ListenSocket]),
Error = case TimeOut of
infinity ->
- ct:print("ssl:ssl_accept(~p, ~p)~n",
+ ct:log("ssl:ssl_accept(~p, ~p)~n",
[AcceptSocket, SslOptions]),
rpc:call(Node, ssl, ssl_accept,
[AcceptSocket, SslOptions]);
_ ->
- ct:print("ssl:ssl_accept(~p, ~p, ~p)~n",
+ ct:log("ssl:ssl_accept(~p, ~p, ~p)~n",
[AcceptSocket, SslOptions, TimeOut]),
rpc:call(Node, ssl, ssl_accept,
[AcceptSocket, SslOptions, TimeOut])
@@ -568,26 +611,26 @@ run_server_error(Opts) ->
Options = proplists:get_value(options, Opts),
Pid = proplists:get_value(from, Opts),
Transport = proplists:get_value(transport, Opts, ssl),
- ct:print("ssl:listen(~p, ~p)~n", [Port, Options]),
+ ct:log("ssl:listen(~p, ~p)~n", [Port, Options]),
case rpc:call(Node, Transport, listen, [Port, Options]) of
{ok, #sslsocket{} = ListenSocket} ->
%% To make sure error_client will
%% get {error, closed} and not {error, connection_refused}
Pid ! {listen, up},
send_selected_port(Pid, Port, ListenSocket),
- ct:print("ssl:transport_accept(~p)~n", [ListenSocket]),
+ ct:log("ssl:transport_accept(~p)~n", [ListenSocket]),
case rpc:call(Node, Transport, transport_accept, [ListenSocket]) of
{error, _} = Error ->
Pid ! {self(), Error};
{ok, AcceptSocket} ->
- ct:print("ssl:ssl_accept(~p)~n", [AcceptSocket]),
+ ct:log("ssl:ssl_accept(~p)~n", [AcceptSocket]),
Error = rpc:call(Node, ssl, ssl_accept, [AcceptSocket]),
Pid ! {self(), Error}
end;
{ok, ListenSocket} ->
Pid ! {listen, up},
send_selected_port(Pid, Port, ListenSocket),
- ct:print("~p:accept(~p)~n", [Transport, ListenSocket]),
+ ct:log("~p:accept(~p)~n", [Transport, ListenSocket]),
case rpc:call(Node, Transport, accept, [ListenSocket]) of
{error, _} = Error ->
Pid ! {self(), Error}
@@ -609,7 +652,7 @@ run_client_error(Opts) ->
Pid = proplists:get_value(from, Opts),
Transport = proplists:get_value(transport, Opts, ssl),
Options = proplists:get_value(options, Opts),
- ct:print("ssl:connect(~p, ~p, ~p)~n", [Host, Port, Options]),
+ ct:log("ssl:connect(~p, ~p, ~p)~n", [Host, Port, Options]),
Error = rpc:call(Node, Transport, connect, [Host, Port, Options]),
Pid ! {self(), Error}.
@@ -666,11 +709,16 @@ send_selected_port(Pid, 0, Socket) ->
send_selected_port(_,_,_) ->
ok.
-rsa_suites() ->
- lists:filter(fun({dhe_dss, _, _}) ->
- false;
+rsa_suites(CounterPart) ->
+ ECC = is_sane_ecc(CounterPart),
+ lists:filter(fun({rsa, _, _}) ->
+ true;
+ ({dhe_rsa, _, _}) ->
+ true;
+ ({ecdhe_rsa, _, _}) when ECC == true ->
+ true;
(_) ->
- true
+ false
end,
ssl:cipher_suites()).
@@ -690,17 +738,32 @@ dsa_suites() ->
end,
ssl:cipher_suites()).
+ecdsa_suites() ->
+ lists:filter(fun({ecdhe_ecdsa, _, _}) ->
+ true;
+ (_) ->
+ false
+ end,
+ ssl:cipher_suites()).
+
+ecdh_rsa_suites() ->
+ lists:filter(fun({ecdh_rsa, _, _}) ->
+ true;
+ (_) ->
+ false
+ end,
+ ssl:cipher_suites()).
openssl_rsa_suites() ->
Ciphers = ssl:cipher_suites(openssl),
lists:filter(fun(Str) ->
- case re:run(Str,"DSS",[]) of
+ case re:run(Str,"DSS|ECDH-RSA|ECDSA",[]) of
nomatch ->
true;
_ ->
false
end
- end, Ciphers).
+ end, Ciphers).
openssl_dsa_suites() ->
Ciphers = ssl:cipher_suites(openssl),
@@ -713,18 +776,56 @@ openssl_dsa_suites() ->
end
end, Ciphers).
+openssl_ecdsa_suites() ->
+ Ciphers = ssl:cipher_suites(openssl),
+ lists:filter(fun(Str) ->
+ case re:run(Str,"ECDHE-ECDSA",[]) of
+ nomatch ->
+ false;
+ _ ->
+ true
+ end
+ end, Ciphers).
+
+openssl_ecdh_rsa_suites() ->
+ Ciphers = ssl:cipher_suites(openssl),
+ lists:filter(fun(Str) ->
+ case re:run(Str,"ECDH-RSA",[]) of
+ nomatch ->
+ false;
+ _ ->
+ true
+ end
+ end, Ciphers).
+
anonymous_suites() ->
- [{dh_anon, rc4_128, md5},
- {dh_anon, des_cbc, sha},
- {dh_anon, '3des_ede_cbc', sha},
- {dh_anon, aes_128_cbc, sha},
- {dh_anon, aes_256_cbc, sha}].
+ Suites =
+ [{dh_anon, rc4_128, md5},
+ {dh_anon, des_cbc, sha},
+ {dh_anon, '3des_ede_cbc', sha},
+ {dh_anon, aes_128_cbc, sha},
+ {dh_anon, aes_256_cbc, sha},
+ {ecdh_anon,rc4_128,sha},
+ {ecdh_anon,'3des_ede_cbc',sha},
+ {ecdh_anon,aes_128_cbc,sha},
+ {ecdh_anon,aes_256_cbc,sha}],
+ ssl_cipher:filter_suites(Suites).
psk_suites() ->
- [{rsa_psk, rc4_128, sha},
- {rsa_psk, '3des_ede_cbc', sha},
- {rsa_psk, aes_128_cbc, sha},
- {rsa_psk, aes_256_cbc, sha}].
+ Suites =
+ [{psk, rc4_128, sha},
+ {psk, '3des_ede_cbc', sha},
+ {psk, aes_128_cbc, sha},
+ {psk, aes_256_cbc, sha},
+ {dhe_psk, rc4_128, sha},
+ {dhe_psk, '3des_ede_cbc', sha},
+ {dhe_psk, aes_128_cbc, sha},
+ {dhe_psk, aes_256_cbc, sha},
+ {rsa_psk, rc4_128, sha},
+ {rsa_psk, '3des_ede_cbc', sha},
+ {rsa_psk, aes_128_cbc, sha},
+ {rsa_psk, aes_256_cbc, sha}],
+ ssl_cipher:filter_suites(Suites).
psk_anon_suites() ->
[{psk, rc4_128, sha},
@@ -737,9 +838,14 @@ psk_anon_suites() ->
{dhe_psk, aes_256_cbc, sha}].
srp_suites() ->
- [{srp_rsa, '3des_ede_cbc', sha},
- {srp_rsa, aes_128_cbc, sha},
- {srp_rsa, aes_256_cbc, sha}].
+ Suites =
+ [{srp_anon, '3des_ede_cbc', sha},
+ {srp_rsa, '3des_ede_cbc', sha},
+ {srp_anon, aes_128_cbc, sha},
+ {srp_rsa, aes_128_cbc, sha},
+ {srp_anon, aes_256_cbc, sha},
+ {srp_rsa, aes_256_cbc, sha}],
+ ssl_cipher:filter_suites(Suites).
srp_anon_suites() ->
[{srp_anon, '3des_ede_cbc', sha},
@@ -747,9 +853,11 @@ srp_anon_suites() ->
{srp_anon, aes_256_cbc, sha}].
srp_dss_suites() ->
- [{srp_dss, '3des_ede_cbc', sha},
- {srp_dss, aes_128_cbc, sha},
- {srp_dss, aes_256_cbc, sha}].
+ Suites =
+ [{srp_dss, '3des_ede_cbc', sha},
+ {srp_dss, aes_128_cbc, sha},
+ {srp_dss, aes_256_cbc, sha}],
+ ssl_cipher:filter_suites(Suites).
pem_to_der(File) ->
{ok, PemBin} = file:read_file(File),
@@ -761,7 +869,7 @@ der_to_pem(File, Entries) ->
cipher_result(Socket, Result) ->
Result = ssl:connection_info(Socket),
- ct:print("Successfull connect: ~p~n", [Result]),
+ ct:log("Successfull connect: ~p~n", [Result]),
%% Importante to send two packets here
%% to properly test "cipher state" handling
ssl:send(Socket, "Hello\n"),
@@ -831,15 +939,9 @@ init_tls_version(Version) ->
ssl:start().
sufficient_crypto_support('tlsv1.2') ->
- Data = "Sampl",
- Data2 = "e #1",
- Key = <<0,1,2,3,16,17,18,19,32,33,34,35,48,49,50,51,4,5,6,7,20,21,22,23,36,37,38,39,
- 52,53,54,55,8,9,10,11,24,25,26,27,40,41,42,43,56,57,58,59>>,
- try
- crypto:sha256_mac(Key, lists:flatten([Data, Data2])),
- true
- catch _:_ -> false
- end;
+ proplists:get_bool(sha256, crypto:algorithms());
+sufficient_crypto_support(ciphers_ec) ->
+ proplists:get_bool(ec, crypto:algorithms());
sufficient_crypto_support(_) ->
true.
@@ -872,3 +974,35 @@ send_recv_result_active_once(Socket) ->
{ssl, Socket, "Hello world"} ->
ok
end.
+
+is_sane_ecc(openssl) ->
+ case os:cmd("openssl version") of
+ "OpenSSL 1.0.0a" ++ _ -> % Known bug in openssl
+ %% manifests as SSL_CHECK_SERVERHELLO_TLSEXT:tls invalid ecpointformat list
+ false;
+ "OpenSSL 1.0.0" ++ _ -> % Known bug in openssl
+ %% manifests as SSL_CHECK_SERVERHELLO_TLSEXT:tls invalid ecpointformat list
+ false;
+ "OpenSSL 0.9.8" ++ _ -> % Does not support ECC
+ false;
+ "OpenSSL 0.9.7" ++ _ -> % Does not support ECC
+ false;
+ _ ->
+ true
+ end;
+is_sane_ecc(_) ->
+ true.
+
+cipher_restriction(Config0) ->
+ case is_sane_ecc(openssl) of
+ false ->
+ Opts = proplists:get_value(server_opts, Config0),
+ Config1 = proplists:delete(server_opts, Config0),
+ VerOpts = proplists:get_value(server_verification_opts, Config1),
+ Config = proplists:delete(server_verification_opts, Config1),
+ Restricted0 = ssl:cipher_suites() -- ecdsa_suites(),
+ Restricted = Restricted0 -- ecdh_rsa_suites(),
+ [{server_opts, [{ciphers, Restricted} | Opts]}, {server_verification_opts, [{ciphers, Restricted} | VerOpts] } | Config];
+ true ->
+ Config0
+ end.
diff --git a/lib/ssl/test/ssl_to_openssl_SUITE.erl b/lib/ssl/test/ssl_to_openssl_SUITE.erl
index a3d382f837..075b4b1ec4 100644
--- a/lib/ssl/test/ssl_to_openssl_SUITE.erl
+++ b/lib/ssl/test/ssl_to_openssl_SUITE.erl
@@ -104,10 +104,11 @@ init_per_suite(Config0) ->
Result =
(catch make_certs:all(?config(data_dir, Config0),
?config(priv_dir, Config0))),
- ct:print("Make certs ~p~n", [Result]),
+ ct:log("Make certs ~p~n", [Result]),
Config1 = ssl_test_lib:make_dsa_cert(Config0),
Config = ssl_test_lib:cert_options(Config1),
- [{watchdog, Dog} | Config]
+ NewConfig = [{watchdog, Dog} | Config],
+ ssl_test_lib:cipher_restriction(NewConfig)
catch _:_ ->
{skip, "Crypto did not start"}
end
@@ -200,7 +201,7 @@ basic_erlang_client_openssl_server(Config) when is_list(Config) ->
Cmd = "openssl s_server -accept " ++ integer_to_list(Port) ++
" -cert " ++ CertFile ++ " -key " ++ KeyFile,
- ct:print("openssl cmd: ~p~n", [Cmd]),
+ ct:log("openssl cmd: ~p~n", [Cmd]),
OpensslPort = open_port({spawn, Cmd}, [stderr_to_stdout]),
@@ -212,7 +213,7 @@ basic_erlang_client_openssl_server(Config) when is_list(Config) ->
{mfa, {?MODULE,
erlang_ssl_receive, [Data]}},
{options, ClientOpts}]),
- port_command(OpensslPort, Data),
+ true = port_command(OpensslPort, Data),
ssl_test_lib:check_result(Client, ok),
@@ -241,10 +242,10 @@ basic_erlang_server_openssl_client(Config) when is_list(Config) ->
Cmd = "openssl s_client -port " ++ integer_to_list(Port) ++
" -host localhost",
- ct:print("openssl cmd: ~p~n", [Cmd]),
+ ct:log("openssl cmd: ~p~n", [Cmd]),
OpenSslPort = open_port({spawn, Cmd}, [stderr_to_stdout]),
- port_command(OpenSslPort, Data),
+ true = port_command(OpenSslPort, Data),
ssl_test_lib:check_result(Server, ok),
@@ -272,7 +273,7 @@ erlang_client_openssl_server(Config) when is_list(Config) ->
Cmd = "openssl s_server -accept " ++ integer_to_list(Port) ++ version_flag(Version) ++
" -cert " ++ CertFile ++ " -key " ++ KeyFile,
- ct:print("openssl cmd: ~p~n", [Cmd]),
+ ct:log("openssl cmd: ~p~n", [Cmd]),
OpensslPort = open_port({spawn, Cmd}, [stderr_to_stdout]),
@@ -284,7 +285,7 @@ erlang_client_openssl_server(Config) when is_list(Config) ->
{mfa, {?MODULE,
erlang_ssl_receive, [Data]}},
{options, ClientOpts}]),
- port_command(OpensslPort, Data),
+ true = port_command(OpensslPort, Data),
ssl_test_lib:check_result(Client, ok),
@@ -314,10 +315,10 @@ erlang_server_openssl_client(Config) when is_list(Config) ->
Cmd = "openssl s_client -port " ++ integer_to_list(Port) ++ version_flag(Version) ++
" -host localhost",
- ct:print("openssl cmd: ~p~n", [Cmd]),
+ ct:log("openssl cmd: ~p~n", [Cmd]),
OpenSslPort = open_port({spawn, Cmd}, [stderr_to_stdout]),
- port_command(OpenSslPort, Data),
+ true = port_command(OpenSslPort, Data),
ssl_test_lib:check_result(Server, ok),
@@ -349,7 +350,7 @@ erlang_client_openssl_server_dsa_cert(Config) when is_list(Config) ->
" -cert " ++ CertFile ++ " -CAfile " ++ CaCertFile
++ " -key " ++ KeyFile ++ " -Verify 2 -msg",
- ct:print("openssl cmd: ~p~n", [Cmd]),
+ ct:log("openssl cmd: ~p~n", [Cmd]),
OpensslPort = open_port({spawn, Cmd}, [stderr_to_stdout]),
@@ -362,7 +363,7 @@ erlang_client_openssl_server_dsa_cert(Config) when is_list(Config) ->
erlang_ssl_receive, [Data]}},
{options, ClientOpts}]),
- port_command(OpensslPort, Data),
+ true = port_command(OpensslPort, Data),
ssl_test_lib:check_result(Client, ok),
@@ -396,10 +397,10 @@ erlang_server_openssl_client_dsa_cert(Config) when is_list(Config) ->
" -host localhost " ++ " -cert " ++ CertFile ++ " -CAfile " ++ CaCertFile
++ " -key " ++ KeyFile ++ " -msg",
- ct:print("openssl cmd: ~p~n", [Cmd]),
+ ct:log("openssl cmd: ~p~n", [Cmd]),
OpenSslPort = open_port({spawn, Cmd}, [stderr_to_stdout]),
- port_command(OpenSslPort, Data),
+ true = port_command(OpenSslPort, Data),
ssl_test_lib:check_result(Server, ok),
@@ -431,11 +432,11 @@ erlang_server_openssl_client_reuse_session(Config) when is_list(Config) ->
Cmd = "openssl s_client -port " ++ integer_to_list(Port) ++ version_flag(Version) ++
" -host localhost -reconnect",
- ct:print("openssl cmd: ~p~n", [Cmd]),
+ ct:log("openssl cmd: ~p~n", [Cmd]),
OpenSslPort = open_port({spawn, Cmd}, [stderr_to_stdout]),
- port_command(OpenSslPort, Data),
+ true = port_command(OpenSslPort, Data),
ssl_test_lib:check_result(Server, ok),
@@ -467,7 +468,7 @@ erlang_client_openssl_server_renegotiate(Config) when is_list(Config) ->
Cmd = "openssl s_server -accept " ++ integer_to_list(Port) ++ version_flag(Version) ++
" -cert " ++ CertFile ++ " -key " ++ KeyFile ++ " -msg",
- ct:print("openssl cmd: ~p~n", [Cmd]),
+ ct:log("openssl cmd: ~p~n", [Cmd]),
OpensslPort = open_port({spawn, Cmd}, [stderr_to_stdout]),
@@ -480,9 +481,9 @@ erlang_client_openssl_server_renegotiate(Config) when is_list(Config) ->
delayed_send, [[ErlData, OpenSslData]]}},
{options, ClientOpts}]),
- port_command(OpensslPort, ?OPENSSL_RENEGOTIATE),
+ true = port_command(OpensslPort, ?OPENSSL_RENEGOTIATE),
ct:sleep(?SLEEP),
- port_command(OpensslPort, OpenSslData),
+ true = port_command(OpensslPort, OpenSslData),
ssl_test_lib:check_result(Client, ok),
@@ -516,7 +517,7 @@ erlang_client_openssl_server_nowrap_seqnum(Config) when is_list(Config) ->
Cmd = "openssl s_server -accept " ++ integer_to_list(Port) ++ version_flag(Version) ++
" -cert " ++ CertFile ++ " -key " ++ KeyFile ++ " -msg",
- ct:print("openssl cmd: ~p~n", [Cmd]),
+ ct:log("openssl cmd: ~p~n", [Cmd]),
OpensslPort = open_port({spawn, Cmd}, [stderr_to_stdout]),
@@ -562,11 +563,11 @@ erlang_server_openssl_client_nowrap_seqnum(Config) when is_list(Config) ->
Cmd = "openssl s_client -port " ++ integer_to_list(Port) ++ version_flag(Version) ++
" -host localhost -msg",
- ct:print("openssl cmd: ~p~n", [Cmd]),
+ ct:log("openssl cmd: ~p~n", [Cmd]),
OpenSslPort = open_port({spawn, Cmd}, [stderr_to_stdout]),
- port_command(OpenSslPort, Data),
+ true = port_command(OpenSslPort, Data),
ssl_test_lib:check_result(Server, ok),
@@ -597,7 +598,7 @@ erlang_client_openssl_server_no_server_ca_cert(Config) when is_list(Config) ->
Cmd = "openssl s_server -accept " ++ integer_to_list(Port) ++ version_flag(Version) ++
" -cert " ++ CertFile ++ " -key " ++ KeyFile ++ " -msg",
- ct:print("openssl cmd: ~p~n", [Cmd]),
+ ct:log("openssl cmd: ~p~n", [Cmd]),
OpensslPort = open_port({spawn, Cmd}, [stderr_to_stdout]),
@@ -610,7 +611,7 @@ erlang_client_openssl_server_no_server_ca_cert(Config) when is_list(Config) ->
erlang_ssl_receive, [Data]}},
{options, ClientOpts}]),
- port_command(OpensslPort, Data),
+ true = port_command(OpensslPort, Data),
ssl_test_lib:check_result(Client, ok),
@@ -640,7 +641,7 @@ erlang_client_openssl_server_client_cert(Config) when is_list(Config) ->
" -cert " ++ CertFile ++ " -CAfile " ++ CaCertFile
++ " -key " ++ KeyFile ++ " -Verify 2",
- ct:print("openssl cmd: ~p~n", [Cmd]),
+ ct:log("openssl cmd: ~p~n", [Cmd]),
OpensslPort = open_port({spawn, Cmd}, [stderr_to_stdout]),
@@ -652,7 +653,7 @@ erlang_client_openssl_server_client_cert(Config) when is_list(Config) ->
{mfa, {?MODULE,
erlang_ssl_receive, [Data]}},
{options, ClientOpts}]),
- port_command(OpensslPort, Data),
+ true = port_command(OpensslPort, Data),
ssl_test_lib:check_result(Client, ok),
@@ -691,10 +692,10 @@ erlang_server_openssl_client_client_cert(Config) when is_list(Config) ->
++ " -key " ++ KeyFile ++ " -port " ++ integer_to_list(Port) ++ version_flag(Version) ++
" -host localhost",
- ct:print("openssl cmd: ~p~n", [Cmd]),
+ ct:log("openssl cmd: ~p~n", [Cmd]),
OpenSslPort = open_port({spawn, Cmd}, [stderr_to_stdout]),
- port_command(OpenSslPort, Data),
+ true = port_command(OpenSslPort, Data),
ssl_test_lib:check_result(Server, ok),
@@ -749,7 +750,7 @@ ciphers_rsa_signed_certs(Config) when is_list(Config) ->
Version =
ssl_record:protocol_version(ssl_record:highest_protocol_version([])),
- Ciphers = ssl_test_lib:rsa_suites(),
+ Ciphers = ssl_test_lib:rsa_suites(openssl),
run_suites(Ciphers, Version, Config, rsa).
%%--------------------------------------------------------------------
@@ -779,7 +780,7 @@ erlang_client_bad_openssl_server(Config) when is_list(Config) ->
Cmd = "openssl s_server -accept " ++ integer_to_list(Port) ++ version_flag(Version) ++
" -cert " ++ CertFile ++ " -key " ++ KeyFile ++ "",
- ct:print("openssl cmd: ~p~n", [Cmd]),
+ ct:log("openssl cmd: ~p~n", [Cmd]),
OpensslPort = open_port({spawn, Cmd}, [stderr_to_stdout]),
@@ -793,7 +794,7 @@ erlang_client_bad_openssl_server(Config) when is_list(Config) ->
[{versions, [Version]} | ClientOpts]}]),
%% Send garbage
- port_command(OpensslPort, ?OPENSSL_GARBAGE),
+ true = port_command(OpensslPort, ?OPENSSL_GARBAGE),
ct:sleep(?SLEEP),
@@ -835,7 +836,7 @@ expired_session(Config) when is_list(Config) ->
Cmd = "openssl s_server -accept " ++ integer_to_list(Port) ++
" -cert " ++ CertFile ++ " -key " ++ KeyFile ++ "",
- ct:print("openssl cmd: ~p~n", [Cmd]),
+ ct:log("openssl cmd: ~p~n", [Cmd]),
OpensslPort = open_port({spawn, Cmd}, [stderr_to_stdout]),
@@ -893,10 +894,10 @@ ssl2_erlang_server_openssl_client(Config) when is_list(Config) ->
Cmd = "openssl s_client -port " ++ integer_to_list(Port) ++
" -host localhost -ssl2 -msg",
- ct:print("openssl cmd: ~p~n", [Cmd]),
+ ct:log("openssl cmd: ~p~n", [Cmd]),
OpenSslPort = open_port({spawn, Cmd}, [stderr_to_stdout]),
- port_command(OpenSslPort, Data),
+ true = port_command(OpenSslPort, Data),
receive
{'EXIT', OpenSslPort, _} ->
ok
@@ -912,7 +913,7 @@ erlang_client_openssl_server_npn() ->
erlang_client_openssl_server_npn(Config) when is_list(Config) ->
Data = "From openssl to erlang",
start_erlang_client_and_openssl_server_for_npn_negotiation(Config, Data, fun(Client, OpensslPort) ->
- port_command(OpensslPort, Data),
+ true = port_command(OpensslPort, Data),
ssl_test_lib:check_result(Client, ok)
end),
@@ -925,9 +926,9 @@ erlang_client_openssl_server_npn_renegotiate() ->
erlang_client_openssl_server_npn_renegotiate(Config) when is_list(Config) ->
Data = "From openssl to erlang",
start_erlang_client_and_openssl_server_for_npn_negotiation(Config, Data, fun(Client, OpensslPort) ->
- port_command(OpensslPort, ?OPENSSL_RENEGOTIATE),
+ true = port_command(OpensslPort, ?OPENSSL_RENEGOTIATE),
ct:sleep(?SLEEP),
- port_command(OpensslPort, Data),
+ true = port_command(OpensslPort, Data),
ssl_test_lib:check_result(Client, ok)
end),
ok.
@@ -939,7 +940,7 @@ erlang_server_openssl_client_npn(Config) when is_list(Config) ->
Data = "From openssl to erlang",
start_erlang_server_and_openssl_client_for_npn_negotiation(Config, Data, fun(Server, OpensslPort) ->
- port_command(OpensslPort, Data),
+ true = port_command(OpensslPort, Data),
ssl_test_lib:check_result(Server, ok)
end),
ok.
@@ -951,9 +952,9 @@ erlang_server_openssl_client_npn_renegotiate() ->
erlang_server_openssl_client_npn_renegotiate(Config) when is_list(Config) ->
Data = "From openssl to erlang",
start_erlang_server_and_openssl_client_for_npn_negotiation(Config, Data, fun(Server, OpensslPort) ->
- port_command(OpensslPort, ?OPENSSL_RENEGOTIATE),
+ true = port_command(OpensslPort, ?OPENSSL_RENEGOTIATE),
ct:sleep(?SLEEP),
- port_command(OpensslPort, Data),
+ true = port_command(OpensslPort, Data),
ssl_test_lib:check_result(Server, ok)
end),
ok.
@@ -962,7 +963,7 @@ erlang_client_openssl_server_npn_only_server(Config) when is_list(Config) ->
Data = "From openssl to erlang",
start_erlang_client_and_openssl_server_with_opts(Config, [],
"-nextprotoneg spdy/2", Data, fun(Server, OpensslPort) ->
- port_command(OpensslPort, Data),
+ true = port_command(OpensslPort, Data),
ssl_test_lib:check_result(Server, ok)
end),
ok.
@@ -975,7 +976,7 @@ erlang_client_openssl_server_npn_only_client(Config) when is_list(Config) ->
[{client_preferred_next_protocols,
{client, [<<"spdy/2">>], <<"http/1.1">>}}], "",
Data, fun(Server, OpensslPort) ->
- port_command(OpensslPort, Data),
+ true = port_command(OpensslPort, Data),
ssl_test_lib:check_result(Server, ok)
end),
ok.
@@ -985,7 +986,7 @@ erlang_server_openssl_client_npn_only_server(Config) when is_list(Config) ->
Data = "From openssl to erlang",
start_erlang_server_and_openssl_client_with_opts(Config, [{next_protocols_advertised, [<<"spdy/2">>]}], "",
Data, fun(Server, OpensslPort) ->
- port_command(OpensslPort, Data),
+ true = port_command(OpensslPort, Data),
ssl_test_lib:check_result(Server, ok)
end),
ok.
@@ -994,7 +995,7 @@ erlang_server_openssl_client_npn_only_client(Config) when is_list(Config) ->
Data = "From openssl to erlang",
start_erlang_server_and_openssl_client_with_opts(Config, [], "-nextprotoneg spdy/2",
Data, fun(Server, OpensslPort) ->
- port_command(OpensslPort, Data),
+ true = port_command(OpensslPort, Data),
ssl_test_lib:check_result(Server, ok)
end),
ok.
@@ -1020,13 +1021,13 @@ run_suites(Ciphers, Version, Config, Type) ->
[] ->
ok;
Error ->
- ct:print("Cipher suite errors: ~p~n", [Error]),
+ ct:log("Cipher suite errors: ~p~n", [Error]),
ct:fail(cipher_suite_failed_see_test_case_log)
end.
cipher(CipherSuite, Version, Config, ClientOpts, ServerOpts) ->
process_flag(trap_exit, true),
- ct:print("Testing CipherSuite ~p~n", [CipherSuite]),
+ ct:log("Testing CipherSuite ~p~n", [CipherSuite]),
{ClientNode, _ServerNode, Hostname} = ssl_test_lib:run_where(Config),
Port = ssl_test_lib:inet_port(node()),
@@ -1036,7 +1037,7 @@ cipher(CipherSuite, Version, Config, ClientOpts, ServerOpts) ->
Cmd = "openssl s_server -accept " ++ integer_to_list(Port) ++ version_flag(Version) ++
" -cert " ++ CertFile ++ " -key " ++ KeyFile ++ "",
- ct:print("openssl cmd: ~p~n", [Cmd]),
+ ct:log("openssl cmd: ~p~n", [Cmd]),
OpenSslPort = open_port({spawn, Cmd}, [stderr_to_stdout]),
@@ -1052,19 +1053,19 @@ cipher(CipherSuite, Version, Config, ClientOpts, ServerOpts) ->
[{ciphers,[CipherSuite]} |
ClientOpts]}]),
- port_command(OpenSslPort, "Hello\n"),
+ true = port_command(OpenSslPort, "Hello\n"),
receive
{Port, {data, _}} when is_port(Port) ->
ok
after 500 ->
- ct:print("Time out on openssl port, check that"
+ ct:log("Time out on openssl port, check that"
" the messages Hello and world are received"
" during close of port" , []),
ok
end,
- port_command(OpenSslPort, " world\n"),
+ true = port_command(OpenSslPort, " world\n"),
Result = ssl_test_lib:wait_for_result(Client, ok),
@@ -1100,7 +1101,7 @@ start_erlang_client_and_openssl_server_with_opts(Config, ErlangClientOpts, Opens
integer_to_list(Port) ++ version_flag(Version) ++
" -cert " ++ CertFile ++ " -key " ++ KeyFile,
- ct:print("openssl cmd: ~p~n", [Cmd]),
+ ct:log("openssl cmd: ~p~n", [Cmd]),
OpensslPort = open_port({spawn, Cmd}, [stderr_to_stdout]),
@@ -1139,7 +1140,7 @@ start_erlang_client_and_openssl_server_for_npn_negotiation(Config, Data, Callbac
Cmd = "openssl s_server -msg -nextprotoneg http/1.1,spdy/2 -accept " ++ integer_to_list(Port) ++ version_flag(Version) ++
" -cert " ++ CertFile ++ " -key " ++ KeyFile,
- ct:print("openssl cmd: ~p~n", [Cmd]),
+ ct:log("openssl cmd: ~p~n", [Cmd]),
OpensslPort = open_port({spawn, Cmd}, [stderr_to_stdout]),
@@ -1177,7 +1178,7 @@ start_erlang_server_and_openssl_client_for_npn_negotiation(Config, Data, Callbac
Cmd = "openssl s_client -nextprotoneg http/1.0,spdy/2 -msg -port " ++ integer_to_list(Port) ++ version_flag(Version) ++
" -host localhost",
- ct:print("openssl cmd: ~p~n", [Cmd]),
+ ct:log("openssl cmd: ~p~n", [Cmd]),
OpenSslPort = open_port({spawn, Cmd}, [stderr_to_stdout]),
@@ -1206,7 +1207,7 @@ start_erlang_server_and_openssl_client_with_opts(Config, ErlangServerOpts, OpenS
Cmd = "openssl s_client " ++ OpenSSLClientOpts ++ " -msg -port " ++ integer_to_list(Port) ++ version_flag(Version) ++
" -host localhost",
- ct:print("openssl cmd: ~p~n", [Cmd]),
+ ct:log("openssl cmd: ~p~n", [Cmd]),
OpenSslPort = open_port({spawn, Cmd}, [stderr_to_stdout]),
@@ -1225,7 +1226,7 @@ erlang_ssl_receive_and_assert_npn(Socket, Protocol, Data) ->
ok.
erlang_ssl_receive(Socket, Data) ->
- ct:print("Connection info: ~p~n",
+ ct:log("Connection info: ~p~n",
[ssl:connection_info(Socket)]),
receive
{ssl, Socket, Data} ->
@@ -1247,7 +1248,7 @@ erlang_ssl_receive(Socket, Data) ->
connection_info(Socket, Version) ->
case ssl:connection_info(Socket) of
{ok, {Version, _} = Info} ->
- ct:print("Connection info: ~p~n", [Info]),
+ ct:log("Connection info: ~p~n", [Info]),
ok;
{ok, {OtherVersion, _}} ->
{wrong_version, OtherVersion}
@@ -1269,28 +1270,28 @@ close_port(Port) ->
close_loop(Port, Time, SentClose) ->
receive
{Port, {data,Debug}} when is_port(Port) ->
- io:format("openssl ~s~n",[Debug]),
+ ct:log("openssl ~s~n",[Debug]),
close_loop(Port, Time, SentClose);
{ssl,_,Msg} ->
- io:format("ssl Msg ~s~n",[Msg]),
+ ct:log("ssl Msg ~s~n",[Msg]),
close_loop(Port, Time, SentClose);
{Port, closed} ->
- io:format("Port Closed~n",[]),
+ ct:log("Port Closed~n",[]),
ok;
{'EXIT', Port, Reason} ->
- io:format("Port Closed ~p~n",[Reason]),
+ ct:log("Port Closed ~p~n",[Reason]),
ok;
Msg ->
- io:format("Port Msg ~p~n",[Msg]),
+ ct:log("Port Msg ~p~n",[Msg]),
close_loop(Port, Time, SentClose)
after Time ->
case SentClose of
false ->
- io:format("Closing port ~n",[]),
+ ct:log("Closing port ~n",[]),
catch erlang:port_close(Port),
close_loop(Port, Time, true);
true ->
- io:format("Timeout~n",[])
+ ct:log("Timeout~n",[])
end
end.
@@ -1305,7 +1306,7 @@ server_sent_garbage(Socket) ->
wait_for_openssl_server() ->
receive
{Port, {data, Debug}} when is_port(Port) ->
- io:format("openssl ~s~n",[Debug]),
+ ct:log("openssl ~s~n",[Debug]),
%% openssl has started make sure
%% it will be in accept. Parsing
%% output is too error prone. (Even
diff --git a/lib/stdlib/src/epp.erl b/lib/stdlib/src/epp.erl
index e31cd63f69..d1d060ebc8 100644
--- a/lib/stdlib/src/epp.erl
+++ b/lib/stdlib/src/epp.erl
@@ -601,7 +601,7 @@ enter_file2(NewF, Pname, From, St0, AtLocation) ->
%% file will depend on the order of file inclusions in the parent files
Path = [filename:dirname(Pname) | tl(St0#epp.path)],
_ = set_encoding(NewF),
- #epp{file=NewF,location=Loc,name=Pname,delta=0,
+ #epp{file=NewF,location=Loc,name=Pname,name2=Pname,delta=0,
sstk=[St0|St0#epp.sstk],path=Path,macs=Ms}.
enter_file_reply(From, Name, Location, AtLocation) ->
diff --git a/lib/stdlib/src/erl_pp.erl b/lib/stdlib/src/erl_pp.erl
index 7c7566e4ec..c0596e5ba6 100644
--- a/lib/stdlib/src/erl_pp.erl
+++ b/lib/stdlib/src/erl_pp.erl
@@ -35,7 +35,7 @@
| fun((Expr :: erl_parse:abstract_expr(),
CurrentIndentation :: integer(),
CurrentPrecedence :: non_neg_integer(),
- HookFunction :: hook_function()) ->
+ Options :: options()) ->
io_lib:chars())).
-type(option() :: {hook, hook_function()}
@@ -225,7 +225,7 @@ lattribute(module, {M,Vs}, _Opts, _State) ->
lattribute(module, M, _Opts, _State) ->
attr("module", [{var,0,pname(M)}]);
lattribute(export, Falist, _Opts, _State) ->
- call({var,0,"-export"}, [falist(Falist)], 0, none);
+ call({var,0,"-export"}, [falist(Falist)], 0, options(none));
lattribute(import, Name, _Opts, _State) when is_list(Name) ->
attr("import", [{var,0,pname(Name)}]);
lattribute(import, {From,Falist}, _Opts, _State) ->
@@ -240,10 +240,10 @@ lattribute(Name, Arg, #options{encoding = Encoding}, _State) ->
typeattr(Tag, {TypeName,Type,Args}, _Opts) ->
{first,leaf("-"++atom_to_list(Tag)++" "),
- typed(call({atom,0,TypeName}, Args, 0, none), Type)}.
+ typed(call({atom,0,TypeName}, Args, 0, options(none)), Type)}.
ltype({ann_type,_Line,[V,T]}) ->
- typed(lexpr(V, none), T);
+ typed(lexpr(V, options(none)), T);
ltype({paren_type,_Line,[T]}) ->
[$(,ltype(T),$)];
ltype({type,_Line,union,Ts}) ->
@@ -253,7 +253,7 @@ ltype({type,_Line,list,[T]}) ->
ltype({type,_Line,nonempty_list,[T]}) ->
{seq,$[,$],[$,],[ltype(T),leaf("...")]};
ltype({type,Line,nil,[]}) ->
- lexpr({nil,Line}, 0, none);
+ lexpr({nil,Line}, 0, options(none));
ltype({type,Line,tuple,any}) ->
simple_type({atom,Line,tuple}, []);
ltype({type,_Line,tuple,Ts}) ->
@@ -261,7 +261,7 @@ ltype({type,_Line,tuple,Ts}) ->
ltype({type,_Line,record,[{atom,_,N}|Fs]}) ->
record_type(N, Fs);
ltype({type,_Line,range,[_I1,_I2]=Es}) ->
- expr_list(Es, '..', fun lexpr/2, none);
+ expr_list(Es, '..', fun lexpr/2, options(none));
ltype({type,_Line,binary,[I1,I2]}) ->
binary_type(I1, I2); % except binary()
ltype({type,_Line,'fun',[]}) ->
@@ -277,14 +277,14 @@ ltype({remote_type,Line,[M,F,Ts]}) ->
ltype({atom,_,T}) ->
leaf(write(T));
ltype(E) ->
- lexpr(E, 0, none).
+ lexpr(E, 0, options(none)).
binary_type(I1, I2) ->
B = [[] || {integer,_,0} <- [I1]] =:= [],
U = [[] || {integer,_,0} <- [I2]] =:= [],
P = max_prec(),
- E1 = [[leaf("_:"),lexpr(I1, P, none)] || B],
- E2 = [[leaf("_:_*"),lexpr(I2, P, none)] || U],
+ E1 = [[leaf("_:"),lexpr(I1, P, options(none))] || B],
+ E2 = [[leaf("_:_*"),lexpr(I2, P, options(none))] || U],
{seq,'<<','>>',[$,],E1++E2}.
record_type(Name, Fields) ->
@@ -294,7 +294,7 @@ field_types(Fs) ->
tuple_type(Fs, fun field_type/1).
field_type({type,_Line,field_type,[Name,Type]}) ->
- typed(lexpr(Name, none), Type).
+ typed(lexpr(Name, options(none)), Type).
typed(B, {type,_,union,Ts}) ->
%% Special layout for :: followed by union.
@@ -330,7 +330,8 @@ sig_type(FunType) ->
fun_type([], FunType).
guard_type(Before, Gs) ->
- Gl = {list,[{step,'when',expr_list(Gs, [$,], fun constraint/2, none)}]},
+ Opts = options(none),
+ Gl = {list,[{step,'when',expr_list(Gs, [$,], fun constraint/2, Opts)}]},
{list,[{step,Before,Gl}]}.
constraint({type,_Line,constraint,[Tag,As]}, _Opts) ->
@@ -345,7 +346,7 @@ type_args({type,_line,product,Ts}) ->
targs(Ts).
simple_type(Tag, Types) ->
- {first,lexpr(Tag, 0, none),targs(Types)}.
+ {first,lexpr(Tag, 0, options(none)),targs(Types)}.
targs(Ts) ->
{seq,$(,$),[$,],ltypes(Ts)}.
@@ -357,7 +358,7 @@ ltypes(Ts, F) ->
[F(T) || T <- Ts].
attr(Name, Args) ->
- call({var,0,format("-~s", [Name])}, Args, 0, none).
+ call({var,0,format("-~s", [Name])}, Args, 0, options(none)).
pname(['' | As]) ->
[$. | pname(As)];
@@ -632,11 +633,11 @@ bit_elem_types([T | Rest]) ->
[bit_elem_type(T), $-|bit_elem_types(Rest)].
bit_elem_type({A,B}) ->
- [lexpr(erl_parse:abstract(A), none),
+ [lexpr(erl_parse:abstract(A), options(none)),
$:,
- lexpr(erl_parse:abstract(B), none)];
+ lexpr(erl_parse:abstract(B), options(none))];
bit_elem_type(T) ->
- lexpr(erl_parse:abstract(T), none).
+ lexpr(erl_parse:abstract(T), options(none)).
%% end of BITS
diff --git a/lib/stdlib/src/otp_internal.erl b/lib/stdlib/src/otp_internal.erl
index a4f4035c79..f2849e50ec 100644
--- a/lib/stdlib/src/otp_internal.erl
+++ b/lib/stdlib/src/otp_internal.erl
@@ -66,6 +66,139 @@ obsolete_1(rpc, safe_multi_server_call, A) when A =:= 2; A =:= 3 ->
{deprecated, {rpc, multi_server_call, A}};
+%% *** CRYPTO add in R16B01 ***
+
+obsolete_1(crypto, md4, 1) ->
+ {deprecated, {crypto, hash, 2}};
+obsolete_1(crypto, md5, 1) ->
+ {deprecated, {crypto, hash, 2}};
+obsolete_1(crypto, sha, 1) ->
+ {deprecated, {crypto, hash, 2}};
+
+obsolete_1(crypto, md4_init, 1) ->
+ {deprecated, {crypto, hash_init, 2}};
+obsolete_1(crypto, md5_init, 1) ->
+ {deprecated, {crypto, hash_init, 2}};
+obsolete_1(crypto, sha_init, 1) ->
+ {deprecated, {crypto, hash_init, 2}};
+
+obsolete_1(crypto, md4_update, 2) ->
+ {deprecated, {crypto, hash_update, 3}};
+obsolete_1(crypto, md5_update, 2) ->
+ {deprecated, {crypto, hash_update, 3}};
+obsolete_1(crypto, sah_update, 2) ->
+ {deprecated, {crypto, hash_update, 3}};
+
+obsolete_1(crypto, md4_final, 1) ->
+ {deprecated, {crypto, hash_final, 2}};
+obsolete_1(crypto, md5_final, 1) ->
+ {deprecated, {crypto, hash_final, 2}};
+obsolete_1(crypto, sha_final, 1) ->
+ {deprecated, {crypto, hash_final, 2}};
+
+obsolete_1(crypto, md5_mac, 2) ->
+ {deprecated, {crypto, hmac, 3}};
+obsolete_1(crypto, sha_mac, 2) ->
+ {deprecated, {crypto, hmac, 3}};
+
+obsolete_1(crypto, sha_mac_96, 2) ->
+ {deprecated, {crypto, hmac_n, 3}};
+obsolete_1(crypto, md5_mac_96, 2) ->
+ {deprecated, {crypto, hmac_n, 3}};
+
+obsolete_1(crypto, rsa_sign, 3) ->
+ {deprecated, {crypto, sign, 4}};
+obsolete_1(crypto, rsa_verify, 3) ->
+ {deprecated, {crypto, verify, 4}};
+
+obsolete_1(crypto, dss_sign, 2) ->
+ {deprecated, {crypto, sign, 4}};
+obsolete_1(crypto, dss_sign, 3) ->
+ {deprecated, {crypto, sign, 4}};
+
+obsolete_1(crypto, dss_verify, 3) ->
+ {deprecated, {crypto, verify, 4}};
+obsolete_1(crypto, dss_verify, 4) ->
+ {deprecated, {crypto, verify, 4}};
+
+obsolete_1(crypto, mod_exp, 3) ->
+ {deprecated, {crypto, mod_pow, 3}};
+
+obsolete_1(crypto, dh_compute_key, 3) ->
+ {deprecated, {crypto, compute_key, 4}};
+obsolete_1(crypto, dh_generate_key, 1) ->
+ {deprecated, {crypto, generate_key, 3}};
+obsolete_1(crypto, dh_generate_key, 2) ->
+ {deprecated, {crypto, generate_key, 3}};
+
+obsolete_1(crypto, des_cbc_encrypt, 3) ->
+ {deprecated, {crypto, block_encrypt, 4}};
+obsolete_1(crypto, des3_cbc_encrypt, 5) ->
+ {deprecated, {crypto, block_encrypt, 4}};
+obsolete_1(crypto, des_ecb_encrypt, 3) ->
+ {deprecated, {crypto, block_encrypt, 4}};
+obsolete_1(crypto, des_ede3_cbc_encrypt, 5) ->
+ {deprecated, {crypto, block_encrypt, 4}};
+obsolete_1(crypto, des_cfb_encrypt, 3) ->
+ {deprecated, {crypto, block_encrypt, 4}};
+obsolete_1(crypto, des3_cfb_encrypt, 5) ->
+ {deprecated, {crypto, block_encrypt, 4}};
+obsolete_1(crypto, blowfish_ecb_encrypt, 2) ->
+ {deprecated, {crypto, block_encrypt, 3}};
+obsolete_1(crypto, blowfish_cbc_encrypt, 3) ->
+ {deprecated, {crypto, block_encrypt, 4}};
+obsolete_1(crypto, blowfish_cfb64_encrypt, 3) ->
+ {deprecated, {crypto, block_encrypt, 4}};
+obsolete_1(crypto, blowfish_ofb64_encrypt, 3) ->
+ {deprecated, {crypto, block_encrypt, 4}};
+obsolete_1(crypto, aes_cfb_128_encrypt, 3) ->
+ {deprecated, {crypto, block_encrypt, 4}};
+obsolete_1(crypto, aes_cbc_256_encrypt, 3) ->
+ {deprecated, {crypto, block_encrypt, 4}};
+obsolete_1(crypto,rc2_cbc_encrypt, 3) ->
+ {deprecated, {crypto, block_encrypt, 4}};
+obsolete_1(crypto,rc2_40_cbc_encrypt, 3) ->
+ {deprecated, {crypto, block_encrypt, 4}};
+
+obsolete_1(crypto, des_cbc_decrypt, 3) ->
+ {deprecated, {crypto, block_decrypt, 4}};
+obsolete_1(crypto, des3_cbc_decrypt, 5) ->
+ {deprecated, {crypto, block_decrypt, 4}};
+obsolete_1(crypto, des_ecb_decrypt, 3) ->
+ {deprecated, {crypto, block_decrypt, 4}};
+obsolete_1(crypto, des_ede3_cbc_decrypt, 5) ->
+ {deprecated, {crypto, block_decrypt, 4}};
+obsolete_1(crypto, des_cfb_decrypt, 3) ->
+ {deprecated, {crypto, block_decrypt, 4}};
+obsolete_1(crypto, des3_cfb_decrypt, 5) ->
+ {deprecated, {crypto, block_decrypt, 4}};
+obsolete_1(crypto, blowfish_ecb_decrypt, 2) ->
+ {deprecated, {crypto, block_decrypt, 3}};
+obsolete_1(crypto, blowfish_cbc_decrypt, 3) ->
+ {deprecated, {crypto, block_decrypt, 4}};
+obsolete_1(crypto, blowfish_cfb64_decrypt, 3) ->
+ {deprecated, {crypto, block_decrypt, 4}};
+obsolete_1(crypto, blowfish_ofb64_decrypt, 3) ->
+ {deprecated, {crypto, block_decrypt, 4}};
+obsolete_1(crypto, aes_cfb_128_decrypt, 3) ->
+ {deprecated, {crypto, block_decrypt, 4}};
+obsolete_1(crypto, aes_cbc_256_decrypt, 3) ->
+ {deprecated, {crypto, block_decrypt, 4}};
+obsolete_1(crypto,rc2_cbc_decrypt, 3) ->
+ {deprecated, {crypto, block_decrypt, 4}};
+obsolete_1(crypto,rc2_40_cbc_decrypt, 3) ->
+ {deprecated, {crypto, block_decrypt, 4}};
+
+obsolete_1(crypto,info, 0) ->
+ {deprecated, {crypto, module_info, 0}};
+
+obsolete_1(crypto, strong_rand_mpint, 3) ->
+ {deprecated, "needed only by deprecated functions"};
+obsolete_1(crypto, erlint, 3) ->
+ {deprecated, "needed only by deprecated functions"};
+obsolete_1(crypto, mpint, 3) ->
+ {deprecated, "needed only by deprecated functions"};
+
%% *** SNMP ***
obsolete_1(snmp, N, A) ->
diff --git a/lib/stdlib/test/epp_SUITE.erl b/lib/stdlib/test/epp_SUITE.erl
index b2f1aa955a..0cbdf76270 100644
--- a/lib/stdlib/test/epp_SUITE.erl
+++ b/lib/stdlib/test/epp_SUITE.erl
@@ -104,6 +104,8 @@ include_local(suite) ->
include_local(Config) when is_list(Config) ->
?line DataDir = ?config(data_dir, Config),
?line File = filename:join(DataDir, "include_local.erl"),
+ FooHrl = filename:join([DataDir,"include","foo.hrl"]),
+ BarHrl = filename:join([DataDir,"include","bar.hrl"]),
%% include_local.erl includes include/foo.hrl which
%% includes bar.hrl (also in include/) without requiring
%% any additional include path, and overriding any file
@@ -111,6 +113,8 @@ include_local(Config) when is_list(Config) ->
?line {ok, List} = epp:parse_file(File, [DataDir], []),
?line {value, {attribute,_,a,{true,true}}} =
lists:keysearch(a,3,List),
+ [{File,1},{FooHrl,1},{BarHrl,1},{FooHrl,5},{File,5}] =
+ [ FileLine || {attribute,_,file,FileLine} <- List ],
ok.
%%% Here is a little reimplementation of epp:parse_file, which times out
diff --git a/lib/stdlib/test/erl_pp_SUITE.erl b/lib/stdlib/test/erl_pp_SUITE.erl
index 9c0a43abcc..ff3470349e 100644
--- a/lib/stdlib/test/erl_pp_SUITE.erl
+++ b/lib/stdlib/test/erl_pp_SUITE.erl
@@ -49,7 +49,7 @@
otp_6321/1, otp_6911/1, otp_6914/1, otp_8150/1, otp_8238/1,
otp_8473/1, otp_8522/1, otp_8567/1, otp_8664/1, otp_9147/1,
- otp_10302/1, otp_10820/1]).
+ otp_10302/1, otp_10820/1, otp_11100/1]).
%% Internal export.
-export([ehook/6]).
@@ -81,7 +81,7 @@ groups() ->
{tickets, [],
[otp_6321, otp_6911, otp_6914, otp_8150, otp_8238,
otp_8473, otp_8522, otp_8567, otp_8664, otp_9147,
- otp_10302, otp_10820]}].
+ otp_10302, otp_10820, otp_11100]}].
init_per_suite(Config) ->
Config.
@@ -1103,6 +1103,45 @@ file_attr_is_string("-file(\"" ++ _) -> true;
file_attr_is_string([_ | L]) ->
file_attr_is_string(L).
+otp_11100(doc) ->
+ "OTP-11100. Fix printing of invalid forms.";
+otp_11100(suite) -> [];
+otp_11100(Config) when is_list(Config) ->
+ %% There are a few places where the added code ("options(none)")
+ %% doesn't make a difference (pp:bit_elem_type/1 is an example).
+
+ %% Cannot trigger the use of the hook function with export/import.
+ "-export([{fy,a}/b]).\n" =
+ pf({attribute,1,export,[{{fy,a},b}]}),
+ "-type foo() :: integer(INVALID-FORM:{foo,bar}:).\n" =
+ pf({attribute,1,type,{foo,{type,1,integer,[{foo,bar}]},[]}}),
+ pf({attribute,1,type,
+ {a,{type,1,range,[{integer,1,1},{foo,bar}]},[]}}),
+ "-type foo(INVALID-FORM:{foo,bar}:) :: A.\n" =
+ pf({attribute,1,type,{foo,{var,1,'A'},[{foo,bar}]}}),
+ "-type foo() :: (INVALID-FORM:{foo,bar}: :: []).\n" =
+ pf({attribute,1,type,
+ {foo,{paren_type,1,
+ [{ann_type,1,[{foo,bar},{type,1,nil,[]}]}]},
+ []}}),
+ "-type foo() :: <<_:INVALID-FORM:{foo,bar}:>>.\n" =
+ pf({attribute,1,type,
+ {foo,{type,1,binary,[{foo,bar},{integer,1,0}]},[]}}),
+ "-type foo() :: <<_:10, _:_*INVALID-FORM:{foo,bar}:>>.\n" =
+ pf({attribute,1,type,
+ {foo,{type,1,binary,[{integer,1,10},{foo,bar}]},[]}}),
+ "-type foo() :: #r{INVALID-FORM:{foo,bar}: :: integer()}.\n" =
+ pf({attribute,1,type,
+ {foo,{type,1,record,
+ [{atom,1,r},
+ {type,1,field_type,
+ [{foo,bar},{type,1,integer,[]}]}]},
+ []}}),
+ ok.
+
+pf(Form) ->
+ lists:flatten(erl_pp:form(Form,none)).
+
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
compile(Config, Tests) ->
diff --git a/lib/stdlib/test/ets_SUITE.erl b/lib/stdlib/test/ets_SUITE.erl
index af5d5a8f21..bd69019892 100644
--- a/lib/stdlib/test/ets_SUITE.erl
+++ b/lib/stdlib/test/ets_SUITE.erl
@@ -75,6 +75,7 @@
-export([otp_9932/1]).
-export([otp_9423/1]).
-export([otp_10182/1]).
+-export([memory_check_summary/1]).
-export([init_per_testcase/2, end_per_testcase/2]).
%% Convenience for manual testing
@@ -149,7 +150,9 @@ all() ->
give_away, setopts, bad_table, types,
otp_10182,
otp_9932,
- otp_9423].
+ otp_9423,
+
+ memory_check_summary]. % MUST BE LAST
groups() ->
[{new, [],
@@ -185,7 +188,8 @@ init_per_suite(Config) ->
end_per_suite(_Config) ->
stop_spawn_logger(),
- catch erts_debug:set_internal_state(available_internal_state, false).
+ catch erts_debug:set_internal_state(available_internal_state, false),
+ ok.
init_per_group(_GroupName, Config) ->
Config.
@@ -193,6 +197,26 @@ init_per_group(_GroupName, Config) ->
end_per_group(_GroupName, Config) ->
Config.
+%% Test that we did not have "too many" failed verify_etsmem()'s
+%% in the test suite.
+%% verify_etsmem() may give a low number of false positives
+%% as concurrent activities, such as lingering processes
+%% from earlier test suites, may do unrelated ets (de)allocations.
+memory_check_summary(_Config) ->
+ case whereis(ets_test_spawn_logger) of
+ undefined ->
+ ?t:fail("No spawn logger exist");
+ _ ->
+ ets_test_spawn_logger ! {self(), get_failed_memchecks},
+ receive {get_failed_memchecks, FailedMemchecks} -> ok end,
+ io:format("Failed memchecks: ~p\n",[FailedMemchecks]),
+ if FailedMemchecks > 3 ->
+ ct:fail("Too many failed (~p) memchecks", [FailedMemchecks]);
+ true ->
+ ok
+ end
+ end.
+
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
@@ -5635,7 +5659,8 @@ verify_etsmem({MemInfo,AllTabs}) ->
io:format("Actual: ~p", [MemInfo2]),
io:format("Changed tables before: ~p\n",[AllTabs -- AllTabs2]),
io:format("Changed tables after: ~p\n", [AllTabs2 -- AllTabs]),
- ?t:fail()
+ ets_test_spawn_logger ! failed_memcheck,
+ {comment, "Failed memory check"}
end.
@@ -5657,10 +5682,10 @@ stop_loopers(Loopers) ->
looper(Fun, State) ->
looper(Fun, Fun(State)).
-spawn_logger(Procs) ->
+spawn_logger(Procs, FailedMemchecks) ->
receive
{new_test_proc, Proc} ->
- spawn_logger([Proc|Procs]);
+ spawn_logger([Proc|Procs], FailedMemchecks);
{sync_test_procs, Kill, From} ->
lists:foreach(fun (Proc) when From == Proc ->
ok;
@@ -5683,7 +5708,14 @@ spawn_logger(Procs) ->
end
end, Procs),
From ! test_procs_synced,
- spawn_logger([From])
+ spawn_logger([From], FailedMemchecks);
+
+ failed_memcheck ->
+ spawn_logger(Procs, FailedMemchecks+1);
+
+ {Pid, get_failed_memchecks} ->
+ Pid ! {get_failed_memchecks, FailedMemchecks},
+ spawn_logger(Procs, FailedMemchecks)
end.
pid_status(Pid) ->
@@ -5699,7 +5731,7 @@ start_spawn_logger() ->
case whereis(ets_test_spawn_logger) of
Pid when is_pid(Pid) -> true;
_ -> register(ets_test_spawn_logger,
- spawn_opt(fun () -> spawn_logger([]) end,
+ spawn_opt(fun () -> spawn_logger([], 0) end,
[{priority, max}]))
end.
@@ -5710,8 +5742,7 @@ start_spawn_logger() ->
stop_spawn_logger() ->
Mon = erlang:monitor(process, ets_test_spawn_logger),
(catch exit(whereis(ets_test_spawn_logger), kill)),
- receive {'DOWN', Mon, _, _, _} -> ok end,
- ok.
+ receive {'DOWN', Mon, _, _, _} -> ok end.
wait_for_test_procs() ->
wait_for_test_procs(false).
@@ -5811,7 +5842,7 @@ spawn_monitor_with_pid(Pid, Fun, N) ->
end) of
Pid ->
{Pid, erlang:monitor(process, Pid)};
- Other ->
+ _Other ->
spawn_monitor_with_pid(Pid,Fun,N-1)
end.
@@ -6117,11 +6148,18 @@ repeat_for_opts(F, OptGenList) ->
repeat_for_opts(F, OptGenList, []).
repeat_for_opts(F, [], Acc) ->
- lists:map(fun(Opts) ->
- OptList = lists:filter(fun(E) -> E =/= void end, Opts),
- io:format("Calling with options ~p\n",[OptList]),
- F(OptList)
- end, Acc);
+ lists:foldl(fun(Opts, RV_Acc) ->
+ OptList = lists:filter(fun(E) -> E =/= void end, Opts),
+ io:format("Calling with options ~p\n",[OptList]),
+ RV = F(OptList),
+ case RV_Acc of
+ {comment,_} -> RV_Acc;
+ _ -> case RV of
+ {comment,_} -> RV;
+ _ -> [RV | RV_Acc]
+ end
+ end
+ end, [], Acc);
repeat_for_opts(F, [OptList | Tail], []) when is_list(OptList) ->
repeat_for_opts(F, Tail, [[Opt] || Opt <- OptList]);
repeat_for_opts(F, [OptList | Tail], AccList) when is_list(OptList) ->
diff --git a/make/run_make.mk b/make/run_make.mk
index 1b4213107f..bb0da6743c 100644
--- a/make/run_make.mk
+++ b/make/run_make.mk
@@ -30,7 +30,7 @@ include $(ERL_TOP)/make/target.mk
.PHONY: valgrind
-opt debug purify quantify purecov valgrind gcov gprof lcnt:
+opt debug purify quantify purecov valgrind gcov gprof lcnt frmptr:
$(make_verbose)$(MAKE) -f $(TARGET)/Makefile TYPE=$@
plain smp frag smp_frag: